claude-code-rust 0.9.0 → 0.10.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 +9 -3
- package/agent-sdk/dist/bridge/events.js +116 -8
- package/agent-sdk/dist/bridge/logger.js +245 -0
- package/agent-sdk/dist/bridge/mcp.js +81 -5
- package/agent-sdk/dist/bridge/message_handlers.js +87 -48
- package/agent-sdk/dist/bridge/session_lifecycle.js +385 -51
- package/agent-sdk/dist/bridge/shared.js +0 -7
- package/agent-sdk/dist/bridge/tool_calls.js +174 -59
- package/agent-sdk/dist/bridge/user_interaction.js +34 -23
- package/agent-sdk/dist/bridge.js +203 -21
- package/package.json +1 -1
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { asRecordOrNull } from "./shared.js";
|
|
2
2
|
import { toPermissionMode, buildModeState } from "./commands.js";
|
|
3
|
-
import { writeEvent, emitSessionUpdate, emitConnectEvent,
|
|
3
|
+
import { writeEvent, emitSessionUpdate, emitConnectEvent, emitSessionReplacedEvent, } from "./events.js";
|
|
4
4
|
import { TOOL_RESULT_TYPES, unwrapToolUseResult } from "./tooling.js";
|
|
5
|
-
import { emitToolCall, emitPlanIfTodoWrite, emitToolResultUpdate, finalizeOpenToolCalls, emitToolProgressUpdate, emitToolSummaryUpdate, ensureToolCallVisible, resolveTaskToolUseId, taskProgressText, } from "./tool_calls.js";
|
|
5
|
+
import { emitToolCall, emitToolCallUpdate, emitPlanIfTodoWrite, emitToolResultUpdate, finalizeOpenToolCalls, emitToolProgressUpdate, emitToolSummaryUpdate, ensureToolCallVisible, resolveTaskToolUseId, taskProgressText, } from "./tool_calls.js";
|
|
6
6
|
import { emitAuthRequired, classifyTurnErrorKind, emitFastModeUpdateIfChanged } from "./error_classification.js";
|
|
7
7
|
import { mapAvailableAgentsFromNames, emitAvailableAgentsIfChanged, refreshAvailableAgents } from "./agents.js";
|
|
8
8
|
import { buildRateLimitUpdate, numberField } from "./state_parsing.js";
|
|
9
9
|
import { looksLikeAuthRequired } from "./auth.js";
|
|
10
10
|
import { updateSessionId } from "./session_lifecycle.js";
|
|
11
|
+
import { bridgeLogger, LOG_TARGETS } from "./logger.js";
|
|
11
12
|
export function textFromPrompt(command) {
|
|
12
13
|
const chunks = command.chunks ?? [];
|
|
13
14
|
return chunks
|
|
@@ -20,6 +21,77 @@ export function textFromPrompt(command) {
|
|
|
20
21
|
.filter((part) => part.length > 0)
|
|
21
22
|
.join("");
|
|
22
23
|
}
|
|
24
|
+
/** MIME types supported by the Anthropic Vision API.
|
|
25
|
+
* NOTE: Keep in sync with `SUPPORTED_IMAGE_MIME_TYPES` in
|
|
26
|
+
* `src/app/clipboard_image.rs`. */
|
|
27
|
+
const SUPPORTED_IMAGE_MIME_TYPES = new Set([
|
|
28
|
+
"image/png",
|
|
29
|
+
"image/jpeg",
|
|
30
|
+
"image/gif",
|
|
31
|
+
"image/webp",
|
|
32
|
+
]);
|
|
33
|
+
/** Fast check that a string looks like valid base64 (non-empty, correct charset & padding). */
|
|
34
|
+
function isValidBase64(data) {
|
|
35
|
+
if (!data)
|
|
36
|
+
return false;
|
|
37
|
+
const clean = data.replace(/\s/g, "");
|
|
38
|
+
if (clean.length % 4 !== 0)
|
|
39
|
+
return false;
|
|
40
|
+
// Padding ('=') must only appear at the end and be at most 2 characters.
|
|
41
|
+
return /^[A-Za-z0-9+/]+={0,2}$/.test(clean);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Build a content array from prompt chunks, supporting both text and image blocks.
|
|
45
|
+
* Returns the Anthropic API content block format expected by MessageParam.
|
|
46
|
+
*/
|
|
47
|
+
export function contentFromPrompt(command) {
|
|
48
|
+
const chunks = command.chunks ?? [];
|
|
49
|
+
const content = [];
|
|
50
|
+
for (const chunk of chunks) {
|
|
51
|
+
if (chunk.kind === "text") {
|
|
52
|
+
const text = typeof chunk.value === "string" ? chunk.value : "";
|
|
53
|
+
if (text.trim()) {
|
|
54
|
+
content.push({ type: "text", text });
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
else if (chunk.kind === "image") {
|
|
58
|
+
const val = chunk.value && typeof chunk.value === "object" ? chunk.value : null;
|
|
59
|
+
if (!val)
|
|
60
|
+
continue;
|
|
61
|
+
const data = typeof val.data === "string" ? val.data : "";
|
|
62
|
+
const mimeType = typeof val.mime_type === "string" ? val.mime_type : "image/png";
|
|
63
|
+
if (!SUPPORTED_IMAGE_MIME_TYPES.has(mimeType)) {
|
|
64
|
+
bridgeLogger.warn({
|
|
65
|
+
target: LOG_TARGETS.BRIDGE_PROTOCOL,
|
|
66
|
+
eventName: "prompt_image_skipped",
|
|
67
|
+
message: "skipping unsupported prompt image type",
|
|
68
|
+
outcome: "skipped",
|
|
69
|
+
fields: { mime_type: mimeType },
|
|
70
|
+
});
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
if (!isValidBase64(data)) {
|
|
74
|
+
bridgeLogger.warn({
|
|
75
|
+
target: LOG_TARGETS.BRIDGE_PROTOCOL,
|
|
76
|
+
eventName: "prompt_image_skipped",
|
|
77
|
+
message: "skipping prompt image with invalid base64 data",
|
|
78
|
+
outcome: "skipped",
|
|
79
|
+
fields: { mime_type: mimeType, reason: "invalid_base64" },
|
|
80
|
+
});
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
content.push({
|
|
84
|
+
type: "image",
|
|
85
|
+
source: {
|
|
86
|
+
type: "base64",
|
|
87
|
+
media_type: mimeType,
|
|
88
|
+
data,
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return content;
|
|
94
|
+
}
|
|
23
95
|
export function handleTaskSystemMessage(session, subtype, msg) {
|
|
24
96
|
if (subtype !== "task_started" && subtype !== "task_progress" && subtype !== "task_notification") {
|
|
25
97
|
return;
|
|
@@ -35,28 +107,18 @@ export function handleTaskSystemMessage(session, subtype, msg) {
|
|
|
35
107
|
}
|
|
36
108
|
const toolCall = ensureToolCallVisible(session, toolUseId, "Agent", {});
|
|
37
109
|
if (toolCall.status === "pending") {
|
|
38
|
-
|
|
39
|
-
emitSessionUpdate(session.sessionId, {
|
|
40
|
-
type: "tool_call_update",
|
|
41
|
-
tool_call_update: { tool_call_id: toolUseId, fields: { status: "in_progress" } },
|
|
42
|
-
});
|
|
110
|
+
emitToolCallUpdate(session, toolUseId, { status: "in_progress" }, "progress");
|
|
43
111
|
}
|
|
44
112
|
if (subtype === "task_started") {
|
|
45
113
|
const description = typeof msg.description === "string" ? msg.description : "";
|
|
46
114
|
if (!description) {
|
|
47
115
|
return;
|
|
48
116
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
status: "in_progress",
|
|
55
|
-
raw_output: description,
|
|
56
|
-
content: [{ type: "content", content: { type: "text", text: description } }],
|
|
57
|
-
},
|
|
58
|
-
},
|
|
59
|
-
});
|
|
117
|
+
emitToolCallUpdate(session, toolUseId, {
|
|
118
|
+
status: "in_progress",
|
|
119
|
+
raw_output: description,
|
|
120
|
+
content: [{ type: "content", content: { type: "text", text: description } }],
|
|
121
|
+
}, "task_started");
|
|
60
122
|
return;
|
|
61
123
|
}
|
|
62
124
|
if (subtype === "task_progress") {
|
|
@@ -64,17 +126,11 @@ export function handleTaskSystemMessage(session, subtype, msg) {
|
|
|
64
126
|
if (!progress) {
|
|
65
127
|
return;
|
|
66
128
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
status: "in_progress",
|
|
73
|
-
raw_output: progress,
|
|
74
|
-
content: [{ type: "content", content: { type: "text", text: progress } }],
|
|
75
|
-
},
|
|
76
|
-
},
|
|
77
|
-
});
|
|
129
|
+
emitToolCallUpdate(session, toolUseId, {
|
|
130
|
+
status: "in_progress",
|
|
131
|
+
raw_output: progress,
|
|
132
|
+
content: [{ type: "content", content: { type: "text", text: progress } }],
|
|
133
|
+
}, "task_progress");
|
|
78
134
|
return;
|
|
79
135
|
}
|
|
80
136
|
const status = typeof msg.status === "string" ? msg.status : "";
|
|
@@ -85,11 +141,7 @@ export function handleTaskSystemMessage(session, subtype, msg) {
|
|
|
85
141
|
fields.raw_output = summary;
|
|
86
142
|
fields.content = [{ type: "content", content: { type: "text", text: summary } }];
|
|
87
143
|
}
|
|
88
|
-
|
|
89
|
-
type: "tool_call_update",
|
|
90
|
-
tool_call_update: { tool_call_id: toolUseId, fields },
|
|
91
|
-
});
|
|
92
|
-
toolCall.status = finalStatus;
|
|
144
|
+
emitToolCallUpdate(session, toolUseId, fields, "task_notification");
|
|
93
145
|
if (taskId) {
|
|
94
146
|
session.taskToolUseIds.delete(taskId);
|
|
95
147
|
}
|
|
@@ -257,20 +309,7 @@ export function handleSdkMessage(session, message) {
|
|
|
257
309
|
emitConnectEvent(session);
|
|
258
310
|
}
|
|
259
311
|
else if (previousSessionId !== session.sessionId) {
|
|
260
|
-
|
|
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();
|
|
312
|
+
emitSessionReplacedEvent(session);
|
|
274
313
|
}
|
|
275
314
|
else {
|
|
276
315
|
if (session.model !== previousModelName) {
|