@odla-ai/cli 0.40.2 → 0.41.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.
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runCli
4
- } from "./chunk-XUTMQMXZ.js";
4
+ } from "./chunk-6RGM4W73.js";
5
5
  import {
6
6
  exitCodeFor
7
7
  } from "./chunk-UKLSRQ5J.js";
@@ -9,4 +9,4 @@ export {
9
9
  exitCodeFor,
10
10
  runCli
11
11
  };
12
- //# sourceMappingURL=cli-WJSQEBDO.js.map
12
+ //# sourceMappingURL=cli-N5PASRYU.js.map
package/dist/index.cjs CHANGED
@@ -6275,7 +6275,7 @@ async function stageWorkspacePair(baselineSource, workspaceSource, options = {})
6275
6275
  }
6276
6276
  }
6277
6277
 
6278
- // ../harness/dist/chunk-L2T3LPEF.js
6278
+ // ../harness/dist/chunk-5HX5LWTG.js
6279
6279
  var import_crypto = require("crypto");
6280
6280
  var import_promises5 = require("fs/promises");
6281
6281
  var import_path5 = require("path");
@@ -6612,7 +6612,7 @@ function validateSnapshot(snapshot, limits) {
6612
6612
  }
6613
6613
  }
6614
6614
 
6615
- // ../harness/dist/chunk-L2T3LPEF.js
6615
+ // ../harness/dist/chunk-5HX5LWTG.js
6616
6616
  var import_child_process4 = require("child_process");
6617
6617
  var import_promises6 = require("fs/promises");
6618
6618
  var import_path6 = require("path");
@@ -6627,6 +6627,7 @@ var import_promises8 = require("fs/promises");
6627
6627
  var import_os3 = require("os");
6628
6628
  var import_path8 = require("path");
6629
6629
  var import_ai4 = require("@odla-ai/ai");
6630
+ var import_ai5 = require("@odla-ai/ai");
6630
6631
  var import_promises9 = require("fs/promises");
6631
6632
  var import_path9 = require("path");
6632
6633
 
@@ -6914,7 +6915,7 @@ function looksLikeDestination(value2) {
6914
6915
  return /^(?:[a-z][a-z0-9+.-]*:\/\/|\/|\\\\)/i.test(text3) || /^[\w.-]+\.[a-z]{2,}(?:[/:]|$)/i.test(text3);
6915
6916
  }
6916
6917
 
6917
- // ../harness/dist/chunk-L2T3LPEF.js
6918
+ // ../harness/dist/chunk-5HX5LWTG.js
6918
6919
  var import_promises10 = require("fs/promises");
6919
6920
  var import_promises11 = require("fs/promises");
6920
6921
  var import_path10 = require("path");
@@ -7182,7 +7183,7 @@ async function buildCodeGraph(input) {
7182
7183
  return builder.build();
7183
7184
  }
7184
7185
 
7185
- // ../harness/dist/chunk-L2T3LPEF.js
7186
+ // ../harness/dist/chunk-5HX5LWTG.js
7186
7187
  var import_crypto4 = require("crypto");
