@dimi-agent/cli 0.6.7 → 0.6.8

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.
Files changed (2) hide show
  1. package/dist/main.mjs +2279 -92
  2. package/package.json +4 -4
package/dist/main.mjs CHANGED
@@ -34346,7 +34346,7 @@ var init_telemetry$2 = __esmMin((() => {
34346
34346
  };
34347
34347
  ITelemetryService = createDecorator("agentTelemetryService");
34348
34348
  }));
34349
- var init_events$7 = __esmMin((() => {}));
34349
+ var init_events$8 = __esmMin((() => {}));
34350
34350
  //#endregion
34351
34351
  //#region ../../packages/agent-core-v2/src/app/telemetry/telemetryService.ts
34352
34352
  var TelemetryService, TelemetryContextView;
@@ -99307,6 +99307,11 @@ function loadNative() {
99307
99307
  function coldRebuild(recordsJson) {
99308
99308
  return loadNative().coldRebuild(recordsJson);
99309
99309
  }
99310
+ /** Release an agent's scoped subagent registry (tasks + steering queues).
99311
+ * Call when the owning agent scope is disposed. */
99312
+ function dropTaskRegistry(registryId) {
99313
+ loadNative().dropTaskRegistry(registryId);
99314
+ }
99310
99315
  /** `RustHostProcess.spawn` — the M2 exec spawn socket. */
99311
99316
  async function rustHostProcessSpawn(command, args, options) {
99312
99317
  return loadNative().RustHostProcess.spawn(command, [...args], options);
@@ -99337,7 +99342,7 @@ function rustHostEnvironmentProbe() {
99337
99342
  function rustTerminalSpawn(options) {
99338
99343
  return loadNative().RustTerminal.spawn(options);
99339
99344
  }
99340
- var nodeRequire$4, binding, PLATFORM_SUBPACKAGE, RustAgentTranscript, RustFileSystem;
99345
+ var nodeRequire$4, binding, PLATFORM_SUBPACKAGE, RustAgentTranscript, RustFileSystem, RustTurnSession;
99341
99346
  var init_src$7 = __esmMin((() => {
99342
99347
  nodeRequire$4 = createRequire(import.meta.url);
99343
99348
  PLATFORM_SUBPACKAGE = `@dimi-agent/dimi-native-${process.platform}-${process.arch}`;
@@ -99397,6 +99402,89 @@ var init_src$7 = __esmMin((() => {
99397
99402
  return loadNative().RustFileSystem.realpath(path);
99398
99403
  }
99399
99404
  };
99405
+ RustTurnSession = class {
99406
+ #inner;
99407
+ constructor(inputJson, policyJson, scriptedSegmentsJson, registryId) {
99408
+ const NativeClass = loadNative().RustTurnSession;
99409
+ this.#inner = new NativeClass(inputJson, policyJson, scriptedSegmentsJson ?? null, registryId);
99410
+ }
99411
+ /** Release the agent-scoped subagent registry (tasks + steering queues).
99412
+ * Call when the owning agent scope is disposed. */
99413
+ static dropTaskRegistry(registryId) {
99414
+ dropTaskRegistry(registryId);
99415
+ }
99416
+ /** Register the per-event callback: every engine event emitted by `run()` /
99417
+ * `resume()` is pushed through it as a JSON string, in emission order, as
99418
+ * it happens. Register before the first `run()`. */
99419
+ setOnEvent(callback) {
99420
+ this.#inner.setOnEvent(callback);
99421
+ }
99422
+ async run() {
99423
+ return this.#inner.run();
99424
+ }
99425
+ async resume(decisionJson) {
99426
+ return this.#inner.resume(decisionJson);
99427
+ }
99428
+ /** Record a session-scope approval (P1-6): the engine's policy is re-read
99429
+ * on every run/resume, so a pattern approved for the session mid-turn is
99430
+ * honored by the SAME turn's remaining batch. */
99431
+ addSessionApproval(pattern) {
99432
+ this.#inner.addSessionApproval(pattern);
99433
+ }
99434
+ /** Register the native-tool PreToolUse gate (A2 review): every registry
99435
+ * tool call is announced through `callback` (`{requestId, toolName,
99436
+ * arguments}` JSON); answer with `completeToolGate(requestId,
99437
+ * {decision:'allow'|'block', reason?})`. A block short-circuits the call. */
99438
+ setToolGate(callback) {
99439
+ this.#inner.setToolGate(callback);
99440
+ }
99441
+ /** Answer a pending gate request (see `setToolGate`). */
99442
+ completeToolGate(requestId, verdictJson) {
99443
+ this.#inner.completeToolGate(requestId, verdictJson);
99444
+ }
99445
+ /** Register a TS-side tool; `completeToolCall` finishes each call. The
99446
+ * definition (description + JSON parameters schema) is advertised to the
99447
+ * model from the next request on. */
99448
+ registerExternalTool(name, description, parametersJson, callback) {
99449
+ this.#inner.registerExternalTool(name, description, parametersJson, callback);
99450
+ }
99451
+ /** Advertise the LLM-facing definition (description + JSON parameters
99452
+ * schema) of a Rust-native tool (Agent / AgentOutput / WaitFor) registered
99453
+ * executor-first at construction. The executor stays the same; only the
99454
+ * def is updated, so the engine's request `tools` field carries it from
99455
+ * the next request on. */
99456
+ registerNativeToolDef(name, description, parametersJson) {
99457
+ this.#inner.registerNativeToolDef(name, description, parametersJson);
99458
+ }
99459
+ /** Steer the running turn (drained into its next LLM request). Returns
99460
+ * `false` when the turn has already finished — the caller must start a
99461
+ * new turn instead (the steer is never dropped). */
99462
+ steer(message) {
99463
+ return this.#inner.steer(message);
99464
+ }
99465
+ /** Steer a background subagent spawned by the `Agent` tool. */
99466
+ steerSubagent(agentId, message) {
99467
+ this.#inner.steerSubagent(agentId, message);
99468
+ }
99469
+ /** Cancel the running turn (engine stops at the next boundary). */
99470
+ cancel() {
99471
+ this.#inner.cancel();
99472
+ }
99473
+ /** Cancel a background task (TaskStop parity): the engine kills the
99474
+ * subagent nested turn / backgrounded bash command and settles "killed",
99475
+ * carrying the stop reason on the wire. */
99476
+ cancelTask(taskId, reason) {
99477
+ this.#inner.cancelTask(taskId, reason);
99478
+ }
99479
+ /** Close the session (agent dispose): task events stop forwarding, the
99480
+ * in-flight turn is cancelled. Background workers observe the close. */
99481
+ close() {
99482
+ this.#inner.close();
99483
+ }
99484
+ completeToolCall(requestId, resultJson) {
99485
+ this.#inner.completeToolCall(requestId, resultJson);
99486
+ }
99487
+ };
99400
99488
  }));
99401
99489
  //#endregion
99402
99490
  //#region ../../packages/agent-core-v2/src/os/backends/rust-local/rustHostEnvironmentService.ts
@@ -121936,7 +122024,7 @@ function emptyOutputSnapshot() {
121936
122024
  function agentTaskNotificationChildren(output) {
121937
122025
  if (output.fullOutputAvailable && output.outputPath !== void 0) return [renderOutputFileBlock(output.outputPath, output.outputSizeBytes)];
121938
122026
  if (output.preview.length === 0) return void 0;
121939
- return [renderOutputPreviewBlock(output)];
122027
+ return [renderOutputPreviewBlock$1(output)];
121940
122028
  }
121941
122029
  function renderOutputFileBlock(outputPath, outputSizeBytes) {
121942
122030
  return [
@@ -121945,7 +122033,7 @@ function renderOutputFileBlock(outputPath, outputSizeBytes) {
121945
122033
  "</output-file>"
121946
122034
  ].join("\n");
121947
122035
  }
121948
- function renderOutputPreviewBlock(output) {
122036
+ function renderOutputPreviewBlock$1(output) {
121949
122037
  return [
121950
122038
  `<output-preview bytes="${String(output.previewBytes)}" total_bytes="${String(output.outputSizeBytes)}" truncated="${String(output.truncated)}">`,
121951
122039
  output.truncated ? `Showing the last ${String(output.previewBytes)} bytes. No persisted full output is available.` : "No persisted full output is available; this preview is the currently buffered task output.",
@@ -122027,7 +122115,7 @@ function errorMessage$7(error) {
122027
122115
  if (error instanceof Error) return error.message;
122028
122116
  return String(error);
122029
122117
  }
122030
- var TaskNotificationDeliveryModel, MAX_OUTPUT_BYTES, TERMINAL_OUTPUT_TAIL_BYTES, MAX_TASK_OUTPUT_BYTES, SIGTERM_GRACE_MS, TASK_ID_ALPHABET, SESSION_CLOSED_REASON, NOTIFICATION_FALLBACK_PREVIEW_BYTES, ACTIVE_BACKGROUND_TASK_INJECTION_VARIANT, ACTIVE_BACKGROUND_TASK_GUIDANCE, TaskNotificationStepRequest, taskGhostsKey, taskScheduledNotificationKeysKey, taskDeliveredNotificationKeysKey, taskActiveTaskReminderPendingKey, AgentTaskService;
122118
+ var TaskNotificationDeliveryModel, MAX_OUTPUT_BYTES, TERMINAL_OUTPUT_TAIL_BYTES, MAX_TASK_OUTPUT_BYTES, TASK_ID_ALPHABET, SESSION_CLOSED_REASON, NOTIFICATION_FALLBACK_PREVIEW_BYTES, ACTIVE_BACKGROUND_TASK_INJECTION_VARIANT, ACTIVE_BACKGROUND_TASK_GUIDANCE, TaskNotificationStepRequest, taskGhostsKey, taskScheduledNotificationKeysKey, taskDeliveredNotificationKeysKey, taskActiveTaskReminderPendingKey, AgentTaskService;
122031
122119
  var init_taskService = __esmMin((() => {
122032
122120
  init_dist$5();
122033
122121
  init_scope();
@@ -122075,7 +122163,6 @@ var init_taskService = __esmMin((() => {
122075
122163
  MAX_OUTPUT_BYTES = 1024 * 1024;
122076
122164
  TERMINAL_OUTPUT_TAIL_BYTES = 4 * 1024;
122077
122165
  MAX_TASK_OUTPUT_BYTES = 16 * 1024 * 1024;
122078
- SIGTERM_GRACE_MS = 5e3;
122079
122166
  TASK_ID_ALPHABET = "0123456789abcdefghijklmnopqrstuvwxyz";
122080
122167
  SESSION_CLOSED_REASON = "Session closed";
122081
122168
  NOTIFICATION_FALLBACK_PREVIEW_BYTES = 3e3;
@@ -122274,7 +122361,7 @@ var init_taskService = __esmMin((() => {
122274
122361
  };
122275
122362
  this.assertCanRegister(detached);
122276
122363
  const entry = {
122277
- taskId: generateTaskId(task.idPrefix),
122364
+ taskId: options.taskId ?? generateTaskId(task.idPrefix),
122278
122365
  task,
122279
122366
  handle: void 0,
122280
122367
  outputChunks: [],
@@ -122584,7 +122671,7 @@ var init_taskService = __esmMin((() => {
122584
122671
  entry.stopReason = options.stopReason;
122585
122672
  if (entry.handle) entry.handle.cancel();
122586
122673
  else entry.abortController.abort(options.abortReason);
122587
- const graceMs = resolveAgentTaskConfig(this.config)?.killGracePeriodMs ?? SIGTERM_GRACE_MS;
122674
+ const graceMs = resolveAgentTaskConfig(this.config)?.killGracePeriodMs ?? 5e3;
122588
122675
  let graceTimer;
122589
122676
  const graceful = await Promise.race([entry.lifecyclePromise.then(() => true, () => true), new Promise((resolve) => {
122590
122677
  graceTimer = setTimeout(() => {
@@ -123262,6 +123349,258 @@ var init_waitForTool = __esmMin((() => {
123262
123349
  });
123263
123350
  }));
123264
123351
  //#endregion
123352
+ //#region ../../packages/agent-core-v2/src/agent/tools/agent-output/agent-output.ts
123353
+ var AgentOutputInputSchema, AGENT_NOT_FOUND_MESSAGE, IAgentOutputTool;
123354
+ var init_agent_output$1 = __esmMin((() => {
123355
+ init_zod$1();
123356
+ init_instantiation();
123357
+ AgentOutputInputSchema = object({
123358
+ agent_id: string$2().describe("Agent ID of the subagent to inspect (returned by the Agent tool)."),
123359
+ tail_lines: number$2().int().min(1).max(500).optional().describe("How many of the most recent renderable records to show. Defaults to 60. The output is a transcript-style view of the subagent's latest activity.")
123360
+ });
123361
+ AGENT_NOT_FOUND_MESSAGE = "Agent instance not found.";
123362
+ IAgentOutputTool = createDecorator("agentOutputTool");
123363
+ }));
123364
+ //#endregion
123365
+ //#region ../../packages/agent-core-v2/src/agent/contextSize/contextSize.ts
123366
+ var IAgentContextSizeService;
123367
+ var init_contextSize = __esmMin((() => {
123368
+ init_instantiation();
123369
+ IAgentContextSizeService = createDecorator("agentContextSizeService");
123370
+ }));
123371
+ //#endregion
123372
+ //#region ../../packages/agent-core-v2/src/agent/tools/agent-output/agent-output.md?raw
123373
+ var agent_output_default;
123374
+ var init_agent_output = __esmMin((() => {
123375
+ agent_output_default = "Read the recent rendered output of a subagent — the same transcript-style view a human sees in the TUI: its latest assistant text, thinking, tool calls, and task progress, in time order.\n\nSubagents run fully asynchronously. Use this tool to check on one:\n\n- While you still have other work, do that work instead — the subagent's result (and completion notification) arrives on its own.\n- When you have nothing else to do and want to see what the subagent is doing, call this tool with the `agent_id` returned by the Agent tool.\n- If it is still working and you want to park until it progresses, call `WaitFor` with a reasonable `timeout_seconds` instead of polling this tool in a loop; the wait wakes you on the completion notification or the timeout, then check again with this tool.\n\nPass `tail_lines` to control how much of the recent activity to show (default 60). The `agent_id` is the Agent tool's `agent_id` parameter value (e.g. \"agent-6\"), NOT the `task_id` from its output.\n";
123376
+ }));
123377
+ //#endregion
123378
+ //#region ../../packages/agent-core-v2/src/agent/tools/agent-output/agentOutputTool.ts
123379
+ /**
123380
+ * `tools` domain (L7) — `AgentOutputTool` implementation (the `AgentOutput`
123381
+ * tool).
123382
+ *
123383
+ * Returns a transcript-style view of a subagent's recent activity by reading
123384
+ * the tail of its `wire.jsonl` journal (`<sessionDir>/agents/<agentId>/`):
123385
+ * assistant text, thinking, tool calls, and task progress in time order —
123386
+ * the same surface a human sees in the TUI. Subagents run fully
123387
+ * asynchronously, so this is the primary progress-check tool for the calling
123388
+ * agent (park with `WaitFor` instead of polling when there is nothing else
123389
+ * to do).
123390
+ *
123391
+ * Registered via the module-level `registerAgentToolService(IAgentOutputTool,
123392
+ * AgentOutputTool)` at the bottom of this file — the same "import = register"
123393
+ * pattern used by every agent tool. Bound at Agent scope.
123394
+ */
123395
+ function toRenderable(line) {
123396
+ const trimmed = line.trim();
123397
+ if (trimmed.length === 0) return void 0;
123398
+ let parsed;
123399
+ try {
123400
+ parsed = JSON.parse(trimmed);
123401
+ } catch {
123402
+ return;
123403
+ }
123404
+ if (typeof parsed !== "object" || parsed === null) return void 0;
123405
+ const record = parsed;
123406
+ const timeMs = typeof record.time === "number" ? normalizeTimestampMs$1(record.time) : void 0;
123407
+ const turnStep = turnStepLabel(record.event);
123408
+ switch (record.type) {
123409
+ case "turn.prompt": return {
123410
+ timeMs: timeMs ?? 0,
123411
+ turnStep: "",
123412
+ lines: [`user: ${clip(textOfPrompt(record.input), PROMPT_MAX_CHARS)}`]
123413
+ };
123414
+ case "context.append_loop_event": {
123415
+ const event = record.event;
123416
+ const eventType = event?.type;
123417
+ if (eventType === "content.part" && typeof event?.part?.type === "string") {
123418
+ const partType = event.part.type;
123419
+ const text = partType === "think" ? typeof event.part.think === "string" ? event.part.think : "" : typeof event.part.text === "string" ? event.part.text : "";
123420
+ return {
123421
+ timeMs: timeMs ?? 0,
123422
+ turnStep,
123423
+ lines: [`${partType === "think" ? "think" : "assistant"}: ${clip(text, LINE_MAX_CHARS)}`]
123424
+ };
123425
+ }
123426
+ if (eventType === "tool.call" && typeof event?.name === "string") return {
123427
+ timeMs: timeMs ?? 0,
123428
+ turnStep,
123429
+ lines: [`tool: ${event.name}${argsLabel(event.args)}`]
123430
+ };
123431
+ if (eventType === "tool.result") {
123432
+ const done = event?.isError === true ? "error" : "done";
123433
+ return {
123434
+ timeMs: timeMs ?? 0,
123435
+ turnStep,
123436
+ lines: [` → ${done}`]
123437
+ };
123438
+ }
123439
+ return;
123440
+ }
123441
+ case "task.started":
123442
+ case "task.terminated": {
123443
+ const info = record.info;
123444
+ if (info === void 0) return void 0;
123445
+ const description = typeof info.description === "string" ? info.description : "";
123446
+ const taskId = typeof info.taskId === "string" ? info.taskId : "";
123447
+ const status = typeof info.status === "string" ? info.status : "";
123448
+ const label = record.type === "task.started" ? `task: ${clip(description, LINE_MAX_CHARS)} (running, ${taskId})` : `task: ${clip(description, LINE_MAX_CHARS)} (${status}, ${taskId})`;
123449
+ return {
123450
+ timeMs: timeMs ?? 0,
123451
+ turnStep: "",
123452
+ lines: [label]
123453
+ };
123454
+ }
123455
+ default: return;
123456
+ }
123457
+ }
123458
+ function turnStepLabel(event) {
123459
+ if (event === void 0) return "";
123460
+ const turn = typeof event.turnId === "string" ? event.turnId : void 0;
123461
+ const step = typeof event.step === "number" ? event.step : void 0;
123462
+ if (turn === void 0 && step === void 0) return "";
123463
+ return `[turn ${turn ?? "?"} step ${step ?? "?"}] `;
123464
+ }
123465
+ function argsLabel(args) {
123466
+ if (typeof args !== "object" || args === null) return "";
123467
+ return `(${clip(JSON.stringify(args), ARGS_MAX_CHARS)})`;
123468
+ }
123469
+ function textOfPrompt(input) {
123470
+ if (!Array.isArray(input)) return "";
123471
+ return input.flatMap((part) => typeof part === "object" && part !== null && part.type === "text" && typeof part.text === "string" ? [part.text] : []).join("").replaceAll(/\s+/g, " ").trim();
123472
+ }
123473
+ function clip(text, max) {
123474
+ const collapsed = text.replaceAll(/\s+/g, " ").trim();
123475
+ if (collapsed.length <= max) return collapsed;
123476
+ return `${collapsed.slice(0, max)}…`;
123477
+ }
123478
+ function normalizeTimestampMs$1(value) {
123479
+ return value > 0xe8d4a51000 ? Math.floor(value) : Math.floor(value * 1e3);
123480
+ }
123481
+ function formatTime(timeMs) {
123482
+ if (timeMs <= 0) return "";
123483
+ const date = new Date(timeMs);
123484
+ const pad = (n) => String(n).padStart(2, "0");
123485
+ return `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
123486
+ }
123487
+ function formatTokens$2(size) {
123488
+ if (size < 1024) return `${String(size)} tokens`;
123489
+ return `${(size / 1024).toFixed(1)}k tokens`;
123490
+ }
123491
+ function isMissingPath$3(error) {
123492
+ return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
123493
+ }
123494
+ var WIRE_FILENAME$1, TAIL_READ_BYTES, LINE_MAX_CHARS, ARGS_MAX_CHARS, PROMPT_MAX_CHARS, AgentOutputTool;
123495
+ var init_agentOutputTool = __esmMin((() => {
123496
+ init_dist$5();
123497
+ init_input_schema();
123498
+ init_rule_match();
123499
+ init_toolContribution();
123500
+ init_contextSize();
123501
+ init_loop();
123502
+ init_profile();
123503
+ init_agentLifecycle();
123504
+ init_sessionContext();
123505
+ init_agent_output$1();
123506
+ init_agent_output();
123507
+ init_decorateParam();
123508
+ init_decorate();
123509
+ WIRE_FILENAME$1 = "wire.jsonl";
123510
+ TAIL_READ_BYTES = 256 * 1024;
123511
+ LINE_MAX_CHARS = 240;
123512
+ ARGS_MAX_CHARS = 120;
123513
+ PROMPT_MAX_CHARS = 300;
123514
+ AgentOutputTool = class AgentOutputTool {
123515
+ lifecycle;
123516
+ session;
123517
+ name = "AgentOutput";
123518
+ description = agent_output_default;
123519
+ parameters = toInputJsonSchema(AgentOutputInputSchema);
123520
+ constructor(lifecycle, session) {
123521
+ this.lifecycle = lifecycle;
123522
+ this.session = session;
123523
+ }
123524
+ resolveExecution(args) {
123525
+ return {
123526
+ description: `Reading output of agent ${args.agent_id}`,
123527
+ taskMode: "control",
123528
+ approvalRule: this.name,
123529
+ matchesRule: (ruleArgs) => matchesGlobRuleSubject(ruleArgs, args.agent_id),
123530
+ execute: () => this.execute(args)
123531
+ };
123532
+ }
123533
+ async execute(args) {
123534
+ const target = this.lifecycle.get(args.agent_id);
123535
+ if (target === void 0) return {
123536
+ isError: true,
123537
+ output: `${AGENT_NOT_FOUND_MESSAGE} agent_id=${args.agent_id}`
123538
+ };
123539
+ const records = await this.readRecentRecords(args.agent_id, args.tail_lines ?? 60);
123540
+ const profileName = target.accessor.get(IAgentProfileService).data().profileName ?? "agent";
123541
+ const status = target.accessor.get(IAgentLoopService).status();
123542
+ const contextSize = target.accessor.get(IAgentContextSizeService)?.get().size ?? 0;
123543
+ const lines = [[
123544
+ `agent_id: ${args.agent_id}`,
123545
+ `type: ${profileName}`,
123546
+ `status: ${status.state}${status.activeTurnId !== void 0 ? ` · turn ${String(status.activeTurnId)}` : ""}`,
123547
+ `context: ${formatTokens$2(contextSize)}`
123548
+ ].join(" · "), ""];
123549
+ if (records.length === 0) lines.push("(no activity recorded yet)");
123550
+ else for (const record of records) {
123551
+ const stamp = formatTime(record.timeMs);
123552
+ for (const line of record.lines) lines.push(`${stamp} ${record.turnStep}${line}`);
123553
+ }
123554
+ return {
123555
+ output: lines.join("\n"),
123556
+ isError: false
123557
+ };
123558
+ }
123559
+ async readRecentRecords(agentId, tailLines) {
123560
+ const path = join$5(this.session.sessionDir, "agents", agentId, WIRE_FILENAME$1);
123561
+ let file;
123562
+ try {
123563
+ file = await open(path, "r");
123564
+ } catch (error) {
123565
+ if (isMissingPath$3(error)) return [];
123566
+ throw error;
123567
+ }
123568
+ let input;
123569
+ try {
123570
+ const size = (await file.stat()).size;
123571
+ const start = Math.max(0, size - TAIL_READ_BYTES);
123572
+ input = size === 0 ? Readable.from([]) : file.createReadStream({
123573
+ encoding: "utf8",
123574
+ autoClose: false,
123575
+ start,
123576
+ end: size - 1
123577
+ });
123578
+ const lines = createInterface({
123579
+ input,
123580
+ crlfDelay: Infinity
123581
+ });
123582
+ const rendered = [];
123583
+ for await (const line of lines) {
123584
+ const record = toRenderable(line);
123585
+ if (record === void 0) continue;
123586
+ rendered.push(record);
123587
+ if (rendered.length > tailLines) rendered.shift();
123588
+ }
123589
+ return rendered;
123590
+ } finally {
123591
+ input?.destroy();
123592
+ if (input !== void 0) await finished(input, { cleanup: true }).catch(() => {});
123593
+ await file.close();
123594
+ }
123595
+ }
123596
+ };
123597
+ AgentOutputTool = __decorate$1([__decorateParam(0, IAgentLifecycleService), __decorateParam(1, ISessionContext)], AgentOutputTool);
123598
+ registerAgentToolService(IAgentOutputTool, AgentOutputTool, {
123599
+ name: "AgentOutput",
123600
+ domain: "subagent"
123601
+ });
123602
+ }));
123603
+ //#endregion
123265
123604
  //#region ../../packages/agent-core-v2/src/agent/tools/all-done/all-done.md?raw
123266
123605
  var all_done_default;
123267
123606
  var init_all_done = __esmMin((() => {
@@ -139289,13 +139628,6 @@ var init_subagent_task = __esmMin((() => {
139289
139628
  };
139290
139629
  }));
139291
139630
  //#endregion
139292
- //#region ../../packages/agent-core-v2/src/agent/contextSize/contextSize.ts
139293
- var IAgentContextSizeService;
139294
- var init_contextSize = __esmMin((() => {
139295
- init_instantiation();
139296
- IAgentContextSizeService = createDecorator("agentContextSizeService");
139297
- }));
139298
- //#endregion
139299
139631
  //#region ../../packages/agent-core-v2/src/session/subagent/mirrorAgentRun.ts
139300
139632
  function emitAgentRunSpawned(requester, targetAgentId, meta) {
139301
139633
  requester.accessor.get(IEventBus)?.publish({
@@ -208545,7 +208877,7 @@ function turnPromptText(input) {
208545
208877
  const text = input.filter((part) => part.type === "text").map((part) => part.text).join("");
208546
208878
  return text.length > 0 ? text : void 0;
208547
208879
  }
208548
- function isDisplayablePromptOrigin(origin) {
208880
+ function isDisplayablePromptOrigin$1(origin) {
208549
208881
  if (origin.kind === "user") return true;
208550
208882
  return (origin.kind === "skill_activation" || origin.kind === "plugin_command") && origin.trigger === "user-slash";
208551
208883
  }
@@ -209007,7 +209339,7 @@ var init_loopService = __esmMin((() => {
209007
209339
  type: "turn.started",
209008
209340
  turnId: job.turn.id,
209009
209341
  origin,
209010
- prompt: isDisplayablePromptOrigin(origin) ? turnPromptText(job.seed.input) : void 0
209342
+ prompt: isDisplayablePromptOrigin$1(origin) ? turnPromptText(job.seed.input) : void 0
209011
209343
  });
209012
209344
  this.runTurn(job.turn, job.ready).then(job.result.resolve, job.result.reject);
209013
209345
  }
@@ -213601,6 +213933,1504 @@ var init_rpc$2 = __esmMin((() => {
213601
213933
  createDecorator("agentSessionRPCService");
213602
213934
  }));
213603
213935
  //#endregion
213936
+ //#region ../../packages/agent-core-v2/src/agent/loop/engineTaskAdapter.ts
213937
+ /** Extract a human-readable stop reason from an AbortSignal's abort reason:
213938
+ * TaskStop aborts with the normalized reason string; `stopByUser` aborts
213939
+ * with a `UserCancellationError` (its `.message` is the user-facing reason);
213940
+ * anything else (undefined / session close) yields no reason — the engine
213941
+ * falls back to "Stopped by TaskStop". An empty reason (e.g. an Error with
213942
+ * an empty message) counts as "no reason" too, so the wire settle carries
213943
+ * the documented fallback instead of an empty `error` string. */
213944
+ function abortReasonString(reason) {
213945
+ if (typeof reason === "string") return reason === "" ? void 0 : reason;
213946
+ if (reason instanceof Error) return reason.message === "" ? void 0 : reason.message;
213947
+ }
213948
+ var EngineTaskAdapter;
213949
+ var init_engineTaskAdapter = __esmMin((() => {
213950
+ EngineTaskAdapter = class {
213951
+ options;
213952
+ idPrefix;
213953
+ kind;
213954
+ description;
213955
+ sink;
213956
+ pendingOutput = "";
213957
+ pendingSettlement;
213958
+ pendingExitCode;
213959
+ exitCode;
213960
+ settleResolve;
213961
+ settled;
213962
+ removeAbortListener;
213963
+ /** UTF-8 bytes already pushed to the sink (or buffered pre-start). The
213964
+ * engine guarantees its `task.output` deltas concatenate byte-for-byte to
213965
+ * the settle's full output — the bash poller seeds a backgrounded command
213966
+ * with its pre-timeout foreground output as the FIRST delta, and the
213967
+ * subagent worker streams the nested turn's assistant deltas verbatim —
213968
+ * so `complete` appends only the not-yet-streamed tail. */
213969
+ streamedBytes = 0;
213970
+ constructor(options) {
213971
+ this.options = options;
213972
+ this.idPrefix = options.kind === "agent" ? "agent" : "bash";
213973
+ this.kind = options.kind;
213974
+ this.description = options.description;
213975
+ this.settled = new Promise((resolve) => {
213976
+ this.settleResolve = resolve;
213977
+ });
213978
+ }
213979
+ async start(sink) {
213980
+ this.sink = sink;
213981
+ const requestStop = () => {
213982
+ this.options.forceStop(abortReasonString(sink.signal.reason));
213983
+ };
213984
+ if (sink.signal.aborted) requestStop();
213985
+ else {
213986
+ sink.signal.addEventListener("abort", requestStop, { once: true });
213987
+ this.removeAbortListener = () => {
213988
+ sink.signal.removeEventListener("abort", requestStop);
213989
+ };
213990
+ }
213991
+ this.flush();
213992
+ await this.settled;
213993
+ }
213994
+ async forceStop() {
213995
+ this.options.forceStop();
213996
+ }
213997
+ /** Runner-side live output (engine `task.output` events): stream the delta
213998
+ * straight into the service sink so TaskOutput shows partial output while
213999
+ * the task runs. Deltas racing `start()` (settle/stream before the
214000
+ * service invoked start) are buffered and flushed with the settle. */
214001
+ appendOutput(delta) {
214002
+ this.streamedBytes += Buffer.byteLength(delta, "utf-8");
214003
+ if (this.sink !== void 0) this.sink.appendOutput(delta);
214004
+ else this.pendingOutput += delta;
214005
+ }
214006
+ /** Runner-side settle: record the final output/exit code and settle the
214007
+ * registry entry (the runner dispatches the wire `task.terminated` and
214008
+ * delivers the notification itself — the service's `recorded: false`
214009
+ * entry only drives TaskList/TaskStop). The settle output is the engine's
214010
+ * full accumulated output; the deltas streamed during the run already
214011
+ * landed in the sink, so only the not-yet-streamed tail is appended (the
214012
+ * concatenated deltas equal the settle output byte-for-byte). */
214013
+ complete(output, settlement, exitCode) {
214014
+ this.pendingSettlement = settlement;
214015
+ this.pendingExitCode = exitCode ?? null;
214016
+ const fullBytes = Buffer.byteLength(output, "utf-8");
214017
+ const streamed = this.streamedBytes;
214018
+ if (streamed < fullBytes) {
214019
+ const tail = Buffer.from(output, "utf-8").subarray(streamed).toString("utf-8");
214020
+ if (this.sink !== void 0) this.sink.appendOutput(tail);
214021
+ else this.pendingOutput += tail;
214022
+ }
214023
+ this.flush();
214024
+ }
214025
+ toInfo(base) {
214026
+ if (this.kind === "agent") return {
214027
+ ...base,
214028
+ kind: "agent",
214029
+ agentId: this.options.agentId ?? "",
214030
+ subagentType: this.options.subagentType ?? this.options.description,
214031
+ detached: true
214032
+ };
214033
+ return {
214034
+ ...base,
214035
+ kind: "process",
214036
+ command: this.description,
214037
+ pid: this.options.pid ?? 0,
214038
+ exitCode: this.exitCode ?? null,
214039
+ detached: true
214040
+ };
214041
+ }
214042
+ flush() {
214043
+ const sink = this.sink;
214044
+ const settlement = this.pendingSettlement;
214045
+ if (sink === void 0 || settlement === void 0) return;
214046
+ this.exitCode = this.pendingExitCode ?? null;
214047
+ if (this.pendingOutput.length > 0) sink.appendOutput(this.pendingOutput);
214048
+ this.pendingOutput = "";
214049
+ this.pendingSettlement = void 0;
214050
+ this.removeAbortListener?.();
214051
+ this.removeAbortListener = void 0;
214052
+ sink.settle(settlement);
214053
+ this.settleResolve?.();
214054
+ }
214055
+ };
214056
+ }));
214057
+ //#endregion
214058
+ //#region ../../packages/agent-core-v2/src/agent/toolResultTruncation/toolResultTruncation.ts
214059
+ var IAgentToolResultTruncationService;
214060
+ var init_toolResultTruncation = __esmMin((() => {
214061
+ init_instantiation();
214062
+ IAgentToolResultTruncationService = createDecorator("agentToolResultTruncationService");
214063
+ }));
214064
+ //#endregion
214065
+ //#region ../../packages/agent-core-v2/src/agent/loop/rustEngineTurnRunner.ts
214066
+ /**
214067
+ * `rustEngineTurnRunner` — the default turn runner: one turn through the Rust
214068
+ * engine (`RustTurnSession` napi socket) instead of the TS loop.
214069
+ *
214070
+ * Enabled by default; the CLI `--legacy` flag sets `DIMI_LEGACY=1` to keep
214071
+ * the TS loop. The runner:
214072
+ * 1. records `turn.prompt` (turn clock) and appends the user message;
214073
+ * 2. assembles the LLM messages from the context (context assembly stays
214074
+ * on the TS side until slice 3);
214075
+ * 3. runs `RustTurnSession` (aimux-backed LLM in production, scripted
214076
+ * segments under test);
214077
+ * 4. streams the engine events onto the event bus as they happen (the
214078
+ * bridge pushes each event through a per-event callback while the turn
214079
+ * is in flight) — the transcript projection layer (`coreEventMap`)
214080
+ * folds them into wire ops exactly as it does for the TS loop — and
214081
+ * mirrors them into the context (`step.begin` / `content.part` /
214082
+ * `tool.call` / `tool.result` / `step.end` + the assistant message) so
214083
+ * the next turn's history is intact.
214084
+ *
214085
+ * Slice-1 scope: single turn, no queue/cancellation/undo (those land with
214086
+ * later slices). The runner is a parallel path — `loopService` is untouched.
214087
+ */
214088
+ function wrapSystemReminder(text) {
214089
+ const trimmed = text.trim();
214090
+ if (trimmed.startsWith("<system-reminder>") && trimmed.endsWith("</system-reminder>")) return trimmed;
214091
+ return `<system-reminder>\n${trimmed}\n</system-reminder>`;
214092
+ }
214093
+ /**
214094
+ * The Rust engine is the default runtime; the CLI `--legacy` flag sets
214095
+ * `DIMI_LEGACY=1` to keep the TS loop (and the node-local OS backends).
214096
+ */
214097
+ function rustEngineEnabled() {
214098
+ return process.env["DIMI_LEGACY"] !== "1";
214099
+ }
214100
+ /** Render an engine event/tool value as text (strings pass through). */
214101
+ function toText(value) {
214102
+ return typeof value === "string" ? value : JSON.stringify(value) ?? "";
214103
+ }
214104
+ /**
214105
+ * Serialize a TS `PromptOrigin` into the wire `TurnOrigin` JSON shape the
214106
+ * engine deserializes (`{ kind: 'user' }` / `{ kind: 'task', taskId }` /
214107
+ * … — see `dimi-wire` `model.rs`). Unknown kinds fall back to a plain user
214108
+ * origin (the wire default).
214109
+ */
214110
+ function toEngineTurnOrigin(origin) {
214111
+ switch (origin.kind) {
214112
+ case "task": return {
214113
+ kind: "task",
214114
+ taskId: origin.taskId
214115
+ };
214116
+ case "cron_job": return {
214117
+ kind: "cron",
214118
+ taskId: origin.jobId
214119
+ };
214120
+ case "cron_missed": return { kind: "cron" };
214121
+ case "hook_result": return { kind: "hook" };
214122
+ case "compaction_summary": return { kind: "compaction" };
214123
+ default: return { kind: "user" };
214124
+ }
214125
+ }
214126
+ /**
214127
+ * TS `isDisplayablePromptOrigin` parity: only user-origin (and user-slash
214128
+ * skill/plugin) turns expose their prompt on `turn.started`; task/cron/hook
214129
+ * steering text must never leak into the transcript.
214130
+ */
214131
+ function isDisplayablePromptOrigin(origin) {
214132
+ if (origin.kind === "user") return true;
214133
+ return (origin.kind === "skill_activation" || origin.kind === "plugin_command") && origin.trigger === "user-slash";
214134
+ }
214135
+ /**
214136
+ * Build a DimiErrorPayload-shaped error from the engine's `{ message, code }`
214137
+ * payload (TS `toDimiErrorPayload` parity): always carries `name` (the error
214138
+ * class name, mapped from the code when the engine omitted it), `retryable`
214139
+ * (mapped from the code per the TS registry) and `message`.
214140
+ */
214141
+ function buildErrorPayload(rawError) {
214142
+ const error = { ...rawError };
214143
+ if (error["name"] === void 0 || error["name"] === null) error["name"] = error["code"] === "PROVIDER_FILTERED" ? "ProviderFilteredError" : "Error";
214144
+ if (error["retryable"] === void 0) error["retryable"] = typeof error["code"] === "string" && RETRYABLE_ERROR_CODES.has(error["code"]);
214145
+ return error;
214146
+ }
214147
+ /** Optional numeric engine field (pid / exitCode). */
214148
+ function toOptionalNumber(value) {
214149
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
214150
+ }
214151
+ /** Mirrors the task domain's `buildAgentTaskNotificationBody` (minus the
214152
+ * output-file block — the engine carries the tail inline). */
214153
+ function buildTaskNotificationBody(task) {
214154
+ const baseLine = task.status === "timed_out" ? `${task.description} timed out.` : task.status === "killed" && task.error !== void 0 ? `${task.description} was stopped. Reason: ${task.error}` : task.status === "failed" && task.error !== void 0 ? `${task.description} failed. Reason: ${task.error}` : `${task.description} ${task.status}.`;
214155
+ if (task.kind !== "agent" || task.status === "completed") return baseLine;
214156
+ return `${baseLine}${[
214157
+ "",
214158
+ `To recover or continue this subagent, call Agent(resume="${task.agentId}", prompt="Pick up where you left off; redo the last tool call if its result was never observed.").`,
214159
+ `Use agent_id ("${task.agentId}"), NOT source_id / task_id ("${task.taskId}") — the two look alike but only agent_id is accepted by the resume parameter.`,
214160
+ "Add run_in_background=true to keep it backgrounded, or omit it to take the result inline in the current turn.",
214161
+ "The subagent retains its full prior context across the restart, but any in-flight tool call lost its result and may need to be redone."
214162
+ ].join("\n")}`;
214163
+ }
214164
+ /** Mirrors the task domain's `renderOutputPreviewBlock` (tail inline): the
214165
+ * engine's accumulated output is the "currently buffered" output, so the
214166
+ * preview is the last `NOTIFICATION_OUTPUT_PREVIEW_BYTES` bytes with the
214167
+ * same heading / `truncated` / `bytes` semantics the TS service renders. */
214168
+ function renderOutputPreviewBlock(output) {
214169
+ const fullBytes = Buffer.byteLength(output, "utf-8");
214170
+ const previewBytes = Math.min(NOTIFICATION_OUTPUT_PREVIEW_BYTES, fullBytes);
214171
+ const truncated = fullBytes > previewBytes;
214172
+ const preview = previewBytes > 0 ? Buffer.from(output, "utf-8").subarray(fullBytes - previewBytes).toString("utf-8") : "";
214173
+ return [
214174
+ `<output-preview bytes="${String(previewBytes)}" total_bytes="${String(fullBytes)}" truncated="${String(truncated)}">`,
214175
+ truncated ? `Showing the last ${String(previewBytes)} bytes. No persisted full output is available.` : "No persisted full output is available; this preview is the currently buffered task output.",
214176
+ escapeXml$1(preview),
214177
+ "</output-preview>"
214178
+ ].join("\n");
214179
+ }
214180
+ /** Resolve once the signal aborts (used to race an approval wait). */
214181
+ function abortOnSignal(signal) {
214182
+ return new Promise((resolve) => {
214183
+ if (signal.aborted) {
214184
+ resolve();
214185
+ return;
214186
+ }
214187
+ signal.addEventListener("abort", () => {
214188
+ resolve();
214189
+ }, { once: true });
214190
+ });
214191
+ }
214192
+ var WAIT_FOR_NATIVE_DESCRIPTION, ENGINE_NATIVE_TOOLS, WAIT_FOR_NATIVE_PARAMETERS, IRustEngineTurnRunner, RETRYABLE_ERROR_CODES, TERMINAL_OUTPUT_TAIL_CHARS, NOTIFICATION_OUTPUT_PREVIEW_BYTES, RustEngineTurnRunner;
214193
+ var init_rustEngineTurnRunner = __esmMin((() => {
214194
+ init_src$7();
214195
+ init_xml_escape();
214196
+ init_contextMemory();
214197
+ init_permissionMode();
214198
+ init_toolRegistry();
214199
+ init_toolPolicy();
214200
+ init_permissionRules();
214201
+ init_engineTaskAdapter();
214202
+ init_notificationXml();
214203
+ init_taskOps();
214204
+ init_task$5();
214205
+ init_configSection$12();
214206
+ init_turnOps();
214207
+ init_eventBus();
214208
+ init_config$5();
214209
+ init_log();
214210
+ init_canonical_args();
214211
+ init_errors$11();
214212
+ init_externalHooksRunner();
214213
+ init_toolResultTruncation();
214214
+ init_approval$4();
214215
+ init_usage();
214216
+ init_profile();
214217
+ init_scopeContext();
214218
+ init_catalog$1();
214219
+ init_providerRuntime();
214220
+ init_sessionContext();
214221
+ init_sessionMetadata();
214222
+ init_usage$1();
214223
+ init_wire();
214224
+ init_compactionHandoff();
214225
+ init_compactionOps();
214226
+ init_completion();
214227
+ init_decorateParam();
214228
+ init_decorate();
214229
+ init_instantiation();
214230
+ init_scope();
214231
+ WAIT_FOR_NATIVE_DESCRIPTION = [
214232
+ "Wait for a background subagent task to finish (or time out).",
214233
+ "Pass the `agent_id` of a subagent launched by the Agent tool (from its launch output).",
214234
+ "The call blocks until that subagent completes, fails, or the timeout expires, then returns its final status and output.",
214235
+ "This waits on a specific subagent task, NOT on the user: user-wait (waking on user notifications) is not implemented.",
214236
+ "Prefer AgentOutput for a quick status check; use WaitFor when the turn should pause until the subagent finishes."
214237
+ ].join(" ");
214238
+ ENGINE_NATIVE_TOOLS = new Set([
214239
+ "Bash",
214240
+ "Agent",
214241
+ "AgentOutput",
214242
+ "WaitFor"
214243
+ ]);
214244
+ WAIT_FOR_NATIVE_PARAMETERS = {
214245
+ type: "object",
214246
+ properties: {
214247
+ agent_id: {
214248
+ type: "string",
214249
+ description: "Agent id of the running subagent task to wait for, as returned by the Agent tool launch output."
214250
+ },
214251
+ timeout_seconds: {
214252
+ type: "integer",
214253
+ minimum: 1,
214254
+ maximum: 1800,
214255
+ description: "How long to wait for the subagent before giving up. Defaults to 60; maximum 1800."
214256
+ }
214257
+ },
214258
+ required: ["agent_id"],
214259
+ additionalProperties: false
214260
+ };
214261
+ IRustEngineTurnRunner = createDecorator("rustEngineTurnRunner");
214262
+ RETRYABLE_ERROR_CODES = new Set([
214263
+ "provider.rate_limit",
214264
+ "provider.connection_error",
214265
+ "provider.overloaded",
214266
+ "context.overflow"
214267
+ ]);
214268
+ TERMINAL_OUTPUT_TAIL_CHARS = 4 * 1024;
214269
+ NOTIFICATION_OUTPUT_PREVIEW_BYTES = 3e3;
214270
+ RustEngineTurnRunner = class RustEngineTurnRunner {
214271
+ context;
214272
+ eventBus;
214273
+ wire;
214274
+ config;
214275
+ modeService;
214276
+ rulesService;
214277
+ toolRegistry;
214278
+ usageService;
214279
+ profile;
214280
+ scopeContext;
214281
+ sessionContext;
214282
+ sessionMetadata;
214283
+ tasks;
214284
+ modelCatalog;
214285
+ providerRuntime;
214286
+ instantiation;
214287
+ toolPolicy;
214288
+ log;
214289
+ /** The in-flight Rust session, while a turn is running (steer/cancel target). */
214290
+ activeSession;
214291
+ /** FIFO queue of turns waiting behind the running one (TS loop queue
214292
+ * parity): prompts during an active turn wait for it to finish. */
214293
+ queued = [];
214294
+ /** Whether a turn is currently executing (queue gate). */
214295
+ turnRunning = false;
214296
+ /** turnId of the executing turn (cancel validation). */
214297
+ executingTurnId;
214298
+ /** Aborts the in-flight approval wait on cancel. */
214299
+ approvalAbort;
214300
+ /**
214301
+ * Rust-side task registry mirror: taskId → launch facts (description /
214302
+ * startedAt / pid) recorded from `task.started`, used to build the
214303
+ * terminal `task.terminated` info from `task.settled`. Entries are removed
214304
+ * once the settle is handled (a task settles exactly once), so the map
214305
+ * stays bounded by the number of tasks in flight.
214306
+ */
214307
+ taskInfos = /* @__PURE__ */ new Map();
214308
+ /** Notification dedupe (TS `deliveredNotificationKeys` parity): guards a
214309
+ * single settle from being delivered twice. Keys are removed after the
214310
+ * delivery completes — a settled task never settles again — so the set
214311
+ * stays bounded; the mid-turn+idle double-delivery guard is the
214312
+ * single-call structure of `deliverTaskNotification`, not this set. */
214313
+ deliveredNotificationKeys = /* @__PURE__ */ new Set();
214314
+ /** Registry entries for engine background tasks (TaskList/TaskStop parity):
214315
+ * taskId → adapter registered with `IAgentTaskService`. Removed once the
214316
+ * task settles (a task settles exactly once), so the map stays bounded. */
214317
+ engineTaskAdapters = /* @__PURE__ */ new Map();
214318
+ /** Owning RustTurnSession per engine task id (F1): recorded at
214319
+ * `task.started` from the session whose EventSink delivered the event.
214320
+ * Tasks launched from background workers (a subagent spawning a
214321
+ * sub-subagent, or a subagent launching a backgrounded bash) emit their
214322
+ * start AFTER the launching turn ended, when `activeSession` is undefined
214323
+ * or a newer turn's session — and the engine's per-task cancel signal
214324
+ * lives on the OWNING session's task map (`RustTurnSession::new` creates
214325
+ * a fresh map per turn), so TaskStop must cancel through this session.
214326
+ * Removed once the task settles, so the map stays bounded. */
214327
+ taskSessions = /* @__PURE__ */ new Map();
214328
+ /** Every subagent agent id this runner has handed out (the engine's
214329
+ * `agent-<n>` ids across turns): the next-turn seed must continue past
214330
+ * them so ids stay monotonic within the session (TS
214331
+ * `nextAvailableAgentId` parity). */
214332
+ engineAgentIds = /* @__PURE__ */ new Set();
214333
+ /** Every RustTurnSession this runner created. Held until the agent scope
214334
+ * is disposed so a session's EventSink stays open while its background
214335
+ * tasks are still settling (a subagent launched in turn 1 must be able to
214336
+ * notify after turn 1 ends), and so teardown can close them all at once
214337
+ * (TS `taskService.dispose` parity). */
214338
+ sessions = /* @__PURE__ */ new Set();
214339
+ /** Whether the agent scope was disposed: late engine events (background
214340
+ * task settles racing the teardown) are ignored instead of dispatching
214341
+ * wire ops on a disposed wire / appending to a disposed context. */
214342
+ disposed = false;
214343
+ constructor(context, eventBus, wire, config, modeService, rulesService, toolRegistry, usageService, profile, scopeContext, sessionContext, sessionMetadata, tasks, modelCatalog, providerRuntime, instantiation, toolPolicy, log) {
214344
+ this.context = context;
214345
+ this.eventBus = eventBus;
214346
+ this.wire = wire;
214347
+ this.config = config;
214348
+ this.modeService = modeService;
214349
+ this.rulesService = rulesService;
214350
+ this.toolRegistry = toolRegistry;
214351
+ this.usageService = usageService;
214352
+ this.profile = profile;
214353
+ this.scopeContext = scopeContext;
214354
+ this.sessionContext = sessionContext;
214355
+ this.sessionMetadata = sessionMetadata;
214356
+ this.tasks = tasks;
214357
+ this.modelCatalog = modelCatalog;
214358
+ this.providerRuntime = providerRuntime;
214359
+ this.instantiation = instantiation;
214360
+ this.toolPolicy = toolPolicy;
214361
+ this.log = log;
214362
+ this.registryId = randomUUID();
214363
+ }
214364
+ /** Agent-scoped Rust subagent registry id (see constructor). */
214365
+ registryId;
214366
+ /** TS `stopHookContinuationUsed` parity: the Stop hook fires at most once
214367
+ * after a continuation was delivered. */
214368
+ stopHookContinuationUsed = false;
214369
+ static isEnabled() {
214370
+ return rustEngineEnabled();
214371
+ }
214372
+ /**
214373
+ * Steer the running turn. Mirrors the TS steer path (`steerTurn` op +
214374
+ * user message in the context) and forwards the text into the engine's
214375
+ * steer queue, where it is drained into the next LLM request. Returns
214376
+ * `false` when there is no steerable turn: either no session is active
214377
+ * (the caller starts a new turn) or the engine's turn already finished
214378
+ * (a steer racing the teardown — between the engine's final steer check
214379
+ * and this runner clearing `activeSession` — would land in a queue that
214380
+ * is never drained again; the caller's `runTurn` fallback queues it as
214381
+ * the next turn instead, so it is never lost).
214382
+ */
214383
+ steer(payload) {
214384
+ if (this.disposed) return false;
214385
+ const session = this.activeSession;
214386
+ if (session === void 0) return false;
214387
+ const text = payload.input.filter((part) => part.type === "text").map((part) => part.text ?? "").join("");
214388
+ if (text.length === 0) return false;
214389
+ if (!session.steer(text)) return false;
214390
+ this.wire.dispatch(steerTurn({
214391
+ input: [...payload.input],
214392
+ origin: payload.origin
214393
+ }));
214394
+ this.context.append({
214395
+ role: "user",
214396
+ content: [...payload.input],
214397
+ toolCalls: [],
214398
+ origin: payload.origin,
214399
+ id: randomUUID()
214400
+ });
214401
+ return true;
214402
+ }
214403
+ /**
214404
+ * Run one turn through the Rust engine. The turn clock advances at enqueue
214405
+ * time (TS parity); the turn itself either starts immediately (resolves
214406
+ * with its id) or waits behind the running turn (resolves `undefined`,
214407
+ * like TS `state === 'pending'`).
214408
+ */
214409
+ async runTurn(payload) {
214410
+ if (this.disposed) return void 0;
214411
+ this.wire.dispatch(promptTurn({
214412
+ input: [...payload.input],
214413
+ origin: payload.origin
214414
+ }));
214415
+ const turnId = this.wire.getModel(TurnModel).nextTurnId - 1;
214416
+ const userMessage = {
214417
+ role: "user",
214418
+ content: [...payload.input],
214419
+ toolCalls: [],
214420
+ origin: payload.origin,
214421
+ id: randomUUID()
214422
+ };
214423
+ this.context.append(userMessage);
214424
+ if (this.turnRunning) {
214425
+ this.queued.push({
214426
+ turnId,
214427
+ payload,
214428
+ cancelled: false
214429
+ });
214430
+ return;
214431
+ }
214432
+ this.startQueuedTurn({
214433
+ turnId,
214434
+ payload,
214435
+ cancelled: false
214436
+ });
214437
+ return { turnId };
214438
+ }
214439
+ /** Cancel the active turn; with `turnId`, also cancels a queued turn. */
214440
+ cancel(turnId) {
214441
+ const session = this.activeSession;
214442
+ if (session !== void 0 && (turnId === void 0 || turnId === this.executingTurnId)) {
214443
+ this.approvalAbort?.abort();
214444
+ session.cancel();
214445
+ return true;
214446
+ }
214447
+ let cancelled = false;
214448
+ for (const entry of this.queued) if (entry.turnId === turnId) {
214449
+ entry.cancelled = true;
214450
+ this.wire.dispatch(cancelTurn({ turnId }));
214451
+ cancelled = true;
214452
+ }
214453
+ return cancelled;
214454
+ }
214455
+ /**
214456
+ * Agent-scope teardown (TS `taskService.dispose` parity): every Rust
214457
+ * session is closed — its EventSink stops forwarding, the in-flight turn
214458
+ * is cancelled, and background workers/pollers observe the closed flag and
214459
+ * kill their processes — and late engine events are ignored instead of
214460
+ * dispatching wire ops on a disposed wire. The DI container invokes this
214461
+ * when the agent scope is disposed.
214462
+ */
214463
+ dispose() {
214464
+ this.disposed = true;
214465
+ this.approvalAbort?.abort();
214466
+ for (const session of this.sessions) session.close();
214467
+ this.sessions.clear();
214468
+ this.taskSessions.clear();
214469
+ this.engineTaskAdapters.clear();
214470
+ RustTurnSession.dropTaskRegistry(this.registryId);
214471
+ }
214472
+ startQueuedTurn(entry) {
214473
+ this.turnRunning = true;
214474
+ this.executingTurnId = entry.turnId;
214475
+ this.runTurnNow(entry.turnId, entry.payload.origin).catch(() => void 0).finally(() => {
214476
+ this.turnRunning = false;
214477
+ this.executingTurnId = void 0;
214478
+ if (this.disposed) {
214479
+ this.queued.length = 0;
214480
+ return;
214481
+ }
214482
+ const next = this.queued.find((queued) => !queued.cancelled);
214483
+ if (next === void 0) return;
214484
+ this.queued.splice(this.queued.indexOf(next), 1);
214485
+ this.startQueuedTurn(next);
214486
+ });
214487
+ }
214488
+ async runTurnNow(turnId, origin) {
214489
+ if (this.disposed) return { turnId };
214490
+ const messages = [{
214491
+ role: "system",
214492
+ content: this.profile.getSystemPrompt()
214493
+ }, ...this.context.get().map((message) => this.toLlmMessage(message))];
214494
+ const provider = await this.providerConfig();
214495
+ const inputJson = JSON.stringify({
214496
+ turnId,
214497
+ origin: toEngineTurnOrigin(origin),
214498
+ usesWorkerRejectionGuidance: this.scopeContext.agentId !== "main",
214499
+ activeTools: this.effectiveActiveTools() ?? null,
214500
+ messages,
214501
+ tools: [],
214502
+ provider,
214503
+ maxStepsPerTurn: this.maxStepsPerTurn() ?? null,
214504
+ maxRetriesPerStep: this.maxRetriesPerStep() ?? null,
214505
+ maxContextTokens: this.maxContextTokens() ?? null,
214506
+ nextAgentId: await this.computeNextAgentId(),
214507
+ killGraceMs: this.killGracePeriodMs(),
214508
+ completionReview: {
214509
+ minSteps: 10,
214510
+ reminder: completion_review_default
214511
+ },
214512
+ cwd: this.profile.data().cwd ?? process.cwd()
214513
+ });
214514
+ const policyJson = JSON.stringify({
214515
+ mode: this.modeService.mode,
214516
+ rules: this.rulesService.rules,
214517
+ sessionApprovedPatterns: this.rulesService.sessionApprovalRulePatterns
214518
+ });
214519
+ const scripted = process.env["DIMI_RUST_ENGINE_SCRIPTED"];
214520
+ const session = new RustTurnSession(inputJson, policyJson, scripted ?? void 0, this.registryId);
214521
+ this.sessions.add(session);
214522
+ this.activeSession = session;
214523
+ session.setToolGate((payloadJson) => {
214524
+ (async () => {
214525
+ const payload = JSON.parse(payloadJson);
214526
+ let verdict = { decision: "allow" };
214527
+ try {
214528
+ const hooksRunner = this.instantiation.invokeFunction((accessor) => accessor.get(IExternalHooksRunnerService));
214529
+ if (hooksRunner !== void 0 && ENGINE_NATIVE_TOOLS.has(payload.toolName)) {
214530
+ const block = await hooksRunner.triggerBlock("PreToolUse", {
214531
+ matcherValue: payload.toolName,
214532
+ signal: new AbortController().signal,
214533
+ sessionId: this.sessionContext.sessionId,
214534
+ inputData: {
214535
+ toolName: payload.toolName,
214536
+ toolInput: isPlainRecord(payload.arguments) ? payload.arguments : {},
214537
+ toolCallId: `native-${payload.toolName}`
214538
+ }
214539
+ });
214540
+ if (block !== void 0) verdict = {
214541
+ decision: "block",
214542
+ reason: block.reason
214543
+ };
214544
+ }
214545
+ } catch {}
214546
+ session.completeToolGate(payload.requestId, JSON.stringify(verdict));
214547
+ })();
214548
+ });
214549
+ try {
214550
+ await this.runEngineSession(session, turnId, provider["model"], origin);
214551
+ } finally {
214552
+ this.activeSession = void 0;
214553
+ }
214554
+ return { turnId };
214555
+ }
214556
+ /**
214557
+ * Run one engine session to completion: register the TS tool ecosystem,
214558
+ * drive the approval loop, mirror the engine events into the context.
214559
+ */
214560
+ async runEngineSession(session, turnId, providerModel, origin) {
214561
+ const engineNativeTools = ENGINE_NATIVE_TOOLS;
214562
+ const activeSet = this.effectiveActiveTools();
214563
+ const isToolActiveForRunner = (name) => activeSet === void 0 || activeSet.includes(name);
214564
+ for (const info of this.toolRegistry.list()) {
214565
+ if (!isToolActiveForRunner(info.name)) continue;
214566
+ try {
214567
+ if (engineNativeTools.has(info.name)) {
214568
+ if (info.name !== "Bash") if (info.name === "WaitFor") session.registerNativeToolDef(info.name, WAIT_FOR_NATIVE_DESCRIPTION, JSON.stringify(WAIT_FOR_NATIVE_PARAMETERS));
214569
+ else session.registerNativeToolDef(info.name, info.description, JSON.stringify(info.parameters ?? {
214570
+ type: "object",
214571
+ properties: {}
214572
+ }));
214573
+ continue;
214574
+ }
214575
+ const tool = this.toolRegistry.resolve(info.name);
214576
+ if (tool === void 0) continue;
214577
+ session.registerExternalTool(info.name, info.description, JSON.stringify(info.parameters ?? {
214578
+ type: "object",
214579
+ properties: {}
214580
+ }), (payloadJson) => {
214581
+ (async () => {
214582
+ const payload = JSON.parse(payloadJson);
214583
+ try {
214584
+ const toolCalls = (payload.toolCalls ?? []).map((call) => ({
214585
+ type: "function",
214586
+ id: call.id ?? payload.toolCallId ?? payload.requestId,
214587
+ name: call.name,
214588
+ arguments: typeof call.arguments === "string" ? call.arguments : JSON.stringify(call.arguments) ?? "null"
214589
+ }));
214590
+ const execution = await tool.resolveExecution(payload.arguments, { toolCalls });
214591
+ if (execution.isError === true) {
214592
+ session.completeToolCall(payload.requestId, JSON.stringify({
214593
+ toolCallId: payload.toolCallId ?? payload.requestId,
214594
+ toolName: payload.name,
214595
+ output: toText(execution.output),
214596
+ isError: true,
214597
+ stopTurn: execution.stopTurn === true,
214598
+ updates: []
214599
+ }));
214600
+ return;
214601
+ }
214602
+ const signal = new AbortController().signal;
214603
+ const hooksRunner = this.instantiation.invokeFunction((accessor) => accessor.get(IExternalHooksRunnerService));
214604
+ const toolInput = isPlainRecord(payload.arguments) ? payload.arguments : {};
214605
+ const toolCallId = payload.toolCallId ?? payload.requestId;
214606
+ if (hooksRunner !== void 0) {
214607
+ const block = await hooksRunner.triggerBlock("PreToolUse", {
214608
+ matcherValue: payload.name,
214609
+ signal,
214610
+ sessionId: this.sessionContext.sessionId,
214611
+ inputData: {
214612
+ toolName: payload.name,
214613
+ toolInput,
214614
+ toolCallId
214615
+ }
214616
+ });
214617
+ if (block !== void 0) {
214618
+ session.completeToolCall(payload.requestId, JSON.stringify({
214619
+ toolCallId,
214620
+ toolName: payload.name,
214621
+ output: block.reason,
214622
+ isError: true,
214623
+ stopTurn: false,
214624
+ updates: []
214625
+ }));
214626
+ return;
214627
+ }
214628
+ }
214629
+ const result = await execution.execute({
214630
+ turnId: 0,
214631
+ toolCallId,
214632
+ signal,
214633
+ onUpdate: (update) => {
214634
+ if (signal.aborted) return;
214635
+ this.eventBus.publish({
214636
+ type: "tool.progress",
214637
+ turnId,
214638
+ toolCallId,
214639
+ update
214640
+ });
214641
+ }
214642
+ });
214643
+ let finalResult = result;
214644
+ const truncation = this.instantiation.invokeFunction((accessor) => accessor.get(IAgentToolResultTruncationService));
214645
+ if (truncation !== void 0) try {
214646
+ finalResult = await truncation.truncateForModel({
214647
+ toolName: payload.name,
214648
+ toolCallId,
214649
+ result
214650
+ });
214651
+ } catch {}
214652
+ session.completeToolCall(payload.requestId, JSON.stringify({
214653
+ toolCallId,
214654
+ toolName: payload.name,
214655
+ output: toText(finalResult.output),
214656
+ isError: finalResult.isError === true,
214657
+ stopTurn: finalResult.stopTurn === true,
214658
+ updates: []
214659
+ }));
214660
+ if (hooksRunner !== void 0) {
214661
+ const outputText = toText(finalResult.output);
214662
+ const isError = finalResult.isError === true;
214663
+ hooksRunner.fireAndForgetTrigger(isError ? "PostToolUseFailure" : "PostToolUse", {
214664
+ matcherValue: payload.name,
214665
+ signal,
214666
+ sessionId: this.sessionContext.sessionId,
214667
+ inputData: {
214668
+ toolName: payload.name,
214669
+ toolInput,
214670
+ toolCallId,
214671
+ error: isError ? toDimiErrorPayload(outputText) : void 0,
214672
+ toolOutput: isError ? void 0 : outputText.slice(0, 2e3)
214673
+ }
214674
+ });
214675
+ }
214676
+ } catch (error) {
214677
+ session.completeToolCall(payload.requestId, JSON.stringify({
214678
+ toolCallId: payload.toolCallId ?? payload.requestId,
214679
+ toolName: payload.name,
214680
+ output: `Tool "${payload.name}" failed: ${error instanceof Error ? error.message : String(error)}`,
214681
+ isError: true,
214682
+ stopTurn: false,
214683
+ updates: []
214684
+ }));
214685
+ }
214686
+ })();
214687
+ });
214688
+ } catch (error) {
214689
+ if (engineNativeTools.has(info.name) && info.name !== "Bash") {
214690
+ this.log.error("[rustEngineTurnRunner] failed to register native tool def", {
214691
+ name: info.name,
214692
+ error
214693
+ });
214694
+ this.eventBus.publish({
214695
+ type: "turn.ended",
214696
+ turnId,
214697
+ reason: "failed",
214698
+ error: {
214699
+ name: "ToolRegistrationError",
214700
+ message: `Failed to register native tool def "${info.name}"`
214701
+ }
214702
+ });
214703
+ this.eventBus.publish({
214704
+ type: "error",
214705
+ name: "ToolRegistrationError",
214706
+ message: `Failed to register native tool def "${info.name}"`
214707
+ });
214708
+ throw error;
214709
+ }
214710
+ this.log.error("[rustEngineTurnRunner] failed to register external tool", {
214711
+ name: info.name,
214712
+ error
214713
+ });
214714
+ }
214715
+ }
214716
+ let stepUuid;
214717
+ const segments = [];
214718
+ let stepSawToolCall = false;
214719
+ const nativeToolCalls = /* @__PURE__ */ new Map();
214720
+ let usage = emptyUsage();
214721
+ const publish = (event) => {
214722
+ const { type, ...rest } = event;
214723
+ this.eventBus.publish({
214724
+ type,
214725
+ ...rest
214726
+ });
214727
+ };
214728
+ const flushParts = (turnId, step) => {
214729
+ for (const segment of segments.splice(0)) {
214730
+ const part = segment.type === "think" ? {
214731
+ type: "think",
214732
+ think: segment.text
214733
+ } : {
214734
+ type: "text",
214735
+ text: segment.text
214736
+ };
214737
+ this.context.appendLoopEvent({
214738
+ type: "content.part",
214739
+ stepUuid,
214740
+ part,
214741
+ uuid: randomUUID(),
214742
+ turnId: String(turnId),
214743
+ step
214744
+ });
214745
+ }
214746
+ };
214747
+ const handleEngineEvent = (event) => {
214748
+ if (this.disposed) return;
214749
+ if (event["type"] === "task.started") {
214750
+ this.taskSessions.set(toText(event["taskId"]), session);
214751
+ this.handleTaskStarted(event);
214752
+ return;
214753
+ }
214754
+ if (event["type"] === "task.output") {
214755
+ this.handleTaskOutput(event);
214756
+ return;
214757
+ }
214758
+ if (event["type"] === "task.settled") {
214759
+ this.handleTaskSettled(event);
214760
+ return;
214761
+ }
214762
+ if (event["type"] === "completion.review.injected") {
214763
+ this.context.append({
214764
+ role: "user",
214765
+ content: [{
214766
+ type: "text",
214767
+ text: wrapSystemReminder(toText(event["reminder"]))
214768
+ }],
214769
+ toolCalls: [],
214770
+ origin: {
214771
+ kind: "system_trigger",
214772
+ name: "completion_review"
214773
+ },
214774
+ id: randomUUID()
214775
+ });
214776
+ return;
214777
+ }
214778
+ const busEvent = { ...event };
214779
+ if (event["type"] === "turn.step.completed") {
214780
+ const engineUsage = event["usage"];
214781
+ if (engineUsage !== void 0) {
214782
+ const inputCacheRead = engineUsage.cachedTokens ?? 0;
214783
+ busEvent["usage"] = {
214784
+ inputOther: Math.max((engineUsage.inputTokens ?? 0) - inputCacheRead, 0),
214785
+ output: engineUsage.outputTokens ?? 0,
214786
+ inputCacheRead,
214787
+ inputCacheCreation: 0
214788
+ };
214789
+ } else busEvent["usage"] = emptyUsage();
214790
+ } else if (event["type"] === "turn.ended" && event["reason"] === "failed") {
214791
+ const rawError = event["error"];
214792
+ if (rawError !== void 0) busEvent["error"] = buildErrorPayload(rawError);
214793
+ } else if (event["type"] === "turn.started" && !isDisplayablePromptOrigin(origin)) delete busEvent["prompt"];
214794
+ publish(busEvent);
214795
+ switch (event["type"]) {
214796
+ case "turn.step.started": {
214797
+ const stepNumber = Number(event["step"] ?? 1);
214798
+ stepUuid = randomUUID();
214799
+ stepSawToolCall = false;
214800
+ this.context.appendLoopEvent({
214801
+ type: "step.begin",
214802
+ uuid: stepUuid,
214803
+ turnId: String(turnId),
214804
+ step: stepNumber
214805
+ });
214806
+ break;
214807
+ }
214808
+ case "thinking.delta": {
214809
+ const last = segments[segments.length - 1];
214810
+ if (last?.type === "think") last.text += toText(event["delta"]);
214811
+ else segments.push({
214812
+ type: "think",
214813
+ text: toText(event["delta"])
214814
+ });
214815
+ break;
214816
+ }
214817
+ case "assistant.delta": {
214818
+ const last = segments[segments.length - 1];
214819
+ if (last?.type === "text") last.text += toText(event["delta"]);
214820
+ else segments.push({
214821
+ type: "text",
214822
+ text: toText(event["delta"])
214823
+ });
214824
+ break;
214825
+ }
214826
+ case "tool.call.delta": break;
214827
+ case "tool.call.started": {
214828
+ const id = toText(event["toolCallId"]);
214829
+ const name = toText(event["name"]);
214830
+ stepSawToolCall = true;
214831
+ if (ENGINE_NATIVE_TOOLS.has(name)) nativeToolCalls.set(id, {
214832
+ name,
214833
+ input: event["args"]
214834
+ });
214835
+ this.context.appendLoopEvent({
214836
+ type: "tool.call",
214837
+ stepUuid,
214838
+ toolCallId: id,
214839
+ name,
214840
+ args: event["args"],
214841
+ uuid: randomUUID(),
214842
+ turnId: String(turnId),
214843
+ step: Number(event["step"] ?? 1)
214844
+ });
214845
+ break;
214846
+ }
214847
+ case "tool.result": {
214848
+ const id = toText(event["toolCallId"]);
214849
+ const output = toText(event["output"]);
214850
+ const isError = event["isError"] === true;
214851
+ const native = nativeToolCalls.get(id);
214852
+ if (native !== void 0) {
214853
+ nativeToolCalls.delete(id);
214854
+ const hooksRunner = this.instantiation.invokeFunction((accessor) => accessor.get(IExternalHooksRunnerService));
214855
+ if (hooksRunner !== void 0) hooksRunner.fireAndForgetTrigger(isError ? "PostToolUseFailure" : "PostToolUse", {
214856
+ matcherValue: native.name,
214857
+ signal: new AbortController().signal,
214858
+ sessionId: this.sessionContext.sessionId,
214859
+ inputData: {
214860
+ toolName: native.name,
214861
+ toolInput: isPlainRecord(native.input) ? native.input : {},
214862
+ toolCallId: id,
214863
+ error: isError ? toDimiErrorPayload(output) : void 0,
214864
+ toolOutput: isError ? void 0 : output.slice(0, 2e3)
214865
+ }
214866
+ });
214867
+ }
214868
+ this.context.appendLoopEvent({
214869
+ type: "tool.result",
214870
+ toolCallId: id,
214871
+ result: {
214872
+ output,
214873
+ isError
214874
+ },
214875
+ parentUuid: stepUuid
214876
+ });
214877
+ break;
214878
+ }
214879
+ case "context.compacted": {
214880
+ const summary = toText(event["summary"]);
214881
+ const tokensBefore = Number(event["tokensBefore"] ?? 0);
214882
+ const compactedCount = Number(event["compactedCount"] ?? 0);
214883
+ this.wire.dispatch(fullCompactionBegin({ source: "auto" }));
214884
+ const result = this.context.applyCompaction({
214885
+ summary,
214886
+ contextSummary: buildCompactionSummaryText(summary),
214887
+ compactedCount,
214888
+ tokensBefore
214889
+ });
214890
+ this.wire.dispatch(fullCompactionComplete({}));
214891
+ this.eventBus.publish({
214892
+ type: "compaction.completed",
214893
+ result
214894
+ });
214895
+ break;
214896
+ }
214897
+ case "turn.step.interrupted":
214898
+ if (stepSawToolCall) flushParts(turnId, Number(event["step"] ?? 1));
214899
+ break;
214900
+ case "turn.step.completed": {
214901
+ const stepFinish = toText(event["finishReason"] ?? "end_turn");
214902
+ const stepNumber = Number(event["step"] ?? 1);
214903
+ flushParts(turnId, stepNumber);
214904
+ const engineUsage = event["usage"];
214905
+ if (engineUsage !== void 0) {
214906
+ const inputCacheRead = engineUsage.cachedTokens ?? 0;
214907
+ usage = {
214908
+ inputOther: Math.max((engineUsage.inputTokens ?? 0) - inputCacheRead, 0),
214909
+ output: engineUsage.outputTokens ?? 0,
214910
+ inputCacheRead,
214911
+ inputCacheCreation: 0
214912
+ };
214913
+ } else usage = emptyUsage();
214914
+ this.usageService.record(providerModel, usage, {
214915
+ kind: "loop",
214916
+ turnId: String(turnId),
214917
+ step: stepNumber
214918
+ });
214919
+ this.context.appendLoopEvent({
214920
+ type: "step.end",
214921
+ uuid: stepUuid,
214922
+ turnId: String(turnId),
214923
+ step: stepNumber,
214924
+ finishReason: stepFinish,
214925
+ usage
214926
+ });
214927
+ if (stepFinish !== "tool_use" && stepFinish !== "filtered") this.runStopHook(turnId);
214928
+ break;
214929
+ }
214930
+ case "turn.ended":
214931
+ this.stopHookContinuationUsed = false;
214932
+ if (event["reason"] === "failed" && event["error"] !== void 0) this.eventBus.publish({
214933
+ type: "error",
214934
+ ...buildErrorPayload(event["error"])
214935
+ });
214936
+ break;
214937
+ default: break;
214938
+ }
214939
+ };
214940
+ session.setOnEvent((eventJson) => {
214941
+ try {
214942
+ handleEngineEvent(JSON.parse(eventJson));
214943
+ } catch (error) {
214944
+ this.log.error("[rustEngineTurnRunner] failed to process engine event", { error });
214945
+ }
214946
+ });
214947
+ let progress = JSON.parse(await session.run());
214948
+ while (progress.progress.status === "needsApproval") {
214949
+ const approval = progress.progress.approval;
214950
+ const approvalRequest = {
214951
+ sessionId: this.sessionContext.sessionId,
214952
+ agentId: this.scopeContext.agentId,
214953
+ turnId,
214954
+ toolCallId: approval.toolCallId,
214955
+ toolName: approval.toolName,
214956
+ action: `Approve ${approval.toolName}`,
214957
+ display: {
214958
+ kind: "generic",
214959
+ summary: `Approve ${approval.toolName}`,
214960
+ detail: approval.toolInput
214961
+ }
214962
+ };
214963
+ this.eventBus.publish({
214964
+ type: "permission.approval.requested",
214965
+ ...approvalRequest
214966
+ });
214967
+ let response = { decision: "approved" };
214968
+ const approvalController = new AbortController();
214969
+ this.approvalAbort = approvalController;
214970
+ try {
214971
+ const approvalService = this.instantiation.invokeFunction((accessor) => accessor.get(ISessionApprovalService));
214972
+ response = approvalService !== void 0 ? await Promise.race([approvalService.request(approvalRequest), abortOnSignal(approvalController.signal).then(() => ({ decision: "cancelled" }))]) : { decision: "approved" };
214973
+ } catch {
214974
+ response = { decision: "rejected" };
214975
+ } finally {
214976
+ this.approvalAbort = void 0;
214977
+ }
214978
+ this.eventBus.publish({
214979
+ type: "permission.approval.resolved",
214980
+ ...approvalRequest,
214981
+ decision: response.decision
214982
+ });
214983
+ this.rulesService.recordApprovalResult({
214984
+ turnId,
214985
+ toolCallId: approvalRequest.toolCallId,
214986
+ toolName: approvalRequest.toolName,
214987
+ action: approvalRequest.action,
214988
+ sessionApprovalRule: response.decision === "approved" && response.scope === "session" ? approvalRequest.toolName : void 0,
214989
+ result: response
214990
+ });
214991
+ if (response.decision === "approved" && response.scope === "session") session.addSessionApproval(approvalRequest.toolName);
214992
+ progress = JSON.parse(await session.resume(JSON.stringify(response)));
214993
+ }
214994
+ }
214995
+ /**
214996
+ * TS `externalHooksService.runStop` parity (P1-3): after a non-tool step,
214997
+ * fire the Stop hook; a returned reason becomes a continuation message
214998
+ * (origin `system_trigger`/`stop_hook`) that keeps the turn alive —
214999
+ * steered into the running turn, or launched as a fresh turn when the
215000
+ * engine already finished (the task-notification fallback). Fires at most
215001
+ * once after a continuation was used, mirroring `stopHookContinuationUsed`.
215002
+ */
215003
+ runStopHook(turnId) {
215004
+ if (this.stopHookContinuationUsed) return;
215005
+ this.stopHookContinuationUsed = true;
215006
+ const hooksRunner = this.instantiation.invokeFunction((accessor) => accessor.get(IExternalHooksRunnerService));
215007
+ if (hooksRunner === void 0) return;
215008
+ (async () => {
215009
+ try {
215010
+ const reason = (await hooksRunner.triggerBlock("Stop", {
215011
+ signal: new AbortController().signal,
215012
+ sessionId: this.sessionContext.sessionId,
215013
+ inputData: { stopHookActive: false }
215014
+ }))?.reason;
215015
+ if (reason === void 0 || reason.length === 0) return;
215016
+ const origin = {
215017
+ kind: "system_trigger",
215018
+ name: "stop_hook"
215019
+ };
215020
+ if (this.turnRunning && this.activeSession !== void 0 && this.activeSession.steer(reason)) {
215021
+ this.context.append({
215022
+ role: "user",
215023
+ content: [{
215024
+ type: "text",
215025
+ text: reason
215026
+ }],
215027
+ toolCalls: [],
215028
+ origin,
215029
+ id: randomUUID()
215030
+ });
215031
+ this.wire.dispatch(steerTurn({
215032
+ input: [{
215033
+ type: "text",
215034
+ text: reason
215035
+ }],
215036
+ origin
215037
+ }));
215038
+ } else this.runTurn({
215039
+ input: [{
215040
+ type: "text",
215041
+ text: reason
215042
+ }],
215043
+ origin
215044
+ }).catch(() => void 0);
215045
+ } catch {}
215046
+ })();
215047
+ }
215048
+ /**
215049
+ * `task.started` (engine transport) → TS records: the persisted
215050
+ * `task.started` wire op (TaskModel / transcript / TaskList) plus the
215051
+ * `subagent.spawned` session event for subagent launches.
215052
+ */
215053
+ handleTaskStarted(event) {
215054
+ const taskId = toText(event["taskId"]);
215055
+ const agentId = toText(event["agentId"]);
215056
+ const kind = toText(event["kind"]);
215057
+ const description = toText(event["description"]);
215058
+ const startedAt = Date.now();
215059
+ const pid = toOptionalNumber(event["pid"]);
215060
+ this.taskInfos.set(taskId, {
215061
+ description,
215062
+ startedAt,
215063
+ pid
215064
+ });
215065
+ if (kind === "agent" && agentId !== "") this.engineAgentIds.add(agentId);
215066
+ const info = kind === "agent" ? {
215067
+ taskId,
215068
+ kind: "agent",
215069
+ agentId,
215070
+ subagentType: description,
215071
+ description,
215072
+ status: "running",
215073
+ detached: true,
215074
+ startedAt,
215075
+ endedAt: null
215076
+ } : {
215077
+ taskId,
215078
+ kind: "process",
215079
+ command: description,
215080
+ pid: pid ?? 0,
215081
+ exitCode: null,
215082
+ description,
215083
+ status: "running",
215084
+ detached: true,
215085
+ startedAt,
215086
+ endedAt: null
215087
+ };
215088
+ this.wire.dispatch(taskStarted({ info }));
215089
+ this.registerEngineTask(taskId, agentId, kind, description, pid);
215090
+ if (kind === "agent") {
215091
+ this.eventBus.publish({
215092
+ type: "subagent.spawned",
215093
+ subagentId: agentId,
215094
+ subagentName: description,
215095
+ parentToolCallId: toText(event["parentToolCallId"]),
215096
+ parentAgentId: this.scopeContext.agentId,
215097
+ callerAgentId: this.scopeContext.agentId,
215098
+ description,
215099
+ runInBackground: false
215100
+ });
215101
+ this.eventBus.publish({
215102
+ type: "subagent.started",
215103
+ subagentId: agentId
215104
+ });
215105
+ }
215106
+ }
215107
+ /**
215108
+ * `task.output` (engine transport) → the task-service entry's live sink:
215109
+ * append the streamed delta so TaskOutput shows partial output while the
215110
+ * engine task is still running (TS ProcessTask parity — TS streams chunks
215111
+ * as they arrive; the adapter's settle also appends only the not-yet-
215112
+ * streamed tail, so nothing is duplicated). No wire op / bus event: the
215113
+ * live output is the service's retained buffer, the wire `task.terminated`
215114
+ * tail comes from the settle's full output.
215115
+ */
215116
+ handleTaskOutput(event) {
215117
+ const taskId = toText(event["taskId"]);
215118
+ const delta = toText(event["delta"]);
215119
+ if (delta.length === 0) return;
215120
+ const adapter = this.engineTaskAdapters.get(taskId);
215121
+ if (adapter !== void 0) {
215122
+ adapter.appendOutput(delta);
215123
+ return;
215124
+ }
215125
+ this.log.debug("[rustEngineTurnRunner] task.output for unregistered task", { taskId });
215126
+ }
215127
+ /**
215128
+ * Register an engine background task with `IAgentTaskService` (TaskList /
215129
+ * TaskStop / TaskOutput parity). The adapter bridges TaskStop into the
215130
+ * engine's per-task cancel (`session.cancelTask`) — the launching session's
215131
+ * worker/poller kills its work and settles "killed" — and its `start`
215132
+ * streams the settle output into the service's sink so TaskOutput and the
215133
+ * terminal info see it.
215134
+ */
215135
+ registerEngineTask(taskId, agentId, kind, description, pid) {
215136
+ const session = this.taskSessions.get(taskId) ?? this.activeSession;
215137
+ const adapter = new EngineTaskAdapter({
215138
+ taskId,
215139
+ agentId,
215140
+ kind: kind === "agent" ? "agent" : "process",
215141
+ description,
215142
+ pid,
215143
+ subagentType: kind === "agent" ? description : void 0,
215144
+ forceStop: (reason) => {
215145
+ try {
215146
+ session?.cancelTask(taskId, reason);
215147
+ } catch (error) {
215148
+ this.log.error("[rustEngineTurnRunner] failed to cancel engine task", {
215149
+ taskId,
215150
+ error
215151
+ });
215152
+ }
215153
+ }
215154
+ });
215155
+ this.engineTaskAdapters.set(taskId, adapter);
215156
+ try {
215157
+ this.tasks.registerTask(adapter, {
215158
+ taskId,
215159
+ detached: false
215160
+ });
215161
+ } catch (error) {
215162
+ this.log.error("[rustEngineTurnRunner] failed to register engine task", {
215163
+ taskId,
215164
+ error
215165
+ });
215166
+ this.engineTaskAdapters.delete(taskId);
215167
+ }
215168
+ }
215169
+ /**
215170
+ * `task.settled` (engine transport) → TS records: the persisted
215171
+ * `task.terminated` wire op (bounded output tail), the `subagent.completed`
215172
+ * / `subagent.failed` session events, and the completion notification
215173
+ * delivered to the model (context message + `task.notified` + steer/new
215174
+ * turn — TS `activeOrNewTurn` parity).
215175
+ */
215176
+ handleTaskSettled(event) {
215177
+ const taskId = toText(event["taskId"]);
215178
+ const agentId = toText(event["agentId"]);
215179
+ const kind = toText(event["kind"]);
215180
+ const status = toText(event["status"]);
215181
+ const output = toText(event["output"]);
215182
+ const error = event["error"] === void 0 || event["error"] === null ? void 0 : toText(event["error"]);
215183
+ const launch = this.taskInfos.get(taskId);
215184
+ const endedAt = Date.now();
215185
+ const stopReason = status === "failed" || status === "timed_out" || status === "killed" ? error : void 0;
215186
+ const base = {
215187
+ taskId,
215188
+ description: launch?.description ?? "",
215189
+ status,
215190
+ detached: true,
215191
+ startedAt: launch?.startedAt ?? endedAt,
215192
+ endedAt,
215193
+ stopReason
215194
+ };
215195
+ const info = kind === "agent" ? {
215196
+ ...base,
215197
+ kind: "agent",
215198
+ agentId,
215199
+ subagentType: launch?.description ?? ""
215200
+ } : {
215201
+ ...base,
215202
+ kind: "process",
215203
+ command: launch?.description ?? "",
215204
+ pid: launch?.pid ?? 0,
215205
+ exitCode: toOptionalNumber(event["exitCode"]) ?? null
215206
+ };
215207
+ this.wire.dispatch(taskTerminated({
215208
+ info,
215209
+ outputTail: output.slice(-TERMINAL_OUTPUT_TAIL_CHARS)
215210
+ }));
215211
+ if (kind === "agent") {
215212
+ if (status === "completed") this.eventBus.publish({
215213
+ type: "subagent.completed",
215214
+ subagentId: agentId,
215215
+ resultSummary: output
215216
+ });
215217
+ else if (status === "failed") this.eventBus.publish({
215218
+ type: "subagent.failed",
215219
+ subagentId: agentId,
215220
+ error: error ?? status
215221
+ });
215222
+ }
215223
+ const adapter = this.engineTaskAdapters.get(taskId);
215224
+ if (adapter !== void 0) {
215225
+ adapter.complete(output, {
215226
+ status,
215227
+ stopReason
215228
+ }, toOptionalNumber(event["exitCode"]));
215229
+ this.engineTaskAdapters.delete(taskId);
215230
+ }
215231
+ this.taskInfos.delete(taskId);
215232
+ this.taskSessions.delete(taskId);
215233
+ if (this.tasks.getTask(taskId)?.terminalNotificationSuppressed === true) return;
215234
+ this.deliverTaskNotification({
215235
+ taskId,
215236
+ agentId,
215237
+ kind,
215238
+ status,
215239
+ description: launch?.description ?? "",
215240
+ output,
215241
+ error
215242
+ });
215243
+ }
215244
+ /**
215245
+ * Deliver a task completion notification to the model — the Rust-engine
215246
+ * equivalent of the TS task domain's detached-task notification
215247
+ * (`TaskNotificationStepRequest`, `activeOrNewTurn` admission): append the
215248
+ * `<notification>` XML as a task-origin user message, fire the
215249
+ * `task.notified` hook event, then fold it into the running turn's next
215250
+ * step (steer) or launch a notification turn when idle.
215251
+ */
215252
+ deliverTaskNotification(task) {
215253
+ const key = `task:${task.taskId}:${task.status}`;
215254
+ if (this.deliveredNotificationKeys.has(key)) return;
215255
+ this.deliveredNotificationKeys.add(key);
215256
+ const kindLabel = task.kind === "agent" ? "agent" : "process";
215257
+ const notification = {
215258
+ id: key,
215259
+ category: "task",
215260
+ type: `task.${task.status}`,
215261
+ source_kind: "background_task",
215262
+ source_id: task.taskId,
215263
+ agent_id: task.kind === "agent" ? task.agentId : void 0,
215264
+ title: `Background ${kindLabel} ${task.status}`,
215265
+ severity: task.status === "completed" ? "info" : "warning",
215266
+ body: buildTaskNotificationBody(task),
215267
+ children: task.output.length > 0 ? [renderOutputPreviewBlock(task.output)] : void 0
215268
+ };
215269
+ const xml = renderNotificationXml(notification);
215270
+ const origin = {
215271
+ kind: "task",
215272
+ taskId: task.taskId,
215273
+ status: task.status,
215274
+ notificationId: key
215275
+ };
215276
+ try {
215277
+ if (this.turnRunning && this.activeSession !== void 0 && this.activeSession.steer(xml)) {
215278
+ this.context.append({
215279
+ role: "user",
215280
+ content: [{
215281
+ type: "text",
215282
+ text: xml
215283
+ }],
215284
+ toolCalls: [],
215285
+ origin,
215286
+ id: randomUUID()
215287
+ });
215288
+ this.wire.dispatch(steerTurn({
215289
+ input: [{
215290
+ type: "text",
215291
+ text: xml
215292
+ }],
215293
+ origin
215294
+ }));
215295
+ } else this.runTurn({
215296
+ input: [{
215297
+ type: "text",
215298
+ text: xml
215299
+ }],
215300
+ origin
215301
+ }).catch(() => void 0);
215302
+ this.eventBus.publish({
215303
+ type: "task.notified",
215304
+ notificationType: `task.${task.status}`,
215305
+ title: notification.title,
215306
+ body: notification.body,
215307
+ severity: notification.severity,
215308
+ sourceKind: notification.source_kind,
215309
+ sourceId: notification.source_id
215310
+ });
215311
+ } finally {
215312
+ this.deliveredNotificationKeys.delete(key);
215313
+ }
215314
+ }
215315
+ toLlmMessage(message) {
215316
+ const text = message.content.filter((part) => part.type === "text").map((part) => part.text ?? "").join("");
215317
+ const media = message.content.filter((part) => part.type === "image_url" || part.type === "audio_url" || part.type === "video_url").map((part) => {
215318
+ return {
215319
+ type: "media_url",
215320
+ url: part.imageUrl?.url ?? part.audioUrl?.url ?? part.videoUrl?.url
215321
+ };
215322
+ }).filter((part) => part.url !== void 0);
215323
+ const toolCalls = message.toolCalls.map((call) => ({
215324
+ id: call.id,
215325
+ type: "function",
215326
+ function: {
215327
+ name: call.name,
215328
+ arguments: call.arguments
215329
+ }
215330
+ }));
215331
+ return {
215332
+ role: message.role,
215333
+ content: media.length > 0 ? [...media, ...text.length > 0 ? [{
215334
+ type: "text",
215335
+ text
215336
+ }] : []] : text,
215337
+ ...message.role === "assistant" && toolCalls.length > 0 ? { toolCalls } : {},
215338
+ ...message.role === "tool" && message.toolCallId !== void 0 ? { toolCallId: message.toolCallId } : {}
215339
+ };
215340
+ }
215341
+ /**
215342
+ * The next subagent agent-id number to hand to the engine for this turn
215343
+ * (TS `nextAvailableAgentId` parity): the max known `agent-<n>` suffix
215344
+ * among (a) the ids this runner's engine has already handed out across
215345
+ * turns and (b) the session's persisted agents, plus one. The engine seeds
215346
+ * its per-session counter from it, so ids stay monotonic across turns and
215347
+ * server restarts and never collide with TS-assigned ids.
215348
+ */
215349
+ async computeNextAgentId() {
215350
+ let maxSuffix = -1;
215351
+ const consider = (id) => {
215352
+ const match = /^agent-(\d+)$/.exec(id);
215353
+ if (match !== null) maxSuffix = Math.max(maxSuffix, Number(match[1]));
215354
+ };
215355
+ for (const id of this.engineAgentIds) consider(id);
215356
+ try {
215357
+ const persisted = (await this.sessionMetadata.read()).agents ?? {};
215358
+ for (const id of Object.keys(persisted)) consider(id);
215359
+ } catch {
215360
+ this.log.warn("[rustEngineTurnRunner] failed to read session metadata; seeding next agent id from in-session engine ids only");
215361
+ }
215362
+ return maxSuffix + 1;
215363
+ }
215364
+ maxStepsPerTurn() {
215365
+ return this.config.get("loop_control")?.maxStepsPerTurn;
215366
+ }
215367
+ /**
215368
+ * The effective engine-side tool allowlist (TS `isToolActiveComposed`
215369
+ * parity): the runner's `IAgentToolPolicyService.isToolActive` composes
215370
+ * the profile allowlist/denylist, the global `[tools]` config, and the
215371
+ * session denylist — with MCP glob semantics for `mcp__*` tools. AllDone
215372
+ * stays active regardless (the completion-review protocol needs it).
215373
+ * `undefined` = unconstrained (all tools).
215374
+ */
215375
+ effectiveActiveTools() {
215376
+ const all = this.toolRegistry.list().map((info) => info.name);
215377
+ const active = all.filter((name) => {
215378
+ if (name === "AllDone") return true;
215379
+ return this.toolPolicy.isToolActive(name);
215380
+ });
215381
+ return active.length === all.length ? void 0 : active;
215382
+ }
215383
+ maxRetriesPerStep() {
215384
+ return this.config.get("loop_control")?.maxRetriesPerStep;
215385
+ }
215386
+ killGracePeriodMs() {
215387
+ return resolveAgentTaskConfig(this.config)?.killGracePeriodMs ?? 5e3;
215388
+ }
215389
+ maxContextTokens() {
215390
+ const capability = this.profile.data().modelCapabilities;
215391
+ const max = capability.max_input_tokens ?? capability.max_context_tokens;
215392
+ return max > 0 ? max : void 0;
215393
+ }
215394
+ async providerConfig() {
215395
+ const modelAlias = this.profile.data().modelAlias ?? this.profile.getModel();
215396
+ let baseUrl = "";
215397
+ let apiKey = "";
215398
+ try {
215399
+ const model = this.modelCatalog.get(modelAlias);
215400
+ baseUrl = model.baseUrl;
215401
+ apiKey = (await this.providerRuntime.getAuth(model))?.auth.apiKey ?? "";
215402
+ } catch {}
215403
+ return {
215404
+ baseUrl: baseUrl || "https://api.openai.com/v1",
215405
+ apiKey,
215406
+ model: modelAlias || "gpt-4o",
215407
+ thinkingEffort: this.profile.getEffectiveThinkingLevel()
215408
+ };
215409
+ }
215410
+ };
215411
+ RustEngineTurnRunner = __decorate$1([
215412
+ __decorateParam(0, IAgentContextMemoryService),
215413
+ __decorateParam(1, IEventBus),
215414
+ __decorateParam(2, IWireService),
215415
+ __decorateParam(3, IConfigService),
215416
+ __decorateParam(4, IAgentPermissionModeService),
215417
+ __decorateParam(5, IAgentPermissionRulesService),
215418
+ __decorateParam(6, IAgentToolRegistryService),
215419
+ __decorateParam(7, IAgentUsageService),
215420
+ __decorateParam(8, IAgentProfileService),
215421
+ __decorateParam(9, IAgentScopeContext),
215422
+ __decorateParam(10, ISessionContext),
215423
+ __decorateParam(11, ISessionMetadata),
215424
+ __decorateParam(12, IAgentTaskService),
215425
+ __decorateParam(13, IModelCatalog),
215426
+ __decorateParam(14, IProviderRuntime),
215427
+ __decorateParam(15, IInstantiationService),
215428
+ __decorateParam(16, IAgentToolPolicyService),
215429
+ __decorateParam(17, ILogService)
215430
+ ], RustEngineTurnRunner);
215431
+ registerScopedService(2, IRustEngineTurnRunner, RustEngineTurnRunner, 0, "rustEngineTurnRunner");
215432
+ }));
215433
+ //#endregion
213604
215434
  //#region ../../packages/agent-core-v2/src/agent/rpc/prompt-metadata.ts
213605
215435
  function promptMetadataTextFromPayload(payload) {
213606
215436
  return promptMetadataTextFromContentParts(payload.input);
@@ -213669,6 +215499,7 @@ var init_rpcService = __esmMin((() => {
213669
215499
  init_telemetry$2();
213670
215500
  init_toolRegistry();
213671
215501
  init_loop();
215502
+ init_rustEngineTurnRunner();
213672
215503
  init_rpc$2();
213673
215504
  init_prompt_metadata();
213674
215505
  init_decorateParam();
@@ -213692,7 +215523,8 @@ var init_rpcService = __esmMin((() => {
213692
215523
  sessionContext;
213693
215524
  scopeContext;
213694
215525
  agentLifecycle;
213695
- constructor(promptService, conversationUndo, loop, toolPolicy, permissionMode, fullCompaction, toolRegistry, context, contextSize, skills, telemetry, eventBus, eventService, plugins, metadata, sessionContext, scopeContext, agentLifecycle) {
215526
+ rustEngineTurnRunner;
215527
+ constructor(promptService, conversationUndo, loop, toolPolicy, permissionMode, fullCompaction, toolRegistry, context, contextSize, skills, telemetry, eventBus, eventService, plugins, metadata, sessionContext, scopeContext, agentLifecycle, rustEngineTurnRunner) {
213696
215528
  this.promptService = promptService;
213697
215529
  this.conversationUndo = conversationUndo;
213698
215530
  this.loop = loop;
@@ -213711,6 +215543,7 @@ var init_rpcService = __esmMin((() => {
213711
215543
  this.sessionContext = sessionContext;
213712
215544
  this.scopeContext = scopeContext;
213713
215545
  this.agentLifecycle = agentLifecycle;
215546
+ this.rustEngineTurnRunner = rustEngineTurnRunner;
213714
215547
  }
213715
215548
  async prompt(payload) {
213716
215549
  if (payload.disabledTools !== void 0) try {
@@ -213720,6 +215553,13 @@ var init_rpcService = __esmMin((() => {
213720
215553
  throw error;
213721
215554
  }
213722
215555
  await this.updatePromptMetadata(promptMetadataTextFromPayload(payload));
215556
+ if (RustEngineTurnRunner.isEnabled()) {
215557
+ const launched = await this.rustEngineTurnRunner.runTurn({
215558
+ input: [...payload.input],
215559
+ origin: { kind: "user" }
215560
+ });
215561
+ return launched === void 0 ? void 0 : { turn_id: launched.turnId };
215562
+ }
213723
215563
  const handle = await this.promptService.enqueue({ message: {
213724
215564
  role: "user",
213725
215565
  content: [...payload.input],
@@ -213732,6 +215572,17 @@ var init_rpcService = __esmMin((() => {
213732
215572
  }
213733
215573
  async steer(payload) {
213734
215574
  this.telemetry.track2("input_steer", { parts: payload.input.length });
215575
+ if (RustEngineTurnRunner.isEnabled()) {
215576
+ if (this.rustEngineTurnRunner.steer({
215577
+ input: [...payload.input],
215578
+ origin: { kind: "user" }
215579
+ })) return { turn_id: 0 };
215580
+ const launched = await this.rustEngineTurnRunner.runTurn({
215581
+ input: [...payload.input],
215582
+ origin: { kind: "user" }
215583
+ });
215584
+ return launched === void 0 ? void 0 : { turn_id: launched.turnId };
215585
+ }
213735
215586
  const submitted = await this.promptService.enqueueOrSteer({ message: {
213736
215587
  role: "user",
213737
215588
  content: [...payload.input],
@@ -213742,6 +215593,10 @@ var init_rpcService = __esmMin((() => {
213742
215593
  return turn === void 0 ? void 0 : { turn_id: turn.id };
213743
215594
  }
213744
215595
  cancel({ turnId }) {
215596
+ if (RustEngineTurnRunner.isEnabled()) {
215597
+ this.rustEngineTurnRunner.cancel(turnId);
215598
+ return;
215599
+ }
213745
215600
  if (this.loop.status().state === "running") this.telemetry.track2("cancel", {
213746
215601
  from: "streaming",
213747
215602
  trace_id: this.loop.status().activeTraceId
@@ -213846,7 +215701,8 @@ var init_rpcService = __esmMin((() => {
213846
215701
  __decorateParam(14, ISessionMetadata),
213847
215702
  __decorateParam(15, ISessionContext),
213848
215703
  __decorateParam(16, IAgentScopeContext),
213849
- __decorateParam(17, IAgentLifecycleService)
215704
+ __decorateParam(17, IAgentLifecycleService),
215705
+ __decorateParam(18, IRustEngineTurnRunner)
213850
215706
  ], AgentRPCService);
213851
215707
  registerScopedService(2, IAgentRPCService, AgentRPCService, 0, "rpc");
213852
215708
  }));
@@ -216423,13 +218279,6 @@ var init_args_validator = __esmMin((() => {
216423
218279
  ]);
216424
218280
  }));
216425
218281
  //#endregion
216426
- //#region ../../packages/agent-core-v2/src/agent/toolResultTruncation/toolResultTruncation.ts
216427
- var IAgentToolResultTruncationService;
216428
- var init_toolResultTruncation = __esmMin((() => {
216429
- init_instantiation();
216430
- IAgentToolResultTruncationService = createDecorator("agentToolResultTruncationService");
216431
- }));
216432
- //#endregion
216433
218282
  //#region ../../packages/agent-core-v2/src/agent/toolExecutor/toolScheduler.ts
216434
218283
  function createControlledPromise() {
216435
218284
  let resolve;
@@ -217493,7 +219342,7 @@ var init_src$6 = __esmMin((() => {
217493
219342
  init_migration();
217494
219343
  init_sessionLogService();
217495
219344
  init_telemetry$2();
217496
- init_events$7();
219345
+ init_events$8();
217497
219346
  init_telemetryService();
217498
219347
  init_agentTelemetryContext();
217499
219348
  init_agentTelemetryContextService();
@@ -217688,6 +219537,8 @@ var init_src$6 = __esmMin((() => {
217688
219537
  init_wait();
217689
219538
  init_waitService();
217690
219539
  init_waitForTool();
219540
+ init_agent_output$1();
219541
+ init_agentOutputTool();
217691
219542
  init_completion();
217692
219543
  init_allDoneTool();
217693
219544
  init_configSection$4();
@@ -218578,7 +220429,7 @@ var modelCatalogItemSchema$1, providerCatalogStatusSchema$1, providerCatalogItem
218578
220429
  provider: string$2().min(1),
218579
220430
  reason: string$2().min(1)
218580
220431
  });
218581
- })), tokenUsageSchema$2, finishReasonSchema$1, usageStatusSchema$2, permissionModeSchema$2, skillSourceSchema$2, userPromptOriginSchema$1, skillActivationOriginSchema$1, pluginCommandOriginSchema$1, injectionOriginSchema$1, shellCommandOriginSchema$1, compactionSummaryOriginSchema$1, systemTriggerOriginSchema$1, taskLifecycleStatusSchema$2, taskOriginSchema$1, cronJobOriginSchema$1, cronMissedOriginSchema$1, hookResultOriginSchema$1, retryOriginSchema$1, promptOriginSchema$1, dimiErrorCodeSchema$1, dimiErrorPayloadSchema$1, dimiErrorPayloadObjectSchema$1, taskInfoBaseSchema$1, processTaskInfoSchema$1, agentTaskInfoSchema$2, questionTaskInfoSchema$1, toolTaskInfoSchema$1, taskInfoSchema$1, compactionResultSchema$1, toolUpdateSchema$1, turnEndReasonSchema$2, agentPhaseSchema$1, agentStatusUpdatedEventSchema$2, sessionMetaUpdatedEventSchema$1, sessionCreatedEventSchema$1, workspaceCreatedEventSchema$1, workspaceUpdatedEventSchema$1, workspaceDeletedEventSchema$1, sessionWorkChangedEventSchema$1, sessionStatusChangedEventSchema$1, modelCatalogChangedEventSchema, skillActivatedEventSchema$1, pluginCommandActivatedEventSchema$1, errorEventSchema$2, warningEventSchema$2, turnStartedEventSchema$2, turnEndedEventSchema$2, turnStepStartedEventSchema$1, turnStepCompletedEventSchema$1, turnStepRetryingEventSchema$1, turnStepInterruptedEventSchema$1, assistantDeltaEventSchema$2, hookResultEventSchema$1, thinkingDeltaEventSchema$2, toolCallDeltaEventSchema$1, toolCallStartedEventSchema$2, toolProgressEventSchema$1, shellOutputEventSchema$1, shellStartedEventSchema$1, shellCompletedEventSchema$1, toolResultEventSchema$2, subagentSpawnedEventSchema$1, subagentStartedEventSchema$1, subagentSuspendedEventSchema$1, subagentCompletedEventSchema$1, subagentFailedEventSchema$1, compactionStartedEventSchema$1, compactionBlockedEventSchema$1, compactionCancelledEventSchema$1, compactionCompletedEventSchema$1, taskStartedEventSchema$1, taskTerminatedEventSchema$1, cronFiredEventSchema$1, promptSubmittedEventSchema$1, promptCompletedEventSchema$2, promptAbortedEventSchema$2, promptSteeredEventSchema$1, toolListUpdatedReasonSchema$1, toolListUpdatedEventSchema$1, mcpServerStatusPayloadSchema$1, mcpServerStatusEventSchema$1, agentEventSchema$1, eventSchema$1, VOLATILE_EVENT_TYPES$1, init_events$6 = __esmMin((() => {
220432
+ })), tokenUsageSchema$2, finishReasonSchema$1, usageStatusSchema$2, permissionModeSchema$2, skillSourceSchema$2, userPromptOriginSchema$1, skillActivationOriginSchema$1, pluginCommandOriginSchema$1, injectionOriginSchema$1, shellCommandOriginSchema$1, compactionSummaryOriginSchema$1, systemTriggerOriginSchema$1, taskLifecycleStatusSchema$2, taskOriginSchema$1, cronJobOriginSchema$1, cronMissedOriginSchema$1, hookResultOriginSchema$1, retryOriginSchema$1, promptOriginSchema$1, dimiErrorCodeSchema$1, dimiErrorPayloadSchema$1, dimiErrorPayloadObjectSchema$1, taskInfoBaseSchema$1, processTaskInfoSchema$1, agentTaskInfoSchema$2, questionTaskInfoSchema$1, toolTaskInfoSchema$1, taskInfoSchema$1, compactionResultSchema$1, toolUpdateSchema$1, turnEndReasonSchema$2, agentPhaseSchema$1, agentStatusUpdatedEventSchema$2, sessionMetaUpdatedEventSchema$1, sessionCreatedEventSchema$1, workspaceCreatedEventSchema$1, workspaceUpdatedEventSchema$1, workspaceDeletedEventSchema$1, sessionWorkChangedEventSchema$1, sessionStatusChangedEventSchema$1, modelCatalogChangedEventSchema, skillActivatedEventSchema$1, pluginCommandActivatedEventSchema$1, errorEventSchema$2, warningEventSchema$2, turnStartedEventSchema$2, turnEndedEventSchema$2, turnStepStartedEventSchema$1, turnStepCompletedEventSchema$1, turnStepRetryingEventSchema$1, turnStepInterruptedEventSchema$1, assistantDeltaEventSchema$2, hookResultEventSchema$1, thinkingDeltaEventSchema$2, toolCallDeltaEventSchema$1, toolCallStartedEventSchema$2, toolProgressEventSchema$1, shellOutputEventSchema$1, shellStartedEventSchema$1, shellCompletedEventSchema$1, toolResultEventSchema$2, subagentSpawnedEventSchema$1, subagentStartedEventSchema$1, subagentSuspendedEventSchema$1, subagentCompletedEventSchema$1, subagentFailedEventSchema$1, compactionStartedEventSchema$1, compactionBlockedEventSchema$1, compactionCancelledEventSchema$1, compactionCompletedEventSchema$1, taskStartedEventSchema$1, taskTerminatedEventSchema$1, cronFiredEventSchema$1, promptSubmittedEventSchema$1, promptCompletedEventSchema$2, promptAbortedEventSchema$2, promptSteeredEventSchema$1, toolListUpdatedReasonSchema$1, toolListUpdatedEventSchema$1, mcpServerStatusPayloadSchema$1, mcpServerStatusEventSchema$1, agentEventSchema$1, eventSchema$1, VOLATILE_EVENT_TYPES$1, init_events$7 = __esmMin((() => {
218582
220433
  init_zod$1();
218583
220434
  init_display$1();
218584
220435
  init_message$1();
@@ -219352,7 +221203,7 @@ var modelCatalogItemSchema$1, providerCatalogStatusSchema$1, providerCatalogItem
219352
221203
  })), sessionCursorSchema$1, cursorsBySessionSchema$1, wsEventEnvelopeSchema$1, wsAckEnvelopeSchema$1, serverHelloPayloadSchema$1, serverHelloMessageSchema$1, agentFilterSchema$1, clientHelloPayloadSchema$1, clientHelloMessageSchema$1, clientHelloAckPayloadSchema$1, clientHelloAckMessageSchema$1, watchFsConfigSchema$1, subscribePayloadSchema$1, subscribeMessageSchema$1, subscribeAckPayloadSchema$1, subscribeAckMessageSchema$1, unsubscribePayloadSchema$1, unsubscribeMessageSchema$1, unsubscribeAckPayloadSchema$1, unsubscribeAckMessageSchema$1, watchFsAddPayloadSchema$1, watchFsAddMessageSchema$1, watchFsRemovePayloadSchema$1, watchFsRemoveMessageSchema$1, watchFsAckPayloadSchema$1, watchFsAckMessageSchema$1, abortPayloadSchema$1, abortMessageSchema$1, abortAckPayloadSchema$1, abortAckMessageSchema$1, terminalAttachPayloadSchema$1, terminalAttachMessageSchema$1, terminalAttachAckPayloadSchema$1, terminalAttachAckMessageSchema$1, terminalDetachPayloadSchema$1, terminalDetachMessageSchema$1, terminalDetachAckPayloadSchema$1, terminalDetachAckMessageSchema$1, terminalInputPayloadSchema$1, terminalInputMessageSchema$1, terminalInputAckPayloadSchema$1, terminalInputAckMessageSchema$1, terminalResizePayloadSchema$1, terminalResizeMessageSchema$1, terminalResizeAckPayloadSchema$1, terminalResizeAckMessageSchema$1, terminalClosePayloadSchema$1, terminalCloseMessageSchema$1, terminalCloseAckPayloadSchema$1, terminalCloseAckMessageSchema$1, pingPayloadSchema$1, pingMessageSchema$1, pongPayloadSchema$1, pongMessageSchema$1, resyncRequiredPayloadSchema$1, resyncRequiredMessageSchema$1, wsErrorPayloadSchema$1, wsErrorMessageSchema$1, terminalOutputPayloadSchema$1, terminalExitPayloadSchema$1, clientControlOperations$1, serverSystemOperations$1;
219353
221204
  var init_ws_control$1 = __esmMin((() => {
219354
221205
  init_zod$1();
219355
- init_events$6();
221206
+ init_events$7();
219356
221207
  init_time();
219357
221208
  sessionCursorSchema$1 = object({
219358
221209
  seq: number$2().int().nonnegative(),
@@ -219897,7 +221748,7 @@ var init_tool$2 = __esmMin((() => {
219897
221748
  var skillDescriptorSchema$1;
219898
221749
  var init_skill$2 = __esmMin((() => {
219899
221750
  init_zod$1();
219900
- init_events$6();
221751
+ init_events$7();
219901
221752
  skillDescriptorSchema$1 = object({
219902
221753
  name: string$2().min(1),
219903
221754
  description: string$2(),
@@ -220630,7 +222481,7 @@ var init_src$5 = __esmMin((() => {
220630
222481
  init_pagination$1();
220631
222482
  init_time();
220632
222483
  init_request_id$2();
220633
- init_events$6();
222484
+ init_events$7();
220634
222485
  init_display$1();
220635
222486
  init_ws_control$1();
220636
222487
  init_asyncapi$1();
@@ -220669,7 +222520,7 @@ var init_src$5 = __esmMin((() => {
220669
222520
  }));
220670
222521
  //#endregion
220671
222522
  //#region ../../packages/node-sdk/src/events.ts
220672
- var init_events$5 = __esmMin((() => {
222523
+ var init_events$6 = __esmMin((() => {
220673
222524
  init_src$5();
220674
222525
  }));
220675
222526
  //#endregion
@@ -220724,7 +222575,7 @@ var MAIN_AGENT_ID$6, Session;
220724
222575
  var init_session$3 = __esmMin((() => {
220725
222576
  init_src$6();
220726
222577
  init_errors$3();
220727
- init_events$5();
222578
+ init_events$6();
220728
222579
  MAIN_AGENT_ID$6 = "main";
220729
222580
  Session = class {
220730
222581
  id;
@@ -221753,7 +223604,7 @@ var init_helpers = __esmMin((() => {
221753
223604
  removed: array$2(string$2()),
221754
223605
  changed: array$2(string$2())
221755
223606
  });
221756
- })), textPartSchema, imageUrlPartSchema, videoUrlPartSchema, promptPartSchema, emptyPayloadSchema, promptPayloadSchema, steerPayloadSchema, promptLaunchResultSchema, cancelPayloadSchema, runShellCommandPayloadSchema, shellCommandResultSchema, setModelResultSchema, permissionModeSchema$1, setPermissionPayloadSchema, tokenUsageSchema$1, usageStatusSchema$1, agentContextDataSchema, planDataSchema, taskLifecycleStatusSchema$1, taskInfoBaseFields, agentTaskInfoSchema$1, agentRpcContract;
223607
+ })), textPartSchema, imageUrlPartSchema, videoUrlPartSchema, promptPartSchema, emptyPayloadSchema, promptPayloadSchema, steerPayloadSchema, promptLaunchResultSchema, cancelPayloadSchema, runShellCommandPayloadSchema, shellCommandResultSchema$1, setModelResultSchema, permissionModeSchema$1, setPermissionPayloadSchema, tokenUsageSchema$1, usageStatusSchema$1, agentContextDataSchema, planDataSchema, taskLifecycleStatusSchema$1, taskInfoBaseFields, agentTaskInfoSchema$1, agentRpcContract;
221757
223608
  var init_rpc$1 = __esmMin((() => {
221758
223609
  init_zod$1();
221759
223610
  init_helpers();
@@ -221792,7 +223643,7 @@ var init_rpc$1 = __esmMin((() => {
221792
223643
  command: string$2(),
221793
223644
  commandId: string$2().optional()
221794
223645
  });
221795
- shellCommandResultSchema = object({
223646
+ shellCommandResultSchema$1 = object({
221796
223647
  stdout: string$2(),
221797
223648
  stderr: string$2(),
221798
223649
  isError: boolean$2().optional(),
@@ -221924,7 +223775,7 @@ var init_services = __esmMin((() => {
221924
223775
  agentShellCommandContract = {
221925
223776
  run: {
221926
223777
  input: tuple([runShellCommandPayloadSchema]),
221927
- output: shellCommandResultSchema
223778
+ output: shellCommandResultSchema$1
221928
223779
  },
221929
223780
  cancel: {
221930
223781
  input: tuple([string$2()]),
@@ -222868,7 +224719,7 @@ var init_contract$1 = __esmMin((() => {
222868
224719
  //#endregion
222869
224720
  //#region ../../packages/klient/src/contract/global/events.ts
222870
224721
  var configChangedSchema, reloadSummarySchema, sessionMetaUpdatedSchema, globalEvents;
222871
- var init_events$4 = __esmMin((() => {
224722
+ var init_events$5 = __esmMin((() => {
222872
224723
  init_zod$1();
222873
224724
  configChangedSchema = object({
222874
224725
  domain: string$2(),
@@ -222932,7 +224783,7 @@ var init_events$4 = __esmMin((() => {
222932
224783
  //#endregion
222933
224784
  //#region ../../packages/klient/src/contract/session/events.ts
222934
224785
  var sessionEvents;
222935
- var init_events$3 = __esmMin((() => {
224786
+ var init_events$4 = __esmMin((() => {
222936
224787
  init_zod$1();
222937
224788
  init_interaction$1();
222938
224789
  init_metadata();
@@ -222958,7 +224809,7 @@ var init_events$3 = __esmMin((() => {
222958
224809
  //#endregion
222959
224810
  //#region ../../packages/klient/src/contract/agent/events.ts
222960
224811
  var turnStartedEventSchema$1, turnEndedEventSchema$1, assistantDeltaEventSchema$1, thinkingDeltaEventSchema$1, toolCallStartedEventSchema$1, toolResultEventSchema$1, promptCompletedEventSchema$1, promptAbortedEventSchema$1, permissionApprovalRequestedEventSchema, permissionApprovalResolvedEventSchema, errorEventSchema$1, warningEventSchema$1, agentStatusUpdatedEventSchema$1, agentEvents;
222961
- var init_events$2 = __esmMin((() => {
224812
+ var init_events$3 = __esmMin((() => {
222962
224813
  init_zod$1();
222963
224814
  turnStartedEventSchema$1 = object({
222964
224815
  type: literal("turn.started"),
@@ -223592,9 +225443,9 @@ function createKlientFromChannel(channel, options = {}) {
223592
225443
  }
223593
225444
  var init_klient = __esmMin((() => {
223594
225445
  init_contract$1();
225446
+ init_events$5();
223595
225447
  init_events$4();
223596
225448
  init_events$3();
223597
- init_events$2();
223598
225449
  init_hub();
223599
225450
  init_global();
223600
225451
  init_session$2();
@@ -226020,7 +227871,7 @@ var init_src$4 = __esmMin((() => {
226020
227871
  init_errors$3();
226021
227872
  init_logging();
226022
227873
  init_src$6();
226023
- init_events$5();
227874
+ init_events$6();
226024
227875
  }));
226025
227876
  //#endregion
226026
227877
  //#region ../../packages/telemetry/src/index.ts
@@ -232272,7 +234123,7 @@ var init_schema$1 = __esmMin((() => {
232272
234123
  seq: transcriptSeqSchema.optional()
232273
234124
  });
232274
234125
  })), transcriptResetEventSchema, transcriptOpsEventSchema;
232275
- var init_events$1 = __esmMin((() => {
234126
+ var init_events$2 = __esmMin((() => {
232276
234127
  init_zod$1();
232277
234128
  init_schema$1();
232278
234129
  transcriptResetEventSchema = transcriptResetPayloadSchema.extend({ type: literal("transcript.reset") });
@@ -232303,7 +234154,7 @@ var init_src$2 = __esmMin((() => {
232303
234154
  init_groupTurns();
232304
234155
  init_foldFacts();
232305
234156
  init_schema$1();
232306
- init_events$1();
234157
+ init_events$2();
232307
234158
  }));
232308
234159
  //#endregion
232309
234160
  //#region ../../packages/agent-core-v2/src/agent/contextMemory/protocolMessage.ts
@@ -259106,7 +260957,7 @@ function isVolatileEventType(type) {
259106
260957
  return volatileEventTypeSet.has(type);
259107
260958
  }
259108
260959
  var VOLATILE_EVENT_TYPES, volatileEventTypeSet;
259109
- var init_events = __esmMin((() => {
260960
+ var init_events$1 = __esmMin((() => {
259110
260961
  VOLATILE_EVENT_TYPES = [
259111
260962
  "assistant.delta",
259112
260963
  "thinking.delta",
@@ -259344,11 +261195,11 @@ function registerApprovalsRoutes(app, core) {
259344
261195
  const listRoute = defineRoute({
259345
261196
  method: "GET",
259346
261197
  path: "/sessions/{session_id}/approvals",
259347
- params: sessionIdParamSchema$9,
261198
+ params: sessionIdParamSchema$10,
259348
261199
  querystring: listPendingApprovalsQuerySchema,
259349
261200
  success: { data: listPendingApprovalsResponseSchema },
259350
261201
  errors: {
259351
- [ErrorCode.VALIDATION_FAILED]: { detailsSchema: detailsSchema$7 },
261202
+ [ErrorCode.VALIDATION_FAILED]: { detailsSchema: detailsSchema$8 },
259352
261203
  [ErrorCode.SESSION_NOT_FOUND]: {}
259353
261204
  },
259354
261205
  description: "List pending approval requests for a session",
@@ -259371,7 +261222,7 @@ function registerApprovalsRoutes(app, core) {
259371
261222
  body: approvalResolveRequestSchema,
259372
261223
  success: { data: approvalResolveResultSchema },
259373
261224
  errors: {
259374
- [ErrorCode.VALIDATION_FAILED]: { detailsSchema: detailsSchema$7 },
261225
+ [ErrorCode.VALIDATION_FAILED]: { detailsSchema: detailsSchema$8 },
259375
261226
  [ErrorCode.SESSION_NOT_FOUND]: {},
259376
261227
  [ErrorCode.APPROVAL_NOT_FOUND]: {},
259377
261228
  [ErrorCode.APPROVAL_ALREADY_RESOLVED]: { dataSchema: approvalAlreadyResolvedDataSchema }
@@ -259434,7 +261285,7 @@ function toWireApproval(interaction, sessionId) {
259434
261285
  expires_at: new Date(interaction.createdAt + APPROVAL_EXPIRY_MS).toISOString()
259435
261286
  };
259436
261287
  }
259437
- var sessionIdParamSchema$9, approvalParamsSchema, detailsSchema$7, APPROVAL_EXPIRY_MS;
261288
+ var sessionIdParamSchema$10, approvalParamsSchema, detailsSchema$8, APPROVAL_EXPIRY_MS;
259438
261289
  var init_approvals = __esmMin((() => {
259439
261290
  init_src$6();
259440
261291
  init_error_codes();
@@ -259443,12 +261294,12 @@ var init_approvals = __esmMin((() => {
259443
261294
  init_envelope();
259444
261295
  init_requestLog();
259445
261296
  init_defineRoute();
259446
- sessionIdParamSchema$9 = object({ session_id: string$2().min(1) });
261297
+ sessionIdParamSchema$10 = object({ session_id: string$2().min(1) });
259447
261298
  approvalParamsSchema = object({
259448
261299
  session_id: string$2().min(1),
259449
261300
  approval_id: string$2().min(1)
259450
261301
  });
259451
- detailsSchema$7 = array$2(object({
261302
+ detailsSchema$8 = array$2(object({
259452
261303
  path: string$2(),
259453
261304
  message: string$2()
259454
261305
  }));
@@ -259507,11 +261358,11 @@ function registerQuestionsRoutes(app, core) {
259507
261358
  const listRoute = defineRoute({
259508
261359
  method: "GET",
259509
261360
  path: "/sessions/{session_id}/questions",
259510
- params: sessionIdParamSchema$8,
261361
+ params: sessionIdParamSchema$9,
259511
261362
  querystring: listPendingQuestionsQuerySchema,
259512
261363
  success: { data: listPendingQuestionsResponseSchema },
259513
261364
  errors: {
259514
- [ErrorCode.VALIDATION_FAILED]: { detailsSchema: detailsSchema$6 },
261365
+ [ErrorCode.VALIDATION_FAILED]: { detailsSchema: detailsSchema$7 },
259515
261366
  [ErrorCode.SESSION_NOT_FOUND]: {}
259516
261367
  },
259517
261368
  description: "List pending question requests for a session",
@@ -259533,7 +261384,7 @@ function registerQuestionsRoutes(app, core) {
259533
261384
  params: tailParamsSchema,
259534
261385
  success: { data: questionResolveResultSchema },
259535
261386
  errors: {
259536
- [ErrorCode.VALIDATION_FAILED]: { detailsSchema: detailsSchema$6 },
261387
+ [ErrorCode.VALIDATION_FAILED]: { detailsSchema: detailsSchema$7 },
259537
261388
  [ErrorCode.SESSION_NOT_FOUND]: {},
259538
261389
  [ErrorCode.QUESTION_NOT_FOUND]: {},
259539
261390
  [ErrorCode.APPROVAL_ALREADY_RESOLVED]: { dataSchema: questionAlreadyResolvedDataSchema },
@@ -259717,7 +261568,7 @@ function toInProcessResponse(resp, request) {
259717
261568
  if (resp.method !== void 0 && resp.method !== "click") out.method = resp.method;
259718
261569
  return out;
259719
261570
  }
259720
- var sessionIdParamSchema$8, tailParamsSchema, detailsSchema$6;
261571
+ var sessionIdParamSchema$9, tailParamsSchema, detailsSchema$7;
259721
261572
  var init_questions = __esmMin((() => {
259722
261573
  init_src$6();
259723
261574
  init_error_codes();
@@ -259728,12 +261579,12 @@ var init_questions = __esmMin((() => {
259728
261579
  init_requestLog();
259729
261580
  init_defineRoute();
259730
261581
  init_action_suffix();
259731
- sessionIdParamSchema$8 = object({ session_id: string$2().min(1) });
261582
+ sessionIdParamSchema$9 = object({ session_id: string$2().min(1) });
259732
261583
  tailParamsSchema = object({
259733
261584
  session_id: string$2().min(1),
259734
261585
  tail: string$2().min(1)
259735
261586
  });
259736
- detailsSchema$6 = array$2(object({
261587
+ detailsSchema$7 = array$2(object({
259737
261588
  path: string$2(),
259738
261589
  message: string$2()
259739
261590
  }));
@@ -260411,7 +262262,7 @@ function sessionCreatedPayload(payload) {
260411
262262
  var GLOBAL_SESSION_ID, TRANSCRIPT_RESET_TAIL_TURNS, SessionEventBroadcaster, volatileSignalTypeSet, TRANSCRIPT_PROJECTED_EVENT_TYPES;
260412
262263
  var init_sessionEventBroadcaster = __esmMin((() => {
260413
262264
  init_src$6();
260414
- init_events();
262265
+ init_events$1();
260415
262266
  init_src$2();
260416
262267
  init_approvals();
260417
262268
  init_questions();
@@ -264961,11 +266812,11 @@ function registerMessagesRoutes(app, core) {
264961
266812
  const listRoute = defineRoute({
264962
266813
  method: "GET",
264963
266814
  path: "/sessions/{session_id}/messages",
264964
- params: sessionIdParamSchema$7,
266815
+ params: sessionIdParamSchema$8,
264965
266816
  querystring: messagesListQueryCoercion,
264966
266817
  success: { data: listMessagesResponseSchema },
264967
266818
  errors: {
264968
- [ErrorCode.VALIDATION_FAILED]: { detailsSchema: detailsSchema$5 },
266819
+ [ErrorCode.VALIDATION_FAILED]: { detailsSchema: detailsSchema$6 },
264969
266820
  [ErrorCode.SESSION_NOT_FOUND]: {}
264970
266821
  },
264971
266822
  description: "List messages for a session",
@@ -264986,7 +266837,7 @@ function registerMessagesRoutes(app, core) {
264986
266837
  params: messageIdParamSchema,
264987
266838
  success: { data: getMessageResponseSchema },
264988
266839
  errors: {
264989
- [ErrorCode.VALIDATION_FAILED]: { detailsSchema: detailsSchema$5 },
266840
+ [ErrorCode.VALIDATION_FAILED]: { detailsSchema: detailsSchema$6 },
264990
266841
  [ErrorCode.SESSION_NOT_FOUND]: {},
264991
266842
  [ErrorCode.MESSAGE_NOT_FOUND]: {}
264992
266843
  },
@@ -265023,7 +266874,7 @@ function sendMappedError$7(reply, req, err) {
265023
266874
  log?.error({ err }, "message request failed");
265024
266875
  reply.send(errEnvelope(ErrorCode.INTERNAL_ERROR, err instanceof Error ? err.message : String(err), requestId, err instanceof Error ? err.stack : void 0));
265025
266876
  }
265026
- var messagesListQueryCoercion, sessionIdParamSchema$7, messageIdParamSchema, detailsSchema$5;
266877
+ var messagesListQueryCoercion, sessionIdParamSchema$8, messageIdParamSchema, detailsSchema$6;
265027
266878
  var init_messages = __esmMin((() => {
265028
266879
  init_src$6();
265029
266880
  init_protocolMessage();
@@ -265047,12 +266898,12 @@ var init_messages = __esmMin((() => {
265047
266898
  params: { code: ErrorCode.VALIDATION_FAILED }
265048
266899
  });
265049
266900
  });
265050
- sessionIdParamSchema$7 = object({ session_id: string$2().min(1) });
266901
+ sessionIdParamSchema$8 = object({ session_id: string$2().min(1) });
265051
266902
  messageIdParamSchema = object({
265052
266903
  session_id: string$2().min(1),
265053
266904
  message_id: string$2().min(1)
265054
266905
  });
265055
- detailsSchema$5 = array$2(object({
266906
+ detailsSchema$6 = array$2(object({
265056
266907
  path: string$2(),
265057
266908
  message: string$2()
265058
266909
  }));
@@ -265405,6 +267256,107 @@ var init_registerDebugRoutes = __esmMin((() => {
265405
267256
  init_serviceDispatcherRoutes();
265406
267257
  }));
265407
267258
  //#endregion
267259
+ //#region ../../packages/kap-server/src/routes/events.ts
267260
+ function registerEventsRoute(app, opts) {
267261
+ app.get("/sessions/:session_id/events", { schema: {
267262
+ params: {
267263
+ type: "object",
267264
+ properties: { session_id: { type: "string" } },
267265
+ required: ["session_id"]
267266
+ },
267267
+ querystring: {
267268
+ type: "object",
267269
+ properties: { event_seq: { type: "string" } },
267270
+ required: []
267271
+ }
267272
+ } }, async (req, reply) => {
267273
+ const { session_id } = req.params;
267274
+ if (!session_id) {
267275
+ await reply.code(400).send({
267276
+ code: 4e4,
267277
+ msg: "session_id required",
267278
+ data: null,
267279
+ request_id: req.id
267280
+ });
267281
+ return;
267282
+ }
267283
+ const eventSeq = parseEventSeq(req.query.event_seq);
267284
+ if (eventSeq !== void 0 && (!Number.isInteger(eventSeq) || eventSeq < 0)) {
267285
+ await reply.code(400).send({
267286
+ code: 4e4,
267287
+ msg: "event_seq must be a non-negative integer",
267288
+ data: null,
267289
+ request_id: req.id
267290
+ });
267291
+ return;
267292
+ }
267293
+ reply.hijack();
267294
+ const raw = reply.raw;
267295
+ raw.writeHead(200, SSE_HEADERS);
267296
+ raw.write(": connected\n\n");
267297
+ let closed = false;
267298
+ const target = { send(envelope) {
267299
+ if (closed) return;
267300
+ raw.write(`event: ${envelope.type}\ndata: ${JSON.stringify(envelope)}\n\n`);
267301
+ } };
267302
+ if (!await opts.broadcaster.subscribe(session_id, target)) {
267303
+ if (await opts.core.accessor.get(ISessionLifecycleService).resume(session_id) === void 0) {
267304
+ closed = true;
267305
+ raw.write("event: error\ndata: {\"code\":40401,\"msg\":\"session not found\"}\n\n");
267306
+ raw.end();
267307
+ return;
267308
+ }
267309
+ if (!await opts.broadcaster.subscribe(session_id, target)) {
267310
+ closed = true;
267311
+ raw.write("event: error\ndata: {\"code\":40401,\"msg\":\"session not found\"}\n\n");
267312
+ raw.end();
267313
+ return;
267314
+ }
267315
+ }
267316
+ if (eventSeq !== void 0) {
267317
+ const result = await opts.broadcaster.getBufferedSince(session_id, { seq: eventSeq });
267318
+ if (result.resyncRequired !== false) raw.write(`event: resync_required\ndata: ${JSON.stringify({
267319
+ type: "resync_required",
267320
+ session_id,
267321
+ reason: result.resyncRequired,
267322
+ current_seq: result.currentSeq,
267323
+ epoch: result.epoch
267324
+ })}\n\n`);
267325
+ else for (const { envelope } of result.events) target.send(envelope);
267326
+ }
267327
+ const heartbeat = setInterval(() => {
267328
+ if (!closed) raw.write(": ping\n\n");
267329
+ }, HEARTBEAT_INTERVAL_MS);
267330
+ req.raw.on("close", () => {
267331
+ closed = true;
267332
+ clearInterval(heartbeat);
267333
+ opts.broadcaster.unsubscribe(session_id, target);
267334
+ });
267335
+ });
267336
+ }
267337
+ /**
267338
+ * Parse the optional `?event_seq=` replay cursor. `undefined` = absent
267339
+ * (live-only stream); `NaN` = present but malformed — the caller rejects it
267340
+ * with a 400. A valid cursor is a non-negative integer (the journal seq
267341
+ * domain, matching `sessionCursorSchema.seq`).
267342
+ */
267343
+ function parseEventSeq(raw) {
267344
+ if (raw === void 0) return void 0;
267345
+ if (typeof raw !== "string" || !/^\d+$/.test(raw)) return NaN;
267346
+ return Number(raw);
267347
+ }
267348
+ var SSE_HEADERS, HEARTBEAT_INTERVAL_MS;
267349
+ var init_events = __esmMin((() => {
267350
+ init_src$6();
267351
+ SSE_HEADERS = {
267352
+ "Content-Type": "text/event-stream",
267353
+ "Cache-Control": "no-cache",
267354
+ Connection: "keep-alive",
267355
+ "X-Accel-Buffering": "no"
267356
+ };
267357
+ HEARTBEAT_INTERVAL_MS = 15e3;
267358
+ }));
267359
+ //#endregion
265408
267360
  //#region ../../packages/kap-server/src/protocol/rest-meta.ts
265409
267361
  var metaCapabilitiesSchema, metaResponseSchema;
265410
267362
  var init_rest_meta = __esmMin((() => {
@@ -266010,7 +267962,7 @@ function registerPromptsRoutes(app, core) {
266010
267962
  const listRoute = defineRoute({
266011
267963
  method: "GET",
266012
267964
  path: "/sessions/{session_id}/prompts",
266013
- params: sessionIdParamSchema$6,
267965
+ params: sessionIdParamSchema$7,
266014
267966
  success: { data: promptListResponseSchema },
266015
267967
  errors: { [ErrorCode.SESSION_NOT_FOUND]: {} },
266016
267968
  description: "List the active prompt and queued prompts for a session",
@@ -266030,7 +267982,7 @@ function registerPromptsRoutes(app, core) {
266030
267982
  method: "POST",
266031
267983
  path: "/sessions/{session_id}/prompts",
266032
267984
  body: promptSubmissionSchema,
266033
- params: sessionIdParamSchema$6,
267985
+ params: sessionIdParamSchema$7,
266034
267986
  success: { data: promptSubmitResultSchema },
266035
267987
  errors: {
266036
267988
  [ErrorCode.VALIDATION_FAILED]: { detailsSchema: validationDetailsSchema },
@@ -266096,7 +268048,7 @@ function registerPromptsRoutes(app, core) {
266096
268048
  method: "POST",
266097
268049
  path: "/sessions/{session_id}/prompts::steer",
266098
268050
  body: promptSteerRequestSchema,
266099
- params: sessionIdParamSchema$6,
268051
+ params: sessionIdParamSchema$7,
266100
268052
  success: { data: promptSteerResultSchema },
266101
268053
  errors: {
266102
268054
  [ErrorCode.VALIDATION_FAILED]: {},
@@ -266588,7 +268540,7 @@ function authModelDetails(err) {
266588
268540
  if (typeof providerId === "string") details.provider_id = providerId;
266589
268541
  return Object.keys(details).length === 0 ? null : details;
266590
268542
  }
266591
- var sessionIdParamSchema$6, validationDetailsSchema, authProviderDetailsSchema, authModelDetailsSchema, VIDEO_EXT_BY_MIME, ATTACHMENT_NAME_MAX;
268543
+ var sessionIdParamSchema$7, validationDetailsSchema, authProviderDetailsSchema, authModelDetailsSchema, VIDEO_EXT_BY_MIME, ATTACHMENT_NAME_MAX;
266592
268544
  var init_prompts$1 = __esmMin((() => {
266593
268545
  init_src$6();
266594
268546
  init_error_codes();
@@ -266599,7 +268551,7 @@ var init_prompts$1 = __esmMin((() => {
266599
268551
  init_defineRoute();
266600
268552
  init_mainAgent();
266601
268553
  init_action_suffix();
266602
- sessionIdParamSchema$6 = object({ session_id: string$2().min(1) });
268554
+ sessionIdParamSchema$7 = object({ session_id: string$2().min(1) });
266603
268555
  validationDetailsSchema = array$2(object({
266604
268556
  path: string$2(),
266605
268557
  message: string$2()
@@ -266881,7 +268833,7 @@ function registerSessionsRoutes(app, core) {
266881
268833
  body: createSessionRequestSchema,
266882
268834
  success: { data: sessionSchema },
266883
268835
  errors: {
266884
- [ErrorCode.VALIDATION_FAILED]: { detailsSchema: detailsSchema$4 },
268836
+ [ErrorCode.VALIDATION_FAILED]: { detailsSchema: detailsSchema$5 },
266885
268837
  [ErrorCode.WORKSPACE_NOT_FOUND]: {},
266886
268838
  [ErrorCode.FS_PATH_NOT_FOUND]: {}
266887
268839
  },
@@ -266919,6 +268871,7 @@ function registerSessionsRoutes(app, core) {
266919
268871
  const touched = await registry.createOrTouch(workDir);
266920
268872
  const handle = await core.accessor.get(ISessionLifecycleService).create({ workDir });
266921
268873
  if (typeof body.title === "string") await handle.accessor.get(ISessionMetadata).setTitle(body.title);
268874
+ if (body.metadata !== void 0 && Object.keys(body.metadata).length > 0) await handle.accessor.get(ISessionMetadata).update({ custom: { ...body.metadata } });
266922
268875
  const session = toWireSession({
266923
268876
  ...await handle.accessor.get(ISessionMetadata).read(),
266924
268877
  workspaceId: touched.id
@@ -266947,7 +268900,7 @@ function registerSessionsRoutes(app, core) {
266947
268900
  querystring: sessionsListQueryCoercion,
266948
268901
  success: { data: pageResponseSchema(sessionSchema) },
266949
268902
  errors: {
266950
- [ErrorCode.VALIDATION_FAILED]: { detailsSchema: detailsSchema$4 },
268903
+ [ErrorCode.VALIDATION_FAILED]: { detailsSchema: detailsSchema$5 },
266951
268904
  [ErrorCode.WORKSPACE_NOT_FOUND]: {}
266952
268905
  },
266953
268906
  description: "List sessions",
@@ -267015,10 +268968,10 @@ function registerSessionsRoutes(app, core) {
267015
268968
  const getRoute = defineRoute({
267016
268969
  method: "GET",
267017
268970
  path: "/sessions/{session_id}",
267018
- params: sessionIdParamSchema$5,
268971
+ params: sessionIdParamSchema$6,
267019
268972
  success: { data: sessionSchema },
267020
268973
  errors: {
267021
- [ErrorCode.VALIDATION_FAILED]: { detailsSchema: detailsSchema$4 },
268974
+ [ErrorCode.VALIDATION_FAILED]: { detailsSchema: detailsSchema$5 },
267022
268975
  [ErrorCode.SESSION_NOT_FOUND]: {}
267023
268976
  },
267024
268977
  description: "Get a session by ID",
@@ -267041,10 +268994,10 @@ function registerSessionsRoutes(app, core) {
267041
268994
  const getProfileRoute = defineRoute({
267042
268995
  method: "GET",
267043
268996
  path: "/sessions/{session_id}/profile",
267044
- params: sessionIdParamSchema$5,
268997
+ params: sessionIdParamSchema$6,
267045
268998
  success: { data: sessionSchema },
267046
268999
  errors: {
267047
- [ErrorCode.VALIDATION_FAILED]: { detailsSchema: detailsSchema$4 },
269000
+ [ErrorCode.VALIDATION_FAILED]: { detailsSchema: detailsSchema$5 },
267048
269001
  [ErrorCode.SESSION_NOT_FOUND]: {}
267049
269002
  },
267050
269003
  description: "Get session profile",
@@ -267067,11 +269020,11 @@ function registerSessionsRoutes(app, core) {
267067
269020
  const updateProfileRoute = defineRoute({
267068
269021
  method: "POST",
267069
269022
  path: "/sessions/{session_id}/profile",
267070
- params: sessionIdParamSchema$5,
269023
+ params: sessionIdParamSchema$6,
267071
269024
  body: updateSessionProfileRequestSchema,
267072
269025
  success: { data: sessionSchema },
267073
269026
  errors: {
267074
- [ErrorCode.VALIDATION_FAILED]: { detailsSchema: detailsSchema$4 },
269027
+ [ErrorCode.VALIDATION_FAILED]: { detailsSchema: detailsSchema$5 },
267075
269028
  [ErrorCode.SESSION_NOT_FOUND]: {}
267076
269029
  },
267077
269030
  description: "Update session profile (title, metadata, agent_config)",
@@ -267113,7 +269066,7 @@ function registerSessionsRoutes(app, core) {
267113
269066
  archiveSessionResponseSchema
267114
269067
  ]) },
267115
269068
  errors: {
267116
- [ErrorCode.VALIDATION_FAILED]: { detailsSchema: detailsSchema$4 },
269069
+ [ErrorCode.VALIDATION_FAILED]: { detailsSchema: detailsSchema$5 },
267117
269070
  [ErrorCode.SESSION_NOT_FOUND]: {},
267118
269071
  [ErrorCode.SESSION_BUSY]: {},
267119
269072
  [ErrorCode.COMPACTION_UNABLE]: {},
@@ -267252,11 +269205,11 @@ function registerSessionsRoutes(app, core) {
267252
269205
  const listChildrenRoute = defineRoute({
267253
269206
  method: "GET",
267254
269207
  path: "/sessions/{session_id}/children",
267255
- params: sessionIdParamSchema$5,
269208
+ params: sessionIdParamSchema$6,
267256
269209
  querystring: sessionChildrenListQueryCoercion,
267257
269210
  success: { data: listSessionChildrenResponseSchema },
267258
269211
  errors: {
267259
- [ErrorCode.VALIDATION_FAILED]: { detailsSchema: detailsSchema$4 },
269212
+ [ErrorCode.VALIDATION_FAILED]: { detailsSchema: detailsSchema$5 },
267260
269213
  [ErrorCode.SESSION_NOT_FOUND]: {}
267261
269214
  },
267262
269215
  description: "List child sessions",
@@ -267290,11 +269243,11 @@ function registerSessionsRoutes(app, core) {
267290
269243
  const createChildRoute = defineRoute({
267291
269244
  method: "POST",
267292
269245
  path: "/sessions/{session_id}/children",
267293
- params: sessionIdParamSchema$5,
269246
+ params: sessionIdParamSchema$6,
267294
269247
  body: createSessionChildRequestSchema,
267295
269248
  success: { data: sessionSchema },
267296
269249
  errors: {
267297
- [ErrorCode.VALIDATION_FAILED]: { detailsSchema: detailsSchema$4 },
269250
+ [ErrorCode.VALIDATION_FAILED]: { detailsSchema: detailsSchema$5 },
267298
269251
  [ErrorCode.SESSION_NOT_FOUND]: {},
267299
269252
  [ErrorCode.SESSION_BUSY]: {}
267300
269253
  },
@@ -267331,10 +269284,10 @@ function registerSessionsRoutes(app, core) {
267331
269284
  const statusRoute = defineRoute({
267332
269285
  method: "GET",
267333
269286
  path: "/sessions/{session_id}/status",
267334
- params: sessionIdParamSchema$5,
269287
+ params: sessionIdParamSchema$6,
267335
269288
  success: { data: sessionStatusResponseSchema },
267336
269289
  errors: {
267337
- [ErrorCode.VALIDATION_FAILED]: { detailsSchema: detailsSchema$4 },
269290
+ [ErrorCode.VALIDATION_FAILED]: { detailsSchema: detailsSchema$5 },
267338
269291
  [ErrorCode.SESSION_NOT_FOUND]: {}
267339
269292
  },
267340
269293
  description: "Get realtime session status (best-effort in this slice)",
@@ -267352,10 +269305,10 @@ function registerSessionsRoutes(app, core) {
267352
269305
  const sessionWarningsRoute = defineRoute({
267353
269306
  method: "GET",
267354
269307
  path: "/sessions/{session_id}/warnings",
267355
- params: sessionIdParamSchema$5,
269308
+ params: sessionIdParamSchema$6,
267356
269309
  success: { data: sessionWarningsResponseSchema },
267357
269310
  errors: {
267358
- [ErrorCode.VALIDATION_FAILED]: { detailsSchema: detailsSchema$4 },
269311
+ [ErrorCode.VALIDATION_FAILED]: { detailsSchema: detailsSchema$5 },
267359
269312
  [ErrorCode.SESSION_NOT_FOUND]: {}
267360
269313
  },
267361
269314
  description: "Get session-level warnings (e.g. oversized AGENTS.md)",
@@ -267511,7 +269464,7 @@ function sendMappedError$4(reply, req, err) {
267511
269464
  log?.error({ err }, "session request failed");
267512
269465
  reply.send(errEnvelope(ErrorCode.INTERNAL_ERROR, err instanceof Error ? err.message : String(err), requestId, err instanceof Error ? err.stack : void 0));
267513
269466
  }
267514
- var booleanQueryParam, DEFAULT_SESSION_LIST_PAGE_SIZE, sessionsListQueryCoercion, sessionIdParamSchema$5, sessionChildrenListQueryCoercion, sessionActionTailParamSchema, sessionActionRequestSchema, detailsSchema$4, DEFAULT_UNDO_MESSAGE_PAGE_SIZE, MAX_UNDO_MESSAGE_PAGE_SIZE;
269467
+ var booleanQueryParam, DEFAULT_SESSION_LIST_PAGE_SIZE, sessionsListQueryCoercion, sessionIdParamSchema$6, sessionChildrenListQueryCoercion, sessionActionTailParamSchema, sessionActionRequestSchema, detailsSchema$5, DEFAULT_UNDO_MESSAGE_PAGE_SIZE, MAX_UNDO_MESSAGE_PAGE_SIZE;
267515
269468
  var init_sessions = __esmMin((() => {
267516
269469
  init_src$6();
267517
269470
  init_error_codes();
@@ -267555,7 +269508,7 @@ var init_sessions = __esmMin((() => {
267555
269508
  params: { code: ErrorCode.VALIDATION_FAILED }
267556
269509
  });
267557
269510
  });
267558
- sessionIdParamSchema$5 = object({ session_id: string$2().min(1) });
269511
+ sessionIdParamSchema$6 = object({ session_id: string$2().min(1) });
267559
269512
  sessionChildrenListQueryCoercion = object({
267560
269513
  before_id: string$2().min(1).optional(),
267561
269514
  after_id: string$2().min(1).optional(),
@@ -267577,7 +269530,7 @@ var init_sessions = __esmMin((() => {
267577
269530
  count: number$2().int().positive().optional(),
267578
269531
  page_size: number$2().int().min(1).max(100).optional()
267579
269532
  }));
267580
- detailsSchema$4 = array$2(object({
269533
+ detailsSchema$5 = array$2(object({
267581
269534
  path: string$2(),
267582
269535
  message: string$2()
267583
269536
  }));
@@ -267585,6 +269538,60 @@ var init_sessions = __esmMin((() => {
267585
269538
  MAX_UNDO_MESSAGE_PAGE_SIZE = 100;
267586
269539
  }));
267587
269540
  //#endregion
269541
+ //#region ../../packages/kap-server/src/routes/shell.ts
269542
+ function registerShellRoute(app, core) {
269543
+ const runShellCommandRoute = defineRoute({
269544
+ method: "POST",
269545
+ path: "/sessions/{session_id}/shell",
269546
+ params: sessionIdParamSchema$5,
269547
+ body: shellCommandRequestSchema,
269548
+ success: { data: shellCommandResultSchema },
269549
+ errors: {
269550
+ [ErrorCode.VALIDATION_FAILED]: { detailsSchema: detailsSchema$4 },
269551
+ [ErrorCode.SESSION_NOT_FOUND]: {}
269552
+ },
269553
+ description: "Run a user-initiated `!` shell command in a session",
269554
+ tags: ["sessions"]
269555
+ }, async (req, reply) => {
269556
+ const { session_id } = req.params;
269557
+ const session = await core.accessor.get(ISessionLifecycleService).resume(session_id);
269558
+ if (session === void 0) {
269559
+ reply.send(errEnvelope(ErrorCode.SESSION_NOT_FOUND, `session ${session_id} does not exist`, req.id));
269560
+ return;
269561
+ }
269562
+ const result = await (await ensureMainAgent(session)).accessor.get(IAgentShellCommandService).run({
269563
+ command: req.body.command,
269564
+ commandId: req.body.commandId
269565
+ });
269566
+ reply.send(okEnvelope(result, req.id));
269567
+ });
269568
+ app.post(runShellCommandRoute.path, runShellCommandRoute.options, runShellCommandRoute.handler);
269569
+ }
269570
+ var sessionIdParamSchema$5, shellCommandRequestSchema, shellCommandResultSchema, detailsSchema$4;
269571
+ var init_shell = __esmMin((() => {
269572
+ init_src$6();
269573
+ init_zod$1();
269574
+ init_envelope();
269575
+ init_defineRoute();
269576
+ init_error_codes();
269577
+ init_mainAgent();
269578
+ sessionIdParamSchema$5 = object({ session_id: string$2().min(1) });
269579
+ shellCommandRequestSchema = object({
269580
+ command: string$2(),
269581
+ commandId: string$2().optional()
269582
+ });
269583
+ shellCommandResultSchema = object({
269584
+ stdout: string$2(),
269585
+ stderr: string$2(),
269586
+ isError: boolean$2().optional(),
269587
+ backgrounded: boolean$2().optional()
269588
+ });
269589
+ detailsSchema$4 = array$2(object({
269590
+ path: string$2(),
269591
+ message: string$2()
269592
+ }));
269593
+ }));
269594
+ //#endregion
267588
269595
  //#region ../../packages/kap-server/src/routes/shutdown.ts
267589
269596
  function registerShutdownRoutes(app, opts) {
267590
269597
  const route = defineRoute({
@@ -269820,6 +271827,11 @@ async function registerApiV1Routes(app, core, opts) {
269820
271827
  registerConfigRoutes(apiV1, core);
269821
271828
  registerModelCatalogRoutes(apiV1, core);
269822
271829
  registerSessionsRoutes(apiV1, core);
271830
+ registerShellRoute(apiV1, core);
271831
+ registerEventsRoute(apiV1, {
271832
+ broadcaster: opts.broadcaster,
271833
+ core
271834
+ });
269823
271835
  registerSessionExportRoute(apiV1, core, { serverVersion: opts.serverVersion });
269824
271836
  registerSkillsRoutes(apiV1, core);
269825
271837
  registerMessagesRoutes(apiV1, core);
@@ -269878,6 +271890,7 @@ var init_registerApiV1Routes = __esmMin((() => {
269878
271890
  init_guiStore();
269879
271891
  init_messages();
269880
271892
  init_registerDebugRoutes();
271893
+ init_events();
269881
271894
  init_meta();
269882
271895
  init_modelCatalog();
269883
271896
  init_oauth();
@@ -269885,6 +271898,7 @@ var init_registerApiV1Routes = __esmMin((() => {
269885
271898
  init_questions();
269886
271899
  init_sessionExport();
269887
271900
  init_sessions();
271901
+ init_shell();
269888
271902
  init_shutdown();
269889
271903
  init_snapshot();
269890
271904
  init_skills$1();
@@ -273846,7 +275860,9 @@ var DEFAULT_MAX_BUFFER_SIZE, DEFAULT_FLUSH_INTERVAL_MS, DEFAULT_MAX_BATCH_SIZE,
273846
275860
  var init_wsConnectionV1 = __esmMin((() => {
273847
275861
  init_ws_control();
273848
275862
  init_src$2();
275863
+ init_src$6();
273849
275864
  init_node$3();
275865
+ init_error_codes();
273850
275866
  init_protocol();
273851
275867
  init_sessionEventBroadcaster();
273852
275868
  init_fsWatchBridge();
@@ -273864,6 +275880,7 @@ var init_wsConnectionV1 = __esmMin((() => {
273864
275880
  socket;
273865
275881
  broadcaster;
273866
275882
  fsWatchBridge;
275883
+ core;
273867
275884
  validateCredential;
273868
275885
  maxBufferSize;
273869
275886
  flushIntervalMs;
@@ -273875,6 +275892,12 @@ var init_wsConnectionV1 = __esmMin((() => {
273875
275892
  /** Per-session subscription state: legacy agent allowlist + opt-in transcript grades. */
273876
275893
  subscriptions = /* @__PURE__ */ new Map();
273877
275894
  /**
275895
+ * Terminal services this connection has attached to (one per session,
275896
+ * resolved lazily). Tracked so teardown can detach every terminal sink
275897
+ * the connection owns.
275898
+ */
275899
+ terminalServices = /* @__PURE__ */ new Set();
275900
+ /**
273878
275901
  * Serializes control-frame handling in receive order. Frames arrive
273879
275902
  * back-to-back (e.g. `client_hello` immediately followed by
273880
275903
  * `subscribe_v2`), and a later handler reads subscription state the
@@ -273896,6 +275919,7 @@ var init_wsConnectionV1 = __esmMin((() => {
273896
275919
  this.socket = opts.socket;
273897
275920
  this.broadcaster = opts.broadcaster;
273898
275921
  this.fsWatchBridge = opts.fsWatchBridge;
275922
+ this.core = opts.core;
273899
275923
  this.validateCredential = opts.validateCredential;
273900
275924
  this.logger = opts.logger;
273901
275925
  this.maxBufferSize = opts.maxBufferSize ?? DEFAULT_MAX_BUFFER_SIZE;
@@ -273959,6 +275983,21 @@ var init_wsConnectionV1 = __esmMin((() => {
273959
275983
  case "watch_fs_remove":
273960
275984
  this.enqueueControl(() => this.onWatchFs(frame, false));
273961
275985
  return;
275986
+ case "terminal_attach":
275987
+ this.enqueueControl(() => this.onTerminalAttach(frame));
275988
+ return;
275989
+ case "terminal_input":
275990
+ this.enqueueControl(() => this.onTerminalInput(frame));
275991
+ return;
275992
+ case "terminal_resize":
275993
+ this.enqueueControl(() => this.onTerminalResize(frame));
275994
+ return;
275995
+ case "terminal_close":
275996
+ this.enqueueControl(() => this.onTerminalClose(frame));
275997
+ return;
275998
+ case "terminal_detach":
275999
+ this.enqueueControl(() => this.onTerminalDetach(frame));
276000
+ return;
273962
276001
  default: return;
273963
276002
  }
273964
276003
  }
@@ -274104,6 +276143,120 @@ var init_wsConnectionV1 = __esmMin((() => {
274104
276143
  }));
274105
276144
  }
274106
276145
  /**
276146
+ * `terminal_attach` — attach this connection's sink to a session terminal
276147
+ * stream. The sink's frames (`terminal_output` / `terminal_exit`) are
276148
+ * delivered over the same subscription buffer as session events (coalesced
276149
+ * only when mergeable — terminal frames never merge, they just share the
276150
+ * flush window). `since_seq` replays buffered frames past the cursor, like
276151
+ * the REST/WS attach contract.
276152
+ */
276153
+ async onTerminalAttach(frame) {
276154
+ const parsed = terminalAttachMessageSchema.safeParse(frame);
276155
+ if (!parsed.success) {
276156
+ this.sendImmediateFrame(buildAck(frame.id ?? "", 1, "invalid terminal_attach payload", {}));
276157
+ return;
276158
+ }
276159
+ const { session_id, terminal_id, since_seq } = parsed.data.payload;
276160
+ try {
276161
+ const terminals = await this.resolveTerminalService(session_id);
276162
+ const sink = {
276163
+ id: this.id,
276164
+ send: (terminalFrame) => this.sendSubscribedFrame(terminalFrame)
276165
+ };
276166
+ const { replayed } = await terminals.attach(terminal_id, sink, { sinceSeq: since_seq });
276167
+ this.sendImmediateFrame(buildAck(frame.id ?? "", 0, "success", {
276168
+ attached: true,
276169
+ replayed
276170
+ }));
276171
+ } catch (error) {
276172
+ this.sendTerminalErrorAck(frame.id, error);
276173
+ }
276174
+ }
276175
+ /** `terminal_input` — write bytes to the attached terminal's pty. */
276176
+ async onTerminalInput(frame) {
276177
+ const parsed = terminalInputMessageSchema.safeParse(frame);
276178
+ if (!parsed.success) {
276179
+ this.sendImmediateFrame(buildAck(frame.id ?? "", 1, "invalid terminal_input payload", {}));
276180
+ return;
276181
+ }
276182
+ const { session_id, terminal_id, data } = parsed.data.payload;
276183
+ try {
276184
+ await (await this.resolveTerminalService(session_id)).write(terminal_id, data);
276185
+ this.sendImmediateFrame(buildAck(frame.id ?? "", 0, "success", { accepted: true }));
276186
+ } catch (error) {
276187
+ this.sendTerminalErrorAck(frame.id, error);
276188
+ }
276189
+ }
276190
+ /** `terminal_resize` — resize the attached terminal's pty. */
276191
+ async onTerminalResize(frame) {
276192
+ const parsed = terminalResizeMessageSchema.safeParse(frame);
276193
+ if (!parsed.success) {
276194
+ this.sendImmediateFrame(buildAck(frame.id ?? "", 1, "invalid terminal_resize payload", {}));
276195
+ return;
276196
+ }
276197
+ const { session_id, terminal_id, cols, rows } = parsed.data.payload;
276198
+ try {
276199
+ await (await this.resolveTerminalService(session_id)).resize(terminal_id, cols, rows);
276200
+ this.sendImmediateFrame(buildAck(frame.id ?? "", 0, "success", { resized: true }));
276201
+ } catch (error) {
276202
+ this.sendTerminalErrorAck(frame.id, error);
276203
+ }
276204
+ }
276205
+ /** `terminal_close` — close the terminal's pty (idempotent). */
276206
+ async onTerminalClose(frame) {
276207
+ const parsed = terminalCloseMessageSchema.safeParse(frame);
276208
+ if (!parsed.success) {
276209
+ this.sendImmediateFrame(buildAck(frame.id ?? "", 1, "invalid terminal_close payload", {}));
276210
+ return;
276211
+ }
276212
+ const { session_id, terminal_id } = parsed.data.payload;
276213
+ try {
276214
+ await (await this.resolveTerminalService(session_id)).close(terminal_id);
276215
+ this.sendImmediateFrame(buildAck(frame.id ?? "", 0, "success", { closed: true }));
276216
+ } catch (error) {
276217
+ this.sendTerminalErrorAck(frame.id, error);
276218
+ }
276219
+ }
276220
+ /** `terminal_detach` — detach this connection's sink from a terminal stream. */
276221
+ async onTerminalDetach(frame) {
276222
+ const parsed = terminalDetachMessageSchema.safeParse(frame);
276223
+ if (!parsed.success) {
276224
+ this.sendImmediateFrame(buildAck(frame.id ?? "", 1, "invalid terminal_detach payload", {}));
276225
+ return;
276226
+ }
276227
+ const { session_id, terminal_id } = parsed.data.payload;
276228
+ try {
276229
+ (await this.resolveTerminalService(session_id)).detach(terminal_id, this.id);
276230
+ this.sendImmediateFrame(buildAck(frame.id ?? "", 0, "success", { detached: true }));
276231
+ } catch (error) {
276232
+ this.sendTerminalErrorAck(frame.id, error);
276233
+ }
276234
+ }
276235
+ /**
276236
+ * Resolve a session's `ISessionTerminalService` (cold-loading a
276237
+ * persisted-but-not-live session, matching the REST terminal route).
276238
+ * The resolved service is remembered so `onClose` can detach every sink
276239
+ * this connection owns.
276240
+ */
276241
+ async resolveTerminalService(sessionId) {
276242
+ const session = await this.core.accessor.get(ISessionLifecycleService).resume(sessionId);
276243
+ if (session === void 0) throw new Error2(ErrorCodes.SESSION_NOT_FOUND, `session ${sessionId} does not exist`);
276244
+ const terminals = session.accessor.get(ISessionTerminalService);
276245
+ this.terminalServices.add(terminals);
276246
+ return terminals;
276247
+ }
276248
+ /** Ack a terminal control failure with the wire error code when known. */
276249
+ sendTerminalErrorAck(id, error) {
276250
+ let code = 1;
276251
+ let msg = "internal error";
276252
+ if (isError2(error)) {
276253
+ if (error.code === ErrorCodes.SESSION_NOT_FOUND) code = ErrorCode.SESSION_NOT_FOUND;
276254
+ else if (error.code === ErrorCodes.TERMINAL_NOT_FOUND) code = ErrorCode.TERMINAL_NOT_FOUND;
276255
+ msg = error.message;
276256
+ } else if (error instanceof Error) msg = error.message;
276257
+ this.sendImmediateFrame(buildAck(id ?? "", code, msg, {}));
276258
+ }
276259
+ /**
274107
276260
  * Shared attach path behind `client_hello` (legacy inline subscriptions)
274108
276261
  * and `subscribe`. Subscribes the connection via the broadcaster, then
274109
276262
  * either replays durable events since the client's cursor (with the
@@ -274248,6 +276401,7 @@ var init_wsConnectionV1 = __esmMin((() => {
274248
276401
  this.outbound = [];
274249
276402
  this.broadcaster.removeGlobalTarget(this);
274250
276403
  for (const sid of this.subscriptions.keys()) this.broadcaster.unsubscribe(sid, this);
276404
+ for (const terminals of this.terminalServices) terminals.detachAllForSink(this.id);
274251
276405
  this.fsWatchBridge?.detachConnection(this);
274252
276406
  }
274253
276407
  };
@@ -274266,6 +276420,7 @@ function registerWsV1(core, opts) {
274266
276420
  broadcaster,
274267
276421
  fsWatchBridge: opts.fsWatchBridge,
274268
276422
  connectionRegistry: registry,
276423
+ core,
274269
276424
  validateCredential: opts.validateCredential,
274270
276425
  remoteAddress: req.socket.remoteAddress ?? null,
274271
276426
  userAgent: req.headers["user-agent"] ?? null,
@@ -296567,6 +298722,15 @@ function stringifyToolOutput(output) {
296567
298722
  if (typeof output === "string") return output;
296568
298723
  return JSON.stringify(output) ?? String(output);
296569
298724
  }
298725
+ function stringifyToolArgs(args) {
298726
+ if (typeof args === "string") return args;
298727
+ return JSON.stringify(args) ?? String(args);
298728
+ }
298729
+ function truncateChars(text, max) {
298730
+ if (text.length <= max) return text;
298731
+ const suffix = `… (${text.length - max} more chars)`;
298732
+ return `${text.slice(0, max - suffix.length)}${suffix}`;
298733
+ }
296570
298734
  function writeVersion(version, outputFormat, stdout, stderr) {
296571
298735
  if (outputFormat === "stream-json") {
296572
298736
  const message = {
@@ -296595,16 +298759,23 @@ function writeResumeHint(sessionId, outputFormat, stdout, stderr) {
296595
298759
  }
296596
298760
  stderr.write(`${content}\n`);
296597
298761
  }
296598
- var PROMPT_BLOCK_BULLET, PROMPT_BLOCK_INDENT, PromptTranscriptWriter, PromptJsonWriter, PromptBlockWriter;
298762
+ var PROMPT_BLOCK_BULLET, PROMPT_BLOCK_INDENT, TOOL_CALL_MARK, TOOL_RESULT_MARK, RETRY_MARK, MAX_TOOL_CALL_ARGS_CHARS, MAX_TOOL_RESULT_CHARS, PromptTranscriptWriter, PromptJsonWriter, PromptBlockWriter;
296599
298763
  var init_prompt_render = __esmMin((() => {
296600
298764
  PROMPT_BLOCK_BULLET = "• ";
296601
298765
  PROMPT_BLOCK_INDENT = " ";
298766
+ TOOL_CALL_MARK = "⚒ ";
298767
+ TOOL_RESULT_MARK = "⚒ result: ";
298768
+ RETRY_MARK = "↻ retry";
298769
+ MAX_TOOL_CALL_ARGS_CHARS = 500;
298770
+ MAX_TOOL_RESULT_CHARS = 2e3;
296602
298771
  PromptTranscriptWriter = class {
296603
298772
  assistantWriter;
296604
298773
  thinkingWriter;
298774
+ toolWriter;
296605
298775
  constructor(stdout, stderr) {
296606
298776
  this.assistantWriter = new PromptBlockWriter(stdout);
296607
298777
  this.thinkingWriter = new PromptBlockWriter(stderr);
298778
+ this.toolWriter = new PromptBlockWriter(stderr);
296608
298779
  }
296609
298780
  writeAssistantDelta(delta) {
296610
298781
  this.thinkingWriter.finish();
@@ -296619,10 +298790,25 @@ var init_prompt_render = __esmMin((() => {
296619
298790
  writeThinkingDelta(delta) {
296620
298791
  this.thinkingWriter.write(delta);
296621
298792
  }
296622
- writeToolCall() {}
298793
+ writeToolCall(toolCallId, name, args) {
298794
+ this.thinkingWriter.finish();
298795
+ this.assistantWriter.finish();
298796
+ this.toolWriter.write(`${TOOL_CALL_MARK}${name}(${truncateChars(stringifyToolArgs(args), MAX_TOOL_CALL_ARGS_CHARS)})`);
298797
+ this.toolWriter.finish();
298798
+ }
296623
298799
  writeToolCallDelta() {}
296624
- writeToolResult() {}
296625
- writeRetrying() {}
298800
+ writeToolResult(toolCallId, output) {
298801
+ this.toolWriter.finish();
298802
+ this.toolWriter.write(`${TOOL_RESULT_MARK}${truncateChars(stringifyToolOutput(output), MAX_TOOL_RESULT_CHARS)}`);
298803
+ this.toolWriter.finish();
298804
+ }
298805
+ writeRetrying(event) {
298806
+ this.thinkingWriter.finish();
298807
+ this.assistantWriter.finish();
298808
+ const error = [event.errorName, event.errorMessage].filter(Boolean).join(": ");
298809
+ this.toolWriter.write(`${RETRY_MARK} ${event.failedAttempt}/${event.maxAttempts} (${error}) — ${event.delayMs}ms`);
298810
+ this.toolWriter.finish();
298811
+ }
296626
298812
  flushAssistant() {
296627
298813
  this.assistantWriter.finish();
296628
298814
  }
@@ -296630,6 +298816,7 @@ var init_prompt_render = __esmMin((() => {
296630
298816
  finish() {
296631
298817
  this.thinkingWriter.finish();
296632
298818
  this.assistantWriter.finish();
298819
+ this.toolWriter.finish();
296633
298820
  }
296634
298821
  };
296635
298822
  PromptJsonWriter = class {