claude-code-rust 0.14.1 → 0.14.3
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/agent-sdk/dist/bridge/available_commands.js +1 -1
- package/agent-sdk/dist/bridge/command_interactions.js +16 -0
- package/agent-sdk/dist/bridge/command_lifecycle.js +184 -0
- package/agent-sdk/dist/bridge/command_mcp.js +32 -0
- package/agent-sdk/dist/bridge/command_scheduler.js +136 -0
- package/agent-sdk/dist/bridge/command_session_control.js +269 -0
- package/agent-sdk/dist/bridge/command_session_data.js +203 -0
- package/agent-sdk/dist/bridge/commands.js +6 -0
- package/agent-sdk/dist/bridge/error_classification.js +24 -7
- package/agent-sdk/dist/bridge/events.js +42 -9
- package/agent-sdk/dist/bridge/history.js +7 -3
- package/agent-sdk/dist/bridge/logger.js +2 -0
- package/agent-sdk/dist/bridge/mcp.js +90 -80
- package/agent-sdk/dist/bridge/mcp_auth_adapter.js +67 -0
- package/agent-sdk/dist/bridge/mcp_monitor.js +59 -0
- package/agent-sdk/dist/bridge/message_handlers.js +61 -17
- package/agent-sdk/dist/bridge/session_lifecycle.js +54 -4
- package/agent-sdk/dist/bridge/state_parsing.js +8 -1
- package/agent-sdk/dist/bridge/tool_calls.js +12 -10
- package/agent-sdk/dist/bridge/tooling.js +183 -1
- package/agent-sdk/dist/bridge.js +118 -617
- package/package.json +8 -8
|
@@ -11,7 +11,7 @@ import { isToolSearchToolName } from "./tooling.js";
|
|
|
11
11
|
import { requestExitPlanModeApproval, requestAskUserQuestionAnswers, EXIT_PLAN_MODE_TOOL_NAME, ASK_USER_QUESTION_TOOL_NAME, } from "./user_interaction.js";
|
|
12
12
|
import { mapAvailableAgents, emitAvailableAgentsIfChanged, refreshAvailableAgents } from "./agents.js";
|
|
13
13
|
import { mapSdkSlashCommands, updateAvailableCommands, } from "./available_commands.js";
|
|
14
|
-
import { emitAuthRequired,
|
|
14
|
+
import { emitAuthRequired, emitFastModeUpdate, setFastModeSnapshotIfChanged, } from "./error_classification.js";
|
|
15
15
|
import { mapAvailableModels, resolveCurrentModel, currentModelsEqual, } from "./model_metadata.js";
|
|
16
16
|
import { shouldEmitStartupAuthRequiredForAccount } from "./account_metadata.js";
|
|
17
17
|
export { mapAvailableModels, resolveCurrentModel } from "./model_metadata.js";
|
|
@@ -34,6 +34,7 @@ function permissionDisplayFromCanUseOptions(options) {
|
|
|
34
34
|
};
|
|
35
35
|
}
|
|
36
36
|
export const sessions = new Map();
|
|
37
|
+
const pendingSessionCloseTasks = new Set();
|
|
37
38
|
const DEFAULT_SETTING_SOURCES = ["user", "project", "local"];
|
|
38
39
|
const DEFAULT_PERMISSION_MODE = "default";
|
|
39
40
|
function isSdkElicitationContentValue(value) {
|
|
@@ -134,7 +135,44 @@ export function updateSessionId(session, newSessionId) {
|
|
|
134
135
|
session.sessionId = newSessionId;
|
|
135
136
|
sessions.set(newSessionId, session);
|
|
136
137
|
}
|
|
138
|
+
export function beginSessionClose(session) {
|
|
139
|
+
session.closing = true;
|
|
140
|
+
for (const monitor of session.mcpAuthMonitors.values()) {
|
|
141
|
+
monitor.controller.abort();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
export function detachSessionForClose(session) {
|
|
145
|
+
beginSessionClose(session);
|
|
146
|
+
if (sessions.get(session.sessionId) === session) {
|
|
147
|
+
sessions.delete(session.sessionId);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
export function trackSessionCloseTask(task) {
|
|
151
|
+
const ownedTask = task.catch((error) => {
|
|
152
|
+
bridgeLogger.error({
|
|
153
|
+
target: LOG_TARGETS.APP_SESSION,
|
|
154
|
+
eventName: "session_close_task_failed",
|
|
155
|
+
message: "background session cleanup failed",
|
|
156
|
+
outcome: "failure",
|
|
157
|
+
fields: {
|
|
158
|
+
error_message: error instanceof Error ? error.message : String(error),
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
pendingSessionCloseTasks.add(ownedTask);
|
|
163
|
+
void ownedTask.then(() => {
|
|
164
|
+
pendingSessionCloseTasks.delete(ownedTask);
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
async function waitForPendingSessionCloseTasks() {
|
|
168
|
+
while (pendingSessionCloseTasks.size > 0) {
|
|
169
|
+
await Promise.all(Array.from(pendingSessionCloseTasks));
|
|
170
|
+
}
|
|
171
|
+
}
|
|
137
172
|
export async function closeSession(session) {
|
|
173
|
+
beginSessionClose(session);
|
|
174
|
+
const mcpAuthMonitors = Array.from(session.mcpAuthMonitors.values());
|
|
175
|
+
session.mcpAuthMonitors.clear();
|
|
138
176
|
session.input.close();
|
|
139
177
|
session.query.close();
|
|
140
178
|
for (const pending of session.pendingPermissions.values()) {
|
|
@@ -154,6 +192,11 @@ export async function closeSession(session) {
|
|
|
154
192
|
pending.resolve({ action: "cancel" });
|
|
155
193
|
}
|
|
156
194
|
session.pendingElicitations.clear();
|
|
195
|
+
await Promise.all([
|
|
196
|
+
session.initializationTask,
|
|
197
|
+
session.queryConsumerTask,
|
|
198
|
+
...mcpAuthMonitors.map((monitor) => monitor.task),
|
|
199
|
+
].filter((task) => task !== undefined));
|
|
157
200
|
}
|
|
158
201
|
export async function closeSessionWithLogging(session, options = {}) {
|
|
159
202
|
await closeSession(session);
|
|
@@ -191,6 +234,7 @@ export async function closeAllSessions(options = {}) {
|
|
|
191
234
|
reason: options.reason ?? "bulk_close",
|
|
192
235
|
requestId: options.requestId,
|
|
193
236
|
})));
|
|
237
|
+
await waitForPendingSessionCloseTasks();
|
|
194
238
|
bridgeLogger.info({
|
|
195
239
|
target: LOG_TARGETS.APP_SESSION,
|
|
196
240
|
eventName: "all_sessions_closed",
|
|
@@ -335,6 +379,7 @@ export async function createSession(params) {
|
|
|
335
379
|
query: queryHandle,
|
|
336
380
|
input,
|
|
337
381
|
connected: false,
|
|
382
|
+
closing: false,
|
|
338
383
|
connectEvent: params.connectEvent,
|
|
339
384
|
connectRequestId: params.requestId,
|
|
340
385
|
toolCalls: new Map(),
|
|
@@ -347,7 +392,9 @@ export async function createSession(params) {
|
|
|
347
392
|
pendingUserDialogs: new Map(),
|
|
348
393
|
pendingElicitations: new Map(),
|
|
349
394
|
informationalDedupKeys: new Set(),
|
|
395
|
+
knownConnectedMcpServers: new Set(),
|
|
350
396
|
mcpStatusRevalidatedAt: new Map(),
|
|
397
|
+
mcpAuthMonitors: new Map(),
|
|
351
398
|
hiddenToolUseIds: new Set(),
|
|
352
399
|
authHintSent: false,
|
|
353
400
|
...(params.resumeUpdates && params.resumeUpdates.length > 0
|
|
@@ -396,7 +443,7 @@ export async function createSession(params) {
|
|
|
396
443
|
// In stream-input mode the SDK may defer init until input arrives.
|
|
397
444
|
// Trigger initialization explicitly so the Rust UI can receive `connected`
|
|
398
445
|
// before the first user prompt.
|
|
399
|
-
|
|
446
|
+
session.initializationTask = session.query
|
|
400
447
|
.initializationResult()
|
|
401
448
|
.then(async (result) => {
|
|
402
449
|
bridgeLogger.info({
|
|
@@ -416,6 +463,7 @@ export async function createSession(params) {
|
|
|
416
463
|
const currentModelChanged = refreshCurrentModel(session);
|
|
417
464
|
const { buildModeState, refreshSupportedModesForSession } = await import("./commands.js");
|
|
418
465
|
refreshSupportedModesForSession(session);
|
|
466
|
+
const fastModeChanged = setFastModeSnapshotIfChanged(session, result.fast_mode_state, result.fast_mode_disabled_reason);
|
|
419
467
|
if (!session.connected) {
|
|
420
468
|
emitConnectEvent(session);
|
|
421
469
|
}
|
|
@@ -429,13 +477,15 @@ export async function createSession(params) {
|
|
|
429
477
|
mode: buildModeState(session, session.mode),
|
|
430
478
|
});
|
|
431
479
|
}
|
|
480
|
+
if (fastModeChanged) {
|
|
481
|
+
emitFastModeUpdate(session);
|
|
482
|
+
}
|
|
432
483
|
}
|
|
433
484
|
// Proactively detect missing auth from account info so the UI can
|
|
434
485
|
// show the login hint immediately, without waiting for the first prompt.
|
|
435
486
|
if (shouldEmitStartupAuthRequiredForAccount(result.account)) {
|
|
436
487
|
emitAuthRequired(session);
|
|
437
488
|
}
|
|
438
|
-
emitFastModeUpdateIfChanged(session, result.fast_mode_state);
|
|
439
489
|
updateAvailableCommands(session, "session_result_commands", mapSdkSlashCommands(result.commands));
|
|
440
490
|
emitAvailableAgentsIfChanged(session, mapAvailableAgents(result.agents));
|
|
441
491
|
refreshAvailableAgents(session);
|
|
@@ -457,7 +507,7 @@ export async function createSession(params) {
|
|
|
457
507
|
failConnection(`agent initialization failed: ${message}`, session.connectRequestId);
|
|
458
508
|
session.connectRequestId = undefined;
|
|
459
509
|
});
|
|
460
|
-
|
|
510
|
+
session.queryConsumerTask = (async () => {
|
|
461
511
|
try {
|
|
462
512
|
for await (const message of session.query) {
|
|
463
513
|
// Lazy import to break circular dependency at module-evaluation time.
|
|
@@ -15,7 +15,7 @@ function nonNegativeNumberField(record, ...keys) {
|
|
|
15
15
|
}
|
|
16
16
|
return value;
|
|
17
17
|
}
|
|
18
|
-
function nonNegativeIntegerField(record, ...keys) {
|
|
18
|
+
export function nonNegativeIntegerField(record, ...keys) {
|
|
19
19
|
const value = numberField(record, ...keys);
|
|
20
20
|
return value !== undefined && value >= 0 && Number.isInteger(value) ? value : undefined;
|
|
21
21
|
}
|
|
@@ -49,6 +49,13 @@ export function parseFastModeState(value) {
|
|
|
49
49
|
}
|
|
50
50
|
return null;
|
|
51
51
|
}
|
|
52
|
+
export function parseFastModeDisabledReason(value) {
|
|
53
|
+
if (typeof value !== "string") {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
const reason = value.trim();
|
|
57
|
+
return reason.length > 0 ? reason : undefined;
|
|
58
|
+
}
|
|
52
59
|
export function parseRateLimitStatus(value) {
|
|
53
60
|
if (value === "allowed" || value === "allowed_warning" || value === "rejected") {
|
|
54
61
|
return value;
|
|
@@ -3,7 +3,7 @@ import { bridgeLogger, LOG_TARGETS } from "./logger.js";
|
|
|
3
3
|
import { asRecordOrNull } from "./shared.js";
|
|
4
4
|
import { applyTaskToolResult } from "./tasks.js";
|
|
5
5
|
import { activeTaskIdForToolUse, linkTaskToolUse, unlinkTaskToolUse } from "./task_links.js";
|
|
6
|
-
import { backgroundToolLaunchTaskIdFromResult, buildToolResultFields, createToolCall, } from "./tooling.js";
|
|
6
|
+
import { applyToolNonExecutionMetadata, backgroundToolLaunchTaskIdFromResult, buildToolResultFields, createToolCall, } from "./tooling.js";
|
|
7
7
|
const TOOL_SUMMARY_TOOL_NAMES = new Set(["Agent", "Task", "WebSearch", "WebFetch", "ExitPlanMode"]);
|
|
8
8
|
const TASK_LIFECYCLE_TOOL_NAMES = new Set(["Agent", "Task", "Monitor", "Workflow"]);
|
|
9
9
|
function jsonSize(value) {
|
|
@@ -308,18 +308,19 @@ export function ensureToolCallVisible(session, toolUseId, toolName, input, paren
|
|
|
308
308
|
emitInitialToolCall(session, toolCall);
|
|
309
309
|
return toolCall;
|
|
310
310
|
}
|
|
311
|
-
export function emitToolResultUpdate(session, toolUseId, isError, rawContent, rawResult = rawContent, sourceMessageUuid) {
|
|
311
|
+
export function emitToolResultUpdate(session, toolUseId, isError, rawContent, rawResult = rawContent, sourceMessageUuid, nonExecutionMetadata) {
|
|
312
312
|
const base = session.toolCalls.get(toolUseId);
|
|
313
313
|
const baseToolName = toolNameFromMeta(base?.meta) ?? "";
|
|
314
314
|
const fields = buildToolResultFields(isError, rawContent, base, rawResult, taskTitleContext(session, baseToolName, asRecordOrNull(base?.raw_input) ?? {}));
|
|
315
|
-
|
|
315
|
+
applyToolNonExecutionMetadata(fields, nonExecutionMetadata);
|
|
316
|
+
if (!isError && !nonExecutionMetadata) {
|
|
316
317
|
const taskId = backgroundToolLaunchTaskIdFromResult(baseToolName, rawResult, rawContent);
|
|
317
318
|
if (taskId) {
|
|
318
319
|
linkTaskToolUse(session, taskId, toolUseId);
|
|
319
320
|
}
|
|
320
321
|
}
|
|
321
322
|
emitToolCallUpdate(session, toolUseId, fields, "result", sourceMessageUuid);
|
|
322
|
-
applyTaskToolResult(session, toolUseId, isError, rawContent, rawResult);
|
|
323
|
+
applyTaskToolResult(session, toolUseId, isError || nonExecutionMetadata !== undefined, rawContent, rawResult);
|
|
323
324
|
if (baseToolName === "Agent" || baseToolName === "Task") {
|
|
324
325
|
const taskId = activeTaskIdForToolUse(session, toolUseId);
|
|
325
326
|
if (taskId) {
|
|
@@ -338,14 +339,15 @@ export function finalizeOpenToolCalls(session, status) {
|
|
|
338
339
|
emitToolCallUpdate(session, toolUseId, { status }, "finalize");
|
|
339
340
|
}
|
|
340
341
|
}
|
|
341
|
-
|
|
342
|
-
|
|
342
|
+
/**
|
|
343
|
+
* Apply advisory progress only to a tool created by an authoritative tool-use event.
|
|
344
|
+
*/
|
|
345
|
+
export function emitToolProgressUpdate(session, toolUseId, progress = {}) {
|
|
346
|
+
const existing = session.toolCalls.get(toolUseId);
|
|
343
347
|
if (!existing) {
|
|
344
|
-
|
|
345
|
-
existing = session.toolCalls.get(toolUseId);
|
|
348
|
+
return;
|
|
346
349
|
}
|
|
347
|
-
if (
|
|
348
|
-
existing.status === "completed" ||
|
|
350
|
+
if (existing.status === "completed" ||
|
|
349
351
|
existing.status === "failed" ||
|
|
350
352
|
existing.status === "killed") {
|
|
351
353
|
return;
|
|
@@ -23,6 +23,19 @@ const WORKFLOW_TOOL_NAME = "Workflow";
|
|
|
23
23
|
const PROJECTS_TOOL_NAME = "Projects";
|
|
24
24
|
const ARTIFACT_TOOL_NAME = "Artifact";
|
|
25
25
|
const SHOW_ONBOARDING_ROLE_PICKER_TOOL_NAME = "ShowOnboardingRolePicker";
|
|
26
|
+
const SKILL_TOOL_NAME = "Skill";
|
|
27
|
+
const SKILL_WORD_OVERRIDES = {
|
|
28
|
+
api: "API",
|
|
29
|
+
ci: "CI",
|
|
30
|
+
cli: "CLI",
|
|
31
|
+
gh: "GH",
|
|
32
|
+
github: "GitHub",
|
|
33
|
+
mcp: "MCP",
|
|
34
|
+
pdf: "PDF",
|
|
35
|
+
sdk: "SDK",
|
|
36
|
+
ui: "UI",
|
|
37
|
+
ux: "UX",
|
|
38
|
+
};
|
|
26
39
|
const READ_MCP_RESOURCE_TOOL_NAME = "ReadMcpResource";
|
|
27
40
|
const READ_MCP_RESOURCE_DIR_TOOL_NAME = "ReadMcpResourceDir";
|
|
28
41
|
const SEARCH_OUTPUT_MODES = new Set(["content", "files_with_matches", "count"]);
|
|
@@ -183,6 +196,7 @@ export function normalizeToolKind(name) {
|
|
|
183
196
|
case "Projects":
|
|
184
197
|
case "Artifact":
|
|
185
198
|
case "ShowOnboardingRolePicker":
|
|
199
|
+
case SKILL_TOOL_NAME:
|
|
186
200
|
return "other";
|
|
187
201
|
case "Task":
|
|
188
202
|
case "Agent":
|
|
@@ -194,6 +208,34 @@ export function normalizeToolKind(name) {
|
|
|
194
208
|
return "think";
|
|
195
209
|
}
|
|
196
210
|
}
|
|
211
|
+
function skillDisplayName(rawName) {
|
|
212
|
+
const trimmed = rawName.trim();
|
|
213
|
+
const segments = trimmed.split(":");
|
|
214
|
+
if (segments.length > 2 ||
|
|
215
|
+
segments.some((segment) => !segment || !/^[a-zA-Z0-9]+(?:[-_][a-zA-Z0-9]+)*$/.test(segment))) {
|
|
216
|
+
return trimmed;
|
|
217
|
+
}
|
|
218
|
+
const displaySegments = segments.map((segment) => segment
|
|
219
|
+
.split(/[-_]/)
|
|
220
|
+
.map((word) => skillDisplayWord(word))
|
|
221
|
+
.join(" "));
|
|
222
|
+
if (displaySegments.length === 2 &&
|
|
223
|
+
displaySegments[0].toLowerCase() === displaySegments[1].toLowerCase()) {
|
|
224
|
+
return displaySegments[1];
|
|
225
|
+
}
|
|
226
|
+
return displaySegments.join(" / ");
|
|
227
|
+
}
|
|
228
|
+
function skillDisplayWord(word) {
|
|
229
|
+
const override = SKILL_WORD_OVERRIDES[word.toLowerCase()];
|
|
230
|
+
if (override) {
|
|
231
|
+
return override;
|
|
232
|
+
}
|
|
233
|
+
if (/^[A-Z0-9]+$/.test(word) ||
|
|
234
|
+
(/[a-z]/.test(word) && /[A-Z]/.test(word) && !/^[A-Z][a-z0-9]*$/.test(word))) {
|
|
235
|
+
return word;
|
|
236
|
+
}
|
|
237
|
+
return `${word.charAt(0).toUpperCase()}${word.slice(1).toLowerCase()}`;
|
|
238
|
+
}
|
|
197
239
|
export function toolTitle(name, input, context = {}) {
|
|
198
240
|
const agentTitle = agentInputTitle(name, input);
|
|
199
241
|
if (agentTitle) {
|
|
@@ -263,6 +305,12 @@ export function toolTitle(name, input, context = {}) {
|
|
|
263
305
|
if (name === SHOW_ONBOARDING_ROLE_PICKER_TOOL_NAME) {
|
|
264
306
|
return SHOW_ONBOARDING_ROLE_PICKER_TOOL_NAME;
|
|
265
307
|
}
|
|
308
|
+
if (name === SKILL_TOOL_NAME) {
|
|
309
|
+
const skillName = nonEmptyString(input.skill);
|
|
310
|
+
return skillName
|
|
311
|
+
? `${SKILL_TOOL_NAME}: ${skillDisplayName(skillName)}`
|
|
312
|
+
: SKILL_TOOL_NAME;
|
|
313
|
+
}
|
|
266
314
|
if (name === "EnterWorktree") {
|
|
267
315
|
const worktreeName = typeof input.name === "string" ? input.name.trim() : "";
|
|
268
316
|
return worktreeName || "EnterWorktree";
|
|
@@ -369,6 +417,17 @@ function resultRecordCandidates(rawResult, rawContent) {
|
|
|
369
417
|
pushNestedRecords(rawContent);
|
|
370
418
|
return candidates;
|
|
371
419
|
}
|
|
420
|
+
function imageReadResultText(rawResult, rawContent, rawInput) {
|
|
421
|
+
const isImage = resultRecordCandidates(rawResult, rawContent).some((candidate) => candidate.type === "image");
|
|
422
|
+
if (!isImage) {
|
|
423
|
+
return undefined;
|
|
424
|
+
}
|
|
425
|
+
const input = asRecordOrNull(rawInput);
|
|
426
|
+
const filePath = typeof input?.file_path === "string" ? input.file_path.trim() : "";
|
|
427
|
+
const normalizedPath = filePath.replaceAll("\\", "/");
|
|
428
|
+
const fileName = normalizedPath.slice(normalizedPath.lastIndexOf("/") + 1);
|
|
429
|
+
return fileName ? `Viewed Image ${fileName}` : "Viewed Image";
|
|
430
|
+
}
|
|
372
431
|
function parseJsonCandidate(value) {
|
|
373
432
|
const text = typeof value === "string" ? value : extractText(value);
|
|
374
433
|
const trimmed = text.trim();
|
|
@@ -528,7 +587,59 @@ function extractToolOutputMetadata(toolName, rawResult, rawContent) {
|
|
|
528
587
|
}
|
|
529
588
|
}
|
|
530
589
|
}
|
|
531
|
-
|
|
590
|
+
if (toolName === "Skill") {
|
|
591
|
+
for (const candidate of candidates) {
|
|
592
|
+
if (candidate.background === true) {
|
|
593
|
+
metadata.skill = { background: true };
|
|
594
|
+
break;
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
return metadata.bash || metadata.agent || metadata.web_fetch || metadata.skill
|
|
599
|
+
? metadata
|
|
600
|
+
: undefined;
|
|
601
|
+
}
|
|
602
|
+
export function parseToolNonExecutionMetadata(value) {
|
|
603
|
+
const byToolUseId = new Map();
|
|
604
|
+
if (!Array.isArray(value)) {
|
|
605
|
+
return byToolUseId;
|
|
606
|
+
}
|
|
607
|
+
for (const entry of value) {
|
|
608
|
+
const record = asRecordOrNull(entry);
|
|
609
|
+
const id = nonEmptyString(record?.id);
|
|
610
|
+
const kind = nonEmptyString(record?.non_execution_kind);
|
|
611
|
+
if (!id || !kind || byToolUseId.has(id)) {
|
|
612
|
+
continue;
|
|
613
|
+
}
|
|
614
|
+
const userFeedback = nonEmptyString(record?.user_feedback);
|
|
615
|
+
byToolUseId.set(id, {
|
|
616
|
+
kind,
|
|
617
|
+
...(userFeedback ? { user_feedback: userFeedback } : {}),
|
|
618
|
+
});
|
|
619
|
+
}
|
|
620
|
+
return byToolUseId;
|
|
621
|
+
}
|
|
622
|
+
export function applyToolNonExecutionMetadata(fields, metadata) {
|
|
623
|
+
if (!metadata) {
|
|
624
|
+
return;
|
|
625
|
+
}
|
|
626
|
+
fields.output_metadata = {
|
|
627
|
+
...(fields.output_metadata ?? {}),
|
|
628
|
+
non_execution: metadata,
|
|
629
|
+
};
|
|
630
|
+
switch (metadata.kind) {
|
|
631
|
+
case "user-rejected":
|
|
632
|
+
case "permission-rule":
|
|
633
|
+
case "automode-unavailable":
|
|
634
|
+
case "automode-parsing-error":
|
|
635
|
+
case "automode-blocked":
|
|
636
|
+
fields.status = "failed";
|
|
637
|
+
break;
|
|
638
|
+
case "cancelled":
|
|
639
|
+
case "interrupted":
|
|
640
|
+
fields.status = "killed";
|
|
641
|
+
break;
|
|
642
|
+
}
|
|
532
643
|
}
|
|
533
644
|
export function extractText(value) {
|
|
534
645
|
if (typeof value === "string") {
|
|
@@ -1541,6 +1652,51 @@ function collectResultCandidates(rawResult, rawContent) {
|
|
|
1541
1652
|
}
|
|
1542
1653
|
return candidates;
|
|
1543
1654
|
}
|
|
1655
|
+
function parseSkillResult(toolName, rawResult, rawContent) {
|
|
1656
|
+
if (toolName !== SKILL_TOOL_NAME) {
|
|
1657
|
+
return undefined;
|
|
1658
|
+
}
|
|
1659
|
+
for (const candidate of collectResultCandidates(rawResult, rawContent)) {
|
|
1660
|
+
const commandName = nonEmptyString(candidate.commandName);
|
|
1661
|
+
if (!commandName || typeof candidate.success !== "boolean") {
|
|
1662
|
+
continue;
|
|
1663
|
+
}
|
|
1664
|
+
if (candidate.status === "forked") {
|
|
1665
|
+
const agentId = nonEmptyString(candidate.agentId);
|
|
1666
|
+
if (!agentId || typeof candidate.result !== "string") {
|
|
1667
|
+
continue;
|
|
1668
|
+
}
|
|
1669
|
+
if (candidate.background !== undefined && typeof candidate.background !== "boolean") {
|
|
1670
|
+
continue;
|
|
1671
|
+
}
|
|
1672
|
+
return {
|
|
1673
|
+
success: candidate.success,
|
|
1674
|
+
commandName,
|
|
1675
|
+
status: "forked",
|
|
1676
|
+
agentId,
|
|
1677
|
+
result: candidate.result,
|
|
1678
|
+
...(typeof candidate.background === "boolean"
|
|
1679
|
+
? { background: candidate.background }
|
|
1680
|
+
: {}),
|
|
1681
|
+
};
|
|
1682
|
+
}
|
|
1683
|
+
if (candidate.status === undefined || candidate.status === "inline") {
|
|
1684
|
+
const allowedToolsValid = candidate.allowedTools === undefined ||
|
|
1685
|
+
(Array.isArray(candidate.allowedTools) &&
|
|
1686
|
+
candidate.allowedTools.every((tool) => typeof tool === "string"));
|
|
1687
|
+
const modelValid = candidate.model === undefined || typeof candidate.model === "string";
|
|
1688
|
+
if (!allowedToolsValid || !modelValid) {
|
|
1689
|
+
continue;
|
|
1690
|
+
}
|
|
1691
|
+
return {
|
|
1692
|
+
success: candidate.success,
|
|
1693
|
+
commandName,
|
|
1694
|
+
status: "inline",
|
|
1695
|
+
};
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1698
|
+
return undefined;
|
|
1699
|
+
}
|
|
1544
1700
|
function monitorResultFields(toolName, rawResult, rawContent) {
|
|
1545
1701
|
if (toolName !== MONITOR_TOOL_NAME) {
|
|
1546
1702
|
return undefined;
|
|
@@ -1745,6 +1901,32 @@ export function buildToolResultFields(isError, rawContent, base, rawResult, _con
|
|
|
1745
1901
|
if (outputMetadata) {
|
|
1746
1902
|
fields.output_metadata = outputMetadata;
|
|
1747
1903
|
}
|
|
1904
|
+
const skillResult = !isError ? parseSkillResult(toolName, rawResult, rawContent) : undefined;
|
|
1905
|
+
if (skillResult) {
|
|
1906
|
+
fields.title = `${SKILL_TOOL_NAME}: ${skillDisplayName(skillResult.commandName)}`;
|
|
1907
|
+
if (!skillResult.success) {
|
|
1908
|
+
fields.status = "failed";
|
|
1909
|
+
}
|
|
1910
|
+
else if (skillResult.status === "inline") {
|
|
1911
|
+
return fields;
|
|
1912
|
+
}
|
|
1913
|
+
else {
|
|
1914
|
+
const output = skillResult.result.trim();
|
|
1915
|
+
if (output) {
|
|
1916
|
+
fields.raw_output = output;
|
|
1917
|
+
fields.content = [{ type: "content", content: { type: "text", text: output } }];
|
|
1918
|
+
}
|
|
1919
|
+
return fields;
|
|
1920
|
+
}
|
|
1921
|
+
}
|
|
1922
|
+
const imageReadText = !isError && toolName === "Read"
|
|
1923
|
+
? imageReadResultText(rawResult, rawContent, base?.raw_input)
|
|
1924
|
+
: undefined;
|
|
1925
|
+
if (imageReadText !== undefined) {
|
|
1926
|
+
fields.raw_output = imageReadText;
|
|
1927
|
+
fields.content = [{ type: "content", content: { type: "text", text: imageReadText } }];
|
|
1928
|
+
return fields;
|
|
1929
|
+
}
|
|
1748
1930
|
const fileUnchangedText = !isError && toolName === "Read" ? fileUnchangedResultText(rawResult, rawContent) : "";
|
|
1749
1931
|
if (fileUnchangedText) {
|
|
1750
1932
|
fields.raw_output = fileUnchangedText;
|