Automatically answers GitHub issues on SAP/ai-sdk-js using the SAP AI SDK itself — dogfooding @sap-ai-sdk/langchain to support @sap-ai-sdk.
Trigger: issues: opened → GitHub Actions (contributors only)
LLM: anthropic--claude-4.5-haiku via OrchestrationClient on SAP AI Core
Retrieval: Context7 MCP (docs) + GitHub MCP (issues) + local semantic search (embeddings)
GitHub issue opened (MEMBER / OWNER / COLLABORATOR only)
│
├── ① Post issue preview to Slack (continue-on-error)
├── ② Generate answer — reply.ts → askBot()
│ └── Agent loop (max 8 iterations)
│ LLM decides which tools to call:
│ • context7__query-docs — official SAP AI SDK docs (532 snippets)
│ • github__search_issues — past issues keyword search
│ • github__get_issue — full issue body
│ • github__search_code — code examples in the repo
│ • semantic_search — local embedding index (cross-validation)
├── ③ Reply bot answer in Slack thread (continue-on-error)
└── ④ Post comment on GitHub issue (always runs)
- Node.js 22+, pnpm 10+
- SAP AI Core service key with
anthropic--claude-4.5-haikudeployment - GitHub Personal Access Token (
reporead scope)
pnpm install
cp .env.example .env
# Fill in AICORE_SERVICE_KEY and GITHUB_TOKEN in .envpnpm start # interactive CLI (readline REPL)
pnpm serve # HTTP server on :3000 (POST /ask, GET /health)
pnpm build # TypeScript type check
pnpm refresh # Rebuild local embedding index from GitHub issues| Variable | Required | Description |
|---|---|---|
AICORE_SERVICE_KEY |
✅ | SAP AI Core service key (full JSON string) |
GITHUB_TOKEN |
✅ | GitHub PAT — repo read scope |
BOT_API_KEY |
optional | Bearer token for POST /ask (skip for local dev) |
PORT |
optional | HTTP server port (default: 3000) |
SLACK_BOT_TOKEN |
optional | Slack Bot OAuth token for issue notifications |
SLACK_CHANNEL_ID |
optional | Slack channel ID (e.g. C...) |
| Secret | Value |
|---|---|
AICORE_SERVICE_KEY |
SAP AI Core service key JSON |
GITHUB_TOKEN |
Auto-provided by GitHub Actions |
SLACK_BOT_TOKEN |
xoxb-... Bot token (optional) |
SLACK_CHANNEL_ID |
Slack channel ID (optional) |
| File | Trigger | Purpose |
|---|---|---|
.github/workflows/issue-reply.yml |
issues: opened |
Generate and post answer |
.github/workflows/refresh-embeddings.yml |
Weekly (Mon 03:00 UTC) + manual | Rebuild embedding index |
- api.slack.com/apps → Create New App → From scratch
- OAuth & Permissions → Bot Token Scopes:
chat:write,chat:write.public - Install to Workspace → copy Bot User OAuth Token (
xoxb-...) - Add
SLACK_BOT_TOKENandSLACK_CHANNEL_IDsecrets to the repo
The local semantic search uses pre-built embeddings (text-embedding-3-large, 3072 dimensions).
| File | Contents | Count |
|---|---|---|
src/embeddings-resolved.json |
Closed issues with resolution | 71 |
src/embeddings-open.json |
Open issues | 13 |
Rebuild with pnpm refresh or trigger refresh-embeddings.yml manually.
POST /ask
Body: { "question": string } (max 2000 chars)
Auth: Authorization: Bearer <BOT_API_KEY> (required if BOT_API_KEY is set)
Response: { "answer": string }
GET /health
Response: { "status": "ok" }
src/
agent.ts — askBot(), initAgent(), closeAgent() — core agent loop
reply.ts — GitHub Actions entry point (parses issue body → askBot)
server.ts — HTTP server entry point
cli.ts — Local REPL entry point
embeddings.ts — loadEmbeddingIndex(), semanticSearch()
knowledge.ts — SDK_KNOWLEDGE static reference (injected into system prompt)
embeddings-resolved.json
embeddings-open.json
scripts/
refresh-embeddings.ts — Rebuild embedding index from GitHub API
.github/workflows/
issue-reply.yml
refresh-embeddings.yml
See IMPLEMENTATION_PLAN.md for planned improvements.