comisai 1.0.36 → 1.0.37
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.js +9 -0
- package/node_modules/@comis/agent/dist/background/background-task-manager.d.ts +22 -2
- package/node_modules/@comis/agent/dist/background/background-task-manager.js +48 -41
- package/node_modules/@comis/agent/dist/background/background-task-persistence.js +28 -5
- package/node_modules/@comis/agent/dist/background/background-task-types.d.ts +49 -0
- package/node_modules/@comis/agent/dist/background/completion-dispatcher.d.ts +130 -0
- package/node_modules/@comis/agent/dist/background/completion-dispatcher.js +215 -0
- package/node_modules/@comis/agent/dist/background/completion-runner.d.ts +10 -1
- package/node_modules/@comis/agent/dist/background/completion-runner.js +98 -15
- package/node_modules/@comis/agent/dist/background/index.d.ts +6 -1
- package/node_modules/@comis/agent/dist/background/index.js +2 -0
- package/node_modules/@comis/agent/dist/background/session-resolver.d.ts +85 -0
- package/node_modules/@comis/agent/dist/background/session-resolver.js +78 -0
- package/node_modules/@comis/agent/dist/bootstrap/sections/messaging-sections.js +1 -0
- package/node_modules/@comis/agent/dist/bootstrap/sections/tool-descriptions.js +3 -3
- package/node_modules/@comis/agent/dist/bootstrap/sections/tooling-sections.d.ts +30 -2
- package/node_modules/@comis/agent/dist/bootstrap/sections/tooling-sections.js +51 -2
- package/node_modules/@comis/agent/dist/bootstrap/system-prompt-assembler.d.ts +22 -0
- package/node_modules/@comis/agent/dist/bootstrap/system-prompt-assembler.js +2 -2
- package/node_modules/@comis/agent/dist/bridge/bridge-event-handlers.d.ts +1 -5
- package/node_modules/@comis/agent/dist/bridge/bridge-event-handlers.js +2 -14
- package/node_modules/@comis/agent/dist/bridge/bridge-metrics.d.ts +26 -0
- package/node_modules/@comis/agent/dist/bridge/bridge-metrics.js +3 -0
- package/node_modules/@comis/agent/dist/bridge/pi-event-bridge.d.ts +9 -0
- package/node_modules/@comis/agent/dist/bridge/pi-event-bridge.js +73 -2
- package/node_modules/@comis/agent/dist/context-engine/signature-surrogate-guard.d.ts +10 -10
- package/node_modules/@comis/agent/dist/context-engine/signature-surrogate-guard.js +14 -14
- package/node_modules/@comis/agent/dist/context-engine/thinking-block-cleaner.d.ts +11 -13
- package/node_modules/@comis/agent/dist/context-engine/thinking-block-cleaner.js +14 -15
- package/node_modules/@comis/agent/dist/executor/capability-index-context.d.ts +72 -0
- package/node_modules/@comis/agent/dist/executor/capability-index-context.js +329 -0
- package/node_modules/@comis/agent/dist/executor/drain-helper.d.ts +122 -0
- package/node_modules/@comis/agent/dist/executor/drain-helper.js +173 -0
- package/node_modules/@comis/agent/dist/executor/error-classifier.js +2 -2
- package/node_modules/@comis/agent/dist/executor/executor-post-execution.d.ts +48 -4
- package/node_modules/@comis/agent/dist/executor/executor-post-execution.js +134 -31
- package/node_modules/@comis/agent/dist/executor/executor-prompt-runner.d.ts +7 -0
- package/node_modules/@comis/agent/dist/executor/executor-prompt-runner.js +25 -4
- package/node_modules/@comis/agent/dist/executor/executor-tool-assembly.d.ts +18 -1
- package/node_modules/@comis/agent/dist/executor/executor-tool-assembly.js +19 -16
- package/node_modules/@comis/agent/dist/executor/jit-guide-injector.d.ts +11 -2
- package/node_modules/@comis/agent/dist/executor/jit-guide-injector.js +16 -2
- package/node_modules/@comis/agent/dist/executor/pi-executor.d.ts +8 -2
- package/node_modules/@comis/agent/dist/executor/pi-executor.js +25 -12
- package/node_modules/@comis/agent/dist/executor/prompt-assembly.d.ts +9 -1
- package/node_modules/@comis/agent/dist/executor/prompt-assembly.js +15 -1
- package/node_modules/@comis/agent/dist/executor/tool-deferral.d.ts +18 -27
- package/node_modules/@comis/agent/dist/executor/tool-deferral.js +29 -38
- package/node_modules/@comis/agent/dist/model/model-registry-adapter.js +1 -1
- package/node_modules/@comis/agent/dist/model/model-scanner.js +1 -1
- package/node_modules/@comis/agent/dist/safety/tool-retry-breaker.d.ts +11 -1
- package/node_modules/@comis/agent/dist/safety/tool-retry-breaker.js +19 -22
- package/node_modules/@comis/agent/dist/session/comis-session-manager.d.ts +16 -2
- package/node_modules/@comis/agent/dist/spawn/pi-mono-adapters.d.ts +1 -1
- package/node_modules/@comis/agent/dist/spawn/pi-mono-adapters.js +5 -5
- package/node_modules/@comis/agent/dist/workspace/data-env.d.ts +38 -0
- package/node_modules/@comis/agent/dist/workspace/data-env.js +56 -0
- package/node_modules/@comis/agent/dist/workspace/index.d.ts +1 -0
- package/node_modules/@comis/agent/dist/workspace/index.js +1 -0
- package/node_modules/@comis/agent/dist/workspace/templates.js +5 -1
- package/node_modules/@comis/agent/package.json +1 -1
- package/node_modules/@comis/channels/dist/index.d.ts +1 -1
- package/node_modules/@comis/channels/dist/index.js +1 -1
- package/node_modules/@comis/channels/dist/shared/channel-manager.d.ts +9 -3
- package/node_modules/@comis/channels/dist/shared/inbound-gate.d.ts +1 -1
- package/node_modules/@comis/channels/dist/shared/inbound-gate.js +22 -7
- package/node_modules/@comis/channels/dist/shared/inbound-pipeline.d.ts +10 -3
- package/node_modules/@comis/channels/dist/shared/inbound-route.d.ts +1 -1
- package/node_modules/@comis/channels/dist/shared/inbound-route.js +13 -2
- package/node_modules/@comis/channels/dist/shared/response-filter.d.ts +11 -24
- package/node_modules/@comis/channels/dist/shared/response-filter.js +25 -53
- package/node_modules/@comis/channels/package.json +1 -1
- package/node_modules/@comis/cli/dist/commands/providers.d.ts +1 -2
- package/node_modules/@comis/cli/dist/commands/providers.js +5 -6
- package/node_modules/@comis/cli/package.json +1 -1
- package/node_modules/@comis/core/dist/config/field-metadata.js +2 -0
- package/node_modules/@comis/core/dist/config/immutable-keys.js +4 -1
- package/node_modules/@comis/core/dist/config/index.d.ts +4 -0
- package/node_modules/@comis/core/dist/config/index.js +2 -0
- package/node_modules/@comis/core/dist/config/schema-agent.d.ts +0 -792
- package/node_modules/@comis/core/dist/config/schema-approvals.d.ts +0 -14
- package/node_modules/@comis/core/dist/config/schema-auto-reply-engine.d.ts +0 -6
- package/node_modules/@comis/core/dist/config/schema-background-tasks.d.ts +0 -12
- package/node_modules/@comis/core/dist/config/schema-browser.d.ts +0 -18
- package/node_modules/@comis/core/dist/config/schema-channel.d.ts +0 -158
- package/node_modules/@comis/core/dist/config/schema-coalescer.d.ts +0 -5
- package/node_modules/@comis/core/dist/config/schema-daemon.d.ts +0 -32
- package/node_modules/@comis/core/dist/config/schema-delivery.d.ts +0 -18
- package/node_modules/@comis/core/dist/config/schema-documentation.d.ts +0 -12
- package/node_modules/@comis/core/dist/config/schema-embedding.d.ts +0 -20
- package/node_modules/@comis/core/dist/config/schema-envelope.d.ts +0 -15
- package/node_modules/@comis/core/dist/config/schema-gateway.d.ts +0 -37
- package/node_modules/@comis/core/dist/config/schema-gemini-cache.d.ts +0 -2
- package/node_modules/@comis/core/dist/config/schema-integrations.d.ts +0 -318
- package/node_modules/@comis/core/dist/config/schema-lifecycle-reactions.d.ts +0 -18
- package/node_modules/@comis/core/dist/config/schema-memory-review.d.ts +0 -7
- package/node_modules/@comis/core/dist/config/schema-memory.d.ts +0 -16
- package/node_modules/@comis/core/dist/config/schema-messages.d.ts +0 -8
- package/node_modules/@comis/core/dist/config/schema-models.d.ts +0 -15
- package/node_modules/@comis/core/dist/config/schema-notification.d.ts +0 -5
- package/node_modules/@comis/core/dist/config/schema-oauth.d.ts +0 -5
- package/node_modules/@comis/core/dist/config/schema-observability.d.ts +0 -38
- package/node_modules/@comis/core/dist/config/schema-output-retention.d.ts +34 -0
- package/node_modules/@comis/core/dist/config/schema-output-retention.js +48 -0
- package/node_modules/@comis/core/dist/config/schema-plugins.d.ts +0 -8
- package/node_modules/@comis/core/dist/config/schema-providers.d.ts +0 -64
- package/node_modules/@comis/core/dist/config/schema-queue.d.ts +0 -58
- package/node_modules/@comis/core/dist/config/schema-response-prefix.d.ts +0 -2
- package/node_modules/@comis/core/dist/config/schema-retry.d.ts +0 -6
- package/node_modules/@comis/core/dist/config/schema-scheduler.d.ts +0 -39
- package/node_modules/@comis/core/dist/config/schema-secrets.d.ts +0 -3
- package/node_modules/@comis/core/dist/config/schema-security.d.ts +0 -18
- package/node_modules/@comis/core/dist/config/schema-send-policy.d.ts +0 -13
- package/node_modules/@comis/core/dist/config/schema-sender-trust-display.d.ts +0 -5
- package/node_modules/@comis/core/dist/config/schema-serializer.js +2 -0
- package/node_modules/@comis/core/dist/config/schema-skills.d.ts +0 -61
- package/node_modules/@comis/core/dist/config/schema-streaming.d.ts +0 -38
- package/node_modules/@comis/core/dist/config/schema-telegram-file-guard.d.ts +0 -3
- package/node_modules/@comis/core/dist/config/schema-tooling.d.ts +87 -0
- package/node_modules/@comis/core/dist/config/schema-tooling.js +152 -0
- package/node_modules/@comis/core/dist/config/schema-verbosity.d.ts +0 -12
- package/node_modules/@comis/core/dist/config/schema-webhooks.d.ts +0 -40
- package/node_modules/@comis/core/dist/config/schema.d.ts +41 -38
- package/node_modules/@comis/core/dist/config/schema.js +6 -0
- package/node_modules/@comis/core/dist/context/context.d.ts +0 -4
- package/node_modules/@comis/core/dist/domain/approval-request.d.ts +0 -17
- package/node_modules/@comis/core/dist/domain/background-task-origin.d.ts +0 -10
- package/node_modules/@comis/core/dist/domain/delivery-origin.d.ts +0 -5
- package/node_modules/@comis/core/dist/domain/execution-graph.d.ts +0 -48
- package/node_modules/@comis/core/dist/domain/memory-entry.d.ts +0 -3
- package/node_modules/@comis/core/dist/domain/model-compat.d.ts +0 -4
- package/node_modules/@comis/core/dist/domain/normalized-message.d.ts +0 -15
- package/node_modules/@comis/core/dist/domain/provider-capabilities.d.ts +0 -6
- package/node_modules/@comis/core/dist/domain/rich-message.d.ts +0 -14
- package/node_modules/@comis/core/dist/domain/subagent-context-config.d.ts +0 -22
- package/node_modules/@comis/core/dist/domain/subagent-context-types.d.ts +0 -8
- package/node_modules/@comis/core/dist/event-bus/events-agent.d.ts +31 -0
- package/node_modules/@comis/core/dist/event-bus/events-infra.d.ts +5 -0
- package/node_modules/@comis/core/dist/exports/config.d.ts +2 -2
- package/node_modules/@comis/core/dist/exports/config.js +3 -1
- package/node_modules/@comis/core/dist/exports/hooks.d.ts +1 -1
- 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/channel-plugin.d.ts +0 -13
- package/node_modules/@comis/core/dist/ports/index.d.ts +2 -0
- package/node_modules/@comis/core/dist/ports/index.js +4 -0
- package/node_modules/@comis/core/dist/ports/no-op-tool-capability.d.ts +30 -0
- package/node_modules/@comis/core/dist/ports/no-op-tool-capability.js +47 -0
- package/node_modules/@comis/core/dist/ports/tool-capability.d.ts +165 -0
- package/node_modules/@comis/core/dist/ports/tool-capability.js +15 -0
- package/node_modules/@comis/core/dist/security/audit.d.ts +0 -11
- package/node_modules/@comis/core/dist/tool-metadata.d.ts +21 -1
- package/node_modules/@comis/core/dist/tool-metadata.js +1 -1
- package/node_modules/@comis/core/package.json +1 -1
- package/node_modules/@comis/daemon/bundled-skills/skill-creator/scripts/validate-skill.py +1 -1
- package/node_modules/@comis/daemon/dist/daemon.js +89 -14
- package/node_modules/@comis/daemon/dist/rpc/agent-inline-workspace.d.ts +1 -1
- package/node_modules/@comis/daemon/dist/rpc/agent-inline-workspace.js +1 -1
- package/node_modules/@comis/daemon/dist/rpc/builtin-provider-guard.js +2 -2
- package/node_modules/@comis/daemon/dist/rpc/credential-resolver.js +1 -1
- package/node_modules/@comis/daemon/dist/rpc/model-handlers.d.ts +1 -1
- package/node_modules/@comis/daemon/dist/rpc/model-handlers.js +2 -2
- package/node_modules/@comis/daemon/dist/sub-agent-runner.d.ts +18 -0
- package/node_modules/@comis/daemon/dist/sub-agent-runner.js +41 -9
- 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/setup-agents.d.ts +36 -2
- package/node_modules/@comis/daemon/dist/wiring/setup-agents.js +45 -8
- package/node_modules/@comis/daemon/dist/wiring/setup-background-completion-runner.d.ts +28 -9
- package/node_modules/@comis/daemon/dist/wiring/setup-background-completion-runner.js +36 -9
- package/node_modules/@comis/daemon/dist/wiring/setup-background-tasks.js +2 -2
- package/node_modules/@comis/daemon/dist/wiring/setup-channels.d.ts +9 -2
- package/node_modules/@comis/daemon/dist/wiring/setup-channels.js +15 -9
- package/node_modules/@comis/daemon/dist/wiring/setup-cross-session.d.ts +20 -5
- package/node_modules/@comis/daemon/dist/wiring/setup-cross-session.js +20 -15
- package/node_modules/@comis/daemon/dist/wiring/setup-delivery.js +14 -2
- package/node_modules/@comis/daemon/dist/wiring/setup-gateway.d.ts +4 -6
- package/node_modules/@comis/daemon/dist/wiring/setup-gateway.js +3 -5
- package/node_modules/@comis/daemon/dist/wiring/setup-heartbeat.d.ts +20 -5
- package/node_modules/@comis/daemon/dist/wiring/setup-heartbeat.js +11 -2
- package/node_modules/@comis/daemon/dist/wiring/setup-output-retention.d.ts +89 -0
- package/node_modules/@comis/daemon/dist/wiring/setup-output-retention.js +212 -0
- package/node_modules/@comis/daemon/dist/wiring/setup-tools.d.ts +18 -4
- package/node_modules/@comis/daemon/dist/wiring/setup-tools.js +29 -10
- package/node_modules/@comis/daemon/dist/wiring/tool-capability-adapter.d.ts +75 -0
- package/node_modules/@comis/daemon/dist/wiring/tool-capability-adapter.js +253 -0
- package/node_modules/@comis/daemon/package.json +1 -1
- package/node_modules/@comis/gateway/dist/webhook/webhook-endpoint.d.ts +0 -4
- package/node_modules/@comis/gateway/package.json +1 -1
- package/node_modules/@comis/infra/package.json +1 -1
- package/node_modules/@comis/memory/package.json +1 -1
- package/node_modules/@comis/scheduler/dist/cron/cron-types.d.ts +0 -42
- package/node_modules/@comis/scheduler/dist/heartbeat/agent-heartbeat-source.d.ts +29 -8
- package/node_modules/@comis/scheduler/dist/heartbeat/agent-heartbeat-source.js +19 -7
- package/node_modules/@comis/scheduler/dist/system-events/system-event-types.d.ts +0 -3
- package/node_modules/@comis/scheduler/dist/tasks/task-types.d.ts +0 -17
- package/node_modules/@comis/scheduler/package.json +1 -1
- package/node_modules/@comis/shared/dist/index.d.ts +3 -0
- package/node_modules/@comis/shared/dist/index.js +4 -0
- package/node_modules/@comis/shared/dist/mcp-tool-name.d.ts +78 -0
- package/node_modules/@comis/shared/dist/mcp-tool-name.js +92 -0
- package/node_modules/@comis/shared/dist/silent-tokens.d.ts +38 -0
- package/node_modules/@comis/shared/dist/silent-tokens.js +51 -0
- package/node_modules/@comis/shared/dist/visible-delivery.d.ts +28 -0
- package/node_modules/@comis/shared/dist/visible-delivery.js +16 -0
- package/node_modules/@comis/shared/package.json +1 -1
- package/node_modules/@comis/skills/dist/bridge/mcp-tool-bridge.d.ts +2 -13
- package/node_modules/@comis/skills/dist/bridge/mcp-tool-bridge.js +3 -21
- package/node_modules/@comis/skills/dist/bridge/tool-metadata-enforcement.js +1 -1
- package/node_modules/@comis/skills/dist/bridge/tool-metadata-registry.js +4 -4
- package/node_modules/@comis/skills/dist/builtin/exec-tool.d.ts +55 -9
- package/node_modules/@comis/skills/dist/builtin/exec-tool.js +383 -19
- package/node_modules/@comis/skills/dist/builtin/install-detour.d.ts +67 -0
- package/node_modules/@comis/skills/dist/builtin/install-detour.js +342 -0
- package/node_modules/@comis/skills/dist/builtin/platform/admin-manage-factory.js +5 -5
- package/node_modules/@comis/skills/dist/builtin/platform/agents-manage-tool.d.ts +2 -2
- package/node_modules/@comis/skills/dist/builtin/platform/agents-manage-tool.js +2 -2
- package/node_modules/@comis/skills/dist/builtin/platform/message-tool.js +18 -0
- package/node_modules/@comis/skills/dist/builtin/platform/messaging-factory.d.ts +18 -1
- package/node_modules/@comis/skills/dist/builtin/platform/messaging-factory.js +18 -2
- package/node_modules/@comis/skills/dist/builtin/platform/models-manage-tool.js +3 -3
- package/node_modules/@comis/skills/dist/builtin/process-registry.d.ts +14 -0
- package/node_modules/@comis/skills/dist/builtin/process-tool.d.ts +24 -4
- package/node_modules/@comis/skills/dist/builtin/process-tool.js +25 -7
- package/node_modules/@comis/skills/dist/builtin/sandbox/bwrap-provider.d.ts +1 -1
- package/node_modules/@comis/skills/dist/builtin/sandbox/bwrap-provider.js +9 -0
- package/node_modules/@comis/skills/dist/index.d.ts +4 -1
- package/node_modules/@comis/skills/dist/index.js +3 -1
- package/node_modules/@comis/skills/dist/manifest/capability-parser.d.ts +44 -0
- package/node_modules/@comis/skills/dist/manifest/capability-parser.js +68 -0
- package/node_modules/@comis/skills/dist/manifest/schema.d.ts +44 -37
- package/node_modules/@comis/skills/dist/manifest/schema.js +35 -0
- package/node_modules/@comis/skills/dist/registry/discovery.d.ts +8 -0
- package/node_modules/@comis/skills/dist/registry/discovery.js +10 -3
- package/node_modules/@comis/skills/dist/registry/skill-registry.d.ts +45 -1
- package/node_modules/@comis/skills/dist/registry/skill-registry.js +70 -7
- package/node_modules/@comis/skills/package.json +1 -1
- package/node_modules/@comis/web/package.json +1 -1
- package/package.json +21 -21
|
@@ -4,8 +4,36 @@
|
|
|
4
4
|
*/
|
|
5
5
|
/** Model size tier — determines prompt verbosity for tool descriptions. */
|
|
6
6
|
export type ModelTier = "small" | "medium" | "large";
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Build the static `## Available Tools` block (legacy path, gate-off) OR a
|
|
9
|
+
* single residual one-liner pointing the model at the per-turn `## Capabilities`
|
|
10
|
+
* block (gate-on path).
|
|
11
|
+
*
|
|
12
|
+
* @param capabilityIndexEnabled - When `true`, emits ONLY the residual
|
|
13
|
+
* one-liner. When `false` or undefined, emits the legacy flat block
|
|
14
|
+
* BYTE-IDENTICALLY to the pre-feature baseline. The two paths are MUTUALLY
|
|
15
|
+
* EXCLUSIVE.
|
|
16
|
+
*
|
|
17
|
+
* Restart-required: this gate selects between two cached system-prompt
|
|
18
|
+
* shapes; toggling at runtime is forbidden. Operator-facing constraint is
|
|
19
|
+
* documented in config docs.
|
|
20
|
+
*/
|
|
21
|
+
export declare function buildToolingSection(toolNames: string[], _modelTier: ModelTier, toolSummaries?: Record<string, string>, capabilityIndexEnabled?: boolean): string[];
|
|
22
|
+
/**
|
|
23
|
+
* Build the static "## Tool Call Style" section with conditional coding guidelines.
|
|
24
|
+
*
|
|
25
|
+
* @param capabilityIndexEnabled - When `true`, AND when `exec` is in
|
|
26
|
+
* `toolNames`, the rendered output includes the dual-gated "Tool-first
|
|
27
|
+
* principle" bullet immediately before the existing Python-virtualenv rule.
|
|
28
|
+
* When `false` or `undefined`, the bullet is omitted; the existing venv
|
|
29
|
+
* rule emits unchanged when `exec` is present.
|
|
30
|
+
*
|
|
31
|
+
* Restart-required: the gate value flows from `tooling.capabilityIndex.enabled`
|
|
32
|
+
* via `AssemblerParams.capabilityIndexEnabled`, populated at the prompt
|
|
33
|
+
* assembly site from `port.isCapabilityIndexEnabled()`. The value is
|
|
34
|
+
* config-derived and stable per session — SAFE inside the cache fence.
|
|
35
|
+
*/
|
|
36
|
+
export declare function buildToolCallStyleSection(isMinimal: boolean, toolNames?: string[], capabilityIndexEnabled?: boolean): string[];
|
|
9
37
|
/** Tool names that trigger the confirmation flow / self-update gating section. */
|
|
10
38
|
export declare const CONFIRMATION_TOOL_NAMES: string[];
|
|
11
39
|
/**
|
|
@@ -5,9 +5,36 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { TOOL_SUMMARIES, TOOL_ORDER } from "./tool-descriptions.js";
|
|
7
7
|
import { getProviders } from "@mariozechner/pi-ai";
|
|
8
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Build the static `## Available Tools` block (legacy path, gate-off) OR a
|
|
10
|
+
* single residual one-liner pointing the model at the per-turn `## Capabilities`
|
|
11
|
+
* block (gate-on path).
|
|
12
|
+
*
|
|
13
|
+
* @param capabilityIndexEnabled - When `true`, emits ONLY the residual
|
|
14
|
+
* one-liner. When `false` or undefined, emits the legacy flat block
|
|
15
|
+
* BYTE-IDENTICALLY to the pre-feature baseline. The two paths are MUTUALLY
|
|
16
|
+
* EXCLUSIVE.
|
|
17
|
+
*
|
|
18
|
+
* Restart-required: this gate selects between two cached system-prompt
|
|
19
|
+
* shapes; toggling at runtime is forbidden. Operator-facing constraint is
|
|
20
|
+
* documented in config docs.
|
|
21
|
+
*/
|
|
22
|
+
export function buildToolingSection(toolNames, _modelTier, toolSummaries, capabilityIndexEnabled) {
|
|
9
23
|
if (toolNames.length === 0)
|
|
10
24
|
return [];
|
|
25
|
+
// Gate-on path: residual one-liner only. The per-turn `## Capabilities`
|
|
26
|
+
// block is rendered into the dynamic preamble by `executor-prompt-runner.ts`.
|
|
27
|
+
// The wording below is normative.
|
|
28
|
+
if (capabilityIndexEnabled === true) {
|
|
29
|
+
return [
|
|
30
|
+
"When this turn includes a `Capabilities` context, refer to it for grouped tool guidance " +
|
|
31
|
+
"before invoking tools or running installs. Tool schemas in your active toolspace are " +
|
|
32
|
+
"authoritative for parameter shapes.",
|
|
33
|
+
];
|
|
34
|
+
}
|
|
35
|
+
// Gate-off path: legacy flat block BYTE-IDENTICAL to pre-feature baseline.
|
|
36
|
+
// DO NOT modify the body below — the byte-identity assertion in
|
|
37
|
+
// tooling-sections.test.ts depends on this shape staying exact.
|
|
11
38
|
const summaries = { ...TOOL_SUMMARIES, ...toolSummaries };
|
|
12
39
|
const ordered = TOOL_ORDER.filter((t) => toolNames.includes(t));
|
|
13
40
|
const extras = toolNames.filter((t) => !TOOL_ORDER.includes(t)).sort();
|
|
@@ -23,7 +50,21 @@ export function buildToolingSection(toolNames, _modelTier, toolSummaries) {
|
|
|
23
50
|
// ---------------------------------------------------------------------------
|
|
24
51
|
// 4. Tool Call Style (skip if minimal)
|
|
25
52
|
// ---------------------------------------------------------------------------
|
|
26
|
-
|
|
53
|
+
/**
|
|
54
|
+
* Build the static "## Tool Call Style" section with conditional coding guidelines.
|
|
55
|
+
*
|
|
56
|
+
* @param capabilityIndexEnabled - When `true`, AND when `exec` is in
|
|
57
|
+
* `toolNames`, the rendered output includes the dual-gated "Tool-first
|
|
58
|
+
* principle" bullet immediately before the existing Python-virtualenv rule.
|
|
59
|
+
* When `false` or `undefined`, the bullet is omitted; the existing venv
|
|
60
|
+
* rule emits unchanged when `exec` is present.
|
|
61
|
+
*
|
|
62
|
+
* Restart-required: the gate value flows from `tooling.capabilityIndex.enabled`
|
|
63
|
+
* via `AssemblerParams.capabilityIndexEnabled`, populated at the prompt
|
|
64
|
+
* assembly site from `port.isCapabilityIndexEnabled()`. The value is
|
|
65
|
+
* config-derived and stable per session — SAFE inside the cache fence.
|
|
66
|
+
*/
|
|
67
|
+
export function buildToolCallStyleSection(isMinimal, toolNames = [], capabilityIndexEnabled) {
|
|
27
68
|
if (isMinimal)
|
|
28
69
|
return [];
|
|
29
70
|
const lines = [
|
|
@@ -64,6 +105,14 @@ export function buildToolCallStyleSection(isMinimal, toolNames = []) {
|
|
|
64
105
|
guidelines.push("- Show file paths clearly when working with files.");
|
|
65
106
|
}
|
|
66
107
|
if (has("exec")) {
|
|
108
|
+
// Dual-gated counterweight to the venv rule below. The bullet precedes
|
|
109
|
+
// the venv rule because the first read sets the default; the second is
|
|
110
|
+
// the install fallback. Restart-required: capabilityIndexEnabled flows
|
|
111
|
+
// from `tooling.capabilityIndex.enabled` via AssemblerParams →
|
|
112
|
+
// SECTIONS["tool-call-style"].
|
|
113
|
+
if (capabilityIndexEnabled === true) {
|
|
114
|
+
guidelines.push("- **Tool-first principle.** When this turn includes a `Capabilities` context and the task can be satisfied by a connected tool or available skill, prefer that capability over installing a Python or Node package. Use installs only for capabilities not covered by active tools, deferred tools, or visible prompt skills.");
|
|
115
|
+
}
|
|
67
116
|
guidelines.push("- **Python projects:** Always create a virtualenv per project (`python3 -m venv .venv`). "
|
|
68
117
|
+ "Install packages into the project venv (`source .venv/bin/activate && pip install ...`). "
|
|
69
118
|
+ "Never use `--break-system-packages` — it pollutes the system Python. "
|
|
@@ -79,6 +79,28 @@ export interface AssemblerParams {
|
|
|
79
79
|
excludeBootstrapFromContext?: boolean;
|
|
80
80
|
/** Workspace profile controlling platform instruction verbosity ('full' or 'specialist'). */
|
|
81
81
|
workspaceProfile?: "full" | "specialist";
|
|
82
|
+
/**
|
|
83
|
+
* Capability index gate.
|
|
84
|
+
*
|
|
85
|
+
* When `true`, `buildToolingSection` emits the residual one-liner instead
|
|
86
|
+
* of the legacy `## Available Tools` flat block; the per-turn
|
|
87
|
+
* `## Capabilities` block is rendered into the dynamic preamble in
|
|
88
|
+
* `executor-prompt-runner.ts`.
|
|
89
|
+
* When `false` or `undefined`, the static prompt is byte-identical to
|
|
90
|
+
* the pre-feature baseline.
|
|
91
|
+
*
|
|
92
|
+
* RESTART-REQUIRED: this flag selects between two cached system-prompt
|
|
93
|
+
* shapes. Daemon wiring documents the operator-facing constraint.
|
|
94
|
+
*
|
|
95
|
+
* SAFE INSIDE THE CACHE FENCE: this value is config-derived
|
|
96
|
+
* (operator-only, restart-required) and stable across all turns of a
|
|
97
|
+
* session. Plumbing it through `assemblerParams` does NOT create a
|
|
98
|
+
* cache-thrash regression. Live-runtime accessors
|
|
99
|
+
* (getPromptSkillCapabilities, getConnectedMcpServers) are forbidden
|
|
100
|
+
* inside this interface and enforced by an architecture-grep test.
|
|
101
|
+
* Adding a config-derived flag to the cache fence is safe.
|
|
102
|
+
*/
|
|
103
|
+
capabilityIndexEnabled?: boolean;
|
|
82
104
|
/** Whether Silent Execution Planner (SEP) is enabled for this agent. */
|
|
83
105
|
sepEnabled?: boolean;
|
|
84
106
|
}
|
|
@@ -82,8 +82,8 @@ export const SECTIONS = [
|
|
|
82
82
|
{ id: "safety", includeIn: MODES_ALL, build: (p, m) => buildSafetySection(m === "minimal") },
|
|
83
83
|
{ id: "language", includeIn: MODES_ALL, build: (p) => buildLanguageSection(p.userLanguage) },
|
|
84
84
|
// --- Semi-stable body: operational-kept sections (MODES_ALL -- builders self-filter for minimal) ---
|
|
85
|
-
{ id: "tooling", includeIn: MODES_ALL, build: (p, m) => buildToolingSection(p.toolNames ?? [], m === "minimal" ? "small" : "large", p.toolSummaries) },
|
|
86
|
-
{ id: "tool-call-style", includeIn: MODES_ALL, build: (p, m) => buildToolCallStyleSection(m === "minimal", p.toolNames ?? []) },
|
|
85
|
+
{ id: "tooling", includeIn: MODES_ALL, build: (p, m) => buildToolingSection(p.toolNames ?? [], m === "minimal" ? "small" : "large", p.toolSummaries, p.capabilityIndexEnabled) },
|
|
86
|
+
{ id: "tool-call-style", includeIn: MODES_ALL, build: (p, m) => buildToolCallStyleSection(m === "minimal", p.toolNames ?? [], p.capabilityIndexEnabled) },
|
|
87
87
|
// --- Operational-stripped sections (MODES_FULL_MIN -- dropped in "operational") ---
|
|
88
88
|
{ id: "self-update", includeIn: MODES_FULL_MIN, build: (p, m) => buildSelfUpdateGatingSection(p.toolNames ?? [], m === "minimal", true) },
|
|
89
89
|
{ id: "config-secret", includeIn: MODES_FULL_MIN, build: (p, m) => buildConfigSecretIntegritySection(p.toolNames ?? [], m === "minimal") },
|
|
@@ -10,11 +10,7 @@
|
|
|
10
10
|
*
|
|
11
11
|
* @module
|
|
12
12
|
*/
|
|
13
|
-
|
|
14
|
-
* Extract the MCP server name from a sanitized tool name.
|
|
15
|
-
* Format: `mcp__serverName--toolName`. Returns undefined for non-MCP tools.
|
|
16
|
-
*/
|
|
17
|
-
export declare function extractMcpServerName(toolName: string): string | undefined;
|
|
13
|
+
export { extractMcpServerName } from "@comis/shared";
|
|
18
14
|
/**
|
|
19
15
|
* Classify an MCP error message into a category for observability.
|
|
20
16
|
*/
|
|
@@ -13,21 +13,9 @@
|
|
|
13
13
|
*/
|
|
14
14
|
// ---------------------------------------------------------------------------
|
|
15
15
|
// MCP attribution helpers
|
|
16
|
-
//
|
|
16
|
+
// Re-exported from @comis/shared (canonical home).
|
|
17
17
|
// ---------------------------------------------------------------------------
|
|
18
|
-
|
|
19
|
-
* Extract the MCP server name from a sanitized tool name.
|
|
20
|
-
* Format: `mcp__serverName--toolName`. Returns undefined for non-MCP tools.
|
|
21
|
-
*/
|
|
22
|
-
export function extractMcpServerName(toolName) {
|
|
23
|
-
if (!toolName.startsWith("mcp__"))
|
|
24
|
-
return undefined;
|
|
25
|
-
const rest = toolName.slice(5);
|
|
26
|
-
const sepIdx = rest.indexOf("--");
|
|
27
|
-
if (sepIdx <= 0)
|
|
28
|
-
return undefined;
|
|
29
|
-
return rest.slice(0, sepIdx);
|
|
30
|
-
}
|
|
18
|
+
export { extractMcpServerName } from "@comis/shared";
|
|
31
19
|
/**
|
|
32
20
|
* Classify an MCP error message into a category for observability.
|
|
33
21
|
*/
|
|
@@ -26,6 +26,16 @@ export interface BridgeMetricsState {
|
|
|
26
26
|
lastContextUsage: ContextUsageData | undefined;
|
|
27
27
|
textEmitted: boolean;
|
|
28
28
|
lastLlmErrorMessage: string | undefined;
|
|
29
|
+
/** Per-turn capture of outbound delivery events. Populated by pi-event-bridge
|
|
30
|
+
* on tool_execution_end for `message(action='send'|'reply'|'attach')`.
|
|
31
|
+
* Read by executor-post-execution.ts to make sentinel-aware decisions.
|
|
32
|
+
* Reset at turn start. */
|
|
33
|
+
outboundLog: Array<{
|
|
34
|
+
action: string;
|
|
35
|
+
channelType: string;
|
|
36
|
+
channelId: string;
|
|
37
|
+
timestamp: number;
|
|
38
|
+
}>;
|
|
29
39
|
toolStartTimes: Map<string, number>;
|
|
30
40
|
toolCallHistory: string[];
|
|
31
41
|
lastActiveToolName: string | undefined;
|
|
@@ -75,6 +85,22 @@ export interface BridgeMetricsState {
|
|
|
75
85
|
/** Total tool calls across all signature-replay scrubs whose thoughtSignature
|
|
76
86
|
* was stripped (post-incident-visibility metric). */
|
|
77
87
|
signatureScrubsToolCallsAffected: number;
|
|
88
|
+
/**
|
|
89
|
+
* Per-composite-key drain inflight gate. Owned by the bridge; passed into
|
|
90
|
+
* `drainAt(...)` at the `tool_execution_end` call site (inline-consumption +
|
|
91
|
+
* composite drain).
|
|
92
|
+
*
|
|
93
|
+
* Map keyed by `${agentId}:${channelType}:${channelId}` (composite key).
|
|
94
|
+
* Concurrent calls for the SAME composite key return immediately
|
|
95
|
+
* (single-tick gate). Concurrent calls for DIFFERENT composite keys drain
|
|
96
|
+
* independently (multi-agent isolation).
|
|
97
|
+
*
|
|
98
|
+
* Entry cleanup: `.delete(formatted)` runs in `.finally(...)` of the
|
|
99
|
+
* drain promise so the Map size remains bounded across long-running
|
|
100
|
+
* sessions (entry removed within one event-loop tick of drain
|
|
101
|
+
* resolution).
|
|
102
|
+
*/
|
|
103
|
+
drainInflightByKey: Map<string, Promise<void>>;
|
|
78
104
|
}
|
|
79
105
|
/**
|
|
80
106
|
* Create a fresh metrics state with all counters zeroed.
|
|
@@ -29,6 +29,7 @@ export function createBridgeMetrics() {
|
|
|
29
29
|
lastContextUsage: undefined,
|
|
30
30
|
textEmitted: false,
|
|
31
31
|
lastLlmErrorMessage: undefined,
|
|
32
|
+
outboundLog: [],
|
|
32
33
|
toolStartTimes: new Map(),
|
|
33
34
|
toolCallHistory: [],
|
|
34
35
|
lastActiveToolName: undefined,
|
|
@@ -58,6 +59,8 @@ export function createBridgeMetrics() {
|
|
|
58
59
|
hashAssertionMismatches: 0,
|
|
59
60
|
signatureScrubs: 0,
|
|
60
61
|
signatureScrubsToolCallsAffected: 0,
|
|
62
|
+
// per-composite-key drain inflight gate.
|
|
63
|
+
drainInflightByKey: new Map(),
|
|
61
64
|
};
|
|
62
65
|
}
|
|
63
66
|
/**
|
|
@@ -20,6 +20,7 @@ import type { ProviderHealthMonitor } from "../safety/provider-health-monitor.js
|
|
|
20
20
|
import type { ContextWindowGuard, ContextUsageData } from "../safety/context-window-guard.js";
|
|
21
21
|
import type { ExecutionResult } from "../executor/types.js";
|
|
22
22
|
import type { ExecutionPlan } from "../planner/types.js";
|
|
23
|
+
import { type DrainInflightState } from "../executor/drain-helper.js";
|
|
23
24
|
import { type ThinkingBlockHash } from "./thinking-block-hash-invariant.js";
|
|
24
25
|
/** Per-call TTL split estimate, populated by requestBodyInjector's onPayload.
|
|
25
26
|
* Shared mutable object — written by the stream wrapper, read by the bridge. */
|
|
@@ -203,6 +204,14 @@ export interface PiEventBridgeResult {
|
|
|
203
204
|
hashes: ReadonlyMap<string, ReadonlyArray<ThinkingBlockHash>>;
|
|
204
205
|
canonical: ReadonlyMap<string, ReadonlyArray<unknown>>;
|
|
205
206
|
};
|
|
207
|
+
/**
|
|
208
|
+
* Expose the bridge-owned drain inflight gate so executor-post-execution
|
|
209
|
+
* can fire an end-of-turn backstop drainAt sharing the same composite-key
|
|
210
|
+
* gate map. Returns the live `BridgeMetricsState` slice -- callers MUST
|
|
211
|
+
* treat this as read-mostly (the only mutation contract is `drainAt`
|
|
212
|
+
* adding/removing entries).
|
|
213
|
+
*/
|
|
214
|
+
getDrainState: () => DrainInflightState;
|
|
206
215
|
}
|
|
207
216
|
export { sanitizeToolArgs, extractErrorText } from "./bridge-event-handlers.js";
|
|
208
217
|
/**
|
|
@@ -18,8 +18,10 @@ import { getCacheProviderInfo } from "../executor/cache-usage-helpers.js";
|
|
|
18
18
|
import { sanitizeMcpToolNameForAnalytics } from "../executor/cache-break-detection.js";
|
|
19
19
|
import { classifyError } from "../executor/error-classifier.js";
|
|
20
20
|
import { extractPlanFromResponse } from "../planner/plan-extractor.js";
|
|
21
|
-
import { extractMcpServerName
|
|
21
|
+
import { extractMcpServerName } from "@comis/shared";
|
|
22
|
+
import { classifyMcpErrorType, sanitizeToolArgs, extractErrorText } from "./bridge-event-handlers.js";
|
|
22
23
|
import { createBridgeMetrics, buildBridgeResult } from "./bridge-metrics.js";
|
|
24
|
+
import { drainAt } from "../executor/drain-helper.js";
|
|
23
25
|
import { checkStepLimit, emitStepLimitAbort, checkBudgetLimit, emitBudgetAbort, checkBudgetTrajectory, checkContextWindow, emitContextAbort, checkCircuitBreaker, emitCircuitBreakerAbort } from "./bridge-safety-controls.js";
|
|
24
26
|
import { computeThinkingBlockHashes, diffThinkingBlocksAgainstPersisted, WIRE_DIFF_HINT_FILE_MISSING, WIRE_DIFF_HINT_NOT_FOUND, } from "./thinking-block-hash-invariant.js";
|
|
25
27
|
// Re-export helper functions for backward compatibility with existing imports
|
|
@@ -171,6 +173,62 @@ export function createPiEventBridge(deps) {
|
|
|
171
173
|
durationMs,
|
|
172
174
|
...(errorText && { errorText }),
|
|
173
175
|
});
|
|
176
|
+
// Capture outbound deliveries. The post-execution silent-sentinel
|
|
177
|
+
// gate reads this per-turn log to make sentinel-aware decisions
|
|
178
|
+
// about paired memory persistence. Reset at turn_start; bounded by
|
|
179
|
+
// per-turn outbound message count.
|
|
180
|
+
//
|
|
181
|
+
// On the SAME tool_execution_end event, fire
|
|
182
|
+
// `drainAt({agentId, channelType, channelId})` (the composite-keyed
|
|
183
|
+
// inline-consumption drain). The gate state lives in bridge-metrics
|
|
184
|
+
// (`m.drainInflightByKey`) so concurrent drains for the same
|
|
185
|
+
// composite key collapse to a single in-flight Promise; concurrent
|
|
186
|
+
// drains for different composite keys (multi-agent) run
|
|
187
|
+
// independently. Failures inside drainAt are suppressed with WARN
|
|
188
|
+
// logging -- the bridge's tool_execution_end propagation is NEVER
|
|
189
|
+
// aborted by drain misbehavior.
|
|
190
|
+
if (endEvent.toolName === "message" && toolSuccess && sanitizedArgs) {
|
|
191
|
+
const action = typeof sanitizedArgs.action === "string" ? sanitizedArgs.action : "";
|
|
192
|
+
if (action === "send" || action === "reply" || action === "attach") {
|
|
193
|
+
const channelType = typeof sanitizedArgs.channel_type === "string" ? sanitizedArgs.channel_type : "";
|
|
194
|
+
const channelId = typeof sanitizedArgs.channel_id === "string" ? sanitizedArgs.channel_id : "";
|
|
195
|
+
m.outboundLog.push({
|
|
196
|
+
action,
|
|
197
|
+
channelType,
|
|
198
|
+
channelId,
|
|
199
|
+
timestamp: Date.now(),
|
|
200
|
+
});
|
|
201
|
+
// Composite-key drain at the bridge call site. The composite
|
|
202
|
+
// (agentId, channelType, channelId) prevents cross-agent
|
|
203
|
+
// contamination of the inline-consumption queue. Use the
|
|
204
|
+
// message tool's own channel_type / channel_id when present
|
|
205
|
+
// (the tool resolved them); fall back to the bridge's bound
|
|
206
|
+
// deps.channelId when the tool args were sanitized away
|
|
207
|
+
// (defensive). A drain trigger with empty channelType OR empty
|
|
208
|
+
// channelId is skipped -- formatDrainKey would otherwise
|
|
209
|
+
// produce ambiguous keys.
|
|
210
|
+
//
|
|
211
|
+
// drainAt is fire-and-forget: it spawns the drain Promise and
|
|
212
|
+
// wraps it in suppressError internally. The kickoffDrain
|
|
213
|
+
// wrapper below double-wraps the synchronous invocation in
|
|
214
|
+
// suppressError (Promise.resolve adapter) so a (impossible)
|
|
215
|
+
// synchronous throw inside drainAt cannot abort the bridge's
|
|
216
|
+
// tool_execution_end propagation -- fire-and-forget contract /
|
|
217
|
+
// non-fatal drain failure.
|
|
218
|
+
const drainChannelType = channelType.length > 0 ? channelType : "";
|
|
219
|
+
const drainChannelId = channelId.length > 0 ? channelId : deps.channelId;
|
|
220
|
+
if (drainChannelType.length > 0 && drainChannelId.length > 0) {
|
|
221
|
+
const kickoffDrain = Promise.resolve().then(() => {
|
|
222
|
+
drainAt({
|
|
223
|
+
agentId: deps.agentId,
|
|
224
|
+
channelType: drainChannelType,
|
|
225
|
+
channelId: drainChannelId,
|
|
226
|
+
}, { drainInflightByKey: m.drainInflightByKey }, deps.logger);
|
|
227
|
+
});
|
|
228
|
+
suppressError(kickoffDrain, "bridge tool_use_complete drainAt kickoff");
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
174
232
|
// Look up truncation metadata from stream wrapper registry
|
|
175
233
|
const truncMeta = deps.getTruncationMeta?.(endEvent.toolCallId);
|
|
176
234
|
deps.eventBus.emit("tool:executed", {
|
|
@@ -222,6 +280,10 @@ export function createPiEventBridge(deps) {
|
|
|
222
280
|
// LLM turn about to start (pre-serialize hook for assert+restore)
|
|
223
281
|
// -----------------------------------------------------------------
|
|
224
282
|
case "turn_start": {
|
|
283
|
+
// Reset per-turn outbound capture. The log accumulates
|
|
284
|
+
// message(send/reply/attach) calls across the turn so the
|
|
285
|
+
// post-execution gate can make sentinel-aware decisions.
|
|
286
|
+
m.outboundLog.length = 0;
|
|
225
287
|
// Run the executor-supplied pre-call closure once per turn, before
|
|
226
288
|
// pi-ai reads `session.agent.state.messages` to serialize the next
|
|
227
289
|
// API request. The closure performs the assert-then-restore pass
|
|
@@ -1050,5 +1112,14 @@ export function createPiEventBridge(deps) {
|
|
|
1050
1112
|
hashes: m.thinkingBlockHashes,
|
|
1051
1113
|
canonical: m.thinkingBlockCanonical,
|
|
1052
1114
|
});
|
|
1053
|
-
|
|
1115
|
+
// Expose the per-composite-key drain inflight gate so executor-post-
|
|
1116
|
+
// execution can fire an end-of-turn backstop drainAt that shares the SAME
|
|
1117
|
+
// gate map as the bridge's tool_execution_end call site. The returned
|
|
1118
|
+
// object has a live reference to the underlying Map -- mutations from the
|
|
1119
|
+
// bridge AND the executor post-execution path land in the same state
|
|
1120
|
+
// container, satisfying the single-tick gate contract.
|
|
1121
|
+
const getDrainState = () => ({
|
|
1122
|
+
drainInflightByKey: m.drainInflightByKey,
|
|
1123
|
+
});
|
|
1124
|
+
return { listener, getResult, addGhostCost, getThinkingBlockStores, getDrainState };
|
|
1054
1125
|
}
|
|
@@ -21,16 +21,16 @@
|
|
|
21
21
|
* plain text rather than sending sanitized-text + original-signature
|
|
22
22
|
* mismatch. Skips `redacted: true` blocks (no readable text to taint).
|
|
23
23
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
24
|
+
* cacheFenceIndex is intentionally NOT consulted to gate guarding. The
|
|
25
|
+
* guard is pure/deterministic — input messages → same guarded output every
|
|
26
|
+
* time — so iter 1 strips, Anthropic caches the guarded prefix, iter 2
|
|
27
|
+
* strips identically, and the cache hits. The prior fence-skip caused
|
|
28
|
+
* per-execution divergence symmetric to the bug found in
|
|
29
|
+
* `signature-replay-scrubber.ts` and `thinking-block-cleaner.ts`: iter 1
|
|
30
|
+
* stripped (fence=-1) and built a surrogate-safe cached prefix, iter 2
|
|
31
|
+
* preserved fence-protected messages (fence>0) and re-introduced
|
|
32
|
+
* surrogate-tainted-with-original-signature blocks at positions Anthropic
|
|
33
|
+
* had cached without them.
|
|
34
34
|
*
|
|
35
35
|
* Immutability: never mutates input; shallow-copies the block and the
|
|
36
36
|
* containing message only when scrubbing is needed. When no scrub fires,
|
|
@@ -22,16 +22,16 @@
|
|
|
22
22
|
* plain text rather than sending sanitized-text + original-signature
|
|
23
23
|
* mismatch. Skips `redacted: true` blocks (no readable text to taint).
|
|
24
24
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
25
|
+
* cacheFenceIndex is intentionally NOT consulted to gate guarding. The
|
|
26
|
+
* guard is pure/deterministic — input messages → same guarded output every
|
|
27
|
+
* time — so iter 1 strips, Anthropic caches the guarded prefix, iter 2
|
|
28
|
+
* strips identically, and the cache hits. The prior fence-skip caused
|
|
29
|
+
* per-execution divergence symmetric to the bug found in
|
|
30
|
+
* `signature-replay-scrubber.ts` and `thinking-block-cleaner.ts`: iter 1
|
|
31
|
+
* stripped (fence=-1) and built a surrogate-safe cached prefix, iter 2
|
|
32
|
+
* preserved fence-protected messages (fence>0) and re-introduced
|
|
33
|
+
* surrogate-tainted-with-original-signature blocks at positions Anthropic
|
|
34
|
+
* had cached without them.
|
|
35
35
|
*
|
|
36
36
|
* Immutability: never mutates input; shallow-copies the block and the
|
|
37
37
|
* containing message only when scrubbing is needed. When no scrub fires,
|
|
@@ -69,10 +69,10 @@ export function createSignatureSurrogateGuard(deps) {
|
|
|
69
69
|
for (let i = 0; i < messages.length; i++) {
|
|
70
70
|
// eslint-disable-next-line security/detect-object-injection -- numeric index
|
|
71
71
|
const original = messages[i];
|
|
72
|
-
//
|
|
73
|
-
//
|
|
74
|
-
//
|
|
75
|
-
//
|
|
72
|
+
// cacheFenceIndex is intentionally NOT consulted here. Stripping
|
|
73
|
+
// uniformly across the array keeps the guarded prefix identical
|
|
74
|
+
// across iterations of the same execution, which is what
|
|
75
|
+
// Anthropic's prompt-cache validator requires.
|
|
76
76
|
const msg = original;
|
|
77
77
|
if (msg.role !== "assistant" || !Array.isArray(msg.content)) {
|
|
78
78
|
// eslint-disable-next-line security/detect-object-injection -- numeric index
|
|
@@ -5,17 +5,16 @@
|
|
|
5
5
|
* keep-window, measured in assistant turns (not turn pairs). Redacted thinking
|
|
6
6
|
* blocks (containing encrypted signatures for API continuity) are always preserved.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* stats only and never gates the strip decision.
|
|
8
|
+
* cacheFenceIndex is intentionally NOT consulted to gate stripping. The
|
|
9
|
+
* cleaner is pure/deterministic — input messages → same cleaned output
|
|
10
|
+
* every time — so iteration 1 strips, Anthropic caches the cleaned prefix,
|
|
11
|
+
* iteration 2 strips identically, and the cache hits. The prior fence-skip
|
|
12
|
+
* caused per-execution divergence: iter 1 stripped (fence=-1) and built a
|
|
13
|
+
* thinking-free cached prefix, iter 2 preserved fence-protected messages
|
|
14
|
+
* (fence>0) and re-introduced thinking blocks at positions Anthropic had
|
|
15
|
+
* cached without them, which the prompt-cache validator rejected with
|
|
16
|
+
* `400 ... blocks cannot be modified`. The cacheFenceIndex on the budget
|
|
17
|
+
* is read for diagnostic stats only and never gates the strip decision.
|
|
19
18
|
*
|
|
20
19
|
* Immutability: never mutates input messages or arrays. Returns new arrays and
|
|
21
20
|
* shallow-copied messages only when changes are needed. When no changes are
|
|
@@ -39,8 +38,7 @@ import type { ContextLayer } from "./types.js";
|
|
|
39
38
|
export declare function createThinkingBlockCleaner(keepTurns: number, onCleaned?: (stats: {
|
|
40
39
|
blocksRemoved: number;
|
|
41
40
|
/** Cache fence index when present on the budget; reported for diagnostics
|
|
42
|
-
* only. Stripping is no longer gated on the fence
|
|
43
|
-
* thinking-block). */
|
|
41
|
+
* only. Stripping is no longer gated on the fence. */
|
|
44
42
|
cacheFenceIndex?: number;
|
|
45
43
|
/** Number of messages protected by the cache fence. Always undefined now
|
|
46
44
|
* because the fence does not protect any messages from stripping. */
|
|
@@ -6,17 +6,16 @@
|
|
|
6
6
|
* keep-window, measured in assistant turns (not turn pairs). Redacted thinking
|
|
7
7
|
* blocks (containing encrypted signatures for API continuity) are always preserved.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* stats only and never gates the strip decision.
|
|
9
|
+
* cacheFenceIndex is intentionally NOT consulted to gate stripping. The
|
|
10
|
+
* cleaner is pure/deterministic — input messages → same cleaned output
|
|
11
|
+
* every time — so iteration 1 strips, Anthropic caches the cleaned prefix,
|
|
12
|
+
* iteration 2 strips identically, and the cache hits. The prior fence-skip
|
|
13
|
+
* caused per-execution divergence: iter 1 stripped (fence=-1) and built a
|
|
14
|
+
* thinking-free cached prefix, iter 2 preserved fence-protected messages
|
|
15
|
+
* (fence>0) and re-introduced thinking blocks at positions Anthropic had
|
|
16
|
+
* cached without them, which the prompt-cache validator rejected with
|
|
17
|
+
* `400 ... blocks cannot be modified`. The cacheFenceIndex on the budget
|
|
18
|
+
* is read for diagnostic stats only and never gates the strip decision.
|
|
20
19
|
*
|
|
21
20
|
* Immutability: never mutates input messages or arrays. Returns new arrays and
|
|
22
21
|
* shallow-copied messages only when changes are needed. When no changes are
|
|
@@ -77,10 +76,10 @@ export function createThinkingBlockCleaner(keepTurns, onCleaned, getKeepTurnsOve
|
|
|
77
76
|
let blocksRemoved = 0;
|
|
78
77
|
const result = new Array(messages.length);
|
|
79
78
|
for (let i = 0; i < messages.length; i++) {
|
|
80
|
-
//
|
|
81
|
-
//
|
|
82
|
-
//
|
|
83
|
-
//
|
|
79
|
+
// cacheFenceIndex is intentionally NOT consulted here. Stripping
|
|
80
|
+
// uniformly across the array keeps the cleaned prefix identical
|
|
81
|
+
// across iterations of the same execution, which is what
|
|
82
|
+
// Anthropic's prompt-cache validator requires.
|
|
84
83
|
const msg = messages[i];
|
|
85
84
|
if (!oldAssistantIndices.has(i)) {
|
|
86
85
|
// Within keep-window or not an assistant message -- pass through unchanged
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-turn capability-index renderer.
|
|
3
|
+
*
|
|
4
|
+
* Renders the `## Capabilities` block for the dynamic preamble. Lives
|
|
5
|
+
* post-deferral in the executor lifecycle; consumes a `ToolCapabilityPort`
|
|
6
|
+
* for cluster/skill resolution and an `ExcludeDeferralResult` for active
|
|
7
|
+
* vs deferred tool partitioning.
|
|
8
|
+
*
|
|
9
|
+
* Pure-function builder: no logger, no IO, no `Result` envelope, no mutable
|
|
10
|
+
* module state beyond frozen module-level constants. Mirrors the shape of
|
|
11
|
+
* `buildDeferredToolsContext` in `tool-deferral.ts`.
|
|
12
|
+
*
|
|
13
|
+
* IMPORTANT -- cache fence:
|
|
14
|
+
* This module is consumed ONLY by `executor-tool-assembly.ts`. It MUST NOT
|
|
15
|
+
* be imported by `prompt-assembly.ts` -- the static prompt cache prefix MUST
|
|
16
|
+
* stay byte-identical when the skill registry reloads between turns.
|
|
17
|
+
* An architecture-grep enforces this invariant.
|
|
18
|
+
*
|
|
19
|
+
* @module
|
|
20
|
+
*/
|
|
21
|
+
import type { ToolCapabilityPort } from "@comis/core";
|
|
22
|
+
import type { ExcludeDeferralResult } from "./tool-deferral.js";
|
|
23
|
+
/**
|
|
24
|
+
* Output struct from {@link buildCapabilityIndexContext}. All counts are
|
|
25
|
+
* post-elision -- they reflect what the renderer surfaces, not the upstream
|
|
26
|
+
* input cardinality.
|
|
27
|
+
*/
|
|
28
|
+
export interface CapabilityIndexRenderResult {
|
|
29
|
+
/** Rendered text block. Empty string when the index is gated off or all-zero counts. */
|
|
30
|
+
readonly text: string;
|
|
31
|
+
/** Estimated tokens for the rendered text (`Math.ceil(text.length / CHARS_PER_TOKEN_RATIO)`). */
|
|
32
|
+
readonly capabilityIndexTokens: number;
|
|
33
|
+
/** Number of distinct clusters surfaced. */
|
|
34
|
+
readonly clusterCount: number;
|
|
35
|
+
/** Number of active tools (builtins + active MCP tools). */
|
|
36
|
+
readonly activeToolCount: number;
|
|
37
|
+
/** Number of deferred MCP tools after the orphan-drop (server connected). */
|
|
38
|
+
readonly deferredToolCount: number;
|
|
39
|
+
/** Number of visible eligible prompt skills (port-reported, not rendered count). */
|
|
40
|
+
readonly promptSkillCount: number;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Build the per-turn capability-index render result.
|
|
44
|
+
*
|
|
45
|
+
* Behavior:
|
|
46
|
+
* - Gate respect: returns {@link EMPTY} when `port.isCapabilityIndexEnabled()` is false.
|
|
47
|
+
* - Empty-input fast path: returns {@link EMPTY} when all three surface counts are zero.
|
|
48
|
+
* - Cluster bucketing: builtins -> `getBuiltinCluster()` (or `"other-tools"`),
|
|
49
|
+
* MCP -> `getMcpServerHint().cluster` (or `"external-integrations"`),
|
|
50
|
+
* skills -> `skill.cluster` (or `"prompt-skills"`).
|
|
51
|
+
* - Orphan-drop: deferred MCP tools whose server is not in the live
|
|
52
|
+
* `getConnectedMcpServers()` snapshot are dropped silently.
|
|
53
|
+
* - Sort: `(priority asc, clusterId asc)` for clusters; `TOOL_ORDER` for
|
|
54
|
+
* builtins (alphabetical fallback for unknowns); alphabetical for MCP
|
|
55
|
+
* servers and skills.
|
|
56
|
+
* - Per-group cap: 8 names + `+N more`.
|
|
57
|
+
* - >32 elision: drop ALL per-cluster name lists; keep headers + counts only.
|
|
58
|
+
* - Forbidden-literal discipline: the rendered text names neither the
|
|
59
|
+
* client-side discovery tool nor the server-side tool search regex tool.
|
|
60
|
+
* The deferred-tools preamble bullet uses the mechanism-neutral
|
|
61
|
+
* `"discovery mechanism available in your active toolspace"` wording.
|
|
62
|
+
* An architecture-grep enforces the file-level invariant.
|
|
63
|
+
*
|
|
64
|
+
* Restart-required note: `tooling.capabilityIndex.enabled` requires a daemon
|
|
65
|
+
* restart to take effect. The renderer respects the port's reported value at
|
|
66
|
+
* render time but does not enforce the restart constraint.
|
|
67
|
+
*
|
|
68
|
+
* @param deferralResult - Output of `applyToolDeferral` (active + deferred tool partition).
|
|
69
|
+
* @param port - The capability port (gate flag, cluster/skill resolution, live runtime view).
|
|
70
|
+
* @returns Frozen {@link CapabilityIndexRenderResult}; identity-stable {@link EMPTY} for the no-op path.
|
|
71
|
+
*/
|
|
72
|
+
export declare function buildCapabilityIndexContext(deferralResult: ExcludeDeferralResult, port: ToolCapabilityPort): CapabilityIndexRenderResult;
|