@odla-ai/cli 0.16.1 → 0.16.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1995,10 +1995,10 @@ var import_node_fs7 = require("fs");
1995
1995
  var import_node_os = require("os");
1996
1996
  var import_node_path4 = require("path");
1997
1997
 
1998
- // ../harness/dist/chunk-UG5XHNFB.js
1998
+ // ../harness/dist/chunk-QTUEF2HZ.js
1999
1999
  var HARNESS_PROTOCOL_VERSION = 1;
2000
2000
 
2001
- // ../harness/dist/chunk-QALIIZRJ.js
2001
+ // ../harness/dist/chunk-GE6CCN7W.js
2002
2002
  var CONTROL = /[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/;
2003
2003
  var HarnessProtocolError = class extends Error {
2004
2004
  name = "HarnessProtocolError";
@@ -2076,7 +2076,7 @@ function encodeAgentInput(message2) {
2076
2076
  `;
2077
2077
  }
2078
2078
 
2079
- // ../harness/dist/chunk-TA2FKK27.js
2079
+ // ../harness/dist/chunk-IRFCMVKU.js
2080
2080
  var import_child_process = require("child_process");
2081
2081
  var import_fs = require("fs");
2082
2082
  var import_promises2 = require("fs/promises");
@@ -2593,7 +2593,7 @@ async function stageWorkspacePair(baselineSource, workspaceSource, options = {})
2593
2593
  }
2594
2594
  }
2595
2595
 
2596
- // ../harness/dist/chunk-5E2R3LHE.js
2596
+ // ../harness/dist/chunk-4MOSEKB6.js
2597
2597
  var import_crypto = require("crypto");
2598
2598
  var import_promises5 = require("fs/promises");
2599
2599
  var import_path5 = require("path");
@@ -2930,7 +2930,7 @@ function validateSnapshot(snapshot, limits) {
2930
2930
  }
2931
2931
  }
2932
2932
 
2933
- // ../harness/dist/chunk-5E2R3LHE.js
2933
+ // ../harness/dist/chunk-4MOSEKB6.js
2934
2934
  var import_child_process4 = require("child_process");
2935
2935
  var import_promises6 = require("fs/promises");
2936
2936
  var import_path6 = require("path");
@@ -3223,7 +3223,7 @@ function looksLikeDestination(value) {
3223
3223
  return /^(?:[a-z][a-z0-9+.-]*:\/\/|\/|\\\\)/i.test(text) || /^[\w.-]+\.[a-z]{2,}(?:[/:]|$)/i.test(text);
3224
3224
  }
3225
3225
 
3226
- // ../harness/dist/chunk-5E2R3LHE.js
3226
+ // ../harness/dist/chunk-4MOSEKB6.js
3227
3227
  var import_crypto4 = require("crypto");
3228
3228
  async function digestStagedWorkspace(root, limits) {
3229
3229
  const files = [];
@@ -4414,6 +4414,7 @@ function codeCommandMetadata(payload, resume) {
4414
4414
  const role = payload.role;
4415
4415
  const title = payload.title;
4416
4416
  const prompt = payload.prompt;
4417
+ const maxTokensPerInteraction = payload.maxTokensPerInteraction ?? 32e3;
4417
4418
  if (role !== "coding" && role !== "review" || typeof title !== "string" || typeof prompt !== "string") {
4418
4419
  throw new TypeError(`invalid Code ${resume ? "resume" : "start"} metadata`);
4419
4420
  }
@@ -4425,10 +4426,14 @@ function codeCommandMetadata(payload, resume) {
4425
4426
  if (typeof repository !== "string" || !repository.includes("/") || typeof baseCommitSha !== "string" || !/^[0-9a-f]{40}$/.test(baseCommitSha) || typeof sourceTreeDigest !== "string" || !/^sha256:[0-9a-f]{64}$/.test(sourceTreeDigest)) {
4426
4427
  throw new TypeError(`invalid Code ${resume ? "resume" : "start"} trusted base`);
4427
4428
  }
4429
+ if (!Number.isSafeInteger(maxTokensPerInteraction) || Number(maxTokensPerInteraction) < 4e3 || Number(maxTokensPerInteraction) > 2e5) {
4430
+ throw new TypeError(`invalid Code ${resume ? "resume" : "start"} interaction token limit`);
4431
+ }
4428
4432
  return {
4429
4433
  role,
4430
4434
  title,
4431
4435
  prompt,
4436
+ maxTokensPerInteraction: Number(maxTokensPerInteraction),
4432
4437
  planningInputDigest: typeof planning === "string" && /^sha256:[0-9a-f]{64}$/.test(planning) ? planning : null,
4433
4438
  attestationDigest: typeof attestation === "string" ? attestation : "resume",
4434
4439
  repository,
@@ -4504,6 +4509,57 @@ function createCodeRuntimeToolBroker(input, lease, role) {
4504
4509
  });
4505
4510
  return role === "coding" ? broker : { execute: (context, request) => request.tool === "sandbox.read" ? broker.execute(context, request) : Promise.resolve({ requestId: request.requestId, ok: false, content: "review sessions are read-only" }) };
4506
4511
  }
4512
+ async function handleCodeRuntimeInference(input) {
4513
+ const { command, metadata: metadata2, request, state } = input;
4514
+ if (state.tokens >= metadata2.maxTokensPerInteraction) {
4515
+ if (!state.noticeEmitted) {
4516
+ state.noticeEmitted = true;
4517
+ await input.event({
4518
+ type: "message",
4519
+ actor: "system",
4520
+ body: `Pi paused at the ${metadata2.maxTokensPerInteraction.toLocaleString("en-US")}-token per-interaction limit. Send a new instruction to continue.`
4521
+ }).catch(() => void 0);
4522
+ }
4523
+ return {
4524
+ protocolVersion: HARNESS_PROTOCOL_VERSION,
4525
+ type: "inference.response",
4526
+ requestId: request.requestId,
4527
+ response: {
4528
+ id: `budget:${command.commandId}`,
4529
+ provider: "openai",
4530
+ model: "interaction-budget",
4531
+ role: "assistant",
4532
+ content: [{ type: "text", text: "Pause now. The owner-set token limit for this interaction has been reached." }],
4533
+ stopReason: "end_turn",
4534
+ usage: { inputTokens: 0, outputTokens: 0 }
4535
+ }
4536
+ };
4537
+ }
4538
+ const startedAt = Date.now();
4539
+ const response2 = await input.control.infer(command.sessionId, {
4540
+ requestId: request.requestId,
4541
+ interactionId: command.commandId,
4542
+ call: request.call
4543
+ });
4544
+ state.tokens += response2.receipt.inputTokens + response2.receipt.outputTokens;
4545
+ await input.event({
4546
+ type: "usage",
4547
+ provider: response2.receipt.provider,
4548
+ model: response2.receipt.model,
4549
+ inputTokens: response2.receipt.inputTokens,
4550
+ outputTokens: response2.receipt.outputTokens,
4551
+ durationMs: Date.now() - startedAt,
4552
+ interactionId: command.commandId,
4553
+ interactionTokens: state.tokens,
4554
+ interactionMaxTokens: metadata2.maxTokensPerInteraction
4555
+ }).catch(() => void 0);
4556
+ return {
4557
+ protocolVersion: HARNESS_PROTOCOL_VERSION,
4558
+ type: "inference.response",
4559
+ requestId: request.requestId,
4560
+ response: response2.response
4561
+ };
4562
+ }
4507
4563
  async function appendCodeRuntimeEvent(control, command, event, refs) {
4508
4564
  const eventId = `${command.commandId.slice(0, 45)}:${refs.length + 1}`;
4509
4565
  refs.push(eventId);
@@ -4522,7 +4578,13 @@ var safeRuntimeJson = (value) => {
4522
4578
  };
4523
4579
  function runtimeResultText(value) {
4524
4580
  const record32 = runtimeRecord(value);
4525
- return record32 && typeof record32.text === "string" ? record32.text.slice(0, 2e4) : null;
4581
+ if (record32 && typeof record32.text === "string") return record32.text.slice(0, 2e4);
4582
+ if (record32 && typeof record32.error === "string") return `Pi failed: ${record32.error.slice(0, 19989)}`;
4583
+ return null;
4584
+ }
4585
+ function runtimeResultError(value) {
4586
+ const record32 = runtimeRecord(value);
4587
+ return record32 && typeof record32.error === "string" && record32.error.trim() ? record32.error.trim().slice(0, 2e3) : null;
4526
4588
  }
4527
4589
  var CodePiRuntimeEngine = class {
4528
4590
  constructor(options) {
@@ -4609,6 +4671,7 @@ var CodePiRuntimeEngine = class {
4609
4671
  acknowledged: false,
4610
4672
  role: metadata2.role,
4611
4673
  title: metadata2.title,
4674
+ maxTokensPerInteraction: metadata2.maxTokensPerInteraction,
4612
4675
  baseCommitSha: metadata2.baseCommitSha,
4613
4676
  repository: metadata2.repository,
4614
4677
  sourceTreeDigest: metadata2.sourceTreeDigest,
@@ -4630,9 +4693,11 @@ var CodePiRuntimeEngine = class {
4630
4693
  }, conversationRefs);
4631
4694
  }
4632
4695
  active.done = this.#runAttempt(command, metadata2, active).catch(async (cause) => {
4633
- await this.#event(command, { type: "message", actor: "system", body: `Pi failed: ${runtimeErrorMessage(cause)}` }, conversationRefs).catch(() => void 0);
4696
+ const detail = runtimeErrorMessage(cause);
4697
+ await this.#event(command, { type: "message", actor: "system", body: `Pi failed: ${detail}` }, conversationRefs).catch(() => void 0);
4698
+ await this.#diagnostic(command, active, detail);
4634
4699
  await this.#event(command, { type: "status", status: "failed" }, conversationRefs).catch(() => void 0);
4635
- await this.#failure(command, active, runtimeErrorMessage(cause));
4700
+ await this.#failure(command, active, detail);
4636
4701
  return null;
4637
4702
  });
4638
4703
  return { status: "running", message: resume ? "Pi resumed from a portable checkpoint" : "Pi started" };
@@ -4643,6 +4708,11 @@ var CodePiRuntimeEngine = class {
4643
4708
  if (!active || typeof prompt !== "string" || !prompt.trim() || prompt.length > 2e4) {
4644
4709
  throw new TypeError("prompt requires an active Code session and bounded text");
4645
4710
  }
4711
+ const requestedLimit = command.payload.maxTokensPerInteraction ?? active.maxTokensPerInteraction;
4712
+ if (!Number.isSafeInteger(requestedLimit) || Number(requestedLimit) < 4e3 || Number(requestedLimit) > 2e5) {
4713
+ throw new TypeError("prompt requires a valid interaction token limit");
4714
+ }
4715
+ active.maxTokensPerInteraction = Number(requestedLimit);
4646
4716
  await active.done;
4647
4717
  active.abort = new AbortController();
4648
4718
  active.acknowledged = false;
@@ -4651,19 +4721,22 @@ var CodePiRuntimeEngine = class {
4651
4721
  role: active.role,
4652
4722
  title: active.title,
4653
4723
  prompt,
4724
+ maxTokensPerInteraction: active.maxTokensPerInteraction,
4654
4725
  planningInputDigest: active.planningInputDigest,
4655
4726
  attestationDigest: "follow-up",
4656
4727
  repository: active.repository,
4657
4728
  baseCommitSha: active.baseCommitSha,
4658
4729
  sourceTreeDigest: active.sourceTreeDigest
4659
4730
  }, active).catch(async (cause) => {
4731
+ const detail = runtimeErrorMessage(cause);
4660
4732
  await this.#event(
4661
4733
  command,
4662
- { type: "message", actor: "system", body: `Pi failed: ${runtimeErrorMessage(cause)}` },
4734
+ { type: "message", actor: "system", body: `Pi failed: ${detail}` },
4663
4735
  active.conversationRefs
4664
4736
  ).catch(() => void 0);
4737
+ await this.#diagnostic(command, active, detail);
4665
4738
  await this.#event(command, { type: "status", status: "failed" }, active.conversationRefs).catch(() => void 0);
4666
- await this.#failure(command, active, runtimeErrorMessage(cause));
4739
+ await this.#failure(command, active, detail);
4667
4740
  return null;
4668
4741
  });
4669
4742
  return { status: "running", message: "Pi accepted the owner prompt" };
@@ -4677,6 +4750,7 @@ var CodePiRuntimeEngine = class {
4677
4750
  }, lease, metadata2.role);
4678
4751
  const startedAt = Date.now();
4679
4752
  let completionSeen = false;
4753
+ const interaction = { tokens: 0, noticeEmitted: false };
4680
4754
  const result = await this.#run({
4681
4755
  engine: this.options.engine,
4682
4756
  image: this.options.image,
@@ -4692,25 +4766,18 @@ var CodePiRuntimeEngine = class {
4692
4766
  }, active.conversationRefs),
4693
4767
  onMessage: async (output) => {
4694
4768
  if (output.type === "inference.request") {
4695
- const inferenceStarted = Date.now();
4696
- const response2 = await this.options.control.infer(command.sessionId, {
4697
- requestId: output.requestId,
4698
- call: output.call
4769
+ return handleCodeRuntimeInference({
4770
+ command,
4771
+ metadata: metadata2,
4772
+ request: output,
4773
+ state: interaction,
4774
+ control: this.options.control,
4775
+ event: (event) => this.#event(
4776
+ command,
4777
+ event,
4778
+ active.conversationRefs
4779
+ )
4699
4780
  });
4700
- await this.#event(command, {
4701
- type: "usage",
4702
- provider: response2.receipt.provider,
4703
- model: response2.receipt.model,
4704
- inputTokens: response2.receipt.inputTokens,
4705
- outputTokens: response2.receipt.outputTokens,
4706
- durationMs: Date.now() - inferenceStarted
4707
- }, active.conversationRefs).catch(() => void 0);
4708
- return {
4709
- protocolVersion: HARNESS_PROTOCOL_VERSION,
4710
- type: "inference.response",
4711
- requestId: output.requestId,
4712
- response: response2.response
4713
- };
4714
4781
  }
4715
4782
  if (output.type === "tool.request") {
4716
4783
  const toolStarted = Date.now();
@@ -4775,7 +4842,9 @@ var CodePiRuntimeEngine = class {
4775
4842
  durationMs: Date.now() - startedAt
4776
4843
  }, active.conversationRefs).catch(() => void 0);
4777
4844
  if (result.status === "failed") {
4778
- await this.#failure(command, active, result.stderr || "Pi container failed");
4845
+ const detail = (runtimeResultError(result.result) ?? result.stderr.trim()) || "Pi container failed";
4846
+ await this.#diagnostic(command, active, detail);
4847
+ await this.#failure(command, active, detail);
4779
4848
  }
4780
4849
  return result;
4781
4850
  }
@@ -4792,6 +4861,15 @@ var CodePiRuntimeEngine = class {
4792
4861
  await this.options.control.reportSessionFailure(command.sessionId, active.failure).catch(() => void 0);
4793
4862
  }
4794
4863
  }
4864
+ async #diagnostic(command, active, value) {
4865
+ const detail = value.trim().slice(0, 2e3) || "Pi runtime failed";
4866
+ this.options.onDiagnostic?.(detail);
4867
+ await this.#event(
4868
+ command,
4869
+ { type: "diagnostic", level: "error", message: detail },
4870
+ active.conversationRefs
4871
+ ).catch(() => void 0);
4872
+ }
4795
4873
  async #event(command, event, refs) {
4796
4874
  await appendCodeRuntimeEvent(this.options.control, command, event, refs);
4797
4875
  }
@@ -5198,12 +5276,15 @@ async function prepareCodeImages(engine, images) {
5198
5276
  }
5199
5277
 
5200
5278
  // src/code-runtime-config.ts
5201
- var CODE_PI_IMAGE = "ghcr.io/cory/odla-pi-agent@sha256:e7858b4f0291543171b2659b47c5d00f97acc4767cafd9b74ae5228899e0cde4";
5279
+ var CODE_PI_IMAGE = "ghcr.io/cory/odla-pi-agent@sha256:2a52a1c8eed66ad167e7bccab4d603ed8fcd75c42dddfb320083436ed89b7c9c";
5202
5280
  var CODE_BUILD_RECIPES = Object.freeze([{
5203
5281
  id: "odla-code-contracts",
5204
5282
  image: "node:24-alpine@sha256:a0b9bf06e4e6193cf7a0f58816cc935ff8c2a908f81e6f1a95432d679c54fbfd",
5205
5283
  command: [
5206
5284
  "node",
5285
+ // The clean source mount deliberately has no node_modules. Reuse the
5286
+ // semver copy inside this digest-pinned npm image without network access.
5287
+ "--import=data:text/javascript,import%20Module%20from%20%22node%3Amodule%22%3Bprocess.env.NODE_PATH%3D%22%2Fusr%2Flocal%2Flib%2Fnode_modules%2Fnpm%2Fnode_modules%22%3BModule._initPaths%28%29",
5207
5288
  "--test",
5208
5289
  "scripts/lib/directories.test.mjs",
5209
5290
  "scripts/lib/internal-deps.test.mjs",
@@ -5344,7 +5425,8 @@ async function runCodeRuntime(input) {
5344
5425
  image: CODE_PI_IMAGE,
5345
5426
  recipes: CODE_BUILD_RECIPES,
5346
5427
  recipeAuthorization: "registered_recipe",
5347
- localSource: input.localSource
5428
+ localSource: input.localSource,
5429
+ onDiagnostic: (message2) => input.stdout.error(`Pi runtime failed \xB7 ${message2}`)
5348
5430
  });
5349
5431
  const reconciler = new CodeRuntimeReconciler(control, commandEngine);
5350
5432
  try {