7187
7188
  async function digestStagedWorkspace(root, limits) {
7188
7189
  const files = [];
@@ -8428,6 +8429,7 @@ async function runCodeAgent(options) {
8428
8429
  }
8429
8430
  async function runCodeAgentAttempt(options) {
8430
8431
  try {
8432
+ const surface = options.surface ?? "v2";
8431
8433
  const { run } = await runCodeAgent({
8432
8434
  inference: options.inference,
8433
8435
  broker: options.broker,
@@ -8437,17 +8439,31 @@ async function runCodeAgentAttempt(options) {
8437
8439
  // The brokered route resolves the real model from platform policy; this
8438
8440
  // id only labels the request the control plane is about to rewrite.
8439
8441
  model: "brokered",
8440
- surface: options.surface ?? "v2",
8442
+ surface,
8441
8443
  ...options.maxSteps === void 0 ? {} : { maxSteps: options.maxSteps },
8442
8444
  ...options.budget ? { budget: options.budget } : {},
8443
8445
  ...options.signal ? { signal: options.signal } : {},
8444
8446
  ...options.onToolCall ? { onToolCall: options.onToolCall } : {}
8445
8447
  });
8448
+ let finalText = run.finalText.trim();
8449
+ if (!finalText && run.stoppedReason !== "refusal") {
8450
+ const closing = await options.inference.chat({
8451
+ model: "brokered",
8452
+ system: `${SYSTEM_PROMPT_FOR[surface]}
8453
+
8454
+ Finish with a concise, non-empty answer to the owner. Do not call tools or promise future work.`,
8455
+ messages: [...run.messages, { role: "user", content: "Give the owner the closing answer now, grounded in the repository evidence and tool results above." }],
8456
+ maxTokens: 16384,
8457
+ ...options.signal ? { signal: options.signal } : {}
8458
+ });
8459
+ finalText = (0, import_ai5.extractText)(closing.content).trim();
8460
+ }
8461
+ const missingClosing = !finalText && run.stoppedReason !== "refusal";
8446
8462
  return {
8447
- status: run.stoppedReason === "refusal" ? "failed" : "completed",
8448
- finalText: run.finalText,
8463
+ status: run.stoppedReason === "refusal" || missingClosing ? "failed" : "completed",
8464
+ finalText,
8449
8465
  stoppedReason: run.stoppedReason,
8450
- ...run.stoppedReason === "refusal" ? { error: run.finalText || "the agent refused the task" } : {}
8466
+ ...run.stoppedReason === "refusal" ? { error: finalText || "the agent refused the task" } : missingClosing ? { error: "the Code agent did not produce a closing answer" } : {}
8451
8467
  };
8452
8468
  } catch (cause) {
8453
8469
  const error = (cause instanceof Error ? cause.message : String(cause)).slice(0, 2e3);
@@ -8455,31 +8471,7 @@ async function runCodeAgentAttempt(options) {
8455
8471
  }
8456
8472
  }
8457
8473
  async function handleCodeRuntimeInference(input) {
8458
- const { command, metadata: metadata2, request: request3, state: state2 } = input;
8459
- if (state2.tokens >= metadata2.maxTokensPerInteraction) {
8460
- if (!state2.noticeEmitted) {
8461
- state2.noticeEmitted = true;
8462
- await input.event({
8463
- type: "message",
8464
- actor: "system",
8465
- body: `The agent paused at the ${metadata2.maxTokensPerInteraction.toLocaleString("en-US")}-token per-interaction limit. Send a new instruction to continue.`
8466
- }).catch(() => void 0);
8467
- }
8468
- return {
8469
- protocolVersion: HARNESS_PROTOCOL_VERSION,
8470
- type: "inference.response",
8471
- requestId: request3.requestId,
8472
- response: {
8473
- id: `budget:${command.commandId}`,
8474
- provider: "openai",
8475
- model: "interaction-budget",
8476
- role: "assistant",
8477
- content: [{ type: "text", text: "Pause now. The owner-set token limit for this interaction has been reached." }],
8478
- stopReason: "end_turn",
8479
- usage: { inputTokens: 0, outputTokens: 0 }
8480
- }
8481
- };
8482
- }
8474
+ const { command, request: request3, state: state2 } = input;
8483
8475
  const startedAt = Date.now();
8484
8476
  const response2 = await input.control.infer(command.sessionId, {
8485
8477
  requestId: request3.requestId,
@@ -8499,7 +8491,6 @@ async function handleCodeRuntimeInference(input) {
8499
8491
  durationMs: Date.now() - startedAt,
8500
8492
  interactionId: command.commandId,
8501
8493
  interactionTokens: state2.tokens,
8502
- interactionMaxTokens: metadata2.maxTokensPerInteraction,
8503
8494
  ...costUsd === void 0 ? {} : { costUsd },
8504
8495
  ...state2.costKnown ? { interactionCostUsd: state2.costUsd } : {}
8505
8496
  }).catch(() => void 0);
@@ -9568,7 +9559,7 @@ var CodePiRuntimeEngine = class {
9568
9559
  recipeAuthorization: this.options.recipeAuthorization
9569
9560
  }, lease, metadata2.role));
9570
9561
  const startedAt = Date.now();
9571
- const interaction = { tokens: 0, noticeEmitted: false, costUsd: 0, costKnown: true };
9562
+ const interaction = { tokens: 0, costUsd: 0, costKnown: true };
9572
9563
  const inference = createCodeRuntimeInference({
9573
9564
  command,
9574
9565
  metadata: metadata2,
@@ -9583,31 +9574,30 @@ var CodePiRuntimeEngine = class {
9583
9574
  lease,
9584
9575
  workspaceDir: active.workspace.workspaceDir,
9585
9576
  prompt: metadata2.prompt,
9586
- signal: active.abort.signal,
9587
- // The owner's per-interaction allowance, enforced by runAgent against
9588
- // INCREMENTAL usage. The control plane still reserves against the same
9589
- // ceiling, but this is what stops the loop cleanly at the boundary rather
9590
- // than letting it discover the limit through a synthesized pause reply.
9591
- budget: { maxTotalTokens: metadata2.maxTokensPerInteraction }
9577
+ signal: active.abort.signal
9592
9578
  });
9593
- const body = result.finalText.trim() || (result.status === "completed" ? "The agent finished without a closing message." : result.error ?? "The agent failed.");
9579
+ const closing = result.finalText.trim();
9580
+ const completed = result.status === "completed" && Boolean(closing);
9581
+ const detail = result.error?.trim() || (closing ? "the Code agent failed" : "the Code agent did not produce a closing answer");
9582
+ const body = closing || detail;
9594
9583
  await this.#event(command, {
9595
9584
  type: "message",
9596
- actor: result.status === "completed" ? "agent" : "system",
9585
+ actor: completed ? "agent" : "system",
9597
9586
  body
9598
9587
  }, active.conversationRefs).catch(() => void 0);
9599
9588
  await this.#event(command, {
9600
9589
  type: "status",
9601
- status: result.status === "completed" ? "idle" : "failed",
9590
+ status: completed ? "idle" : "failed",
9602
9591
  durationMs: Date.now() - startedAt
9603
9592
  }, active.conversationRefs).catch(() => void 0);
