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
|
@@ -6,10 +6,16 @@ import { resolvePreToolAskApproval } from '../tool-helpers.mjs';
|
|
|
6
6
|
import { runAbortable, throwIfAborted } from '../../../../../shared/abort-race.mjs';
|
|
7
7
|
import { evaluateExecPolicy } from '../../../tools/bash-policy-scan.mjs';
|
|
8
8
|
import { beginSessionApprovalWait } from '../../manager/runtime-liveness.mjs';
|
|
9
|
+
import { agentMcpToolPermission } from '../../../mcp/agent-connectors.mjs';
|
|
10
|
+
import { humanGateDecision, recordHumanDecision } from '../../human-gate/gate.mjs';
|
|
11
|
+
import { applyEditedArgs } from '../../human-gate/requests.mjs';
|
|
9
12
|
|
|
10
13
|
const isArgsObject = (value) => value && typeof value === 'object' && !Array.isArray(value);
|
|
11
14
|
|
|
12
|
-
async function askApproval(
|
|
15
|
+
async function askApproval(
|
|
16
|
+
call,
|
|
17
|
+
{ callerSessionId, executeOpts, toolApprovalHook, decision, request = null, gate = null }
|
|
18
|
+
) {
|
|
13
19
|
const askReason = String(decision?.reason || 'approval requested by hook').trim();
|
|
14
20
|
// While the user decides, the session is waiting on them, not working.
|
|
15
21
|
const releaseApprovalWait = beginSessionApprovalWait(callerSessionId);
|
|
@@ -24,17 +30,45 @@ async function askApproval(call, { callerSessionId, executeOpts, toolApprovalHoo
|
|
|
24
30
|
toolCallId: executeOpts.toolCallId || null,
|
|
25
31
|
askReason,
|
|
26
32
|
toolApprovalHook,
|
|
33
|
+
request,
|
|
27
34
|
})
|
|
28
35
|
);
|
|
29
36
|
} finally {
|
|
30
37
|
releaseApprovalWait();
|
|
31
38
|
}
|
|
32
|
-
if (askOutcome.denial) return { denial: askOutcome.denial };
|
|
33
39
|
const approval = askOutcome.approval;
|
|
40
|
+
await recordHumanDecision(gate, approval);
|
|
41
|
+
if (askOutcome.denial) return { denial: askOutcome.denial };
|
|
34
42
|
if (approval && typeof approval === 'object' && isArgsObject(approval.args)) call.args = approval.args;
|
|
43
|
+
// The card's edited text replaces the model's before the call runs.
|
|
44
|
+
if (request?.kind === 'outbound' && approval?.editedArgs) {
|
|
45
|
+
call.args = applyEditedArgs(call.args, approval.editedArgs, request.outbound?.editable);
|
|
46
|
+
}
|
|
47
|
+
// The user approved this very call on the richer outbound card.
|
|
48
|
+
if (request?.kind === 'outbound') call.outboundApproved = true;
|
|
35
49
|
return null;
|
|
36
50
|
}
|
|
37
51
|
|
|
52
|
+
export const CONNECTOR_APPROVAL_REASON = 'This connector tool is set to ask before it runs for this agent.';
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* A connector tool the running agent set to `needs_approval` asks through the
|
|
56
|
+
* ordinary approval hook, whatever the PreToolUse hooks decided. Run after
|
|
57
|
+
* them, on the final call: a renamed call is judged under its final name.
|
|
58
|
+
* A call the outbound card already got approved is not asked a second time.
|
|
59
|
+
* @returns {Promise<{ denial: string } | null>} the denial, or null to run
|
|
60
|
+
*/
|
|
61
|
+
export function applyConnectorApproval(call, { agentId, callerSessionId, executeOpts, toolApprovalHook }) {
|
|
62
|
+
if (call.outboundApproved) return null;
|
|
63
|
+
if (agentMcpToolPermission(agentId, call.name) !== 'needs_approval') return null;
|
|
64
|
+
return askApproval(call, {
|
|
65
|
+
callerSessionId,
|
|
66
|
+
executeOpts,
|
|
67
|
+
toolApprovalHook,
|
|
68
|
+
decision: { reason: CONNECTOR_APPROVAL_REASON },
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
38
72
|
/**
|
|
39
73
|
* Elevation pass for a shell call (or a terminal `run`) whose exec policy
|
|
40
74
|
* decision is 'ask' (elevated launch). Runs after the final call is known.
|
|
@@ -62,22 +96,40 @@ export async function applyBeforeToolHook({
|
|
|
62
96
|
executeOpts,
|
|
63
97
|
beforeToolHook,
|
|
64
98
|
toolApprovalHook,
|
|
99
|
+
mcpScopeId = null,
|
|
65
100
|
}) {
|
|
66
101
|
const call = { name, args, cwd };
|
|
67
102
|
// ask_user is itself the user prompt; it never goes through the ordinary approval gate.
|
|
68
|
-
if (
|
|
103
|
+
if (name === 'ask_user') return call;
|
|
69
104
|
try {
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
105
|
+
const hookDecision = beforeToolHook
|
|
106
|
+
? await runAbortable(executeOpts.signal, () =>
|
|
107
|
+
beforeToolHook(
|
|
108
|
+
{
|
|
109
|
+
name,
|
|
110
|
+
args,
|
|
111
|
+
cwd,
|
|
112
|
+
sessionId: callerSessionId,
|
|
113
|
+
toolCallId: executeOpts.toolCallId || null,
|
|
114
|
+
},
|
|
115
|
+
{ signal: executeOpts.signal }
|
|
116
|
+
)
|
|
117
|
+
)
|
|
118
|
+
: null;
|
|
119
|
+
// Outbound sends ask the user whatever the hooks allowed (human-gate/gate.mjs).
|
|
120
|
+
// Judged as the call will run: only a rewriting decision changes name/args.
|
|
121
|
+
const hookAction = String(hookDecision?.action || hookDecision?.decision || '').toLowerCase();
|
|
122
|
+
const rewritten = hookAction === 'ask' || hookAction === 'modify' || hookAction === 'rewrite';
|
|
123
|
+
const { decision, request, gate } = await humanGateDecision(
|
|
124
|
+
{
|
|
125
|
+
name:
|
|
126
|
+
rewritten && typeof hookDecision?.name === 'string' && hookDecision.name.trim()
|
|
127
|
+
? hookDecision.name.trim()
|
|
128
|
+
: name,
|
|
129
|
+
args: rewritten && isArgsObject(hookDecision?.args) ? hookDecision.args : args,
|
|
130
|
+
},
|
|
131
|
+
hookDecision,
|
|
132
|
+
{ sessionId: callerSessionId, mcpScopeId }
|
|
81
133
|
);
|
|
82
134
|
const action = String(decision?.action || decision?.decision || '').toLowerCase();
|
|
83
135
|
if (action === 'deny' || action === 'block') {
|
|
@@ -89,7 +141,14 @@ export async function applyBeforeToolHook({
|
|
|
89
141
|
if (typeof decision?.name === 'string' && decision.name.trim()) call.name = decision.name.trim();
|
|
90
142
|
}
|
|
91
143
|
if (action === 'ask') {
|
|
92
|
-
const denied = await askApproval(call, {
|
|
144
|
+
const denied = await askApproval(call, {
|
|
145
|
+
callerSessionId,
|
|
146
|
+
executeOpts,
|
|
147
|
+
toolApprovalHook,
|
|
148
|
+
decision,
|
|
149
|
+
request,
|
|
150
|
+
gate,
|
|
151
|
+
});
|
|
93
152
|
if (denied) return denied;
|
|
94
153
|
}
|
|
95
154
|
} catch (error) {
|
|
@@ -14,7 +14,7 @@ import { runWithToolExecutionOwner } from '../../../../shared/tool-execution-own
|
|
|
14
14
|
import { runWithLocalSearchTelemetry } from '../../tools/builtin/local-search-telemetry.mjs';
|
|
15
15
|
import { throwIfAborted } from '../../../../shared/abort-race.mjs';
|
|
16
16
|
import { prepareToolCall } from './tool-exec/call-prep.mjs';
|
|
17
|
-
import { applyBeforeToolHook, applyShellElevationGate } from './tool-exec/before-hook.mjs';
|
|
17
|
+
import { applyBeforeToolHook, applyConnectorApproval, applyShellElevationGate } from './tool-exec/before-hook.mjs';
|
|
18
18
|
import { dispatchToolCall } from './tool-exec/dispatch.mjs';
|
|
19
19
|
import { applyAfterToolHook } from './tool-exec/after-hook.mjs';
|
|
20
20
|
import { runReadOnlyIoWithDeadline } from './tool-exec/read-only-deadline.mjs';
|
|
@@ -50,8 +50,16 @@ async function executeToolOwned(name, args, cwd, callerSessionId, sessionRef, ex
|
|
|
50
50
|
executeOpts,
|
|
51
51
|
beforeToolHook: hookFrom(executeOpts, sessionRef, 'beforeToolHook'),
|
|
52
52
|
toolApprovalHook,
|
|
53
|
+
mcpScopeId: sessionRef?.mcpScopeId || null,
|
|
53
54
|
});
|
|
54
55
|
if (hooked.denial) return hooked.denial;
|
|
56
|
+
const connectorDenied = await applyConnectorApproval(hooked, {
|
|
57
|
+
agentId: sessionRef?.agent,
|
|
58
|
+
callerSessionId,
|
|
59
|
+
executeOpts,
|
|
60
|
+
toolApprovalHook,
|
|
61
|
+
});
|
|
62
|
+
if (connectorDenied) return connectorDenied.denial;
|
|
55
63
|
// A decision can settle after its turn was cancelled. It must never
|
|
56
64
|
// authorize a new mutation, even if the hook ignores the abort signal.
|
|
57
65
|
throwIfAborted(executeOpts.signal);
|
|
@@ -27,12 +27,13 @@ function invalidateForToolSurfaceMigration(session) {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
|
-
* After a surface re-apply outside a request (resume, provider switch
|
|
31
|
-
*
|
|
30
|
+
* After a surface re-apply outside a request (resume, provider switch, a
|
|
31
|
+
* workflow switch: `intent`) changed the request prefix: the first send of the
|
|
32
|
+
* next turn carries the tag.
|
|
32
33
|
*/
|
|
33
|
-
export function markToolSurfaceMigrated(session) {
|
|
34
|
+
export function markToolSurfaceMigrated(session, intent = TOOL_SURFACE_MIGRATION_INTENT) {
|
|
34
35
|
invalidateForToolSurfaceMigration(session);
|
|
35
|
-
session.pendingCacheBreakIntent =
|
|
36
|
+
session.pendingCacheBreakIntent = intent;
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
/** Provider switch: rebuild the surface for `provider`, migrating bridge ↔ native. */
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// message-array change detect, tool-kind classification, skills, hook overrides,
|
|
3
3
|
// native tool-search payload parsing, bash-session routing, and approval.
|
|
4
4
|
import { isMcpTool } from '../../mcp/client.mjs';
|
|
5
|
+
import { unattendedApprovalPort } from '../human-gate/gate.mjs';
|
|
5
6
|
import { isBuiltinTool } from '../../tools/builtin.mjs';
|
|
6
7
|
import { isInternalTool } from '../../internal-tools.mjs';
|
|
7
8
|
import { loadSkillToolDependencies } from '../../runtime-core/skill-tool-loading.mjs';
|
|
@@ -207,15 +208,24 @@ export async function resolvePreToolAskApproval({
|
|
|
207
208
|
toolCallId,
|
|
208
209
|
askReason,
|
|
209
210
|
toolApprovalHook,
|
|
211
|
+
request = null,
|
|
210
212
|
}) {
|
|
211
213
|
const name = String(toolName || 'tool');
|
|
212
214
|
const reason = String(askReason || 'approval requested by hook').trim();
|
|
213
|
-
|
|
215
|
+
// Unattended runs never auto-approve and have no card: a schedule or webhook
|
|
216
|
+
// run always holds the request for its owner; a room member does when no
|
|
217
|
+
// approval UI is attached (session-runtime/held-requests.mjs).
|
|
218
|
+
const unattended = unattendedApprovalPort();
|
|
219
|
+
const run = unattended?.runOf?.(sessionId) || null;
|
|
220
|
+
const held = run && (run.kind !== 'room' || typeof toolApprovalHook !== 'function');
|
|
221
|
+
const ask = held ? unattended.hold : toolApprovalHook;
|
|
222
|
+
if (typeof ask !== 'function') {
|
|
214
223
|
return { denial: formatMissingToolApprovalUiDenial(name, reason) };
|
|
215
224
|
}
|
|
216
225
|
let approval;
|
|
217
226
|
try {
|
|
218
|
-
approval = await
|
|
227
|
+
approval = await ask({
|
|
228
|
+
...(request || {}),
|
|
219
229
|
name,
|
|
220
230
|
args,
|
|
221
231
|
cwd,
|
|
@@ -229,7 +239,7 @@ export async function resolvePreToolAskApproval({
|
|
|
229
239
|
}
|
|
230
240
|
if (!approvalGranted(approval)) {
|
|
231
241
|
const detail = approvalReason(approval, reason || 'not approved');
|
|
232
|
-
return { denial: `Error: tool "${name}" denied by hook: ${detail}
|
|
242
|
+
return { denial: `Error: tool "${name}" denied by hook: ${detail}`, approval };
|
|
233
243
|
}
|
|
234
244
|
return { approval };
|
|
235
245
|
}
|
|
@@ -41,6 +41,7 @@ export function usageDeltaEvent({
|
|
|
41
41
|
usage,
|
|
42
42
|
sendTools,
|
|
43
43
|
toolCalls = 0,
|
|
44
|
+
requestMs = 0,
|
|
44
45
|
}) {
|
|
45
46
|
return {
|
|
46
47
|
sessionId,
|
|
@@ -56,6 +57,13 @@ export function usageDeltaEvent({
|
|
|
56
57
|
deltaToolCalls: toolCalls,
|
|
57
58
|
...reasoningUsage(usage),
|
|
58
59
|
deltaPrompt: usage.promptTokens || 0,
|
|
60
|
+
// Request start → end of this response (first-token wait included, as the
|
|
61
|
+
// ledger's duration_ms); 0 when the call was not timed. Only timed output
|
|
62
|
+
// enters speed figures.
|
|
63
|
+
requestMs,
|
|
64
|
+
// A provider that cannot measure the prompt or its cache split says so;
|
|
65
|
+
// its zeros are unknowns, not readings (no cache hit can be derived).
|
|
66
|
+
promptKnown: usage.inputTokensKnown !== false && usage.cacheTokensKnown !== false,
|
|
59
67
|
// Cache delta carried alongside input/output so live metrics reflect
|
|
60
68
|
// the same token classes the terminal aggregate adds; additive —
|
|
61
69
|
// callers that ignore these fields keep working.
|
|
@@ -72,6 +80,47 @@ export function usageDeltaEvent({
|
|
|
72
80
|
};
|
|
73
81
|
}
|
|
74
82
|
|
|
83
|
+
const SUMMED_USAGE_FIELDS = [
|
|
84
|
+
'inputTokens',
|
|
85
|
+
'outputTokens',
|
|
86
|
+
'cachedTokens',
|
|
87
|
+
'cacheWriteTokens',
|
|
88
|
+
'cacheWrite1hTokens',
|
|
89
|
+
'promptTokens',
|
|
90
|
+
];
|
|
91
|
+
|
|
92
|
+
/** What `total` added after the running total `earlier` (both from addUsage); null when nothing. */
|
|
93
|
+
export function usageSince(total, earlier) {
|
|
94
|
+
if (!total) return null;
|
|
95
|
+
if (!earlier) return { ...total };
|
|
96
|
+
const delta = {};
|
|
97
|
+
for (const field of SUMMED_USAGE_FIELDS) delta[field] = Math.max(0, (total[field] || 0) - (earlier[field] || 0));
|
|
98
|
+
if (total.reasoningTokens != null) {
|
|
99
|
+
delta.reasoningTokens = Math.max(0, total.reasoningTokens - (earlier.reasoningTokens ?? 0));
|
|
100
|
+
delta.reasoningTokensComplete = total.reasoningTokensComplete === true;
|
|
101
|
+
}
|
|
102
|
+
if (total.costUsd != null) delta.costUsd = Math.max(0, total.costUsd - (earlier.costUsd || 0));
|
|
103
|
+
if (total.contextTokens) delta.contextTokens = total.contextTokens;
|
|
104
|
+
return Object.values(delta).some((value) => typeof value === 'number' && value > 0) ? delta : null;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* The turn's usage split per model when the route switched mid-turn:
|
|
109
|
+
* `hops` holds, per left model, the running total when it was left. Each
|
|
110
|
+
* segment carries only its own tokens so it is priced at its own rates.
|
|
111
|
+
*/
|
|
112
|
+
export function routeUsageSegments(hops, total, current) {
|
|
113
|
+
if (!Array.isArray(hops) || !hops.length) return null;
|
|
114
|
+
const boundaries = [...hops, { ...current, usage: total }];
|
|
115
|
+
return boundaries
|
|
116
|
+
.map((segment, index) => ({
|
|
117
|
+
provider: segment.provider,
|
|
118
|
+
model: segment.model,
|
|
119
|
+
usage: usageSince(segment.usage, index ? boundaries[index - 1].usage : null),
|
|
120
|
+
}))
|
|
121
|
+
.filter((segment) => segment.usage);
|
|
122
|
+
}
|
|
123
|
+
|
|
75
124
|
export function addUsage(total, usage) {
|
|
76
125
|
const delta = normalizeUsage(usage);
|
|
77
126
|
if (!delta) return total;
|
|
@@ -120,14 +120,24 @@ function recordAgentRuntimeCall(session, result) {
|
|
|
120
120
|
export async function recordAskUsage({ session, result, askStartedAt, turnSignal }) {
|
|
121
121
|
const prefixHashForLog = recordAgentRuntimeCall(session, result);
|
|
122
122
|
if (!result.usage) return;
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
123
|
+
// A turn that switched models mid-way books one row per model, each priced
|
|
124
|
+
// at that model's rates; otherwise one row for the whole turn.
|
|
125
|
+
const segments = result.usageSegments?.length
|
|
126
|
+
? result.usageSegments
|
|
127
|
+
: [{ provider: session.provider, model: session.model, usage: result.usage }];
|
|
128
|
+
for (const segment of segments) {
|
|
129
|
+
await logSessionLlmUsage({
|
|
130
|
+
session:
|
|
131
|
+
segment.provider === session.provider && segment.model === session.model
|
|
132
|
+
? session
|
|
133
|
+
: { ...session, provider: segment.provider, model: segment.model },
|
|
134
|
+
usage: segment.usage,
|
|
135
|
+
startedAt: askStartedAt,
|
|
136
|
+
signal: turnSignal,
|
|
137
|
+
prefixHash: prefixHashForLog,
|
|
138
|
+
transportTiming: result.transportTiming || null,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
131
141
|
recordStandaloneStatusTelemetry(session, result, Date.now() - askStartedAt);
|
|
132
142
|
}
|
|
133
143
|
|
|
@@ -186,6 +186,7 @@ export async function prepareAskTurn({ sessionId, opened, input, cwdOverride, tr
|
|
|
186
186
|
beforeCount: historyMessages.length + 1,
|
|
187
187
|
deferredToolDelta: userTurn.deferredToolDelta,
|
|
188
188
|
goalReminder: userTurn.goalReminder,
|
|
189
|
+
workflowNotice: userTurn.workflowNotice,
|
|
189
190
|
workspaceNotice: userTurn.workspaceNotice,
|
|
190
191
|
setupNotice: userTurn.setupNotice,
|
|
191
192
|
};
|
|
@@ -8,6 +8,7 @@ import { createAskSteeringDrain } from './ask-turn-steering-drain.mjs';
|
|
|
8
8
|
import { updateSessionStage, markSessionStreamDelta } from './runtime-liveness.mjs';
|
|
9
9
|
import { codexWireSendOpts } from './session-id.mjs';
|
|
10
10
|
import { persistIterationMetrics } from './usage-metrics.mjs';
|
|
11
|
+
import { isAgentModeSession } from '../agent-mode.mjs';
|
|
11
12
|
|
|
12
13
|
const optionalFn = (value) => (typeof value === 'function' ? value : undefined);
|
|
13
14
|
const relay = (fn, ...args) => {
|
|
@@ -184,7 +185,8 @@ export function buildAgentLoopOptions({
|
|
|
184
185
|
onCompactEvent: (event) => {
|
|
185
186
|
checkpoint.refreshContextState();
|
|
186
187
|
checkpoint.schedule(true);
|
|
187
|
-
|
|
188
|
+
// Agent mode compacts silently: no compaction notice reaches the host.
|
|
189
|
+
if (!isAgentModeSession(session)) relay(askOpts?.onCompactEvent, event);
|
|
188
190
|
},
|
|
189
191
|
// Pre-send gauge sync. Defined only when a host listens so the loop
|
|
190
192
|
// never computes a display number nobody reads.
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
snapshotPendingWorkspaceNotice,
|
|
20
20
|
snapshotPendingSetupNotice,
|
|
21
21
|
} from './prompt-utils.mjs';
|
|
22
|
+
import { snapshotPendingWorkflowNotice } from './workflow-switch-notice.mjs';
|
|
22
23
|
import { codexWireSendOpts } from './session-id.mjs';
|
|
23
24
|
import { _tryBridgeExplicitPrefetch } from './prefetch-bridge.mjs';
|
|
24
25
|
import { filterModelVisibleSessionMessages } from './message-sanitize.mjs';
|
|
@@ -180,7 +181,11 @@ export async function buildUserTurn({
|
|
|
180
181
|
const workspaceNotice = snapshotPendingWorkspaceNotice(session);
|
|
181
182
|
// What preparing a new worktree linked, installed, ran, failed or skipped.
|
|
182
183
|
const setupNotice = snapshotPendingSetupNotice(session);
|
|
184
|
+
// A mid-conversation workflow switch: the prompt and tools were rebuilt
|
|
185
|
+
// for the new workflow; this turn tells the model once.
|
|
186
|
+
const workflowNotice = snapshotPendingWorkflowNotice(session);
|
|
183
187
|
const reminderBlock = [
|
|
188
|
+
workflowNotice?.content || '',
|
|
184
189
|
workspaceNotice?.content || '',
|
|
185
190
|
setupNotice?.content || '',
|
|
186
191
|
currentTimeBlock ? `<system-reminder>\n# Current Time\n${currentTimeBlock}\n</system-reminder>` : '',
|
|
@@ -209,6 +214,7 @@ export async function buildUserTurn({
|
|
|
209
214
|
historyMessages,
|
|
210
215
|
deferredToolDelta,
|
|
211
216
|
goalReminder,
|
|
217
|
+
workflowNotice,
|
|
212
218
|
workspaceNotice,
|
|
213
219
|
setupNotice,
|
|
214
220
|
userTurnMessage,
|
|
@@ -9,6 +9,7 @@ import { persistedAssistantTranscriptMetadata } from '../../../../shared/transcr
|
|
|
9
9
|
import { acknowledgePendingDeferredToolDelta } from '../../runtime-core/deferred-tool-delta.mjs';
|
|
10
10
|
import { acknowledgePendingGoalReminder } from '../../runtime-core/goal-reminder.mjs';
|
|
11
11
|
import { acknowledgePendingSetupNotice, acknowledgePendingWorkspaceNotice } from './prompt-utils.mjs';
|
|
12
|
+
import { acknowledgePendingWorkflowNotice } from './workflow-switch-notice.mjs';
|
|
12
13
|
import {
|
|
13
14
|
finalizePendingMessageDelivery,
|
|
14
15
|
drainPendingMessages,
|
|
@@ -139,6 +140,7 @@ export async function commitAskTurn({ sessionId, opened, prepared, result, rawTr
|
|
|
139
140
|
if (prepared.goalReminder) {
|
|
140
141
|
acknowledgePendingGoalReminder(session, prepared.goalReminder.revision);
|
|
141
142
|
}
|
|
143
|
+
if (prepared.workflowNotice) acknowledgePendingWorkflowNotice(session, prepared.workflowNotice.revision);
|
|
142
144
|
if (prepared.workspaceNotice) {
|
|
143
145
|
acknowledgePendingWorkspaceNotice(session, prepared.workspaceNotice.revision);
|
|
144
146
|
}
|
|
@@ -40,14 +40,6 @@ export function currentPendingLifecycleToken(sessionId) {
|
|
|
40
40
|
return pendingLifecycleToken(pendingSessionLifecycle(sessionId));
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
// Refusal verdict of the lifecycle a token was minted from (tombstoned or
|
|
44
|
-
// unreadable) — exactly pendingLifecycleInvalidated(sessionId) for that same
|
|
45
|
-
// read, so a caller holding a fresh token needs no second durable read.
|
|
46
|
-
export function lifecycleTokenClosed(token) {
|
|
47
|
-
const { source } = parseLifecycleToken(token);
|
|
48
|
-
return source === 'closed' || source === 'unreadable';
|
|
49
|
-
}
|
|
50
|
-
|
|
51
43
|
// Parses a `source:generation` epoch token.
|
|
52
44
|
function parseLifecycleToken(token) {
|
|
53
45
|
const text = String(token);
|
|
@@ -207,29 +207,46 @@ function bp3SliceAt(text, heading) {
|
|
|
207
207
|
|
|
208
208
|
/**
|
|
209
209
|
* Replace the workspace-scoped tail of a BP3 core (composeSystemPrompt order:
|
|
210
|
-
* …, `#
|
|
211
|
-
*
|
|
212
|
-
*
|
|
213
|
-
*
|
|
210
|
+
* …, `# Instruction Files`, `# Core Memory`). Core memory is the last,
|
|
211
|
+
* separator-free part; the instruction-files slice before it may itself
|
|
212
|
+
* contain separators, so both are cut by position. A core from before that
|
|
213
|
+
* order (memory, then instruction files) is read too and written in the
|
|
214
|
+
* current order. `undefined` keeps a slice, an empty string drops it.
|
|
214
215
|
* @param {string} core
|
|
215
216
|
* @param {{ coreMemoryContext?: string, instructionFilesContext?: string }} slices
|
|
216
217
|
*/
|
|
217
218
|
export function replaceWorkspaceCoreSlices(core, { coreMemoryContext, instructionFilesContext } = {}) {
|
|
219
|
+
let { head, instructionFiles, memory } = splitWorkspaceCoreSlices(core);
|
|
220
|
+
if (coreMemoryContext !== undefined) {
|
|
221
|
+
const value = trimmedSlice(coreMemoryContext);
|
|
222
|
+
memory = value ? `${CORE_MEMORY_HEADING}${value}` : '';
|
|
223
|
+
}
|
|
224
|
+
if (instructionFilesContext !== undefined) instructionFiles = trimmedSlice(instructionFilesContext);
|
|
225
|
+
return [head, instructionFiles, memory].filter((part) => part?.trim()).join(BP3_PART_SEPARATOR);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/** A BP3 core's `{ head, instructionFiles, memory }` (each '' when absent). */
|
|
229
|
+
function splitWorkspaceCoreSlices(core) {
|
|
218
230
|
let head = String(core || '');
|
|
231
|
+
let memory = '';
|
|
232
|
+
const memoryAt = bp3SliceAt(head, CORE_MEMORY_HEADING);
|
|
233
|
+
if (memoryAt) {
|
|
234
|
+
memory = head.slice(memoryAt.start);
|
|
235
|
+
head = head.slice(0, memoryAt.cut);
|
|
236
|
+
const legacy = memory.indexOf(`${BP3_PART_SEPARATOR}${INSTRUCTION_FILES_HEADING}`);
|
|
237
|
+
if (legacy >= 0) {
|
|
238
|
+
const instructions = memory.slice(legacy + BP3_PART_SEPARATOR.length);
|
|
239
|
+
memory = memory.slice(0, legacy);
|
|
240
|
+
head = head ? `${head}${BP3_PART_SEPARATOR}${instructions}` : instructions;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
219
243
|
let instructionFiles = '';
|
|
220
244
|
const instructionAt = bp3SliceAt(head, INSTRUCTION_FILES_HEADING);
|
|
221
245
|
if (instructionAt) {
|
|
222
246
|
instructionFiles = head.slice(instructionAt.start);
|
|
223
247
|
head = head.slice(0, instructionAt.cut);
|
|
224
248
|
}
|
|
225
|
-
|
|
226
|
-
if (coreMemoryContext !== undefined) {
|
|
227
|
-
parts = parts.filter((part) => !part.startsWith(CORE_MEMORY_HEADING));
|
|
228
|
-
const memory = trimmedSlice(coreMemoryContext);
|
|
229
|
-
if (memory) parts.push(`${CORE_MEMORY_HEADING}${memory}`);
|
|
230
|
-
}
|
|
231
|
-
if (instructionFilesContext !== undefined) instructionFiles = trimmedSlice(instructionFilesContext);
|
|
232
|
-
return [...parts, instructionFiles].filter((part) => part?.trim()).join(BP3_PART_SEPARATOR);
|
|
249
|
+
return { head, instructionFiles, memory };
|
|
233
250
|
}
|
|
234
251
|
|
|
235
252
|
/**
|
|
@@ -286,9 +303,7 @@ function textOf(message) {
|
|
|
286
303
|
*/
|
|
287
304
|
function presentedWorkspace(session) {
|
|
288
305
|
const core = session.bp3EnvSplit === true ? textOf(bp3SystemMessage(session)) : String(session.bp3CoreContext || '');
|
|
289
|
-
const
|
|
290
|
-
const head = instructionAt ? core.slice(0, instructionAt.cut) : core;
|
|
291
|
-
const memory = (head ? head.split(BP3_PART_SEPARATOR) : []).find((part) => part.startsWith(CORE_MEMORY_HEADING));
|
|
306
|
+
const { instructionFiles, memory } = splitWorkspaceCoreSlices(core);
|
|
292
307
|
const tail = typeof session.bp3EnvironmentContext === 'string' ? session.bp3EnvironmentContext : '';
|
|
293
308
|
const facts = tail.split(BP3_PART_SEPARATOR)[0] || '';
|
|
294
309
|
const promptText = [textOf(bpEnvSystemMessage(session)), textOf(bp3SystemMessage(session))].join('\n');
|
|
@@ -297,10 +312,23 @@ function presentedWorkspace(session) {
|
|
|
297
312
|
cwd: cwd ? cwd.trim() : null,
|
|
298
313
|
environmentContext: facts.startsWith('- ') ? facts.trim() : '',
|
|
299
314
|
coreMemoryContext: memory ? memory.slice(CORE_MEMORY_HEADING.length).trim() : '',
|
|
300
|
-
instructionFilesContext:
|
|
315
|
+
instructionFilesContext: instructionFiles.trim(),
|
|
301
316
|
};
|
|
302
317
|
}
|
|
303
318
|
|
|
319
|
+
/**
|
|
320
|
+
* A rebuilt BP3 core head (composed without workspace slices) followed by the
|
|
321
|
+
* instruction-files and core-memory slices the session's prompt presents now,
|
|
322
|
+
* so a rebuild of the rest of the core (a mid-conversation workflow switch)
|
|
323
|
+
* leaves what the model was told about its workspace — and any staged
|
|
324
|
+
* workspaceReroot — as it was.
|
|
325
|
+
*/
|
|
326
|
+
export function withPresentedWorkspaceSlices(session, nextHead) {
|
|
327
|
+
const core = session.bp3EnvSplit === true ? textOf(bp3SystemMessage(session)) : String(session.bp3CoreContext || '');
|
|
328
|
+
const { instructionFiles, memory } = splitWorkspaceCoreSlices(core);
|
|
329
|
+
return [nextHead, instructionFiles, memory].filter((part) => part?.trim()).join(BP3_PART_SEPARATOR);
|
|
330
|
+
}
|
|
331
|
+
|
|
304
332
|
const WORKSPACE_SLICES = ['environmentContext', 'coreMemoryContext', 'instructionFilesContext'];
|
|
305
333
|
|
|
306
334
|
/**
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// Provider-native replay state on transcript messages: reasoning items,
|
|
2
|
+
// thinking blocks with their signatures, ordered native blocks, Gemini thought
|
|
3
|
+
// signatures on tool calls. It belongs to the provider (and the account) that
|
|
4
|
+
// produced it — another provider rejects it or, worse, a gateway of the same
|
|
5
|
+
// family validates it against its own key. A route change drops it; what the
|
|
6
|
+
// next provider needs (text, tool calls and their results, in order) stays,
|
|
7
|
+
// and each adapter rebuilds its own wire shape from that.
|
|
8
|
+
|
|
9
|
+
// Every message field a provider adapter replays or re-reads as native state.
|
|
10
|
+
const PROVIDER_REPLAY_FIELDS = [
|
|
11
|
+
'providerReplay',
|
|
12
|
+
'reasoning',
|
|
13
|
+
'thinkingBlocks',
|
|
14
|
+
'assistantBlocks',
|
|
15
|
+
'reasoningItems',
|
|
16
|
+
'reasoningContent',
|
|
17
|
+
'providerMetadata',
|
|
18
|
+
];
|
|
19
|
+
// Opaque provider tokens a tool call may carry (Gemini thought signatures).
|
|
20
|
+
const TOOL_CALL_SIGNATURE_FIELDS = ['thoughtSignature', 'thought_signature'];
|
|
21
|
+
|
|
22
|
+
const hasAny = (value, fields) => fields.some((field) => field in value);
|
|
23
|
+
|
|
24
|
+
function plainToolCalls(toolCalls) {
|
|
25
|
+
if (!Array.isArray(toolCalls) || !toolCalls.some((call) => call && hasAny(call, TOOL_CALL_SIGNATURE_FIELDS))) {
|
|
26
|
+
return toolCalls;
|
|
27
|
+
}
|
|
28
|
+
return toolCalls.map((call) => {
|
|
29
|
+
if (!call || !hasAny(call, TOOL_CALL_SIGNATURE_FIELDS)) return call;
|
|
30
|
+
const plain = { ...call };
|
|
31
|
+
for (const field of TOOL_CALL_SIGNATURE_FIELDS) delete plain[field];
|
|
32
|
+
return plain;
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** `message` without provider-native replay state; the same object when it carries none. */
|
|
37
|
+
export function stripProviderReplayMessage(message) {
|
|
38
|
+
if (!message || typeof message !== 'object') return message;
|
|
39
|
+
const toolCalls = plainToolCalls(message.toolCalls);
|
|
40
|
+
if (!hasAny(message, PROVIDER_REPLAY_FIELDS) && toolCalls === message.toolCalls) return message;
|
|
41
|
+
const plain = { ...message };
|
|
42
|
+
for (const field of PROVIDER_REPLAY_FIELDS) delete plain[field];
|
|
43
|
+
if (toolCalls !== message.toolCalls) plain.toolCalls = toolCalls;
|
|
44
|
+
return plain;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Replace, never mutate: delta saves see rewritten messages as changed. */
|
|
48
|
+
export function stripProviderReplayMessages(messages) {
|
|
49
|
+
return Array.isArray(messages) ? messages.map(stripProviderReplayMessage) : messages;
|
|
50
|
+
}
|
|
@@ -112,20 +112,36 @@ export function _buildAgentRules(profile = 'full') {
|
|
|
112
112
|
);
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
|
|
115
|
+
// One `part` of LEAD.md (rules-builder buildLeadRoleContent): 'common' (the
|
|
116
|
+
// lines every Lead shares), 'coding' / 'agent' (the mode-variant passages),
|
|
117
|
+
// 'identity' (the coding identity sentence).
|
|
118
|
+
export function _buildLeadRules({ includeLeadBrief = true, part = 'common' } = {}) {
|
|
116
119
|
const PLUGIN_ROOT = mixdogRoot();
|
|
117
120
|
const DATA_DIR = resolvePluginData();
|
|
118
121
|
const RULES_DIR = join(PLUGIN_ROOT, 'rules');
|
|
122
|
+
const variant = includeLeadBrief ? 'delegating' : 'delegation-free';
|
|
119
123
|
return buildCachedRules(
|
|
120
124
|
'buildLeadRoleContent',
|
|
121
125
|
'lead role rules',
|
|
122
126
|
[join(RULES_DIR, 'lead'), join(DATA_DIR, 'mixdog-config.json')],
|
|
123
|
-
{ PLUGIN_ROOT, DATA_DIR, includeLeadBrief },
|
|
124
|
-
|
|
127
|
+
{ PLUGIN_ROOT, DATA_DIR, includeLeadBrief, part },
|
|
128
|
+
`${variant}\n${part}`
|
|
125
129
|
);
|
|
126
130
|
}
|
|
127
131
|
|
|
128
|
-
|
|
132
|
+
// One agent-mode rule file (rules/agent-mode): 'conduct', 'mixy' or 'routine'.
|
|
133
|
+
export function _buildAgentModeRules({ part = 'conduct' } = {}) {
|
|
134
|
+
const PLUGIN_ROOT = mixdogRoot();
|
|
135
|
+
return buildCachedRules(
|
|
136
|
+
'buildAgentModeContent',
|
|
137
|
+
'agent mode rules',
|
|
138
|
+
[join(PLUGIN_ROOT, 'rules', 'agent-mode')],
|
|
139
|
+
{ PLUGIN_ROOT, part },
|
|
140
|
+
part
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function _buildLeadMetaContext({ includeOutputStyle = true } = {}) {
|
|
129
145
|
const PLUGIN_ROOT = mixdogRoot();
|
|
130
146
|
const DATA_DIR = resolvePluginData();
|
|
131
147
|
const RULES_DIR = join(PLUGIN_ROOT, 'rules');
|
|
@@ -138,7 +154,8 @@ export function _buildLeadMetaContext() {
|
|
|
138
154
|
join(PLUGIN_ROOT, 'output-styles'),
|
|
139
155
|
join(DATA_DIR, 'output-styles'),
|
|
140
156
|
],
|
|
141
|
-
{ PLUGIN_ROOT, DATA_DIR }
|
|
157
|
+
{ PLUGIN_ROOT, DATA_DIR, includeOutputStyle },
|
|
158
|
+
includeOutputStyle ? 'style' : 'no-style'
|
|
142
159
|
);
|
|
143
160
|
}
|
|
144
161
|
|