la-machina-engine 0.7.4 → 0.7.6
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/dist/index.cjs +692 -42
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +394 -45
- package/dist/index.d.ts +394 -45
- package/dist/index.js +690 -42
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -841,6 +841,7 @@ __export(index_exports, {
|
|
|
841
841
|
EpisodicMemory: () => EpisodicMemory,
|
|
842
842
|
Hippocampus: () => Hippocampus,
|
|
843
843
|
InlineSkillSource: () => InlineSkillSource,
|
|
844
|
+
InspectWriter: () => InspectWriter,
|
|
844
845
|
LocalStorageAdapter: () => LocalStorageAdapter,
|
|
845
846
|
MAX_ATTEMPTS: () => MAX_ATTEMPTS,
|
|
846
847
|
McpClient: () => McpClient,
|
|
@@ -848,6 +849,7 @@ __export(index_exports, {
|
|
|
848
849
|
McpManager: () => McpManager,
|
|
849
850
|
McpProtocolError: () => McpProtocolError,
|
|
850
851
|
McpTimeoutError: () => McpTimeoutError,
|
|
852
|
+
NULL_INSPECT_WRITER: () => NULL_INSPECT_WRITER,
|
|
851
853
|
NodeBackgroundExecutor: () => NodeBackgroundExecutor,
|
|
852
854
|
NotImplementedError: () => NotImplementedError,
|
|
853
855
|
PlanSchema: () => PlanSchema,
|
|
@@ -1022,6 +1024,10 @@ var DEFAULTS = {
|
|
|
1022
1024
|
enableRollback: true,
|
|
1023
1025
|
maxPlanSteps: 20,
|
|
1024
1026
|
agentMaxTurns: 15
|
|
1027
|
+
},
|
|
1028
|
+
inspect: {
|
|
1029
|
+
enabled: true,
|
|
1030
|
+
redactBaseURL: false
|
|
1025
1031
|
}
|
|
1026
1032
|
};
|
|
1027
1033
|
|
|
@@ -1257,6 +1263,11 @@ var RunnerConfigResolved = import_zod.z.object({
|
|
|
1257
1263
|
url: import_zod.z.string().url(),
|
|
1258
1264
|
secret: import_zod.z.string().min(1, "runner.secret cannot be empty")
|
|
1259
1265
|
}).strict();
|
|
1266
|
+
var InspectConfigResolved = import_zod.z.object({
|
|
1267
|
+
enabled: import_zod.z.boolean(),
|
|
1268
|
+
redactBaseURL: import_zod.z.boolean()
|
|
1269
|
+
}).strict();
|
|
1270
|
+
var InspectConfigUser = InspectConfigResolved.partial();
|
|
1260
1271
|
var ResolvedConfigSchema = import_zod.z.object({
|
|
1261
1272
|
model: ModelConfigResolved,
|
|
1262
1273
|
storage: StorageConfigResolved,
|
|
@@ -1275,7 +1286,8 @@ var ResolvedConfigSchema = import_zod.z.object({
|
|
|
1275
1286
|
orchestrator: OrchestratorConfigResolved,
|
|
1276
1287
|
runner: RunnerConfigResolved.optional(),
|
|
1277
1288
|
api: ApiConfigResolved.optional(),
|
|
1278
|
-
knowledge: KnowledgeConfigResolved.optional()
|
|
1289
|
+
knowledge: KnowledgeConfigResolved.optional(),
|
|
1290
|
+
inspect: InspectConfigResolved
|
|
1279
1291
|
}).strict();
|
|
1280
1292
|
var R2ConfigUser = R2ConfigResolved.partial();
|
|
1281
1293
|
var ModelConfigUser = ModelConfigResolved.partial();
|
|
@@ -1352,7 +1364,8 @@ var UserConfigSchema = import_zod.z.object({
|
|
|
1352
1364
|
orchestrator: OrchestratorConfigUser.optional(),
|
|
1353
1365
|
runner: RunnerConfigUser.optional(),
|
|
1354
1366
|
api: ApiConfigUser.optional(),
|
|
1355
|
-
knowledge: KnowledgeConfigUser.optional()
|
|
1367
|
+
knowledge: KnowledgeConfigUser.optional(),
|
|
1368
|
+
inspect: InspectConfigUser.optional()
|
|
1356
1369
|
}).strict();
|
|
1357
1370
|
|
|
1358
1371
|
// src/config/merge.ts
|
|
@@ -3025,6 +3038,30 @@ function isSubagentPausedError(err) {
|
|
|
3025
3038
|
}
|
|
3026
3039
|
|
|
3027
3040
|
// src/engine/agentLoop.ts
|
|
3041
|
+
async function emitInspectTurn(args) {
|
|
3042
|
+
const writer = args.inspect;
|
|
3043
|
+
if (writer === void 0) return;
|
|
3044
|
+
const completedAt = Date.now();
|
|
3045
|
+
const cacheCreate = args.endTokens.cacheCreationInput !== void 0 ? args.endTokens.cacheCreationInput - (args.startTokens.cacheCreationInput ?? 0) : void 0;
|
|
3046
|
+
const cacheRead = args.endTokens.cacheReadInput !== void 0 ? args.endTokens.cacheReadInput - (args.startTokens.cacheReadInput ?? 0) : void 0;
|
|
3047
|
+
const delta = {
|
|
3048
|
+
input: args.endTokens.input - args.startTokens.input,
|
|
3049
|
+
output: args.endTokens.output - args.startTokens.output,
|
|
3050
|
+
...cacheCreate !== void 0 ? { cacheCreationInput: cacheCreate } : {},
|
|
3051
|
+
...cacheRead !== void 0 ? { cacheReadInput: cacheRead } : {}
|
|
3052
|
+
};
|
|
3053
|
+
await writer.appendTurn({
|
|
3054
|
+
turn: args.turn,
|
|
3055
|
+
startedAt: args.startedAt,
|
|
3056
|
+
completedAt,
|
|
3057
|
+
durationMs: completedAt - args.startedAt,
|
|
3058
|
+
tokensUsed: delta,
|
|
3059
|
+
stopReason: args.stopReason,
|
|
3060
|
+
toolCallsCount: args.toolCallsCount,
|
|
3061
|
+
...cacheCreate !== void 0 ? { cacheCreationInput: cacheCreate } : {},
|
|
3062
|
+
...cacheRead !== void 0 ? { cacheReadInput: cacheRead } : {}
|
|
3063
|
+
});
|
|
3064
|
+
}
|
|
3028
3065
|
var DEFAULT_COMPACTION = {
|
|
3029
3066
|
strategy: "drop-middle",
|
|
3030
3067
|
threshold: 0.85,
|
|
@@ -3067,6 +3104,8 @@ async function agentLoop(options) {
|
|
|
3067
3104
|
};
|
|
3068
3105
|
for (; ; ) {
|
|
3069
3106
|
compactedThisTurn = false;
|
|
3107
|
+
const turnStartedAt = Date.now();
|
|
3108
|
+
const turnStartTokens = { ...ctx.getTokensUsed() };
|
|
3070
3109
|
if (options.runSignal?.aborted === true) {
|
|
3071
3110
|
return failed(new RunTimeoutError(options.runTimeoutMs ?? 0), transcript);
|
|
3072
3111
|
}
|
|
@@ -3076,6 +3115,12 @@ async function agentLoop(options) {
|
|
|
3076
3115
|
if (options.tokenBudget !== void 0) {
|
|
3077
3116
|
const used = ctx.getTokensUsed();
|
|
3078
3117
|
if (used.input + used.output >= options.tokenBudget) {
|
|
3118
|
+
await options.inspect?.appendEvent({
|
|
3119
|
+
type: "budget_hit",
|
|
3120
|
+
totalTokens: used.input + used.output,
|
|
3121
|
+
budget: options.tokenBudget,
|
|
3122
|
+
ts: Date.now()
|
|
3123
|
+
});
|
|
3079
3124
|
return {
|
|
3080
3125
|
status: "done",
|
|
3081
3126
|
output: lastAssistantText || "[Token budget exhausted]",
|
|
@@ -3120,6 +3165,19 @@ async function agentLoop(options) {
|
|
|
3120
3165
|
});
|
|
3121
3166
|
if (compactResult.compacted) {
|
|
3122
3167
|
messages = compactResult.messages;
|
|
3168
|
+
const used = ctx.getTokensUsed();
|
|
3169
|
+
const total = used.input + used.output;
|
|
3170
|
+
const ratio = total / contextLimit;
|
|
3171
|
+
const dropped = compactResult.result?.dropped ?? 0;
|
|
3172
|
+
await options.inspect?.appendEvent({
|
|
3173
|
+
type: "compaction_threshold",
|
|
3174
|
+
turn: ctx.getTurnCount(),
|
|
3175
|
+
ratio,
|
|
3176
|
+
threshold: compactionConfig.threshold,
|
|
3177
|
+
strategy: compactResult.result?.strategy ?? compactionConfig.strategy,
|
|
3178
|
+
dropped,
|
|
3179
|
+
ts: Date.now()
|
|
3180
|
+
});
|
|
3123
3181
|
}
|
|
3124
3182
|
await fireProgress("streaming");
|
|
3125
3183
|
const textBlocks = [];
|
|
@@ -3132,13 +3190,21 @@ async function agentLoop(options) {
|
|
|
3132
3190
|
turnCount: ctx.getTurnCount(),
|
|
3133
3191
|
maxTurns: ctx.getMaxTurns()
|
|
3134
3192
|
})) {
|
|
3193
|
+
const instruction = lastTurnInstruction(options.outputFormat);
|
|
3135
3194
|
messagesForApi = [
|
|
3136
3195
|
...messages,
|
|
3137
3196
|
{
|
|
3138
3197
|
role: "user",
|
|
3139
|
-
content: [{ type: "text", text:
|
|
3198
|
+
content: [{ type: "text", text: instruction }]
|
|
3140
3199
|
}
|
|
3141
3200
|
];
|
|
3201
|
+
await options.inspect?.appendEvent({
|
|
3202
|
+
type: "last_turn_guard",
|
|
3203
|
+
turn: ctx.getTurnCount(),
|
|
3204
|
+
outputFormat: options.outputFormat ?? "text",
|
|
3205
|
+
instruction,
|
|
3206
|
+
ts: Date.now()
|
|
3207
|
+
});
|
|
3142
3208
|
}
|
|
3143
3209
|
const normalizedMessages = normalizeMessages(
|
|
3144
3210
|
messagesForApi
|
|
@@ -3173,6 +3239,13 @@ async function agentLoop(options) {
|
|
|
3173
3239
|
system
|
|
3174
3240
|
});
|
|
3175
3241
|
if (emergency.compacted) {
|
|
3242
|
+
await options.inspect?.appendEvent({
|
|
3243
|
+
type: "compaction_413",
|
|
3244
|
+
turn: ctx.getTurnCount(),
|
|
3245
|
+
droppedMessages: messages.length - emergency.messages.length,
|
|
3246
|
+
strategy: compactionConfig.strategy,
|
|
3247
|
+
ts: Date.now()
|
|
3248
|
+
});
|
|
3176
3249
|
ctx.rehydrate({
|
|
3177
3250
|
messages: emergency.messages,
|
|
3178
3251
|
turnCount: ctx.getTurnCount(),
|
|
@@ -3200,6 +3273,14 @@ async function agentLoop(options) {
|
|
|
3200
3273
|
}
|
|
3201
3274
|
const retryAfter = err instanceof RateLimitError && err.retryAfterMs ? err.retryAfterMs : BASE_BACKOFF_MS * Math.pow(2, apiRetryCount - 1);
|
|
3202
3275
|
const delay = Math.min(retryAfter, 3e4);
|
|
3276
|
+
await options.inspect?.appendEvent({
|
|
3277
|
+
type: "api_retry",
|
|
3278
|
+
turn: ctx.getTurnCount(),
|
|
3279
|
+
status: err instanceof Error && "status" in err ? err.status ?? null : null,
|
|
3280
|
+
attempt: apiRetryCount,
|
|
3281
|
+
delayMs: delay,
|
|
3282
|
+
ts: Date.now()
|
|
3283
|
+
});
|
|
3203
3284
|
await new Promise((r) => setTimeout(r, delay));
|
|
3204
3285
|
continue;
|
|
3205
3286
|
}
|
|
@@ -3282,16 +3363,31 @@ async function agentLoop(options) {
|
|
|
3282
3363
|
const firstTool = toolCallsToDispatch[0]?.name;
|
|
3283
3364
|
await fireProgress("tool_dispatch", firstTool);
|
|
3284
3365
|
const streamExec = new StreamingToolExecutor(executor);
|
|
3366
|
+
let anyConcurrent = false;
|
|
3285
3367
|
for (const call of toolCallsToDispatch) {
|
|
3286
3368
|
const tool = options.registry?.get(call.name);
|
|
3287
3369
|
const safe = tool?.isConcurrencySafe?.(call.input) ?? false;
|
|
3370
|
+
if (safe) anyConcurrent = true;
|
|
3288
3371
|
streamExec.addTool(call.id, call.name, call.input, safe);
|
|
3289
3372
|
}
|
|
3373
|
+
await options.inspect?.appendEvent({
|
|
3374
|
+
type: "tool_batch",
|
|
3375
|
+
turn: ctx.getTurnCount(),
|
|
3376
|
+
toolNames: toolCallsToDispatch.map((c) => c.name),
|
|
3377
|
+
concurrent: anyConcurrent && toolCallsToDispatch.length > 1,
|
|
3378
|
+
ts: Date.now()
|
|
3379
|
+
});
|
|
3290
3380
|
try {
|
|
3291
3381
|
for await (const { id, result } of streamExec.results()) {
|
|
3292
3382
|
const missing = result.metadata?.capabilityMissing;
|
|
3293
3383
|
if (typeof missing === "string") {
|
|
3294
3384
|
ctx.recordCapabilityMissing(missing);
|
|
3385
|
+
await options.inspect?.appendEvent({
|
|
3386
|
+
type: "capability_stub",
|
|
3387
|
+
turn: ctx.getTurnCount(),
|
|
3388
|
+
toolName: missing,
|
|
3389
|
+
ts: Date.now()
|
|
3390
|
+
});
|
|
3295
3391
|
}
|
|
3296
3392
|
const call = toolCallsToDispatch.find((c) => c.id === id);
|
|
3297
3393
|
let contentForTranscript;
|
|
@@ -3351,6 +3447,15 @@ async function agentLoop(options) {
|
|
|
3351
3447
|
apiRetryCount = 0;
|
|
3352
3448
|
consecutive529 = 0;
|
|
3353
3449
|
await ctx.endTurn();
|
|
3450
|
+
await emitInspectTurn({
|
|
3451
|
+
inspect: options.inspect,
|
|
3452
|
+
turn: ctx.getTurnCount() - 1,
|
|
3453
|
+
startedAt: turnStartedAt,
|
|
3454
|
+
startTokens: turnStartTokens,
|
|
3455
|
+
endTokens: ctx.getTokensUsed(),
|
|
3456
|
+
stopReason,
|
|
3457
|
+
toolCallsCount: toolCallsToDispatch.length
|
|
3458
|
+
});
|
|
3354
3459
|
await fireProgress("idle");
|
|
3355
3460
|
if (options.postTurnHooks && options.postTurnHooks.length > 0) {
|
|
3356
3461
|
await dispatchHooks(options.postTurnHooks, {
|
|
@@ -3382,6 +3487,15 @@ async function agentLoop(options) {
|
|
|
3382
3487
|
continue;
|
|
3383
3488
|
}
|
|
3384
3489
|
await ctx.endTurn();
|
|
3490
|
+
await emitInspectTurn({
|
|
3491
|
+
inspect: options.inspect,
|
|
3492
|
+
turn: ctx.getTurnCount() - 1,
|
|
3493
|
+
startedAt: turnStartedAt,
|
|
3494
|
+
startTokens: turnStartTokens,
|
|
3495
|
+
endTokens: ctx.getTokensUsed(),
|
|
3496
|
+
stopReason,
|
|
3497
|
+
toolCallsCount: 0
|
|
3498
|
+
});
|
|
3385
3499
|
if (options.postTurnHooks && options.postTurnHooks.length > 0) {
|
|
3386
3500
|
await dispatchHooks(options.postTurnHooks, {
|
|
3387
3501
|
runId: ctx.runId,
|
|
@@ -3408,11 +3522,25 @@ async function agentLoop(options) {
|
|
|
3408
3522
|
if (!maxTokensEscalated) {
|
|
3409
3523
|
maxTokensEscalated = true;
|
|
3410
3524
|
escalatedMaxTokens = ESCALATED_MAX_TOKENS;
|
|
3525
|
+
await options.inspect?.appendEvent({
|
|
3526
|
+
type: "recovery_max_tokens",
|
|
3527
|
+
turn: ctx.getTurnCount(),
|
|
3528
|
+
attempt: 0,
|
|
3529
|
+
escalatedTo: ESCALATED_MAX_TOKENS,
|
|
3530
|
+
ts: Date.now()
|
|
3531
|
+
});
|
|
3411
3532
|
continue;
|
|
3412
3533
|
}
|
|
3413
3534
|
if (recoveryCount < MAX_OUTPUT_TOKENS_RECOVERY_LIMIT) {
|
|
3414
3535
|
recoveryCount++;
|
|
3415
3536
|
escalatedMaxTokens = void 0;
|
|
3537
|
+
await options.inspect?.appendEvent({
|
|
3538
|
+
type: "recovery_max_tokens",
|
|
3539
|
+
turn: ctx.getTurnCount(),
|
|
3540
|
+
attempt: recoveryCount,
|
|
3541
|
+
escalatedTo: 0,
|
|
3542
|
+
ts: Date.now()
|
|
3543
|
+
});
|
|
3416
3544
|
await ctx.addUserMessage(
|
|
3417
3545
|
"Output token limit hit. Resume directly \u2014 no apology, no recap of what you were doing. Pick up mid-thought if that is where the cut happened. Break remaining work into smaller pieces."
|
|
3418
3546
|
);
|
|
@@ -4408,25 +4536,45 @@ If omitted, defaults to "${defaultAgent.name}".`;
|
|
|
4408
4536
|
const lastAssistant = [...parentMsgs].reverse().find((m) => m.role === "assistant");
|
|
4409
4537
|
const assistantContent = lastAssistant ? Array.isArray(lastAssistant.content) ? lastAssistant.content : [] : [];
|
|
4410
4538
|
const forkedMsgs = buildForkedMessages(taskDescription, assistantContent);
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4426
|
-
|
|
4427
|
-
|
|
4428
|
-
|
|
4429
|
-
|
|
4539
|
+
let result2;
|
|
4540
|
+
try {
|
|
4541
|
+
result2 = await runAgent({
|
|
4542
|
+
agentId: spawn2.agentId,
|
|
4543
|
+
description: taskDescription,
|
|
4544
|
+
storage: options.storage,
|
|
4545
|
+
client: options.client,
|
|
4546
|
+
registry: options.childRegistry,
|
|
4547
|
+
parentLogPath: options.parentLogPath,
|
|
4548
|
+
system: options.system,
|
|
4549
|
+
// inherit parent's system prompt
|
|
4550
|
+
maxTurns: options.maxTurns,
|
|
4551
|
+
contextLimit: options.contextLimit,
|
|
4552
|
+
turnTimeoutMs: options.turnTimeoutMs,
|
|
4553
|
+
flushPolicy: options.flushPolicy,
|
|
4554
|
+
idleFlushMs: options.idleFlushMs,
|
|
4555
|
+
// Fork: prepend parent messages + forked messages
|
|
4556
|
+
prependMessages: [...parentMsgs, ...forkedMsgs],
|
|
4557
|
+
...options.gateBeforeTool !== void 0 ? { gateBeforeTool: options.gateBeforeTool } : {},
|
|
4558
|
+
...options.toolResultOffload !== void 0 ? { toolResultOffload: options.toolResultOffload } : {}
|
|
4559
|
+
});
|
|
4560
|
+
await options.inspect?.appendEvent({
|
|
4561
|
+
type: "subagent_spawn_attempt",
|
|
4562
|
+
agentId: spawn2.agentId,
|
|
4563
|
+
subagentType: "fork",
|
|
4564
|
+
success: true,
|
|
4565
|
+
ts: Date.now()
|
|
4566
|
+
});
|
|
4567
|
+
} catch (err) {
|
|
4568
|
+
await options.inspect?.appendEvent({
|
|
4569
|
+
type: "subagent_spawn_attempt",
|
|
4570
|
+
agentId: spawn2.agentId,
|
|
4571
|
+
subagentType: "fork",
|
|
4572
|
+
success: false,
|
|
4573
|
+
error: err instanceof Error ? err.message : String(err),
|
|
4574
|
+
ts: Date.now()
|
|
4575
|
+
});
|
|
4576
|
+
throw err;
|
|
4577
|
+
}
|
|
4430
4578
|
handlePausedResult(result2, spawn2.agentId, "fork");
|
|
4431
4579
|
const t2 = result2;
|
|
4432
4580
|
options.subagentRegistry.setStatus(spawn2.agentId, t2.isError ? "stopped" : "completed");
|
|
@@ -4480,7 +4628,7 @@ If omitted, defaults to "${defaultAgent.name}".`;
|
|
|
4480
4628
|
const shouldRunAsync = run_in_background === true || options.coordinatorMode === true;
|
|
4481
4629
|
if (shouldRunAsync) {
|
|
4482
4630
|
options.subagentRegistry.setBackground(spawn.agentId);
|
|
4483
|
-
const bgPromise = runAgent(runOpts).then((result2) => {
|
|
4631
|
+
const bgPromise = runAgent(runOpts).then(async (result2) => {
|
|
4484
4632
|
if (result2.kind !== "terminal") {
|
|
4485
4633
|
options.subagentRegistry.setStatus(spawn.agentId, "stopped");
|
|
4486
4634
|
options.subagentRegistry.setBackgroundResult(spawn.agentId, {
|
|
@@ -4489,6 +4637,14 @@ If omitted, defaults to "${defaultAgent.name}".`;
|
|
|
4489
4637
|
isError: true,
|
|
4490
4638
|
description: taskDescription
|
|
4491
4639
|
});
|
|
4640
|
+
await options.inspect?.appendEvent({
|
|
4641
|
+
type: "subagent_spawn_attempt",
|
|
4642
|
+
agentId: spawn.agentId,
|
|
4643
|
+
subagentType: typeName ?? "unknown",
|
|
4644
|
+
success: false,
|
|
4645
|
+
error: "background subagent paused (pause not supported for async)",
|
|
4646
|
+
ts: Date.now()
|
|
4647
|
+
});
|
|
4492
4648
|
return;
|
|
4493
4649
|
}
|
|
4494
4650
|
options.subagentRegistry.setStatus(
|
|
@@ -4501,7 +4657,15 @@ If omitted, defaults to "${defaultAgent.name}".`;
|
|
|
4501
4657
|
isError: result2.isError,
|
|
4502
4658
|
description: taskDescription
|
|
4503
4659
|
});
|
|
4504
|
-
|
|
4660
|
+
await options.inspect?.appendEvent({
|
|
4661
|
+
type: "subagent_spawn_attempt",
|
|
4662
|
+
agentId: spawn.agentId,
|
|
4663
|
+
subagentType: typeName ?? "unknown",
|
|
4664
|
+
success: !result2.isError,
|
|
4665
|
+
...result2.isError ? { error: "child returned isError" } : {},
|
|
4666
|
+
ts: Date.now()
|
|
4667
|
+
});
|
|
4668
|
+
}).catch(async (err) => {
|
|
4505
4669
|
options.subagentRegistry.setStatus(spawn.agentId, "stopped");
|
|
4506
4670
|
options.subagentRegistry.setBackgroundResult(spawn.agentId, {
|
|
4507
4671
|
agentId: spawn.agentId,
|
|
@@ -4509,6 +4673,14 @@ If omitted, defaults to "${defaultAgent.name}".`;
|
|
|
4509
4673
|
isError: true,
|
|
4510
4674
|
description: taskDescription
|
|
4511
4675
|
});
|
|
4676
|
+
await options.inspect?.appendEvent({
|
|
4677
|
+
type: "subagent_spawn_attempt",
|
|
4678
|
+
agentId: spawn.agentId,
|
|
4679
|
+
subagentType: typeName ?? "unknown",
|
|
4680
|
+
success: false,
|
|
4681
|
+
error: err instanceof Error ? err.message : String(err),
|
|
4682
|
+
ts: Date.now()
|
|
4683
|
+
});
|
|
4512
4684
|
});
|
|
4513
4685
|
options.subagentRegistry.setBackgroundPromise(spawn.agentId, bgPromise);
|
|
4514
4686
|
return {
|
|
@@ -4524,7 +4696,27 @@ Use SendMessage with to: '${spawn.agentId}' to communicate with this agent.`,
|
|
|
4524
4696
|
}
|
|
4525
4697
|
};
|
|
4526
4698
|
}
|
|
4527
|
-
|
|
4699
|
+
let result;
|
|
4700
|
+
try {
|
|
4701
|
+
result = await runAgent(runOpts);
|
|
4702
|
+
await options.inspect?.appendEvent({
|
|
4703
|
+
type: "subagent_spawn_attempt",
|
|
4704
|
+
agentId: spawn.agentId,
|
|
4705
|
+
subagentType: typeName ?? "unknown",
|
|
4706
|
+
success: true,
|
|
4707
|
+
ts: Date.now()
|
|
4708
|
+
});
|
|
4709
|
+
} catch (err) {
|
|
4710
|
+
await options.inspect?.appendEvent({
|
|
4711
|
+
type: "subagent_spawn_attempt",
|
|
4712
|
+
agentId: spawn.agentId,
|
|
4713
|
+
subagentType: typeName ?? "unknown",
|
|
4714
|
+
success: false,
|
|
4715
|
+
error: err instanceof Error ? err.message : String(err),
|
|
4716
|
+
ts: Date.now()
|
|
4717
|
+
});
|
|
4718
|
+
throw err;
|
|
4719
|
+
}
|
|
4528
4720
|
handlePausedResult(result, spawn.agentId, typeName);
|
|
4529
4721
|
const t = result;
|
|
4530
4722
|
options.subagentRegistry.setStatus(spawn.agentId, t.isError ? "stopped" : "completed");
|
|
@@ -4727,6 +4919,7 @@ function createSendMessageTool(options) {
|
|
|
4727
4919
|
|
|
4728
4920
|
// src/engine/engine.ts
|
|
4729
4921
|
init_contract();
|
|
4922
|
+
var import_zod_to_json_schema4 = require("zod-to-json-schema");
|
|
4730
4923
|
|
|
4731
4924
|
// src/tools/fileEdit.ts
|
|
4732
4925
|
init_cjs_shims();
|
|
@@ -6858,7 +7051,7 @@ init_contract();
|
|
|
6858
7051
|
function mcpToolName(serverName, toolName) {
|
|
6859
7052
|
return `mcp__${serverName}__${toolName}`;
|
|
6860
7053
|
}
|
|
6861
|
-
function adaptMcpTool(client, serverName, def) {
|
|
7054
|
+
function adaptMcpTool(client, serverName, def, opts) {
|
|
6862
7055
|
const registeredName = mcpToolName(serverName, def.name);
|
|
6863
7056
|
return defineTool({
|
|
6864
7057
|
name: registeredName,
|
|
@@ -6868,6 +7061,9 @@ function adaptMcpTool(client, serverName, def) {
|
|
|
6868
7061
|
// bypassing Zod-to-JSON-Schema conversion (which would produce `{}`
|
|
6869
7062
|
// for our `z.unknown()` Zod schema).
|
|
6870
7063
|
anthropicSchemaOverride: def.inputSchema,
|
|
7064
|
+
// Plan 027 — stdio servers spawn subprocesses; flag so the engine's
|
|
7065
|
+
// capability-stub wrapper can swap them on Workers.
|
|
7066
|
+
...opts.transport === "stdio" ? { requiresNode: true } : {},
|
|
6871
7067
|
execute: async (input) => {
|
|
6872
7068
|
try {
|
|
6873
7069
|
const result = await client.callTool(def.name, input);
|
|
@@ -6911,6 +7107,8 @@ var McpManager = class {
|
|
|
6911
7107
|
this.logger = logger;
|
|
6912
7108
|
this.servers = Object.entries(config.servers).map(([name, serverConfig]) => ({
|
|
6913
7109
|
name,
|
|
7110
|
+
// Plan 027 — capture transport for the stdio-handoff wiring.
|
|
7111
|
+
transport: serverConfig.type,
|
|
6914
7112
|
client: new McpClient({
|
|
6915
7113
|
serverName: name,
|
|
6916
7114
|
config: serverConfig,
|
|
@@ -7050,7 +7248,9 @@ var McpManager = class {
|
|
|
7050
7248
|
try {
|
|
7051
7249
|
await server.client.connect();
|
|
7052
7250
|
const defs = server.client.listTools();
|
|
7053
|
-
server.tools = defs.map(
|
|
7251
|
+
server.tools = defs.map(
|
|
7252
|
+
(def) => adaptMcpTool(server.client, server.name, def, { transport: server.transport })
|
|
7253
|
+
);
|
|
7054
7254
|
server.state = "connected";
|
|
7055
7255
|
this.pendingConnected.push(server.name);
|
|
7056
7256
|
} catch (err) {
|
|
@@ -9721,6 +9921,198 @@ function applyRunToolFilter(registry, options) {
|
|
|
9721
9921
|
}
|
|
9722
9922
|
}
|
|
9723
9923
|
|
|
9924
|
+
// src/inspect/writer.ts
|
|
9925
|
+
init_cjs_shims();
|
|
9926
|
+
var InspectWriter = class {
|
|
9927
|
+
storage;
|
|
9928
|
+
logger;
|
|
9929
|
+
enabled;
|
|
9930
|
+
/** Subdirectory holding all inspect files. Constant per writer. */
|
|
9931
|
+
dir;
|
|
9932
|
+
constructor(opts) {
|
|
9933
|
+
this.storage = opts.storage;
|
|
9934
|
+
if (opts.logger !== void 0) this.logger = opts.logger;
|
|
9935
|
+
this.enabled = opts.enabled;
|
|
9936
|
+
this.dir = `${opts.logPath}/inspect`;
|
|
9937
|
+
}
|
|
9938
|
+
/**
|
|
9939
|
+
* Write the eight start-snapshot files atomically (well, sequentially —
|
|
9940
|
+
* R2 has no multi-object atomic; failures partially-write and the
|
|
9941
|
+
* fail-soft path logs each one).
|
|
9942
|
+
*/
|
|
9943
|
+
async writeStartSnapshot(input) {
|
|
9944
|
+
if (!this.enabled) return;
|
|
9945
|
+
await this.safeWrite("system-prompt.txt", input.systemPrompt);
|
|
9946
|
+
await this.safeWriteJson("tools.json", input.tools);
|
|
9947
|
+
await this.safeWriteJson("run-options.json", input.runOptions);
|
|
9948
|
+
await this.safeWriteJson("model-config.json", input.modelConfig);
|
|
9949
|
+
if (input.skills !== void 0) {
|
|
9950
|
+
await this.safeWriteJson("skills.json", input.skills);
|
|
9951
|
+
}
|
|
9952
|
+
if (input.mcpServers !== void 0) {
|
|
9953
|
+
await this.safeWriteJson("mcp-servers.json", input.mcpServers);
|
|
9954
|
+
}
|
|
9955
|
+
if (input.apiServices !== void 0) {
|
|
9956
|
+
await this.safeWriteJson("api-services.json", input.apiServices);
|
|
9957
|
+
}
|
|
9958
|
+
if (input.knowledge !== void 0) {
|
|
9959
|
+
await this.safeWriteJson("knowledge-scope.json", input.knowledge);
|
|
9960
|
+
}
|
|
9961
|
+
}
|
|
9962
|
+
/** Append one event line to events.jsonl. */
|
|
9963
|
+
async appendEvent(event) {
|
|
9964
|
+
if (!this.enabled) return;
|
|
9965
|
+
await this.safeAppend("events.jsonl", JSON.stringify(event) + "\n");
|
|
9966
|
+
}
|
|
9967
|
+
/** Append one row to turns.jsonl. */
|
|
9968
|
+
async appendTurn(row) {
|
|
9969
|
+
if (!this.enabled) return;
|
|
9970
|
+
await this.safeAppend("turns.jsonl", JSON.stringify(row) + "\n");
|
|
9971
|
+
}
|
|
9972
|
+
/** Write the terminal `tools-summary.json` once at run end. */
|
|
9973
|
+
async writeToolsSummary(summary) {
|
|
9974
|
+
if (!this.enabled) return;
|
|
9975
|
+
await this.safeWriteJson("tools-summary.json", summary);
|
|
9976
|
+
}
|
|
9977
|
+
// ---------- private fail-soft helpers ----------
|
|
9978
|
+
async safeWrite(name, content) {
|
|
9979
|
+
try {
|
|
9980
|
+
await this.storage.writeFile(`${this.dir}/${name}`, content);
|
|
9981
|
+
} catch (err) {
|
|
9982
|
+
this.logFailure("writeFile", name, err);
|
|
9983
|
+
}
|
|
9984
|
+
}
|
|
9985
|
+
async safeWriteJson(name, value) {
|
|
9986
|
+
try {
|
|
9987
|
+
await this.storage.writeFile(`${this.dir}/${name}`, JSON.stringify(value, null, 2));
|
|
9988
|
+
} catch (err) {
|
|
9989
|
+
this.logFailure("writeFile (json)", name, err);
|
|
9990
|
+
}
|
|
9991
|
+
}
|
|
9992
|
+
async safeAppend(name, line) {
|
|
9993
|
+
try {
|
|
9994
|
+
await this.storage.appendFile(`${this.dir}/${name}`, line);
|
|
9995
|
+
} catch (err) {
|
|
9996
|
+
this.logFailure("appendFile", name, err);
|
|
9997
|
+
}
|
|
9998
|
+
}
|
|
9999
|
+
logFailure(op, name, err) {
|
|
10000
|
+
if (this.logger === void 0) return;
|
|
10001
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
10002
|
+
this.logger.warn?.("inspect-writer failed", {
|
|
10003
|
+
op,
|
|
10004
|
+
file: `${this.dir}/${name}`,
|
|
10005
|
+
error: msg
|
|
10006
|
+
});
|
|
10007
|
+
}
|
|
10008
|
+
};
|
|
10009
|
+
var NULL_INSPECT_WRITER = {
|
|
10010
|
+
writeStartSnapshot: async () => void 0,
|
|
10011
|
+
appendEvent: async () => void 0,
|
|
10012
|
+
appendTurn: async () => void 0,
|
|
10013
|
+
writeToolsSummary: async () => void 0
|
|
10014
|
+
};
|
|
10015
|
+
|
|
10016
|
+
// src/inspect/scrub.ts
|
|
10017
|
+
init_cjs_shims();
|
|
10018
|
+
var import_zod_to_json_schema3 = require("zod-to-json-schema");
|
|
10019
|
+
function scrubModelConfig(cfg, opts = { redactBaseURL: false }) {
|
|
10020
|
+
const out = {
|
|
10021
|
+
schemaVersion: 1,
|
|
10022
|
+
provider: cfg.provider,
|
|
10023
|
+
modelId: cfg.modelId
|
|
10024
|
+
};
|
|
10025
|
+
if (!opts.redactBaseURL && cfg.baseURL !== void 0) out.baseURL = cfg.baseURL;
|
|
10026
|
+
if (cfg.temperature !== void 0) out.temperature = cfg.temperature;
|
|
10027
|
+
if (cfg.maxTokens !== void 0) out.maxTokens = cfg.maxTokens;
|
|
10028
|
+
if (cfg.maxRetries !== void 0) out.maxRetries = cfg.maxRetries;
|
|
10029
|
+
return out;
|
|
10030
|
+
}
|
|
10031
|
+
function scrubRunOptions(opts) {
|
|
10032
|
+
const out = {
|
|
10033
|
+
schemaVersion: 1,
|
|
10034
|
+
runId: opts.runId ?? "",
|
|
10035
|
+
nodeId: opts.nodeId,
|
|
10036
|
+
task: opts.task
|
|
10037
|
+
};
|
|
10038
|
+
if (opts.maxTurns !== void 0) out.maxTurns = opts.maxTurns;
|
|
10039
|
+
if (opts.outputFormat !== void 0) out.outputFormat = opts.outputFormat;
|
|
10040
|
+
if (opts.outputSchema !== void 0) out.outputSchema = serializeOutputSchema(opts.outputSchema);
|
|
10041
|
+
if (opts.tools !== void 0) out.tools = [...opts.tools];
|
|
10042
|
+
if (opts.toolChoice !== void 0) out.toolChoice = opts.toolChoice;
|
|
10043
|
+
if (opts.tokenBudget !== void 0) out.tokenBudget = opts.tokenBudget;
|
|
10044
|
+
if (opts.knowledge !== void 0) {
|
|
10045
|
+
const k = {};
|
|
10046
|
+
if (opts.knowledge.folders !== void 0) k.folders = [...opts.knowledge.folders];
|
|
10047
|
+
if (opts.knowledge.external !== void 0) {
|
|
10048
|
+
k.external = opts.knowledge.external.map((e) => {
|
|
10049
|
+
const link = { url: e.url };
|
|
10050
|
+
if (e.description !== void 0) link.description = e.description;
|
|
10051
|
+
return link;
|
|
10052
|
+
});
|
|
10053
|
+
}
|
|
10054
|
+
out.knowledge = k;
|
|
10055
|
+
}
|
|
10056
|
+
if (opts.api !== void 0 && opts.api.services !== void 0) {
|
|
10057
|
+
out.api = {
|
|
10058
|
+
services: opts.api.services.map((s) => {
|
|
10059
|
+
const svc = { name: s.name };
|
|
10060
|
+
if (s.description !== void 0) svc.description = s.description;
|
|
10061
|
+
if (s.baseUrl !== void 0) svc.baseUrl = s.baseUrl;
|
|
10062
|
+
return svc;
|
|
10063
|
+
})
|
|
10064
|
+
};
|
|
10065
|
+
}
|
|
10066
|
+
if (opts.skills !== void 0) {
|
|
10067
|
+
out.skills = opts.skills.map((s) => ({
|
|
10068
|
+
name: s.name,
|
|
10069
|
+
description: s.description ?? "",
|
|
10070
|
+
hasBody: "body" in s && typeof s.body === "string",
|
|
10071
|
+
hasUrl: "url" in s && typeof s.url === "string"
|
|
10072
|
+
}));
|
|
10073
|
+
}
|
|
10074
|
+
if (opts.compaction !== void 0) out.compaction = opts.compaction;
|
|
10075
|
+
if (opts.context !== void 0) out.context = { ...opts.context };
|
|
10076
|
+
return out;
|
|
10077
|
+
}
|
|
10078
|
+
function serializeOutputSchema(schema) {
|
|
10079
|
+
if (schema === null || typeof schema !== "object") return schema;
|
|
10080
|
+
const candidate = schema;
|
|
10081
|
+
if (candidate._def !== void 0 && typeof candidate.safeParse === "function") {
|
|
10082
|
+
try {
|
|
10083
|
+
return (0, import_zod_to_json_schema3.zodToJsonSchema)(schema, {
|
|
10084
|
+
target: "jsonSchema7",
|
|
10085
|
+
$refStrategy: "none"
|
|
10086
|
+
});
|
|
10087
|
+
} catch {
|
|
10088
|
+
return { error: "failed to serialize Zod schema for inspect" };
|
|
10089
|
+
}
|
|
10090
|
+
}
|
|
10091
|
+
return schema;
|
|
10092
|
+
}
|
|
10093
|
+
function scrubSkills(skills) {
|
|
10094
|
+
return {
|
|
10095
|
+
schemaVersion: 1,
|
|
10096
|
+
skills: skills.map((s) => ({
|
|
10097
|
+
name: s.name,
|
|
10098
|
+
description: s.description ?? "",
|
|
10099
|
+
hasPages: s.hasPages ?? false
|
|
10100
|
+
}))
|
|
10101
|
+
};
|
|
10102
|
+
}
|
|
10103
|
+
function scrubApiServices(services) {
|
|
10104
|
+
return {
|
|
10105
|
+
schemaVersion: 1,
|
|
10106
|
+
services: services.map((s) => {
|
|
10107
|
+
const out = { name: s.name };
|
|
10108
|
+
if (s.description !== void 0) out.description = s.description;
|
|
10109
|
+
if (s.baseUrl !== void 0) out.baseUrl = s.baseUrl;
|
|
10110
|
+
if (s.methods !== void 0) out.methods = s.methods.map((m) => m.name);
|
|
10111
|
+
return out;
|
|
10112
|
+
})
|
|
10113
|
+
};
|
|
10114
|
+
}
|
|
10115
|
+
|
|
9724
10116
|
// src/engine/rehydrate.ts
|
|
9725
10117
|
init_cjs_shims();
|
|
9726
10118
|
function rebuildMessagesFromEntries(entries) {
|
|
@@ -10179,6 +10571,7 @@ var Engine = class {
|
|
|
10179
10571
|
systemPrompt += "\n\n" + buildSchemaPrompt(options.outputSchema);
|
|
10180
10572
|
}
|
|
10181
10573
|
const gate = this.resolveGate();
|
|
10574
|
+
const inspect = this.buildInspectWriter(storage.workspace, logPath);
|
|
10182
10575
|
const registry = buildToolRegistry({
|
|
10183
10576
|
config: this.config,
|
|
10184
10577
|
storage,
|
|
@@ -10190,6 +10583,7 @@ var Engine = class {
|
|
|
10190
10583
|
agents,
|
|
10191
10584
|
mcpTools,
|
|
10192
10585
|
memory,
|
|
10586
|
+
inspect,
|
|
10193
10587
|
...this.config.hooks.propagateGateToSubagents === true && gate !== void 0 ? { subagentGate: gate } : {},
|
|
10194
10588
|
...skillSource !== void 0 ? { skillSource } : {},
|
|
10195
10589
|
...apiConfig !== void 0 ? { apiConfig } : {},
|
|
@@ -10198,6 +10592,36 @@ var Engine = class {
|
|
|
10198
10592
|
...this.internals.fetch !== void 0 ? { fetch: this.internals.fetch } : {}
|
|
10199
10593
|
});
|
|
10200
10594
|
applyRunToolFilter(registry, options);
|
|
10595
|
+
await inspect.writeStartSnapshot({
|
|
10596
|
+
systemPrompt,
|
|
10597
|
+
tools: this.snapshotTools(registry, mcpTools),
|
|
10598
|
+
runOptions: scrubRunOptions({ ...options, runId }),
|
|
10599
|
+
modelConfig: scrubModelConfig(
|
|
10600
|
+
{
|
|
10601
|
+
provider: this.config.model.provider,
|
|
10602
|
+
modelId: this.config.model.modelId,
|
|
10603
|
+
...this.config.model.baseURL !== void 0 ? { baseURL: this.config.model.baseURL } : {},
|
|
10604
|
+
...this.config.model.temperature !== void 0 ? { temperature: this.config.model.temperature } : {},
|
|
10605
|
+
...this.config.model.maxTokens !== void 0 ? { maxTokens: this.config.model.maxTokens } : {},
|
|
10606
|
+
...this.config.model.maxRetries !== void 0 ? { maxRetries: this.config.model.maxRetries } : {}
|
|
10607
|
+
},
|
|
10608
|
+
{ redactBaseURL: this.config.inspect.redactBaseURL }
|
|
10609
|
+
),
|
|
10610
|
+
...skillList !== void 0 ? { skills: scrubSkills(skillList) } : {},
|
|
10611
|
+
...mcpTools.length > 0 ? { mcpServers: this.snapshotMcpServers(mcpTools) } : {},
|
|
10612
|
+
...apiConfig !== void 0 && apiConfig.services.length > 0 ? { apiServices: scrubApiServices(apiConfig.services) } : {},
|
|
10613
|
+
...knowledgeRuntime !== void 0 ? {
|
|
10614
|
+
knowledge: {
|
|
10615
|
+
schemaVersion: 1,
|
|
10616
|
+
folders: [...knowledgeRuntime.folders],
|
|
10617
|
+
external: knowledgeRuntime.external.map((e) => {
|
|
10618
|
+
const link = { url: e.url };
|
|
10619
|
+
if (e.description !== void 0) link.description = e.description;
|
|
10620
|
+
return link;
|
|
10621
|
+
})
|
|
10622
|
+
}
|
|
10623
|
+
} : {}
|
|
10624
|
+
});
|
|
10201
10625
|
const writer = new TranscriptWriter({
|
|
10202
10626
|
storage: storage.workspace,
|
|
10203
10627
|
logPath,
|
|
@@ -10259,14 +10683,24 @@ var Engine = class {
|
|
|
10259
10683
|
// is already handled above by stripping the tool list, so the
|
|
10260
10684
|
// loop only ever sees `'auto'` or `'required'`.
|
|
10261
10685
|
...options.outputFormat !== void 0 ? { outputFormat: options.outputFormat } : {},
|
|
10262
|
-
...options.toolChoice === "required" ? { toolChoice: "required" } : {}
|
|
10263
|
-
|
|
10264
|
-
|
|
10265
|
-
|
|
10266
|
-
...options.outputSchema !== void 0 ? { outputSchema: options.outputSchema } : {}
|
|
10686
|
+
...options.toolChoice === "required" ? { toolChoice: "required" } : {},
|
|
10687
|
+
// Plan 026 — pass the inspect writer so the loop can append
|
|
10688
|
+
// events / per-turn rows. Disabled-mode writer is a no-op.
|
|
10689
|
+
inspect
|
|
10267
10690
|
});
|
|
10691
|
+
const result = await this.finalizeResult(
|
|
10692
|
+
loopResult,
|
|
10693
|
+
writer,
|
|
10694
|
+
logPath,
|
|
10695
|
+
{
|
|
10696
|
+
...options.outputFormat !== void 0 ? { outputFormat: options.outputFormat } : {},
|
|
10697
|
+
...options.outputSchema !== void 0 ? { outputSchema: options.outputSchema } : {}
|
|
10698
|
+
},
|
|
10699
|
+
inspect
|
|
10700
|
+
);
|
|
10268
10701
|
this.logRunEnd(log, runId, options.nodeId, result);
|
|
10269
10702
|
await this.firePostRunHook(runId, options.nodeId, result, ctx, logPath);
|
|
10703
|
+
await this.writeInspectToolsSummary(inspect, storage.workspace, logPath);
|
|
10270
10704
|
const capabilitiesMissing = ctx.getCapabilitiesMissing();
|
|
10271
10705
|
return toResponse(result, {
|
|
10272
10706
|
runId,
|
|
@@ -10334,6 +10768,7 @@ var Engine = class {
|
|
|
10334
10768
|
systemPrompt += "\n\n" + buildSchemaPrompt(options.outputSchema);
|
|
10335
10769
|
}
|
|
10336
10770
|
const gate = this.resolveGate();
|
|
10771
|
+
const inspect = this.buildInspectWriter(storage.workspace, logPath);
|
|
10337
10772
|
const registry = buildToolRegistry({
|
|
10338
10773
|
config: this.config,
|
|
10339
10774
|
storage,
|
|
@@ -10345,6 +10780,7 @@ var Engine = class {
|
|
|
10345
10780
|
agents,
|
|
10346
10781
|
mcpTools,
|
|
10347
10782
|
memory,
|
|
10783
|
+
inspect,
|
|
10348
10784
|
...this.config.hooks.propagateGateToSubagents === true && gate !== void 0 ? { subagentGate: gate } : {},
|
|
10349
10785
|
...skillSource !== void 0 ? { skillSource } : {},
|
|
10350
10786
|
...apiConfig !== void 0 ? { apiConfig } : {},
|
|
@@ -10352,6 +10788,42 @@ var Engine = class {
|
|
|
10352
10788
|
...knowledgeRuntime !== void 0 ? { knowledge: knowledgeRuntime } : {},
|
|
10353
10789
|
...this.internals.fetch !== void 0 ? { fetch: this.internals.fetch } : {}
|
|
10354
10790
|
});
|
|
10791
|
+
await inspect.writeStartSnapshot({
|
|
10792
|
+
systemPrompt,
|
|
10793
|
+
tools: this.snapshotTools(registry, mcpTools),
|
|
10794
|
+
runOptions: scrubRunOptions({
|
|
10795
|
+
runId: snapshot.runId,
|
|
10796
|
+
nodeId: snapshot.nodeId,
|
|
10797
|
+
task: "[resumed run \u2014 original task in transcript]",
|
|
10798
|
+
...options.outputFormat !== void 0 ? { outputFormat: options.outputFormat } : {},
|
|
10799
|
+
...options.outputSchema !== void 0 ? { outputSchema: options.outputSchema } : {}
|
|
10800
|
+
}),
|
|
10801
|
+
modelConfig: scrubModelConfig(
|
|
10802
|
+
{
|
|
10803
|
+
provider: this.config.model.provider,
|
|
10804
|
+
modelId: this.config.model.modelId,
|
|
10805
|
+
...this.config.model.baseURL !== void 0 ? { baseURL: this.config.model.baseURL } : {},
|
|
10806
|
+
...this.config.model.temperature !== void 0 ? { temperature: this.config.model.temperature } : {},
|
|
10807
|
+
...this.config.model.maxTokens !== void 0 ? { maxTokens: this.config.model.maxTokens } : {},
|
|
10808
|
+
...this.config.model.maxRetries !== void 0 ? { maxRetries: this.config.model.maxRetries } : {}
|
|
10809
|
+
},
|
|
10810
|
+
{ redactBaseURL: this.config.inspect.redactBaseURL }
|
|
10811
|
+
),
|
|
10812
|
+
...skillList !== void 0 ? { skills: scrubSkills(skillList) } : {},
|
|
10813
|
+
...mcpTools.length > 0 ? { mcpServers: this.snapshotMcpServers(mcpTools) } : {},
|
|
10814
|
+
...apiConfig !== void 0 && apiConfig.services.length > 0 ? { apiServices: scrubApiServices(apiConfig.services) } : {},
|
|
10815
|
+
...knowledgeRuntime !== void 0 ? {
|
|
10816
|
+
knowledge: {
|
|
10817
|
+
schemaVersion: 1,
|
|
10818
|
+
folders: [...knowledgeRuntime.folders],
|
|
10819
|
+
external: knowledgeRuntime.external.map((e) => {
|
|
10820
|
+
const link = { url: e.url };
|
|
10821
|
+
if (e.description !== void 0) link.description = e.description;
|
|
10822
|
+
return link;
|
|
10823
|
+
})
|
|
10824
|
+
}
|
|
10825
|
+
} : {}
|
|
10826
|
+
});
|
|
10355
10827
|
const priorState = await loadWriterState(storage.workspace, logPath);
|
|
10356
10828
|
const writer = new TranscriptWriter({
|
|
10357
10829
|
storage: storage.workspace,
|
|
@@ -10441,14 +10913,24 @@ ${inputJson}
|
|
|
10441
10913
|
...runTimeout.signal !== void 0 ? { runSignal: runTimeout.signal, runTimeoutMs: this.config.execution.runTimeoutMs } : {},
|
|
10442
10914
|
...gate !== void 0 ? { gateBeforeTool: gate } : {},
|
|
10443
10915
|
..._internal?.handoffToRunner === true ? { handoffToRunner: true } : {},
|
|
10444
|
-
...offloadConfig !== void 0 ? { toolResultOffload: offloadConfig } : {}
|
|
10445
|
-
|
|
10446
|
-
|
|
10447
|
-
|
|
10448
|
-
...options.outputSchema !== void 0 ? { outputSchema: options.outputSchema } : {}
|
|
10916
|
+
...offloadConfig !== void 0 ? { toolResultOffload: offloadConfig } : {},
|
|
10917
|
+
// Plan 026 — append resume's events / per-turn rows to the
|
|
10918
|
+
// existing inspect/ logs.
|
|
10919
|
+
inspect
|
|
10449
10920
|
});
|
|
10921
|
+
const result = await this.finalizeResult(
|
|
10922
|
+
loopResult,
|
|
10923
|
+
writer,
|
|
10924
|
+
logPath,
|
|
10925
|
+
{
|
|
10926
|
+
...options.outputFormat !== void 0 ? { outputFormat: options.outputFormat } : {},
|
|
10927
|
+
...options.outputSchema !== void 0 ? { outputSchema: options.outputSchema } : {}
|
|
10928
|
+
},
|
|
10929
|
+
inspect
|
|
10930
|
+
);
|
|
10450
10931
|
this.logRunEnd(log, snapshot.runId, snapshot.nodeId, result);
|
|
10451
10932
|
await this.firePostRunHook(snapshot.runId, snapshot.nodeId, result, ctx, logPath);
|
|
10933
|
+
await this.writeInspectToolsSummary(inspect, storage.workspace, logPath);
|
|
10452
10934
|
const capabilitiesMissing = ctx.getCapabilitiesMissing();
|
|
10453
10935
|
return toResponse(result, {
|
|
10454
10936
|
runId: snapshot.runId,
|
|
@@ -11096,7 +11578,7 @@ ${inputJson}
|
|
|
11096
11578
|
};
|
|
11097
11579
|
await dispatchHooks(this.config.hooks.postRun, event);
|
|
11098
11580
|
}
|
|
11099
|
-
async finalizeResult(loopResult, writer, _logPath, jsonOptions) {
|
|
11581
|
+
async finalizeResult(loopResult, writer, _logPath, jsonOptions, inspect) {
|
|
11100
11582
|
if (loopResult.status === "done") {
|
|
11101
11583
|
await writer.setStatus("done");
|
|
11102
11584
|
let data;
|
|
@@ -11105,10 +11587,27 @@ ${inputJson}
|
|
|
11105
11587
|
if (parsed.ok) {
|
|
11106
11588
|
if (jsonOptions.outputSchema) {
|
|
11107
11589
|
const validated = validateOutput(parsed.value, jsonOptions.outputSchema);
|
|
11108
|
-
|
|
11590
|
+
if (validated.ok) {
|
|
11591
|
+
data = validated.data;
|
|
11592
|
+
} else {
|
|
11593
|
+
await inspect?.appendEvent({
|
|
11594
|
+
type: "json_parse_failure",
|
|
11595
|
+
turn: loopResult.turns,
|
|
11596
|
+
validationError: validated.error,
|
|
11597
|
+
ts: Date.now()
|
|
11598
|
+
});
|
|
11599
|
+
data = void 0;
|
|
11600
|
+
}
|
|
11109
11601
|
} else {
|
|
11110
11602
|
data = parsed.value;
|
|
11111
11603
|
}
|
|
11604
|
+
} else {
|
|
11605
|
+
await inspect?.appendEvent({
|
|
11606
|
+
type: "json_parse_failure",
|
|
11607
|
+
turn: loopResult.turns,
|
|
11608
|
+
parseError: parsed.error ?? "unknown parse error",
|
|
11609
|
+
ts: Date.now()
|
|
11610
|
+
});
|
|
11112
11611
|
}
|
|
11113
11612
|
}
|
|
11114
11613
|
return {
|
|
@@ -11292,7 +11791,147 @@ ${inputJson}
|
|
|
11292
11791
|
...this.internals.fetch !== void 0 ? { fetch: this.internals.fetch } : {}
|
|
11293
11792
|
});
|
|
11294
11793
|
}
|
|
11794
|
+
// Plan 026 — inspect-bundle helpers ----------------------------
|
|
11795
|
+
buildInspectWriter(storage, logPath) {
|
|
11796
|
+
const inspect = this.config.inspect;
|
|
11797
|
+
return new InspectWriter({
|
|
11798
|
+
storage,
|
|
11799
|
+
logPath,
|
|
11800
|
+
enabled: inspect.enabled
|
|
11801
|
+
});
|
|
11802
|
+
}
|
|
11803
|
+
/**
|
|
11804
|
+
* Snapshot the live ToolRegistry into the inspect-bundle shape.
|
|
11805
|
+
* Tool source is inferred by name: MCP tools have the
|
|
11806
|
+
* `mcp__{server}__{tool}` prefix; everything else is core.
|
|
11807
|
+
*/
|
|
11808
|
+
snapshotTools(registry, mcpTools) {
|
|
11809
|
+
const mcpNameSet = new Set(mcpTools.map((t) => t.name));
|
|
11810
|
+
return {
|
|
11811
|
+
schemaVersion: 1,
|
|
11812
|
+
tools: registry.list().map((t) => {
|
|
11813
|
+
const out = {
|
|
11814
|
+
name: t.name,
|
|
11815
|
+
description: t.description ?? "",
|
|
11816
|
+
inputSchema: this.toolInputSchemaToJson(t),
|
|
11817
|
+
source: mcpNameSet.has(t.name) ? "mcp" : "core",
|
|
11818
|
+
...t.isCapabilityStub === true ? { isCapabilityStub: true } : {}
|
|
11819
|
+
};
|
|
11820
|
+
return out;
|
|
11821
|
+
})
|
|
11822
|
+
};
|
|
11823
|
+
}
|
|
11824
|
+
/** Convert a Zod input schema to JSON Schema for persistence. */
|
|
11825
|
+
toolInputSchemaToJson(t) {
|
|
11826
|
+
const raw = t.inputSchema;
|
|
11827
|
+
if (raw === void 0 || raw === null) return {};
|
|
11828
|
+
const candidate = raw;
|
|
11829
|
+
if (typeof candidate === "object" && candidate._def !== void 0 && typeof candidate.safeParse === "function") {
|
|
11830
|
+
try {
|
|
11831
|
+
const json2 = (0, import_zod_to_json_schema4.zodToJsonSchema)(raw, {
|
|
11832
|
+
target: "jsonSchema7",
|
|
11833
|
+
$refStrategy: "none"
|
|
11834
|
+
});
|
|
11835
|
+
return json2;
|
|
11836
|
+
} catch {
|
|
11837
|
+
return {};
|
|
11838
|
+
}
|
|
11839
|
+
}
|
|
11840
|
+
return raw;
|
|
11841
|
+
}
|
|
11842
|
+
/**
|
|
11843
|
+
* Plan 026 — aggregate `tools-summary.json` from the persisted
|
|
11844
|
+
* transcript shards. Walks meta.json for shard count, reads each
|
|
11845
|
+
* shard, counts every tool_use block by name. Best-effort; the
|
|
11846
|
+
* InspectWriter swallows write failures.
|
|
11847
|
+
*/
|
|
11848
|
+
async writeInspectToolsSummary(inspect, storage, logPath) {
|
|
11849
|
+
const counts = /* @__PURE__ */ new Map();
|
|
11850
|
+
let total = 0;
|
|
11851
|
+
try {
|
|
11852
|
+
const metaRaw = await storage.readFile(`${logPath}/meta.json`);
|
|
11853
|
+
if (!metaRaw) return;
|
|
11854
|
+
const meta = JSON.parse(metaRaw);
|
|
11855
|
+
const shardCount = meta.shardCount ?? 0;
|
|
11856
|
+
for (let i = 0; i < shardCount; i++) {
|
|
11857
|
+
const name = `${String(i).padStart(6, "0")}.jsonl`;
|
|
11858
|
+
const text2 = await storage.readFile(`${logPath}/${name}`);
|
|
11859
|
+
if (!text2) continue;
|
|
11860
|
+
for (const line of text2.split("\n")) {
|
|
11861
|
+
if (!line) continue;
|
|
11862
|
+
try {
|
|
11863
|
+
const entry = JSON.parse(line);
|
|
11864
|
+
if (entry.type !== "assistant") continue;
|
|
11865
|
+
const content = entry.message?.content;
|
|
11866
|
+
if (!Array.isArray(content)) continue;
|
|
11867
|
+
for (const block of content) {
|
|
11868
|
+
const b = block;
|
|
11869
|
+
if (b.type === "tool_use" && typeof b.name === "string") {
|
|
11870
|
+
counts.set(b.name, (counts.get(b.name) ?? 0) + 1);
|
|
11871
|
+
total++;
|
|
11872
|
+
}
|
|
11873
|
+
}
|
|
11874
|
+
} catch {
|
|
11875
|
+
}
|
|
11876
|
+
}
|
|
11877
|
+
}
|
|
11878
|
+
} catch {
|
|
11879
|
+
return;
|
|
11880
|
+
}
|
|
11881
|
+
await inspect.writeToolsSummary({
|
|
11882
|
+
schemaVersion: 1,
|
|
11883
|
+
tools: [...counts.entries()].map(([name, callCount]) => ({ name, callCount })).sort((a, b) => b.callCount - a.callCount),
|
|
11884
|
+
totalCalls: total
|
|
11885
|
+
});
|
|
11886
|
+
}
|
|
11887
|
+
/**
|
|
11888
|
+
* Snapshot the resolved MCP servers. Right now `mcpManager.getTools()`
|
|
11889
|
+
* returns the flat tool list; we group them by server-name prefix to
|
|
11890
|
+
* recover which server exposed which tool.
|
|
11891
|
+
*/
|
|
11892
|
+
snapshotMcpServers(mcpTools) {
|
|
11893
|
+
const byServer = /* @__PURE__ */ new Map();
|
|
11894
|
+
for (const t of mcpTools) {
|
|
11895
|
+
const m = t.name.match(/^mcp__([^_]+)__(.+)$/);
|
|
11896
|
+
const server = m?.[1] ?? "unknown";
|
|
11897
|
+
const list = byServer.get(server) ?? [];
|
|
11898
|
+
list.push(t.name);
|
|
11899
|
+
byServer.set(server, list);
|
|
11900
|
+
}
|
|
11901
|
+
const declaredMap = this.config.mcp.servers;
|
|
11902
|
+
return {
|
|
11903
|
+
schemaVersion: 1,
|
|
11904
|
+
servers: [...byServer.entries()].map(([name, tools]) => {
|
|
11905
|
+
const declared = declaredMap[name];
|
|
11906
|
+
const out = {
|
|
11907
|
+
name,
|
|
11908
|
+
// If the server isn't in the declared map (synthetic / dynamic),
|
|
11909
|
+
// default to 'http' as a best-effort label.
|
|
11910
|
+
type: declared?.type ?? "http",
|
|
11911
|
+
state: "connected",
|
|
11912
|
+
tools
|
|
11913
|
+
};
|
|
11914
|
+
if (declared !== void 0) {
|
|
11915
|
+
if (declared.type === "stdio") {
|
|
11916
|
+
out.command = declared.command;
|
|
11917
|
+
out.args = [...declared.args];
|
|
11918
|
+
} else {
|
|
11919
|
+
out.url = declared.url;
|
|
11920
|
+
if (declared.headers !== void 0) {
|
|
11921
|
+
out.headers = redactHeadersInline(declared.headers);
|
|
11922
|
+
}
|
|
11923
|
+
}
|
|
11924
|
+
}
|
|
11925
|
+
return out;
|
|
11926
|
+
})
|
|
11927
|
+
};
|
|
11928
|
+
}
|
|
11295
11929
|
};
|
|
11930
|
+
function redactHeadersInline(headers) {
|
|
11931
|
+
const out = {};
|
|
11932
|
+
for (const k of Object.keys(headers)) out[k] = "<redacted>";
|
|
11933
|
+
return out;
|
|
11934
|
+
}
|
|
11296
11935
|
function buildToolRegistry(options) {
|
|
11297
11936
|
const {
|
|
11298
11937
|
config,
|
|
@@ -11446,7 +12085,10 @@ function buildToolRegistry(options) {
|
|
|
11446
12085
|
agents,
|
|
11447
12086
|
coordinatorMode: isCoordinatorMode(config),
|
|
11448
12087
|
...subagentGate !== void 0 ? { gateBeforeTool: subagentGate } : {},
|
|
11449
|
-
...options.toolResultOffload !== void 0 ? { toolResultOffload: options.toolResultOffload } : {}
|
|
12088
|
+
...options.toolResultOffload !== void 0 ? { toolResultOffload: options.toolResultOffload } : {},
|
|
12089
|
+
// Plan 026 — Agent tool emits subagent_spawn_attempt to the
|
|
12090
|
+
// parent's events.jsonl on each runAgent call (success and failure).
|
|
12091
|
+
...options.inspect !== void 0 ? { inspect: options.inspect } : {}
|
|
11450
12092
|
});
|
|
11451
12093
|
if (!disabled.has("Agent") && (wantAll || enabled.has("Agent"))) {
|
|
11452
12094
|
registry.register(agentTool);
|
|
@@ -11462,8 +12104,9 @@ function buildToolRegistry(options) {
|
|
|
11462
12104
|
for (const tool of mcpTools) {
|
|
11463
12105
|
if (disabled.has(tool.name)) continue;
|
|
11464
12106
|
if (wantAll || enabled.has(tool.name)) {
|
|
11465
|
-
|
|
11466
|
-
|
|
12107
|
+
const wrapped = withCapabilityCheck(tool, spawnAvailable);
|
|
12108
|
+
registry.register(wrapped);
|
|
12109
|
+
childRegistry.register(wrapped);
|
|
11467
12110
|
}
|
|
11468
12111
|
}
|
|
11469
12112
|
if (!disabled.has("ToolSearch") && (wantAll || enabled.has("ToolSearch"))) {
|
|
@@ -11483,6 +12126,11 @@ init_retry();
|
|
|
11483
12126
|
init_snapshot();
|
|
11484
12127
|
init_synthesize();
|
|
11485
12128
|
init_types();
|
|
12129
|
+
|
|
12130
|
+
// src/inspect/index.ts
|
|
12131
|
+
init_cjs_shims();
|
|
12132
|
+
|
|
12133
|
+
// src/index.ts
|
|
11486
12134
|
var ENGINE_VERSION = "0.0.0";
|
|
11487
12135
|
function initEngine(user = {}) {
|
|
11488
12136
|
let resolved;
|
|
@@ -11522,6 +12170,7 @@ function resolveApiKey(config) {
|
|
|
11522
12170
|
EpisodicMemory,
|
|
11523
12171
|
Hippocampus,
|
|
11524
12172
|
InlineSkillSource,
|
|
12173
|
+
InspectWriter,
|
|
11525
12174
|
LocalStorageAdapter,
|
|
11526
12175
|
MAX_ATTEMPTS,
|
|
11527
12176
|
McpClient,
|
|
@@ -11529,6 +12178,7 @@ function resolveApiKey(config) {
|
|
|
11529
12178
|
McpManager,
|
|
11530
12179
|
McpProtocolError,
|
|
11531
12180
|
McpTimeoutError,
|
|
12181
|
+
NULL_INSPECT_WRITER,
|
|
11532
12182
|
NodeBackgroundExecutor,
|
|
11533
12183
|
NotImplementedError,
|
|
11534
12184
|
PlanSchema,
|