@odla-ai/harness 0.5.1 → 0.5.2

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.
@@ -1384,6 +1384,9 @@ async function materializeCommandWorkspace(input) {
1384
1384
  }
1385
1385
  }
1386
1386
 
1387
+ // src/code-runtime-attempt.ts
1388
+ var import_ai2 = require("@odla-ai/ai");
1389
+
1387
1390
  // src/code-agent.ts
1388
1391
  var import_ai = require("@odla-ai/ai");
1389
1392
 
@@ -1584,6 +1587,7 @@ async function runCodeAgent(options) {
1584
1587
  // src/code-runtime-attempt.ts
1585
1588
  async function runCodeAgentAttempt(options) {
1586
1589
  try {
1590
+ const surface = options.surface ?? "v2";
1587
1591
  const { run } = await runCodeAgent({
1588
1592
  inference: options.inference,
1589
1593
  broker: options.broker,
@@ -1593,17 +1597,31 @@ async function runCodeAgentAttempt(options) {
1593
1597
  // The brokered route resolves the real model from platform policy; this
1594
1598
  // id only labels the request the control plane is about to rewrite.
1595
1599
  model: "brokered",
1596
- surface: options.surface ?? "v2",
1600
+ surface,
1597
1601
  ...options.maxSteps === void 0 ? {} : { maxSteps: options.maxSteps },
1598
1602
  ...options.budget ? { budget: options.budget } : {},
1599
1603
  ...options.signal ? { signal: options.signal } : {},
1600
1604
  ...options.onToolCall ? { onToolCall: options.onToolCall } : {}
1601
1605
  });
1606
+ let finalText = run.finalText.trim();
1607
+ if (!finalText && run.stoppedReason !== "refusal") {
1608
+ const closing = await options.inference.chat({
1609
+ model: "brokered",
1610
+ system: `${SYSTEM_PROMPT_FOR[surface]}
1611
+
1612
+ Finish with a concise, non-empty answer to the owner. Do not call tools or promise future work.`,
1613
+ messages: [...run.messages, { role: "user", content: "Give the owner the closing answer now, grounded in the repository evidence and tool results above." }],
1614
+ maxTokens: 16384,
1615
+ ...options.signal ? { signal: options.signal } : {}
1616
+ });
1617
+ finalText = (0, import_ai2.extractText)(closing.content).trim();
1618
+ }
1619
+ const missingClosing = !finalText && run.stoppedReason !== "refusal";
1602
1620
  return {
1603
- status: run.stoppedReason === "refusal" ? "failed" : "completed",
1604
- finalText: run.finalText,
1621
+ status: run.stoppedReason === "refusal" || missingClosing ? "failed" : "completed",
1622
+ finalText,
1605
1623
  stoppedReason: run.stoppedReason,
1606
- ...run.stoppedReason === "refusal" ? { error: run.finalText || "the agent refused the task" } : {}
1624
+ ...run.stoppedReason === "refusal" ? { error: finalText || "the agent refused the task" } : missingClosing ? { error: "the Code agent did not produce a closing answer" } : {}
1607
1625
  };
1608
1626
  } catch (cause) {
1609
1627
  const error = (cause instanceof Error ? cause.message : String(cause)).slice(0, 2e3);
@@ -1613,31 +1631,7 @@ async function runCodeAgentAttempt(options) {
1613
1631
 
1614
1632
  // src/code-runtime-inference.ts
1615
1633
  async function handleCodeRuntimeInference(input) {
1616
- const { command, metadata, request, state } = input;
1617
- if (state.tokens >= metadata.maxTokensPerInteraction) {
1618
- if (!state.noticeEmitted) {
1619
- state.noticeEmitted = true;
1620
- await input.event({
1621
- type: "message",
1622
- actor: "system",
1623
- body: `The agent paused at the ${metadata.maxTokensPerInteraction.toLocaleString("en-US")}-token per-interaction limit. Send a new instruction to continue.`
1624
- }).catch(() => void 0);
1625
- }
1626
- return {
1627
- protocolVersion: HARNESS_PROTOCOL_VERSION,
1628
- type: "inference.response",
1629
- requestId: request.requestId,
1630
- response: {
1631
- id: `budget:${command.commandId}`,
1632
- provider: "openai",
1633
- model: "interaction-budget",
1634
- role: "assistant",
1635
- content: [{ type: "text", text: "Pause now. The owner-set token limit for this interaction has been reached." }],
1636
- stopReason: "end_turn",
1637
- usage: { inputTokens: 0, outputTokens: 0 }
1638
- }
1639
- };
1640
- }
1634
+ const { command, request, state } = input;
1641
1635
  const startedAt = Date.now();
1642
1636
  const response2 = await input.control.infer(command.sessionId, {
1643
1637
  requestId: request.requestId,
@@ -1657,7 +1651,6 @@ async function handleCodeRuntimeInference(input) {
1657
1651
  durationMs: Date.now() - startedAt,
1658
1652
  interactionId: command.commandId,
1659
1653
  interactionTokens: state.tokens,
1660
- interactionMaxTokens: metadata.maxTokensPerInteraction,
1661
1654
  ...costUsd === void 0 ? {} : { costUsd },
1662
1655
  ...state.costKnown ? { interactionCostUsd: state.costUsd } : {}
1663
1656
  }).catch(() => void 0);
@@ -2765,7 +2758,7 @@ var CodePiRuntimeEngine = class {
2765
2758
  recipeAuthorization: this.options.recipeAuthorization
2766
2759
  }, lease, metadata.role));
2767
2760
  const startedAt = Date.now();
2768
- const interaction = { tokens: 0, noticeEmitted: false, costUsd: 0, costKnown: true };
2761
+ const interaction = { tokens: 0, costUsd: 0, costKnown: true };
2769
2762
  const inference = createCodeRuntimeInference({
2770
2763
  command,
2771
2764
  metadata,
@@ -2780,31 +2773,30 @@ var CodePiRuntimeEngine = class {
2780
2773
  lease,
2781
2774
  workspaceDir: active.workspace.workspaceDir,
2782
2775
  prompt: metadata.prompt,
2783
- signal: active.abort.signal,
2784
- // The owner's per-interaction allowance, enforced by runAgent against
2785
- // INCREMENTAL usage. The control plane still reserves against the same
2786
- // ceiling, but this is what stops the loop cleanly at the boundary rather
2787
- // than letting it discover the limit through a synthesized pause reply.
2788
- budget: { maxTotalTokens: metadata.maxTokensPerInteraction }
2776
+ signal: active.abort.signal
2789
2777
  });
2790
- const body = result.finalText.trim() || (result.status === "completed" ? "The agent finished without a closing message." : result.error ?? "The agent failed.");
2778
+ const closing = result.finalText.trim();
2779
+ const completed = result.status === "completed" && Boolean(closing);
2780
+ const detail = result.error?.trim() || (closing ? "the Code agent failed" : "the Code agent did not produce a closing answer");
2781
+ const body = closing || detail;
2791
2782
  await this.#event(command, {
2792
2783
  type: "message",
2793
- actor: result.status === "completed" ? "agent" : "system",
2784
+ actor: completed ? "agent" : "system",
2794
2785
  body
2795
2786
  }, active.conversationRefs).catch(() => void 0);
2796
2787
  await this.#event(command, {
2797
2788
  type: "status",
2798
- status: result.status === "completed" ? "idle" : "failed",
2789
+ status: completed ? "idle" : "failed",
2799
2790
  durationMs: Date.now() - startedAt
2800
2791
  }, active.conversationRefs).catch(() => void 0);
2801
- if (result.status === "failed") {
2802
- const detail = (result.error ?? "").trim() || "the Code agent failed";
2792
+ if (!completed) {
2803
2793
  await this.#diagnostic(command, active, detail);
2804
2794
  await this.#failure(command, active, detail);
2805
2795
  }
2806
2796
  return {
2807
2797
  ...result,
2798
+ status: completed ? "completed" : "failed",
2799
+ ...!completed ? { error: detail } : {},
2808
2800
  tokens: interaction.tokens,
2809
2801
  ...interaction.costKnown ? { costUsd: interaction.costUsd } : {}
2810
2802
  };