@themoltnet/pi-extension 0.32.0 → 0.32.1

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/index.js +272 -140
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -1965,7 +1965,7 @@ var findLatestRuntimeSlotForAttempt = (options) => (options.client ?? client).ge
1965
1965
  ...options
1966
1966
  });
1967
1967
  /**
1968
- * Delete terminal tasks in bulk. Safe mode skips live, unauthorized, missing, and protected tasks.
1968
+ * Queue asynchronous deletion of terminal tasks in bulk. By default, live, unauthorized, missing, and protected tasks are skipped. Set force: true with a reason to delete protected terminal tasks.
1969
1969
  */
1970
1970
  var batchDeleteTasks = (options) => (options.client ?? client).delete({
1971
1971
  security: [
@@ -26409,14 +26409,10 @@ async function executePiTask(claimedTask, reporter, opts) {
26409
26409
  });
26410
26410
  return makeFailedOutput("session_setup_failed", message);
26411
26411
  }
26412
- let llmAbort = false;
26413
- let llmErrorMessage = null;
26414
- let assistantText = "";
26412
+ const turnState = createSessionTurnState();
26415
26413
  let reporterError = null;
26416
26414
  const usage = finalUsage;
26417
26415
  let capAbort = null;
26418
- let toolUseTurnCount = 0;
26419
- let bashTimeoutCount = 0;
26420
26416
  const maxTurns = opts.maxTurns ?? 0;
26421
26417
  const maxBashTimeouts = opts.maxBashTimeouts ?? 3;
26422
26418
  cancelListener = wireSessionAbort(reporter.cancelSignal, session);
@@ -26451,49 +26447,16 @@ async function executePiTask(claimedTask, reporter, opts) {
26451
26447
  message
26452
26448
  }));
26453
26449
  };
26454
- session.subscribe((event) => {
26455
- if (event.type === "message_update") {
26456
- const ae = event.assistantMessageEvent;
26457
- if (ae.type === "text_delta") {
26458
- assistantText += ae.delta;
26459
- track(emit("text_delta", { delta: ae.delta }));
26460
- }
26461
- } else if (event.type === "tool_execution_start") track(emit("tool_call_start", { tool_name: event.toolName }));
26462
- else if (event.type === "tool_execution_end") {
26463
- track(emit("tool_call_end", {
26464
- tool_name: event.toolName,
26465
- is_error: event.isError,
26466
- result: event.isError ? truncateForWire(event.result) : void 0
26467
- }));
26468
- if (shouldEmitToolCallError(event)) track(emitError("tool_call_error", describeToolErrorMessage(event.result), {
26469
- tool: event.toolName,
26470
- result: truncateForWire(event.result)
26471
- }));
26472
- if (maxBashTimeouts > 0 && event.toolName === "bash" && event.isError && isBashTimeoutResult(event.result)) {
26473
- bashTimeoutCount += 1;
26474
- if (bashTimeoutCount >= maxBashTimeouts) triggerCapAbort("max_bash_timeouts_exceeded", `Aborted after ${bashTimeoutCount} bash timeouts in this attempt (cap ${maxBashTimeouts}).`);
26475
- }
26476
- } else if (event.type === "turn_end") {
26477
- const msg = event.message;
26478
- if (msg?.role === "assistant" && msg.usage) {
26479
- usage.inputTokens += Math.max(0, msg.usage.input ?? 0);
26480
- usage.outputTokens += Math.max(0, msg.usage.output ?? 0);
26481
- const cr = Math.max(0, msg.usage.cacheRead ?? 0);
26482
- const cw = Math.max(0, msg.usage.cacheWrite ?? 0);
26483
- if (cr) usage.cacheReadTokens = (usage.cacheReadTokens ?? 0) + cr;
26484
- if (cw) usage.cacheWriteTokens = (usage.cacheWriteTokens ?? 0) + cw;
26485
- }
26486
- const stopReason = msg?.stopReason ?? "end_turn";
26487
- track(emit("turn_end", { stop_reason: stopReason }));
26488
- if (maxTurns > 0 && stopReason !== "end_turn" && stopReason !== "aborted" && stopReason !== "error") {
26489
- toolUseTurnCount += 1;
26490
- if (toolUseTurnCount >= maxTurns) triggerCapAbort("max_turns_exceeded", `Aborted after ${toolUseTurnCount} tool-use turns (cap ${maxTurns}).`);
26491
- }
26492
- llmAbort = msg?.stopReason === "error";
26493
- if (msg?.stopReason === "error") llmErrorMessage = typeof msg.errorMessage === "string" && msg.errorMessage.length > 0 ? msg.errorMessage : null;
26494
- else llmErrorMessage = null;
26495
- }
26496
- });
26450
+ session.subscribe(makeSessionEventHandler({
26451
+ state: turnState,
26452
+ usage,
26453
+ maxTurns,
26454
+ maxBashTimeouts,
26455
+ emit,
26456
+ emitError,
26457
+ track,
26458
+ triggerCapAbort
26459
+ }));
26497
26460
  let runError = null;
