@vellumai/assistant 0.4.48 → 0.4.49
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/ARCHITECTURE.md +2 -2
- package/README.md +2 -23
- package/docs/architecture/integrations.md +45 -41
- package/docs/architecture/keychain-broker.md +3 -3
- package/docs/runbook-trusted-contacts.md +3 -8
- package/hook-templates/debug-prompt-logger/hook.json +1 -1
- package/hook-templates/debug-prompt-logger/run.sh +1 -3
- package/package.json +1 -1
- package/src/__tests__/actor-token-service.test.ts +0 -1
- package/src/__tests__/anthropic-provider.test.ts +156 -0
- package/src/__tests__/approval-cascade.test.ts +810 -0
- package/src/__tests__/approval-primitive.test.ts +0 -1
- package/src/__tests__/approval-routes-http.test.ts +2 -0
- package/src/__tests__/assistant-attachments.test.ts +12 -34
- package/src/__tests__/assistant-feature-flag-guardrails.test.ts +76 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +0 -1
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +2 -2
- package/src/__tests__/channel-guardian.test.ts +0 -2
- package/src/__tests__/channel-readiness-routes.test.ts +15 -6
- package/src/__tests__/channel-readiness-service.test.ts +10 -9
- package/src/__tests__/checker.test.ts +9 -29
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +1 -1
- package/src/__tests__/computer-use-tools.test.ts +2 -19
- package/src/__tests__/config-watcher.test.ts +0 -1
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
- package/src/__tests__/context-image-dimensions.test.ts +332 -0
- package/src/__tests__/context-token-estimator.test.ts +196 -13
- package/src/__tests__/conversation-attention-store.test.ts +0 -1
- package/src/__tests__/conversation-attention-telegram.test.ts +0 -1
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +144 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
- package/src/__tests__/credential-metadata-store.test.ts +64 -73
- package/src/__tests__/credential-security-invariants.test.ts +13 -7
- package/src/__tests__/credential-vault-unit.test.ts +280 -49
- package/src/__tests__/credential-vault.test.ts +138 -16
- package/src/__tests__/credentials-cli.test.ts +71 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
- package/src/__tests__/ephemeral-permissions.test.ts +3 -3
- package/src/__tests__/gateway-only-guard.test.ts +0 -1
- package/src/__tests__/guardian-action-grant-mint-consume.test.ts +0 -1
- package/src/__tests__/guardian-decision-primitive-canonical.test.ts +0 -1
- package/src/__tests__/guardian-routing-invariants.test.ts +0 -1
- package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -1
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +0 -39
- package/src/__tests__/heartbeat-service.test.ts +0 -1
- package/src/__tests__/host-cu-proxy.test.ts +629 -0
- package/src/__tests__/host-shell-tool.test.ts +27 -15
- package/src/__tests__/http-user-message-parity.test.ts +1 -0
- package/src/__tests__/ingress-url-consistency.test.ts +14 -21
- package/src/__tests__/integration-status.test.ts +32 -51
- package/src/__tests__/intent-routing.test.ts +0 -1
- package/src/__tests__/invite-routes-http.test.ts +10 -9
- package/src/__tests__/keychain-broker-client.test.ts +11 -43
- package/src/__tests__/notification-routing-intent.test.ts +0 -1
- package/src/__tests__/oauth-cli.test.ts +373 -14
- package/src/__tests__/oauth-provider-profiles.test.ts +9 -9
- package/src/__tests__/oauth-scope-policy.test.ts +4 -6
- package/src/__tests__/oauth-store.test.ts +756 -0
- package/src/__tests__/onboarding-starter-tasks.test.ts +0 -1
- package/src/__tests__/provider-error-scenarios.test.ts +0 -1
- package/src/__tests__/provider-streaming.benchmark.test.ts +0 -1
- package/src/__tests__/public-ingress-urls.test.ts +15 -21
- package/src/__tests__/recording-handler.test.ts +3 -4
- package/src/__tests__/registry.test.ts +2 -2
- package/src/__tests__/runtime-events-sse.test.ts +55 -7
- package/src/__tests__/schedule-store.test.ts +0 -1
- package/src/__tests__/scheduler-recurrence.test.ts +0 -1
- package/src/__tests__/scoped-approval-grants.test.ts +0 -1
- package/src/__tests__/scoped-grant-security-matrix.test.ts +0 -1
- package/src/__tests__/secret-ingress-handler.test.ts +0 -1
- package/src/__tests__/send-endpoint-busy.test.ts +21 -6
- package/src/__tests__/sequence-store.test.ts +0 -1
- package/src/__tests__/session-init.benchmark.test.ts +4 -5
- package/src/__tests__/skill-include-graph.test.ts +66 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +0 -1
- package/src/__tests__/skill-load-tool.test.ts +149 -1
- package/src/__tests__/skill-projection-feature-flag.test.ts +0 -1
- package/src/__tests__/skills-uninstall.test.ts +1 -1
- package/src/__tests__/skills.test.ts +3 -3
- package/src/__tests__/slack-channel-config.test.ts +67 -3
- package/src/__tests__/slack-share-routes.test.ts +17 -19
- package/src/__tests__/system-prompt.test.ts +0 -1
- package/src/__tests__/telegram-invite-adapter.test.ts +18 -22
- package/src/__tests__/terminal-tools.test.ts +4 -3
- package/src/__tests__/test-support/computer-use-skill-harness.ts +3 -2
- package/src/__tests__/tool-approval-handler.test.ts +0 -1
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -1
- package/src/__tests__/tool-executor-shell-integration.test.ts +0 -1
- package/src/__tests__/tool-executor.test.ts +0 -1
- package/src/__tests__/tool-grant-request-escalation.test.ts +0 -1
- package/src/__tests__/trust-store-pattern-matches.test.ts +29 -0
- package/src/__tests__/trust-store.test.ts +1 -22
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +0 -1
- package/src/__tests__/twilio-routes.test.ts +0 -16
- package/src/__tests__/verification-control-plane-policy.test.ts +0 -1
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +0 -1
- package/src/agent/ax-tree-compaction.test.ts +235 -0
- package/src/agent/loop.ts +76 -130
- package/src/calls/call-domain.ts +1 -6
- package/src/calls/relay-server.ts +9 -13
- package/src/calls/twilio-config.ts +2 -7
- package/src/calls/twilio-routes.ts +1 -2
- package/src/calls/voice-ingress-preflight.ts +1 -1
- package/src/cli/commands/browser-relay.ts +18 -12
- package/src/cli/commands/completions.ts +0 -3
- package/src/cli/commands/credentials.ts +101 -15
- package/src/cli/commands/oauth/apps.ts +255 -0
- package/src/cli/commands/oauth/connections.ts +299 -0
- package/src/cli/commands/oauth/index.ts +52 -0
- package/src/cli/commands/oauth/providers.ts +242 -0
- package/src/cli/commands/skills.ts +4 -338
- package/src/cli/program.ts +1 -5
- package/src/cli/reference.ts +1 -3
- package/src/config/assistant-feature-flags.ts +0 -3
- package/src/config/bundled-skills/_shared/CLI_RETRIEVAL_PATTERN.md +1 -1
- package/src/config/bundled-skills/computer-use/SKILL.md +3 -6
- package/src/config/bundled-skills/computer-use/TOOLS.json +22 -4
- package/src/config/bundled-skills/google-calendar/calendar-client.ts +21 -16
- package/src/config/bundled-skills/messaging/tools/shared.ts +1 -4
- package/src/config/bundled-skills/settings/SKILL.md +1 -1
- package/src/config/bundled-skills/settings/TOOLS.json +2 -8
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +5 -33
- package/src/config/env-registry.ts +14 -83
- package/src/config/env.ts +11 -50
- package/src/config/feature-flag-registry.json +16 -16
- package/src/config/loader.ts +0 -6
- package/src/config/schema.ts +3 -1
- package/src/config/skills.ts +21 -2
- package/src/context/image-dimensions.ts +229 -0
- package/src/context/token-estimator.ts +75 -12
- package/src/context/window-manager.ts +49 -10
- package/src/daemon/assistant-attachments.ts +1 -13
- package/src/daemon/handlers/config-ingress.ts +8 -33
- package/src/daemon/handlers/config-slack-channel.ts +49 -46
- package/src/daemon/handlers/config-telegram.ts +32 -16
- package/src/daemon/handlers/sessions.ts +10 -24
- package/src/daemon/handlers/shared.ts +0 -130
- package/src/daemon/host-cu-proxy.ts +401 -0
- package/src/daemon/lifecycle.ts +36 -68
- package/src/daemon/message-protocol.ts +3 -0
- package/src/daemon/message-types/computer-use.ts +2 -119
- package/src/daemon/message-types/host-cu.ts +19 -0
- package/src/daemon/message-types/messages.ts +3 -0
- package/src/daemon/server.ts +14 -21
- package/src/daemon/session-agent-loop-handlers.ts +2 -0
- package/src/daemon/session-attachments.ts +1 -2
- package/src/daemon/session-slash.ts +1 -1
- package/src/daemon/session-surfaces.ts +40 -28
- package/src/daemon/session-tool-setup.ts +2 -9
- package/src/daemon/session.ts +138 -15
- package/src/daemon/tool-side-effects.ts +2 -8
- package/src/daemon/watch-handler.ts +2 -2
- package/src/events/tool-metrics-listener.ts +2 -2
- package/src/hooks/manager.ts +1 -4
- package/src/inbound/public-ingress-urls.ts +7 -7
- package/src/logfire.ts +16 -5
- package/src/memory/conversation-key-store.ts +21 -0
- package/src/memory/db-init.ts +4 -0
- package/src/memory/migrations/149-oauth-tables.ts +60 -0
- package/src/memory/migrations/index.ts +1 -0
- package/src/memory/schema/index.ts +1 -0
- package/src/memory/schema/oauth.ts +65 -0
- package/src/messaging/provider.ts +4 -4
- package/src/messaging/providers/gmail/client.ts +82 -2
- package/src/messaging/providers/gmail/people-client.ts +10 -10
- package/src/messaging/providers/telegram-bot/adapter.ts +17 -17
- package/src/messaging/providers/whatsapp/adapter.ts +11 -8
- package/src/messaging/registry.ts +2 -32
- package/src/notifications/copy-composer.ts +0 -5
- package/src/notifications/signal.ts +4 -5
- package/src/oauth/byo-connection.test.ts +126 -25
- package/src/oauth/byo-connection.ts +22 -6
- package/src/oauth/connect-orchestrator.ts +113 -57
- package/src/oauth/connect-types.ts +17 -23
- package/src/oauth/connection-resolver.ts +35 -11
- package/src/oauth/connection.ts +1 -1
- package/src/oauth/manual-token-connection.ts +104 -0
- package/src/oauth/oauth-store.ts +496 -0
- package/src/oauth/platform-connection.test.ts +29 -0
- package/src/oauth/platform-connection.ts +6 -5
- package/src/oauth/provider-behaviors.ts +124 -0
- package/src/oauth/scope-policy.ts +9 -2
- package/src/oauth/seed-providers.ts +161 -0
- package/src/oauth/token-persistence.ts +74 -78
- package/src/permissions/checker.ts +3 -3
- package/src/permissions/defaults.ts +0 -1
- package/src/permissions/prompter.ts +10 -1
- package/src/permissions/trust-store.ts +13 -0
- package/src/prompts/__tests__/build-cli-reference-section.test.ts +3 -1
- package/src/prompts/system-prompt.ts +28 -40
- package/src/providers/anthropic/client.ts +133 -24
- package/src/providers/retry.ts +1 -27
- package/src/runtime/auth/route-policy.ts +0 -3
- package/src/runtime/channel-reply-delivery.ts +0 -40
- package/src/runtime/gateway-client.ts +0 -7
- package/src/runtime/http-server.ts +8 -6
- package/src/runtime/http-types.ts +2 -2
- package/src/runtime/middleware/twilio-validation.ts +1 -11
- package/src/runtime/pending-interactions.ts +14 -12
- package/src/runtime/routes/channel-delivery-routes.ts +0 -1
- package/src/runtime/routes/conversation-routes.ts +73 -19
- package/src/runtime/routes/events-routes.ts +21 -11
- package/src/runtime/routes/host-cu-routes.ts +97 -0
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +12 -111
- package/src/runtime/routes/integrations/slack/share.ts +6 -7
- package/src/runtime/routes/log-export-routes.ts +126 -8
- package/src/runtime/routes/settings-routes.ts +55 -48
- package/src/runtime/routes/surface-action-routes.ts +1 -1
- package/src/runtime/routes/watch-routes.ts +128 -0
- package/src/schedule/integration-status.ts +10 -9
- package/src/security/credential-key.ts +0 -156
- package/src/security/keychain-broker-client.ts +5 -6
- package/src/security/oauth2.ts +1 -1
- package/src/security/token-manager.ts +119 -46
- package/src/skills/catalog-install.ts +358 -0
- package/src/skills/include-graph.ts +32 -0
- package/src/telegram/bot-username.ts +2 -3
- package/src/tools/browser/network-recorder.ts +1 -1
- package/src/tools/browser/network-recording-types.ts +1 -1
- package/src/tools/computer-use/definitions.ts +46 -11
- package/src/tools/computer-use/registry.ts +4 -5
- package/src/tools/credentials/broker.ts +1 -2
- package/src/tools/credentials/metadata-store.ts +17 -121
- package/src/tools/credentials/vault.ts +94 -167
- package/src/tools/registry.ts +2 -7
- package/src/tools/skills/load.ts +62 -3
- package/src/tools/watch/watch-state.ts +0 -12
- package/src/util/logger.ts +7 -41
- package/src/util/platform.ts +9 -28
- package/src/watcher/providers/google-calendar.ts +2 -1
- package/src/__tests__/computer-use-session-compaction.test.ts +0 -143
- package/src/__tests__/computer-use-session-lifecycle.test.ts +0 -322
- package/src/__tests__/computer-use-session-working-dir.test.ts +0 -166
- package/src/__tests__/computer-use-skill-baseline.test.ts +0 -78
- package/src/__tests__/computer-use-skill-endstate.test.ts +0 -105
- package/src/__tests__/computer-use-skill-lifecycle-cleanup.test.ts +0 -249
- package/src/__tests__/ride-shotgun-handler.test.ts +0 -452
- package/src/cli/commands/dev.ts +0 -129
- package/src/cli/commands/map.ts +0 -391
- package/src/cli/commands/oauth.ts +0 -77
- package/src/config/bundled-skills/computer-use/tools/computer-use-request-control.ts +0 -16
- package/src/daemon/computer-use-session.ts +0 -1026
- package/src/daemon/ride-shotgun-handler.ts +0 -569
- package/src/oauth/provider-base-urls.ts +0 -21
- package/src/oauth/provider-profiles.ts +0 -192
- package/src/prompts/computer-use-prompt.ts +0 -98
- package/src/runtime/routes/computer-use-routes.ts +0 -641
- package/src/runtime/telegram-streaming-delivery.test.ts +0 -729
- package/src/runtime/telegram-streaming-delivery.ts +0 -393
- package/src/tools/computer-use/request-computer-control.ts +0 -56
|
@@ -63,6 +63,20 @@ function isToolUseBlock(block: unknown): block is Anthropic.ToolUseBlockParam {
|
|
|
63
63
|
);
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
+
/** Type-guard for server_tool_use blocks (e.g. native web search). */
|
|
67
|
+
function isServerToolUseBlock(block: unknown): block is {
|
|
68
|
+
type: "server_tool_use";
|
|
69
|
+
id: string;
|
|
70
|
+
name: string;
|
|
71
|
+
input: unknown;
|
|
72
|
+
} {
|
|
73
|
+
return (
|
|
74
|
+
typeof block === "object" &&
|
|
75
|
+
block != null &&
|
|
76
|
+
(block as { type: string }).type === "server_tool_use"
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
66
80
|
/** Type-guard for tool_result blocks in Anthropic-formatted content. */
|
|
67
81
|
function isToolResultBlock(
|
|
68
82
|
block: unknown,
|
|
@@ -74,6 +88,19 @@ function isToolResultBlock(
|
|
|
74
88
|
);
|
|
75
89
|
}
|
|
76
90
|
|
|
91
|
+
/** Type-guard for web_search_tool_result blocks. */
|
|
92
|
+
function isWebSearchToolResultBlock(block: unknown): block is {
|
|
93
|
+
type: "web_search_tool_result";
|
|
94
|
+
tool_use_id: string;
|
|
95
|
+
content: unknown;
|
|
96
|
+
} {
|
|
97
|
+
return (
|
|
98
|
+
typeof block === "object" &&
|
|
99
|
+
block != null &&
|
|
100
|
+
(block as { type: string }).type === "web_search_tool_result"
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
77
104
|
/**
|
|
78
105
|
* Build a short diagnostic summary of a message array for error logging.
|
|
79
106
|
* Shows role + block types (with tool_use/tool_result IDs) for each message.
|
|
@@ -84,8 +111,12 @@ function summarizeMessages(messages: Anthropic.MessageParam[]): string[] {
|
|
|
84
111
|
const blockDescs = content.map((b) => {
|
|
85
112
|
const bt = (b as { type: string }).type;
|
|
86
113
|
if (bt === "tool_use") return `tool_use(${(b as { id: string }).id})`;
|
|
114
|
+
if (bt === "server_tool_use")
|
|
115
|
+
return `server_tool_use(${(b as { id: string }).id})`;
|
|
87
116
|
if (bt === "tool_result")
|
|
88
117
|
return `tool_result(${(b as { tool_use_id: string }).tool_use_id})`;
|
|
118
|
+
if (bt === "web_search_tool_result")
|
|
119
|
+
return `web_search_tool_result(${(b as { tool_use_id: string }).tool_use_id})`;
|
|
89
120
|
return bt;
|
|
90
121
|
});
|
|
91
122
|
return `[${idx}] ${m.role}: ${blockDescs.join(", ") || "(empty)"}`;
|
|
@@ -103,29 +134,70 @@ function buildSyntheticToolResult(
|
|
|
103
134
|
};
|
|
104
135
|
}
|
|
105
136
|
|
|
106
|
-
function
|
|
107
|
-
|
|
108
|
-
):
|
|
137
|
+
function buildSyntheticWebSearchToolResult(
|
|
138
|
+
toolUseId: string,
|
|
139
|
+
): Anthropic.ContentBlockParam {
|
|
140
|
+
return {
|
|
141
|
+
type: "web_search_tool_result",
|
|
142
|
+
tool_use_id: toolUseId,
|
|
143
|
+
content: {
|
|
144
|
+
type: "web_search_tool_result_error",
|
|
145
|
+
error_code: "unavailable",
|
|
146
|
+
},
|
|
147
|
+
} as unknown as Anthropic.ContentBlockParam;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/** Build the appropriate synthetic result block based on whether the ID is for a server tool or regular tool. */
|
|
151
|
+
function buildSyntheticResult(
|
|
152
|
+
toolUseId: string,
|
|
153
|
+
serverToolIds: ReadonlySet<string>,
|
|
154
|
+
): Anthropic.ContentBlockParam {
|
|
155
|
+
if (serverToolIds.has(toolUseId)) {
|
|
156
|
+
return buildSyntheticWebSearchToolResult(toolUseId);
|
|
157
|
+
}
|
|
158
|
+
return buildSyntheticToolResult(toolUseId);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function getOrderedToolUseIds(content: Anthropic.ContentBlockParam[]): {
|
|
162
|
+
ids: string[];
|
|
163
|
+
serverToolIds: Set<string>;
|
|
164
|
+
} {
|
|
109
165
|
const ids: string[] = [];
|
|
110
166
|
const seen = new Set<string>();
|
|
167
|
+
const serverToolIds = new Set<string>();
|
|
111
168
|
for (const block of content) {
|
|
112
|
-
if (
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
169
|
+
if (isToolUseBlock(block)) {
|
|
170
|
+
if (!seen.has(block.id)) {
|
|
171
|
+
seen.add(block.id);
|
|
172
|
+
ids.push(block.id);
|
|
173
|
+
}
|
|
174
|
+
} else if (isServerToolUseBlock(block)) {
|
|
175
|
+
if (!seen.has(block.id)) {
|
|
176
|
+
seen.add(block.id);
|
|
177
|
+
ids.push(block.id);
|
|
178
|
+
serverToolIds.add(block.id);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
116
181
|
}
|
|
117
|
-
return ids;
|
|
182
|
+
return { ids, serverToolIds };
|
|
118
183
|
}
|
|
119
184
|
|
|
120
185
|
function hasOrderedToolResultPrefix(
|
|
121
186
|
content: Anthropic.ContentBlockParam[],
|
|
122
187
|
orderedToolUseIds: string[],
|
|
188
|
+
serverToolIds: ReadonlySet<string>,
|
|
123
189
|
): boolean {
|
|
124
190
|
if (content.length < orderedToolUseIds.length) return false;
|
|
125
191
|
for (let idx = 0; idx < orderedToolUseIds.length; idx++) {
|
|
126
192
|
const block = content[idx];
|
|
127
|
-
|
|
128
|
-
if (
|
|
193
|
+
const expectedId = orderedToolUseIds[idx];
|
|
194
|
+
if (serverToolIds.has(expectedId)) {
|
|
195
|
+
if (!isWebSearchToolResultBlock(block)) return false;
|
|
196
|
+
if (block.tool_use_id !== expectedId) return false;
|
|
197
|
+
} else {
|
|
198
|
+
if (!isToolResultBlock(block)) return false;
|
|
199
|
+
if (block.tool_use_id !== expectedId) return false;
|
|
200
|
+
}
|
|
129
201
|
}
|
|
130
202
|
return true;
|
|
131
203
|
}
|
|
@@ -134,14 +206,15 @@ function splitAssistantForToolPairing(content: Anthropic.ContentBlockParam[]): {
|
|
|
134
206
|
pairedContent: Anthropic.ContentBlockParam[];
|
|
135
207
|
carryoverContent: Anthropic.ContentBlockParam[];
|
|
136
208
|
toolUseIds: string[];
|
|
209
|
+
serverToolIds: Set<string>;
|
|
137
210
|
} {
|
|
138
211
|
const leading: Anthropic.ContentBlockParam[] = [];
|
|
139
|
-
const toolUseBlocks: Anthropic.
|
|
212
|
+
const toolUseBlocks: Anthropic.ContentBlockParam[] = [];
|
|
140
213
|
const carryover: Anthropic.ContentBlockParam[] = [];
|
|
141
214
|
let seenToolUse = false;
|
|
142
215
|
|
|
143
216
|
for (const block of content) {
|
|
144
|
-
if (isToolUseBlock(block)) {
|
|
217
|
+
if (isToolUseBlock(block) || isServerToolUseBlock(block)) {
|
|
145
218
|
seenToolUse = true;
|
|
146
219
|
toolUseBlocks.push(block);
|
|
147
220
|
continue;
|
|
@@ -158,6 +231,7 @@ function splitAssistantForToolPairing(content: Anthropic.ContentBlockParam[]): {
|
|
|
158
231
|
pairedContent: content,
|
|
159
232
|
carryoverContent: [],
|
|
160
233
|
toolUseIds: [],
|
|
234
|
+
serverToolIds: new Set(),
|
|
161
235
|
};
|
|
162
236
|
}
|
|
163
237
|
|
|
@@ -165,16 +239,19 @@ function splitAssistantForToolPairing(content: Anthropic.ContentBlockParam[]): {
|
|
|
165
239
|
...leading,
|
|
166
240
|
...toolUseBlocks,
|
|
167
241
|
];
|
|
242
|
+
const { ids, serverToolIds } = getOrderedToolUseIds(pairedContent);
|
|
168
243
|
return {
|
|
169
244
|
pairedContent,
|
|
170
245
|
carryoverContent: carryover,
|
|
171
|
-
toolUseIds:
|
|
246
|
+
toolUseIds: ids,
|
|
247
|
+
serverToolIds,
|
|
172
248
|
};
|
|
173
249
|
}
|
|
174
250
|
|
|
175
251
|
function normalizeFollowingUserContent(
|
|
176
252
|
nextContent: Anthropic.ContentBlockParam[],
|
|
177
253
|
orderedToolUseIds: string[],
|
|
254
|
+
serverToolIds: ReadonlySet<string>,
|
|
178
255
|
): {
|
|
179
256
|
toolResultPrefix: Anthropic.ContentBlockParam[];
|
|
180
257
|
remainingContent: Anthropic.ContentBlockParam[];
|
|
@@ -182,24 +259,37 @@ function normalizeFollowingUserContent(
|
|
|
182
259
|
hadOrderedPrefix: boolean;
|
|
183
260
|
} {
|
|
184
261
|
const pendingIds = new Set(orderedToolUseIds);
|
|
185
|
-
const matchedById = new Map<string, Anthropic.
|
|
262
|
+
const matchedById = new Map<string, Anthropic.ContentBlockParam>();
|
|
186
263
|
const remaining: Anthropic.ContentBlockParam[] = [];
|
|
187
264
|
|
|
188
265
|
for (const block of nextContent) {
|
|
189
266
|
if (
|
|
190
267
|
isToolResultBlock(block) &&
|
|
191
268
|
pendingIds.has(block.tool_use_id) &&
|
|
192
|
-
!matchedById.has(block.tool_use_id)
|
|
269
|
+
!matchedById.has(block.tool_use_id) &&
|
|
270
|
+
!serverToolIds.has(block.tool_use_id)
|
|
193
271
|
) {
|
|
194
272
|
matchedById.set(block.tool_use_id, block);
|
|
195
273
|
continue;
|
|
196
274
|
}
|
|
275
|
+
if (
|
|
276
|
+
isWebSearchToolResultBlock(block) &&
|
|
277
|
+
pendingIds.has(block.tool_use_id) &&
|
|
278
|
+
!matchedById.has(block.tool_use_id) &&
|
|
279
|
+
serverToolIds.has(block.tool_use_id)
|
|
280
|
+
) {
|
|
281
|
+
matchedById.set(
|
|
282
|
+
block.tool_use_id,
|
|
283
|
+
block as unknown as Anthropic.ContentBlockParam,
|
|
284
|
+
);
|
|
285
|
+
continue;
|
|
286
|
+
}
|
|
197
287
|
remaining.push(block);
|
|
198
288
|
}
|
|
199
289
|
|
|
200
290
|
const missingIds = orderedToolUseIds.filter((id) => !matchedById.has(id));
|
|
201
291
|
const orderedResults = orderedToolUseIds.map(
|
|
202
|
-
(id) => matchedById.get(id) ??
|
|
292
|
+
(id) => matchedById.get(id) ?? buildSyntheticResult(id, serverToolIds),
|
|
203
293
|
);
|
|
204
294
|
|
|
205
295
|
return {
|
|
@@ -209,6 +299,7 @@ function normalizeFollowingUserContent(
|
|
|
209
299
|
hadOrderedPrefix: hasOrderedToolResultPrefix(
|
|
210
300
|
nextContent,
|
|
211
301
|
orderedToolUseIds,
|
|
302
|
+
serverToolIds,
|
|
212
303
|
),
|
|
213
304
|
};
|
|
214
305
|
}
|
|
@@ -237,7 +328,7 @@ function ensureToolPairing(
|
|
|
237
328
|
}
|
|
238
329
|
|
|
239
330
|
const content = Array.isArray(msg.content) ? msg.content : [];
|
|
240
|
-
const { pairedContent, carryoverContent, toolUseIds } =
|
|
331
|
+
const { pairedContent, carryoverContent, toolUseIds, serverToolIds } =
|
|
241
332
|
splitAssistantForToolPairing(content);
|
|
242
333
|
|
|
243
334
|
if (toolUseIds.length === 0) {
|
|
@@ -246,7 +337,7 @@ function ensureToolPairing(
|
|
|
246
337
|
continue;
|
|
247
338
|
}
|
|
248
339
|
|
|
249
|
-
// Assistant message — push the paired portion (pre-tool text + tool_use blocks)
|
|
340
|
+
// Assistant message — push the paired portion (pre-tool text + tool_use/server_tool_use blocks)
|
|
250
341
|
result.push({
|
|
251
342
|
role: "assistant" as const,
|
|
252
343
|
content: pairedContent,
|
|
@@ -267,7 +358,11 @@ function ensureToolPairing(
|
|
|
267
358
|
const next = messages[i + 1];
|
|
268
359
|
if (next && next.role === "user") {
|
|
269
360
|
const nextContent = Array.isArray(next.content) ? next.content : [];
|
|
270
|
-
const normalized = normalizeFollowingUserContent(
|
|
361
|
+
const normalized = normalizeFollowingUserContent(
|
|
362
|
+
nextContent,
|
|
363
|
+
toolUseIds,
|
|
364
|
+
serverToolIds,
|
|
365
|
+
);
|
|
271
366
|
if (normalized.missingIds.length > 0) {
|
|
272
367
|
log.warn(
|
|
273
368
|
{
|
|
@@ -332,7 +427,9 @@ function ensureToolPairing(
|
|
|
332
427
|
);
|
|
333
428
|
result.push({
|
|
334
429
|
role: "user" as const,
|
|
335
|
-
content: toolUseIds.map((id) =>
|
|
430
|
+
content: toolUseIds.map((id) =>
|
|
431
|
+
buildSyntheticResult(id, serverToolIds),
|
|
432
|
+
),
|
|
336
433
|
});
|
|
337
434
|
|
|
338
435
|
// If the assistant contained collapsed post-tool text, preserve it as a
|
|
@@ -353,17 +450,29 @@ function ensureToolPairing(
|
|
|
353
450
|
const m = result[j];
|
|
354
451
|
if (m.role !== "assistant") continue;
|
|
355
452
|
const c = Array.isArray(m.content) ? m.content : [];
|
|
356
|
-
const ids =
|
|
357
|
-
|
|
453
|
+
const { ids: validationIds, serverToolIds: validationServerToolIds } =
|
|
454
|
+
getOrderedToolUseIds(c);
|
|
455
|
+
if (validationIds.length === 0) continue;
|
|
358
456
|
|
|
359
457
|
const nxt = result[j + 1];
|
|
360
458
|
const nxtContent =
|
|
361
459
|
nxt && nxt.role === "user" && Array.isArray(nxt.content)
|
|
362
460
|
? nxt.content
|
|
363
461
|
: [];
|
|
364
|
-
if (
|
|
365
|
-
|
|
462
|
+
if (
|
|
463
|
+
!hasOrderedToolResultPrefix(
|
|
464
|
+
nxtContent,
|
|
465
|
+
validationIds,
|
|
466
|
+
validationServerToolIds,
|
|
467
|
+
)
|
|
468
|
+
) {
|
|
469
|
+
const unmatchedIds = validationIds.filter((id, idx) => {
|
|
366
470
|
const block = nxtContent[idx];
|
|
471
|
+
if (validationServerToolIds.has(id)) {
|
|
472
|
+
return !(
|
|
473
|
+
isWebSearchToolResultBlock(block) && block.tool_use_id === id
|
|
474
|
+
);
|
|
475
|
+
}
|
|
367
476
|
return !(isToolResultBlock(block) && block.tool_use_id === id);
|
|
368
477
|
});
|
|
369
478
|
log.error(
|
package/src/providers/retry.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ProviderError } from "../util/errors.js";
|
|
2
|
-
import { getLogger
|
|
2
|
+
import { getLogger } from "../util/logger.js";
|
|
3
3
|
import {
|
|
4
4
|
computeRetryDelay,
|
|
5
5
|
DEFAULT_BASE_DELAY_MS,
|
|
@@ -96,43 +96,17 @@ export class RetryProvider implements Provider {
|
|
|
96
96
|
options?: SendMessageOptions,
|
|
97
97
|
): Promise<ProviderResponse> {
|
|
98
98
|
let lastError: unknown;
|
|
99
|
-
const debug = isDebug();
|
|
100
|
-
|
|
101
|
-
if (debug) {
|
|
102
|
-
log.debug(
|
|
103
|
-
{
|
|
104
|
-
provider: this.name,
|
|
105
|
-
messageCount: messages.length,
|
|
106
|
-
toolCount: tools?.length ?? 0,
|
|
107
|
-
},
|
|
108
|
-
"Provider sendMessage start",
|
|
109
|
-
);
|
|
110
|
-
}
|
|
111
99
|
|
|
112
100
|
const normalizedOptions = normalizeSendMessageOptions(this.name, options);
|
|
113
101
|
|
|
114
102
|
for (let attempt = 0; attempt <= DEFAULT_MAX_RETRIES; attempt++) {
|
|
115
103
|
try {
|
|
116
|
-
const start = Date.now();
|
|
117
104
|
const result = await this.inner.sendMessage(
|
|
118
105
|
messages,
|
|
119
106
|
tools,
|
|
120
107
|
systemPrompt,
|
|
121
108
|
normalizedOptions,
|
|
122
109
|
);
|
|
123
|
-
if (debug) {
|
|
124
|
-
log.debug(
|
|
125
|
-
{
|
|
126
|
-
provider: this.name,
|
|
127
|
-
durationMs: Date.now() - start,
|
|
128
|
-
attempt: attempt + 1,
|
|
129
|
-
model: result.model,
|
|
130
|
-
inputTokens: result.usage.inputTokens,
|
|
131
|
-
outputTokens: result.usage.outputTokens,
|
|
132
|
-
},
|
|
133
|
-
"Provider sendMessage success",
|
|
134
|
-
);
|
|
135
|
-
}
|
|
136
110
|
return result;
|
|
137
111
|
} catch (error) {
|
|
138
112
|
lastError = error;
|
|
@@ -358,9 +358,6 @@ const ACTOR_ENDPOINTS: Array<{ endpoint: string; scopes: Scope[] }> = [
|
|
|
358
358
|
{ endpoint: "computer-use/sessions/abort", scopes: ["chat.write"] },
|
|
359
359
|
{ endpoint: "computer-use/observations", scopes: ["chat.write"] },
|
|
360
360
|
{ endpoint: "computer-use/tasks", scopes: ["chat.write"] },
|
|
361
|
-
{ endpoint: "computer-use/ride-shotgun/start", scopes: ["chat.write"] },
|
|
362
|
-
{ endpoint: "computer-use/ride-shotgun/stop", scopes: ["chat.write"] },
|
|
363
|
-
{ endpoint: "computer-use/ride-shotgun/status", scopes: ["chat.write"] },
|
|
364
361
|
{ endpoint: "computer-use/watch", scopes: ["chat.write"] },
|
|
365
362
|
|
|
366
363
|
// Recordings
|
|
@@ -208,43 +208,3 @@ export async function deliverReplyViaCallback(
|
|
|
208
208
|
break;
|
|
209
209
|
}
|
|
210
210
|
}
|
|
211
|
-
|
|
212
|
-
/**
|
|
213
|
-
* Deliver only the attachments from the last assistant message, skipping text.
|
|
214
|
-
* Used when streaming already delivered the text content and only file
|
|
215
|
-
* attachments remain to be sent via the normal delivery path.
|
|
216
|
-
*/
|
|
217
|
-
export async function deliverAttachmentsOnly(
|
|
218
|
-
conversationId: string,
|
|
219
|
-
externalChatId: string,
|
|
220
|
-
callbackUrl: string,
|
|
221
|
-
bearerToken?: string,
|
|
222
|
-
assistantId?: string,
|
|
223
|
-
): Promise<void> {
|
|
224
|
-
const msgs = getMessages(conversationId);
|
|
225
|
-
for (let i = msgs.length - 1; i >= 0; i--) {
|
|
226
|
-
if (msgs[i].role !== "assistant") continue;
|
|
227
|
-
|
|
228
|
-
const linked = attachmentsStore.getAttachmentMetadataForMessage(msgs[i].id);
|
|
229
|
-
if (linked.length === 0) return;
|
|
230
|
-
|
|
231
|
-
const replyAttachments: RuntimeAttachmentMetadata[] = linked.map((a) => ({
|
|
232
|
-
id: a.id,
|
|
233
|
-
filename: a.originalFilename,
|
|
234
|
-
mimeType: a.mimeType,
|
|
235
|
-
sizeBytes: a.sizeBytes,
|
|
236
|
-
kind: a.kind,
|
|
237
|
-
}));
|
|
238
|
-
|
|
239
|
-
await deliverChannelReply(
|
|
240
|
-
callbackUrl,
|
|
241
|
-
{
|
|
242
|
-
chatId: externalChatId,
|
|
243
|
-
attachments: replyAttachments,
|
|
244
|
-
assistantId,
|
|
245
|
-
},
|
|
246
|
-
bearerToken,
|
|
247
|
-
);
|
|
248
|
-
break;
|
|
249
|
-
}
|
|
250
|
-
}
|
|
@@ -31,8 +31,6 @@ export interface ChannelReplyPayload {
|
|
|
31
31
|
ephemeral?: boolean;
|
|
32
32
|
/** Slack user ID — required when `ephemeral` is true. */
|
|
33
33
|
user?: string;
|
|
34
|
-
/** Telegram message_id for editing an existing message instead of sending a new one. */
|
|
35
|
-
messageId?: number;
|
|
36
34
|
/** When provided, instructs the delivery endpoint to update an existing message instead of posting a new one. */
|
|
37
35
|
messageTs?: string;
|
|
38
36
|
/** When true, auto-generate Block Kit blocks from text via textToBlocks(). */
|
|
@@ -45,8 +43,6 @@ export interface ChannelDeliveryResult {
|
|
|
45
43
|
ok: boolean;
|
|
46
44
|
/** The message timestamp returned by the delivery endpoint (e.g. Slack message ts). */
|
|
47
45
|
ts?: string;
|
|
48
|
-
/** The Telegram message_id returned when a new message was sent. */
|
|
49
|
-
messageId?: number;
|
|
50
46
|
}
|
|
51
47
|
|
|
52
48
|
interface ManagedOutboundCallbackContext {
|
|
@@ -100,9 +96,6 @@ export async function deliverChannelReply(
|
|
|
100
96
|
if (typeof responseBody.ts === "string") {
|
|
101
97
|
result.ts = responseBody.ts;
|
|
102
98
|
}
|
|
103
|
-
if (typeof responseBody.messageId === "number") {
|
|
104
|
-
result.messageId = responseBody.messageId;
|
|
105
|
-
}
|
|
106
99
|
} catch {
|
|
107
100
|
// Response may not be JSON for non-Slack channels; that's fine.
|
|
108
101
|
}
|
|
@@ -110,7 +110,6 @@ import {
|
|
|
110
110
|
stopGuardianExpirySweep,
|
|
111
111
|
} from "./routes/channel-routes.js";
|
|
112
112
|
import { channelVerificationRouteDefinitions } from "./routes/channel-verification-routes.js";
|
|
113
|
-
import { computerUseRouteDefinitions } from "./routes/computer-use-routes.js";
|
|
114
113
|
import {
|
|
115
114
|
contactCatchAllRouteDefinitions,
|
|
116
115
|
contactRouteDefinitions,
|
|
@@ -126,6 +125,7 @@ import { guardianActionRouteDefinitions } from "./routes/guardian-action-routes.
|
|
|
126
125
|
import { handleGuardianBootstrap } from "./routes/guardian-bootstrap-routes.js";
|
|
127
126
|
import { handleGuardianRefresh } from "./routes/guardian-refresh-routes.js";
|
|
128
127
|
import { hostBashRouteDefinitions } from "./routes/host-bash-routes.js";
|
|
128
|
+
import { hostCuRouteDefinitions } from "./routes/host-cu-routes.js";
|
|
129
129
|
import { hostFileRouteDefinitions } from "./routes/host-file-routes.js";
|
|
130
130
|
import { handleHealth } from "./routes/identity-routes.js";
|
|
131
131
|
import { identityRouteDefinitions } from "./routes/identity-routes.js";
|
|
@@ -155,6 +155,7 @@ import { surfaceActionRouteDefinitions } from "./routes/surface-action-routes.js
|
|
|
155
155
|
import { surfaceContentRouteDefinitions } from "./routes/surface-content-routes.js";
|
|
156
156
|
import { trustRulesRouteDefinitions } from "./routes/trust-rules-routes.js";
|
|
157
157
|
import { usageRouteDefinitions } from "./routes/usage-routes.js";
|
|
158
|
+
import { watchRouteDefinitions } from "./routes/watch-routes.js";
|
|
158
159
|
import { workItemRouteDefinitions } from "./routes/work-items-routes.js";
|
|
159
160
|
import { workspaceRouteDefinitions } from "./routes/workspace-routes.js";
|
|
160
161
|
|
|
@@ -216,7 +217,7 @@ export class RuntimeHttpServer {
|
|
|
216
217
|
private getSkillContext?: RuntimeHttpServerOptions["getSkillContext"];
|
|
217
218
|
private sessionManagementDeps?: RuntimeHttpServerOptions["sessionManagementDeps"];
|
|
218
219
|
private getModelSetContext?: RuntimeHttpServerOptions["getModelSetContext"];
|
|
219
|
-
private
|
|
220
|
+
private getWatchDeps?: RuntimeHttpServerOptions["getWatchDeps"];
|
|
220
221
|
private getRecordingDeps?: RuntimeHttpServerOptions["getRecordingDeps"];
|
|
221
222
|
private router: HttpRouter;
|
|
222
223
|
|
|
@@ -237,7 +238,7 @@ export class RuntimeHttpServer {
|
|
|
237
238
|
this.getSkillContext = options.getSkillContext;
|
|
238
239
|
this.sessionManagementDeps = options.sessionManagementDeps;
|
|
239
240
|
this.getModelSetContext = options.getModelSetContext;
|
|
240
|
-
this.
|
|
241
|
+
this.getWatchDeps = options.getWatchDeps;
|
|
241
242
|
this.getRecordingDeps = options.getRecordingDeps;
|
|
242
243
|
this.router = new HttpRouter(this.buildRouteTable());
|
|
243
244
|
}
|
|
@@ -946,6 +947,7 @@ export class RuntimeHttpServer {
|
|
|
946
947
|
...globalSearchRouteDefinitions(),
|
|
947
948
|
...approvalRouteDefinitions(),
|
|
948
949
|
...hostBashRouteDefinitions(),
|
|
950
|
+
...hostCuRouteDefinitions(),
|
|
949
951
|
...hostFileRouteDefinitions(),
|
|
950
952
|
...(this.getSkillContext
|
|
951
953
|
? skillRouteDefinitions({
|
|
@@ -973,9 +975,9 @@ export class RuntimeHttpServer {
|
|
|
973
975
|
...channelReadinessRouteDefinitions(),
|
|
974
976
|
...attachmentRouteDefinitions(),
|
|
975
977
|
|
|
976
|
-
...(this.
|
|
977
|
-
?
|
|
978
|
-
|
|
978
|
+
...(this.getWatchDeps
|
|
979
|
+
? watchRouteDefinitions({
|
|
980
|
+
getWatchDeps: this.getWatchDeps,
|
|
979
981
|
})
|
|
980
982
|
: []),
|
|
981
983
|
...(this.getRecordingDeps
|
|
@@ -219,8 +219,8 @@ export interface RuntimeHttpServerOptions {
|
|
|
219
219
|
sessionManagementDeps?: SessionManagementDeps;
|
|
220
220
|
/** Lazy factory for model config set context (session eviction, config reload suppression). */
|
|
221
221
|
getModelSetContext?: () => import("../daemon/handlers/config-model.js").ModelSetContext;
|
|
222
|
-
/** Provider for
|
|
223
|
-
|
|
222
|
+
/** Provider for watch observation dependencies (watch routes). */
|
|
223
|
+
getWatchDeps?: () => import("./routes/watch-routes.js").WatchDeps;
|
|
224
224
|
/** Provider for recording dependencies (recording routes). */
|
|
225
225
|
getRecordingDeps?: () => import("./routes/recording-routes.js").RecordingDeps;
|
|
226
226
|
}
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { TwilioConversationRelayProvider } from "../../calls/twilio-provider.js";
|
|
6
|
-
import { isTwilioWebhookValidationDisabled } from "../../config/env.js";
|
|
7
6
|
import { loadConfig } from "../../config/loader.js";
|
|
8
7
|
import { getPublicBaseUrl } from "../../inbound/public-ingress-urls.js";
|
|
9
8
|
import { getLogger } from "../../util/logger.js";
|
|
@@ -51,22 +50,13 @@ export const GATEWAY_ONLY_BLOCKED_SUBPATHS = new Set([
|
|
|
51
50
|
* Returns a 403 Response if signature validation fails.
|
|
52
51
|
*
|
|
53
52
|
* Fail-closed: if the auth token is not configured, the request is rejected
|
|
54
|
-
* with 403 rather than silently skipping validation.
|
|
55
|
-
* bypass is available via TWILIO_WEBHOOK_VALIDATION_DISABLED=true.
|
|
53
|
+
* with 403 rather than silently skipping validation.
|
|
56
54
|
*/
|
|
57
55
|
export async function validateTwilioWebhook(
|
|
58
56
|
req: Request,
|
|
59
57
|
): Promise<{ body: string } | Response> {
|
|
60
58
|
const rawBody = await req.text();
|
|
61
59
|
|
|
62
|
-
// Allow explicit local-dev bypass -- must be exactly "true"
|
|
63
|
-
if (isTwilioWebhookValidationDisabled()) {
|
|
64
|
-
log.warn(
|
|
65
|
-
"Twilio webhook signature validation explicitly disabled via TWILIO_WEBHOOK_VALIDATION_DISABLED",
|
|
66
|
-
);
|
|
67
|
-
return { body: rawBody };
|
|
68
|
-
}
|
|
69
|
-
|
|
70
60
|
const authToken = TwilioConversationRelayProvider.getAuthToken();
|
|
71
61
|
|
|
72
62
|
if (!authToken) {
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* In-memory tracker that maps requestId to session info for pending
|
|
3
|
-
* confirmation, secret, host_bash, and
|
|
3
|
+
* confirmation, secret, host_bash, host_file, and host_cu interactions.
|
|
4
4
|
*
|
|
5
5
|
* When the agent loop emits a confirmation_request, secret_request,
|
|
6
|
-
* host_bash_request, or
|
|
7
|
-
* the interaction here. Standalone HTTP endpoints
|
|
8
|
-
* /v1/
|
|
9
|
-
*
|
|
6
|
+
* host_bash_request, host_file_request, or host_cu_request, the onEvent
|
|
7
|
+
* callback registers the interaction here. Standalone HTTP endpoints
|
|
8
|
+
* (/v1/confirm, /v1/secret, /v1/trust-rules, /v1/host-bash-result,
|
|
9
|
+
* /v1/host-file-result, /v1/host-cu-result) look up the session from
|
|
10
|
+
* this tracker to resolve the interaction.
|
|
10
11
|
*/
|
|
11
12
|
|
|
12
13
|
import type { Session } from "../daemon/session.js";
|
|
@@ -29,7 +30,7 @@ export interface ConfirmationDetails {
|
|
|
29
30
|
export interface PendingInteraction {
|
|
30
31
|
session: Session;
|
|
31
32
|
conversationId: string;
|
|
32
|
-
kind: "confirmation" | "secret" | "host_bash" | "host_file";
|
|
33
|
+
kind: "confirmation" | "secret" | "host_bash" | "host_file" | "host_cu";
|
|
33
34
|
confirmationDetails?: ConfirmationDetails;
|
|
34
35
|
}
|
|
35
36
|
|
|
@@ -82,19 +83,20 @@ export function getByConversation(
|
|
|
82
83
|
* Remove pending confirmation and secret interactions for a given session.
|
|
83
84
|
* Used when auto-denying all pending interactions (e.g. new user message).
|
|
84
85
|
*
|
|
85
|
-
* host_bash and
|
|
86
|
-
* represent in-flight tool executions proxied to the client, not
|
|
86
|
+
* host_bash, host_file, and host_cu interactions are intentionally skipped
|
|
87
|
+
* — they represent in-flight tool executions proxied to the client, not
|
|
87
88
|
* confirmations to auto-deny. Removing them would orphan the request: the
|
|
88
|
-
* client would POST to /v1/host-bash-result
|
|
89
|
-
* completing the operation, get a 404, and the
|
|
90
|
-
* a spurious timeout error.
|
|
89
|
+
* client would POST to /v1/host-bash-result, /v1/host-file-result, or
|
|
90
|
+
* /v1/host-cu-result after completing the operation, get a 404, and the
|
|
91
|
+
* proxy timer would fire with a spurious timeout error.
|
|
91
92
|
*/
|
|
92
93
|
export function removeBySession(session: Session): void {
|
|
93
94
|
for (const [requestId, interaction] of pending) {
|
|
94
95
|
if (
|
|
95
96
|
interaction.session === session &&
|
|
96
97
|
interaction.kind !== "host_bash" &&
|
|
97
|
-
interaction.kind !== "host_file"
|
|
98
|
+
interaction.kind !== "host_file" &&
|
|
99
|
+
interaction.kind !== "host_cu"
|
|
98
100
|
) {
|
|
99
101
|
pending.delete(requestId);
|
|
100
102
|
}
|