mixdog 1.2.6 → 1.3.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/LICENSES/simple-icons-CC0-1.0.txt +30 -0
- package/NOTICE.md +71 -9
- package/package.json +4 -1
- package/scripts/check-model-recommendations.mjs +89 -0
- package/scripts/gate-local.mjs +7 -0
- package/scripts/lib/isolated-test-env.mjs +16 -0
- package/src/agents/reviewer/AGENT.md +4 -2
- package/src/agents/reviewer/agent.json +1 -1
- package/src/defaults/shipped-history.json +10 -0
- package/src/defaults/skills/browser-use/SKILL.md +5 -0
- package/src/defaults/skills/memory-management/SKILL.md +4 -1
- package/src/defaults/skills/setup/references/actions.md +14 -4
- package/src/defaults/skills/setup-guide/SKILL.md +178 -0
- package/src/defaults/skills/setup-guide/model-recommendations.json +333 -0
- package/src/lib/rules-builder.cjs +55 -6
- package/src/output-styles/common.md +13 -8
- package/src/rules/agent/AGENT.md +4 -0
- package/src/rules/agent-mode/AGENT_MODE.md +24 -0
- package/src/rules/agent-mode/MIXY.md +28 -0
- package/src/rules/agent-mode/ROUTINE.md +6 -0
- package/src/rules/lead/LEAD.md +7 -3
- package/src/rules/shared/70-delivery.md +3 -0
- package/src/runtime/agent/orchestrator/agent-runtime/room-supervisor-completion.mjs +86 -0
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +77 -14
- package/src/runtime/agent/orchestrator/context/role-instructions.mjs +241 -14
- package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +4 -2
- package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +216 -0
- package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +5 -4
- package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +10 -1
- package/src/runtime/agent/orchestrator/mcp/client.mjs +115 -11
- package/src/runtime/agent/orchestrator/mcp/oauth-account.mjs +97 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-client.mjs +49 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-credentials.mjs +59 -9
- package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +32 -7
- package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +45 -6
- package/src/runtime/agent/orchestrator/mcp/oauth.mjs +195 -6
- package/src/runtime/agent/orchestrator/mcp/server-connectors.mjs +17 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +7 -2
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-login.mjs +10 -3
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +4 -0
- package/src/runtime/agent/orchestrator/providers/auto-effort.mjs +7 -8
- package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/lib/tool-call-wire-ids.mjs +65 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-retry-profile.mjs +8 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +9 -2
- package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +17 -12
- package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +10 -0
- package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +14 -2
- package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +17 -0
- package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +96 -1
- package/src/runtime/agent/orchestrator/runtime-core/context-status-shape.mjs +4 -0
- package/src/runtime/agent/orchestrator/runtime-core/extension-scopes.mjs +6 -4
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +14 -0
- package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +1 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +12 -6
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +32 -5
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +21 -5
- package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +40 -7
- package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +52 -20
- package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/agent-home.d.mts +4 -0
- package/src/runtime/agent/orchestrator/session/agent-home.mjs +33 -0
- package/src/runtime/agent/orchestrator/session/agent-mode.mjs +62 -0
- package/src/runtime/agent/orchestrator/session/agent-room-supervisor.d.mts +31 -0
- package/src/runtime/agent/orchestrator/session/agent-room-supervisor.mjs +241 -0
- package/src/runtime/agent/orchestrator/session/agent-room.d.mts +166 -0
- package/src/runtime/agent/orchestrator/session/agent-room.mjs +650 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +7 -1
- package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +6 -2
- package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +192 -0
- package/src/runtime/agent/orchestrator/session/human-gate/held-message.mjs +95 -0
- package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +221 -0
- package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +195 -0
- package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +167 -0
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +9 -0
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +10 -0
- package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +108 -6
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +10 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +74 -15
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +9 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +5 -4
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +13 -3
- package/src/runtime/agent/orchestrator/session/loop/usage.mjs +49 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-commit.mjs +18 -8
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/manager/pending-lifecycle-epoch.mjs +0 -8
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +44 -16
- package/src/runtime/agent/orchestrator/session/manager/provider-replay.mjs +50 -0
- package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +22 -5
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +39 -4
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +33 -24
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +58 -8
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +16 -0
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +3 -2
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +7 -1
- package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/manager/workflow-switch-notice.mjs +58 -0
- package/src/runtime/agent/orchestrator/session/mixy-name.mjs +27 -0
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +32 -5
- package/src/runtime/agent/orchestrator/session/routine-result.d.mts +86 -0
- package/src/runtime/agent/orchestrator/session/routine-result.mjs +329 -0
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +8 -0
- package/src/runtime/agent/orchestrator/session/store-record-strict-scan.mjs +28 -9
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +16 -2
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +44 -12
- package/src/runtime/agent/orchestrator/session/store-summary-last-message.mjs +46 -0
- package/src/runtime/agent/orchestrator/session/store-summary-visibility.mjs +0 -4
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +58 -10
- package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +92 -15
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +12 -0
- package/src/runtime/agent/orchestrator/tools/builtin/native-search-client.mjs +113 -5
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +4 -0
- package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +25 -1
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +8 -0
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +6 -0
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +3 -0
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +75 -57
- package/src/runtime/attachments/store.mjs +6 -0
- package/src/runtime/browser-bridge/client.mjs +24 -0
- package/src/runtime/channels/lib/scheduler.mjs +40 -12
- package/src/runtime/channels/lib/schedules-db.mjs +71 -12
- package/src/runtime/channels/lib/webhook/session-dispatch.mjs +36 -16
- package/src/runtime/channels/lib/webhook.mjs +0 -1
- package/src/runtime/channels/lib/webhooks-db.mjs +100 -10
- package/src/runtime/channels/lib/worker-main.mjs +17 -20
- package/src/runtime/computer-bridge/client.mjs +28 -1
- package/src/runtime/connectors/gmail-app-password.mjs +690 -0
- package/src/runtime/connectors/google-mcp.mjs +446 -0
- package/src/runtime/effort-judge/judge-client.mjs +1 -1
- package/src/runtime/effort-judge/model-manifest.json +7 -7
- package/src/runtime/memory/lib/core-memory-access.mjs +69 -0
- package/src/runtime/memory/lib/core-memory-file.mjs +16 -8
- package/src/runtime/memory/lib/core-memory-index.mjs +15 -9
- package/src/runtime/memory/lib/core-memory-management.mjs +10 -4
- package/src/runtime/memory/lib/core-memory-store.mjs +53 -30
- package/src/runtime/memory/lib/core-memory-uniqueness.mjs +10 -6
- package/src/runtime/memory/lib/http-router/session-routes.mjs +3 -2
- package/src/runtime/memory/lib/memory-action-handlers/core-actions.mjs +44 -14
- package/src/runtime/memory/lib/memory-schema/core-and-meta.mjs +11 -0
- package/src/runtime/memory/lib/memory.mjs +7 -1
- package/src/runtime/memory/lib/query-core-recall.mjs +9 -1
- package/src/runtime/memory/lib/query-hybrid-search.mjs +2 -0
- package/src/runtime/memory/lib/tool-call-handler.mjs +2 -0
- package/src/runtime/memory/tool-defs.mjs +5 -0
- package/src/runtime/shared/agent-avatar-sprites.mjs +445 -0
- package/src/runtime/shared/agent-avatar.d.mts +64 -0
- package/src/runtime/shared/agent-avatar.mjs +320 -0
- package/src/runtime/shared/agent-kind.mjs +152 -0
- package/src/runtime/shared/agent-route-config.d.mts +4 -0
- package/src/runtime/shared/agent-route-config.mjs +30 -0
- package/src/runtime/shared/agent-store.mjs +132 -0
- package/src/runtime/shared/atomic-file.mjs +14 -1
- package/src/runtime/shared/bot-split-migration.mjs +457 -0
- package/src/runtime/shared/config-patch.mjs +20 -1
- package/src/runtime/shared/config.mjs +8 -1
- package/src/runtime/shared/connector-accounts.mjs +15 -0
- package/src/runtime/shared/connector-catalog.d.mts +51 -0
- package/src/runtime/shared/connector-catalog.mjs +228 -0
- package/src/runtime/shared/connector-triggers.d.mts +3 -0
- package/src/runtime/shared/connector-triggers.mjs +45 -0
- package/src/runtime/shared/err-text.mjs +3 -1
- package/src/runtime/shared/error-presentation.mjs +91 -6
- package/src/runtime/shared/google-oauth-client.mjs +24 -0
- package/src/runtime/shared/handoff-artifacts.d.mts +20 -0
- package/src/runtime/shared/handoff-artifacts.mjs +61 -0
- package/src/runtime/shared/held-request-host.d.mts +12 -0
- package/src/runtime/shared/held-request-host.mjs +71 -0
- package/src/runtime/shared/llm/provider-model-identities.mjs +6 -1
- package/src/runtime/shared/llm/usage-accounting.mjs +7 -1
- package/src/runtime/shared/model-route-fallback.mjs +79 -7
- package/src/runtime/shared/plain-preview.d.mts +1 -0
- package/src/runtime/shared/plain-preview.mjs +33 -0
- package/src/runtime/shared/routine-limits.d.mts +11 -0
- package/src/runtime/shared/routine-limits.mjs +21 -0
- package/src/runtime/shared/routine-trigger.d.mts +10 -0
- package/src/runtime/shared/routine-trigger.mjs +44 -0
- package/src/runtime/shared/schedule-model-ref.mjs +9 -10
- package/src/runtime/shared/sensitive-path-rules.d.mts +15 -0
- package/src/runtime/shared/sensitive-path-rules.mjs +256 -0
- package/src/runtime/shared/slow-span.mjs +4 -12
- package/src/runtime/shared/statusline/statusline-segments.mjs +13 -1
- package/src/runtime/shared/transcript-metadata.mjs +10 -0
- package/src/runtime/shared/turn-changes.mjs +0 -8
- package/src/runtime/shared/usage-readout-totals.mjs +58 -0
- package/src/runtime/shared/user-data-guard.mjs +119 -38
- package/src/session-runtime/agent-home-delivery.mjs +826 -0
- package/src/session-runtime/agent-profile-changes.mjs +21 -0
- package/src/session-runtime/agent-room-delivery.mjs +133 -0
- package/src/session-runtime/agent-task-sessions.mjs +460 -0
- package/src/session-runtime/boot/apis.mjs +63 -18
- package/src/session-runtime/boot/facade.mjs +5 -8
- package/src/session-runtime/boot/infrastructure.mjs +28 -17
- package/src/session-runtime/boot/providers.mjs +14 -4
- package/src/session-runtime/boot/tools.mjs +3 -0
- package/src/session-runtime/channel-config-api.mjs +53 -5
- package/src/session-runtime/config-lifecycle.mjs +43 -2
- package/src/session-runtime/cwd-plugins/core-memory-context.mjs +36 -20
- package/src/session-runtime/cwd-plugins/plugin-status.mjs +6 -1
- package/src/session-runtime/handoff-attachments.mjs +593 -0
- package/src/session-runtime/held-requests.mjs +228 -0
- package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +121 -0
- package/src/session-runtime/internal-tool-executor/feature-tools.mjs +5 -1
- package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +31 -2
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +56 -3
- package/src/session-runtime/internal-tool-executor.mjs +2 -0
- package/src/session-runtime/lifecycle/session-catalog.mjs +9 -0
- package/src/session-runtime/lifecycle/session-switch/resume.mjs +4 -0
- package/src/session-runtime/lifecycle/shared.mjs +6 -0
- package/src/session-runtime/mcp-glue/server-catalog.mjs +8 -0
- package/src/session-runtime/mcp-glue/server-input.mjs +3 -0
- package/src/session-runtime/mcp-oauth-login.mjs +112 -15
- package/src/session-runtime/model-route/route-persist.mjs +2 -2
- package/src/session-runtime/model-route/route-tuning.mjs +7 -1
- package/src/session-runtime/model-route/set-route.mjs +35 -4
- package/src/session-runtime/native-web-search.mjs +2 -2
- package/src/session-runtime/new-session-config.mjs +6 -1
- package/src/session-runtime/owned-automation-run.mjs +229 -0
- package/src/session-runtime/resource-api.mjs +5 -0
- package/src/session-runtime/resource-mcp-api.mjs +107 -13
- package/src/session-runtime/resource-skills-api.mjs +12 -0
- package/src/session-runtime/room-member-gate.mjs +48 -0
- package/src/session-runtime/route-resolution.mjs +5 -11
- package/src/session-runtime/routine-home-turn.mjs +156 -0
- package/src/session-runtime/routine-owner.mjs +48 -0
- package/src/session-runtime/schedule-session-run.mjs +30 -64
- package/src/session-runtime/services/agent-tool/helpers.mjs +30 -1
- package/src/session-runtime/services/agent-tool/send-flow.mjs +11 -3
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +19 -4
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +2 -0
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +4 -1
- package/src/session-runtime/services/agent-tool/spawn-preset.mjs +5 -8
- package/src/session-runtime/services/agent-tool/tool-def.mjs +7 -0
- package/src/session-runtime/services/channel-admin.mjs +93 -24
- package/src/session-runtime/services/memory-access.mjs +37 -0
- package/src/session-runtime/services/provider-admin.mjs +74 -39
- package/src/session-runtime/services/schedule-access.mjs +91 -0
- package/src/session-runtime/session-create/session-options.mjs +34 -7
- package/src/session-runtime/session-hooks.mjs +16 -8
- package/src/session-runtime/setup-tool/executor.mjs +79 -6
- package/src/session-runtime/setup-tool/extended-actions.mjs +90 -20
- package/src/session-runtime/setup-tool/settings-contract.mjs +14 -6
- package/src/session-runtime/setup-tool/tool-defs.mjs +8 -0
- package/src/session-runtime/skills-api.mjs +16 -1
- package/src/session-runtime/tool-policy-refresh.mjs +249 -29
- package/src/session-runtime/turn/session-ops.mjs +8 -1
- package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +10 -2
- package/src/session-runtime/turn/turn-run/turn-prepare.mjs +14 -0
- package/src/session-runtime/webhook-session-run.mjs +49 -67
- package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +239 -0
- package/src/session-runtime/workflow-agents-api/agent-editor.mjs +650 -25
- package/src/session-runtime/workflow-agents-api/agent-route.mjs +67 -7
- package/src/session-runtime/workflow-agents-api/onboarding.mjs +11 -4
- package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +11 -1
- package/src/session-runtime/workflow-agents-api.mjs +4 -1
- package/src/standalone/daemon-agent-control.mjs +1 -8
- package/src/standalone/daemon-session-control.mjs +21 -4
- package/src/standalone/daemon.mjs +31 -5
- package/src/standalone/session-protocol.mjs +27 -0
- package/src/standalone/session-service/agent-tree/agent-turns.mjs +46 -3
- package/src/standalone/session-service/agent-tree.mjs +4 -3
- package/src/standalone/session-service/session-calls/session-turns.mjs +28 -0
- package/src/standalone/session-service.mjs +19 -0
- package/src/tui/app/slash-commands.mjs +20 -0
- package/src/tui/dist/index.mjs +234 -95
- package/src/tui/session/context-state.mjs +6 -1
- package/src/tui/session/notice-surface.mjs +34 -4
- package/src/tui/session/queue-helpers.mjs +2 -1
- package/src/tui/session/session-api/extensions.mjs +4 -0
- package/src/tui/session/session-api/intake/submission.mjs +5 -0
- package/src/tui/session/session-api/integrations.mjs +8 -0
- package/src/tui/session/session-api/lifecycle/session-reset.mjs +13 -3
- package/src/tui/session/session-api/lifecycle.mjs +17 -1
- package/src/tui/session/session-api/routes.mjs +61 -5
- package/src/tui/session/session-flow/drain.mjs +12 -3
- package/src/tui/session/session-flow/queue/entry-shape.mjs +2 -1
- package/src/tui/session/session-flow/queue/take-entries.mjs +3 -2
- package/src/tui/session/session-flow/steering.mjs +58 -24
- package/src/tui/session/tool-approval.mjs +26 -5
- package/src/tui/session/transcript-intake.mjs +8 -2
- package/src/tui/session/transcript-spill.mjs +5 -1
- package/src/tui/session/tui-steering-persist.mjs +65 -42
- package/src/tui/session/turn-live-call.mjs +64 -0
- package/src/tui/session/turn.mjs +34 -8
- package/src/session-runtime/automation-agents.mjs +0 -94
- package/src/session-runtime/automation-workflow.mjs +0 -59
|
@@ -14,14 +14,6 @@ import { retryAfterMsFromError, sleepWithAbort } from './retry-classifier.mjs';
|
|
|
14
14
|
|
|
15
15
|
const isObject = (value) => value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
16
16
|
|
|
17
|
-
// Explicit quota / billing refusals: waiting never helps, so no retry layer
|
|
18
|
-
// may treat them as an ordinary rate limit.
|
|
19
|
-
const QUOTA_OR_BILLING_CODE_RE = /quota|billing|usage_limit|usage_not_included/;
|
|
20
|
-
|
|
21
|
-
export function isQuotaOrBillingCode(code) {
|
|
22
|
-
return QUOTA_OR_BILLING_CODE_RE.test(String(code || '').toLowerCase());
|
|
23
|
-
}
|
|
24
|
-
|
|
25
17
|
/**
|
|
26
18
|
* Parse an HTTP error body ONCE into its contract fields. `message` is the
|
|
27
19
|
* body's own message (untruncated); callers truncate for diagnostics.
|
|
@@ -211,7 +203,8 @@ export function applyErrorContract(err, { status, headers, code, error, event }
|
|
|
211
203
|
err.status = n;
|
|
212
204
|
err.httpStatus = n;
|
|
213
205
|
}
|
|
214
|
-
const wireHeaders =
|
|
206
|
+
const wireHeaders =
|
|
207
|
+
headers ?? error?.headers ?? event?.error?.headers ?? event?.response?.error?.headers ?? event?.headers;
|
|
215
208
|
if (wireHeaders && typeof wireHeaders === 'object') err.headers = wireHeaders;
|
|
216
209
|
const rawCode = code ?? error?.code ?? error?.type ?? null;
|
|
217
210
|
if (typeof rawCode === 'string' && rawCode.trim()) err.code = rawCode.trim().toLowerCase();
|
|
@@ -225,7 +218,13 @@ export function applyErrorContract(err, { status, headers, code, error, event }
|
|
|
225
218
|
if (err.retryAfterAt == null) err.retryAfterAt = Date.now() + retryAfterMs;
|
|
226
219
|
}
|
|
227
220
|
const type = typeof error?.type === 'string' ? error.type.trim().toLowerCase() : '';
|
|
228
|
-
const mapped = typedWireErrorMessage({
|
|
221
|
+
const mapped = typedWireErrorMessage({
|
|
222
|
+
code: err.code || '',
|
|
223
|
+
type,
|
|
224
|
+
error,
|
|
225
|
+
headers: err.headers,
|
|
226
|
+
resetAt: err.resetAt,
|
|
227
|
+
});
|
|
229
228
|
if (mapped) applyTypedWireMessage(err, mapped, error?.message);
|
|
230
229
|
} catch {}
|
|
231
230
|
return err;
|
|
@@ -238,7 +237,12 @@ export function applyErrorContract(err, { status, headers, code, error, event }
|
|
|
238
237
|
* makes unknown codes default-retryable).
|
|
239
238
|
*/
|
|
240
239
|
export function markContentFilter(err, reason) {
|
|
241
|
-
if (
|
|
240
|
+
if (
|
|
241
|
+
String(reason || '')
|
|
242
|
+
.trim()
|
|
243
|
+
.toLowerCase() !== 'content_filter'
|
|
244
|
+
)
|
|
245
|
+
return err;
|
|
242
246
|
err.code = 'content_filter';
|
|
243
247
|
err.providerErrorCode = 'content_filter';
|
|
244
248
|
return err;
|
|
@@ -260,7 +264,8 @@ export function httpResponseError({ label, status, headers, text, initialRespons
|
|
|
260
264
|
}
|
|
261
265
|
|
|
262
266
|
// The route decides the HTTP/SSE label: the api-key `openai` provider is not OAuth.
|
|
263
|
-
export const httpLabel = (auth) =>
|
|
267
|
+
export const httpLabel = (auth) =>
|
|
268
|
+
auth?.type === 'openai-direct' ? 'OpenAI HTTP fallback' : 'OpenAI OAuth HTTP fallback';
|
|
264
269
|
|
|
265
270
|
/**
|
|
266
271
|
* Changing transport must not bypass the server's retry deadline.
|
|
@@ -92,6 +92,15 @@ export function identityFromTokens(...tokens) {
|
|
|
92
92
|
return normalizeAccountIdentity({ id: [sub, accountId].filter(Boolean).join(':'), email });
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
+
/** ChatGPT plan (e.g. plus, pro) from the first token carrying the claim, else null. */
|
|
96
|
+
export function planFromTokens(...tokens) {
|
|
97
|
+
for (const token of tokens) {
|
|
98
|
+
const plan = decodeJwtPayload(token)?.['https://api.openai.com/auth']?.chatgpt_plan_type;
|
|
99
|
+
if (typeof plan === 'string' && plan) return plan;
|
|
100
|
+
}
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
|
|
95
104
|
/** mtime of the token file, 0 when it is missing or unreadable. */
|
|
96
105
|
export function tokensFileMtimeMs() {
|
|
97
106
|
try {
|
|
@@ -165,6 +174,7 @@ export function describeOpenAIOAuthCredentials() {
|
|
|
165
174
|
...oauthCredentialStatus({ hasRefresh, expiresAt, detail: source, refreshSkewMs: TOKEN_REFRESH_SKEW_MS }),
|
|
166
175
|
...accountIdentityFields(tokens.identity),
|
|
167
176
|
...(accountId ? { accountId } : {}),
|
|
177
|
+
plan: planFromTokens(tokens.id_token, tokens.access_token),
|
|
168
178
|
};
|
|
169
179
|
} catch (err) {
|
|
170
180
|
return {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Transcript lowering is independent of request/turn metadata. A retained
|
|
2
2
|
// message must have the same wire representation in every subsequent request.
|
|
3
3
|
import { providerReplayItems } from './lib/provider-replay.mjs';
|
|
4
|
+
import { OPENAI_RESPONSES_TOOL_CALL_IDS, withWireToolCallIds } from './lib/tool-call-wire-ids.mjs';
|
|
4
5
|
import { responsesEffortUpdates } from './effort-configuration.mjs';
|
|
5
6
|
import { ensureResponsesCallOutputs } from './lib/wire-pairing.mjs';
|
|
6
7
|
import { normalizeContentForOpenAIResponses, splitToolContentForOpenAIResponses } from './media-normalization.mjs';
|
|
@@ -147,7 +148,8 @@ function pushAssistantToolCalls(toolCalls, { out, customToolCallIds, nativeSearc
|
|
|
147
148
|
* - `includeSystem`, `nativePdf`, `splitToolContent`, `startIndex`: the
|
|
148
149
|
* gateway's system/media/continuation handling.
|
|
149
150
|
*/
|
|
150
|
-
export function convertMessagesToResponsesInput(
|
|
151
|
+
export function convertMessagesToResponsesInput(transcript, opts = {}) {
|
|
152
|
+
const messages = withWireToolCallIds(transcript, OPENAI_RESPONSES_TOOL_CALL_IDS);
|
|
151
153
|
const out = [];
|
|
152
154
|
const pendingToolMedia = [];
|
|
153
155
|
const pendingToolLoads = [];
|
|
@@ -335,8 +335,19 @@ const CODE_KINDS = new Map(
|
|
|
335
335
|
quota_exhausted: ['quota_exceeded', 'quota_exhausted', 'usage_limit_reached', 'provider_accounts_exhausted'],
|
|
336
336
|
context_overflow: ['context_length_exceeded', 'context_window_exceeded', 'model_context_window_exceeded'],
|
|
337
337
|
request_too_large: ['request_too_large', 'payload_too_large', 'request_entity_too_large'],
|
|
338
|
-
|
|
339
|
-
|
|
338
|
+
// Google names a rejected or expired key with an ErrorInfo reason on an
|
|
339
|
+
// INVALID_ARGUMENT 400; the reason outranks the envelope status.
|
|
340
|
+
auth: [
|
|
341
|
+
'invalid_api_key',
|
|
342
|
+
'authentication_error',
|
|
343
|
+
'unauthenticated',
|
|
344
|
+
'unauthorized',
|
|
345
|
+
'invalid_authentication',
|
|
346
|
+
'api_key_invalid',
|
|
347
|
+
'api_key_expired',
|
|
348
|
+
'access_token_expired',
|
|
349
|
+
],
|
|
350
|
+
permission: ['permission_error', 'permission_denied', 'forbidden', 'service_disabled', 'api_key_service_blocked'],
|
|
340
351
|
overloaded: [
|
|
341
352
|
'server_is_overloaded',
|
|
342
353
|
'overloaded_error',
|
|
@@ -374,6 +385,7 @@ const CODE_KINDS = new Map(
|
|
|
374
385
|
'not_found',
|
|
375
386
|
'not_found_error',
|
|
376
387
|
'model_not_found',
|
|
388
|
+
'model_not_supported',
|
|
377
389
|
'unsupported_parameter',
|
|
378
390
|
],
|
|
379
391
|
}).flatMap(([kind, codes]) => codes.map((code) => [code, kind]))
|
|
@@ -150,6 +150,13 @@ function isOverloadFailure(status, errorKind) {
|
|
|
150
150
|
return status === 529 || errorKind === 'overloaded';
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
+
function exceedsAdviceCeiling(caught, opts) {
|
|
154
|
+
const ceiling = Number(opts.maxRetryAfterMs);
|
|
155
|
+
if (!(ceiling > 0)) return false;
|
|
156
|
+
const advised = retryAfterMsFromError(caught);
|
|
157
|
+
return advised != null && advised > ceiling;
|
|
158
|
+
}
|
|
159
|
+
|
|
153
160
|
// Decides whether `caught` may be re-issued: returns the error to throw (the
|
|
154
161
|
// caught one, the exhausted-marked one on the last attempt, or the model
|
|
155
162
|
// fallback trigger) or null when the next attempt may run — and only then
|
|
@@ -206,6 +213,16 @@ function retryVerdict(caught, { opts, attempt, maxAttempts, state }) {
|
|
|
206
213
|
const typedQuota = QUOTA_KINDS.has(providerErrorKind(caught, { quotaFlags: false }).kind);
|
|
207
214
|
if (typedQuota || opts.retry429 === false || status !== 429) return caught;
|
|
208
215
|
}
|
|
216
|
+
// Opt-in `maxRetryAfterMs`: a server wait longer than the caller will sit
|
|
217
|
+
// through is a lock-out, not a retry. It surfaces now (with its advice for
|
|
218
|
+
// the notice and the account pool) instead of parking the send for it.
|
|
219
|
+
if (exceedsAdviceCeiling(caught, opts)) {
|
|
220
|
+
return markProviderRecoveryExhausted(caught, {
|
|
221
|
+
owner: opts.recoveryOwner || 'withRetry',
|
|
222
|
+
attempts: attempt + 1,
|
|
223
|
+
terminal: true,
|
|
224
|
+
});
|
|
225
|
+
}
|
|
209
226
|
// Background calls (titles and the like) never retry an overload: during a
|
|
210
227
|
// capacity cascade every retry multiplies gateway load, and nobody is
|
|
211
228
|
// waiting on the result.
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { loginPageUrl } from '../session/human-gate/requests.mjs';
|
|
2
|
+
|
|
1
3
|
const ASK_USER_MAX_QUESTIONS = 4;
|
|
2
4
|
export const ASK_USER_MAX_TEXT = 4000;
|
|
3
5
|
|
|
@@ -50,13 +52,106 @@ export const ASK_USER_TOOL_DEFS = Object.freeze([
|
|
|
50
52
|
required: ['question', 'header', 'options'],
|
|
51
53
|
},
|
|
52
54
|
},
|
|
55
|
+
handoff: {
|
|
56
|
+
type: 'object',
|
|
57
|
+
description:
|
|
58
|
+
'Instead of questions: secret = the user types a password/token into the focused field (you never see it; result provided/skipped/timeout); takeover = the user does a step (sign-in, CAPTCHA, 2FA) and says done.',
|
|
59
|
+
properties: {
|
|
60
|
+
kind: { type: 'string', enum: ['secret', 'takeover'] },
|
|
61
|
+
surface: { type: 'string', enum: ['browser', 'computer'] },
|
|
62
|
+
target: { type: 'string', maxLength: 200, description: 'Site/app and form.' },
|
|
63
|
+
field: { type: 'string', maxLength: 80, description: 'secret: field label.' },
|
|
64
|
+
instructions: { type: 'string', maxLength: 2000, description: 'takeover: what to do.' },
|
|
65
|
+
need: {
|
|
66
|
+
type: 'string',
|
|
67
|
+
enum: ['sign_in', 'action', 'confirmation'],
|
|
68
|
+
description:
|
|
69
|
+
'takeover: sign_in (sign-in, 2FA), action (CAPTCHA, other step), confirmation (identity/payment check). Default action.',
|
|
70
|
+
},
|
|
71
|
+
purpose: {
|
|
72
|
+
type: 'string',
|
|
73
|
+
enum: ['login'],
|
|
74
|
+
description: 'browser takeover: login = sign-in window on url.',
|
|
75
|
+
},
|
|
76
|
+
url: { type: 'string', maxLength: 2048, description: 'login: sign-in page (https).' },
|
|
77
|
+
tab: { type: 'string', maxLength: 64, description: 'browser takeover: page ID from list_tabs.' },
|
|
78
|
+
window_id: { type: 'string', maxLength: 128, description: 'computer takeover: exact window id.' },
|
|
79
|
+
app: { type: 'string', maxLength: 120, description: 'computer takeover: app name.' },
|
|
80
|
+
},
|
|
81
|
+
required: ['kind', 'surface'],
|
|
82
|
+
additionalProperties: false,
|
|
83
|
+
},
|
|
53
84
|
},
|
|
54
|
-
required: ['questions'],
|
|
55
85
|
additionalProperties: false,
|
|
56
86
|
},
|
|
57
87
|
},
|
|
58
88
|
]);
|
|
59
89
|
|
|
90
|
+
/** The handoff of an ask_user call ({ kind, surface, target, field, instructions }), or null. */
|
|
91
|
+
export function validateAskUserHandoff(args) {
|
|
92
|
+
const handoff = args?.handoff;
|
|
93
|
+
if (handoff == null) return null;
|
|
94
|
+
if (args.questions != null) throw new Error('ask_user takes questions or a handoff, not both');
|
|
95
|
+
if (typeof handoff !== 'object' || Array.isArray(handoff)) throw new Error('ask_user handoff must be an object');
|
|
96
|
+
if (handoff.kind !== 'secret' && handoff.kind !== 'takeover') {
|
|
97
|
+
throw new Error('ask_user handoff kind is secret or takeover');
|
|
98
|
+
}
|
|
99
|
+
if (handoff.surface !== 'browser' && handoff.surface !== 'computer') {
|
|
100
|
+
throw new Error('ask_user handoff surface is browser or computer');
|
|
101
|
+
}
|
|
102
|
+
const text = (key, limit) => (typeof handoff[key] === 'string' ? handoff[key].trim().slice(0, limit) : '');
|
|
103
|
+
if (handoff.kind === 'takeover' && !text('instructions', 2000)) {
|
|
104
|
+
throw new Error('ask_user takeover needs instructions');
|
|
105
|
+
}
|
|
106
|
+
const login = handoffLogin(handoff);
|
|
107
|
+
let need = login ? 'sign_in' : 'action';
|
|
108
|
+
if (['sign_in', 'action', 'confirmation'].includes(handoff.need)) need = handoff.need;
|
|
109
|
+
return {
|
|
110
|
+
kind: handoff.kind,
|
|
111
|
+
surface: handoff.surface,
|
|
112
|
+
target: text('target', 200),
|
|
113
|
+
field: text('field', 80),
|
|
114
|
+
instructions: text('instructions', 2000),
|
|
115
|
+
...(handoff.kind === 'takeover' ? { need, identity: handoffIdentity(handoff), ...(login ? { login } : {}) } : {}),
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** A login takeover's sign-in page ({ url, origin }); null without the
|
|
120
|
+
* explicit purpose, so every other takeover keeps the side panel. */
|
|
121
|
+
function handoffLogin(handoff) {
|
|
122
|
+
if (handoff.purpose == null) return null;
|
|
123
|
+
if (handoff.purpose !== 'login' || handoff.kind !== 'takeover' || handoff.surface !== 'browser') {
|
|
124
|
+
throw new Error('ask_user purpose login is a browser takeover');
|
|
125
|
+
}
|
|
126
|
+
const page = loginPageUrl(handoff.url);
|
|
127
|
+
if (!page) throw new Error('ask_user login needs an https url (http only on localhost)');
|
|
128
|
+
return page;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** The window a takeover is about, validated per surface: a browser page ID
|
|
132
|
+
* (list_tabs p1, v1 or a page name) or a computer window id and app. Shapes
|
|
133
|
+
* that are not plain tokens are dropped, never passed on. */
|
|
134
|
+
const TOKEN = /^[\w.:#@-]+$/;
|
|
135
|
+
function handoffIdentity(handoff) {
|
|
136
|
+
const token = (key, limit) => {
|
|
137
|
+
const value = typeof handoff[key] === 'string' ? handoff[key].trim() : '';
|
|
138
|
+
return value && value.length <= limit && TOKEN.test(value) ? value : '';
|
|
139
|
+
};
|
|
140
|
+
if (handoff.surface === 'browser') {
|
|
141
|
+
const tab = token('tab', 64);
|
|
142
|
+
return tab ? { tab } : {};
|
|
143
|
+
}
|
|
144
|
+
const windowId = token('window_id', 128);
|
|
145
|
+
const app =
|
|
146
|
+
typeof handoff.app === 'string'
|
|
147
|
+
? handoff.app
|
|
148
|
+
.replace(/[\r\n]+/g, ' ')
|
|
149
|
+
.trim()
|
|
150
|
+
.slice(0, 120)
|
|
151
|
+
: '';
|
|
152
|
+
return { ...(windowId ? { windowId } : {}), ...(app ? { app } : {}) };
|
|
153
|
+
}
|
|
154
|
+
|
|
60
155
|
/** Throws a clear error when the questions are malformed; returns the list. */
|
|
61
156
|
export function validateAskUserQuestions(args) {
|
|
62
157
|
const questions = args?.questions;
|
|
@@ -46,6 +46,7 @@ export function sessionTokenCounters(session) {
|
|
|
46
46
|
totalOutputTokens: Number(session?.totalOutputTokens || 0),
|
|
47
47
|
totalCachedReadTokens: Number(session?.totalCachedReadTokens || 0),
|
|
48
48
|
totalCacheWriteTokens: Number(session?.totalCacheWriteTokens || 0),
|
|
49
|
+
usageReadout: session?.usageReadout || null,
|
|
49
50
|
compactBoundaryTokens: Number(session?.compactBoundaryTokens || 0),
|
|
50
51
|
};
|
|
51
52
|
}
|
|
@@ -64,6 +65,9 @@ function sessionUsageCounters(session, lastContextTokens) {
|
|
|
64
65
|
totalOutputTokens: Number(session?.totalOutputTokens || 0),
|
|
65
66
|
totalCachedReadTokens: Number(session?.totalCachedReadTokens || 0),
|
|
66
67
|
totalCacheWriteTokens: Number(session?.totalCacheWriteTokens || 0),
|
|
68
|
+
// Session-cumulative cache/speed totals behind the composer readout; null
|
|
69
|
+
// until the session has a call recorded.
|
|
70
|
+
usageReadout: session?.usageReadout || null,
|
|
67
71
|
};
|
|
68
72
|
}
|
|
69
73
|
|
|
@@ -48,12 +48,14 @@ export function filterMcpToolsForCwd(tools, scopes, cwd) {
|
|
|
48
48
|
});
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
/** The MCP tools a session at `cwd` may see. No scopes configured → input
|
|
52
|
-
*
|
|
51
|
+
/** The MCP tools a session at `cwd` may see. No scopes configured → the input
|
|
52
|
+
* as-is, so the global-only fast path costs one config read. An agent's
|
|
53
|
+
* connectors never narrow this list: the schema and the BP2 manifest stay
|
|
54
|
+
* identical across agents (one shared cache prefix), and the connector policy
|
|
55
|
+
* is enforced at dispatch (pre-dispatch-deny / connector approval). */
|
|
53
56
|
export function filterMcpToolsForSession(tools, cwd, config = null) {
|
|
54
57
|
const list = Array.isArray(tools) ? tools : [];
|
|
55
58
|
if (!list.length) return list;
|
|
56
59
|
const scopes = extensionScopesFromConfig(config || loadConfig({ secrets: false }));
|
|
57
|
-
|
|
58
|
-
return filterMcpToolsForCwd(list, scopes, cwd);
|
|
60
|
+
return hasExtensionScopes(scopes) ? filterMcpToolsForCwd(list, scopes, cwd) : list;
|
|
59
61
|
}
|
|
@@ -19,6 +19,20 @@ Lead executes all work directly and never delegates on its own judgment.
|
|
|
19
19
|
Only when the user explicitly asks for delegation, load the deferred \`agent\`
|
|
20
20
|
tool and brief each agent as the Lead rules describe.`;
|
|
21
21
|
|
|
22
|
+
/** Agent mode's fixed delegation block, in place of the orchestration mode. */
|
|
23
|
+
export const AGENT_MODE_DELEGATION = `# Delegation
|
|
24
|
+
|
|
25
|
+
Handle conversation yourself. Delegate specialised work to sub-agents. Hand
|
|
26
|
+
substantial coding to a new agent task session (\`session create\`) with
|
|
27
|
+
a self-contained brief: start it when already requested, otherwise suggest it. Then relay the
|
|
28
|
+
result in your own words. Work sent to an existing session (\`session send\`)
|
|
29
|
+
reports back only when its result says reportsBack: true; promise to report
|
|
30
|
+
only then.`;
|
|
31
|
+
|
|
32
|
+
/** Mixy only: it also routes requests to the user's contact agents. */
|
|
33
|
+
export const MIXY_CONTACTS_INTRO = `You also coordinate the user's contact agents: route a request to the
|
|
34
|
+
contact best suited for it with the same kind of brief.`;
|
|
35
|
+
|
|
22
36
|
export function orchestrationInstructions(value) {
|
|
23
37
|
const mode = normalizeOrchestrationMode(value);
|
|
24
38
|
if (mode === 'none') return SOLO;
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
deferredCatalogUnion,
|
|
15
15
|
filterSessionToolPolicy,
|
|
16
16
|
isReadonlySelectable,
|
|
17
|
+
mcpServerSelection,
|
|
17
18
|
toolSearchMatches,
|
|
18
19
|
} from './tool-catalog.mjs';
|
|
19
20
|
import { parseToolSelection, sortedCatalogByMeasuredUsage } from './tool-catalog-schema.mjs';
|
|
@@ -249,8 +250,9 @@ function describeNames(raw) {
|
|
|
249
250
|
return names;
|
|
250
251
|
}
|
|
251
252
|
|
|
252
|
-
// Requested names → available tools; an alias that names no
|
|
253
|
-
// its members (existing load_tool alias compatibility).
|
|
253
|
+
// Requested names → available tools; an alias or `mcp__<server>` that names no
|
|
254
|
+
// tool expands to its members (existing load_tool alias compatibility).
|
|
255
|
+
// Definitions past the continuation target cap are listed as omitted.
|
|
254
256
|
function resolveDescribeTargets(session, names, mode, available) {
|
|
255
257
|
const eagerNames = eagerToolNames(session);
|
|
256
258
|
const targets = [];
|
|
@@ -271,13 +273,15 @@ function resolveDescribeTargets(session, names, mode, available) {
|
|
|
271
273
|
add(tool);
|
|
272
274
|
continue;
|
|
273
275
|
}
|
|
274
|
-
const
|
|
276
|
+
const aliased = (DEFERRED_SELECT_ALIASES[requested.toLowerCase()] || [])
|
|
275
277
|
.map((member) => lookupByName(available, member))
|
|
276
278
|
.filter(Boolean);
|
|
279
|
+
const members = aliased.length ? aliased : mcpServerSelection(available, requested);
|
|
277
280
|
if (members.length) members.forEach(add);
|
|
278
281
|
else missing.push(requested);
|
|
279
282
|
}
|
|
280
|
-
|
|
283
|
+
const omitted = targets.splice(BRIDGE_LIMITS.continuationMaxTargets).map((tool) => clean(tool?.name));
|
|
284
|
+
return { targets, missing, blocked, omitted };
|
|
281
285
|
}
|
|
282
286
|
|
|
283
287
|
const SEARCH_MAX_MATCHES = 20;
|
|
@@ -367,6 +371,7 @@ export function describeBridgeTools(session, args = {}, { mode } = {}) {
|
|
|
367
371
|
let missing = [];
|
|
368
372
|
let blocked = [];
|
|
369
373
|
let matches = [];
|
|
374
|
+
let omitted = [];
|
|
370
375
|
if (continuation) {
|
|
371
376
|
targets = continuationTargets(session, continuation.indexes, available, mode);
|
|
372
377
|
if (!targets) return catalogChanged();
|
|
@@ -378,10 +383,11 @@ export function describeBridgeTools(session, args = {}, { mode } = {}) {
|
|
|
378
383
|
`names must be 1-${BRIDGE_LIMITS.describeMaxNames} exact tool names of at most ${BRIDGE_LIMITS.nameMaxChars} characters.${syntaxHint}`
|
|
379
384
|
);
|
|
380
385
|
}
|
|
381
|
-
({ targets, missing, blocked } = resolveDescribeTargets(session, names, mode, available));
|
|
386
|
+
({ targets, missing, blocked, omitted } = resolveDescribeTargets(session, names, mode, available));
|
|
382
387
|
({ matches, missing } = searchKeywords(session, missing, mode, available));
|
|
383
388
|
}
|
|
384
|
-
|
|
389
|
+
// Omitted names are described by a later request naming them.
|
|
390
|
+
const found = { ...(matches.length ? { matches } : {}), ...(omitted.length ? { omitted } : {}) };
|
|
385
391
|
const docs = targets.map((tool) => {
|
|
386
392
|
const document = toolDocument(tool);
|
|
387
393
|
return {
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
import { clean } from './session-text.mjs';
|
|
5
5
|
import { mergePendingDeferredToolDelta } from './deferred-tool-delta.mjs';
|
|
6
6
|
import { applyInitialDeferredToolManifestToBp2 } from '../context/collect.mjs';
|
|
7
|
+
import { listedDeferredToolNames } from '../context/deferred-tools.mjs';
|
|
8
|
+
import { parseMcpToolName } from '../../../shared/tool-primitives.mjs';
|
|
7
9
|
import { getMcpServerInstructionsMap, getMcpTools, getMcpToolGeneration } from '../mcp/client.mjs';
|
|
8
10
|
import { filterMcpToolsForSession } from './extension-scopes.mjs';
|
|
9
11
|
import { isDeferredToolAvailable, isToolPermittedBySessionPolicy } from './deferred-tool-availability.mjs';
|
|
@@ -259,6 +261,17 @@ function expandSelectionNames(names) {
|
|
|
259
261
|
return [...new Set(out)];
|
|
260
262
|
}
|
|
261
263
|
|
|
264
|
+
/**
|
|
265
|
+
* The tools of `tools` that `mcp__<server>` stands for (the deferred manifest
|
|
266
|
+
* lists MCP servers, not their tools); [] for any other name. Callers try an
|
|
267
|
+
* exact tool name first.
|
|
268
|
+
*/
|
|
269
|
+
export function mcpServerSelection(tools, requested) {
|
|
270
|
+
const server = /^mcp__(.+)$/i.exec(clean(requested))?.[1]?.toLowerCase();
|
|
271
|
+
if (!server) return [];
|
|
272
|
+
return (tools || []).filter((tool) => String(parseMcpToolName(tool)?.server || '').toLowerCase() === server);
|
|
273
|
+
}
|
|
274
|
+
|
|
262
275
|
function storedDeferredToolNames(session) {
|
|
263
276
|
for (const source of [session?.deferredDiscoveredTools, session?.deferredSelectedTools]) {
|
|
264
277
|
const names = parseToolSelection(source);
|
|
@@ -430,8 +443,11 @@ export function applyDeferredToolSurface(session, mode, extraTools = [], options
|
|
|
430
443
|
// manifest, or the bridge roster + guidance. History stays as is.
|
|
431
444
|
session.mcpServerInstructions = getMcpServerInstructionsMap(session.mcpScopeId);
|
|
432
445
|
applyInitialDeferredToolManifestToBp2(session, deferredPoolToolNames(session), { rebuild: true });
|
|
433
|
-
|
|
434
|
-
|
|
446
|
+
session.deferredAnnouncedTools = listedDeferredToolNames(
|
|
447
|
+
session,
|
|
448
|
+
deferredPoolToolNames(session),
|
|
449
|
+
renderedDeferredManifest(session)
|
|
450
|
+
);
|
|
435
451
|
}
|
|
436
452
|
if (!session.deferredToolBp2Applied && session.messages?.some((m) => m?.role === 'system')) {
|
|
437
453
|
if (!session.mcpServerInstructions || typeof session.mcpServerInstructions !== 'object') {
|
|
@@ -519,8 +535,11 @@ export function refreshInitialDeferredMcpSurface(session, liveMcpTools) {
|
|
|
519
535
|
// Pre-mark ONLY the names that ACTUALLY landed in the rebuilt BP2 manifest as
|
|
520
536
|
// announced; anything the manifest could not advertise stays un-announced so
|
|
521
537
|
// the turn-boundary late reminder can still surface it.
|
|
522
|
-
|
|
523
|
-
|
|
538
|
+
session.deferredAnnouncedTools = listedDeferredToolNames(
|
|
539
|
+
session,
|
|
540
|
+
deferredPoolToolNames(session),
|
|
541
|
+
renderedDeferredManifest(session)
|
|
542
|
+
);
|
|
524
543
|
session.updatedAt = Date.now();
|
|
525
544
|
return true;
|
|
526
545
|
}
|
|
@@ -726,7 +745,15 @@ export function selectDeferredTools(session, names, mode, { exact = false } = {}
|
|
|
726
745
|
const already = [];
|
|
727
746
|
const blocked = [];
|
|
728
747
|
const missing = [];
|
|
729
|
-
|
|
748
|
+
const requested = exact
|
|
749
|
+
? names
|
|
750
|
+
: expandSelectionNames(names).flatMap((raw) => {
|
|
751
|
+
const key = clean(raw);
|
|
752
|
+
if (byName.has(key) || byName.has(key.toLowerCase())) return [key];
|
|
753
|
+
const members = mcpServerSelection(catalog, key).map((tool) => clean(tool?.name));
|
|
754
|
+
return members.length ? members : [key];
|
|
755
|
+
});
|
|
756
|
+
for (const rawName of new Set(requested)) {
|
|
730
757
|
const requestedName = clean(rawName);
|
|
731
758
|
const tool = byName.get(requestedName) || byName.get(requestedName.toLowerCase());
|
|
732
759
|
const name = clean(tool?.name);
|
|
@@ -17,7 +17,8 @@ export const TOOL_SEARCH_TOOL = {
|
|
|
17
17
|
openWorldHint: false,
|
|
18
18
|
agentHidden: true,
|
|
19
19
|
},
|
|
20
|
-
description:
|
|
20
|
+
description:
|
|
21
|
+
'Load full schemas for missing deferred tool names/aliases; a connector name loads all its tools; batch needed names in one call.',
|
|
21
22
|
inputSchema: {
|
|
22
23
|
type: 'object',
|
|
23
24
|
properties: {
|
|
@@ -72,9 +73,9 @@ export const SESSION_TOOL = {
|
|
|
72
73
|
openWorldHint: false,
|
|
73
74
|
agentHidden: true,
|
|
74
75
|
},
|
|
75
|
-
trigger: 'Session lookup/control, title, compact, fork, Project and worktrees.',
|
|
76
|
+
trigger: 'Session lookup/control, agent task sessions, title, compact, fork, Project and worktrees.',
|
|
76
77
|
description:
|
|
77
|
-
'Inspect sessions or control another by exact ID, never a guessed one. send acknowledges queue intake, not completion. Cancel/delete and worktree actions require the user’s request. Other actions affect only the current session.',
|
|
78
|
+
'Inspect sessions or control another by exact ID, never a guessed one. send acknowledges queue intake, not completion; promise a report of it only when its result has reportsBack: true. Cancel/delete and worktree actions require the user’s request. Other actions affect only the current session. Pass files on with attachments; a reported turn returns the files it produced as attachments.',
|
|
78
79
|
inputSchema: {
|
|
79
80
|
type: 'object',
|
|
80
81
|
properties: {
|
|
@@ -87,6 +88,7 @@ export const SESSION_TOOL = {
|
|
|
87
88
|
'send',
|
|
88
89
|
'cancel',
|
|
89
90
|
'delete',
|
|
91
|
+
'create',
|
|
90
92
|
'rename',
|
|
91
93
|
'compact',
|
|
92
94
|
'fork',
|
|
@@ -100,9 +102,9 @@ export const SESSION_TOOL = {
|
|
|
100
102
|
'prune-worktrees',
|
|
101
103
|
],
|
|
102
104
|
description:
|
|
103
|
-
'status defaults to current; list pages sessions; read returns latest items; send queues prompt; cancel stops the turn; delete removes the session. compact runs after this turn; fork copies it without switching. merge-worktree merges into the Project’s checked-out branch; remove-worktree returns to the Project (repeat on WORKTREE_REMOVAL_INCOMPLETE); list-worktrees includes retaining sessions; prune-worktrees removes only clean, merged, unretained worktrees.',
|
|
105
|
+
'status defaults to current; list pages sessions; read returns latest items; send queues prompt (reportsBack: the turn result reports back here); cancel stops the turn; delete removes the session. create (bot conversations) starts a visible agent task session from brief and reports its turns back; unknown Project: list-projects first, still ambiguous: ask the user. compact runs after this turn; fork copies it without switching. merge-worktree merges into the Project’s checked-out branch; remove-worktree returns to the Project (repeat on WORKTREE_REMOVAL_INCOMPLETE); list-worktrees includes retaining sessions; prune-worktrees removes only clean, merged, unretained worktrees.',
|
|
104
106
|
},
|
|
105
|
-
title: { type: 'string', description: 'rename: new current-session title.' },
|
|
107
|
+
title: { type: 'string', description: 'rename: new current-session title; create: task title.' },
|
|
106
108
|
session_id: {
|
|
107
109
|
type: 'string',
|
|
108
110
|
description:
|
|
@@ -143,6 +145,20 @@ export const SESSION_TOOL = {
|
|
|
143
145
|
description: 'remove-worktree: allow uncommitted/unmerged work only when explicitly requested.',
|
|
144
146
|
},
|
|
145
147
|
value: { type: 'boolean', description: 'favorite/archive: on or off.' },
|
|
148
|
+
brief: { type: 'string', description: 'create: self-contained instruction, the first message.' },
|
|
149
|
+
project: { type: 'string', description: 'create: registered Project name or existing directory.' },
|
|
150
|
+
model: {
|
|
151
|
+
type: 'string',
|
|
152
|
+
description: 'create: provider/model or preset; default is the Lead model (else the last-used one).',
|
|
153
|
+
},
|
|
154
|
+
notify: { type: 'boolean', description: 'create: report results back, default true.' },
|
|
155
|
+
attachments: {
|
|
156
|
+
type: 'array',
|
|
157
|
+
items: { type: 'string' },
|
|
158
|
+
maxItems: 8,
|
|
159
|
+
description:
|
|
160
|
+
'send/create: files the target turn receives as real attachments (images, PDF/Office, text): an attachment of this conversation by its file name (a user upload, e.g. its [Image: source: name]) or id (a reported file’s [attachment:id]), or a file path inside this session’s folders. Secret files are refused.',
|
|
161
|
+
},
|
|
146
162
|
},
|
|
147
163
|
additionalProperties: false,
|
|
148
164
|
},
|
|
@@ -9,6 +9,15 @@ import { readJsonSafe, readTextSafe } from '../fs-utils.mjs';
|
|
|
9
9
|
import { SHARED_SCAN_REVALIDATE_MS, createSharedScanCache } from './shared-scan-cache.mjs';
|
|
10
10
|
import { isHiddenAgent } from '../../internal-agents.mjs';
|
|
11
11
|
import { isAgentDisabled } from '../../../../shared/agent-route-config.mjs';
|
|
12
|
+
import { agentDefinitionKind } from '../../../../shared/agent-kind.mjs';
|
|
13
|
+
import {
|
|
14
|
+
BOTS_DIR,
|
|
15
|
+
MIXY_BOT_ID,
|
|
16
|
+
botStoreActive,
|
|
17
|
+
isStoreBot,
|
|
18
|
+
migratedBotIds,
|
|
19
|
+
userDefinitionDir,
|
|
20
|
+
} from '../../../../shared/agent-store.mjs';
|
|
12
21
|
import {
|
|
13
22
|
AGENT_DELETED_MARKER,
|
|
14
23
|
AGENT_ROLE_IDS,
|
|
@@ -21,16 +30,22 @@ import {
|
|
|
21
30
|
setAgentDefinitionCache,
|
|
22
31
|
} from '../workflow-ids.mjs';
|
|
23
32
|
|
|
24
|
-
// Yields its fs requests; see shared-scan-cache.mjs.
|
|
25
|
-
|
|
33
|
+
// Yields its fs requests; see shared-scan-cache.mjs. With the bot store
|
|
34
|
+
// active, bots/ is scanned too and the agents/ originals of the ids the split
|
|
35
|
+
// copied are skipped (agent-store.mjs).
|
|
36
|
+
function* scanCustomAgentIds(userRoot, shippedRoot, botsRoot = null, migrated = new Set()) {
|
|
26
37
|
const ids = new Set();
|
|
27
|
-
for (const root of [userRoot, shippedRoot]) {
|
|
38
|
+
for (const root of [...(botsRoot ? [botsRoot] : []), userRoot, shippedRoot]) {
|
|
28
39
|
const entries = yield { op: 'readdir', path: root };
|
|
29
40
|
for (const entry of entries) {
|
|
30
41
|
if (!entry.isDirectory()) continue;
|
|
31
42
|
const id = normalizeWorkflowId(entry.name);
|
|
32
|
-
|
|
33
|
-
if (
|
|
43
|
+
// `lead` is the Lead's own folder, `mixy` Mixy's: neither is an agent.
|
|
44
|
+
if (!id || id === 'lead' || AGENT_ROLE_IDS.has(id) || isHiddenAgent(id)) continue;
|
|
45
|
+
if (root === botsRoot && id === MIXY_BOT_ID) continue;
|
|
46
|
+
if (root === userRoot && migrated.has(id)) continue;
|
|
47
|
+
if (root === botsRoot && entry.name !== id) continue;
|
|
48
|
+
if (root === shippedRoot && (yield { op: 'exists', path: join(userRoot, id, AGENT_DELETED_MARKER) })) continue;
|
|
34
49
|
if (!(yield { op: 'exists', path: join(root, entry.name, 'AGENT.md') })) continue;
|
|
35
50
|
ids.add(id);
|
|
36
51
|
}
|
|
@@ -56,15 +71,24 @@ const agentListCache = createSharedScanCache();
|
|
|
56
71
|
|
|
57
72
|
export function createWorkflowAgents({ rootDir, dataDir, readMarkdownDocument, normalizeAgentPermissionOrNone }) {
|
|
58
73
|
function agentSourceDirs(dir, id) {
|
|
74
|
+
// A store bot reads only its own folder (agent-store.mjs).
|
|
75
|
+
if (isStoreBot(dir || dataDir, id)) return [userDefinitionDir(dir || dataDir, id)];
|
|
59
76
|
const userDir = join(dir || dataDir, 'agents', id);
|
|
60
77
|
if (existsSync(join(userDir, AGENT_DELETED_MARKER))) return [userDir];
|
|
61
78
|
return [userDir, join(rootDir, 'agents', id)];
|
|
62
79
|
}
|
|
63
80
|
|
|
64
81
|
function agentScan(dir) {
|
|
65
|
-
const
|
|
82
|
+
const base = dir || dataDir;
|
|
83
|
+
const userRoot = join(base, 'agents');
|
|
66
84
|
const shippedRoot = join(rootDir, 'agents');
|
|
67
|
-
|
|
85
|
+
const store = botStoreActive(base);
|
|
86
|
+
const migrated = store ? migratedBotIds(base) : new Set();
|
|
87
|
+
const botsRoot = store ? join(base, BOTS_DIR) : null;
|
|
88
|
+
return {
|
|
89
|
+
key: `${userRoot}\n${shippedRoot}\n${botsRoot || ''}\n${[...migrated].join(',')}`,
|
|
90
|
+
makeScan: () => scanCustomAgentIds(userRoot, shippedRoot, botsRoot, migrated),
|
|
91
|
+
};
|
|
68
92
|
}
|
|
69
93
|
|
|
70
94
|
function listCustomAgentIds(dir) {
|
|
@@ -100,7 +124,16 @@ export function createWorkflowAgents({ rootDir, dataDir, readMarkdownDocument, n
|
|
|
100
124
|
description: clean(manifest.description) || slot?.description || '',
|
|
101
125
|
permission: normalizeAgentPermissionOrNone(doc.frontmatter.permission),
|
|
102
126
|
frontmatter: doc.frontmatter,
|
|
127
|
+
// bot | agent | null, decided read-only (shared/agent-kind.mjs).
|
|
128
|
+
kind: agentDefinitionKind({
|
|
129
|
+
frontmatterKind: doc.frontmatter.kind,
|
|
130
|
+
...(d !== join(rootDir, 'agents', agentId)
|
|
131
|
+
? { dataDir: dir || dataDir, shippedRoot: rootDir, id: agentId, manifest, body }
|
|
132
|
+
: {}),
|
|
133
|
+
}),
|
|
103
134
|
body,
|
|
135
|
+
// Optional PERSONA.md beside AGENT.md (same dir, same cache entry).
|
|
136
|
+
persona: (readTextSafe(join(d, 'PERSONA.md')) || '').trim(),
|
|
104
137
|
};
|
|
105
138
|
setAgentDefinitionCache(cacheKey, definition);
|
|
106
139
|
return definition;
|