26498
26461
  const runPrompt = (promptText) => promptWithProviderErrorRetries({
26499
26462
  session: liveSession,
@@ -26501,8 +26464,8 @@ async function executePiTask(claimedTask, reporter, opts) {
26501
26464
  cancelSignal: reporter.cancelSignal,
26502
26465
  isCapAborted: () => capAbort !== null,
26503
26466
  getProviderErrorState: () => ({
26504
- llmAbort,
26505
- llmErrorMessage
26467
+ llmAbort: turnState.llmAbort,
26468
+ llmErrorMessage: turnState.llmErrorMessage
26506
26469
  }),
26507
26470
  maxRetries: opts.maxProviderErrorRetries ?? 2,
26508
26471
  baseDelayMs: opts.providerErrorRetryBaseDelayMs ?? 2e3,
@@ -26531,7 +26494,7 @@ async function executePiTask(claimedTask, reporter, opts) {
26531
26494
  isStopped: () => submitRepromptStopped({
26532
26495
  cancelled: reporter.cancelSignal.aborted,
26533
26496
  capAborted: capAbort !== null,
26534
- llmAbort
26497
+ llmAbort: turnState.llmAbort
26535
26498
  }),
26536
26499
  onSubmitReprompt: async (event) => {
26537
26500
  await emit("info", event);
@@ -26552,62 +26515,18 @@ async function executePiTask(claimedTask, reporter, opts) {
26552
26515
  let parsedOutput = null;
26553
26516
  let parsedOutputCid = null;
26554
26517
  let parseError = null;
26555
- if (!runError && !llmAbort && !cancelled && !capAbort) {
26556
- const captured = submitToolHandle?.getCaptured() ?? null;
26557
- if (captured) try {
26558
- parsedOutput = captured;
26559
- parsedOutputCid = await computeJsonCid(captured);
26560
- recordTaskOutputParseResult({
26561
- taskType: task.taskType,
26562
- model: opts.model,
26563
- code: "captured_via_tool"
26564
- });
26565
- } catch (err) {
26566
- const message = err instanceof Error ? err.message : String(err);
26567
- parsedOutput = null;
26568
- parsedOutputCid = null;
26569
- parseError = {
26570
- code: "output_cid_compute_failed",
26571
- message: `Captured submit-tool output could not be canonicalized: ${message}`
26572
- };
26573
- recordTaskOutputParseResult({
26574
- taskType: task.taskType,
26575
- model: opts.model,
26576
- code: "output_cid_compute_failed"
26577
- });
26578
- await emit("error", {
26579
- message: parseError.message,
26580
- phase: "output_validation"
26581
- });
26582
- }
26583
- else if (submitToolHandle) {
26584
- const exhausted = submitToolHandle.getExhaustedValidationFailure();
26585
- parseError = exhausted ?? {
26586
- code: "submit_output_missing",
26587
- message: "Agent did not satisfy the promised submit-output criterion: no valid task submit tool call was captured before the session ended."
26588
- };
26589
- if (!exhausted) recordTaskOutputParseResult({
26590
- taskType: task.taskType,
26591
- model: opts.model,
26592
- code: "output_missing"
26593
- });
26594
- await emit("error", {
26595
- message: parseError.message,
26596
- phase: "output_validation"
26597
- });
26598
- } else {
26599
- const parsed = await parseStructuredTaskOutput(assistantText, task.taskType, {
26600
- model: opts.model,
26601
- input: task.input
26602
- });
26603
- parsedOutput = parsed.output;
26604
- parsedOutputCid = parsed.outputCid;
26605
- parseError = parsed.error;
26606
- if (parseError) await emit("error", {
26607
- message: parseError.message,
26608
- phase: "output_validation"
26609
- });
26610
- }
26518
+ if (!runError && !turnState.llmAbort && !cancelled && !capAbort) {
26519
+ const captured = await captureAttemptOutput({
26520
+ taskType: task.taskType,
26521
+ model: opts.model,
26522
+ input: task.input,
26523
+ assistantText: turnState.assistantText,
26524
+ submitToolHandle,
26525
+ emit
26526
+ });
26527
+ parsedOutput = captured.output;
26528
+ parsedOutputCid = captured.outputCid;
26529
+ parseError = captured.error;
26611
26530
  }
26612
26531
  if (cancelled) return {
26613
26532
  taskId: task.id,
@@ -26638,53 +26557,266 @@ async function executePiTask(claimedTask, reporter, opts) {
26638
26557
  retryable: false
26639
26558
  }
26640
26559
  };
26641
- const reporterErrorSnapshot = reporterError;
26642
- const status = runError || llmAbort || parseError || reporterErrorSnapshot ? "failed" : "completed";
26643
- const errorCode = runError?.code ?? parseError?.code ?? reporterErrorSnapshot?.code ?? (llmAbort ? "llm_api_error" : void 0);
26644
- const errorMessage = runError?.message ?? parseError?.message ?? reporterErrorSnapshot?.message ?? (llmAbort ? llmErrorMessage ?? "LLM API error during turn" : void 0);
26645
- const errorRetryable = reporterErrorSnapshot && errorCode === reporterErrorSnapshot.code && errorMessage === reporterErrorSnapshot.message ? reporterErrorSnapshot.retryable ?? false : false;
26646
- return {
26560
+ return buildAttemptResult({
26647
26561
  taskId: task.id,
26648
26562
  attemptN,
26649
- status,
26650
26563
  output: parsedOutput,
26651
26564
  outputCid: parsedOutputCid,
26652
26565
  usage,
26653
26566
  durationMs: Date.now() - startTime,
26654
- ...errorCode && errorMessage ? { error: {
26655
- code: errorCode,
26656
- message: errorMessage,
26657
- retryable: errorRetryable
26658
- } } : {}
26659
- };
26567
+ runError,
26568
+ parseError,
26569
+ reporterError,
26570
+ llmAbort: turnState.llmAbort,
26571
+ llmErrorMessage: turnState.llmErrorMessage
26572
+ });
26660
26573
  } catch (err) {
26661
26574
  return makeFailedOutput("executor_unexpected_error", err instanceof Error ? err.message : String(err));
26662
26575
  } finally {
26663
- if (cancelListener) reporter.cancelSignal.removeEventListener("abort", cancelListener);
26664
- if (session) try {
26665
- session.dispose();
26666
- } catch {}
26667
- if (reporterOpen) {
26668
- try {
26669
- await reporter.finalize(finalUsage);
26670
- } catch (err) {
26671
- const detail = err instanceof Error ? err.message : String(err);
26672
- console.error(`executePiTask: reporter.finalize() failed for task ${task.id} attempt ${attemptN}: ${detail}`);
26576
+ await cleanupAttempt({
26577
+ cancelSignal: reporter.cancelSignal,
26578
+ cancelListener,
26579
+ session,
26580
+ reporterOpen,
26581
+ reporter,
26582
+ finalUsage,
26583
+ managed,
26584
+ workspace,
26585
+ taskId: task.id,
26586
+ attemptN
26587
+ });
26588
+ }
26589
+ }
26590
+ function createSessionTurnState() {
26591
+ return {
26592
+ assistantText: "",
26593
+ llmAbort: false,
26594
+ llmErrorMessage: null,
26595
+ toolUseTurnCount: 0,
26596
+ bashTimeoutCount: 0
26597
+ };
26598
+ }
26599
+ /**
26600
+ * Build the `AgentSession.subscribe` handler for one attempt: bridges pi
26601
+ * events to the reporter, accumulates token usage and assistant text, and
26602
+ * enforces the bash-timeout and tool-use-turn caps. Extracted from
26603
+ * `executePiTask` so this dense, branch-heavy logic is unit-tested against a
26604
+ * scripted event stream instead of only through a booted VM.
26605
+ *
26606
+ * The handler mutates `deps.state` and `deps.usage` in place; the caller reads
26607
+ * them after `session.prompt()` resolves (by which point `state.llmAbort`
26608
+ * holds the terminal turn's outcome — see the "last-turn wins" note below).
26609
+ *
26610
+ * @internal Exported for unit testing; not part of the package's public API.
26611
+ */
26612
+ function makeSessionEventHandler(deps) {
26613
+ const { state, usage, maxTurns, maxBashTimeouts, emit, emitError, track, triggerCapAbort } = deps;
26614
+ return (event) => {
26615
+ if (event.type === "message_update") {
26616
+ const ae = event.assistantMessageEvent;
26617
+ if (ae.type === "text_delta") {
26618
+ state.assistantText += ae.delta;
26619
+ track(emit("text_delta", { delta: ae.delta }));
26673
26620
  }
26674
- try {
26675
- await reporter.close();
26676
- } catch (err) {
26677
- const detail = err instanceof Error ? err.message : String(err);
26678
- console.error(`executePiTask: reporter.close() failed for task ${task.id} attempt ${attemptN}: ${detail}`);
26621
+ } else if (event.type === "tool_execution_start") track(emit("tool_call_start", { tool_name: event.toolName }));
26622
+ else if (event.type === "tool_execution_end") {
26623
+ track(emit("tool_call_end", {
26624
+ tool_name: event.toolName,
26625
+ is_error: event.isError,
26626
+ result: event.isError ? truncateForWire(event.result) : void 0
26627
+ }));
26628
+ if (shouldEmitToolCallError(event)) track(emitError("tool_call_error", describeToolErrorMessage(event.result), {
26629
+ tool: event.toolName,
26630
+ result: truncateForWire(event.result)
26631
+ }));
26632
+ if (maxBashTimeouts > 0 && event.toolName === "bash" && event.isError && isBashTimeoutResult(event.result)) {
26633
+ state.bashTimeoutCount += 1;
26634
+ if (state.bashTimeoutCount >= maxBashTimeouts) triggerCapAbort("max_bash_timeouts_exceeded", `Aborted after ${state.bashTimeoutCount} bash timeouts in this attempt (cap ${maxBashTimeouts}).`);
26679
26635
  }
26636
+ } else if (event.type === "turn_end") {
26637
+ const msg = event.message;
26638
+ if (msg?.role === "assistant" && msg.usage) {
26639
+ usage.inputTokens += Math.max(0, msg.usage.input ?? 0);
26640
+ usage.outputTokens += Math.max(0, msg.usage.output ?? 0);
26641
+ const cr = Math.max(0, msg.usage.cacheRead ?? 0);
26642
+ const cw = Math.max(0, msg.usage.cacheWrite ?? 0);
26643
+ if (cr) usage.cacheReadTokens = (usage.cacheReadTokens ?? 0) + cr;
26644
+ if (cw) usage.cacheWriteTokens = (usage.cacheWriteTokens ?? 0) + cw;
26645
+ }
26646
+ const stopReason = msg?.stopReason ?? "end_turn";
26647
+ track(emit("turn_end", { stop_reason: stopReason }));
26648
+ if (maxTurns > 0 && stopReason !== "end_turn" && stopReason !== "aborted" && stopReason !== "error") {
26649
+ state.toolUseTurnCount += 1;
26650
+ if (state.toolUseTurnCount >= maxTurns) triggerCapAbort("max_turns_exceeded", `Aborted after ${state.toolUseTurnCount} tool-use turns (cap ${maxTurns}).`);
26651
+ }
26652
+ state.llmAbort = msg?.stopReason === "error";
26653
+ if (msg?.stopReason === "error") state.llmErrorMessage = typeof msg.errorMessage === "string" && msg.errorMessage.length > 0 ? msg.errorMessage : null;
26654
+ else state.llmErrorMessage = null;
26680
26655
  }
26681
- if (managed) await managed.vm.close();
26682
- if (workspace) try {
26683
- workspace.cleanup();
26656
+ };
26657
+ }
26658
+ /**
26659
+ * Resolve the attempt's structured output once the session has finished
26660
+ * cleanly (no run error / provider abort / cancel / cap). Three mutually
26661
+ * exclusive paths, in precedence order:
26662
+ *
26663
+ * 1. Submit tool captured a payload → trust it, compute its CID. A
26664
+ * canonicalization failure becomes `output_cid_compute_failed`.
26665
+ * 2. Submit tool registered but nothing captured → the exhausted-validation
26666
+ * failure wins if present, else `submit_output_missing` (recording the
26667
+ * `output_missing` counter so the never-called path is observable).
26668
+ * 3. No submit tool (legacy task type) → parse the trailing assistant text.
26669
+ *
26670
+ * Extracted from `executePiTask` so this precedence — the part a refactor is
26671
+ * most likely to silently reorder — is unit-tested directly. The caller
26672
+ * still owns the guard deciding whether output capture runs at all.
26673
+ *
26674
+ * @internal Exported for unit testing; not part of the package's public API.
26675
+ */
26676
+ async function captureAttemptOutput(deps) {
26677
+ const { taskType, model, input, assistantText, submitToolHandle, emit } = deps;
26678
+ const captured = submitToolHandle?.getCaptured() ?? null;
26679
+ if (captured) try {
26680
+ const outputCid = await computeJsonCid(captured);
26681
+ recordTaskOutputParseResult({
26682
+ taskType,
26683
+ model,
26684
+ code: "captured_via_tool"
26685
+ });
26686
+ return {
26687
+ output: captured,
26688
+ outputCid,
26689
+ error: null
26690
+ };
26691
+ } catch (err) {
26692
+ const error = {
26693
+ code: "output_cid_compute_failed",
26694
+ message: `Captured submit-tool output could not be canonicalized: ${err instanceof Error ? err.message : String(err)}`
26695
+ };
26696
+ recordTaskOutputParseResult({
26697
+ taskType,
26698
+ model,
26699
+ code: "output_cid_compute_failed"
26700
+ });
26701
+ await emit("error", {
26702
+ message: error.message,
26703
+ phase: "output_validation"
26704
+ });
26705
+ return {
26706
+ output: null,
26707
+ outputCid: null,
26708
+ error
26709
+ };
26710
+ }
26711
+ if (submitToolHandle) {
26712
+ const exhausted = submitToolHandle.getExhaustedValidationFailure();
26713
+ const error = exhausted ?? {
26714
+ code: "submit_output_missing",
26715
+ message: "Agent did not satisfy the promised submit-output criterion: no valid task submit tool call was captured before the session ended."
26716
+ };
26717
+ if (!exhausted) recordTaskOutputParseResult({
26718
+ taskType,
26719
+ model,
26720
+ code: "output_missing"
26721
+ });
26722
+ await emit("error", {
26723
+ message: error.message,
26724
+ phase: "output_validation"
26725
+ });
26726
+ return {
26727
+ output: null,
26728
+ outputCid: null,
26729
+ error
26730
+ };
26731
+ }
26732
+ const parsed = await parseStructuredTaskOutput(assistantText, taskType, {
26733
+ model,
26734
+ input
26735
+ });
26736
+ if (parsed.error) await emit("error", {
26737
+ message: parsed.error.message,
26738
+ phase: "output_validation"
26739
+ });
26740
+ return {
26741
+ output: parsed.output,
26742
+ outputCid: parsed.outputCid,
26743
+ error: parsed.error
26744
+ };
26745
+ }
26746
+ /**
26747
+ * Assemble the terminal `TaskOutput` for a clean-or-failed finish (cancel and
26748
+ * cap aborts are handled by the caller's earlier returns). Encapsulates the
26749
+ * failure-precedence ladder — runError → parseError → reporterError →
26750
+ * provider abort — so the ordering is unit-tested rather than buried in the
26751
+ * orchestrator. A provider abort with no captured diagnostic falls back to a
26752
+ * generic message.
26753
+ *
26754
+ * Errors are non-retryable EXCEPT a reporterError that both wins the ladder
26755
+ * and set `retryable: true` (a transient reporter failure, #1538).
26756
+ *
26757
+ * @internal Exported for unit testing; not part of the package's public API.
26758
+ */
26759
+ function buildAttemptResult(args) {
26760
+ const status = args.runError || args.llmAbort || args.parseError || args.reporterError ? "failed" : "completed";
26761
+ const errorCode = args.runError?.code ?? args.parseError?.code ?? args.reporterError?.code ?? (args.llmAbort ? "llm_api_error" : void 0);
26762
+ const errorMessage = args.runError?.message ?? args.parseError?.message ?? args.reporterError?.message ?? (args.llmAbort ? args.llmErrorMessage ?? "LLM API error during turn" : void 0);
26763
+ const errorRetryable = args.reporterError && errorCode === args.reporterError.code && errorMessage === args.reporterError.message ? args.reporterError.retryable ?? false : false;
26764
+ return {
26765
+ taskId: args.taskId,
26766
+ attemptN: args.attemptN,
26767
+ status,
26768
+ output: args.output,
26769
+ outputCid: args.outputCid,
26770
+ usage: args.usage,
26771
+ durationMs: args.durationMs,
26772
+ ...errorCode && errorMessage ? { error: {
26773
+ code: errorCode,
26774
+ message: errorMessage,
26775
+ retryable: errorRetryable
26776
+ } } : {}
26777
+ };
26778
+ }
26779
+ /**
26780
+ * Tear down one attempt's resources, in order: detach the cancel listener →
26781
+ * dispose the pi session → finalize+close the reporter → close the VM →
26782
+ * clean the workspace. Extracted from `executePiTask`'s `finally` so the
26783
+ * swallow-vs-log-vs-propagate policy is pinned by tests.
26784
+ *
26785
+ * Failure handling is deliberately asymmetric and preserved exactly:
26786
+ * `session.dispose()` throws are silently swallowed; reporter finalize/close
26787
+ * and workspace cleanup failures are logged but non-fatal (the task is about
26788
+ * to be reported anyway). `vm.close()` is the one teardown error allowed to
26789
+ * propagate: a leaked VM means a live microVM the host never reclaims, so its
26790
+ * failure must surface loudly rather than be logged and forgotten.
26791
+ *
26792
+ * @internal Exported for unit testing; not part of the package's public API.
26793
+ */
26794
+ async function cleanupAttempt(deps) {
26795
+ const log = deps.logError ?? ((m) => console.error(m));
26796
+ if (deps.cancelListener) deps.cancelSignal.removeEventListener("abort", deps.cancelListener);
26797
+ if (deps.session) try {
26798
+ deps.session.dispose();
26799
+ } catch {}
26800
+ if (deps.reporterOpen) {
26801
+ try {
26802
+ await deps.reporter.finalize(deps.finalUsage);
26684
26803
  } catch (err) {
26685
26804
  const detail = err instanceof Error ? err.message : String(err);
26686
- console.error(`executePiTask: workspace cleanup failed for task ${task.id} attempt ${attemptN}: ${detail}`);
26805
+ log(`executePiTask: reporter.finalize() failed for task ${deps.taskId} attempt ${deps.attemptN}: ${detail}`);
26687
26806
  }
26807
+ try {
26808
+ await deps.reporter.close();
26809
+ } catch (err) {
26810
+ const detail = err instanceof Error ? err.message : String(err);
26811
+ log(`executePiTask: reporter.close() failed for task ${deps.taskId} attempt ${deps.attemptN}: ${detail}`);
26812
+ }
26813
+ }
26814
+ if (deps.managed) await deps.managed.vm.close();
26815
+ if (deps.workspace) try {
26816
+ deps.workspace.cleanup();
26817
+ } catch (err) {
26818
+ const detail = err instanceof Error ? err.message : String(err);
26819
+ log(`executePiTask: workspace cleanup failed for task ${deps.taskId} attempt ${deps.attemptN}: ${detail}`);
26688
26820
  }
26689
26821
  }
26690
26822
  function applyExecutionPlanSandboxOverrides(sandboxConfig, executionPlan) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@themoltnet/pi-extension",
3
- "version": "0.32.0",
3
+ "version": "0.32.1",
4
4
  "type": "module",
5
5
  "description": "MoltNet pi extension — sandboxed tool execution in Gondolin VMs with MoltNet identity and persistent memory",
6
6
  "keywords": [
@@ -36,8 +36,8 @@
36
36
  "@earendil-works/gondolin": "^0.9.1",
37
37
  "@opentelemetry/api": "^1.9.0",
38
38
  "typebox": "^1.2.8",
39
- "@themoltnet/agent-runtime": "0.34.0",
40
- "@themoltnet/sdk": "0.118.0"
39
+ "@themoltnet/sdk": "0.119.0",
40
+ "@themoltnet/agent-runtime": "0.34.1"
41
41
  },
42
42
  "peerDependencies": {
43
43
  "@earendil-works/pi-coding-agent": ">=0.74.0",