9604
- if (result.status === "failed") {
9605
- const detail = (result.error ?? "").trim() || "the Code agent failed";
9593
+ if (!completed) {
9606
9594
  await this.#diagnostic(command, active, detail);
9607
9595
  await this.#failure(command, active, detail);
9608
9596
  }
9609
9597
  return {
9610
9598
  ...result,
9599
+ status: completed ? "completed" : "failed",
9600
+ ...!completed ? { error: detail } : {},
9611
9601
  tokens: interaction.tokens,
9612
9602
  ...interaction.costKnown ? { costUsd: interaction.costUsd } : {}
9613
9603
  };
@@ -10694,12 +10684,12 @@ Usage:
10694
10684
  odla-ai pm <goal|task|decision|bug> rm <id>
10695
10685
  odla-ai pm handoff --app <id> [--project <id>] [--json]
10696
10686
  odla-ai discuss groups [--json]
10697
- odla-ai discuss list [--app <id>] [--q <text>] [--state open|resolved|all] [--json]
10687
+ odla-ai discuss list [--app <id>] [--q <text>] [--state open|resolved|all] [--mentions] [--json]
10698
10688
  odla-ai discuss read <topic> [--limit <n> --offset <n>] [--json]
10699
10689
  odla-ai discuss post --app <id> --subject "..." --body "..." [--markup "... @[Label](kind/id)"] [--mutation-id <id>]
10700
10690
  odla-ai discuss reply <topic> --body "..." [--markup "..."] [--mutation-id <id>]
10701
10691
  odla-ai discuss resolve <topic> [--reopen] [--mutation-id <id>]
10702
- odla-ai discuss who --q <text> [--app <id>] [--kinds user,pm:task] [--json]
10692
+ odla-ai discuss who --q <text> [--app <id>] [--topic <id>] [--kinds user,pm:task] [--json]
10703
10693
  odla-ai discuss watch [<topic>] [--cursor <cursor>] [--by <authorId>] [--self <authorId>] [--interval <s>] [--timeout <s>] [--json|--jsonl]
10704
10694
  odla-ai agent jobs [--env dev] [--state pending|running|succeeded|dead_letter] [--limit 50] [--token <ODLA_API_KEY>] [--json]
10705
10695
  odla-ai agent retry <job-id> [--env dev] [--token <ODLA_API_KEY>] [--json]
@@ -11138,6 +11128,7 @@ async function discussList(ctx, parsed) {
11138
11128
  const value2 = stringOpt(parsed.options[flag]);
11139
11129
  if (value2) query.set(param, value2);
11140
11130
  }
11131
+ if (parsed.options.mentions === true) query.set("mentions", "1");
11141
11132
  const qs = query.toString();
11142
11133
  const page2 = await request(ctx, "GET", `/topics${qs ? `?${qs}` : ""}`);
11143
11134
  emit(ctx, page2, () => {
@@ -11244,11 +11235,16 @@ async function discussWho(ctx, parsed) {
11244
11235
  if (app) query.set("app", app);
11245
11236
  const kinds = stringOpt(parsed.options.kinds);
11246
11237
  if (kinds) query.set("kinds", kinds);
11238
+ const topic = stringOpt(parsed.options.topic);
11239
+ if (topic) query.set("topic", topic);
11247
11240
  const found = await request(ctx, "GET", `/mentionables?${query.toString()}`);
11248
11241
  emit(ctx, found, () => {
11249
- ctx.out.log("mention kind hint");
11242
+ ctx.out.log("mention kind use hint");
11250
11243
  for (const item of found.items) {
11251
- ctx.out.log(`@[${item.label}](${item.kind}/${item.id}) ${item.kind} ${item.hint ?? ""}`);
11244
+ const use = item.kind === "agent" ? item.meta?.executionAvailability === "runnable" ? "runnable" : "reference" : "";
11245
+ ctx.out.log(
11246
+ `@[${item.label}](${item.kind}/${item.id}) ${item.kind} ${use} ${item.hint ?? ""}`
11247
+ );
11252
11248
  }
11253
11249
  if (found.failed.length > 0) ctx.out.error(`(no results from: ${found.failed.join(", ")})`);
11254
11250
  });
@@ -11498,6 +11494,8 @@ var ALLOWED = [
11498
11494
  "reopen",
11499
11495
  "by",
11500
11496
  "self",
11497
+ "topic",
11498
+ "mentions",
11501
11499
  "interval",
11502
11500
  "timeout",
11503
11501
  "cursor",
@@ -13239,7 +13237,7 @@ function percent(value2) {
13239
13237
 
13240
13238
  // src/provision.ts
13241
13239
  var import_apps13 = require("@odla-ai/apps");
13242
- var import_ai5 = require("@odla-ai/ai");
13240
+ var import_ai6 = require("@odla-ai/ai");
13243
13241
  var import_node_process17 = __toESM(require("process"), 1);
13244
13242
 
13245
13243
  // src/integration-provision.ts
@@ -13681,7 +13679,7 @@ async function provision(options) {
13681
13679
  const key = import_node_process17.default.env[cfg.ai.keyEnv];
13682
13680
  if (key) {
13683
13681
  const secretName = cfg.ai.secretName ?? defaultSecretName(cfg.ai.provider);
13684
- await (0, import_ai5.putSecret)({ endpoint: cfg.dbEndpoint, token, fetch: doFetch }, tenantId, secretName, key);
13682
+ await (0, import_ai6.putSecret)({ endpoint: cfg.dbEndpoint, token, fetch: doFetch }, tenantId, secretName, key);
13685
13683
  out.log(`${env}: ${cfg.ai.provider} key stored in vault (${secretName})`);
13686
13684
  } else {
13687
13685
  out.log(`${env}: ${cfg.ai.keyEnv} not set; skipped provider key storage`);