comisai 1.0.34 → 1.0.36
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/node_modules/@comis/agent/dist/background/auto-background-middleware.d.ts +11 -1
- package/node_modules/@comis/agent/dist/background/auto-background-middleware.js +21 -4
- package/node_modules/@comis/agent/dist/background/background-task-manager.d.ts +2 -2
- package/node_modules/@comis/agent/dist/background/background-task-manager.js +61 -20
- package/node_modules/@comis/agent/dist/background/background-task-persistence.js +10 -3
- package/node_modules/@comis/agent/dist/background/background-task-types.d.ts +10 -3
- package/node_modules/@comis/agent/dist/background/background-task-types.js +1 -1
- package/node_modules/@comis/agent/dist/background/completion-formatter.d.ts +39 -0
- package/node_modules/@comis/agent/dist/background/completion-formatter.js +77 -0
- package/node_modules/@comis/agent/dist/background/completion-runner.d.ts +53 -0
- package/node_modules/@comis/agent/dist/background/completion-runner.js +151 -0
- package/node_modules/@comis/agent/dist/background/index.d.ts +4 -0
- package/node_modules/@comis/agent/dist/background/index.js +2 -0
- package/node_modules/@comis/agent/dist/bridge/bridge-metrics.d.ts +17 -2
- package/node_modules/@comis/agent/dist/bridge/bridge-metrics.js +14 -2
- package/node_modules/@comis/agent/dist/bridge/pi-event-bridge.d.ts +23 -23
- package/node_modules/@comis/agent/dist/bridge/pi-event-bridge.js +72 -60
- package/node_modules/@comis/agent/dist/bridge/thinking-block-hash-invariant.d.ts +6 -7
- package/node_modules/@comis/agent/dist/bridge/thinking-block-hash-invariant.js +24 -25
- package/node_modules/@comis/agent/dist/budget/cost-tracker.d.ts +1 -1
- package/node_modules/@comis/agent/dist/context-engine/constants.d.ts +5 -5
- package/node_modules/@comis/agent/dist/context-engine/constants.js +12 -12
- package/node_modules/@comis/agent/dist/context-engine/context-engine.js +13 -4
- package/node_modules/@comis/agent/dist/context-engine/dag-annotator.d.ts +1 -2
- package/node_modules/@comis/agent/dist/context-engine/dag-annotator.js +1 -2
- package/node_modules/@comis/agent/dist/context-engine/llm-compaction.js +20 -16
- package/node_modules/@comis/agent/dist/context-engine/rehydration.js +6 -6
- package/node_modules/@comis/agent/dist/context-engine/signature-replay-scrubber.d.ts +12 -12
- package/node_modules/@comis/agent/dist/context-engine/signature-replay-scrubber.js +36 -22
- package/node_modules/@comis/agent/dist/context-engine/types-core.d.ts +15 -0
- package/node_modules/@comis/agent/dist/executor/cache-break-detection.d.ts +6 -6
- package/node_modules/@comis/agent/dist/executor/cache-break-detection.js +8 -8
- package/node_modules/@comis/agent/dist/executor/executor-context-engine-setup.d.ts +16 -0
- package/node_modules/@comis/agent/dist/executor/executor-context-engine-setup.js +46 -5
- package/node_modules/@comis/agent/dist/executor/executor-post-execution.d.ts +30 -0
- package/node_modules/@comis/agent/dist/executor/executor-post-execution.js +17 -1
- package/node_modules/@comis/agent/dist/executor/executor-prompt-runner.js +1 -1
- package/node_modules/@comis/agent/dist/executor/executor-response-filter.d.ts +7 -6
- package/node_modules/@comis/agent/dist/executor/executor-response-filter.js +9 -42
- package/node_modules/@comis/agent/dist/executor/executor-tool-assembly.js +2 -3
- package/node_modules/@comis/agent/dist/executor/gemini-cache-injector.d.ts +2 -2
- package/node_modules/@comis/agent/dist/executor/gemini-cache-injector.js +4 -4
- package/node_modules/@comis/agent/dist/executor/phase-filter.d.ts +2 -2
- package/node_modules/@comis/agent/dist/executor/phase-filter.js +5 -7
- package/node_modules/@comis/agent/dist/executor/pi-executor.d.ts +13 -0
- package/node_modules/@comis/agent/dist/executor/pi-executor.js +71 -6
- package/node_modules/@comis/agent/dist/executor/post-batch-continuation.js +7 -7
- package/node_modules/@comis/agent/dist/executor/stream-wrappers/request-body-injector.d.ts +1 -1
- package/node_modules/@comis/agent/dist/executor/stream-wrappers/request-body-injector.js +1 -1
- package/node_modules/@comis/agent/dist/executor/tool-deferral.d.ts +2 -2
- package/node_modules/@comis/agent/dist/executor/tool-deferral.js +7 -7
- package/node_modules/@comis/agent/dist/index.d.ts +17 -0
- package/node_modules/@comis/agent/dist/index.js +32 -11
- package/node_modules/@comis/agent/dist/model/auth-provider.d.ts +25 -2
- package/node_modules/@comis/agent/dist/model/auth-provider.js +6 -0
- package/node_modules/@comis/agent/dist/model/compaction-model-resolver.d.ts +3 -3
- package/node_modules/@comis/agent/dist/model/compaction-model-resolver.js +3 -3
- package/node_modules/@comis/agent/dist/model/oauth-credential-store-file.d.ts +37 -0
- package/node_modules/@comis/agent/dist/model/oauth-credential-store-file.js +279 -0
- package/node_modules/@comis/agent/dist/model/oauth-credential-store-selector.d.ts +49 -0
- package/node_modules/@comis/agent/dist/model/oauth-credential-store-selector.js +50 -0
- package/node_modules/@comis/agent/dist/model/oauth-device-code.d.ts +57 -0
- package/node_modules/@comis/agent/dist/model/oauth-device-code.js +302 -0
- package/node_modules/@comis/agent/dist/model/oauth-env.d.ts +33 -0
- package/node_modules/@comis/agent/dist/model/oauth-env.js +38 -0
- package/node_modules/@comis/agent/dist/model/oauth-errors.d.ts +41 -0
- package/node_modules/@comis/agent/dist/model/oauth-errors.js +88 -0
- package/node_modules/@comis/agent/dist/model/oauth-identity.d.ts +53 -0
- package/node_modules/@comis/agent/dist/model/oauth-identity.js +141 -0
- package/node_modules/@comis/agent/dist/model/oauth-login-runner.d.ts +99 -0
- package/node_modules/@comis/agent/dist/model/oauth-login-runner.js +374 -0
- package/node_modules/@comis/agent/dist/model/oauth-tls-preflight.d.ts +58 -0
- package/node_modules/@comis/agent/dist/model/oauth-tls-preflight.js +82 -0
- package/node_modules/@comis/agent/dist/model/oauth-token-manager.d.ts +86 -16
- package/node_modules/@comis/agent/dist/model/oauth-token-manager.js +961 -66
- package/node_modules/@comis/agent/dist/model/operation-model-defaults.d.ts +9 -4
- package/node_modules/@comis/agent/dist/model/operation-model-defaults.js +36 -9
- package/node_modules/@comis/agent/dist/model/resolve-provider-api-key.d.ts +48 -0
- package/node_modules/@comis/agent/dist/model/resolve-provider-api-key.js +66 -0
- package/node_modules/@comis/agent/dist/provider/capabilities.d.ts +5 -5
- package/node_modules/@comis/agent/dist/provider/capabilities.js +10 -23
- package/node_modules/@comis/agent/dist/safety/tool-output-safety.js +3 -3
- package/node_modules/@comis/agent/dist/session/comis-session-manager.d.ts +1 -1
- package/node_modules/@comis/agent/dist/session/comis-session-manager.js +1 -1
- package/node_modules/@comis/agent/dist/spawn/narrative-caster.d.ts +10 -0
- package/node_modules/@comis/agent/dist/spawn/narrative-caster.js +5 -1
- package/node_modules/@comis/agent/package.json +1 -1
- package/node_modules/@comis/channels/dist/email/email-adapter.js +6 -6
- package/node_modules/@comis/channels/dist/email/imap-lifecycle.js +7 -7
- package/node_modules/@comis/channels/dist/shared/deliver-to-channel.js +12 -10
- package/node_modules/@comis/channels/dist/telegram/telegram-adapter.js +1 -1
- package/node_modules/@comis/channels/package.json +1 -1
- package/node_modules/@comis/cli/dist/cli.js +2 -0
- package/node_modules/@comis/cli/dist/commands/agent.d.ts +3 -3
- package/node_modules/@comis/cli/dist/commands/agent.js +46 -3
- package/node_modules/@comis/cli/dist/commands/auth.d.ts +37 -0
- package/node_modules/@comis/cli/dist/commands/auth.js +433 -0
- package/node_modules/@comis/cli/dist/commands/doctor.d.ts +4 -1
- package/node_modules/@comis/cli/dist/commands/doctor.js +20 -5
- package/node_modules/@comis/cli/dist/doctor/checks/oauth-health.d.ts +39 -0
- package/node_modules/@comis/cli/dist/doctor/checks/oauth-health.js +399 -0
- package/node_modules/@comis/cli/dist/doctor/types.d.ts +19 -0
- package/node_modules/@comis/cli/dist/index.d.ts +1 -0
- package/node_modules/@comis/cli/dist/index.js +10 -4
- package/node_modules/@comis/cli/dist/output/relative-time.d.ts +23 -0
- package/node_modules/@comis/cli/dist/output/relative-time.js +36 -0
- package/node_modules/@comis/cli/dist/wizard/non-interactive.js +17 -8
- package/node_modules/@comis/cli/dist/wizard/steps/03-provider.js +2 -1
- package/node_modules/@comis/cli/dist/wizard/steps/04-credentials.js +223 -34
- package/node_modules/@comis/cli/dist/wizard/steps/10-write-config.js +14 -0
- package/node_modules/@comis/cli/dist/wizard/steps/11-daemon-start.js +3 -3
- package/node_modules/@comis/cli/dist/wizard/types.d.ts +7 -0
- package/node_modules/@comis/cli/package.json +1 -1
- package/node_modules/@comis/core/dist/bootstrap.d.ts +1 -1
- package/node_modules/@comis/core/dist/config/env-substitution.d.ts +66 -0
- package/node_modules/@comis/core/dist/config/env-substitution.js +115 -0
- package/node_modules/@comis/core/dist/config/index.d.ts +3 -1
- package/node_modules/@comis/core/dist/config/index.js +2 -1
- package/node_modules/@comis/core/dist/config/loader.js +61 -0
- package/node_modules/@comis/core/dist/config/managed-sections.d.ts +3 -3
- package/node_modules/@comis/core/dist/config/managed-sections.js +10 -5
- package/node_modules/@comis/core/dist/config/schema-agent.d.ts +4 -0
- package/node_modules/@comis/core/dist/config/schema-agent.js +16 -1
- package/node_modules/@comis/core/dist/config/schema-background-tasks.d.ts +7 -0
- package/node_modules/@comis/core/dist/config/schema-background-tasks.js +7 -0
- package/node_modules/@comis/core/dist/config/schema-delivery.d.ts +2 -0
- package/node_modules/@comis/core/dist/config/schema-delivery.js +2 -0
- package/node_modules/@comis/core/dist/config/schema-gemini-cache.d.ts +0 -2
- package/node_modules/@comis/core/dist/config/schema-gemini-cache.js +0 -2
- package/node_modules/@comis/core/dist/config/schema-oauth.d.ts +23 -0
- package/node_modules/@comis/core/dist/config/schema-oauth.js +19 -0
- package/node_modules/@comis/core/dist/config/schema-skills.d.ts +6 -8
- package/node_modules/@comis/core/dist/config/schema-skills.js +3 -4
- package/node_modules/@comis/core/dist/config/schema.d.ts +10 -0
- package/node_modules/@comis/core/dist/config/schema.js +3 -0
- package/node_modules/@comis/core/dist/domain/background-task-origin.d.ts +39 -0
- package/node_modules/@comis/core/dist/domain/background-task-origin.js +39 -0
- package/node_modules/@comis/core/dist/event-bus/events-infra.d.ts +71 -2
- package/node_modules/@comis/core/dist/exports/config.d.ts +2 -2
- package/node_modules/@comis/core/dist/exports/config.js +1 -1
- package/node_modules/@comis/core/dist/exports/domain.d.ts +2 -0
- package/node_modules/@comis/core/dist/exports/domain.js +1 -0
- package/node_modules/@comis/core/dist/exports/ports.d.ts +2 -2
- package/node_modules/@comis/core/dist/exports/ports.js +1 -1
- package/node_modules/@comis/core/dist/ports/delivery-queue.d.ts +23 -0
- package/node_modules/@comis/core/dist/ports/delivery-queue.js +2 -0
- package/node_modules/@comis/core/dist/ports/index.d.ts +2 -0
- package/node_modules/@comis/core/dist/ports/index.js +1 -0
- package/node_modules/@comis/core/dist/ports/oauth-credential-store.d.ts +64 -0
- package/node_modules/@comis/core/dist/ports/oauth-credential-store.js +37 -0
- package/node_modules/@comis/core/dist/tool-metadata.d.ts +20 -0
- package/node_modules/@comis/core/package.json +1 -1
- package/node_modules/@comis/daemon/dist/daemon-types.d.ts +23 -3
- package/node_modules/@comis/daemon/dist/daemon.js +82 -19
- package/node_modules/@comis/daemon/dist/index.d.ts +2 -0
- package/node_modules/@comis/daemon/dist/index.js +5 -0
- package/node_modules/@comis/daemon/dist/observability/channel-health-logger.js +3 -3
- package/node_modules/@comis/daemon/dist/observability/delivery-queue-logger.js +1 -1
- package/node_modules/@comis/daemon/dist/rpc/agent-handlers.d.ts +22 -1
- package/node_modules/@comis/daemon/dist/rpc/agent-handlers.js +84 -21
- package/node_modules/@comis/daemon/dist/rpc/agent-inline-workspace.js +2 -2
- package/node_modules/@comis/daemon/dist/rpc/config-handlers.d.ts +9 -1
- package/node_modules/@comis/daemon/dist/rpc/config-handlers.js +104 -23
- package/node_modules/@comis/daemon/dist/rpc/credential-resolver.d.ts +30 -1
- package/node_modules/@comis/daemon/dist/rpc/credential-resolver.js +74 -11
- package/node_modules/@comis/daemon/dist/rpc/mcp-handlers.d.ts +8 -0
- package/node_modules/@comis/daemon/dist/rpc/mcp-handlers.js +22 -8
- package/node_modules/@comis/daemon/dist/rpc/provider-handlers.js +9 -12
- package/node_modules/@comis/daemon/dist/rpc/rpc-dispatch.d.ts +1 -0
- package/node_modules/@comis/daemon/dist/rpc/rpc-dispatch.js +27 -2
- package/node_modules/@comis/daemon/dist/setup-docker-restart-warn.js +0 -1
- package/node_modules/@comis/daemon/dist/wiring/index.d.ts +2 -0
- package/node_modules/@comis/daemon/dist/wiring/index.js +1 -0
- package/node_modules/@comis/daemon/dist/wiring/oauth-preflight.d.ts +21 -0
- package/node_modules/@comis/daemon/dist/wiring/oauth-preflight.js +134 -0
- package/node_modules/@comis/daemon/dist/wiring/setup-agents.d.ts +46 -1
- package/node_modules/@comis/daemon/dist/wiring/setup-agents.js +127 -3
- package/node_modules/@comis/daemon/dist/wiring/setup-background-completion-runner.d.ts +39 -0
- package/node_modules/@comis/daemon/dist/wiring/setup-background-completion-runner.js +32 -0
- package/node_modules/@comis/daemon/dist/wiring/setup-background-tasks.d.ts +10 -3
- package/node_modules/@comis/daemon/dist/wiring/setup-background-tasks.js +11 -5
- package/node_modules/@comis/daemon/dist/wiring/setup-channels.js +20 -1
- package/node_modules/@comis/daemon/dist/wiring/setup-cross-session.js +1 -1
- package/node_modules/@comis/daemon/dist/wiring/setup-delivery.d.ts +14 -5
- package/node_modules/@comis/daemon/dist/wiring/setup-delivery.js +52 -19
- package/node_modules/@comis/daemon/dist/wiring/setup-schedulers.js +4 -0
- package/node_modules/@comis/daemon/package.json +1 -1
- package/node_modules/@comis/gateway/dist/index.d.ts +2 -0
- package/node_modules/@comis/gateway/dist/index.js +2 -0
- package/node_modules/@comis/gateway/dist/oauth/oauth-callback-route.d.ts +66 -0
- package/node_modules/@comis/gateway/dist/oauth/oauth-callback-route.js +212 -0
- package/node_modules/@comis/gateway/dist/server/hono-server.d.ts +14 -0
- package/node_modules/@comis/gateway/dist/server/hono-server.js +10 -0
- package/node_modules/@comis/gateway/package.json +1 -1
- package/node_modules/@comis/infra/dist/logging/log-fields.d.ts +23 -0
- package/node_modules/@comis/infra/package.json +1 -1
- package/node_modules/@comis/memory/dist/compaction.d.ts +3 -5
- package/node_modules/@comis/memory/dist/compaction.js +2 -3
- package/node_modules/@comis/memory/dist/delivery-queue-adapter.d.ts +2 -2
- package/node_modules/@comis/memory/dist/delivery-queue-adapter.js +49 -1
- package/node_modules/@comis/memory/dist/index.d.ts +2 -0
- package/node_modules/@comis/memory/dist/index.js +3 -0
- package/node_modules/@comis/memory/dist/memory-api.d.ts +1 -1
- package/node_modules/@comis/memory/dist/memory-api.js +1 -1
- package/node_modules/@comis/memory/dist/oauth-profile-schema.d.ts +17 -0
- package/node_modules/@comis/memory/dist/oauth-profile-schema.js +33 -0
- package/node_modules/@comis/memory/dist/oauth-profile-store-encrypted.d.ts +27 -0
- package/node_modules/@comis/memory/dist/oauth-profile-store-encrypted.js +144 -0
- package/node_modules/@comis/memory/dist/session-store.d.ts +1 -1
- package/node_modules/@comis/memory/dist/session-store.js +1 -1
- package/node_modules/@comis/memory/dist/sqlite-secret-store.d.ts +29 -3
- package/node_modules/@comis/memory/dist/sqlite-secret-store.js +11 -3
- package/node_modules/@comis/memory/package.json +1 -1
- package/node_modules/@comis/scheduler/dist/execution/execution-lock.d.ts +13 -0
- package/node_modules/@comis/scheduler/dist/execution/execution-lock.js +1 -1
- package/node_modules/@comis/scheduler/dist/execution/index.d.ts +2 -0
- package/node_modules/@comis/scheduler/dist/execution/index.js +2 -0
- package/node_modules/@comis/scheduler/dist/heartbeat/agent-heartbeat-source.js +1 -1
- package/node_modules/@comis/scheduler/dist/index.d.ts +2 -0
- package/node_modules/@comis/scheduler/dist/index.js +2 -0
- package/node_modules/@comis/scheduler/package.json +1 -1
- package/node_modules/@comis/shared/package.json +1 -1
- package/node_modules/@comis/skills/dist/bridge/schema-validator.d.ts +38 -0
- package/node_modules/@comis/skills/dist/bridge/schema-validator.js +169 -0
- package/node_modules/@comis/skills/dist/bridge/tool-metadata-enforcement.js +12 -0
- package/node_modules/@comis/skills/dist/bridge/tool-metadata-registry.js +130 -0
- package/node_modules/@comis/skills/dist/builtin/exec-diagnostics.d.ts +32 -0
- package/node_modules/@comis/skills/dist/builtin/exec-diagnostics.js +127 -0
- package/node_modules/@comis/skills/dist/builtin/exec-security.js +38 -0
- package/node_modules/@comis/skills/dist/builtin/exec-tool.js +9 -0
- package/node_modules/@comis/skills/dist/builtin/file-tools/grep-tool.js +6 -6
- package/node_modules/@comis/skills/dist/builtin/platform/agents-manage-tool.d.ts +5 -4
- package/node_modules/@comis/skills/dist/builtin/platform/agents-manage-tool.js +38 -27
- package/node_modules/@comis/skills/dist/builtin/platform/background-tasks-tool.d.ts +4 -1
- package/node_modules/@comis/skills/dist/builtin/platform/background-tasks-tool.js +3 -3
- package/node_modules/@comis/skills/dist/builtin/platform/cron-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/gateway-tool.js +6 -6
- package/node_modules/@comis/skills/dist/builtin/platform/mcp-manage-tool.d.ts +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/mcp-manage-tool.js +9 -9
- package/node_modules/@comis/skills/dist/builtin/sandbox/bwrap-provider.d.ts +11 -0
- package/node_modules/@comis/skills/dist/builtin/sandbox/bwrap-provider.js +114 -1
- package/node_modules/@comis/skills/dist/builtin/sandbox/detect-provider.js +40 -15
- package/node_modules/@comis/skills/dist/media/ssrf-fetcher.d.ts +7 -0
- package/node_modules/@comis/skills/dist/media/ssrf-fetcher.js +9 -2
- package/node_modules/@comis/skills/package.json +1 -1
- package/node_modules/@comis/web/dist/assets/{agent-detail-71BSbSfD.js → agent-detail-q8t1NB7w.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{agent-editor-CTSDZhwT.js → agent-editor-B46io5gv.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{agent-list-BEhni2ea.js → agent-list-DQ6g2Rcx.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{billing-view-DVP1IvVs.js → billing-view-IWPR8LgF.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{channel-detail-N_YK74xC.js → channel-detail-DlNNZuuC.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{channel-list-DRk6ZJaF.js → channel-list-DhGwxiMc.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{chat-console-Dm-GtSf9.js → chat-console-Nv6fM3Rc.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{config-editor-CIferYX6.js → config-editor-BYKuJF76.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{context-dag-browser-CL84rXXM.js → context-dag-browser-ClNEtzYE.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{context-engine-B1HOTEZv.js → context-engine-BZJ6HChd.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{delivery-view-Y6JKYVFw.js → delivery-view-Cb7I3vGu.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{diagnostics-view-DWV1UQjz.js → diagnostics-view-9u9Lyu5a.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{ic-chat-message-DfSERzzg.js → ic-chat-message-BFt3cVpx.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{ic-connection-dot-CXyhlJup.js → ic-connection-dot-y77LZ3Gu.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{ic-tool-call-DNmwTjek.js → ic-tool-call-qt6w1NQl.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{index-CBr0Tm9_.js → index-8Tg9oc-C.js} +2 -2
- package/node_modules/@comis/web/dist/assets/{mcp-management-BaH2-vox.js → mcp-management-69dtH_kY.js} +2 -2
- package/node_modules/@comis/web/dist/assets/{media-config-CZLshJoN.js → media-config-BdjLj5c1.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{media-test-C9NUWgo_.js → media-test-DuPqrixi.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{memory-inspector-D_fmTcRN.js → memory-inspector-B-Pepbq-.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{message-center-BBFlNCZn.js → message-center-B7l0yNYY.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{models-BytGLm99.js → models-JHFHuv5S.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{observe-view-VXtHqaqq.js → observe-view-r8mqhy4O.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{pipeline-builder-CfXczlfJ.js → pipeline-builder-XjkiZRcR.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{pipeline-history-CPmXFnbe.js → pipeline-history-CZqJv_Hj.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{pipeline-history-detail-DcueTMs9.js → pipeline-history-detail-BEFGMoDy.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{pipeline-list-B-xG5WZh.js → pipeline-list-B6q5LvO1.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{pipeline-monitor-pnIOYaSY.js → pipeline-monitor-BNomXjVL.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{scheduler-BtUIFHhA.js → scheduler-BJEjcGKA.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{security-C8mWRq2y.js → security-2G1jhBfV.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{session-detail-DgdkO5ka.js → session-detail-DmVPzFBR.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{session-list-DcylcfTn.js → session-list-CsqMQoHs.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{setup-wizard-BP5yjsuL.js → setup-wizard-CAdM-gSP.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{skills-DXt1bX8Z.js → skills-2ODqKaWr.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{subagents-C7YbUHXY.js → subagents-BFlwfTbD.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{workspace-manager-DP6pW4wa.js → workspace-manager--CbOx_dI.js} +1 -1
- package/node_modules/@comis/web/dist/index.html +1 -1
- package/node_modules/@comis/web/package.json +1 -1
- package/package.json +17 -16
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
/**
|
|
3
|
+
* Background completion runner: subscribes to background_task:completed and
|
|
4
|
+
* background_task:failed events from the TypedEventBus and re-enters the
|
|
5
|
+
* originating agent session with a formatted completion announcement.
|
|
6
|
+
*
|
|
7
|
+
* Per-session lock serialization is delegated to the existing session
|
|
8
|
+
* manager (ComisSessionManager.withSession in packages/agent/src/session/).
|
|
9
|
+
* The runner does NOT introduce its own queueing -- one turn per completion
|
|
10
|
+
* event, ordering follows the existing per-session lock.
|
|
11
|
+
*
|
|
12
|
+
* Recursion bound: per-task incoming hop count + 1 must stay below
|
|
13
|
+
* `maxBackgroundHops` (default 3). When the cap is hit, the runner emits
|
|
14
|
+
* the fallback notification instead of triggering executor.execute().
|
|
15
|
+
* The hop count is read from `task.origin.backgroundHopCount`
|
|
16
|
+
* (populated by the originResolver).
|
|
17
|
+
*
|
|
18
|
+
* Latency-instrumentation hook: emits `background_task:reentered`
|
|
19
|
+
* immediately before executor.execute(). Integration tests compute the delta
|
|
20
|
+
* from `background_task:completed.timestamp` to this event for SLO tracking.
|
|
21
|
+
*
|
|
22
|
+
* Failure isolation: each handler is wrapped in suppressError so a single
|
|
23
|
+
* completion's failure does not tear down the subscription (AGENTS §2.1).
|
|
24
|
+
*
|
|
25
|
+
* @module
|
|
26
|
+
*/
|
|
27
|
+
import { randomUUID } from "node:crypto";
|
|
28
|
+
import { suppressError } from "@comis/shared";
|
|
29
|
+
import { parseFormattedSessionKey } from "@comis/core";
|
|
30
|
+
import { formatCompletionAnnouncement } from "./completion-formatter.js";
|
|
31
|
+
/**
|
|
32
|
+
* Wire the completion runner against an event bus + executor + session store.
|
|
33
|
+
* Subscriptions are installed synchronously; call shutdown() to remove them.
|
|
34
|
+
*/
|
|
35
|
+
export function createBackgroundCompletionRunner(deps) {
|
|
36
|
+
const log = deps.logger.child({ submodule: "background-completion-runner" });
|
|
37
|
+
let stopped = false;
|
|
38
|
+
let inflight = Promise.resolve();
|
|
39
|
+
const onCompleted = (data) => {
|
|
40
|
+
if (stopped)
|
|
41
|
+
return;
|
|
42
|
+
const promise = handleEvent(data.taskId, "completed");
|
|
43
|
+
inflight = inflight.then(() => promise).catch(() => undefined);
|
|
44
|
+
suppressError(promise, "background completion handler (completed)");
|
|
45
|
+
};
|
|
46
|
+
const onFailed = (data) => {
|
|
47
|
+
if (stopped)
|
|
48
|
+
return;
|
|
49
|
+
const promise = handleEvent(data.taskId, "failed");
|
|
50
|
+
inflight = inflight.then(() => promise).catch(() => undefined);
|
|
51
|
+
suppressError(promise, "background completion handler (failed)");
|
|
52
|
+
};
|
|
53
|
+
deps.eventBus.on("background_task:completed", onCompleted);
|
|
54
|
+
deps.eventBus.on("background_task:failed", onFailed);
|
|
55
|
+
async function handleEvent(taskId, kind) {
|
|
56
|
+
const task = deps.taskManager.getTask(taskId);
|
|
57
|
+
if (!task) {
|
|
58
|
+
log.warn({ taskId, kind, hint: "Task disappeared from manager before runner could resolve it; no announcement injected", errorKind: "internal" }, "Background completion: task not in manager");
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
// Legacy task without origin -- emit fallback, keep file for audit.
|
|
62
|
+
const origin = task.origin;
|
|
63
|
+
if (!origin || !origin.sessionKey || !origin.agentId) {
|
|
64
|
+
await fallbackForTask(task.toolName, task.origin?.agentId ?? "default", `Background task "${task.toolName}" completed.`);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
// Hop cap. Read incoming hop count from origin (schema field populated
|
|
68
|
+
// by the originResolver).
|
|
69
|
+
const nextHopCount = (origin.backgroundHopCount ?? 0) + 1;
|
|
70
|
+
if (nextHopCount >= deps.maxBackgroundHops) {
|
|
71
|
+
log.info({ taskId, toolName: task.toolName, agentId: origin.agentId, hopCount: nextHopCount, max: deps.maxBackgroundHops }, "Background completion: hop cap reached, falling back to user notification");
|
|
72
|
+
await fallbackForTask(task.toolName, origin.agentId, `Background task "${task.toolName}" completed but follow-up was skipped — recursion limit reached. Run again or check the result manually.`);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
// Missing session -- session expired while the task ran. No channel to deliver
|
|
76
|
+
// to, so skip fallback (which would only produce a WARN from notification-service).
|
|
77
|
+
const sessionExists = deps.sessionStore.loadByFormattedKey(origin.sessionKey) !== undefined;
|
|
78
|
+
if (!sessionExists) {
|
|
79
|
+
log.info({ taskId, sessionKey: origin.sessionKey }, "Background completion: session expired, skipping re-entry");
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
// Reconstruct the SessionKey object for executor.execute().
|
|
83
|
+
const parsedKey = parseFormattedSessionKey(origin.sessionKey);
|
|
84
|
+
if (!parsedKey) {
|
|
85
|
+
log.warn({ taskId, sessionKey: origin.sessionKey, hint: "Persisted sessionKey is malformed; cannot route announcement", errorKind: "internal" }, "Background completion: invalid sessionKey");
|
|
86
|
+
await fallbackForTask(task.toolName, origin.agentId, `Background task "${task.toolName}" completed (routing failed).`);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
// Format the announcement (byte-identical trailing instruction).
|
|
90
|
+
const announcement = formatCompletionAnnouncement(task);
|
|
91
|
+
// Construct the synthetic NormalizedMessage (hop counter in metadata).
|
|
92
|
+
const syntheticMsg = {
|
|
93
|
+
id: randomUUID(),
|
|
94
|
+
channelId: origin.channelId,
|
|
95
|
+
channelType: "background_task",
|
|
96
|
+
senderId: "background-task-runner",
|
|
97
|
+
text: announcement,
|
|
98
|
+
timestamp: Date.now(),
|
|
99
|
+
attachments: [],
|
|
100
|
+
metadata: {
|
|
101
|
+
backgroundHopCount: nextHopCount,
|
|
102
|
+
backgroundTaskId: task.id,
|
|
103
|
+
toolName: task.toolName,
|
|
104
|
+
agentId: origin.agentId,
|
|
105
|
+
traceId: origin.traceId ?? undefined,
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
log.debug({ taskId, sessionKey: origin.sessionKey, agentId: origin.agentId, toolName: task.toolName, hopCount: nextHopCount }, "Background completion runner: invoking executor");
|
|
109
|
+
// Emit background_task:reentered immediately before executor.execute().
|
|
110
|
+
// Integration tests compute p95 latency from
|
|
111
|
+
// background_task:completed.timestamp to this event's timestamp.
|
|
112
|
+
deps.eventBus.emit("background_task:reentered", {
|
|
113
|
+
taskId: task.id,
|
|
114
|
+
agentId: origin.agentId,
|
|
115
|
+
sessionKey: origin.sessionKey,
|
|
116
|
+
hopCount: nextHopCount,
|
|
117
|
+
timestamp: Date.now(),
|
|
118
|
+
});
|
|
119
|
+
// One turn per event. Existing session lock orders concurrent calls.
|
|
120
|
+
try {
|
|
121
|
+
await deps.getExecutor(origin.agentId).execute(syntheticMsg, parsedKey, undefined, undefined, origin.agentId);
|
|
122
|
+
}
|
|
123
|
+
catch (err) {
|
|
124
|
+
log.warn({ taskId, err, hint: "Executor failed mid-completion turn; subscription remains active", errorKind: "internal" }, "Background completion: executor.execute() rejected");
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
async function fallbackForTask(toolName, agentId, message) {
|
|
128
|
+
try {
|
|
129
|
+
await deps.fallbackNotifyFn({
|
|
130
|
+
agentId,
|
|
131
|
+
message,
|
|
132
|
+
priority: "normal",
|
|
133
|
+
origin: "background_task",
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
catch (err) {
|
|
137
|
+
log.warn({ toolName, agentId, err, hint: "fallbackNotifyFn rejected; user will not see the completion notification for this task", errorKind: "internal" }, "Background completion: fallbackNotifyFn rejected");
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return {
|
|
141
|
+
async shutdown() {
|
|
142
|
+
if (stopped)
|
|
143
|
+
return;
|
|
144
|
+
stopped = true;
|
|
145
|
+
deps.eventBus.off("background_task:completed", onCompleted);
|
|
146
|
+
deps.eventBus.off("background_task:failed", onFailed);
|
|
147
|
+
// Wait for any in-flight handler to settle before returning.
|
|
148
|
+
await inflight;
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
}
|
|
@@ -4,8 +4,12 @@
|
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
6
|
export type { BackgroundTask, BackgroundTaskStatus, PersistedTaskState } from "./background-task-types.js";
|
|
7
|
+
export type { BackgroundTaskOrigin } from "@comis/core";
|
|
7
8
|
export { persistTaskSync, loadTask, recoverTasks, removeTaskFile, TASK_DIR_NAME, } from "./background-task-persistence.js";
|
|
8
9
|
export { createBackgroundTaskManager, } from "./background-task-manager.js";
|
|
9
10
|
export type { BackgroundTaskManager, BackgroundTaskManagerOpts, NotifyFn, } from "./background-task-manager.js";
|
|
10
11
|
export { wrapToolForAutoBackground, } from "./auto-background-middleware.js";
|
|
11
12
|
export type { ToolDefinition, } from "./auto-background-middleware.js";
|
|
13
|
+
export { formatCompletionAnnouncement, TRAILING_INSTRUCTION } from "./completion-formatter.js";
|
|
14
|
+
export { createBackgroundCompletionRunner } from "./completion-runner.js";
|
|
15
|
+
export type { BackgroundCompletionRunner, BackgroundCompletionRunnerDeps, RunnerSessionStore, } from "./completion-runner.js";
|
|
@@ -7,3 +7,5 @@
|
|
|
7
7
|
export { persistTaskSync, loadTask, recoverTasks, removeTaskFile, TASK_DIR_NAME, } from "./background-task-persistence.js";
|
|
8
8
|
export { createBackgroundTaskManager, } from "./background-task-manager.js";
|
|
9
9
|
export { wrapToolForAutoBackground, } from "./auto-background-middleware.js";
|
|
10
|
+
export { formatCompletionAnnouncement, TRAILING_INSTRUCTION } from "./completion-formatter.js";
|
|
11
|
+
export { createBackgroundCompletionRunner } from "./completion-runner.js";
|
|
@@ -58,12 +58,23 @@ export interface BridgeMetricsState {
|
|
|
58
58
|
totalThinkingTokens: number;
|
|
59
59
|
budgetWarningEmitted: boolean;
|
|
60
60
|
thinkingBlockHashes: Map<string, ThinkingBlockHash[]>;
|
|
61
|
-
/**
|
|
62
|
-
*
|
|
61
|
+
/** Canonical (pre-mutation) snapshot of each assistant message's full
|
|
62
|
+
* content array, captured at stream close in lockstep with thinkingBlockHashes.
|
|
63
63
|
* Keyed by responseId; capped at 32 with FIFO eviction in lockstep with the
|
|
64
64
|
* hash store. Used by the pre-LLM-call restoration pass to heal cross-turn
|
|
65
65
|
* mutation of signed thinking blocks before pi-ai serializes the next request. */
|
|
66
66
|
thinkingBlockCanonical: Map<string, ReadonlyArray<unknown>>;
|
|
67
|
+
/** Number of pre-LLM-call hash-assertion walks performed (one per turn_start). */
|
|
68
|
+
hashAssertionsRan: number;
|
|
69
|
+
/** Total cross-turn thinking-block hash mismatches surfaced across all walks. */
|
|
70
|
+
hashAssertionMismatches: number;
|
|
71
|
+
/** Number of signature-replay scrubber invocations that scrubbed at least one
|
|
72
|
+
* assistant message in this execute(). Populated via ceSetup.getSignatureScrubCounters
|
|
73
|
+
* in executor-post-execution; surfaced here for symmetry / future bridge-side use. */
|
|
74
|
+
signatureScrubs: number;
|
|
75
|
+
/** Total tool calls across all signature-replay scrubs whose thoughtSignature
|
|
76
|
+
* was stripped (post-incident-visibility metric). */
|
|
77
|
+
signatureScrubsToolCallsAffected: number;
|
|
67
78
|
}
|
|
68
79
|
/**
|
|
69
80
|
* Create a fresh metrics state with all counters zeroed.
|
|
@@ -100,4 +111,8 @@ export declare function buildBridgeResult(metrics: BridgeMetricsState, stepCount
|
|
|
100
111
|
sessionCacheSavedUsd?: number;
|
|
101
112
|
thinkingTokens?: number;
|
|
102
113
|
budgetWarningEmitted?: boolean;
|
|
114
|
+
hashAssertionsRan?: number;
|
|
115
|
+
hashAssertionMismatches?: number;
|
|
116
|
+
signatureScrubs?: number;
|
|
117
|
+
signatureScrubsToolCallsAffected?: number;
|
|
103
118
|
};
|
|
@@ -53,6 +53,11 @@ export function createBridgeMetrics() {
|
|
|
53
53
|
budgetWarningEmitted: false,
|
|
54
54
|
thinkingBlockHashes: new Map(),
|
|
55
55
|
thinkingBlockCanonical: new Map(),
|
|
56
|
+
// per-execute diagnostic counters
|
|
57
|
+
hashAssertionsRan: 0,
|
|
58
|
+
hashAssertionMismatches: 0,
|
|
59
|
+
signatureScrubs: 0,
|
|
60
|
+
signatureScrubsToolCallsAffected: 0,
|
|
56
61
|
};
|
|
57
62
|
}
|
|
58
63
|
/**
|
|
@@ -95,12 +100,19 @@ export function buildBridgeResult(metrics, stepCount) {
|
|
|
95
100
|
lastStopReason: metrics.lastStopReason,
|
|
96
101
|
cacheWrite5mTokens: metrics.totalCacheWrite5mTokens,
|
|
97
102
|
cacheWrite1hTokens: metrics.totalCacheWrite1hTokens,
|
|
98
|
-
//
|
|
103
|
+
// Session-cumulative cost fields
|
|
99
104
|
sessionCostUsd: metrics.sessionCumulativeCostUsd,
|
|
100
105
|
sessionCacheSavedUsd: metrics.sessionCumulativeCacheSavedUsd,
|
|
101
|
-
//
|
|
106
|
+
// Thinking tokens (omitted when 0 to avoid log noise)
|
|
102
107
|
thinkingTokens: metrics.totalThinkingTokens > 0 ? metrics.totalThinkingTokens : undefined,
|
|
103
108
|
// Budget trajectory warning flag
|
|
104
109
|
budgetWarningEmitted: metrics.budgetWarningEmitted || undefined,
|
|
110
|
+
// Per-execute diagnostic counters. Always populated (no `> 0` gate) — a
|
|
111
|
+
// `0` in the bookend log is itself meaningful ("no scrubs/assertions
|
|
112
|
+
// this execute") and gating would lose that signal.
|
|
113
|
+
hashAssertionsRan: metrics.hashAssertionsRan,
|
|
114
|
+
hashAssertionMismatches: metrics.hashAssertionMismatches,
|
|
115
|
+
signatureScrubs: metrics.signatureScrubs,
|
|
116
|
+
signatureScrubsToolCallsAffected: metrics.signatureScrubsToolCallsAffected,
|
|
105
117
|
};
|
|
106
118
|
}
|
|
@@ -54,7 +54,7 @@ export interface PiEventBridgeDeps {
|
|
|
54
54
|
* internal retry. Rate-limit windows are per-minute (longer than the SDK's
|
|
55
55
|
* ~30s retry budget), so retrying within the window cannot succeed.
|
|
56
56
|
* Non-`rate_limited` retryable errors (overloaded, network, 5xx) bypass this
|
|
57
|
-
* hook -- the SDK's normal retry-with-backoff proceeds.
|
|
57
|
+
* hook -- the SDK's normal retry-with-backoff proceeds. */
|
|
58
58
|
onAbortRetry?: () => void;
|
|
59
59
|
/** SDK context usage accessor -- returns live context metrics from AgentSession. */
|
|
60
60
|
getContextUsage?: () => ContextUsageData | undefined;
|
|
@@ -106,7 +106,7 @@ export interface PiEventBridgeDeps {
|
|
|
106
106
|
sepMessageText?: string;
|
|
107
107
|
/** Execution start timestamp for SEP timing metrics. */
|
|
108
108
|
sepExecutionStartMs?: number;
|
|
109
|
-
/** Cache break detection
|
|
109
|
+
/** Cache break detection callback. Returns CacheBreakEvent if break detected. */
|
|
110
110
|
checkCacheBreak?: (input: {
|
|
111
111
|
sessionKey: string;
|
|
112
112
|
provider: string;
|
|
@@ -130,27 +130,27 @@ export interface PiEventBridgeDeps {
|
|
|
130
130
|
graphId?: string;
|
|
131
131
|
/** Graph node ID for cache write signal emission. Set only for graph subagents. */
|
|
132
132
|
nodeId?: string;
|
|
133
|
-
/**
|
|
133
|
+
/** Shared mutable TTL split estimate. Populated by request-body-injector
|
|
134
134
|
* on each API call, read by the bridge on turn_end for per-TTL cost calculation.
|
|
135
135
|
* The bridge normalizes these estimates against the actual SDK-reported cacheWriteTokens. */
|
|
136
136
|
ttlSplit?: TtlSplitEstimate;
|
|
137
|
-
/**
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
137
|
+
/** Pre-call hook: invoked once per `turn_start` event, BEFORE pi-ai
|
|
138
|
+
* serializes the next request. The closure (defined in pi-executor) walks
|
|
139
|
+
* `session.agent.state.messages`, asserts the cross-turn hash-invariant
|
|
140
|
+
* per assistant message with a stored hash entry (logs ERROR on mutation),
|
|
141
|
+
* then runs the canonical-restore helper against the canonical store
|
|
142
|
+
* (heals any mutation in-place by writing the result back to
|
|
143
|
+
* `session.agent.state.messages`). The return value is unused by the
|
|
144
|
+
* bridge -- the side effect is the heal write-back. Optional: when
|
|
145
145
|
* omitted, both the diagnostic and the heal are silently disabled
|
|
146
146
|
* (e.g., unit tests that don't drive a full agent session). */
|
|
147
147
|
getSessionMessages?: () => ReadonlyArray<unknown> | undefined;
|
|
148
|
-
/**
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
148
|
+
/** Wire-edge diagnostic: returns the absolute path to the per-session JSONL
|
|
149
|
+
* on disk. The bridge invokes this only when the LLM error path detects
|
|
150
|
+
* the signed-replay rejection signature, then diff'd against the persisted
|
|
151
|
+
* canonical to surface mutation that occurred AFTER the bridge's
|
|
152
|
+
* restoration hook. Optional — when omitted, the wire-edge diagnostic is
|
|
153
|
+
* a silent no-op. */
|
|
154
154
|
getSessionJsonlPath?: () => string | null;
|
|
155
155
|
}
|
|
156
156
|
/** Estimated cost payload for a timed-out API request. */
|
|
@@ -193,12 +193,12 @@ export interface PiEventBridgeResult {
|
|
|
193
193
|
};
|
|
194
194
|
/** Accumulate estimated cost from a timed-out API request. */
|
|
195
195
|
addGhostCost: (estimated: GhostCostEstimate) => void;
|
|
196
|
-
/**
|
|
197
|
-
*
|
|
198
|
-
*
|
|
199
|
-
*
|
|
200
|
-
*
|
|
201
|
-
*
|
|
196
|
+
/** ReadonlyMap views of the per-responseId hash store and canonical-snapshot
|
|
197
|
+
* store, both populated at stream-close in lockstep. The executor's
|
|
198
|
+
* pre-LLM-call closure reads both stores to drive the hash-invariant
|
|
199
|
+
* assertion plus the canonical restore helper. Returns ReadonlyMap views
|
|
200
|
+
* to preserve internal-state encapsulation -- the underlying `m` object is
|
|
201
|
+
* never exported. */
|
|
202
202
|
getThinkingBlockStores: () => {
|
|
203
203
|
hashes: ReadonlyMap<string, ReadonlyArray<ThinkingBlockHash>>;
|
|
204
204
|
canonical: ReadonlyMap<string, ReadonlyArray<unknown>>;
|
|
@@ -186,7 +186,7 @@ export function createPiEventBridge(deps) {
|
|
|
186
186
|
...(truncMeta && { truncated: truncMeta.truncated, fullChars: truncMeta.fullChars, returnedChars: truncMeta.returnedChars }),
|
|
187
187
|
});
|
|
188
188
|
// Reset prompt timeout after each tool completion so slow tools
|
|
189
|
-
// do not starve subsequent LLM turns
|
|
189
|
+
// do not starve subsequent LLM turns.
|
|
190
190
|
deps.onToolExecutionEnd?.();
|
|
191
191
|
// Safety: check step limit (delegated to bridge-safety-controls)
|
|
192
192
|
{
|
|
@@ -222,20 +222,20 @@ export function createPiEventBridge(deps) {
|
|
|
222
222
|
// LLM turn about to start (pre-serialize hook for assert+restore)
|
|
223
223
|
// -----------------------------------------------------------------
|
|
224
224
|
case "turn_start": {
|
|
225
|
-
//
|
|
226
|
-
//
|
|
227
|
-
//
|
|
228
|
-
//
|
|
229
|
-
//
|
|
230
|
-
//
|
|
231
|
-
//
|
|
232
|
-
//
|
|
225
|
+
// Run the executor-supplied pre-call closure once per turn, before
|
|
226
|
+
// pi-ai reads `session.agent.state.messages` to serialize the next
|
|
227
|
+
// API request. The closure performs the assert-then-restore pass
|
|
228
|
+
// over the live transcript and writes the healed array back into
|
|
229
|
+
// session state when at least one swap happens, so the bytes
|
|
230
|
+
// Anthropic sees match the canonical stream-close snapshot. The
|
|
231
|
+
// closure swallows its own throws; the wrapper here is
|
|
232
|
+
// belt-and-braces.
|
|
233
233
|
//
|
|
234
|
-
//
|
|
235
|
-
//
|
|
236
|
-
//
|
|
237
|
-
//
|
|
238
|
-
//
|
|
234
|
+
// ALWAYS emit ONE INFO log carrying the counters the bridge can
|
|
235
|
+
// derive — even when the closure is unwired or returns undefined /
|
|
236
|
+
// no candidates. This closes the silent-success ambiguity where
|
|
237
|
+
// ZERO agent.bridge.* events appeared despite the helpers having
|
|
238
|
+
// shipped.
|
|
239
239
|
//
|
|
240
240
|
// Counters are computed by the bridge's own walk of the messages
|
|
241
241
|
// returned by the closure (or empty when unwired) so the executor
|
|
@@ -289,15 +289,27 @@ export function createPiEventBridge(deps) {
|
|
|
289
289
|
// implementation; surfaced as a separate field so future asymmetric
|
|
290
290
|
// assert/restore semantics are observable.
|
|
291
291
|
const restoredCount = mismatchesLogged;
|
|
292
|
-
|
|
293
|
-
|
|
292
|
+
m.hashAssertionsRan++;
|
|
293
|
+
m.hashAssertionMismatches += mismatchesLogged;
|
|
294
|
+
const hashAssertionPayload = {
|
|
295
|
+
submodule: "bridge.hash-invariant",
|
|
294
296
|
candidatesChecked,
|
|
295
297
|
mismatchesLogged,
|
|
296
298
|
restoredCount,
|
|
297
299
|
anyResponseIdMatched,
|
|
298
300
|
hashStoreSize,
|
|
299
301
|
canonicalStoreSize,
|
|
300
|
-
}
|
|
302
|
+
};
|
|
303
|
+
if (mismatchesLogged > 0) {
|
|
304
|
+
deps.logger.warn({
|
|
305
|
+
...hashAssertionPayload,
|
|
306
|
+
hint: "Cross-turn thinking-block mutation detected; pre-call restore pass will heal before next API serialize. Investigate if this fires repeatedly without the heal succeeding (canonicalStoreSize === 0).",
|
|
307
|
+
errorKind: "internal",
|
|
308
|
+
}, "Pre-call assertion ran");
|
|
309
|
+
}
|
|
310
|
+
else {
|
|
311
|
+
deps.logger.debug(hashAssertionPayload, "Pre-call assertion ran");
|
|
312
|
+
}
|
|
301
313
|
break;
|
|
302
314
|
}
|
|
303
315
|
// -----------------------------------------------------------------
|
|
@@ -337,14 +349,14 @@ export function createPiEventBridge(deps) {
|
|
|
337
349
|
thinkingLen: typeof b.thinking === "string" ? b.thinking.length : 0,
|
|
338
350
|
})),
|
|
339
351
|
}, "Assistant message block accounting at stream close");
|
|
340
|
-
//
|
|
341
|
-
//
|
|
342
|
-
//
|
|
343
|
-
//
|
|
344
|
-
//
|
|
345
|
-
//
|
|
346
|
-
//
|
|
347
|
-
//
|
|
352
|
+
// Diagnostic + heal: capture hashes AND a canonical (pre-mutation)
|
|
353
|
+
// snapshot of the full content array, keyed by responseId, in
|
|
354
|
+
// lockstep across both stores. The hash store powers the
|
|
355
|
+
// assertion ERROR log (mutation diagnostic); the canonical
|
|
356
|
+
// store powers the pre-call restore pass that heals cross-turn
|
|
357
|
+
// mutation before the next API serialize. Both stores are
|
|
358
|
+
// FIFO-evicted at 32 entries in lockstep so they always share
|
|
359
|
+
// the same keyset.
|
|
348
360
|
if (typeof responseIdForLog === "string") {
|
|
349
361
|
const hashes = computeThinkingBlockHashes(blocks);
|
|
350
362
|
if (hashes.length > 0) {
|
|
@@ -356,11 +368,11 @@ export function createPiEventBridge(deps) {
|
|
|
356
368
|
m.thinkingBlockCanonical.delete(oldestKey);
|
|
357
369
|
}
|
|
358
370
|
m.thinkingBlockHashes.set(responseIdForLog, hashes);
|
|
359
|
-
//
|
|
360
|
-
//
|
|
361
|
-
//
|
|
362
|
-
//
|
|
363
|
-
//
|
|
371
|
+
// Capture canonical (pre-mutation) full content array so
|
|
372
|
+
// the pre-LLM-call restore pass can heal any cross-turn
|
|
373
|
+
// mutation before pi-ai serializes the next request.
|
|
374
|
+
// structuredClone is a Node 22 global; the try/catch is
|
|
375
|
+
// defensive against rare exotic input shapes.
|
|
364
376
|
try {
|
|
365
377
|
const canonical = Object.freeze(structuredClone(blocks));
|
|
366
378
|
m.thinkingBlockCanonical.set(responseIdForLog, canonical);
|
|
@@ -382,7 +394,7 @@ export function createPiEventBridge(deps) {
|
|
|
382
394
|
const llmLatencyMs = turnWallclockMs - effectiveTurnToolMs;
|
|
383
395
|
m.cumulativeLlmDurationMs += llmLatencyMs;
|
|
384
396
|
m.turnToolDurationMs = 0;
|
|
385
|
-
//
|
|
397
|
+
// Extract responseId from assistant message (optional -- not all providers supply it)
|
|
386
398
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- SDK interop boundary
|
|
387
399
|
const responseId = assistantMsg?.responseId;
|
|
388
400
|
if (assistantMsg && "usage" in assistantMsg && assistantMsg.usage) {
|
|
@@ -421,7 +433,7 @@ export function createPiEventBridge(deps) {
|
|
|
421
433
|
if (deps.onTurnWithCacheWrite) {
|
|
422
434
|
deps.onTurnWithCacheWrite(cacheWriteTokens);
|
|
423
435
|
}
|
|
424
|
-
// Cache break detection
|
|
436
|
+
// Cache break detection (all providers, unconditional)
|
|
425
437
|
// MUST NOT guard with cacheReadTokens > 0 -- complete cache misses (drop to 0) must be detected
|
|
426
438
|
if (deps.checkCacheBreak) {
|
|
427
439
|
// Detect API errors -- zero usage with error stop reason
|
|
@@ -451,7 +463,7 @@ export function createPiEventBridge(deps) {
|
|
|
451
463
|
}
|
|
452
464
|
}
|
|
453
465
|
}
|
|
454
|
-
//
|
|
466
|
+
// Extract cacheCreation breakdown (future upstream -- runtime check)
|
|
455
467
|
const rawUsage = usage;
|
|
456
468
|
const cacheCreation = rawUsage.cacheCreation && typeof rawUsage.cacheCreation === "object"
|
|
457
469
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- SDK interop boundary
|
|
@@ -472,7 +484,7 @@ export function createPiEventBridge(deps) {
|
|
|
472
484
|
}
|
|
473
485
|
// Record usage in budget guard (token-based, not cost-based -- stays before correction)
|
|
474
486
|
deps.budgetGuard.recordUsage(usage.totalTokens);
|
|
475
|
-
//
|
|
487
|
+
// COST-FIX ordering: Normalize TTL split estimates BEFORE cost correction.
|
|
476
488
|
// The injector provides raw per-TTL estimates; normalize so they sum to the
|
|
477
489
|
// SDK-reported total (eliminates the 28% estimation error).
|
|
478
490
|
// Mutate in-place so per-TTL cost and accumulation use normalized values.
|
|
@@ -551,10 +563,10 @@ export function createPiEventBridge(deps) {
|
|
|
551
563
|
if (deps.onTurnCacheSavings) {
|
|
552
564
|
deps.onTurnCacheSavings(savedVsUncached);
|
|
553
565
|
}
|
|
554
|
-
//
|
|
566
|
+
// Accumulate session-cumulative costs alongside per-turn values
|
|
555
567
|
m.sessionCumulativeCostUsd += cost.total;
|
|
556
568
|
m.sessionCumulativeCacheSavedUsd += savedVsUncached;
|
|
557
|
-
//
|
|
569
|
+
// Track thinking tokens from SDK usage object.
|
|
558
570
|
// The pi-ai SDK Usage type does not have a dedicated thinking/reasoning field,
|
|
559
571
|
// but future versions or raw API responses may include `reasoningTokens`.
|
|
560
572
|
// Runtime-check the raw usage object for this field.
|
|
@@ -567,9 +579,9 @@ export function createPiEventBridge(deps) {
|
|
|
567
579
|
m.totalThinkingTokens += sdkThinkingTokens;
|
|
568
580
|
}
|
|
569
581
|
}
|
|
570
|
-
//
|
|
571
|
-
// SDK-sourced cacheCreation
|
|
572
|
-
//
|
|
582
|
+
// Populate cacheCreation from bridge metrics TTL split when SDK doesn't provide it.
|
|
583
|
+
// SDK-sourced cacheCreation takes priority; bridge metrics provide the fallback
|
|
584
|
+
// when pi-ai doesn't surface per-TTL breakdown.
|
|
573
585
|
const effectiveCacheCreation = cacheCreation ?? ((m.totalCacheWrite5mTokens > 0 || m.totalCacheWrite1hTokens > 0)
|
|
574
586
|
? { shortTtl: m.totalCacheWrite5mTokens, longTtl: m.totalCacheWrite1hTokens }
|
|
575
587
|
: undefined);
|
|
@@ -844,7 +856,7 @@ export function createPiEventBridge(deps) {
|
|
|
844
856
|
break;
|
|
845
857
|
}
|
|
846
858
|
// -----------------------------------------------------------------
|
|
847
|
-
// SDK auto-retry loop: abort on rate_limited
|
|
859
|
+
// SDK auto-retry loop: abort on rate_limited
|
|
848
860
|
// -----------------------------------------------------------------
|
|
849
861
|
case "auto_retry_start": {
|
|
850
862
|
const errorMessage = event.errorMessage ?? "";
|
|
@@ -854,7 +866,7 @@ export function createPiEventBridge(deps) {
|
|
|
854
866
|
const classification = classifyError(new Error(errorMessage));
|
|
855
867
|
if (classification.category === "rate_limited") {
|
|
856
868
|
deps.logger.info({
|
|
857
|
-
|
|
869
|
+
submodule: "bridge.auto-retry-abort",
|
|
858
870
|
attempt,
|
|
859
871
|
maxAttempts,
|
|
860
872
|
delayMs,
|
|
@@ -884,20 +896,20 @@ export function createPiEventBridge(deps) {
|
|
|
884
896
|
hint: "Check LLM provider status",
|
|
885
897
|
errorKind: "dependency",
|
|
886
898
|
}, "LLM call returned error");
|
|
887
|
-
//
|
|
888
|
-
//
|
|
889
|
-
//
|
|
890
|
-
//
|
|
891
|
-
//
|
|
892
|
-
//
|
|
893
|
-
//
|
|
899
|
+
// Wire-edge diagnostic: when the LLM error matches the Anthropic
|
|
900
|
+
// signed-replay rejection signature ("thinking blocks ... cannot
|
|
901
|
+
// be modified"), diff the in-memory content against the persisted
|
|
902
|
+
// JSONL canonical and emit one ERROR per divergent block. Fully
|
|
903
|
+
// async / fire-and-forget — never blocks the existing error path.
|
|
904
|
+
// Silent no-op when the signature doesn't match or when either
|
|
905
|
+
// getSessionMessages / getSessionJsonlPath is unwired.
|
|
894
906
|
//
|
|
895
|
-
//
|
|
896
|
-
//
|
|
897
|
-
//
|
|
898
|
-
//
|
|
899
|
-
//
|
|
900
|
-
//
|
|
907
|
+
// ALWAYS emit ONE dispatch-decision INFO log carrying boolean flags
|
|
908
|
+
// that explain WHY the wire-diff dispatch was or was not entered
|
|
909
|
+
// (regex match, candidate count, callback presence) — even when
|
|
910
|
+
// regexMatched is false or callbacks are unwired. When the dispatch
|
|
911
|
+
// IS entered, emit a second dispatch-completion INFO after the
|
|
912
|
+
// async candidates loop completes.
|
|
901
913
|
//
|
|
902
914
|
// The signature regex matches Anthropic's actual 400 message:
|
|
903
915
|
// "messages.N.content.M: thinking blocks cannot be modified"
|
|
@@ -936,7 +948,7 @@ export function createPiEventBridge(deps) {
|
|
|
936
948
|
}
|
|
937
949
|
const jsonlPathPresent = typeof jsonlPathForDecision === "string" && jsonlPathForDecision.length > 0;
|
|
938
950
|
deps.logger.info({
|
|
939
|
-
|
|
951
|
+
submodule: "bridge.wire-diff",
|
|
940
952
|
regexMatched,
|
|
941
953
|
candidatesFound: candidates.length,
|
|
942
954
|
jsonlPathPresent,
|
|
@@ -969,7 +981,7 @@ export function createPiEventBridge(deps) {
|
|
|
969
981
|
totalDivergences += entries.length;
|
|
970
982
|
for (const entry of entries) {
|
|
971
983
|
deps.logger.error({
|
|
972
|
-
|
|
984
|
+
submodule: "bridge.wire-diff",
|
|
973
985
|
responseId: c.responseId,
|
|
974
986
|
blockIndex: entry.blockIndex,
|
|
975
987
|
persistedHash: entry.persistedHash,
|
|
@@ -991,7 +1003,7 @@ export function createPiEventBridge(deps) {
|
|
|
991
1003
|
// ALWAYS emit the completion INFO, even on totalDivergences=0
|
|
992
1004
|
// or when every helper call hit a read error.
|
|
993
1005
|
deps.logger.info({
|
|
994
|
-
|
|
1006
|
+
submodule: "bridge.wire-diff",
|
|
995
1007
|
candidatesProcessed,
|
|
996
1008
|
totalDivergences,
|
|
997
1009
|
persistedNotFound,
|
|
@@ -1031,9 +1043,9 @@ export function createPiEventBridge(deps) {
|
|
|
1031
1043
|
m.ghostCostUsd += estimated.costUsd;
|
|
1032
1044
|
m.timedOutRequests += 1;
|
|
1033
1045
|
};
|
|
1034
|
-
//
|
|
1035
|
-
//
|
|
1036
|
-
//
|
|
1046
|
+
// Typed ReadonlyMap accessor for the executor's pre-call closure.
|
|
1047
|
+
// Returns views over the live maps -- the executor never receives the
|
|
1048
|
+
// mutable `m` object itself.
|
|
1037
1049
|
const getThinkingBlockStores = () => ({
|
|
1038
1050
|
hashes: m.thinkingBlockHashes,
|
|
1039
1051
|
canonical: m.thinkingBlockCanonical,
|
|
@@ -3,9 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Observed problem: Anthropic 400 `messages.N.content.M: thinking/redacted_thinking
|
|
5
5
|
* blocks cannot be modified` errors keep firing in production even after the
|
|
6
|
-
* surrogate-guard, drift-scrubber, and signed-replay-detector layers shipped
|
|
7
|
-
*
|
|
8
|
-
* Trace `c7b91328-9dc5-4618-9ae8-ca207b4b93df` on 2026-04-28 hit a 400 ~2.2s
|
|
6
|
+
* surrogate-guard, drift-scrubber, and signed-replay-detector layers shipped,
|
|
7
|
+
* and even after the immutable-section redirect. A trace hit a 400 ~2.2s
|
|
9
8
|
* after `turn_end` -- meaning *some other layer* mutates a signed thinking
|
|
10
9
|
* block between the assistant turn and the next replay. We don't know which.
|
|
11
10
|
*
|
|
@@ -23,12 +22,12 @@
|
|
|
23
22
|
* - NEVER mutates inputs. Pure read; only output is the structured log.
|
|
24
23
|
* - NEVER alters request flow. The mismatch is observable signal only --
|
|
25
24
|
* Anthropic's 400 still surfaces through the existing error path
|
|
26
|
-
* (signed-replay-detector -> executor-prompt-runner).
|
|
27
|
-
*
|
|
25
|
+
* (signed-replay-detector -> executor-prompt-runner). The behavior fix
|
|
26
|
+
* for the underlying bug is gated on what this diagnostic reveals.
|
|
28
27
|
*
|
|
29
28
|
* Logging surface follows CLAUDE.md canonical Pino fields:
|
|
30
29
|
* - object-first signature: `error({...fields}, "msg")`
|
|
31
|
-
* - `
|
|
30
|
+
* - `submodule: "bridge.hash-invariant"` (parent logger binds `module: "agent"`)
|
|
32
31
|
* - `errorKind: "internal"` (classification per AGENTS.md §2.1)
|
|
33
32
|
* - `hint`: actionable next step for the on-call diagnoser
|
|
34
33
|
* - `responseId`, `blockIndex`, `oldHash`, `newHash`,
|
|
@@ -137,7 +136,7 @@ export interface RestoreResult {
|
|
|
137
136
|
* Never throws. On any unexpected error during the walk (e.g. malformed
|
|
138
137
|
* canonical entry whose getter throws), the entire result is `{ messages:
|
|
139
138
|
* <input ref>, restoredCount: 0, affectedResponseIds: [] }` and ONE WARN log
|
|
140
|
-
* fires with `
|
|
139
|
+
* fires with `submodule: RESTORE_SUBMODULE_FIELD, errorKind: "internal"`.
|
|
141
140
|
*/
|
|
142
141
|
export declare function restoreCanonicalThinkingBlocks(messages: ReadonlyArray<unknown> | undefined | null, canonicalStore: ReadonlyMap<string, ReadonlyArray<unknown>>, deps?: RestoreDeps): RestoreResult;
|
|
143
142
|
export declare const WIRE_DIFF_HINT_FILE_MISSING: string;
|