mixdog 1.4.0 → 1.4.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/package.json +1 -1
- package/scripts/check-voice-runtime-inputs.mjs +25 -0
- package/scripts/gate-local.mjs +12 -3
- package/scripts/latest-guard.mjs +21 -9
- package/scripts/lib/isolated-test-env.mjs +10 -5
- package/scripts/lib/run-node-tests.mjs +37 -37
- package/scripts/lib/scoped-temp.d.mts +16 -0
- package/scripts/lib/scoped-temp.mjs +123 -0
- package/scripts/lib/stale-temp.mjs +44 -0
- package/scripts/post-release-check.mjs +1 -6
- package/scripts/pptx-kit-index.mjs +17 -4
- package/scripts/suite-health.mjs +10 -1
- package/scripts/test-data-dir.mjs +10 -7
- package/src/app.mjs +4 -0
- package/src/defaults/shipped-history.json +5 -0
- package/src/defaults/skills/browser-use/SKILL.md +6 -4
- package/src/defaults/skills/computer-use/SKILL.md +4 -2
- package/src/lib/rules-builder.cjs +29 -12
- package/src/output-styles/common.md +2 -2
- package/src/output-styles/simple.md +1 -1
- package/src/rules/agent/AGENT.md +5 -4
- package/src/rules/lead/LEAD.md +10 -5
- package/src/rules/shared/10-tool-workflow.md +3 -1
- package/src/rules/shared/45-destructive.md +0 -2
- package/src/rules/shared/50-execution.md +2 -0
- package/src/rules/shared/70-delivery.md +7 -9
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +29 -6
- package/src/runtime/agent/orchestrator/cache-break-trace.mjs +2 -0
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +1 -1
- package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +3 -1
- package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +5 -2
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +11 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-api-recovery.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +7 -3
- package/src/runtime/agent/orchestrator/providers/anthropic-api-transport.mjs +8 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens-recovery.mjs +6 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/initial-status.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +14 -3
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +6 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/command-code-oauth-login.mjs +1 -10
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-transport.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/devin.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +210 -20
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-prefix-trace.mjs +76 -11
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +45 -6
- package/src/runtime/agent/orchestrator/providers/lib/first-output-window.mjs +58 -0
- package/src/runtime/agent/orchestrator/providers/lib/listen-on.mjs +14 -0
- package/src/runtime/agent/orchestrator/providers/mimo-oauth-login.mjs +1 -10
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +9 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +14 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +4 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream-common.mjs +5 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +16 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/output-items.mjs +5 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +13 -3
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +13 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-watchdogs.mjs +81 -42
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +8 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +136 -5
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +20 -12
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-watchdogs.mjs +48 -22
- package/src/runtime/agent/orchestrator/providers/registry.mjs +12 -0
- package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +41 -13
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +7 -6
- package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +7 -3
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +3 -1
- package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +5 -2
- package/src/runtime/agent/orchestrator/session/cache/scoped-cache.mjs +1 -3
- package/src/runtime/agent/orchestrator/session/cache-warm.mjs +8 -2
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +1 -8
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +23 -0
- package/src/runtime/agent/orchestrator/session/compact/observation-supersession.mjs +103 -23
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +160 -36
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +13 -1
- package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +163 -22
- package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +132 -17
- package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +38 -7
- package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +90 -22
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +33 -3
- package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +7 -2
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +13 -5
- package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +14 -0
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +13 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +39 -21
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +3 -3
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/manager/route-fallback-chain.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +27 -9
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +61 -6
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +19 -8
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +12 -5
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +3 -3
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-context.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +9 -0
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +5 -1
- package/src/runtime/agent/orchestrator/session/prompt-cache-touch-store.mjs +30 -7
- package/src/runtime/agent/orchestrator/session/restart-prefix-parity.fixture.mjs +154 -0
- package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +7 -0
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +15 -0
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +37 -8
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +9 -1
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +61 -2
- package/src/runtime/agent/orchestrator/stall-policy.mjs +23 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/invocation-plan.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +4 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +6 -1
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +46 -20
- package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +31 -5
- package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +22 -8
- package/src/runtime/agent/orchestrator/tools/builtin/lib/scoped-search-flight.mjs +9 -5
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-stream.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +6 -3
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-dispatch.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-publication.mjs +23 -12
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-snapshot.mjs +6 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +1 -8
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/federation.mjs +3 -1
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
- package/src/runtime/agent/orchestrator/tools/lib/isolated-test-env.mjs +4 -3
- package/src/runtime/agent/orchestrator/tools/lib/shell-warm-standby.mjs +26 -4
- package/src/runtime/channels/lib/webhook/signature.mjs +4 -1
- package/src/runtime/channels/lib/whisper-port.mjs +10 -1
- package/src/runtime/computer-bridge/action-schema.mjs +2 -2
- package/src/runtime/computer-bridge/core-actions.mjs +2 -2
- package/src/runtime/computer-bridge/error-recovery.mjs +5 -4
- package/src/runtime/computer-bridge/linux-action-capabilities.mjs +24 -5
- package/src/runtime/computer-bridge/linux-readiness.d.mts +7 -2
- package/src/runtime/local-provider/server-process.mjs +2 -1
- package/src/runtime/media/adapters/gemini-video.mjs +4 -1
- package/src/runtime/media/adapters/xai-media.mjs +2 -1
- package/src/runtime/memory/lib/embedding-worker.mjs +6 -3
- package/src/runtime/memory/lib/memory-action-handlers/cycle-backfill-action.mjs +1 -7
- package/src/runtime/memory/lib/memory-chunk-quality.mjs +1 -6
- package/src/runtime/office/authoring/pdf-author-action.mjs +1 -6
- package/src/runtime/office/design/design-art-direction.mjs +29 -27
- package/src/runtime/office/pdf/pdf-writer.mjs +6 -1
- package/src/runtime/office/portable/portable-snapshot-docx.mjs +7 -1
- package/src/runtime/office/portable/portable-snapshot-shared.mjs +6 -1
- package/src/runtime/office/quality/assurance-rendered.mjs +9 -2
- package/src/runtime/office/quality/assurance-structure-docx.mjs +3 -1
- package/src/runtime/office/quality/design-review.mjs +1 -5
- package/src/runtime/office/quality/document-brief.mjs +1 -5
- package/src/runtime/office/quality/forced-break-pages.mjs +9 -6
- package/src/runtime/office/quality/quality-pipeline.mjs +1 -1
- package/src/runtime/shared/bot-owned-work.mjs +56 -0
- package/src/runtime/shared/defaults-separation.mjs +1 -4
- package/src/runtime/shared/fetch-safe-listen.d.mts +16 -0
- package/src/runtime/shared/fetch-safe-listen.mjs +50 -0
- package/src/runtime/shared/handoff-artifacts.d.mts +2 -1
- package/src/runtime/shared/handoff-artifacts.mjs +18 -8
- package/src/runtime/shared/idle-auto-clear-gate.mjs +29 -7
- package/src/runtime/shared/llm/cost.mjs +5 -1
- package/src/runtime/shared/loopback-listener.mjs +25 -2
- package/src/runtime/shared/model-route-chain.d.mts +7 -2
- package/src/runtime/shared/model-route-chain.mjs +22 -4
- package/src/runtime/shared/open-url.mjs +10 -0
- package/src/runtime/shared/session-activity-signal.mjs +14 -0
- package/src/runtime/shared/session-scratch.mjs +37 -0
- package/src/runtime/shared/tool-card-model/agent-surface.mjs +1 -3
- package/src/runtime/shared/tool-card-model/card-status.mjs +15 -2
- package/src/runtime/shared/tool-result-summary.mjs +1 -1
- package/src/runtime/shared/tool-surface.mjs +3 -0
- package/src/runtime/shared/tool-work-units.mjs +2 -0
- package/src/runtime/shared/turn-snapshot-store.mjs +13 -6
- package/src/runtime/shared/worktrees/contract.mjs +4 -1
- package/src/runtime/shared/worktrees/git.mjs +15 -0
- package/src/runtime/shared/worktrees/manager.mjs +87 -38
- package/src/runtime/shared/worktrees/test-support.mjs +6 -10
- package/src/runtime/visualize-bridge/client.mjs +2 -0
- package/src/session-runtime/agent-home-delivery.mjs +41 -0
- package/src/session-runtime/agent-task-sessions.mjs +152 -63
- package/src/session-runtime/agent-tool-routing.mjs +8 -41
- package/src/session-runtime/boot/tools.mjs +5 -1
- package/src/session-runtime/bot-status.mjs +12 -6
- package/src/session-runtime/bot-target.mjs +38 -0
- package/src/session-runtime/channel-config-api.mjs +6 -1
- package/src/session-runtime/conversation-import/codex-titles.mjs +88 -0
- package/src/session-runtime/conversation-import/discovery.mjs +271 -25
- package/src/session-runtime/conversation-import/service.mjs +26 -5
- package/src/session-runtime/handoff-attachments.mjs +82 -31
- package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +12 -13
- package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +1 -0
- package/src/session-runtime/internal-tool-executor/reaction-tool.mjs +4 -1
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +8 -2
- package/src/session-runtime/lifecycle/cold-heir.mjs +11 -6
- package/src/session-runtime/lifecycle/session-catalog.mjs +9 -1
- package/src/session-runtime/model-route/set-route.mjs +11 -2
- package/src/session-runtime/provider-catalog-cache.mjs +82 -36
- package/src/session-runtime/provider-models/catalog-load.mjs +23 -6
- package/src/session-runtime/provider-models.mjs +4 -2
- package/src/session-runtime/resource-recall-api.mjs +6 -1
- package/src/session-runtime/runtime-feature-gates.mjs +5 -1
- package/src/session-runtime/services/agent-tool/execute.mjs +14 -9
- package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +20 -4
- package/src/session-runtime/services/agent-tool/model-select.mjs +48 -7
- package/src/session-runtime/services/agent-tool/render.mjs +71 -17
- package/src/session-runtime/services/agent-tool/spawn-preset.mjs +6 -2
- package/src/session-runtime/services/agent-tool/tool-def.mjs +9 -9
- package/src/session-runtime/services/provider-admin.mjs +2 -1
- package/src/session-runtime/tool-policy/policy-stage.mjs +1 -0
- package/src/session-runtime/workflow-agents-api/agent-editor.mjs +5 -1
- package/src/session-runtime/workflow-agents-api/agent-route.mjs +15 -4
- package/src/session-runtime/workflow-agents-api/onboarding.mjs +3 -3
- package/src/session-runtime/workspace/transitions.mjs +25 -0
- package/src/session-runtime/workspace/worktree-tool.mjs +26 -9
- package/src/standalone/daemon-session-control.mjs +18 -2
- package/src/standalone/session-service/agent-tree/agent-turns.mjs +16 -12
- package/src/standalone/session-service/session-calls/session-action.mjs +10 -3
- package/src/standalone/session-transport/client-registry/client-grace.mjs +12 -9
- package/src/tui/app/app-view/floating-panel.jsx +7 -4
- package/src/tui/app/model-picker/route-selection/fast-parameters.mjs +1 -3
- package/src/tui/app/model-picker/route-selection.mjs +5 -6
- package/src/tui/app/provider-setup/oauth-actions.mjs +38 -20
- package/src/tui/app/provider-setup/provider-items.mjs +8 -2
- package/src/tui/app/provider-setup-picker.mjs +9 -5
- package/src/tui/components/QuestionPanel.jsx +13 -4
- package/src/tui/dist/index.mjs +75 -28
- package/src/tui/session/session-flow/queue/take-entries.mjs +11 -0
- package/src/ui/statusline-agents.mjs +1 -3
|
@@ -8,6 +8,8 @@ dependencies:
|
|
|
8
8
|
tools:
|
|
9
9
|
- type: tool
|
|
10
10
|
value: browser
|
|
11
|
+
- type: tool
|
|
12
|
+
value: handoff_user
|
|
11
13
|
---
|
|
12
14
|
|
|
13
15
|
# Browser Use
|
|
@@ -170,7 +172,7 @@ not as two blocks joined.
|
|
|
170
172
|
a submitted form's result.
|
|
171
173
|
- **Handoff** — the user must act on the page: payment, approval, or an
|
|
172
174
|
unfinished workflow they continue. A sign-in, CAPTCHA or 2FA step you
|
|
173
|
-
wait on is
|
|
175
|
+
wait on is a `handoff_user` takeover instead (User step mid-flow).
|
|
174
176
|
- `open` replies with exactly one placement: "Shown in the browser panel",
|
|
175
177
|
"Not on screen yet" (this conversation or its panel is not visible; the
|
|
176
178
|
page appears when the user opens it), or an error. Tell the user that and
|
|
@@ -200,12 +202,12 @@ not as two blocks joined.
|
|
|
200
202
|
pages.
|
|
201
203
|
- **User step mid-flow** — a CAPTCHA or human check, 2FA, or identity check is
|
|
202
204
|
a handoff, not completion (an e-mail check of a flow you started is not one:
|
|
203
|
-
E-mail verification). With `
|
|
205
|
+
E-mail verification). With `handoff_user`, call it with `handoff: { kind:
|
|
204
206
|
'takeover', surface: 'browser', tab, instructions, need }`: it shows the
|
|
205
207
|
takeover card, notifies the user, opens that page beside the chat, and
|
|
206
208
|
returns when they press Done; continue from a fresh observation. Never ask
|
|
207
209
|
for the step in plain chat or tell the user to open the panel. Without
|
|
208
|
-
`
|
|
210
|
+
`handoff_user` (an agent), retain the page with `open`, report the required
|
|
209
211
|
user action, and stop.
|
|
210
212
|
- Preserve pre-existing user tabs, unfinished forms, and pages needed for
|
|
211
213
|
recovery. If ownership or disposability is unclear, preserve the page;
|
|
@@ -383,7 +385,7 @@ in the page instead of retrying the same `navigate`.
|
|
|
383
385
|
`MIXDOG_BROWSER_CONFIRM_ACTIONS` and
|
|
384
386
|
`MIXDOG_BROWSER_DENY_ACTIONS` optionally name comma-separated public actions
|
|
385
387
|
(or `*`) the desktop app confirms once or refuses; denial takes precedence.
|
|
386
|
-
- For a password or token, focus the field and call `
|
|
388
|
+
- For a password or token, focus the field and call `handoff_user` with
|
|
387
389
|
`handoff: { kind: 'secret', surface: 'browser' }`; for sign-in, CAPTCHA or
|
|
388
390
|
2FA use `kind: 'takeover'` with instructions. Never ask for secrets or
|
|
389
391
|
these steps in plain chat.
|
|
@@ -8,6 +8,8 @@ dependencies:
|
|
|
8
8
|
tools:
|
|
9
9
|
- type: tool
|
|
10
10
|
value: computer
|
|
11
|
+
- type: tool
|
|
12
|
+
value: handoff_user
|
|
11
13
|
---
|
|
12
14
|
|
|
13
15
|
# Computer Use
|
|
@@ -241,9 +243,9 @@ your results and that browser's pixels are withheld until this turn ends
|
|
|
241
243
|
(`ax` reads still work), but a page that redisplays it can expose it, and other
|
|
242
244
|
programs of the same Windows user are outside this protection. A username is
|
|
243
245
|
an identifier and is not hidden. Continue with keys (`act` key Enter). On a
|
|
244
|
-
refusal, hand the secret to the user (`
|
|
246
|
+
refusal, hand the secret to the user (`handoff_user` kind `secret`,
|
|
245
247
|
surface `computer`); one-time codes, passkeys, security keys and app approvals
|
|
246
|
-
are the user's step (`
|
|
248
|
+
are the user's step (`handoff_user` kind `takeover`). Never type a password or
|
|
247
249
|
code with `type`/`set_value`, even one shown on screen.
|
|
248
250
|
|
|
249
251
|
**Keyboard-driven navigation** — `act` with `key` steps such as `ctrl+s`
|
|
@@ -126,7 +126,10 @@ function buildProfilePreferencesContent(dataDir) {
|
|
|
126
126
|
return lines.length ? `# Profile Preferences\n\n${lines.join('\n')}` : '';
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
-
|
|
129
|
+
// `sharedFormatActive`: the prompt carries the shared Output Format partial,
|
|
130
|
+
// which already keeps literals verbatim (common.md), so the language block
|
|
131
|
+
// need not repeat it.
|
|
132
|
+
function buildLanguageSection(dataDir, sharedFormatActive = false) {
|
|
130
133
|
const profile = normalizeProfileConfig(readAgentConfig(dataDir).profile);
|
|
131
134
|
const language = profileLanguagePrompt(profile.language);
|
|
132
135
|
if (!language?.prompt) return '';
|
|
@@ -139,7 +142,7 @@ function buildLanguageSection(dataDir) {
|
|
|
139
142
|
// mistranslate, so the two clauses would be dead text.
|
|
140
143
|
if (language.prompt !== 'English') {
|
|
141
144
|
lines.push(
|
|
142
|
-
`- Preserve identifiers, paths, commands, API names, and exact errors. Keep technical terms in their established form, usually the original English (blocker, cache, commit); add a short plain explanation only when the reader may not know it. Never invent a literal translation.`
|
|
145
|
+
`- ${sharedFormatActive ? '' : 'Preserve identifiers, paths, commands, API names, and exact errors. '}Keep technical terms in their established form, usually the original English (blocker, cache, commit); add a short plain explanation only when the reader may not know it. Never invent a literal translation.`
|
|
143
146
|
);
|
|
144
147
|
}
|
|
145
148
|
return `# Language\n\n${lines.join('\n')}`;
|
|
@@ -153,7 +156,9 @@ function stripFrontmatter(markdown) {
|
|
|
153
156
|
|
|
154
157
|
// Tool dependency is declared as metadata, not matched against prose. A
|
|
155
158
|
// `<!-- tools: a, b -->` marker binds the block that follows it: the block
|
|
156
|
-
// survives while any listed tool is permitted by the allow/deny policy.
|
|
159
|
+
// survives while any listed tool is permitted by the allow/deny policy. The
|
|
160
|
+
// pseudo-entry `lead` is not a tool: it is permitted for every non-agent
|
|
161
|
+
// session (whatever its tool profile) and never for an agent-owned one.
|
|
157
162
|
// Unspecified allowlists are unrestricted. Markers never reach the model.
|
|
158
163
|
const TOOL_MARKER_RE = /^[ \t]*<!--[ \t]*tools:[ \t]*([^>]*?)[ \t]*-->[ \t]*$/;
|
|
159
164
|
|
|
@@ -188,9 +193,10 @@ function omitKeySet(omitTools) {
|
|
|
188
193
|
}
|
|
189
194
|
|
|
190
195
|
/** Drop routing clauses for tools that are not on the session surface. */
|
|
191
|
-
function omitToolRoutes(text, omitTools = [], allowTools = null) {
|
|
196
|
+
function omitToolRoutes(text, omitTools = [], allowTools = null, ownerIsAgent = false) {
|
|
192
197
|
const deny = omitKeySet(omitTools);
|
|
193
198
|
const allow = Array.isArray(allowTools) ? omitKeySet(allowTools) : null;
|
|
199
|
+
const permitted = (name) => (name === 'lead' ? !ownerIsAgent : !deny.has(name) && (!allow || allow.has(name)));
|
|
194
200
|
const lines = String(text || '').split(/\r?\n/);
|
|
195
201
|
const kept = [];
|
|
196
202
|
let index = 0;
|
|
@@ -204,7 +210,7 @@ function omitToolRoutes(text, omitTools = [], allowTools = null) {
|
|
|
204
210
|
index += 1;
|
|
205
211
|
if (index >= lines.length) break;
|
|
206
212
|
const end = markedBlockEnd(lines, index);
|
|
207
|
-
if (!tools.length || tools.some(
|
|
213
|
+
if (!tools.length || tools.some(permitted)) {
|
|
208
214
|
kept.push(...lines.slice(index, end));
|
|
209
215
|
}
|
|
210
216
|
index = end;
|
|
@@ -252,22 +258,29 @@ function readSharedFormatPartial({ PLUGIN_ROOT, DATA_DIR }) {
|
|
|
252
258
|
);
|
|
253
259
|
}
|
|
254
260
|
|
|
255
|
-
function
|
|
261
|
+
function resolveOutputStyle({ PLUGIN_ROOT, DATA_DIR }) {
|
|
256
262
|
// Root `outputStyle` is the only configured location; the retired
|
|
257
263
|
// `agent.outputStyle` key is dropped by config canonicalization.
|
|
258
264
|
const configured = String(readUnifiedConfig(DATA_DIR).outputStyle || '').trim() || DEFAULT_OUTPUT_STYLE_ID;
|
|
259
265
|
const styles = listOutputStyleEntries({ PLUGIN_ROOT, DATA_DIR });
|
|
260
266
|
const style = matchOutputStyle(configured, styles) || matchOutputStyle(DEFAULT_OUTPUT_STYLE_ID, styles) || styles[0];
|
|
261
|
-
if (!style) return
|
|
267
|
+
if (!style) return null;
|
|
262
268
|
const selected = stripFrontmatter(style.raw);
|
|
263
|
-
if (!selected) return
|
|
269
|
+
if (!selected) return null;
|
|
264
270
|
const common = style.keepSharedFormat ? readSharedFormatPartial({ PLUGIN_ROOT, DATA_DIR }) : '';
|
|
271
|
+
return { style, selected, common };
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function loadOutputStyle(paths) {
|
|
275
|
+
const resolved = resolveOutputStyle(paths);
|
|
276
|
+
if (!resolved) return '';
|
|
277
|
+
const { style, selected, common } = resolved;
|
|
265
278
|
return [`# Output Style: ${style.label}`, OUTPUT_STYLE_ANCHOR, common, selected].filter(Boolean).join('\n\n');
|
|
266
279
|
}
|
|
267
280
|
|
|
268
|
-
function buildSharedToolContent({ PLUGIN_ROOT, omitTools = [], allowTools = null } = {}) {
|
|
281
|
+
function buildSharedToolContent({ PLUGIN_ROOT, omitTools = [], allowTools = null, ownerIsAgent = false } = {}) {
|
|
269
282
|
const SHARED_DIR = path.join(PLUGIN_ROOT, 'rules', 'shared');
|
|
270
|
-
return omitToolRoutes(readMarkdownDirectory(SHARED_DIR), omitTools, allowTools);
|
|
283
|
+
return omitToolRoutes(readMarkdownDirectory(SHARED_DIR), omitTools, allowTools, ownerIsAgent);
|
|
271
284
|
}
|
|
272
285
|
|
|
273
286
|
// Route policy: `rules/routes/*.md` files bound to a provider and/or model
|
|
@@ -444,8 +457,12 @@ function buildLeadMetaContent({ PLUGIN_ROOT, DATA_DIR, includeOutputStyle = true
|
|
|
444
457
|
* preamble and progress lines follow the most recent instruction, so nothing
|
|
445
458
|
* English (session/shell/git lines included) may trail it.
|
|
446
459
|
*/
|
|
447
|
-
function buildLeadLanguageContent({ DATA_DIR }) {
|
|
448
|
-
|
|
460
|
+
function buildLeadLanguageContent({ PLUGIN_ROOT, DATA_DIR, includeOutputStyle = true }) {
|
|
461
|
+
const resolved = includeOutputStyle ? resolveOutputStyle({ PLUGIN_ROOT, DATA_DIR }) : null;
|
|
462
|
+
// Only the shipped partial is known to keep literals verbatim; a user
|
|
463
|
+
// override of common.md may not, so it keeps the language guard.
|
|
464
|
+
const shipped = stripFrontmatter(readOptional(path.join(PLUGIN_ROOT, 'output-styles', 'common.md')));
|
|
465
|
+
return buildLanguageSection(DATA_DIR, Boolean(shipped) && resolved?.common === shipped);
|
|
449
466
|
}
|
|
450
467
|
|
|
451
468
|
/** The configured response language as {id, name} (name = the language block's); null when none. */
|
|
@@ -13,8 +13,8 @@ partial: true
|
|
|
13
13
|
- Distinguish facts, inference, and uncertainty; keep exact literals and
|
|
14
14
|
material risks. Caveats only when they change the reader's next step.
|
|
15
15
|
- Show only what the reader needs: the decision, the result, the blocker, and
|
|
16
|
-
the action. No tangents, raw dumps, or process narration.
|
|
17
|
-
|
|
16
|
+
the action. No tangents, raw dumps, or process narration. Depth
|
|
17
|
+
applies to substantive answers, not the one-line
|
|
18
18
|
pre-tool briefing.
|
|
19
19
|
- At every depth keep decision-relevant failures, security warnings, and
|
|
20
20
|
destructive-action confirmations; quote needed error text exactly.
|
|
@@ -7,7 +7,7 @@ aliases: default, concise, handoff
|
|
|
7
7
|
|
|
8
8
|
## Depth
|
|
9
9
|
|
|
10
|
-
- Give a self-contained summary: the
|
|
10
|
+
- Give a self-contained summary: the core causal
|
|
11
11
|
sequence, the strongest evidence, and the direct consequence or next step.
|
|
12
12
|
- Omit secondary evidence, implementation detail, and extended examples
|
|
13
13
|
unless requested.
|
package/src/rules/agent/AGENT.md
CHANGED
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
- Reporting: send one final message, then stop; never ask whether to
|
|
16
16
|
continue. Start with `Status: done|partial|blocked`, then:
|
|
17
17
|
Result: the answer or outcome, mapped to the brief's done-when.
|
|
18
|
-
Evidence: path+symbol and checks
|
|
19
|
-
Open: risks, gaps, or the blocker.
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
Evidence: path+symbol and checks with outcomes (failures: decisive error
|
|
19
|
+
only), not a retelling of Result. Open: risks, gaps, or the blocker.
|
|
20
|
+
State each fact once; explain a choice only where it departs from the
|
|
21
|
+
brief. Omit empty fields; no logs, narration, nested headings or restated
|
|
22
|
+
brief. Role contracts only add fields. Lead owns the independent review.
|
package/src/rules/lead/LEAD.md
CHANGED
|
@@ -19,11 +19,16 @@
|
|
|
19
19
|
- Be a grounded, candid, and attentive collaborator: natural and respectful,
|
|
20
20
|
without flattery, forced humor, mimicry, or stereotyping.
|
|
21
21
|
<!-- tools: agent -->
|
|
22
|
-
- Briefing an agent: one self-contained English brief with goal and
|
|
23
|
-
owned paths, non-goals
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
- Briefing an agent: one self-contained English brief with the goal and the
|
|
23
|
+
context it needs, owned paths, non-goals, constraints the agent does not
|
|
24
|
+
already receive, and done-when; a running agent gets only changes.
|
|
25
|
+
Done-when is the end state of the product or answer, never a list of
|
|
26
|
+
checks: name no tools, steps, commands or suites; the agent's own rules
|
|
27
|
+
choose its checks. A Reviewer gets the diff scope, the acceptance criteria
|
|
28
|
+
and the author's Evidence verbatim, not the whole report, so passed checks
|
|
29
|
+
are not rerun; a re-review carries only the fixes. Reference evidence by
|
|
30
|
+
path instead of retelling it. Decide first; send scope changes as one
|
|
31
|
+
replacement brief; invent no other restrictions or copies.
|
|
27
32
|
<!-- tools: agent -->
|
|
28
33
|
- Reports arrive as `<task-notification>`: never wait, poll or guess them;
|
|
29
34
|
do independent work and end the turn. On an agent report, each feature
|
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
has its evidence; never widen past what was asked, and never ask
|
|
9
9
|
permission for work the request already covers.
|
|
10
10
|
- When blocked, first look for a workaround you can carry out yourself with
|
|
11
|
-
the available tools
|
|
11
|
+
the available tools.
|
|
12
|
+
<!-- tools: lead -->
|
|
13
|
+
Ask the user only when none exists.
|
|
12
14
|
- Do not add work whose need depends on a pending result. Reuse content
|
|
13
15
|
already delivered; changed sources and omitted ranges are new evidence.
|
|
14
16
|
Trust documented guarantees; no availability checks or defensive branches —
|
|
@@ -7,8 +7,6 @@
|
|
|
7
7
|
files you did not create: it may hold other agents' or the user's
|
|
8
8
|
uncommitted work. Use a copy or managed snapshot for before/after
|
|
9
9
|
comparisons.
|
|
10
|
-
- Worktrees live only in the app-managed store; never create one through
|
|
11
|
-
shell or in a temp folder.
|
|
12
10
|
<!-- tools: git -->
|
|
13
11
|
- Separate-branch work goes into a managed worktree through `git`.
|
|
14
12
|
- Back up only when changes risk irreversible loss, not for routine code edits;
|
|
@@ -4,4 +4,6 @@
|
|
|
4
4
|
data transformation, generated output, unsupported-format decoding. An open
|
|
5
5
|
shell is never a routing reason.
|
|
6
6
|
- Structured service operations go through the service's MCP tool or CLI.
|
|
7
|
+
- Open no window, dialog or elevation prompt unless showing or operating
|
|
8
|
+
that UI is the task.
|
|
7
9
|
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
# Delivery
|
|
2
2
|
|
|
3
3
|
- Unless the user explicitly requests them, do not author separate record-keeping
|
|
4
|
-
artifacts (reports, progress logs, notes, or checklists).
|
|
5
|
-
|
|
4
|
+
artifacts (reports, progress logs, notes, or checklists).
|
|
5
|
+
<!-- tools: lead -->
|
|
6
|
+
Report progress and results in the conversation instead.
|
|
6
7
|
- Reference files and folders in inline code by a Project-root-relative or
|
|
7
8
|
absolute path, optionally `:line[:column]` (`deliverables/report.docx`,
|
|
8
9
|
`src/app.ts:42`); files outside the Project always by absolute path; never a
|
|
@@ -11,14 +12,11 @@
|
|
|
11
12
|
and give their path; never open them in the system browser or paste their
|
|
12
13
|
source unless the user asks.
|
|
13
14
|
<!-- tools: visualize -->
|
|
14
|
-
-
|
|
15
|
-
|
|
16
|
-
plans
|
|
17
|
-
|
|
15
|
+
- Show every finished visual artifact with `visualize open`, loading its schema
|
|
16
|
+
first if deferred: images, video, HTML, documents, decks, mockups, diagrams,
|
|
17
|
+
plans; comparisons or research tables go in a visualize page. Keep the chat
|
|
18
|
+
to a short summary.
|
|
18
19
|
|
|
19
20
|
<!-- tools: git -->
|
|
20
21
|
- A commit request includes selecting and staging its changes; a stage-only
|
|
21
22
|
request stops before commit. Do not stage changes without either request.
|
|
22
|
-
<!-- tools: git -->
|
|
23
|
-
- Stage selected diff changes with `git` using `action:"stage"`. Keep this
|
|
24
|
-
internal step within the requested commit workflow, not a separate approval.
|
|
@@ -243,11 +243,13 @@ export function resolveAgentWatchdogPolicy(agent, overrides = {}) {
|
|
|
243
243
|
// Role budget, floored so the provider recovery window always wins.
|
|
244
244
|
idleStaleMs = Math.max(abort * 1000, PROVIDER_RECOVERY_FLOOR_MS);
|
|
245
245
|
} else {
|
|
246
|
-
// Part B: the
|
|
247
|
-
//
|
|
248
|
-
//
|
|
249
|
-
//
|
|
250
|
-
//
|
|
246
|
+
// Part B: the provider-level idle abort is the first mid-stream catch, but
|
|
247
|
+
// it is transport-based for Anthropic (pings reset it; other providers
|
|
248
|
+
// judge semantic idle). This public-agent idle is a BACKSTOP only, so it
|
|
249
|
+
// must not exceed the stall abort (600s default) — the old 30-min value
|
|
250
|
+
// meant a ping-only wedge that slipped past the provider layer would still
|
|
251
|
+
// hang the owner for half an hour. Anthropic pings extend it only up to
|
|
252
|
+
// KEEPALIVE_MAX_IDLE_MULTIPLIER times (evaluateAgentWatchdogAbort). Cap it at
|
|
251
253
|
// the stall abort while keeping 30 min as an absolute ceiling. Long tool
|
|
252
254
|
// calls refresh progress through the activity heartbeat, so they never
|
|
253
255
|
// trip this backstop.
|
|
@@ -270,6 +272,23 @@ export function resolveAgentWatchdogPolicy(agent, overrides = {}) {
|
|
|
270
272
|
};
|
|
271
273
|
}
|
|
272
274
|
|
|
275
|
+
// How far keepalives may extend liveness past the last real progress, as a
|
|
276
|
+
// multiple of the idle budget. Anthropic pings across legitimate generation
|
|
277
|
+
// gaps (adaptive thinking, a buffered tool input), but a wedged stream that
|
|
278
|
+
// pings forever must still die.
|
|
279
|
+
export const KEEPALIVE_MAX_IDLE_MULTIPLIER = 3;
|
|
280
|
+
|
|
281
|
+
// A keepalive newer than the last real progress holds the idle abort while it
|
|
282
|
+
// is itself fresh and the silence is within the cap. The runtime records one
|
|
283
|
+
// only after the request's first semantic event, so a ping before it never
|
|
284
|
+
// reaches here (the first-output window owns that phase).
|
|
285
|
+
function keepaliveHoldsIdle(snapshot, last, now, idleStaleMs) {
|
|
286
|
+
const keepaliveAt = snapshot.lastKeepaliveAt || 0;
|
|
287
|
+
return (
|
|
288
|
+
keepaliveAt > last && now - keepaliveAt <= idleStaleMs && now - last <= idleStaleMs * KEEPALIVE_MAX_IDLE_MULTIPLIER
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
|
|
273
292
|
export function evaluateAgentWatchdogAbort(snapshot, now, policy) {
|
|
274
293
|
if (!snapshot || !policy) return null;
|
|
275
294
|
// A turn blocked on the user's tool approval (its own, or a sub-agent's that
|
|
@@ -285,7 +304,10 @@ export function evaluateAgentWatchdogAbort(snapshot, now, policy) {
|
|
|
285
304
|
const firstSemanticMs = policy.firstSemanticMs ?? policy.firstVisibleCeilingMs ?? 0;
|
|
286
305
|
// Independent fixed deadlines from request start. Transport can satisfy
|
|
287
306
|
// only the transport deadline; it never switches, extends, or resets the
|
|
288
|
-
// semantic-response deadline.
|
|
307
|
+
// semantic-response deadline. Both are judged per logical model request
|
|
308
|
+
// (runtime-liveness): the request that carries tool results gets the same
|
|
309
|
+
// first-output allowance as the turn's first request, while a retry of a
|
|
310
|
+
// request keeps that request's clock and marks.
|
|
289
311
|
if (snapshot.waitingForTransport && firstTransportMs > 0 && startedAt && now - startedAt > firstTransportMs) {
|
|
290
312
|
return new AgentStallAbortError(`agent first transport stale (${firstTransportMs}ms)`);
|
|
291
313
|
}
|
|
@@ -298,6 +320,7 @@ export function evaluateAgentWatchdogAbort(snapshot, now, policy) {
|
|
|
298
320
|
|
|
299
321
|
const last = snapshot.lastProgressAt || snapshot.firstActivityAt;
|
|
300
322
|
if (policy.idleStaleMs > 0 && last && now - last > policy.idleStaleMs) {
|
|
323
|
+
if (keepaliveHoldsIdle(snapshot, last, now, policy.idleStaleMs)) return null;
|
|
301
324
|
return new AgentStallAbortError(`agent task stale (${policy.idleStaleMs}ms without stream/tool progress)`);
|
|
302
325
|
}
|
|
303
326
|
|
|
@@ -53,6 +53,7 @@ export function buildCacheBreakPayload(record = {}) {
|
|
|
53
53
|
input_prefix_mismatch_actual_hash: cleanHash(record.inputPrefixMismatchActualHash),
|
|
54
54
|
changed_blocks: cleanText(record.changedBlocks),
|
|
55
55
|
system_markers_changed: typeof record.markersChanged === 'boolean' ? record.markersChanged : null,
|
|
56
|
+
lost_message_breakpoints: cleanText(record.lostMessageBreakpoints),
|
|
56
57
|
};
|
|
57
58
|
return Object.fromEntries(Object.entries(payload).filter(([, value]) => value !== null));
|
|
58
59
|
}
|
|
@@ -81,6 +82,7 @@ function formatCacheBreakLine(record = {}) {
|
|
|
81
82
|
['noGuardBaseline', payload.missing_prefix_guard_baseline],
|
|
82
83
|
['changedBlocks', payload.changed_blocks],
|
|
83
84
|
['systemMarkersChanged', payload.system_markers_changed],
|
|
85
|
+
['lostMessageBreakpoints', payload.lost_message_breakpoints],
|
|
84
86
|
].filter(([, value]) => value !== null && value !== undefined);
|
|
85
87
|
return `[cache-break] ${fields.map(([key, value]) => (typeof value === 'string' ? `${key}=${JSON.stringify(value)}` : `${key}=${value}`)).join(' ')}`;
|
|
86
88
|
}
|
|
@@ -100,7 +100,7 @@ export function buildDeferredToolManifest(entries) {
|
|
|
100
100
|
list.sort((a, b) => a.name.localeCompare(b.name));
|
|
101
101
|
return [
|
|
102
102
|
'<available-deferred-tools>',
|
|
103
|
-
'Deferred
|
|
103
|
+
'Deferred tools; load_tool loads their schemas.',
|
|
104
104
|
...list.map((entry) => (entry.description ? `- ${entry.name}: ${entry.description}` : `- ${entry.name}`)),
|
|
105
105
|
'</available-deferred-tools>',
|
|
106
106
|
].join('\n');
|
|
@@ -669,7 +669,9 @@ export function buildSkillManifest(skills, { limit = 80, charBudget = SKILL_MANI
|
|
|
669
669
|
for (const skill of visible) skill.trigger = compactPromptManifestText(skill.trigger, triggerCap);
|
|
670
670
|
const lines = [
|
|
671
671
|
'# available-skills',
|
|
672
|
-
|
|
672
|
+
visible.some((skill) => skill.linkedTools.some((tool) => tool.startsWith('mcp:')))
|
|
673
|
+
? 'Selection triggers and linked tools. mcp:<server> denotes that server’s tools.'
|
|
674
|
+
: 'Selection triggers and linked tools.',
|
|
673
675
|
'<available_skills>',
|
|
674
676
|
...visible.map(
|
|
675
677
|
(skill) => (skill.trigger ? `- ${skill.name}: ${skill.trigger}` : `- ${skill.name}`) + toolSuffix(skill)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createServer } from 'node:http';
|
|
2
|
+
import { listenOnFetchSafePort } from '../../../shared/fetch-safe-listen.mjs';
|
|
2
3
|
import { randomBytes } from 'node:crypto';
|
|
3
4
|
import { normalizeMcpTransportUrl } from './client-config.mjs';
|
|
4
5
|
import { identityFromTokenResponse } from './oauth-account.mjs';
|
|
@@ -48,8 +49,10 @@ export function createLoginFlow({ url, cache, flow, provider, lifetimeSignal, op
|
|
|
48
49
|
await new Promise((resolve, reject) => {
|
|
49
50
|
flow.listener.once('error', reject);
|
|
50
51
|
// Retain the registered redirect URI if this connection later needs
|
|
51
|
-
// refresh or reauthorization; never register a different callback.
|
|
52
|
-
|
|
52
|
+
// refresh or reauthorization; never register a different callback. A new
|
|
53
|
+
// one is a port the browser can be redirected to.
|
|
54
|
+
if (creds.redirectUrl) flow.listener.listen(Number(new URL(creds.redirectUrl).port), '127.0.0.1', resolve);
|
|
55
|
+
else listenOnFetchSafePort(flow.listener, '127.0.0.1', resolve);
|
|
53
56
|
});
|
|
54
57
|
creds.redirectUrl = `http://127.0.0.1:${flow.listener.address().port}/oauth/callback`;
|
|
55
58
|
}
|
|
@@ -244,6 +244,17 @@ function sessionAccountId(providerName, key, messages, options) {
|
|
|
244
244
|
return null;
|
|
245
245
|
}
|
|
246
246
|
|
|
247
|
+
/** The account a send of `model` for `sessionId` would try first right now —
|
|
248
|
+
* the session's binding and the choice poolSend makes for its first attempt
|
|
249
|
+
* — or null when the provider has no roster account or none is eligible. */
|
|
250
|
+
export function plannedAccountId(providerName, { sessionId = null, messages = [], providerState, model = '' } = {}) {
|
|
251
|
+
const pool = readProviderAccountPool(providerName);
|
|
252
|
+
if (!pool.accounts.length) return null;
|
|
253
|
+
const sessionKey = sessionId ? `${providerName}:${sessionId}` : null;
|
|
254
|
+
const boundId = sessionAccountId(providerName, sessionKey, messages, { providerState });
|
|
255
|
+
return chooseProviderAccount(pool, new Set(), Date.now(), model, { sessionAccountId: boundId })?.id || null;
|
|
256
|
+
}
|
|
257
|
+
|
|
247
258
|
// Stamp the serving account on the answer, independent of transport state,
|
|
248
259
|
// with the account the session stays bound to (`bindingId`).
|
|
249
260
|
function recordServingAccount(providerName, result, id, bindingId) {
|
|
@@ -52,7 +52,7 @@ export function createAnthropicApiRecovery({
|
|
|
52
52
|
: PROVIDER_NONSTREAM_TOTAL_TIMEOUT_MS;
|
|
53
53
|
const lifetime = createTimeoutSignal(totalSignal, timeoutMs, `${label} Anthropic non-streaming fallback`);
|
|
54
54
|
try {
|
|
55
|
-
const message = await transport.requestNonStreamingMessage(nonStreamingParams, lifetime.signal);
|
|
55
|
+
const message = await transport.requestNonStreamingMessage(nonStreamingParams, lifetime.signal, timeoutMs);
|
|
56
56
|
return buildTurnResult(normalizeAnthropicNonStreamingResponse(message, useModel));
|
|
57
57
|
} catch (error) {
|
|
58
58
|
if (error instanceof AnthropicFallbackTriggeredError || totalSignal?.aborted) throw error;
|
|
@@ -10,7 +10,11 @@
|
|
|
10
10
|
* anthropic-turn-result.mjs); nothing here touches the socket.
|
|
11
11
|
*/
|
|
12
12
|
import { prepareAnthropicImages } from './lib/anthropic-image-input.mjs';
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
anthropicPrefixFingerprint,
|
|
15
|
+
anthropicPrefixSessionId,
|
|
16
|
+
recordAnthropicPrefix,
|
|
17
|
+
} from './lib/anthropic-prefix-trace.mjs';
|
|
14
18
|
import { buildAnthropicBetaHeaders, supportsAnthropicFastMode } from './anthropic-betas.mjs';
|
|
15
19
|
import { applyAnthropicServerFallback } from './anthropic-server-fallback.mjs';
|
|
16
20
|
import { fastModeAvailable } from './anthropic-fast-mode.mjs';
|
|
@@ -93,7 +97,7 @@ export async function buildAnthropicApiRequest({
|
|
|
93
97
|
// Tools are resolved BEFORE the messages: the lowering needs the final
|
|
94
98
|
// tool list to drop tool_reference blocks whose tool no longer ships
|
|
95
99
|
// in this request (otherwise the API rejects the whole turn).
|
|
96
|
-
const requestTools = requestAnthropicTools(tools, chatMsgs, opts, name);
|
|
100
|
+
const requestTools = requestAnthropicTools(tools, chatMsgs, opts, name, config);
|
|
97
101
|
// Message-tail cache budget (4-BP layout + ANTHROPIC_MSG_SLOTS) is
|
|
98
102
|
// shared with anthropic-oauth — see resolveAnthropicMessageCacheSlots.
|
|
99
103
|
const messageCacheSlots = resolveAnthropicMessageCacheSlots(systemBlocks, ttls, { tools: requestTools });
|
|
@@ -183,7 +187,7 @@ export async function buildAnthropicApiRequest({
|
|
|
183
187
|
// (once) → mark → prepare image bytes → send.
|
|
184
188
|
params.stream = true;
|
|
185
189
|
// Diagnostic: per-block prefix hashes of exactly what is sent.
|
|
186
|
-
recordAnthropicPrefix(opts
|
|
190
|
+
recordAnthropicPrefix(anthropicPrefixSessionId(opts), anthropicPrefixFingerprint(params));
|
|
187
191
|
|
|
188
192
|
const requestHeaders = requestHeadersFor(params, {
|
|
189
193
|
config,
|
|
@@ -215,12 +215,18 @@ export function createAnthropicApiTransport({
|
|
|
215
215
|
}
|
|
216
216
|
};
|
|
217
217
|
|
|
218
|
-
|
|
218
|
+
// `timeoutMs` is the replay's own lifetime, handed to the SDK as the request
|
|
219
|
+
// timeout: without an explicit one the SDK refuses any stream:false body
|
|
220
|
+
// whose max_tokens it estimates past 10 minutes before sending it.
|
|
221
|
+
const requestNonStreamingMessage = (nonStreamingParams, signal, timeoutMs) =>
|
|
219
222
|
withRetry(
|
|
220
223
|
withBodyRecovery(nonStreamingParams, async ({ signal: attemptSignal }) => {
|
|
221
224
|
noteRequestServiceTier(nonStreamingParams.speed);
|
|
222
225
|
try {
|
|
223
|
-
return await client.messages.create(nonStreamingParams,
|
|
226
|
+
return await client.messages.create(nonStreamingParams, {
|
|
227
|
+
...requestOptions(attemptSignal),
|
|
228
|
+
timeout: timeoutMs,
|
|
229
|
+
});
|
|
224
230
|
} catch (err) {
|
|
225
231
|
throw annotateHttpFailure(err);
|
|
226
232
|
}
|
|
@@ -22,11 +22,15 @@ export function parseMaxTokensContextOverflow(status, message) {
|
|
|
22
22
|
const match = OVERFLOW_RE.exec(String(message || ''));
|
|
23
23
|
if (!match) return null;
|
|
24
24
|
const [inputTokens, maxTokens, contextLimit] = match.slice(1).map((value) => Number.parseInt(value, 10));
|
|
25
|
-
return [inputTokens, maxTokens, contextLimit].every(Number.isFinite)
|
|
25
|
+
return [inputTokens, maxTokens, contextLimit].every(Number.isFinite)
|
|
26
|
+
? { inputTokens, maxTokens, contextLimit }
|
|
27
|
+
: null;
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
const thinkingBudget = (body) =>
|
|
29
|
-
body?.thinking?.type === 'enabled' && Number(body.thinking.budget_tokens) > 0
|
|
31
|
+
body?.thinking?.type === 'enabled' && Number(body.thinking.budget_tokens) > 0
|
|
32
|
+
? Number(body.thinking.budget_tokens)
|
|
33
|
+
: 0;
|
|
30
34
|
|
|
31
35
|
/**
|
|
32
36
|
* Shrink `body.max_tokens` to fit the reported context. Returns true when the
|
|
@@ -159,8 +159,8 @@ function deferredAnthropicTools(activeTools, messages, opts, provider = 'anthrop
|
|
|
159
159
|
return sharedDeferredAnthropicTools(activeTools, messages, opts, provider);
|
|
160
160
|
}
|
|
161
161
|
// `provider`: the engine's name (a gateway Messages engine runs under its gateway's).
|
|
162
|
-
export function requestAnthropicTools(tools, messages, opts, provider = 'anthropic') {
|
|
163
|
-
return sharedRequestAnthropicTools(tools, messages, opts, provider);
|
|
162
|
+
export function requestAnthropicTools(tools, messages, opts, provider = 'anthropic', config = {}) {
|
|
163
|
+
return sharedRequestAnthropicTools(tools, messages, opts, provider, config);
|
|
164
164
|
}
|
|
165
165
|
// Test-only: expose the lowering so the steering-provenance test can assert
|
|
166
166
|
// the API-key provider keeps steering-tagged user turns distinct (mirrors
|
|
@@ -50,7 +50,9 @@ export function anthropicQuotaError(status, headers, bodyText = '') {
|
|
|
50
50
|
const detail = bodyText ? `: ${String(bodyText).slice(0, 200)}` : '';
|
|
51
51
|
const retry = retryAfter ? ` retryAfter=${retryAfter}` : '';
|
|
52
52
|
const quota = hasQuotaHeaders(headers);
|
|
53
|
-
const err = new Error(
|
|
53
|
+
const err = new Error(
|
|
54
|
+
`Anthropic OAuth API ${status} ${quota ? 'quota/rate limit' : 'request rejected'}${retry}${detail}`
|
|
55
|
+
);
|
|
54
56
|
err.name = quota ? 'ProviderQuotaError' : 'ProviderRequestRejectedError';
|
|
55
57
|
err.headers = headers;
|
|
56
58
|
err.response = { status, headers };
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import { traceAgentSse, traceAgentUsage } from '../agent-trace.mjs';
|
|
9
9
|
import {
|
|
10
10
|
anthropicPrefixFingerprint,
|
|
11
|
+
anthropicPrefixSessionId,
|
|
11
12
|
latestAnthropicPrefix,
|
|
12
13
|
recordAnthropicPrefix,
|
|
13
14
|
} from './lib/anthropic-prefix-trace.mjs';
|
|
@@ -555,7 +556,7 @@ export class AnthropicOAuthProvider {
|
|
|
555
556
|
const body = buildRequestBody(messages, useModel, tools, sendOpts);
|
|
556
557
|
body.messages = await prepareAnthropicImages(body.messages, { signal: externalSignal });
|
|
557
558
|
// Diagnostic: per-block prefix hashes of exactly what is sent.
|
|
558
|
-
recordAnthropicPrefix(opts
|
|
559
|
+
recordAnthropicPrefix(anthropicPrefixSessionId(opts), anthropicPrefixFingerprint(body));
|
|
559
560
|
if (body.speed === 'fast') {
|
|
560
561
|
this.fastModeBetaHeaderLatched = true;
|
|
561
562
|
}
|
|
@@ -652,6 +653,7 @@ export class AnthropicOAuthProvider {
|
|
|
652
653
|
iteration,
|
|
653
654
|
useModel,
|
|
654
655
|
requestKind: opts.requestKind || null,
|
|
656
|
+
prefixSessionId: anthropicPrefixSessionId(opts),
|
|
655
657
|
});
|
|
656
658
|
tagMidstreamRetries(result, attemptIndex);
|
|
657
659
|
return result;
|
|
@@ -887,7 +889,16 @@ export class AnthropicOAuthProvider {
|
|
|
887
889
|
}
|
|
888
890
|
|
|
889
891
|
// Traces + catalog upkeep for a streamed turn, then the empty-stream guard.
|
|
890
|
-
_settleStreamedTurn({
|
|
892
|
+
_settleStreamedTurn({
|
|
893
|
+
result,
|
|
894
|
+
midState,
|
|
895
|
+
sseStartedAt,
|
|
896
|
+
sessionId,
|
|
897
|
+
iteration,
|
|
898
|
+
useModel,
|
|
899
|
+
requestKind,
|
|
900
|
+
prefixSessionId,
|
|
901
|
+
}) {
|
|
891
902
|
const ttftMs = midState.ttftAt ? midState.ttftAt - sseStartedAt : null;
|
|
892
903
|
const liveModel = result.model || useModel;
|
|
893
904
|
traceAgentSse({
|
|
@@ -912,7 +923,7 @@ export class AnthropicOAuthProvider {
|
|
|
912
923
|
rawUsage: result.usage?.raw || null,
|
|
913
924
|
provider: 'anthropic-oauth',
|
|
914
925
|
requestKind,
|
|
915
|
-
prefixBlocks: latestAnthropicPrefix(
|
|
926
|
+
prefixBlocks: latestAnthropicPrefix(prefixSessionId),
|
|
916
927
|
});
|
|
917
928
|
|
|
918
929
|
// Phase I: if the live response surfaced a model id we don't know
|
|
@@ -161,6 +161,12 @@ function applyAnthropicSseEvent(framedEvent, { turn, watchdogs, state, progress,
|
|
|
161
161
|
return false;
|
|
162
162
|
case 'message_delta':
|
|
163
163
|
return turn.onMessageDelta(event);
|
|
164
|
+
case 'ping':
|
|
165
|
+
// Anthropic bridges long generation gaps (adaptive thinking, a buffered
|
|
166
|
+
// tool input) with `ping` events. A distinct kind, not 'semantic': the
|
|
167
|
+
// agent watchdog decides how far a keepalive may extend liveness.
|
|
168
|
+
progress('keepalive');
|
|
169
|
+
return false;
|
|
164
170
|
case 'message_stop':
|
|
165
171
|
turn.onMessageStop();
|
|
166
172
|
// Anthropic streams can keep emitting `:ping` keepalive frames after
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { traceAgentUsage } from '../agent-trace.mjs';
|
|
13
13
|
import { reportedCostUsd } from './lib/usage-primitives.mjs';
|
|
14
|
-
import { latestAnthropicPrefix } from './lib/anthropic-prefix-trace.mjs';
|
|
14
|
+
import { anthropicPrefixSessionId, latestAnthropicPrefix } from './lib/anthropic-prefix-trace.mjs';
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* @param {object} parseResult the assembled turn (streaming or normalized non-streaming)
|
|
@@ -48,7 +48,7 @@ export function buildAnthropicTurnResult(parseResult, { provider, useModel, opts
|
|
|
48
48
|
// Anthropic usage is additive at this inner transport
|
|
49
49
|
// boundary, even when OpenCode Go supplies the provider id.
|
|
50
50
|
inputTokensInclusive: false,
|
|
51
|
-
prefixBlocks: latestAnthropicPrefix(opts
|
|
51
|
+
prefixBlocks: latestAnthropicPrefix(anthropicPrefixSessionId(opts)),
|
|
52
52
|
});
|
|
53
53
|
}
|
|
54
54
|
|