claude-code-rust 0.5.1 → 0.7.0
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/README.md +8 -8
- package/agent-sdk/dist/bridge/agents.js +75 -0
- package/agent-sdk/dist/bridge/commands.js +45 -14
- package/agent-sdk/dist/bridge/error_classification.js +55 -0
- package/agent-sdk/dist/bridge/events.js +83 -0
- package/agent-sdk/dist/bridge/history.js +49 -258
- package/agent-sdk/dist/bridge/message_handlers.js +428 -0
- package/agent-sdk/dist/bridge/permissions.js +15 -3
- package/agent-sdk/dist/bridge/session_lifecycle.js +368 -0
- package/agent-sdk/dist/bridge/shared.js +49 -0
- package/agent-sdk/dist/bridge/state_parsing.js +66 -0
- package/agent-sdk/dist/bridge/tool_calls.js +168 -0
- package/agent-sdk/dist/bridge/tooling.js +27 -5
- package/agent-sdk/dist/bridge/user_interaction.js +175 -0
- package/agent-sdk/dist/bridge.js +37 -1106
- package/agent-sdk/dist/bridge.test.js +304 -150
- package/bin/claude-rs.js +1 -1
- package/package.json +6 -7
- package/scripts/postinstall.js +2 -2
- package/agent-sdk/README.md +0 -13
- package/agent-sdk/dist/bridge/usage.js +0 -95
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
import { asRecordOrNull } from "./shared.js";
|
|
2
|
+
import { toPermissionMode, buildModeState } from "./commands.js";
|
|
3
|
+
import { writeEvent, emitSessionUpdate, emitConnectEvent, refreshSessionsList } from "./events.js";
|
|
4
|
+
import { TOOL_RESULT_TYPES, unwrapToolUseResult } from "./tooling.js";
|
|
5
|
+
import { emitToolCall, emitPlanIfTodoWrite, emitToolResultUpdate, finalizeOpenToolCalls, emitToolProgressUpdate, emitToolSummaryUpdate, ensureToolCallVisible, resolveTaskToolUseId, taskProgressText, } from "./tool_calls.js";
|
|
6
|
+
import { emitAuthRequired, classifyTurnErrorKind, emitFastModeUpdateIfChanged } from "./error_classification.js";
|
|
7
|
+
import { mapAvailableAgentsFromNames, emitAvailableAgentsIfChanged, refreshAvailableAgents } from "./agents.js";
|
|
8
|
+
import { buildRateLimitUpdate, numberField } from "./state_parsing.js";
|
|
9
|
+
import { looksLikeAuthRequired } from "./auth.js";
|
|
10
|
+
import { updateSessionId } from "./session_lifecycle.js";
|
|
11
|
+
export function textFromPrompt(command) {
|
|
12
|
+
const chunks = command.chunks ?? [];
|
|
13
|
+
return chunks
|
|
14
|
+
.map((chunk) => {
|
|
15
|
+
if (chunk.kind !== "text") {
|
|
16
|
+
return "";
|
|
17
|
+
}
|
|
18
|
+
return typeof chunk.value === "string" ? chunk.value : "";
|
|
19
|
+
})
|
|
20
|
+
.filter((part) => part.length > 0)
|
|
21
|
+
.join("");
|
|
22
|
+
}
|
|
23
|
+
export function handleTaskSystemMessage(session, subtype, msg) {
|
|
24
|
+
if (subtype !== "task_started" && subtype !== "task_progress" && subtype !== "task_notification") {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const taskId = typeof msg.task_id === "string" ? msg.task_id : "";
|
|
28
|
+
const explicitToolUseId = typeof msg.tool_use_id === "string" ? msg.tool_use_id : "";
|
|
29
|
+
if (taskId && explicitToolUseId) {
|
|
30
|
+
session.taskToolUseIds.set(taskId, explicitToolUseId);
|
|
31
|
+
}
|
|
32
|
+
const toolUseId = resolveTaskToolUseId(session, msg);
|
|
33
|
+
if (!toolUseId) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const toolCall = ensureToolCallVisible(session, toolUseId, "Agent", {});
|
|
37
|
+
if (toolCall.status === "pending") {
|
|
38
|
+
toolCall.status = "in_progress";
|
|
39
|
+
emitSessionUpdate(session.sessionId, {
|
|
40
|
+
type: "tool_call_update",
|
|
41
|
+
tool_call_update: { tool_call_id: toolUseId, fields: { status: "in_progress" } },
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
if (subtype === "task_started") {
|
|
45
|
+
const description = typeof msg.description === "string" ? msg.description : "";
|
|
46
|
+
if (!description) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
emitSessionUpdate(session.sessionId, {
|
|
50
|
+
type: "tool_call_update",
|
|
51
|
+
tool_call_update: {
|
|
52
|
+
tool_call_id: toolUseId,
|
|
53
|
+
fields: {
|
|
54
|
+
status: "in_progress",
|
|
55
|
+
raw_output: description,
|
|
56
|
+
content: [{ type: "content", content: { type: "text", text: description } }],
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (subtype === "task_progress") {
|
|
63
|
+
const progress = taskProgressText(msg);
|
|
64
|
+
if (!progress) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
emitSessionUpdate(session.sessionId, {
|
|
68
|
+
type: "tool_call_update",
|
|
69
|
+
tool_call_update: {
|
|
70
|
+
tool_call_id: toolUseId,
|
|
71
|
+
fields: {
|
|
72
|
+
status: "in_progress",
|
|
73
|
+
raw_output: progress,
|
|
74
|
+
content: [{ type: "content", content: { type: "text", text: progress } }],
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const status = typeof msg.status === "string" ? msg.status : "";
|
|
81
|
+
const summary = typeof msg.summary === "string" ? msg.summary : "";
|
|
82
|
+
const finalStatus = status === "completed" ? "completed" : "failed";
|
|
83
|
+
const fields = { status: finalStatus };
|
|
84
|
+
if (summary) {
|
|
85
|
+
fields.raw_output = summary;
|
|
86
|
+
fields.content = [{ type: "content", content: { type: "text", text: summary } }];
|
|
87
|
+
}
|
|
88
|
+
emitSessionUpdate(session.sessionId, {
|
|
89
|
+
type: "tool_call_update",
|
|
90
|
+
tool_call_update: { tool_call_id: toolUseId, fields },
|
|
91
|
+
});
|
|
92
|
+
toolCall.status = finalStatus;
|
|
93
|
+
if (taskId) {
|
|
94
|
+
session.taskToolUseIds.delete(taskId);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
export function handleContentBlock(session, block) {
|
|
98
|
+
const blockType = typeof block.type === "string" ? block.type : "";
|
|
99
|
+
if (blockType === "text") {
|
|
100
|
+
const text = typeof block.text === "string" ? block.text : "";
|
|
101
|
+
if (text) {
|
|
102
|
+
emitSessionUpdate(session.sessionId, { type: "agent_message_chunk", content: { type: "text", text } });
|
|
103
|
+
}
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (blockType === "thinking") {
|
|
107
|
+
const text = typeof block.thinking === "string" ? block.thinking : "";
|
|
108
|
+
if (text) {
|
|
109
|
+
emitSessionUpdate(session.sessionId, { type: "agent_thought_chunk", content: { type: "text", text } });
|
|
110
|
+
}
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
if (blockType === "tool_use" || blockType === "server_tool_use" || blockType === "mcp_tool_use") {
|
|
114
|
+
const toolUseId = typeof block.id === "string" ? block.id : "";
|
|
115
|
+
const name = typeof block.name === "string" ? block.name : "Tool";
|
|
116
|
+
const input = block.input && typeof block.input === "object" ? block.input : {};
|
|
117
|
+
if (!toolUseId) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
emitPlanIfTodoWrite(session, name, input);
|
|
121
|
+
emitToolCall(session, toolUseId, name, input);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (TOOL_RESULT_TYPES.has(blockType)) {
|
|
125
|
+
const toolUseId = typeof block.tool_use_id === "string" ? block.tool_use_id : "";
|
|
126
|
+
if (!toolUseId) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
const isError = Boolean(block.is_error);
|
|
130
|
+
emitToolResultUpdate(session, toolUseId, isError, block.content);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
export function handleStreamEvent(session, event) {
|
|
134
|
+
const eventType = typeof event.type === "string" ? event.type : "";
|
|
135
|
+
if (eventType === "content_block_start") {
|
|
136
|
+
if (event.content_block && typeof event.content_block === "object") {
|
|
137
|
+
handleContentBlock(session, event.content_block);
|
|
138
|
+
}
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
if (eventType === "content_block_delta") {
|
|
142
|
+
if (!event.delta || typeof event.delta !== "object") {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
const delta = event.delta;
|
|
146
|
+
const deltaType = typeof delta.type === "string" ? delta.type : "";
|
|
147
|
+
if (deltaType === "text_delta") {
|
|
148
|
+
const text = typeof delta.text === "string" ? delta.text : "";
|
|
149
|
+
if (text) {
|
|
150
|
+
emitSessionUpdate(session.sessionId, { type: "agent_message_chunk", content: { type: "text", text } });
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
else if (deltaType === "thinking_delta") {
|
|
154
|
+
const text = typeof delta.thinking === "string" ? delta.thinking : "";
|
|
155
|
+
if (text) {
|
|
156
|
+
emitSessionUpdate(session.sessionId, { type: "agent_thought_chunk", content: { type: "text", text } });
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
export function handleAssistantMessage(session, message) {
|
|
162
|
+
const assistantError = typeof message.error === "string" ? message.error : "";
|
|
163
|
+
if (assistantError.length > 0) {
|
|
164
|
+
session.lastAssistantError = assistantError;
|
|
165
|
+
}
|
|
166
|
+
const messageObject = message.message && typeof message.message === "object"
|
|
167
|
+
? message.message
|
|
168
|
+
: null;
|
|
169
|
+
if (!messageObject) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
const content = Array.isArray(messageObject.content) ? messageObject.content : [];
|
|
173
|
+
for (const block of content) {
|
|
174
|
+
if (!block || typeof block !== "object") {
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
const blockRecord = block;
|
|
178
|
+
const blockType = typeof blockRecord.type === "string" ? blockRecord.type : "";
|
|
179
|
+
if (blockType === "tool_use" ||
|
|
180
|
+
blockType === "server_tool_use" ||
|
|
181
|
+
blockType === "mcp_tool_use" ||
|
|
182
|
+
TOOL_RESULT_TYPES.has(blockType)) {
|
|
183
|
+
handleContentBlock(session, blockRecord);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
export function handleUserToolResultBlocks(session, message) {
|
|
188
|
+
const messageObject = message.message && typeof message.message === "object"
|
|
189
|
+
? message.message
|
|
190
|
+
: null;
|
|
191
|
+
if (!messageObject) {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
const content = Array.isArray(messageObject.content) ? messageObject.content : [];
|
|
195
|
+
for (const block of content) {
|
|
196
|
+
if (!block || typeof block !== "object") {
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
const blockRecord = block;
|
|
200
|
+
const blockType = typeof blockRecord.type === "string" ? blockRecord.type : "";
|
|
201
|
+
if (TOOL_RESULT_TYPES.has(blockType)) {
|
|
202
|
+
handleContentBlock(session, blockRecord);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
export function handleResultMessage(session, message) {
|
|
207
|
+
emitFastModeUpdateIfChanged(session, message.fast_mode_state);
|
|
208
|
+
const subtype = typeof message.subtype === "string" ? message.subtype : "";
|
|
209
|
+
if (subtype === "success") {
|
|
210
|
+
session.lastAssistantError = undefined;
|
|
211
|
+
finalizeOpenToolCalls(session, "completed");
|
|
212
|
+
writeEvent({ event: "turn_complete", session_id: session.sessionId });
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
const errors = Array.isArray(message.errors) && message.errors.every((entry) => typeof entry === "string")
|
|
216
|
+
? message.errors
|
|
217
|
+
: [];
|
|
218
|
+
const assistantError = session.lastAssistantError;
|
|
219
|
+
const authHint = errors.find((entry) => looksLikeAuthRequired(entry));
|
|
220
|
+
if (authHint) {
|
|
221
|
+
emitAuthRequired(session, authHint);
|
|
222
|
+
}
|
|
223
|
+
if (assistantError === "authentication_failed") {
|
|
224
|
+
emitAuthRequired(session);
|
|
225
|
+
}
|
|
226
|
+
finalizeOpenToolCalls(session, "failed");
|
|
227
|
+
const errorKind = classifyTurnErrorKind(subtype, errors, assistantError);
|
|
228
|
+
const fallback = subtype ? `turn failed: ${subtype}` : "turn failed";
|
|
229
|
+
writeEvent({
|
|
230
|
+
event: "turn_error",
|
|
231
|
+
session_id: session.sessionId,
|
|
232
|
+
message: errors.length > 0 ? errors.join("\n") : fallback,
|
|
233
|
+
error_kind: errorKind,
|
|
234
|
+
...(subtype ? { sdk_result_subtype: subtype } : {}),
|
|
235
|
+
...(assistantError ? { assistant_error: assistantError } : {}),
|
|
236
|
+
});
|
|
237
|
+
session.lastAssistantError = undefined;
|
|
238
|
+
}
|
|
239
|
+
export function handleSdkMessage(session, message) {
|
|
240
|
+
const msg = message;
|
|
241
|
+
const type = typeof msg.type === "string" ? msg.type : "";
|
|
242
|
+
if (type === "system") {
|
|
243
|
+
const subtype = typeof msg.subtype === "string" ? msg.subtype : "";
|
|
244
|
+
if (subtype === "init") {
|
|
245
|
+
const previousSessionId = session.sessionId;
|
|
246
|
+
const incomingSessionId = typeof msg.session_id === "string" ? msg.session_id : session.sessionId;
|
|
247
|
+
updateSessionId(session, incomingSessionId);
|
|
248
|
+
const previousModelName = session.model;
|
|
249
|
+
const modelName = typeof msg.model === "string" ? msg.model : session.model;
|
|
250
|
+
session.model = modelName;
|
|
251
|
+
const incomingMode = typeof msg.permissionMode === "string" ? toPermissionMode(msg.permissionMode) : null;
|
|
252
|
+
if (incomingMode) {
|
|
253
|
+
session.mode = incomingMode;
|
|
254
|
+
}
|
|
255
|
+
emitFastModeUpdateIfChanged(session, msg.fast_mode_state);
|
|
256
|
+
if (!session.connected) {
|
|
257
|
+
emitConnectEvent(session);
|
|
258
|
+
}
|
|
259
|
+
else if (previousSessionId !== session.sessionId) {
|
|
260
|
+
const historyUpdates = session.resumeUpdates;
|
|
261
|
+
writeEvent({
|
|
262
|
+
event: "session_replaced",
|
|
263
|
+
session_id: session.sessionId,
|
|
264
|
+
cwd: session.cwd,
|
|
265
|
+
model_name: session.model,
|
|
266
|
+
available_models: session.availableModels,
|
|
267
|
+
mode: session.mode ? buildModeState(session.mode) : null,
|
|
268
|
+
...(historyUpdates && historyUpdates.length > 0
|
|
269
|
+
? { history_updates: historyUpdates }
|
|
270
|
+
: {}),
|
|
271
|
+
});
|
|
272
|
+
session.resumeUpdates = undefined;
|
|
273
|
+
refreshSessionsList();
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
if (session.model !== previousModelName) {
|
|
277
|
+
emitSessionUpdate(session.sessionId, {
|
|
278
|
+
type: "config_option_update",
|
|
279
|
+
option_id: "model",
|
|
280
|
+
value: session.model,
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
if (incomingMode) {
|
|
284
|
+
emitSessionUpdate(session.sessionId, {
|
|
285
|
+
type: "mode_state_update",
|
|
286
|
+
mode: buildModeState(incomingMode),
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
if (Array.isArray(msg.slash_commands)) {
|
|
291
|
+
const commands = msg.slash_commands
|
|
292
|
+
.filter((entry) => typeof entry === "string")
|
|
293
|
+
.map((name) => ({ name, description: "", input_hint: undefined }));
|
|
294
|
+
if (commands.length > 0) {
|
|
295
|
+
emitSessionUpdate(session.sessionId, { type: "available_commands_update", commands });
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
if (session.lastAvailableAgentsSignature === undefined && Array.isArray(msg.agents)) {
|
|
299
|
+
emitAvailableAgentsIfChanged(session, mapAvailableAgentsFromNames(msg.agents));
|
|
300
|
+
}
|
|
301
|
+
void session.query
|
|
302
|
+
.supportedCommands()
|
|
303
|
+
.then((commands) => {
|
|
304
|
+
const mapped = commands.map((command) => ({
|
|
305
|
+
name: command.name,
|
|
306
|
+
description: command.description ?? "",
|
|
307
|
+
input_hint: command.argumentHint ?? undefined,
|
|
308
|
+
}));
|
|
309
|
+
emitSessionUpdate(session.sessionId, { type: "available_commands_update", commands: mapped });
|
|
310
|
+
})
|
|
311
|
+
.catch(() => {
|
|
312
|
+
// Best-effort only; slash commands from init were already emitted.
|
|
313
|
+
});
|
|
314
|
+
refreshAvailableAgents(session);
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
if (subtype === "status") {
|
|
318
|
+
const mode = typeof msg.permissionMode === "string" ? toPermissionMode(msg.permissionMode) : null;
|
|
319
|
+
if (mode) {
|
|
320
|
+
session.mode = mode;
|
|
321
|
+
emitSessionUpdate(session.sessionId, { type: "current_mode_update", current_mode_id: mode });
|
|
322
|
+
}
|
|
323
|
+
if (msg.status === "compacting") {
|
|
324
|
+
emitSessionUpdate(session.sessionId, { type: "session_status_update", status: "compacting" });
|
|
325
|
+
}
|
|
326
|
+
else if (msg.status === null) {
|
|
327
|
+
emitSessionUpdate(session.sessionId, { type: "session_status_update", status: "idle" });
|
|
328
|
+
}
|
|
329
|
+
emitFastModeUpdateIfChanged(session, msg.fast_mode_state);
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
if (subtype === "compact_boundary") {
|
|
333
|
+
const compactMetadata = asRecordOrNull(msg.compact_metadata);
|
|
334
|
+
if (!compactMetadata) {
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
const trigger = compactMetadata.trigger;
|
|
338
|
+
const preTokens = numberField(compactMetadata, "pre_tokens", "preTokens");
|
|
339
|
+
if ((trigger === "manual" || trigger === "auto") && preTokens !== undefined) {
|
|
340
|
+
emitSessionUpdate(session.sessionId, {
|
|
341
|
+
type: "compaction_boundary",
|
|
342
|
+
trigger,
|
|
343
|
+
pre_tokens: preTokens,
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
if (subtype === "local_command_output") {
|
|
349
|
+
const content = typeof msg.content === "string" ? msg.content : "";
|
|
350
|
+
if (content.trim().length > 0) {
|
|
351
|
+
emitSessionUpdate(session.sessionId, {
|
|
352
|
+
type: "agent_message_chunk",
|
|
353
|
+
content: { type: "text", text: content },
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
if (subtype === "elicitation_complete") {
|
|
359
|
+
// No-op: elicitation flow is auto-canceled in the onElicitation callback.
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
handleTaskSystemMessage(session, subtype, msg);
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
if (type === "auth_status") {
|
|
366
|
+
const output = Array.isArray(msg.output)
|
|
367
|
+
? msg.output.filter((entry) => typeof entry === "string").join("\n")
|
|
368
|
+
: "";
|
|
369
|
+
const errorText = typeof msg.error === "string" ? msg.error : "";
|
|
370
|
+
const combined = [errorText, output].filter((entry) => entry.length > 0).join("\n");
|
|
371
|
+
if (combined && looksLikeAuthRequired(combined)) {
|
|
372
|
+
emitAuthRequired(session, combined);
|
|
373
|
+
}
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
if (type === "stream_event") {
|
|
377
|
+
if (msg.event && typeof msg.event === "object") {
|
|
378
|
+
handleStreamEvent(session, msg.event);
|
|
379
|
+
}
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
if (type === "tool_progress") {
|
|
383
|
+
const toolUseId = typeof msg.tool_use_id === "string" ? msg.tool_use_id : "";
|
|
384
|
+
const toolName = typeof msg.tool_name === "string" ? msg.tool_name : "Tool";
|
|
385
|
+
if (toolUseId) {
|
|
386
|
+
emitToolProgressUpdate(session, toolUseId, toolName);
|
|
387
|
+
}
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
if (type === "tool_use_summary") {
|
|
391
|
+
const summary = typeof msg.summary === "string" ? msg.summary : "";
|
|
392
|
+
const toolIds = Array.isArray(msg.preceding_tool_use_ids)
|
|
393
|
+
? msg.preceding_tool_use_ids.filter((id) => typeof id === "string")
|
|
394
|
+
: [];
|
|
395
|
+
if (summary && toolIds.length > 0) {
|
|
396
|
+
for (const toolUseId of toolIds) {
|
|
397
|
+
emitToolSummaryUpdate(session, toolUseId, summary);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
if (type === "rate_limit_event") {
|
|
403
|
+
const update = buildRateLimitUpdate(msg.rate_limit_info);
|
|
404
|
+
if (update) {
|
|
405
|
+
emitSessionUpdate(session.sessionId, update);
|
|
406
|
+
}
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
if (type === "user") {
|
|
410
|
+
handleUserToolResultBlocks(session, msg);
|
|
411
|
+
const toolUseId = typeof msg.parent_tool_use_id === "string" ? msg.parent_tool_use_id : "";
|
|
412
|
+
if (toolUseId && "tool_use_result" in msg) {
|
|
413
|
+
const parsed = unwrapToolUseResult(msg.tool_use_result);
|
|
414
|
+
emitToolResultUpdate(session, toolUseId, parsed.isError, parsed.content);
|
|
415
|
+
}
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
if (type === "assistant") {
|
|
419
|
+
if (msg.error === "authentication_failed") {
|
|
420
|
+
emitAuthRequired(session);
|
|
421
|
+
}
|
|
422
|
+
handleAssistantMessage(session, msg);
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
if (type === "result") {
|
|
426
|
+
handleResultMessage(session, msg);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
@@ -83,12 +83,24 @@ export function permissionResultFromOutcome(outcome, toolCallId, inputData, sugg
|
|
|
83
83
|
};
|
|
84
84
|
}
|
|
85
85
|
if (outcome.option_id === "allow_always") {
|
|
86
|
-
const
|
|
86
|
+
const persistentSuggestions = scopedSuggestions.persistent;
|
|
87
|
+
const fallbackSuggestions = persistentSuggestions.length > 0
|
|
88
|
+
? persistentSuggestions
|
|
89
|
+
: toolName
|
|
90
|
+
? [
|
|
91
|
+
{
|
|
92
|
+
type: "addRules",
|
|
93
|
+
rules: [{ toolName }],
|
|
94
|
+
behavior: "allow",
|
|
95
|
+
destination: "localSettings",
|
|
96
|
+
},
|
|
97
|
+
]
|
|
98
|
+
: undefined;
|
|
87
99
|
return {
|
|
88
100
|
behavior: "allow",
|
|
89
101
|
updatedInput: inputData,
|
|
90
|
-
...(
|
|
91
|
-
? { updatedPermissions:
|
|
102
|
+
...(fallbackSuggestions && fallbackSuggestions.length > 0
|
|
103
|
+
? { updatedPermissions: fallbackSuggestions }
|
|
92
104
|
: {}),
|
|
93
105
|
toolUseID: toolCallId,
|
|
94
106
|
};
|