lastlight 0.16.0 → 0.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +71 -692
- package/dist/cli-config.js.map +1 -0
- package/dist/cli-format.js.map +1 -0
- package/dist/{cli/cli-server.d.ts → cli-server.d.ts} +26 -1
- package/dist/{cli/cli-server.js → cli-server.js} +40 -5
- package/dist/cli-server.js.map +1 -0
- package/dist/cli-timeline.js.map +1 -0
- package/dist/{cli/cli.js → cli.js} +4 -3
- package/dist/cli.js.map +1 -0
- package/dist/{cli/fork-cli.d.ts → fork-cli.d.ts} +3 -3
- package/dist/{cli/fork-cli.js → fork-cli.js} +28 -27
- package/dist/fork-cli.js.map +1 -0
- package/dist/{cli/oauth-cli.js → oauth-cli.js} +1 -1
- package/dist/oauth-cli.js.map +1 -0
- package/dist/{cli/setup.js → setup.js} +10 -4
- package/dist/setup.js.map +1 -0
- package/dist/{cli/skills-install.d.ts → skills-install.d.ts} +6 -0
- package/dist/{cli/skills-install.js → skills-install.js} +6 -2
- package/dist/skills-install.js.map +1 -0
- package/package.json +20 -65
- package/plugins/lastlight/.claude-plugin/plugin.json +1 -1
- package/agent-context/rules.md +0 -80
- package/agent-context/security.md +0 -69
- package/agent-context/soul.md +0 -21
- package/config/default.yaml +0 -119
- package/deploy/.env.production.example +0 -100
- package/deploy/entrypoint.sh +0 -82
- package/deploy/native/README.md +0 -160
- package/deploy/native/install.sh +0 -110
- package/deploy/native/lastlight.env.example +0 -95
- package/deploy/native/lastlight.service +0 -50
- package/deploy/sandbox-entrypoint.sh +0 -93
- package/dist/admin/auth.d.ts +0 -51
- package/dist/admin/auth.js +0 -121
- package/dist/admin/auth.js.map +0 -1
- package/dist/admin/chat-session-reader.d.ts +0 -39
- package/dist/admin/chat-session-reader.js +0 -84
- package/dist/admin/chat-session-reader.js.map +0 -1
- package/dist/admin/docker.d.ts +0 -61
- package/dist/admin/docker.js +0 -187
- package/dist/admin/docker.js.map +0 -1
- package/dist/admin/index.d.ts +0 -9
- package/dist/admin/index.js +0 -59
- package/dist/admin/index.js.map +0 -1
- package/dist/admin/routes.d.ts +0 -81
- package/dist/admin/routes.js +0 -1381
- package/dist/admin/routes.js.map +0 -1
- package/dist/admin/sessions.d.ts +0 -89
- package/dist/admin/sessions.js +0 -204
- package/dist/admin/sessions.js.map +0 -1
- package/dist/admin/tail.d.ts +0 -12
- package/dist/admin/tail.js +0 -145
- package/dist/admin/tail.js.map +0 -1
- package/dist/admin/version.d.ts +0 -22
- package/dist/admin/version.js +0 -92
- package/dist/admin/version.js.map +0 -1
- package/dist/cli/cli-config.js.map +0 -1
- package/dist/cli/cli-format.js.map +0 -1
- package/dist/cli/cli-server.js.map +0 -1
- package/dist/cli/cli-timeline.js.map +0 -1
- package/dist/cli/cli.js.map +0 -1
- package/dist/cli/fork-cli.js.map +0 -1
- package/dist/cli/oauth-cli.js.map +0 -1
- package/dist/cli/setup.js.map +0 -1
- package/dist/cli/skills-install.js.map +0 -1
- package/dist/config/config-resolve.d.ts +0 -28
- package/dist/config/config-resolve.js +0 -47
- package/dist/config/config-resolve.js.map +0 -1
- package/dist/config/config.d.ts +0 -157
- package/dist/config/config.js +0 -581
- package/dist/config/config.js.map +0 -1
- package/dist/config/core-pin.d.ts +0 -16
- package/dist/config/core-pin.js +0 -85
- package/dist/config/core-pin.js.map +0 -1
- package/dist/config/overlay-assets.d.ts +0 -20
- package/dist/config/overlay-assets.js +0 -114
- package/dist/config/overlay-assets.js.map +0 -1
- package/dist/config/overlay-bootstrap.d.ts +0 -44
- package/dist/config/overlay-bootstrap.js +0 -304
- package/dist/config/overlay-bootstrap.js.map +0 -1
- package/dist/connectors/github-webhook.d.ts +0 -45
- package/dist/connectors/github-webhook.js +0 -321
- package/dist/connectors/github-webhook.js.map +0 -1
- package/dist/connectors/index.d.ts +0 -18
- package/dist/connectors/index.js +0 -41
- package/dist/connectors/index.js.map +0 -1
- package/dist/connectors/messaging/base.d.ts +0 -42
- package/dist/connectors/messaging/base.js +0 -139
- package/dist/connectors/messaging/base.js.map +0 -1
- package/dist/connectors/messaging/delivery.d.ts +0 -14
- package/dist/connectors/messaging/delivery.js +0 -38
- package/dist/connectors/messaging/delivery.js.map +0 -1
- package/dist/connectors/messaging/index.d.ts +0 -4
- package/dist/connectors/messaging/index.js +0 -4
- package/dist/connectors/messaging/index.js.map +0 -1
- package/dist/connectors/messaging/session-manager.d.ts +0 -53
- package/dist/connectors/messaging/session-manager.js +0 -255
- package/dist/connectors/messaging/session-manager.js.map +0 -1
- package/dist/connectors/messaging/types.d.ts +0 -58
- package/dist/connectors/messaging/types.js +0 -7
- package/dist/connectors/messaging/types.js.map +0 -1
- package/dist/connectors/slack/connector.d.ts +0 -142
- package/dist/connectors/slack/connector.js +0 -494
- package/dist/connectors/slack/connector.js.map +0 -1
- package/dist/connectors/slack/index.d.ts +0 -2
- package/dist/connectors/slack/index.js +0 -3
- package/dist/connectors/slack/index.js.map +0 -1
- package/dist/connectors/slack/mrkdwn.d.ts +0 -19
- package/dist/connectors/slack/mrkdwn.js +0 -240
- package/dist/connectors/slack/mrkdwn.js.map +0 -1
- package/dist/connectors/types.d.ts +0 -61
- package/dist/connectors/types.js +0 -2
- package/dist/connectors/types.js.map +0 -1
- package/dist/cron/fanout.d.ts +0 -33
- package/dist/cron/fanout.js +0 -55
- package/dist/cron/fanout.js.map +0 -1
- package/dist/cron/jobs.d.ts +0 -18
- package/dist/cron/jobs.js +0 -37
- package/dist/cron/jobs.js.map +0 -1
- package/dist/cron/scheduler.d.ts +0 -45
- package/dist/cron/scheduler.js +0 -105
- package/dist/cron/scheduler.js.map +0 -1
- package/dist/engine/agent-executor.d.ts +0 -34
- package/dist/engine/agent-executor.js +0 -246
- package/dist/engine/agent-executor.js.map +0 -1
- package/dist/engine/chat/chat-runner.d.ts +0 -132
- package/dist/engine/chat/chat-runner.js +0 -424
- package/dist/engine/chat/chat-runner.js.map +0 -1
- package/dist/engine/chat/chat-skills.d.ts +0 -45
- package/dist/engine/chat/chat-skills.js +0 -184
- package/dist/engine/chat/chat-skills.js.map +0 -1
- package/dist/engine/chat/chat.d.ts +0 -54
- package/dist/engine/chat/chat.js +0 -316
- package/dist/engine/chat/chat.js.map +0 -1
- package/dist/engine/chat/message-batcher.d.ts +0 -32
- package/dist/engine/chat/message-batcher.js +0 -109
- package/dist/engine/chat/message-batcher.js.map +0 -1
- package/dist/engine/dispatcher.d.ts +0 -73
- package/dist/engine/dispatcher.js +0 -663
- package/dist/engine/dispatcher.js.map +0 -1
- package/dist/engine/event-shim.d.ts +0 -117
- package/dist/engine/event-shim.js +0 -435
- package/dist/engine/event-shim.js.map +0 -1
- package/dist/engine/executors/orchestrator.d.ts +0 -81
- package/dist/engine/executors/orchestrator.js +0 -365
- package/dist/engine/executors/orchestrator.js.map +0 -1
- package/dist/engine/executors/shared.d.ts +0 -189
- package/dist/engine/executors/shared.js +0 -616
- package/dist/engine/executors/shared.js.map +0 -1
- package/dist/engine/github/git-auth.d.ts +0 -62
- package/dist/engine/github/git-auth.js +0 -161
- package/dist/engine/github/git-auth.js.map +0 -1
- package/dist/engine/github/github-app-client.d.ts +0 -23
- package/dist/engine/github/github-app-client.js +0 -33
- package/dist/engine/github/github-app-client.js.map +0 -1
- package/dist/engine/github/github-tools.d.ts +0 -18
- package/dist/engine/github/github-tools.js +0 -263
- package/dist/engine/github/github-tools.js.map +0 -1
- package/dist/engine/github/github.d.ts +0 -1193
- package/dist/engine/github/github.js +0 -357
- package/dist/engine/github/github.js.map +0 -1
- package/dist/engine/github/profiles.d.ts +0 -279
- package/dist/engine/github/profiles.js +0 -42
- package/dist/engine/github/profiles.js.map +0 -1
- package/dist/engine/github/review-poster.d.ts +0 -98
- package/dist/engine/github/review-poster.js +0 -177
- package/dist/engine/github/review-poster.js.map +0 -1
- package/dist/engine/llm.d.ts +0 -79
- package/dist/engine/llm.js +0 -269
- package/dist/engine/llm.js.map +0 -1
- package/dist/engine/oauth.d.ts +0 -43
- package/dist/engine/oauth.js +0 -103
- package/dist/engine/oauth.js.map +0 -1
- package/dist/engine/router.d.ts +0 -29
- package/dist/engine/router.js +0 -680
- package/dist/engine/router.js.map +0 -1
- package/dist/engine/screen/classifier.d.ts +0 -93
- package/dist/engine/screen/classifier.js +0 -215
- package/dist/engine/screen/classifier.js.map +0 -1
- package/dist/engine/screen/screen.d.ts +0 -41
- package/dist/engine/screen/screen.js +0 -93
- package/dist/engine/screen/screen.js.map +0 -1
- package/dist/evals-api.d.ts +0 -24
- package/dist/evals-api.js +0 -22
- package/dist/evals-api.js.map +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -940
- package/dist/index.js.map +0 -1
- package/dist/managed-repos.d.ts +0 -30
- package/dist/managed-repos.js +0 -72
- package/dist/managed-repos.js.map +0 -1
- package/dist/notify/blocks.d.ts +0 -23
- package/dist/notify/blocks.js +0 -118
- package/dist/notify/blocks.js.map +0 -1
- package/dist/notify/index.d.ts +0 -17
- package/dist/notify/index.js +0 -7
- package/dist/notify/index.js.map +0 -1
- package/dist/notify/model.d.ts +0 -57
- package/dist/notify/model.js +0 -89
- package/dist/notify/model.js.map +0 -1
- package/dist/notify/notifier.d.ts +0 -18
- package/dist/notify/notifier.js +0 -100
- package/dist/notify/notifier.js.map +0 -1
- package/dist/notify/render.d.ts +0 -21
- package/dist/notify/render.js +0 -59
- package/dist/notify/render.js.map +0 -1
- package/dist/notify/transports/github.d.ts +0 -26
- package/dist/notify/transports/github.js +0 -27
- package/dist/notify/transports/github.js.map +0 -1
- package/dist/notify/transports/slack.d.ts +0 -27
- package/dist/notify/transports/slack.js +0 -37
- package/dist/notify/transports/slack.js.map +0 -1
- package/dist/notify/types.d.ts +0 -119
- package/dist/notify/types.js +0 -16
- package/dist/notify/types.js.map +0 -1
- package/dist/providers.d.ts +0 -125
- package/dist/providers.js +0 -279
- package/dist/providers.js.map +0 -1
- package/dist/sandbox/docker.d.ts +0 -180
- package/dist/sandbox/docker.js +0 -517
- package/dist/sandbox/docker.js.map +0 -1
- package/dist/sandbox/egress-allowlist.d.ts +0 -74
- package/dist/sandbox/egress-allowlist.js +0 -164
- package/dist/sandbox/egress-allowlist.js.map +0 -1
- package/dist/sandbox/egress-firewall-config.d.ts +0 -127
- package/dist/sandbox/egress-firewall-config.js +0 -434
- package/dist/sandbox/egress-firewall-config.js.map +0 -1
- package/dist/sandbox/images.d.ts +0 -23
- package/dist/sandbox/images.js +0 -55
- package/dist/sandbox/images.js.map +0 -1
- package/dist/sandbox/index.d.ts +0 -112
- package/dist/sandbox/index.js +0 -332
- package/dist/sandbox/index.js.map +0 -1
- package/dist/sandbox/sandbox.d.ts +0 -214
- package/dist/sandbox/sandbox.js +0 -453
- package/dist/sandbox/sandbox.js.map +0 -1
- package/dist/sandbox/smol.d.ts +0 -162
- package/dist/sandbox/smol.js +0 -485
- package/dist/sandbox/smol.js.map +0 -1
- package/dist/session-log.d.ts +0 -63
- package/dist/session-log.js +0 -290
- package/dist/session-log.js.map +0 -1
- package/dist/state/approval-store.d.ts +0 -88
- package/dist/state/approval-store.js +0 -149
- package/dist/state/approval-store.js.map +0 -1
- package/dist/state/build-assets.d.ts +0 -50
- package/dist/state/build-assets.js +0 -154
- package/dist/state/build-assets.js.map +0 -1
- package/dist/state/db.d.ts +0 -81
- package/dist/state/db.js +0 -155
- package/dist/state/db.js.map +0 -1
- package/dist/state/execution-store.d.ts +0 -257
- package/dist/state/execution-store.js +0 -527
- package/dist/state/execution-store.js.map +0 -1
- package/dist/state/migrate.d.ts +0 -15
- package/dist/state/migrate.js +0 -175
- package/dist/state/migrate.js.map +0 -1
- package/dist/state/workflow-run-store.d.ts +0 -216
- package/dist/state/workflow-run-store.js +0 -403
- package/dist/state/workflow-run-store.js.map +0 -1
- package/dist/telemetry/index.d.ts +0 -38
- package/dist/telemetry/index.js +0 -253
- package/dist/telemetry/index.js.map +0 -1
- package/dist/telemetry/pi-events.d.ts +0 -12
- package/dist/telemetry/pi-events.js +0 -134
- package/dist/telemetry/pi-events.js.map +0 -1
- package/dist/workflows/dag.d.ts +0 -37
- package/dist/workflows/dag.js +0 -118
- package/dist/workflows/dag.js.map +0 -1
- package/dist/workflows/loader.d.ts +0 -53
- package/dist/workflows/loader.js +0 -421
- package/dist/workflows/loader.js.map +0 -1
- package/dist/workflows/loop-eval.d.ts +0 -28
- package/dist/workflows/loop-eval.js +0 -74
- package/dist/workflows/loop-eval.js.map +0 -1
- package/dist/workflows/phase-executor.d.ts +0 -222
- package/dist/workflows/phase-executor.js +0 -1153
- package/dist/workflows/phase-executor.js.map +0 -1
- package/dist/workflows/phase-ref.d.ts +0 -50
- package/dist/workflows/phase-ref.js +0 -91
- package/dist/workflows/phase-ref.js.map +0 -1
- package/dist/workflows/resume.d.ts +0 -58
- package/dist/workflows/resume.js +0 -313
- package/dist/workflows/resume.js.map +0 -1
- package/dist/workflows/runner.d.ts +0 -63
- package/dist/workflows/runner.js +0 -381
- package/dist/workflows/runner.js.map +0 -1
- package/dist/workflows/schema.d.ts +0 -344
- package/dist/workflows/schema.js +0 -460
- package/dist/workflows/schema.js.map +0 -1
- package/dist/workflows/simple.d.ts +0 -90
- package/dist/workflows/simple.js +0 -393
- package/dist/workflows/simple.js.map +0 -1
- package/dist/workflows/target-policy.d.ts +0 -74
- package/dist/workflows/target-policy.js +0 -80
- package/dist/workflows/target-policy.js.map +0 -1
- package/dist/workflows/templates.d.ts +0 -88
- package/dist/workflows/templates.js +0 -127
- package/dist/workflows/templates.js.map +0 -1
- package/dist/workflows/triggers.d.ts +0 -21
- package/dist/workflows/triggers.js +0 -45
- package/dist/workflows/triggers.js.map +0 -1
- package/dist/workflows/verdict.d.ts +0 -19
- package/dist/workflows/verdict.js +0 -30
- package/dist/workflows/verdict.js.map +0 -1
- package/dist/worktree/manager.d.ts +0 -43
- package/dist/worktree/manager.js +0 -127
- package/dist/worktree/manager.js.map +0 -1
- package/docker-compose.yml +0 -274
- package/sandbox.Dockerfile +0 -68
- package/skills/README.md +0 -42
- package/skills/browser-qa/SKILL.md +0 -208
- package/skills/browser-qa/scripts/agent-browser.mjs +0 -531
- package/skills/building/SKILL.md +0 -95
- package/skills/chat/SKILL.md +0 -36
- package/skills/code-review/SKILL.md +0 -82
- package/skills/debug-production/SKILL.md +0 -108
- package/skills/demo/SKILL.md +0 -228
- package/skills/demo/scripts/compose-demo.sh +0 -243
- package/skills/issue-answer/SKILL.md +0 -91
- package/skills/issue-comment/SKILL.md +0 -49
- package/skills/issue-triage/SKILL.md +0 -149
- package/skills/issue-triage/references/AGENT-BRIEF.md +0 -65
- package/skills/pr-comment/SKILL.md +0 -64
- package/skills/pr-review/SKILL.md +0 -148
- package/skills/pr-review/references/findings-schema.md +0 -89
- package/skills/qa-test/SKILL.md +0 -97
- package/skills/repo-health/SKILL.md +0 -67
- package/skills/security-feedback/SKILL.md +0 -173
- package/skills/security-feedback/references/templates.md +0 -77
- package/skills/security-review/SKILL.md +0 -215
- package/skills/security-review/references/issue-format.md +0 -302
- package/skills/verify/SKILL.md +0 -118
- package/workflows/answer.yaml +0 -44
- package/workflows/build.yaml +0 -129
- package/workflows/cron-health.yaml +0 -6
- package/workflows/cron-review.yaml +0 -8
- package/workflows/cron-security.yaml +0 -6
- package/workflows/cron-triage.yaml +0 -8
- package/workflows/demo.yaml +0 -62
- package/workflows/examples/bash-smoke.yaml +0 -41
- package/workflows/examples/parallel-review.yaml +0 -36
- package/workflows/examples/tdd-loop.yaml +0 -17
- package/workflows/explore.yaml +0 -80
- package/workflows/issue-comment.yaml +0 -15
- package/workflows/issue-triage.yaml +0 -22
- package/workflows/pr-comment.yaml +0 -16
- package/workflows/pr-fix.yaml +0 -17
- package/workflows/pr-review.yaml +0 -50
- package/workflows/prompts/answer.md +0 -68
- package/workflows/prompts/architect.md +0 -44
- package/workflows/prompts/classifier.md +0 -60
- package/workflows/prompts/classify-adds-info.md +0 -17
- package/workflows/prompts/demo.md +0 -125
- package/workflows/prompts/executor.md +0 -42
- package/workflows/prompts/explore-ask.md +0 -99
- package/workflows/prompts/explore-publish.md +0 -31
- package/workflows/prompts/explore-read.md +0 -120
- package/workflows/prompts/explore-synthesize.md +0 -88
- package/workflows/prompts/fix.md +0 -18
- package/workflows/prompts/guardrails.md +0 -96
- package/workflows/prompts/pr-fix.md +0 -26
- package/workflows/prompts/pr.md +0 -39
- package/workflows/prompts/qa-browser.md +0 -95
- package/workflows/prompts/qa-synth.md +0 -44
- package/workflows/prompts/qa-test.md +0 -60
- package/workflows/prompts/re-reviewer.md +0 -33
- package/workflows/prompts/reviewer.md +0 -60
- package/workflows/prompts/verify-browser.md +0 -93
- package/workflows/prompts/verify-synth.md +0 -44
- package/workflows/prompts/verify.md +0 -63
- package/workflows/qa-test.yaml +0 -94
- package/workflows/repo-health.yaml +0 -15
- package/workflows/security-feedback.yaml +0 -25
- package/workflows/security-review.yaml +0 -37
- package/workflows/verify.yaml +0 -93
- /package/dist/{cli/cli-config.d.ts → cli-config.d.ts} +0 -0
- /package/dist/{cli/cli-config.js → cli-config.js} +0 -0
- /package/dist/{cli/cli-format.d.ts → cli-format.d.ts} +0 -0
- /package/dist/{cli/cli-format.js → cli-format.js} +0 -0
- /package/dist/{cli/cli-timeline.d.ts → cli-timeline.d.ts} +0 -0
- /package/dist/{cli/cli-timeline.js → cli-timeline.js} +0 -0
- /package/dist/{cli/cli.d.ts → cli.d.ts} +0 -0
- /package/dist/{cli/oauth-cli.d.ts → oauth-cli.d.ts} +0 -0
- /package/dist/{cli/setup.d.ts → setup.d.ts} +0 -0
|
@@ -1,424 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* In-process chat agent for Slack/Discord threads. Replaces the
|
|
3
|
-
* `opencode serve` HTTP supervisor with a direct pi-ai conversation:
|
|
4
|
-
*
|
|
5
|
-
* - One pi-ai conversation per messaging thread.
|
|
6
|
-
* - Conversation state lives in our existing `messaging_messages` DB
|
|
7
|
-
* table — rehydrated on every turn so harness restarts are transparent.
|
|
8
|
-
* - Tools are limited to read-only GitHub (see github-tools.ts). No bash,
|
|
9
|
-
* no edit, no file system, no MCP.
|
|
10
|
-
* - Per-thread in-flight chain so two messages in the same thread
|
|
11
|
-
* serialize cleanly while different threads stay parallel.
|
|
12
|
-
*/
|
|
13
|
-
import { randomUUID } from "node:crypto";
|
|
14
|
-
import { Octokit } from "octokit";
|
|
15
|
-
import { completeSimple, getModel, } from "@earendil-works/pi-ai";
|
|
16
|
-
import { buildChatGitHubTools } from "../github/github-tools.js";
|
|
17
|
-
import { OAUTH_ONLY_PROVIDERS, getOAuthProvider, oauthProviderIdForModel, resolveOAuthApiKey, } from "../oauth.js";
|
|
18
|
-
const MAX_TOOL_ROUNDS = 8;
|
|
19
|
-
/**
|
|
20
|
-
* Exponential backoff schedule (ms) for transient chat-model failures —
|
|
21
|
-
* rate limits (429) and provider hiccups (5xx / overloaded / transient
|
|
22
|
-
* network). pi-ai disables the provider SDK's own retries (`maxRetries: 0`),
|
|
23
|
-
* so without this a single 429 from the model would kill the whole turn.
|
|
24
|
-
* The sandbox path already retries via pi-coding-agent's auto-retry; the
|
|
25
|
-
* chat path drives pi-ai directly, so it needs its own.
|
|
26
|
-
*/
|
|
27
|
-
const CHAT_RETRY_BACKOFF_MS = [10_000, 30_000, 60_000];
|
|
28
|
-
/**
|
|
29
|
-
* Match transient, retryable model errors. Deliberately conservative: auth /
|
|
30
|
-
* validation / context-overflow / other 4xx (anything but 429) are NOT
|
|
31
|
-
* retried — only rate limits, server errors, and transient network faults.
|
|
32
|
-
*/
|
|
33
|
-
export function isRetryableModelError(message) {
|
|
34
|
-
const m = message.toLowerCase();
|
|
35
|
-
return (/\b429\b/.test(m) ||
|
|
36
|
-
m.includes("rate limit") ||
|
|
37
|
-
m.includes("rate_limit") ||
|
|
38
|
-
m.includes("too many requests") ||
|
|
39
|
-
m.includes("overloaded") ||
|
|
40
|
-
/\b50[0234]\b/.test(m) || // 500 / 502 / 503 / 504
|
|
41
|
-
m.includes("service unavailable") ||
|
|
42
|
-
m.includes("timeout") ||
|
|
43
|
-
m.includes("etimedout") ||
|
|
44
|
-
m.includes("econnreset") ||
|
|
45
|
-
m.includes("fetch failed"));
|
|
46
|
-
}
|
|
47
|
-
const sleepMs = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
48
|
-
/**
|
|
49
|
-
* Call `complete`, retrying transient failures with exponential backoff.
|
|
50
|
-
* Handles both shapes pi-ai surfaces a failure as: a thrown error, and a
|
|
51
|
-
* returned AssistantMessage with `stopReason === "error"`. Non-retryable
|
|
52
|
-
* outcomes (and the final attempt) are returned/thrown unchanged so the
|
|
53
|
-
* caller's existing error handling still applies. Dependency-injected for
|
|
54
|
-
* testing (`delaysMs` / `sleepFn` / `onRetry`).
|
|
55
|
-
*/
|
|
56
|
-
export async function completeWithRetry(complete, model, context, opts, deps = {}) {
|
|
57
|
-
const delays = deps.delaysMs ?? CHAT_RETRY_BACKOFF_MS;
|
|
58
|
-
const doSleep = deps.sleepFn ?? sleepMs;
|
|
59
|
-
let attempt = 0;
|
|
60
|
-
for (;;) {
|
|
61
|
-
let assistant;
|
|
62
|
-
let errMsg;
|
|
63
|
-
let thrown;
|
|
64
|
-
try {
|
|
65
|
-
assistant = await complete(model, context, opts);
|
|
66
|
-
if (assistant.stopReason !== "error")
|
|
67
|
-
return assistant;
|
|
68
|
-
errMsg = assistant.errorMessage ?? "error";
|
|
69
|
-
}
|
|
70
|
-
catch (err) {
|
|
71
|
-
thrown = err;
|
|
72
|
-
errMsg = err instanceof Error ? err.message : String(err);
|
|
73
|
-
}
|
|
74
|
-
if (attempt >= delays.length || !isRetryableModelError(errMsg)) {
|
|
75
|
-
if (thrown !== undefined)
|
|
76
|
-
throw thrown; // preserve the original error
|
|
77
|
-
return assistant; // non-retryable / exhausted errored assistant
|
|
78
|
-
}
|
|
79
|
-
const delayMs = delays[attempt];
|
|
80
|
-
deps.onRetry?.({ attempt: attempt + 1, delayMs, reason: errMsg });
|
|
81
|
-
await doSleep(delayMs);
|
|
82
|
-
attempt++;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
export class ChatRunner {
|
|
86
|
-
cfg;
|
|
87
|
-
sessionManager;
|
|
88
|
-
tools;
|
|
89
|
-
extraTools;
|
|
90
|
-
/** Concatenated tool list passed to pi-ai (github + extra). */
|
|
91
|
-
mergedTools;
|
|
92
|
-
/**
|
|
93
|
-
* Resolved lazily on the first chat turn. A bad chat model spec
|
|
94
|
-
* (unknown id) MUST NOT crash the whole harness — webhooks, crons and
|
|
95
|
-
* workflows don't depend on it.
|
|
96
|
-
*/
|
|
97
|
-
model;
|
|
98
|
-
modelError;
|
|
99
|
-
chains = new Map();
|
|
100
|
-
/**
|
|
101
|
-
* OAuth provider id backing the chat model (e.g. `openai-codex` for a
|
|
102
|
-
* `openai-codex/gpt-5.4` spec), or undefined for API-key providers. When
|
|
103
|
-
* set, each turn resolves a fresh subscription token instead of relying on
|
|
104
|
-
* a provider env var. Derived once from `cfg.model`.
|
|
105
|
-
*/
|
|
106
|
-
oauthProviderId;
|
|
107
|
-
constructor(cfg, sessionManager) {
|
|
108
|
-
this.cfg = cfg;
|
|
109
|
-
this.sessionManager = sessionManager;
|
|
110
|
-
this.oauthProviderId = oauthProviderIdForModel(cfg.model);
|
|
111
|
-
if (cfg.github) {
|
|
112
|
-
this.tools = buildChatGitHubTools(cfg.github);
|
|
113
|
-
}
|
|
114
|
-
this.extraTools = cfg.extraTools;
|
|
115
|
-
const merged = [
|
|
116
|
-
...(this.tools?.tools ?? []),
|
|
117
|
-
...(this.extraTools?.tools ?? []),
|
|
118
|
-
];
|
|
119
|
-
this.mergedTools = merged.length > 0 ? merged : undefined;
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* Dispatch a tool call to whichever toolset registered it. Github
|
|
123
|
-
* tools take precedence (they're registered first); fall back to the
|
|
124
|
-
* extra toolset for anything not in the github name set.
|
|
125
|
-
*/
|
|
126
|
-
async dispatchTool(call) {
|
|
127
|
-
if (this.tools?.tools.some((t) => t.name === call.name)) {
|
|
128
|
-
return this.tools.execute(call);
|
|
129
|
-
}
|
|
130
|
-
if (this.extraTools?.tools.some((t) => t.name === call.name)) {
|
|
131
|
-
return this.extraTools.execute(call);
|
|
132
|
-
}
|
|
133
|
-
return {
|
|
134
|
-
content: JSON.stringify({ error: `unknown tool: ${call.name}` }),
|
|
135
|
-
isError: true,
|
|
136
|
-
};
|
|
137
|
-
}
|
|
138
|
-
/** Build a failed-turn result carrying a single actionable error message. */
|
|
139
|
-
errorTurn(agentSessionId, message) {
|
|
140
|
-
return {
|
|
141
|
-
text: "",
|
|
142
|
-
agentSessionId,
|
|
143
|
-
tokens: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
144
|
-
costUsd: 0,
|
|
145
|
-
modelTurns: 0,
|
|
146
|
-
finish: "error",
|
|
147
|
-
errors: [message],
|
|
148
|
-
assistantMessages: [],
|
|
149
|
-
toolResults: [],
|
|
150
|
-
modelId: this.cfg.model,
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
resolveModelLazy() {
|
|
154
|
-
if (this.model)
|
|
155
|
-
return this.model;
|
|
156
|
-
if (this.modelError)
|
|
157
|
-
return undefined;
|
|
158
|
-
try {
|
|
159
|
-
this.model = resolveModel(this.cfg.model);
|
|
160
|
-
return this.model;
|
|
161
|
-
}
|
|
162
|
-
catch (err) {
|
|
163
|
-
this.modelError = err instanceof Error ? err.message : String(err);
|
|
164
|
-
console.error(`[chat] ${this.modelError}`);
|
|
165
|
-
return undefined;
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
/**
|
|
169
|
-
* Run one chat turn. Each messagingSessionId maps to a stable pi-ai
|
|
170
|
-
* `agentSessionId` (a UUID we mint on first turn) which the dashboard
|
|
171
|
-
* uses to look up the JSONL on disk.
|
|
172
|
-
*/
|
|
173
|
-
async turn(messagingSessionId, prompt) {
|
|
174
|
-
const prev = this.chains.get(messagingSessionId) ?? Promise.resolve();
|
|
175
|
-
const next = prev
|
|
176
|
-
.catch(() => undefined)
|
|
177
|
-
.then(() => this.doTurn(messagingSessionId, prompt));
|
|
178
|
-
this.chains.set(messagingSessionId, next);
|
|
179
|
-
const cleanup = () => {
|
|
180
|
-
if (this.chains.get(messagingSessionId) === next) {
|
|
181
|
-
this.chains.delete(messagingSessionId);
|
|
182
|
-
}
|
|
183
|
-
};
|
|
184
|
-
next.then(cleanup, cleanup);
|
|
185
|
-
return next;
|
|
186
|
-
}
|
|
187
|
-
async doTurn(messagingSessionId, prompt) {
|
|
188
|
-
// Resolve (or mint) the stable agentSessionId pinned to this thread.
|
|
189
|
-
const session = this.sessionManager.getSession(messagingSessionId);
|
|
190
|
-
let agentSessionId = session?.agentSessionId || null;
|
|
191
|
-
if (!agentSessionId) {
|
|
192
|
-
agentSessionId = randomUUID();
|
|
193
|
-
this.sessionManager.setAgentSessionId(messagingSessionId, agentSessionId);
|
|
194
|
-
}
|
|
195
|
-
// Bail with a clear error if the chat model spec is unknown to pi-ai.
|
|
196
|
-
// Done here rather than in the constructor so a misconfigured chat
|
|
197
|
-
// model only fails chat turns, not the whole server.
|
|
198
|
-
const model = this.resolveModelLazy();
|
|
199
|
-
if (!model) {
|
|
200
|
-
return this.errorTurn(agentSessionId, this.modelError ?? "chat model not configured");
|
|
201
|
-
}
|
|
202
|
-
// Resolve the effective model + credentials. For OAuth-backed chat models
|
|
203
|
-
// (Codex / Claude Pro / Copilot) we mint a fresh subscription token per
|
|
204
|
-
// turn (pi-ai refreshes it if expired) and pass it as the per-call apiKey
|
|
205
|
-
// — the in-process chat path can carry an explicit key, unlike the sandbox.
|
|
206
|
-
let effectiveModel = model;
|
|
207
|
-
let apiKey;
|
|
208
|
-
if (this.oauthProviderId) {
|
|
209
|
-
try {
|
|
210
|
-
const res = await resolveOAuthApiKey(this.oauthProviderId);
|
|
211
|
-
if (res) {
|
|
212
|
-
apiKey = res.apiKey;
|
|
213
|
-
// Some providers rewrite the model (e.g. base URL) from credentials.
|
|
214
|
-
const prov = getOAuthProvider(this.oauthProviderId);
|
|
215
|
-
if (prov?.modifyModels) {
|
|
216
|
-
effectiveModel = prov.modifyModels([model], res.credentials)[0] ?? model;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
else if (OAUTH_ONLY_PROVIDERS.has(this.oauthProviderId)) {
|
|
220
|
-
// OAuth-only provider with no stored credentials — cannot fall back
|
|
221
|
-
// to an API key, so fail this turn with an actionable message.
|
|
222
|
-
return this.errorTurn(agentSessionId, `Chat model '${this.cfg.model}' requires an OAuth login. Run: ` +
|
|
223
|
-
`lastlight oauth login ${this.oauthProviderId}`);
|
|
224
|
-
}
|
|
225
|
-
// Non-OAuth-only (anthropic) with no creds: fall through to env-key auth.
|
|
226
|
-
}
|
|
227
|
-
catch (err) {
|
|
228
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
229
|
-
return this.errorTurn(agentSessionId, `OAuth token refresh failed for '${this.oauthProviderId}': ${msg}. ` +
|
|
230
|
-
`Re-run: lastlight oauth login ${this.oauthProviderId}`);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
// Rehydrate conversation context from the DB. Messages were stored
|
|
234
|
-
// text-only on prior turns; we replay them as alternating user /
|
|
235
|
-
// assistant text messages. Tool calls/results inside a single turn
|
|
236
|
-
// never persist (they only live for that turn's loop) — that's a
|
|
237
|
-
// deliberate simplification: the agent gets a clean conversation
|
|
238
|
-
// history and can re-tool if asked again.
|
|
239
|
-
const history = this.sessionManager.getHistory(messagingSessionId, 50);
|
|
240
|
-
const messages = history.map((h) => textMessage(h.role, h.content, h.timestamp));
|
|
241
|
-
messages.push(textMessage("user", prompt, new Date().toISOString()));
|
|
242
|
-
const context = {
|
|
243
|
-
systemPrompt: this.cfg.systemPrompt,
|
|
244
|
-
messages,
|
|
245
|
-
tools: this.mergedTools,
|
|
246
|
-
};
|
|
247
|
-
const errors = [];
|
|
248
|
-
const assistantMessages = [];
|
|
249
|
-
const toolResults = [];
|
|
250
|
-
const opts = {
|
|
251
|
-
reasoning: pickReasoning(this.cfg.thinking),
|
|
252
|
-
timeoutMs: this.cfg.timeoutMs ?? 120_000,
|
|
253
|
-
...(apiKey ? { apiKey } : {}),
|
|
254
|
-
};
|
|
255
|
-
let finish = "stop";
|
|
256
|
-
let tokensIn = 0;
|
|
257
|
-
let tokensOut = 0;
|
|
258
|
-
let cacheRead = 0;
|
|
259
|
-
let cacheWrite = 0;
|
|
260
|
-
let costUsd = 0;
|
|
261
|
-
let modelTurns = 0;
|
|
262
|
-
let finalText = "";
|
|
263
|
-
for (let round = 0; round < MAX_TOOL_ROUNDS + 1; round++) {
|
|
264
|
-
modelTurns++;
|
|
265
|
-
let assistant;
|
|
266
|
-
try {
|
|
267
|
-
assistant = await completeWithRetry(completeSimple, effectiveModel, context, opts, {
|
|
268
|
-
onRetry: ({ attempt, delayMs, reason }) => console.warn(`[chat] transient model error (retry ${attempt}/${CHAT_RETRY_BACKOFF_MS.length} ` +
|
|
269
|
-
`in ${delayMs / 1000}s): ${reason}`),
|
|
270
|
-
});
|
|
271
|
-
}
|
|
272
|
-
catch (err) {
|
|
273
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
274
|
-
errors.push(msg);
|
|
275
|
-
finish = "error";
|
|
276
|
-
break;
|
|
277
|
-
}
|
|
278
|
-
assistantMessages.push(assistant);
|
|
279
|
-
context.messages.push(assistant);
|
|
280
|
-
tokensIn += assistant.usage.input;
|
|
281
|
-
tokensOut += assistant.usage.output;
|
|
282
|
-
cacheRead += assistant.usage.cacheRead;
|
|
283
|
-
cacheWrite += assistant.usage.cacheWrite;
|
|
284
|
-
costUsd += assistant.usage.cost.total;
|
|
285
|
-
if (assistant.stopReason === "error" || assistant.stopReason === "aborted") {
|
|
286
|
-
errors.push(assistant.errorMessage ?? assistant.stopReason);
|
|
287
|
-
finish = "error";
|
|
288
|
-
break;
|
|
289
|
-
}
|
|
290
|
-
// Pull text out (last text block wins — same convention as pi-ai's run() helper).
|
|
291
|
-
const text = assistant.content
|
|
292
|
-
.filter((c) => c.type === "text" && typeof c.text === "string")
|
|
293
|
-
.map((c) => c.text)
|
|
294
|
-
.join("");
|
|
295
|
-
if (text)
|
|
296
|
-
finalText = text;
|
|
297
|
-
// Tool calls? Execute and loop.
|
|
298
|
-
const toolCalls = assistant.content.filter((c) => c.type === "toolCall");
|
|
299
|
-
if (toolCalls.length === 0) {
|
|
300
|
-
finish = "stop";
|
|
301
|
-
break;
|
|
302
|
-
}
|
|
303
|
-
if (!this.mergedTools) {
|
|
304
|
-
// Model emitted a tool call without any tools registered — shouldn't
|
|
305
|
-
// happen, but bail out rather than loop forever.
|
|
306
|
-
errors.push("Model called a tool, but no tools are registered for chat.");
|
|
307
|
-
finish = "error";
|
|
308
|
-
break;
|
|
309
|
-
}
|
|
310
|
-
for (const call of toolCalls) {
|
|
311
|
-
const { content, isError } = await this.dispatchTool(call);
|
|
312
|
-
const tr = {
|
|
313
|
-
role: "toolResult",
|
|
314
|
-
toolCallId: call.id,
|
|
315
|
-
toolName: call.name,
|
|
316
|
-
content: [{ type: "text", text: content }],
|
|
317
|
-
isError,
|
|
318
|
-
timestamp: Date.now(),
|
|
319
|
-
};
|
|
320
|
-
toolResults.push(tr);
|
|
321
|
-
context.messages.push(tr);
|
|
322
|
-
if (isError)
|
|
323
|
-
errors.push(`${call.name}: ${content}`);
|
|
324
|
-
}
|
|
325
|
-
if (round === MAX_TOOL_ROUNDS) {
|
|
326
|
-
finish = "max-rounds";
|
|
327
|
-
errors.push(`Hit MAX_TOOL_ROUNDS (${MAX_TOOL_ROUNDS}); giving up on this turn.`);
|
|
328
|
-
break;
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
// Persist this turn's user + final assistant text. We do NOT persist
|
|
332
|
-
// tool calls or intermediate model responses — only the human-visible
|
|
333
|
-
// turn boundaries — to keep the rehydrated context compact.
|
|
334
|
-
this.sessionManager.addMessage(messagingSessionId, "user", prompt);
|
|
335
|
-
if (finalText) {
|
|
336
|
-
this.sessionManager.addMessage(messagingSessionId, "assistant", finalText);
|
|
337
|
-
}
|
|
338
|
-
this.sessionManager.touchSession(messagingSessionId);
|
|
339
|
-
return {
|
|
340
|
-
text: finalText,
|
|
341
|
-
agentSessionId,
|
|
342
|
-
tokens: {
|
|
343
|
-
input: tokensIn,
|
|
344
|
-
output: tokensOut,
|
|
345
|
-
cacheRead,
|
|
346
|
-
cacheWrite,
|
|
347
|
-
},
|
|
348
|
-
costUsd,
|
|
349
|
-
modelTurns,
|
|
350
|
-
finish,
|
|
351
|
-
errors,
|
|
352
|
-
assistantMessages,
|
|
353
|
-
toolResults,
|
|
354
|
-
modelId: this.cfg.model,
|
|
355
|
-
};
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
// ── Helpers ─────────────────────────────────────────────────────────
|
|
359
|
-
function resolveModel(spec) {
|
|
360
|
-
const idx = spec.indexOf("/");
|
|
361
|
-
if (idx < 0)
|
|
362
|
-
throw new Error(`model spec must be 'provider/id', got '${spec}'`);
|
|
363
|
-
const provider = spec.slice(0, idx);
|
|
364
|
-
const modelId = spec.slice(idx + 1);
|
|
365
|
-
// pi-ai's getModel is typed against its static registry; at runtime it
|
|
366
|
-
// accepts arbitrary strings AND returns undefined for unknown ids rather
|
|
367
|
-
// than throwing. Without this guard the first chat turn crashes deep in
|
|
368
|
-
// the provider stack with "Cannot read properties of undefined (reading
|
|
369
|
-
// 'api')" — surface a clear, actionable error instead.
|
|
370
|
-
const model = getModel(provider, modelId);
|
|
371
|
-
if (!model) {
|
|
372
|
-
throw new Error(`Unknown chat model '${spec}'. pi-ai's registry has no '${modelId}' for provider '${provider}'. ` +
|
|
373
|
-
`Set LASTLIGHT_MODELS (or LASTLIGHT_MODEL) to a registered model id.`);
|
|
374
|
-
}
|
|
375
|
-
return model;
|
|
376
|
-
}
|
|
377
|
-
function textMessage(role, content, timestamp) {
|
|
378
|
-
const ts = parseTimestamp(timestamp);
|
|
379
|
-
if (role === "user") {
|
|
380
|
-
const m = { role: "user", content, timestamp: ts };
|
|
381
|
-
return m;
|
|
382
|
-
}
|
|
383
|
-
// Treat any non-user historical role as assistant text.
|
|
384
|
-
const m = {
|
|
385
|
-
role: "assistant",
|
|
386
|
-
content: [{ type: "text", text: content }],
|
|
387
|
-
api: "openai-completions",
|
|
388
|
-
provider: "history",
|
|
389
|
-
model: "history",
|
|
390
|
-
usage: zeroUsage(),
|
|
391
|
-
stopReason: "stop",
|
|
392
|
-
timestamp: ts,
|
|
393
|
-
};
|
|
394
|
-
return m;
|
|
395
|
-
}
|
|
396
|
-
function parseTimestamp(raw) {
|
|
397
|
-
const ms = Date.parse(raw);
|
|
398
|
-
return Number.isFinite(ms) ? ms : Date.now();
|
|
399
|
-
}
|
|
400
|
-
function zeroUsage() {
|
|
401
|
-
return {
|
|
402
|
-
input: 0,
|
|
403
|
-
output: 0,
|
|
404
|
-
cacheRead: 0,
|
|
405
|
-
cacheWrite: 0,
|
|
406
|
-
totalTokens: 0,
|
|
407
|
-
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
|
408
|
-
};
|
|
409
|
-
}
|
|
410
|
-
function pickReasoning(level) {
|
|
411
|
-
// pi-ai's SimpleStreamOptions.reasoning excludes "off" — pi-ai default
|
|
412
|
-
// is no reasoning, so we pass undefined for "off".
|
|
413
|
-
if (!level || level === "off")
|
|
414
|
-
return undefined;
|
|
415
|
-
return level;
|
|
416
|
-
}
|
|
417
|
-
/**
|
|
418
|
-
* Octokit is bundled here only because github-tools.ts imports it at module
|
|
419
|
-
* load. Re-export so callers can probe whether the integration is wired
|
|
420
|
-
* without round-tripping through that file. Typed as `unknown` to avoid
|
|
421
|
-
* dragging the Octokit type chain into the published .d.ts.
|
|
422
|
-
*/
|
|
423
|
-
export const __octokitForTest = Octokit;
|
|
424
|
-
//# sourceMappingURL=chat-runner.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"chat-runner.js","sourceRoot":"","sources":["../../../src/engine/chat/chat-runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import type { Tool, ToolCall } from "@earendil-works/pi-ai";
|
|
2
|
-
/**
|
|
3
|
-
* Minimal subset of pi-coding-agent's `Skill` shape — only the fields
|
|
4
|
-
* the chat catalogue + read tool actually use.
|
|
5
|
-
*/
|
|
6
|
-
export interface ChatSkill {
|
|
7
|
-
name: string;
|
|
8
|
-
description: string;
|
|
9
|
-
filePath: string;
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Skills exposed to chat threads. `chat` is the always-on persona;
|
|
13
|
-
* the others let chat assist with one-off lookups that map to these
|
|
14
|
-
* domains without delegating to a full workflow run.
|
|
15
|
-
*/
|
|
16
|
-
export declare const CHAT_SKILL_NAMES: readonly ["chat", "issue-triage", "pr-review", "repo-health"];
|
|
17
|
-
export interface ChatSkillCatalogue {
|
|
18
|
-
/** Skills the chat agent can read on demand, keyed by name. */
|
|
19
|
-
skills: ChatSkill[];
|
|
20
|
-
/**
|
|
21
|
-
* XML block describing each skill (name + description) suitable for
|
|
22
|
-
* prepending to the chat system prompt. Empty string if no skills
|
|
23
|
-
* resolved cleanly.
|
|
24
|
-
*/
|
|
25
|
-
catalogueXml: string;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Load the curated chat skill catalogue from `<repo>/skills/`.
|
|
29
|
-
* Skills missing `name` or `description` frontmatter are silently
|
|
30
|
-
* dropped, matching pi-coding-agent's behaviour on the sandbox path.
|
|
31
|
-
*/
|
|
32
|
-
export declare function loadChatSkillCatalogue(): ChatSkillCatalogue;
|
|
33
|
-
/**
|
|
34
|
-
* Build the `read_skill` tool that chat uses to pull a SKILL.md on
|
|
35
|
-
* demand. Returns the pi-ai `Tool` definition plus a name-keyed
|
|
36
|
-
* dispatcher the chat-runner's toolset can merge into its `execute`.
|
|
37
|
-
*/
|
|
38
|
-
export interface ReadSkillToolset {
|
|
39
|
-
tool: Tool;
|
|
40
|
-
execute(call: ToolCall): {
|
|
41
|
-
content: string;
|
|
42
|
-
isError: boolean;
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
export declare function buildReadSkillTool(skills: ChatSkill[]): ReadSkillToolset;
|
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Skill catalogue + read tool for the in-process chat path.
|
|
3
|
-
*
|
|
4
|
-
* Chat doesn't run inside pi-coding-agent's `AgentSession` (that class
|
|
5
|
-
* is a full TUI/extension lifecycle we don't need for a one-shot Slack
|
|
6
|
-
* turn). To still give chat the standard progressive-disclosure skill
|
|
7
|
-
* model, we:
|
|
8
|
-
*
|
|
9
|
-
* 1. Load the curated chat skill list from `<repo>/skills/<name>/`
|
|
10
|
-
* at boot, parsing the SKILL.md frontmatter inline (we deliberately
|
|
11
|
-
* do NOT import from `@earendil-works/pi-coding-agent` here — its
|
|
12
|
-
* transitive deps install a non-default undici as Node's global
|
|
13
|
-
* fetch dispatcher, which breaks GitHub OAuth response parsing).
|
|
14
|
-
* 2. Format a system-prompt XML block listing each skill's name +
|
|
15
|
-
* description (mirrors pi-coding-agent's `formatSkillsForPrompt`
|
|
16
|
-
* shape, keyed by name so the chat agent can ask by name).
|
|
17
|
-
* 3. Expose a `read_skill` tool that resolves a name to that skill's
|
|
18
|
-
* SKILL.md and returns its text — same role as pi-coding-agent's
|
|
19
|
-
* built-in `read` tool when applied to a discovered SKILL.md.
|
|
20
|
-
*
|
|
21
|
-
* The curated list is intentionally hard-coded for v1. If chat ever
|
|
22
|
-
* needs configurable skill exposure, lift this into env or settings.
|
|
23
|
-
*/
|
|
24
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
25
|
-
import { join, resolve } from "node:path";
|
|
26
|
-
import { Type } from "@sinclair/typebox";
|
|
27
|
-
import { resolveSkillPaths } from "../../workflows/loader.js";
|
|
28
|
-
/**
|
|
29
|
-
* Skills exposed to chat threads. `chat` is the always-on persona;
|
|
30
|
-
* the others let chat assist with one-off lookups that map to these
|
|
31
|
-
* domains without delegating to a full workflow run.
|
|
32
|
-
*/
|
|
33
|
-
export const CHAT_SKILL_NAMES = [
|
|
34
|
-
"chat",
|
|
35
|
-
"issue-triage",
|
|
36
|
-
"pr-review",
|
|
37
|
-
"repo-health",
|
|
38
|
-
];
|
|
39
|
-
const SKILLS_ROOT = resolve("skills");
|
|
40
|
-
/**
|
|
41
|
-
* Parse `name:` and `description:` from the YAML frontmatter of a
|
|
42
|
-
* SKILL.md. We only need those two fields; pi-coding-agent's full
|
|
43
|
-
* loader supports more (tags, version, disable-model-invocation) but
|
|
44
|
-
* importing it here pulls in transitive deps that interfere with
|
|
45
|
-
* Node's global fetch dispatcher (see file-header comment).
|
|
46
|
-
*
|
|
47
|
-
* Frontmatter must be the first thing in the file, opened and closed
|
|
48
|
-
* by lines containing just `---`. Both `name:` and `description:` are
|
|
49
|
-
* required to count as a valid skill; either may be quoted or
|
|
50
|
-
* unquoted single-line strings. Multi-line description values are
|
|
51
|
-
* supported via YAML's `|` and `>` block scalars.
|
|
52
|
-
*/
|
|
53
|
-
function parseSkillFrontmatter(md) {
|
|
54
|
-
const lines = md.split(/\r?\n/);
|
|
55
|
-
if (lines[0]?.trim() !== "---")
|
|
56
|
-
return {};
|
|
57
|
-
const end = lines.findIndex((l, i) => i > 0 && l.trim() === "---");
|
|
58
|
-
if (end < 0)
|
|
59
|
-
return {};
|
|
60
|
-
const body = lines.slice(1, end);
|
|
61
|
-
const out = {};
|
|
62
|
-
for (let i = 0; i < body.length; i++) {
|
|
63
|
-
const m = body[i].match(/^([A-Za-z0-9_-]+)\s*:\s*(.*)$/);
|
|
64
|
-
if (!m)
|
|
65
|
-
continue;
|
|
66
|
-
const key = m[1];
|
|
67
|
-
const raw = m[2];
|
|
68
|
-
if (key !== "name" && key !== "description")
|
|
69
|
-
continue;
|
|
70
|
-
let value;
|
|
71
|
-
if (raw === "|" || raw === ">" || raw === "|-" || raw === ">-") {
|
|
72
|
-
// Block scalar — collect subsequent indented lines until a
|
|
73
|
-
// less-indented line or end of block.
|
|
74
|
-
const collected = [];
|
|
75
|
-
let j = i + 1;
|
|
76
|
-
while (j < body.length && /^\s+/.test(body[j])) {
|
|
77
|
-
collected.push(body[j].replace(/^\s+/, ""));
|
|
78
|
-
j++;
|
|
79
|
-
}
|
|
80
|
-
value = raw.startsWith(">") ? collected.join(" ") : collected.join("\n");
|
|
81
|
-
i = j - 1;
|
|
82
|
-
}
|
|
83
|
-
else {
|
|
84
|
-
value = raw.replace(/^['"]|['"]$/g, "").trim();
|
|
85
|
-
}
|
|
86
|
-
if (value)
|
|
87
|
-
out[key] = value;
|
|
88
|
-
}
|
|
89
|
-
return out;
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* Load the curated chat skill catalogue from `<repo>/skills/`.
|
|
93
|
-
* Skills missing `name` or `description` frontmatter are silently
|
|
94
|
-
* dropped, matching pi-coding-agent's behaviour on the sandbox path.
|
|
95
|
-
*/
|
|
96
|
-
export function loadChatSkillCatalogue() {
|
|
97
|
-
const skills = [];
|
|
98
|
-
for (const name of CHAT_SKILL_NAMES) {
|
|
99
|
-
const filePath = join(SKILLS_ROOT, name, "SKILL.md");
|
|
100
|
-
if (!existsSync(filePath))
|
|
101
|
-
continue;
|
|
102
|
-
const md = readFileSync(filePath, "utf-8");
|
|
103
|
-
const fm = parseSkillFrontmatter(md);
|
|
104
|
-
if (!fm.name || !fm.description)
|
|
105
|
-
continue;
|
|
106
|
-
skills.push({ name: fm.name, description: fm.description, filePath });
|
|
107
|
-
}
|
|
108
|
-
if (skills.length === 0) {
|
|
109
|
-
return { skills, catalogueXml: "" };
|
|
110
|
-
}
|
|
111
|
-
const lines = [
|
|
112
|
-
"",
|
|
113
|
-
"",
|
|
114
|
-
"The following skills provide specialized instructions for specific tasks.",
|
|
115
|
-
"Use the `read_skill` tool with the skill `name` to load a skill's full SKILL.md when the user's task matches its description.",
|
|
116
|
-
"",
|
|
117
|
-
"<available_skills>",
|
|
118
|
-
];
|
|
119
|
-
for (const skill of skills) {
|
|
120
|
-
lines.push(" <skill>");
|
|
121
|
-
lines.push(` <name>${escapeXml(skill.name)}</name>`);
|
|
122
|
-
lines.push(` <description>${escapeXml(skill.description)}</description>`);
|
|
123
|
-
lines.push(" </skill>");
|
|
124
|
-
}
|
|
125
|
-
lines.push("</available_skills>");
|
|
126
|
-
return { skills, catalogueXml: lines.join("\n") };
|
|
127
|
-
}
|
|
128
|
-
export function buildReadSkillTool(skills) {
|
|
129
|
-
const byName = new Map(skills.map((s) => [s.name, s]));
|
|
130
|
-
const enumNames = skills.map((s) => s.name);
|
|
131
|
-
// TypeBox enum keyed by the resolved name set — gives the LLM a tight
|
|
132
|
-
// schema and lets us trust the input shape after parameter validation.
|
|
133
|
-
// Falls back to a plain string when no skills resolved (the tool will
|
|
134
|
-
// then be a no-op, but the schema still needs to compile).
|
|
135
|
-
const parameters = Type.Object({
|
|
136
|
-
name: enumNames.length > 0
|
|
137
|
-
? Type.Union(enumNames.map((n) => Type.Literal(n)), { description: "The skill name from <available_skills>." })
|
|
138
|
-
: Type.String({ description: "The skill name from <available_skills>." }),
|
|
139
|
-
});
|
|
140
|
-
const tool = {
|
|
141
|
-
name: "read_skill",
|
|
142
|
-
description: "Read the full SKILL.md text for a skill listed in <available_skills>. " +
|
|
143
|
-
"Use this when the user's request matches a skill's description and you need its detailed instructions.",
|
|
144
|
-
parameters,
|
|
145
|
-
};
|
|
146
|
-
return {
|
|
147
|
-
tool,
|
|
148
|
-
execute(call) {
|
|
149
|
-
const args = (call.arguments ?? {});
|
|
150
|
-
const name = typeof args.name === "string" ? args.name : "";
|
|
151
|
-
const skill = byName.get(name);
|
|
152
|
-
if (!skill) {
|
|
153
|
-
return {
|
|
154
|
-
content: JSON.stringify({
|
|
155
|
-
error: `unknown skill "${name}". Available: ${enumNames.join(", ") || "(none)"}.`,
|
|
156
|
-
}),
|
|
157
|
-
isError: true,
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
try {
|
|
161
|
-
// Re-resolve through the loader's allowlist + safety check rather
|
|
162
|
-
// than trusting `skill.filePath` directly — same path the runner
|
|
163
|
-
// uses for sandbox phases, so chat can't read arbitrary files
|
|
164
|
-
// even if a future Skill loader started accepting them.
|
|
165
|
-
const [dir] = resolveSkillPaths([skill.name]);
|
|
166
|
-
const md = readFileSync(`${dir}/SKILL.md`, "utf-8");
|
|
167
|
-
return { content: md, isError: false };
|
|
168
|
-
}
|
|
169
|
-
catch (err) {
|
|
170
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
171
|
-
return { content: JSON.stringify({ error: msg }), isError: true };
|
|
172
|
-
}
|
|
173
|
-
},
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
function escapeXml(s) {
|
|
177
|
-
return s
|
|
178
|
-
.replace(/&/g, "&")
|
|
179
|
-
.replace(/</g, "<")
|
|
180
|
-
.replace(/>/g, ">")
|
|
181
|
-
.replace(/"/g, """)
|
|
182
|
-
.replace(/'/g, "'");
|
|
183
|
-
}
|
|
184
|
-
//# sourceMappingURL=chat-skills.js.map
|