mixdog 1.3.0 → 1.3.2
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/NOTICE.md +52 -9
- package/README.md +8 -4
- package/package.json +2 -2
- package/scripts/native-release-status.mjs +238 -0
- package/src/defaults/shipped-history.json +8 -1
- package/src/defaults/skills/pptx/scripts/qc-pages.mjs +3 -2
- package/src/defaults/skills/setup/SKILL.md +23 -1
- package/src/defaults/skills/setup/references/actions.md +54 -4
- package/src/defaults/skills/setup/references/surfaces.md +23 -3
- package/src/defaults/skills/setup-guide/SKILL.md +17 -10
- package/src/defaults/skills/visualize/SKILL.md +9 -6
- package/src/defaults/skills/visualize/references/craft.md +8 -1
- package/src/help.mjs +1 -1
- package/src/lib/keychain-cjs.cjs +4 -1
- package/src/lib/rules-builder.cjs +14 -7
- package/src/output-styles/common.md +13 -8
- package/src/rules/agent-mode/AGENT_MODE.md +9 -6
- package/src/rules/agent-mode/MIXY.md +11 -6
- package/src/rules/lead/LEAD.md +2 -2
- package/src/rules/shared/10-tool-workflow.md +4 -0
- package/src/rules/shared/20-research.md +2 -0
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/preset.mjs +5 -0
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/session-prep.mjs +8 -0
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +6 -1
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +114 -26
- package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +8 -0
- package/src/runtime/agent/orchestrator/agent-runtime/room-supervisor-completion.mjs +5 -4
- package/src/runtime/agent/orchestrator/agent-trace.mjs +3 -0
- package/src/runtime/agent/orchestrator/cache-break-trace.mjs +4 -0
- package/src/runtime/agent/orchestrator/config-presets.mjs +2 -0
- package/src/runtime/agent/orchestrator/config-storage.mjs +10 -3
- package/src/runtime/agent/orchestrator/config.mjs +11 -0
- package/src/runtime/agent/orchestrator/context/role-instructions.mjs +81 -16
- package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +97 -4
- package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +6 -10
- package/src/runtime/agent/orchestrator/mcp/client.mjs +7 -4
- package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +80 -31
- package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +67 -38
- package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +7 -2
- package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +6 -2
- package/src/runtime/agent/orchestrator/providers/auto-effort.mjs +34 -16
- package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +31 -4
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +11 -8
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-prefix-trace.mjs +76 -0
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +19 -1
- package/src/runtime/agent/orchestrator/providers/lib/tail-reminder-split.mjs +13 -0
- package/src/runtime/agent/orchestrator/providers/lib/tool-call-wire-ids.mjs +65 -0
- package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +16 -1
- package/src/runtime/agent/orchestrator/providers/mixdog-local.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +5 -5
- package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +9 -5
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +9 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-retry-profile.mjs +8 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +10 -2
- package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +30 -3
- package/src/runtime/agent/orchestrator/providers/openai-model-capabilities.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +61 -8
- package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +14 -2
- package/src/runtime/agent/orchestrator/providers/registry.mjs +9 -0
- package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +17 -0
- package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +90 -24
- package/src/runtime/agent/orchestrator/runtime-core/fs-utils.mjs +8 -1
- package/src/runtime/agent/orchestrator/runtime-core/goal-mutations.mjs +1 -1
- package/src/runtime/agent/orchestrator/runtime-core/goal-storage.mjs +68 -22
- package/src/runtime/agent/orchestrator/runtime-core/goal-tool-exec.mjs +1 -1
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +5 -5
- package/src/runtime/agent/orchestrator/runtime-core/route-context-state.mjs +81 -0
- package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +2 -1
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +12 -1
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +17 -6
- package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +41 -10
- package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +6 -4
- package/src/runtime/agent/orchestrator/runtime-core/workflow/packs.mjs +8 -4
- package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/agent-mode.mjs +0 -6
- package/src/runtime/agent/orchestrator/session/agent-room-supervisor.d.mts +1 -1
- package/src/runtime/agent/orchestrator/session/agent-room-supervisor.mjs +22 -4
- package/src/runtime/agent/orchestrator/session/agent-room.d.mts +21 -2
- package/src/runtime/agent/orchestrator/session/agent-room.mjs +149 -45
- package/src/runtime/agent/orchestrator/session/attachment-preflight.mjs +80 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +14 -11
- package/src/runtime/agent/orchestrator/session/compact/forked-summary.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +68 -18
- package/src/runtime/agent/orchestrator/session/compact/summary-mode.mjs +16 -0
- package/src/runtime/agent/orchestrator/session/compact/summary-route.mjs +87 -0
- package/src/runtime/agent/orchestrator/session/compact/summary.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/compact/text-utils.mjs +5 -1
- package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +41 -10
- package/src/runtime/agent/orchestrator/session/human-gate/delegation.mjs +230 -0
- package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +156 -25
- package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +20 -0
- package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +21 -9
- package/src/runtime/agent/orchestrator/session/human-gate/run-policy.mjs +73 -0
- package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +55 -27
- package/src/runtime/agent/orchestrator/session/human-gate/unattended-port.mjs +15 -0
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +189 -105
- package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +9 -0
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +6 -2
- package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +111 -9
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +11 -14
- package/src/runtime/agent/orchestrator/session/loop/steering.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +38 -5
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +21 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +12 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +11 -5
- package/src/runtime/agent/orchestrator/session/loop/usage.mjs +46 -4
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +13 -2
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-commit.mjs +18 -8
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +44 -18
- package/src/runtime/agent/orchestrator/session/manager/orchestration-mode-switch-notice.mjs +99 -0
- package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +42 -0
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +3 -9
- package/src/runtime/agent/orchestrator/session/manager/pending-spool-file.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/pending-spool-shard.mjs +5 -3
- package/src/runtime/agent/orchestrator/session/manager/provider-replay.mjs +50 -0
- package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +40 -1
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +12 -0
- package/src/runtime/agent/orchestrator/session/manager/runtime-state.mjs +20 -0
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +62 -47
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +6 -8
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +12 -1
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +6 -15
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +7 -1
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +24 -8
- package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/workflow-switch-notice.mjs +94 -13
- package/src/runtime/agent/orchestrator/session/mixy-name.mjs +5 -2
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +42 -10
- package/src/runtime/agent/orchestrator/session/provider-prefix-guard.mjs +21 -3
- package/src/runtime/agent/orchestrator/session/routine-result.d.mts +35 -4
- package/src/runtime/agent/orchestrator/session/routine-result.mjs +179 -16
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +5 -1
- package/src/runtime/agent/orchestrator/session/side-question-store.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/store/canonical-reader.mjs +41 -7
- package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +10 -2
- package/src/runtime/agent/orchestrator/session/store/load-cache.mjs +14 -2
- package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +15 -1
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-record.mjs +8 -3
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +36 -1
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +40 -5
- package/src/runtime/agent/orchestrator/session/store-summary-last-message.mjs +47 -2
- package/src/runtime/agent/orchestrator/session/tail-reminder-rules.mjs +125 -0
- package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +78 -43
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +49 -14
- package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +134 -17
- package/src/runtime/agent/orchestrator/tools/builtin/advisory-lock.mjs +35 -13
- package/src/runtime/agent/orchestrator/tools/builtin/atomic-write.mjs +25 -5
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +4 -3
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +13 -14
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/transport-artifacts.mjs +9 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +19 -14
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +6 -14
- package/src/runtime/agent/orchestrator/tools/builtin/pdf-test-fixtures.mjs +5 -3
- package/src/runtime/agent/orchestrator/tools/builtin/read-image.mjs +4 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-media.mjs +47 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-special-files.mjs +264 -87
- package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +10 -4
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +34 -21
- package/src/runtime/agent/orchestrator/tools/code-graph/constants.mjs +8 -4
- package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +9 -30
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +24 -12
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +3 -2
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +6 -2
- package/src/runtime/agent/orchestrator/tools/patch/delete-quarantine.mjs +2 -1
- package/src/runtime/agent/orchestrator/tools/patch/replay-capture.mjs +4 -2
- package/src/runtime/agent/orchestrator/tools/patch/rollback-state.mjs +33 -2
- package/src/runtime/agent/orchestrator/tools/patch-manifest.json +13 -13
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +5 -3
- package/src/runtime/agent/orchestrator/tools/shell-exec-output.mjs +3 -1
- package/src/runtime/attachments/attachment-reference.mjs +155 -0
- package/src/runtime/attachments/limits.mjs +5 -1
- package/src/runtime/attachments/office-extract.mjs +3 -6
- package/src/runtime/attachments/pdf-extract.mjs +84 -10
- package/src/runtime/attachments/store.mjs +55 -30
- package/src/runtime/browser-bridge/client.mjs +73 -20
- package/src/runtime/channels/lib/runtime-paths.mjs +1 -1
- package/src/runtime/channels/lib/scheduler.mjs +14 -7
- package/src/runtime/channels/lib/state-file.mjs +15 -15
- package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +14 -13
- package/src/runtime/channels/lib/webhook/relay-tunnel.mjs +22 -18
- package/src/runtime/channels/lib/webhook/session-dispatch.mjs +14 -36
- package/src/runtime/channels/lib/worker-main.mjs +3 -2
- package/src/runtime/effort-judge/compact-tokenizer.mjs +8 -2
- package/src/runtime/effort-judge/judge-client.mjs +6 -3
- package/src/runtime/effort-judge/model-install.mjs +16 -8
- package/src/runtime/effort-judge/model-manifest.json +7 -7
- package/src/runtime/local-provider/asset-installer.mjs +10 -4
- package/src/runtime/local-provider/catalog.mjs +5 -2
- package/src/runtime/local-provider/registered-models.mjs +64 -27
- package/src/runtime/local-provider/server.mjs +2 -3
- package/src/runtime/media/adapters/image-api.mjs +89 -0
- package/src/runtime/media/auth.mjs +64 -1
- package/src/runtime/media/catalog.mjs +66 -4
- package/src/runtime/media/jobs.mjs +4 -0
- package/src/runtime/media/lanes.mjs +46 -5
- package/src/runtime/media/media-usage.mjs +17 -0
- package/src/runtime/media/renditions.mjs +15 -15
- package/src/runtime/media/store.mjs +36 -35
- package/src/runtime/media/tool.mjs +8 -1
- package/src/runtime/memory/lib/cycle-scheduler/health-ledger.mjs +8 -2
- package/src/runtime/memory/lib/embedding-model-files.mjs +30 -7
- package/src/runtime/memory/lib/ingest/transcript-tail.mjs +16 -7
- package/src/runtime/memory/lib/pg/process.mjs +8 -4
- package/src/runtime/memory/lib/project-id-resolver.mjs +5 -1
- package/src/runtime/memory/lib/runtime-fetcher.mjs +6 -1
- package/src/runtime/office/core/journal.mjs +7 -14
- package/src/runtime/office/design/library/design-library-core.mjs +4 -16
- package/src/runtime/office/pdf/ocr-engine-worker.mjs +37 -0
- package/src/runtime/office/pdf/ocr-engine.mjs +146 -0
- package/src/runtime/office/pdf/pdf-ocr.mjs +51 -21
- package/src/runtime/office/pdf/pdf-render.mjs +30 -18
- package/src/runtime/office/portable/ooxml-validator.mjs +2 -2
- package/src/runtime/office/portable/portable-soffice.mjs +4 -0
- package/src/runtime/shared/agent-kind-migration.mjs +200 -0
- package/src/runtime/shared/agent-kind.mjs +152 -0
- package/src/runtime/shared/agent-message-envelope.d.mts +6 -0
- package/src/runtime/shared/agent-message-envelope.mjs +44 -0
- package/src/runtime/shared/agent-reap-state.d.mts +4 -0
- package/src/runtime/shared/agent-route-config.d.mts +1 -0
- package/src/runtime/shared/agent-route-config.mjs +22 -8
- package/src/runtime/shared/agent-store.mjs +149 -0
- package/src/runtime/shared/agent-task-starts.mjs +27 -0
- package/src/runtime/shared/atomic-file.d.mts +50 -0
- package/src/runtime/shared/atomic-file.mjs +394 -132
- package/src/runtime/shared/background-tasks.mjs +7 -4
- package/src/runtime/shared/bot-hops.mjs +30 -0
- package/src/runtime/shared/bot-split-migration.mjs +457 -0
- package/src/runtime/shared/bounded-download.mjs +4 -2
- package/src/runtime/shared/config-patch.mjs +20 -1
- package/src/runtime/shared/config.mjs +39 -9
- package/src/runtime/shared/connector-catalog.d.mts +1 -2
- package/src/runtime/shared/connector-catalog.mjs +2 -4
- package/src/runtime/shared/connector-triggers.mjs +2 -0
- package/src/runtime/shared/defaults-separation.mjs +6 -2
- package/src/runtime/shared/delegated-approval-host.mjs +74 -0
- package/src/runtime/shared/err-text.mjs +7 -1
- package/src/runtime/shared/error-presentation.mjs +113 -10
- package/src/runtime/shared/file-has-data.mjs +28 -0
- package/src/runtime/shared/handoff-artifacts.d.mts +20 -0
- package/src/runtime/shared/handoff-artifacts.mjs +61 -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/llm/usage-ledger-import.mjs +37 -18
- package/src/runtime/shared/model-route-fallback.mjs +79 -7
- package/src/runtime/shared/pending-agent-work.mjs +54 -0
- package/src/runtime/shared/plain-preview.mjs +22 -17
- package/src/runtime/shared/process-lifecycle.mjs +8 -12
- package/src/runtime/shared/projects.mjs +50 -41
- package/src/runtime/shared/provider-accounts.mjs +17 -12
- package/src/runtime/shared/routine-trigger.d.mts +6 -1
- package/src/runtime/shared/routine-trigger.mjs +14 -6
- package/src/runtime/shared/run-child.d.mts +3 -0
- package/src/runtime/shared/run-child.mjs +24 -3
- 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/session-baseline-store.mjs +8 -2
- package/src/runtime/shared/singleton-owner.mjs +7 -6
- package/src/runtime/shared/skill-tool-dependencies.mjs +4 -10
- package/src/runtime/shared/staged-update.mjs +4 -2
- package/src/runtime/shared/statusline/statusline-segments.mjs +4 -15
- package/src/runtime/shared/tool-execution-contract.mjs +6 -0
- package/src/runtime/shared/transcript-metadata.mjs +28 -3
- package/src/runtime/shared/transcript-writer/session-record.mjs +7 -6
- package/src/runtime/shared/turn-snapshot-store.mjs +5 -4
- package/src/runtime/shared/turn-snapshot.mjs +44 -2
- package/src/runtime/shared/usage-readout-totals.mjs +15 -13
- package/src/runtime/shared/user-cwd.mjs +9 -4
- package/src/runtime/shared/user-data-guard.mjs +46 -44
- package/src/runtime/shared/utf8-cut.mjs +10 -0
- package/src/runtime/shared/worktrees/activity-gate.mjs +269 -61
- package/src/runtime/shared/worktrees/registry.mjs +26 -26
- package/src/runtime/tidy/core-install.mjs +26 -4
- package/src/runtime/tidy/install.mjs +91 -23
- package/src/runtime/web-search/lib/config.mjs +4 -16
- package/src/session-runtime/agent-home-delivery.mjs +859 -136
- package/src/session-runtime/agent-room-delivery.mjs +167 -19
- package/src/session-runtime/agent-task-sessions.mjs +831 -69
- package/src/session-runtime/agent-tool-routing.mjs +1 -0
- package/src/session-runtime/boot/apis.mjs +58 -24
- package/src/session-runtime/boot/config.mjs +1 -0
- package/src/session-runtime/boot/facade.mjs +11 -1
- package/src/session-runtime/boot/infrastructure.mjs +14 -2
- package/src/session-runtime/boot/providers.mjs +16 -6
- package/src/session-runtime/boot/shared.mjs +12 -6
- package/src/session-runtime/boot/tools.mjs +2 -2
- package/src/session-runtime/bot-status.mjs +432 -0
- package/src/session-runtime/config-lifecycle/lead-route-sync.mjs +29 -0
- package/src/session-runtime/config-lifecycle.mjs +78 -32
- package/src/session-runtime/cwd-plugins/core-memory-context.mjs +2 -4
- package/src/session-runtime/handoff-attachments.mjs +593 -0
- package/src/session-runtime/held-requests.mjs +36 -33
- package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +10 -1
- package/src/session-runtime/internal-tool-executor/feature-tools.mjs +2 -2
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +45 -6
- package/src/session-runtime/lifecycle/session-catalog.mjs +12 -2
- package/src/session-runtime/lifecycle/teardown.mjs +11 -3
- package/src/session-runtime/mcp-glue/connect.mjs +100 -186
- package/src/session-runtime/mcp-glue/initial-connect-gate.mjs +57 -0
- package/src/session-runtime/mcp-glue/server-connection.mjs +71 -0
- package/src/session-runtime/media-api.mjs +5 -2
- package/src/session-runtime/model-route/route-persist.mjs +2 -2
- package/src/session-runtime/model-route/route-tuning.mjs +11 -2
- package/src/session-runtime/model-route/set-route.mjs +82 -2
- 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 +8 -1
- package/src/session-runtime/room-member-gate.mjs +16 -3
- package/src/session-runtime/route-resolution.mjs +21 -19
- package/src/session-runtime/route-state.mjs +1 -59
- package/src/session-runtime/routine-home-turn.mjs +5 -3
- package/src/session-runtime/runtime-bootstrap.mjs +5 -3
- package/src/session-runtime/runtime-paths.mjs +11 -5
- package/src/session-runtime/runtime-tunables.mjs +6 -0
- package/src/session-runtime/services/agent-tool/close-flow/close-all.mjs +11 -2
- package/src/session-runtime/services/agent-tool/close-flow.mjs +4 -2
- package/src/session-runtime/services/agent-tool/execute-send.mjs +1 -0
- package/src/session-runtime/services/agent-tool/execute-spawn.mjs +1 -0
- package/src/session-runtime/services/agent-tool/helpers.mjs +24 -5
- package/src/session-runtime/services/agent-tool/restart-notify.mjs +10 -0
- package/src/session-runtime/services/agent-tool/send-flow.mjs +36 -24
- package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +4 -0
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +6 -3
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +12 -6
- 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/agent-tool/worker-index/row-liveness.mjs +22 -2
- package/src/session-runtime/services/agent-tool/worker-index.mjs +4 -6
- package/src/session-runtime/services/agent-tool.mjs +6 -0
- package/src/session-runtime/services/daemon-crash-capture/daemon-exit-record.mjs +1 -1
- package/src/session-runtime/services/daemon-crash-capture/retention.mjs +4 -3
- package/src/session-runtime/services/hook-bus/config-loader.mjs +14 -5
- package/src/session-runtime/services/hook-bus/rule-file.mjs +49 -11
- package/src/session-runtime/services/plugin-admin.mjs +26 -26
- package/src/session-runtime/services/provider-admin.mjs +14 -4
- package/src/session-runtime/services/schedule-access.mjs +33 -4
- package/src/session-runtime/services/seeds.mjs +4 -3
- package/src/session-runtime/services/usage-dashboard.mjs +1 -1
- package/src/session-runtime/services/usage-stats-model.mjs +2 -1
- package/src/session-runtime/session-create/materialize.mjs +2 -3
- package/src/session-runtime/session-create/session-options.mjs +15 -2
- package/src/session-runtime/settings-builtin-tools-api.mjs +63 -1
- package/src/session-runtime/settings-compaction-api.mjs +86 -39
- package/src/session-runtime/setup-tool/executor.mjs +20 -3
- package/src/session-runtime/setup-tool/extended-actions.mjs +19 -7
- package/src/session-runtime/setup-tool/settings-contract.mjs +37 -1
- package/src/session-runtime/setup-tool/tool-defs.mjs +20 -3
- package/src/session-runtime/skills-api.mjs +12 -5
- package/src/session-runtime/tool-policy/agent-profile-fold.mjs +265 -0
- package/src/session-runtime/tool-policy/mode-switch.mjs +54 -0
- package/src/session-runtime/tool-policy/pending-switches.mjs +59 -0
- package/src/session-runtime/tool-policy/policy-stage.mjs +165 -0
- package/src/session-runtime/tool-policy/session-switches.mjs +169 -0
- package/src/session-runtime/tool-policy/surface-helpers.mjs +114 -0
- package/src/session-runtime/tool-policy/workflow-overlay.mjs +145 -0
- package/src/session-runtime/tool-policy-refresh.mjs +47 -358
- package/src/session-runtime/tool-surface.mjs +5 -3
- package/src/session-runtime/turn/turn-run/turn-prepare.mjs +99 -81
- package/src/session-runtime/turn/turn-run/turn-timing.mjs +4 -3
- package/src/session-runtime/turn/turn-run.mjs +2 -1
- package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +54 -7
- package/src/session-runtime/workflow-agents-api/agent-editor.mjs +578 -301
- package/src/session-runtime/workflow-agents-api/agent-route.mjs +113 -53
- package/src/session-runtime/workflow-agents-api/onboarding.mjs +11 -4
- package/src/session-runtime/workflow-agents-api/shared.mjs +5 -1
- package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +14 -1
- package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +6 -3
- package/src/session-runtime/workspace/workspace-state.mjs +7 -6
- package/src/standalone/daemon-agent-control.mjs +4 -1
- package/src/standalone/daemon-session-control.mjs +60 -11
- package/src/standalone/daemon.mjs +34 -4
- package/src/standalone/local-session-runtime.mjs +22 -14
- package/src/standalone/session-client.mjs +7 -2
- package/src/standalone/session-protocol.mjs +7 -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 +19 -0
- package/src/standalone/session-service.mjs +11 -0
- package/src/standalone/session-state-projection.mjs +19 -9
- package/src/standalone/session-tool-output.mjs +35 -9
- package/src/tui/app/maintenance-pickers/auto-clear-picker.mjs +19 -13
- package/src/tui/app/settings-picker/settings-rows.mjs +2 -2
- package/src/tui/app/slash-commands.mjs +1 -1
- package/src/tui/app/usage-context-panels/context-model.mjs +8 -2
- package/src/tui/dist/index.mjs +599 -342
- package/src/tui/prompt-history-store.mjs +16 -21
- package/src/tui/session/context-state.mjs +4 -0
- package/src/tui/session/notice-surface.mjs +3 -4
- package/src/tui/session/session-api/intake/abort.mjs +19 -1
- package/src/tui/session/session-api/media.mjs +2 -1
- package/src/tui/session/session-api/routes-agent-definitions.mjs +75 -0
- package/src/tui/session/session-api/routes-write.mjs +203 -0
- package/src/tui/session/session-api/routes.mjs +23 -236
- package/src/tui/session/session-api/settings.mjs +14 -1
- package/src/tui/session/session-flow/drain.mjs +28 -3
- package/src/tui/session/session-flow/failed-turn-rewind.mjs +4 -2
- package/src/tui/session/session-flow/queue/take-entries.mjs +8 -0
- package/src/tui/session/session-flow/steering.mjs +8 -3
- package/src/tui/session/tool-approval.mjs +185 -20
- package/src/tui/session/transcript-intake.mjs +4 -0
- package/src/tui/session/turn-live-call.mjs +11 -3
- package/src/tui/session/turn.mjs +36 -17
- package/src/tui/transcript-tool-failures.mjs +8 -2
- package/src/vendor/statusline/src/gateway/route-meta.mjs +7 -8
- package/src/vendor/statusline/src/gateway/session-routes.mjs +6 -7
- package/src/rules/agent-mode/ROUTINE.md +0 -6
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// What the compaction summary route choice reads: whether the session's
|
|
2
|
+
// prompt cache is still warm (a fork of its last request would read it), and
|
|
3
|
+
// the lighter model of a subscription provider.
|
|
4
|
+
import { cacheCapabilityForProvider, providerTailCacheLifetimeMs } from '../../agent-runtime/cache-strategy.mjs';
|
|
5
|
+
import { getModelMetadataSync } from '../../../../shared/llm/model-catalog.mjs';
|
|
6
|
+
import {
|
|
7
|
+
_compareVersion as compareAnthropicVersion,
|
|
8
|
+
_loadModelCache as loadAnthropicCatalogCache,
|
|
9
|
+
} from '../../providers/anthropic-model-resolve.mjs';
|
|
10
|
+
import { gptVersion } from '../../providers/openai-model-capabilities.mjs';
|
|
11
|
+
import { loadSavedCodexCatalog } from '../../providers/openai-oauth-catalog-store.mjs';
|
|
12
|
+
import { compactionForkRequest } from '../side-question-store.mjs';
|
|
13
|
+
|
|
14
|
+
// A provider outside the Anthropic/OpenAI lifetimes whose catalog marks prompt
|
|
15
|
+
// caching: the shortest common cache lifetime (Gemini's default TTL).
|
|
16
|
+
const CATALOG_PROMPT_CACHE_LIFETIME_MS = 5 * 60_000;
|
|
17
|
+
// The cache is read when the fork is sent, after the route choice: a request
|
|
18
|
+
// this close to its lifetime counts as cold.
|
|
19
|
+
const WARM_MARGIN_MIN_MS = 30_000;
|
|
20
|
+
const WARM_MARGIN_RATIO = 0.1;
|
|
21
|
+
|
|
22
|
+
/** How long the cache a saved request wrote or read stays readable, in ms:
|
|
23
|
+
* Infinity when it does not expire (openai-oauth), 0 when it is not cached.
|
|
24
|
+
* Anthropic: the request's message-tail tier (5m / 1h); OpenAI: the 30m tail
|
|
25
|
+
* that holds the conversation (the Lead's 12h breakpoint covers only the
|
|
26
|
+
* stable tools/instructions prefix). */
|
|
27
|
+
function requestCacheLifetimeMs(request) {
|
|
28
|
+
const name = request?.provider?.name;
|
|
29
|
+
if (name === 'openai-oauth') return Infinity;
|
|
30
|
+
if (name === 'openai' || cacheCapabilityForProvider(name) === 'explicit-breakpoint') {
|
|
31
|
+
return providerTailCacheLifetimeMs(name, request.opts?.cacheStrategy) ?? 0;
|
|
32
|
+
}
|
|
33
|
+
const info = request.provider.getCachedModelInfo?.(request.model) || getModelMetadataSync(request.model, name);
|
|
34
|
+
return info?.supportsPromptCaching ? CATALOG_PROMPT_CACHE_LIFETIME_MS : 0;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Whether the session's last settled request is still inside the cache
|
|
38
|
+
* lifetime it used, with a safety margin. No forkable request = cold. */
|
|
39
|
+
export function compactionCacheWarm(sessionId, now = Date.now()) {
|
|
40
|
+
const request = compactionForkRequest(sessionId);
|
|
41
|
+
if (!request) return false;
|
|
42
|
+
const lifetime = requestCacheLifetimeMs(request);
|
|
43
|
+
if (lifetime === Infinity) return true;
|
|
44
|
+
const margin = Math.max(WARM_MARGIN_MIN_MS, lifetime * WARM_MARGIN_RATIO);
|
|
45
|
+
return now - Number(request.sentAt) < lifetime - margin;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function compareGptVersion(a, b) {
|
|
49
|
+
const [aMajor, aMinor] = gptVersion(a);
|
|
50
|
+
const [bMajor, bMinor] = gptVersion(b);
|
|
51
|
+
// Same version: the undated alias over a dated snapshot.
|
|
52
|
+
return aMajor - bMajor || aMinor - bMinor || b.length - a.length;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// The lighter family per subscription provider: its newest catalog model.
|
|
56
|
+
// API-key providers bill per token and get no lighter step. `catalog` reads
|
|
57
|
+
// the provider's saved catalog only (disk cache, no auth or network on the
|
|
58
|
+
// compaction path): Anthropic's within its 24h TTL, Codex's stale or not.
|
|
59
|
+
const LIGHTER_FAMILY = Object.freeze({
|
|
60
|
+
'anthropic-oauth': {
|
|
61
|
+
catalog: loadAnthropicCatalogCache,
|
|
62
|
+
matches: (row) => row.family === 'haiku',
|
|
63
|
+
compare: compareAnthropicVersion,
|
|
64
|
+
},
|
|
65
|
+
'openai-oauth': {
|
|
66
|
+
catalog: loadSavedCodexCatalog,
|
|
67
|
+
matches: (row, id) => id.includes('-luna') && gptVersion(id) !== null,
|
|
68
|
+
compare: compareGptVersion,
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
/** The newest lighter-family model the saved catalog of `providerName` lists
|
|
73
|
+
* for this account, or null (not a subscription provider, no saved catalog,
|
|
74
|
+
* none listed). */
|
|
75
|
+
export async function lighterSubscriptionModel(providerName) {
|
|
76
|
+
const family = LIGHTER_FAMILY[providerName];
|
|
77
|
+
if (!family) return null;
|
|
78
|
+
const catalog = await family.catalog();
|
|
79
|
+
if (!Array.isArray(catalog)) return null;
|
|
80
|
+
let best = null;
|
|
81
|
+
for (const row of catalog) {
|
|
82
|
+
const id = String(row?.id || '');
|
|
83
|
+
if (!id || !family.matches(row, id)) continue;
|
|
84
|
+
if (!best || family.compare(id, best) > 0) best = id;
|
|
85
|
+
}
|
|
86
|
+
return best;
|
|
87
|
+
}
|
|
@@ -59,6 +59,8 @@ Rules:
|
|
|
59
59
|
- Use terse bullets, not prose paragraphs.
|
|
60
60
|
- Preserve exact file paths, commands, error strings, and identifiers when known.
|
|
61
61
|
- Use the same language as the active user thread when it is clear.
|
|
62
|
+
- Record work as Done or In Progress only when a tool call and its result in the history show it (an agent spawn/send result, an edit, a command outcome). An assistant's stated intent with no matching tool call is not started: list it under Next Steps as "announced, not started".
|
|
63
|
+
- Attribute every decision, answer, and version/choice to its source: the user (message or ask_user answer), a named agent's report, or the assistant. Never credit an agent or the assistant with a user's answer.
|
|
62
64
|
- Do not mention the summary process or that context was compacted.`;
|
|
63
65
|
|
|
64
66
|
// The final user turn of a summary forked from the session's own cached
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
// Text/token/message helpers and secret redaction for compaction.
|
|
2
2
|
import { createHash } from 'node:crypto';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
attachmentTextForPart,
|
|
5
|
+
isAttachmentReference,
|
|
6
|
+
isPermanentAttachmentError,
|
|
7
|
+
} from '../../../../attachments/store.mjs';
|
|
4
8
|
import { estimateMessagesTokens } from '../context-utils.mjs';
|
|
5
9
|
import { inlineFileKind } from '../../../../shared/inline-file-kind.mjs';
|
|
6
10
|
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { SUMMARY_PREFIX_ANCHOR } from './summary-anchor.mjs';
|
|
6
6
|
import { isImportedMessage } from '../imported-message.mjs';
|
|
7
7
|
import {
|
|
8
|
+
CONTROL_MARKER_RE,
|
|
8
9
|
isInternalRuntimeNotificationText,
|
|
9
10
|
isModelVisibleToolCompletionWrapper,
|
|
10
11
|
} from '../../../../shared/tool-execution-contract.mjs';
|
|
@@ -132,7 +133,6 @@ export function isActualUserInstructionMessage(message) {
|
|
|
132
133
|
// isActualUserInstructionMessage deliberately keeps treating "[truncated]" as
|
|
133
134
|
// an instruction (compaction tail selection depends on it), so the real-turn
|
|
134
135
|
// predicate below recognizes it on its own.
|
|
135
|
-
const CONTROL_MARKER_RE = /^\[(?:truncated|request interrupted(?: by user(?: for tool use)?| by process restart)?)\]$/i;
|
|
136
136
|
|
|
137
137
|
/** Whether a message stands for real human conversation: a compact summary
|
|
138
138
|
* (it replaced earlier human turns), imported prose, or the user's own
|
|
@@ -226,7 +226,7 @@ const recordExists = (dir, sessionId) => existsSync(join(dir, `${sessionId}.json
|
|
|
226
226
|
* since `epoch` was captured wins. Any outcome but a rename removes the temp
|
|
227
227
|
* file. */
|
|
228
228
|
async function publishArchive({ dir, path, sessionId, text, epoch }) {
|
|
229
|
-
const tmp = join(dir,
|
|
229
|
+
const tmp = join(dir, `${basename(path)}.mixdog-tmp-${randomBytes(4).toString('hex')}`);
|
|
230
230
|
const removeTmp = () => {
|
|
231
231
|
try {
|
|
232
232
|
unlinkSync(tmp);
|
|
@@ -260,24 +260,55 @@ function messageImageAllowance(m) {
|
|
|
260
260
|
if (!m || typeof m !== 'object') return 0;
|
|
261
261
|
return messageImageDescriptors(m).reduce((sum, descriptor) => sum + imageDescriptorAllowance(descriptor), 0);
|
|
262
262
|
}
|
|
263
|
-
// Inline document (PDF) allowance
|
|
264
|
-
//
|
|
265
|
-
//
|
|
263
|
+
// Inline document (PDF) allowance. A native PDF reader turns every page into
|
|
264
|
+
// one image AND sends the text it extracts from that page (the provider PDF
|
|
265
|
+
// docs: each page is billed as an image plus its text, typically
|
|
266
|
+
// 1,500-3,000 text tokens for a dense page). The page image is bounded like
|
|
267
|
+
// any image — the reader downscales it to the vision ceiling — so a page costs
|
|
268
|
+
// at most IMAGE_TOKEN_ALLOWANCE for its picture whatever its file size. A
|
|
269
|
+
// scanned page has no text layer and costs only its picture.
|
|
270
|
+
//
|
|
271
|
+
// The base64 payload itself is excluded from text estimates (see
|
|
266
272
|
// jsonFallbackFromPart), so this allowance is the document's entire cost.
|
|
267
273
|
const FILE_TOKEN_ALLOWANCE_FLOOR = 1_500;
|
|
268
274
|
const FILE_MAX_TOKEN_ALLOWANCE = 300_000;
|
|
269
|
-
//
|
|
270
|
-
//
|
|
271
|
-
//
|
|
272
|
-
const
|
|
275
|
+
// Extracted PDF text is priced at two characters per token: the low end of
|
|
276
|
+
// the documented per-page range for Latin text, and close to the measured
|
|
277
|
+
// density of Korean/CJK text, so neither is read low.
|
|
278
|
+
const PDF_TEXT_CHARS_PER_TOKEN = 2;
|
|
279
|
+
// A PDF that records its page count but not its text layer (older parts, an
|
|
280
|
+
// inline part from a path that did not measure it) keeps the documented
|
|
281
|
+
// mid-range per-page figure.
|
|
282
|
+
const FILE_TOKENS_PER_PAGE_UNMEASURED = 2_500;
|
|
273
283
|
// A PDF that lowers to text costs at most its extraction budget (~4 bytes/token).
|
|
274
284
|
const PDF_TEXT_MAX_TOKENS = Math.ceil(PDF_TEXT_MAX_BYTES / 4);
|
|
285
|
+
// Without a page count only the file size is known: ~bytes/16 (a typical page
|
|
286
|
+
// is 50-100KB) with a floor and a cap. Never used once pages are known — a
|
|
287
|
+
// scan's bytes are its image data, which the reader downscales, so bytes/16
|
|
288
|
+
// priced a 5 MB, 37-page scan at ~330k tokens instead of ~58k.
|
|
275
289
|
function fileDescriptorAllowance(descriptor, nativePdf = true) {
|
|
276
|
-
const
|
|
277
|
-
|
|
278
|
-
|
|
290
|
+
const pages = descriptor.pageCount || 0;
|
|
291
|
+
let native;
|
|
292
|
+
if (pages > 0 && Number.isFinite(descriptor.textChars)) {
|
|
293
|
+
native = pages * IMAGE_TOKEN_ALLOWANCE + Math.ceil(descriptor.textChars / PDF_TEXT_CHARS_PER_TOKEN);
|
|
294
|
+
} else if (pages > 0) {
|
|
295
|
+
native = pages * FILE_TOKENS_PER_PAGE_UNMEASURED;
|
|
296
|
+
} else {
|
|
297
|
+
native = Math.max(FILE_TOKEN_ALLOWANCE_FLOOR, Math.ceil((descriptor.sizeBytes || 0) / 16));
|
|
298
|
+
}
|
|
299
|
+
native = Math.min(FILE_MAX_TOKEN_ALLOWANCE, native);
|
|
279
300
|
return nativePdf ? native : Math.min(native, PDF_TEXT_MAX_TOKENS);
|
|
280
301
|
}
|
|
302
|
+
|
|
303
|
+
/** The tokens one PDF part costs inline (native reader unless `nativePdf` is false). */
|
|
304
|
+
export function pdfPartAllowance(part, { nativePdf = true } = {}) {
|
|
305
|
+
return contentFileDescriptors([part]).reduce((sum, d) => sum + fileDescriptorAllowance(d, nativePdf), 0);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/** The tokens one image part costs inline. */
|
|
309
|
+
export function imagePartAllowance(part) {
|
|
310
|
+
return contentImageDescriptors([part]).reduce((sum, d) => sum + imageDescriptorAllowance(d), 0);
|
|
311
|
+
}
|
|
281
312
|
/**
|
|
282
313
|
* How many tokens the native-PDF meter overstates `messages` for a provider
|
|
283
314
|
* that takes PDFs as text (nativePdf === false); subtract it from the
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
// session/human-gate/delegation.mjs
|
|
2
|
+
// Who a delegated session works for, recorded when it is created and re-bound
|
|
3
|
+
// only when another session sends it work (rebindDelegation): a sub-agent (any
|
|
4
|
+
// depth) and a task session a bot created carry `delegation` on their session
|
|
5
|
+
// record —
|
|
6
|
+
// { rootSessionId, rootAgentId, via, run?, path }
|
|
7
|
+
// `rootSessionId` is the top-level conversation (a bot's home chat, a room
|
|
8
|
+
// member session, a coding Lead's session); `rootAgentId` the bot or Mixy it
|
|
9
|
+
// acts for ('' under a coding Lead); `via` how that root was acting when the
|
|
10
|
+
// work started: 'home' (the bot's own attended chat), 'room', 'run' (a
|
|
11
|
+
// schedule/webhook turn; `run` = { kind, name }) or 'coding'; `path` the steps
|
|
12
|
+
// from the root down ({ kind: 'task' } | { kind: 'agent', agent }).
|
|
13
|
+
// It is copied from the parent's record (or bound from the parent itself when
|
|
14
|
+
// the parent is top-level) by the host at creation — never from tool input —
|
|
15
|
+
// so no parent walk happens at gate time. It follows the session that drives
|
|
16
|
+
// the work: when a session sends an existing worker (or task session) a new
|
|
17
|
+
// request, the record is re-bound to what that sender is doing now, so work an
|
|
18
|
+
// unattended run started asks when the attended chat later reuses it, and the
|
|
19
|
+
// reverse. A background wake of the worker is no new request and keeps it. A
|
|
20
|
+
// record from before this field existed is
|
|
21
|
+
// backfilled once, from its parent by the same rules (backfillOf), and kept on
|
|
22
|
+
// the in-memory record, which its next save persists. A session that has a
|
|
23
|
+
// parent link but no valid or derivable root is UNRESOLVED: the gate fails
|
|
24
|
+
// closed on it. `via: 'unknown'` — a legacy task session that names its bot
|
|
25
|
+
// but not where it was created: acts as that bot, never remembers.
|
|
26
|
+
import { agentHomeSessionId, agentIdOfHomeSession } from '../agent-home.mjs';
|
|
27
|
+
import { roomMemberOfSession } from '../agent-room.mjs';
|
|
28
|
+
import { loadSession } from '../store/load-session.mjs';
|
|
29
|
+
import { _liveSessions } from '../store/live-state.mjs';
|
|
30
|
+
import { saveSessionAsync } from '../store/save-worker.mjs';
|
|
31
|
+
import { isTurnInFlight, runtimeState } from '../manager/runtime-state.mjs';
|
|
32
|
+
import { unattendedApprovalPort } from './unattended-port.mjs';
|
|
33
|
+
|
|
34
|
+
const VIA = new Set(['home', 'room', 'run', 'coding', 'unknown']);
|
|
35
|
+
const AGENT_ID = /^[A-Za-z0-9_-]+$/;
|
|
36
|
+
const MAX_PATH = 32;
|
|
37
|
+
const clean = (value) => (typeof value === 'string' ? value.trim() : '');
|
|
38
|
+
const isRecord = (value) => Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
39
|
+
|
|
40
|
+
const agentOwned = (record) =>
|
|
41
|
+
clean(record?.owner).toLowerCase() === 'agent' || clean(record?.visibility).toLowerCase() === 'agent-only';
|
|
42
|
+
|
|
43
|
+
/** The session that started `record` (its spawn parent, or the chat that
|
|
44
|
+
* created a task session), or '' for a top-level session. */
|
|
45
|
+
function parentOf(record) {
|
|
46
|
+
if (agentOwned(record)) return clean(record.parentSessionId) || clean(record.ownerSessionId);
|
|
47
|
+
return clean(record?.taskOrigin?.sessionId);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** The step a new session adds to its parent's path. */
|
|
51
|
+
function stepOf(record) {
|
|
52
|
+
return agentOwned(record) ? { kind: 'agent', agent: clean(record.agent) } : { kind: 'task' };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function validDelegation(value) {
|
|
56
|
+
if (!isRecord(value) || !clean(value.rootSessionId) || !VIA.has(value.via)) return null;
|
|
57
|
+
if (!Array.isArray(value.path) || value.path.length === 0 || value.path.length > MAX_PATH) return null;
|
|
58
|
+
if (value.via === 'run' && !isRecord(value.run)) return null;
|
|
59
|
+
return value;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** A failed rebind leaves `{ unresolved: true }` instead of a delegation: an
|
|
63
|
+
* explicit "no root", so the legacy backfill cannot derive one again from a
|
|
64
|
+
* parent that still holds a run. */
|
|
65
|
+
const UNRESOLVED = Object.freeze({ unresolved: true });
|
|
66
|
+
const isUnresolvedMark = (value) => isRecord(value) && value.unresolved === true;
|
|
67
|
+
|
|
68
|
+
/** The recorded delegation of `record`, else its legacy backfill; null when
|
|
69
|
+
* it has none or was explicitly left unresolved. */
|
|
70
|
+
function delegationOfRecord(id, record, depth) {
|
|
71
|
+
if (isUnresolvedMark(record.delegation)) return null;
|
|
72
|
+
return validDelegation(record.delegation) || backfillOf(id, record, depth);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function loadRecord(sessionId) {
|
|
76
|
+
try {
|
|
77
|
+
return loadSession(sessionId);
|
|
78
|
+
} catch {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** How a top-level session `sessionId` is acting right now (no record needed
|
|
84
|
+
* for a home or room member id, which name their agent themselves). */
|
|
85
|
+
function bindingOf(sessionId, record, { legacy = false } = {}) {
|
|
86
|
+
// A legacy record is classified from what was recorded, never from what the
|
|
87
|
+
// parent is doing now (a run going or ended since says nothing about it).
|
|
88
|
+
const run = legacy ? null : unattendedApprovalPort()?.runOf?.(sessionId);
|
|
89
|
+
if (run && run.kind !== 'room') {
|
|
90
|
+
return { rootAgentId: clean(run.agentId), via: 'run', run: { kind: run.kind, name: String(run.name || '') } };
|
|
91
|
+
}
|
|
92
|
+
const member = roomMemberOfSession(sessionId);
|
|
93
|
+
if (member) return { rootAgentId: member.agentId, via: 'room' };
|
|
94
|
+
const home = agentIdOfHomeSession(sessionId);
|
|
95
|
+
if (home) return { rootAgentId: home, via: 'home' };
|
|
96
|
+
if (!record || agentOwned(record)) return null;
|
|
97
|
+
// A Lead with host-set bot provenance (session-options taskOriginSuffix) is
|
|
98
|
+
// a bot's task session, never coding work: its root is that bot's chat.
|
|
99
|
+
const source = sourceTaskOf(record);
|
|
100
|
+
if (source === false) return null;
|
|
101
|
+
if (source) {
|
|
102
|
+
const task = { rootSessionId: agentHomeSessionId(source.bot), rootAgentId: source.bot, task: true };
|
|
103
|
+
if (source.from === 'home') return { ...task, via: 'home' };
|
|
104
|
+
if (source.from === 'run') return { ...task, via: 'run', run: { kind: 'schedule', name: '' } };
|
|
105
|
+
if (source.from === undefined) return { ...task, via: 'unknown' };
|
|
106
|
+
return null; // a room (which one is not recorded) or anything else: ambiguous
|
|
107
|
+
}
|
|
108
|
+
return { rootAgentId: '', via: 'coding' };
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** A Lead's host-set bot provenance `agent:<bot>[@from]`: `{ bot, from }`,
|
|
112
|
+
* null when it has none, false when it is malformed. */
|
|
113
|
+
function sourceTaskOf(record) {
|
|
114
|
+
const source = clean(record?.sourceName);
|
|
115
|
+
if (agentOwned(record) || clean(record?.sourceType) !== 'lead' || !source.startsWith('agent:')) return null;
|
|
116
|
+
const [bot, from, ...rest] = source.slice(6).split('@');
|
|
117
|
+
return AGENT_ID.test(bot) && !rest.length ? { bot, from } : false;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** The root of a top-level `parent` for a child taking `step`. */
|
|
121
|
+
function rootFrom(parent, record, step, options) {
|
|
122
|
+
const binding = bindingOf(parent, record, options);
|
|
123
|
+
if (!binding) return null;
|
|
124
|
+
const { task, ...root } = binding;
|
|
125
|
+
return { rootSessionId: parent, ...root, path: task ? [{ kind: 'task' }, step] : [step] };
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** The delegation a legacy `record` (id `id`, a parent link, none recorded)
|
|
129
|
+
* is given, derived now from what was recorded — its own host-set `@run`
|
|
130
|
+
* provenance, else its parent's record, which must exist — and kept on the
|
|
131
|
+
* live record; null when it cannot be derived. Never `via: 'home'`: whether
|
|
132
|
+
* an old record was started by the attended chat (or by a run that has
|
|
133
|
+
* ended since) is not recorded, so home ancestry becomes 'unknown' — that
|
|
134
|
+
* bot, never remembered. Only a session created with its `delegation` can be
|
|
135
|
+
* 'home'. */
|
|
136
|
+
function backfillOf(id, record, depth = 0) {
|
|
137
|
+
const parent = parentOf(record);
|
|
138
|
+
if (!parent || parent === id || depth >= MAX_PATH) return null;
|
|
139
|
+
const own = sourceTaskOf(record);
|
|
140
|
+
let delegation = null;
|
|
141
|
+
if (own && own.from === 'run') {
|
|
142
|
+
// A run's task session stays the run's, whatever its origin chat is doing now.
|
|
143
|
+
delegation = {
|
|
144
|
+
rootSessionId: agentHomeSessionId(own.bot),
|
|
145
|
+
rootAgentId: own.bot,
|
|
146
|
+
via: 'run',
|
|
147
|
+
run: { kind: 'schedule', name: '' },
|
|
148
|
+
path: [{ kind: 'task' }],
|
|
149
|
+
};
|
|
150
|
+
} else {
|
|
151
|
+
const parentRecord = loadRecord(parent);
|
|
152
|
+
if (!parentRecord) return null;
|
|
153
|
+
const step = stepOf(record);
|
|
154
|
+
if (parentOf(parentRecord)) {
|
|
155
|
+
const inherited = delegationOfRecord(parent, parentRecord, depth + 1);
|
|
156
|
+
if (!inherited || inherited.path.length >= MAX_PATH) return null;
|
|
157
|
+
delegation = { ...inherited, path: [...inherited.path, step] };
|
|
158
|
+
} else {
|
|
159
|
+
delegation = rootFrom(parent, parentRecord, step, { legacy: true });
|
|
160
|
+
}
|
|
161
|
+
if (delegation?.via === 'home') delegation = { ...delegation, via: 'unknown' };
|
|
162
|
+
}
|
|
163
|
+
if (delegation && _liveSessions.get(id) === record) record.delegation = delegation;
|
|
164
|
+
return delegation;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* The `delegation` to record on a session being created with `opts` (its
|
|
169
|
+
* owner/visibility, parentSessionId/ownerSessionId, taskOrigin and agent), or
|
|
170
|
+
* null: none for a top-level session, none for one whose parent's root cannot
|
|
171
|
+
* be established (the record then stays unresolved and the gate fails closed).
|
|
172
|
+
*/
|
|
173
|
+
export function delegationForNewSession(opts = {}) {
|
|
174
|
+
const parent = parentOf(opts);
|
|
175
|
+
if (!parent || parent === clean(opts.id)) return null;
|
|
176
|
+
return delegationUnder(parent, stepOf(opts));
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/** The delegation of a session taking `step` under the session `parent`. */
|
|
180
|
+
function delegationUnder(parent, step) {
|
|
181
|
+
const record = loadRecord(parent);
|
|
182
|
+
if (record && parentOf(record)) {
|
|
183
|
+
// The parent is delegated itself: its recorded root, one step deeper.
|
|
184
|
+
const inherited = delegationOfRecord(parent, record);
|
|
185
|
+
if (!inherited || inherited.path.length >= MAX_PATH) return null;
|
|
186
|
+
return { ...inherited, path: [...inherited.path, step] };
|
|
187
|
+
}
|
|
188
|
+
return rootFrom(parent, record, step);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Session `callerSessionId` sends the delegated session `sessionId` new work
|
|
193
|
+
* (`agent send`, a spawn of its tag, a task-session send): from now on it
|
|
194
|
+
* acts as that caller does — the delegation it would have been created with
|
|
195
|
+
* under the caller — and the record is saved, so a restart keeps it. A worker
|
|
196
|
+
* a run started is attended when the chat sends it work, and the other way
|
|
197
|
+
* round; only the requests of the session that sends it count, never the
|
|
198
|
+
* session that created it. A turn already running keeps its attended status
|
|
199
|
+
* against a run (the run's request queues behind it and asks): it is never
|
|
200
|
+
* loosened mid-turn. Resolves true when the record changed; false when
|
|
201
|
+
* nothing applies (no record, not delegated, no or the same caller, the same
|
|
202
|
+
* delegation) or the running turn kept its status. A caller whose root cannot
|
|
203
|
+
* be established leaves the record without one, which the gate fails closed on.
|
|
204
|
+
*/
|
|
205
|
+
export async function rebindDelegation(sessionId, callerSessionId) {
|
|
206
|
+
const id = clean(sessionId);
|
|
207
|
+
const caller = clean(callerSessionId);
|
|
208
|
+
const record = id ? loadRecord(id) : null;
|
|
209
|
+
if (!record || record.closed === true || !caller || caller === id || !parentOf(record)) return false;
|
|
210
|
+
const current = validDelegation(record.delegation);
|
|
211
|
+
const next = delegationUnder(caller, stepOf(record));
|
|
212
|
+
if (next ? JSON.stringify(current) === JSON.stringify(next) : isUnresolvedMark(record.delegation)) return false;
|
|
213
|
+
if (next?.via === 'run' && current?.via !== 'run' && isTurnInFlight(runtimeState.get(id))) return false;
|
|
214
|
+
record.delegation = next || { ...UNRESOLVED };
|
|
215
|
+
await saveSessionAsync(record, { expectedGeneration: record.generation });
|
|
216
|
+
return true;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/** `{ state: 'top' }` for a top-level session (or one with no record),
|
|
220
|
+
* `{ state: 'resolved', ...delegation }` for a delegated one, `{ state:
|
|
221
|
+
* 'unresolved' }` for one with a parent link and no valid recorded root. */
|
|
222
|
+
export function delegationOf(sessionId) {
|
|
223
|
+
const id = clean(sessionId);
|
|
224
|
+
const record = id ? loadRecord(id) : null;
|
|
225
|
+
if (!record) return { state: 'top' };
|
|
226
|
+
const parent = parentOf(record);
|
|
227
|
+
if (!parent) return { state: 'top' };
|
|
228
|
+
const delegation = parent === id ? null : delegationOfRecord(id, record);
|
|
229
|
+
return delegation ? { state: 'resolved', ...delegation } : { state: 'unresolved' };
|
|
230
|
+
}
|