@odla-ai/cli 0.16.2 → 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/README.md CHANGED
@@ -29,8 +29,8 @@ For a project you keep working in, install it as a dev dependency so the
29
29
  shorter `npx odla-ai` form works and the version is pinned by your lockfile:
30
30
 
31
31
  ```bash
32
- npm view @odla-ai/cli@0.16.2 version
33
- npm i -D --save-exact @odla-ai/cli@0.16.2
32
+ npm view @odla-ai/cli@0.16.3 version
33
+ npm i -D --save-exact @odla-ai/cli@0.16.3
34
34
  ```
35
35
 
36
36
  ## Prerequisites
package/dist/bin.cjs CHANGED
@@ -1942,10 +1942,10 @@ var import_node_fs7 = require("fs");
1942
1942
  var import_node_os = require("os");
1943
1943
  var import_node_path4 = require("path");
1944
1944
 
1945
- // ../harness/dist/chunk-7SN5SG4N.js
1945
+ // ../harness/dist/chunk-QTUEF2HZ.js
1946
1946
  var HARNESS_PROTOCOL_VERSION = 1;
1947
1947
 
1948
- // ../harness/dist/chunk-HX4QYGWE.js
1948
+ // ../harness/dist/chunk-GE6CCN7W.js
1949
1949
  var CONTROL = /[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/;
1950
1950
  var HarnessProtocolError = class extends Error {
1951
1951
  name = "HarnessProtocolError";
@@ -2023,7 +2023,7 @@ function encodeAgentInput(message2) {
2023
2023
  `;
2024
2024
  }
2025
2025
 
2026
- // ../harness/dist/chunk-QWWRL7M4.js
2026
+ // ../harness/dist/chunk-IRFCMVKU.js
2027
2027
  var import_child_process = require("child_process");
2028
2028
  var import_fs = require("fs");
2029
2029
  var import_promises2 = require("fs/promises");
@@ -2540,7 +2540,7 @@ async function stageWorkspacePair(baselineSource, workspaceSource, options = {})
2540
2540
  }
2541
2541
  }
2542
2542
 
2543
- // ../harness/dist/chunk-T2RD6ZAW.js
2543
+ // ../harness/dist/chunk-4MOSEKB6.js
2544
2544
  var import_crypto = require("crypto");
2545
2545
  var import_promises5 = require("fs/promises");
2546
2546
  var import_path5 = require("path");
@@ -2877,7 +2877,7 @@ function validateSnapshot(snapshot, limits) {
2877
2877
  }
2878
2878
  }
2879
2879
 
2880
- // ../harness/dist/chunk-T2RD6ZAW.js
2880
+ // ../harness/dist/chunk-4MOSEKB6.js
2881
2881
  var import_child_process4 = require("child_process");
2882
2882
  var import_promises6 = require("fs/promises");
2883
2883
  var import_path6 = require("path");
@@ -3170,7 +3170,7 @@ function looksLikeDestination(value) {
3170
3170
  return /^(?:[a-z][a-z0-9+.-]*:\/\/|\/|\\\\)/i.test(text) || /^[\w.-]+\.[a-z]{2,}(?:[/:]|$)/i.test(text);
3171
3171
  }
3172
3172
 
3173
- // ../harness/dist/chunk-T2RD6ZAW.js
3173
+ // ../harness/dist/chunk-4MOSEKB6.js
3174
3174
  var import_crypto4 = require("crypto");
3175
3175
  async function digestStagedWorkspace(root, limits) {
3176
3176
  const files = [];
@@ -4361,6 +4361,7 @@ function codeCommandMetadata(payload, resume) {
4361
4361
  const role = payload.role;
4362
4362
  const title = payload.title;
4363
4363
  const prompt = payload.prompt;
4364
+ const maxTokensPerInteraction = payload.maxTokensPerInteraction ?? 32e3;
4364
4365
  if (role !== "coding" && role !== "review" || typeof title !== "string" || typeof prompt !== "string") {
4365
4366
  throw new TypeError(`invalid Code ${resume ? "resume" : "start"} metadata`);
4366
4367
  }
@@ -4372,10 +4373,14 @@ function codeCommandMetadata(payload, resume) {
4372
4373
  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)) {
4373
4374
  throw new TypeError(`invalid Code ${resume ? "resume" : "start"} trusted base`);
4374
4375
  }
4376
+ if (!Number.isSafeInteger(maxTokensPerInteraction) || Number(maxTokensPerInteraction) < 4e3 || Number(maxTokensPerInteraction) > 2e5) {
4377
+ throw new TypeError(`invalid Code ${resume ? "resume" : "start"} interaction token limit`);
4378
+ }
4375
4379
  return {
4376
4380
  role,
4377
4381
  title,
4378
4382
  prompt,
4383
+ maxTokensPerInteraction: Number(maxTokensPerInteraction),
4379
4384
  planningInputDigest: typeof planning === "string" && /^sha256:[0-9a-f]{64}$/.test(planning) ? planning : null,
4380
4385
  attestationDigest: typeof attestation === "string" ? attestation : "resume",
4381
4386
  repository,
@@ -4451,6 +4456,57 @@ function createCodeRuntimeToolBroker(input, lease, role) {
4451
4456
  });
4452
4457
  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" }) };
4453
4458
  }
4459
+ async function handleCodeRuntimeInference(input) {
4460
+ const { command, metadata: metadata2, request, state } = input;
4461
+ if (state.tokens >= metadata2.maxTokensPerInteraction) {
4462
+ if (!state.noticeEmitted) {
4463
+ state.noticeEmitted = true;
4464
+ await input.event({
4465
+ type: "message",
4466
+ actor: "system",
4467
+ body: `Pi paused at the ${metadata2.maxTokensPerInteraction.toLocaleString("en-US")}-token per-interaction limit. Send a new instruction to continue.`
4468
+ }).catch(() => void 0);
4469
+ }
4470
+ return {
4471
+ protocolVersion: HARNESS_PROTOCOL_VERSION,
4472
+ type: "inference.response",
4473
+ requestId: request.requestId,
4474
+ response: {
4475
+ id: `budget:${command.commandId}`,
4476
+ provider: "openai",
4477
+ model: "interaction-budget",
4478
+ role: "assistant",
4479
+ content: [{ type: "text", text: "Pause now. The owner-set token limit for this interaction has been reached." }],
4480
+ stopReason: "end_turn",
4481
+ usage: { inputTokens: 0, outputTokens: 0 }
4482
+ }
4483
+ };
4484
+ }
4485
+ const startedAt = Date.now();
4486
+ const response2 = await input.control.infer(command.sessionId, {
4487
+ requestId: request.requestId,
4488
+ interactionId: command.commandId,
4489
+ call: request.call
4490
+ });
4491
+ state.tokens += response2.receipt.inputTokens + response2.receipt.outputTokens;
4492
+ await input.event({
4493
+ type: "usage",
4494
+ provider: response2.receipt.provider,
4495
+ model: response2.receipt.model,
4496
+ inputTokens: response2.receipt.inputTokens,
4497
+ outputTokens: response2.receipt.outputTokens,
4498
+ durationMs: Date.now() - startedAt,
4499
+ interactionId: command.commandId,
4500
+ interactionTokens: state.tokens,
4501
+ interactionMaxTokens: metadata2.maxTokensPerInteraction
4502
+ }).catch(() => void 0);
4503
+ return {
4504
+ protocolVersion: HARNESS_PROTOCOL_VERSION,
4505
+ type: "inference.response",
4506
+ requestId: request.requestId,
4507
+ response: response2.response
4508
+ };
4509
+ }
4454
4510
  async function appendCodeRuntimeEvent(control, command, event, refs) {
4455
4511
  const eventId = `${command.commandId.slice(0, 45)}:${refs.length + 1}`;
4456
4512
  refs.push(eventId);
@@ -4562,6 +4618,7 @@ var CodePiRuntimeEngine = class {
4562
4618
  acknowledged: false,
4563
4619
  role: metadata2.role,
4564
4620
  title: metadata2.title,
4621
+ maxTokensPerInteraction: metadata2.maxTokensPerInteraction,
4565
4622
  baseCommitSha: metadata2.baseCommitSha,
4566
4623
  repository: metadata2.repository,
4567
4624
  sourceTreeDigest: metadata2.sourceTreeDigest,
@@ -4598,6 +4655,11 @@ var CodePiRuntimeEngine = class {
4598
4655
  if (!active || typeof prompt !== "string" || !prompt.trim() || prompt.length > 2e4) {
4599
4656
  throw new TypeError("prompt requires an active Code session and bounded text");
4600
4657
  }
4658
+ const requestedLimit = command.payload.maxTokensPerInteraction ?? active.maxTokensPerInteraction;
4659
+ if (!Number.isSafeInteger(requestedLimit) || Number(requestedLimit) < 4e3 || Number(requestedLimit) > 2e5) {
4660
+ throw new TypeError("prompt requires a valid interaction token limit");
4661
+ }
4662
+ active.maxTokensPerInteraction = Number(requestedLimit);
4601
4663
  await active.done;
4602
4664
  active.abort = new AbortController();
4603
4665
  active.acknowledged = false;
@@ -4606,6 +4668,7 @@ var CodePiRuntimeEngine = class {
4606
4668
  role: active.role,
4607
4669
  title: active.title,
4608
4670
  prompt,
4671
+ maxTokensPerInteraction: active.maxTokensPerInteraction,
4609
4672
  planningInputDigest: active.planningInputDigest,
4610
4673
  attestationDigest: "follow-up",
4611
4674
  repository: active.repository,
@@ -4634,6 +4697,7 @@ var CodePiRuntimeEngine = class {
4634
4697
  }, lease, metadata2.role);
4635
4698
  const startedAt = Date.now();
4636
4699
  let completionSeen = false;
4700
+ const interaction = { tokens: 0, noticeEmitted: false };
4637
4701
  const result = await this.#run({
4638
4702
  engine: this.options.engine,
4639
4703
  image: this.options.image,
@@ -4649,25 +4713,18 @@ var CodePiRuntimeEngine = class {
4649
4713
  }, active.conversationRefs),
4650
4714
  onMessage: async (output) => {
4651
4715
  if (output.type === "inference.request") {
4652
- const inferenceStarted = Date.now();
4653
- const response2 = await this.options.control.infer(command.sessionId, {
4654
- requestId: output.requestId,
4655
- call: output.call
4716
+ return handleCodeRuntimeInference({
4717
+ command,
4718
+ metadata: metadata2,
4719
+ request: output,
4720
+ state: interaction,
4721
+ control: this.options.control,
4722
+ event: (event) => this.#event(
4723
+ command,
4724
+ event,
4725
+ active.conversationRefs
4726
+ )
4656
4727
  });
4657
- await this.#event(command, {
4658
- type: "usage",
4659
- provider: response2.receipt.provider,
4660
- model: response2.receipt.model,
4661
- inputTokens: response2.receipt.inputTokens,
4662
- outputTokens: response2.receipt.outputTokens,
4663
- durationMs: Date.now() - inferenceStarted
4664
- }, active.conversationRefs).catch(() => void 0);
4665
- return {
4666
- protocolVersion: HARNESS_PROTOCOL_VERSION,
4667
- type: "inference.response",
4668
- requestId: output.requestId,
4669
- response: response2.response
4670
- };
4671
4728
  }
4672
4729
  if (output.type === "tool.request") {
4673
4730
  const toolStarted = Date.now();
@@ -5166,12 +5223,15 @@ async function prepareCodeImages(engine, images) {
5166
5223
  }
5167
5224
 
5168
5225
  // src/code-runtime-config.ts
5169
- var CODE_PI_IMAGE = "ghcr.io/cory/odla-pi-agent@sha256:e7858b4f0291543171b2659b47c5d00f97acc4767cafd9b74ae5228899e0cde4";
5226
+ var CODE_PI_IMAGE = "ghcr.io/cory/odla-pi-agent@sha256:2a52a1c8eed66ad167e7bccab4d603ed8fcd75c42dddfb320083436ed89b7c9c";
5170
5227
  var CODE_BUILD_RECIPES = Object.freeze([{
5171
5228
  id: "odla-code-contracts",
5172
5229
  image: "node:24-alpine@sha256:a0b9bf06e4e6193cf7a0f58816cc935ff8c2a908f81e6f1a95432d679c54fbfd",
5173
5230
  command: [
5174
5231
  "node",
5232
+ // The clean source mount deliberately has no node_modules. Reuse the
5233
+ // semver copy inside this digest-pinned npm image without network access.
5234
+ "--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",
5175
5235
  "--test",
5176
5236
  "scripts/lib/directories.test.mjs",
5177
5237
  "scripts/lib/internal-deps.test.mjs",