@odla-ai/harness 0.2.0 → 0.3.0

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.
@@ -6,7 +6,7 @@ import {
6
6
  assertCodeBuildRecipe,
7
7
  createCodeRuntimeControlClient,
8
8
  runCodeRuntimeHeartbeatLoop
9
- } from "./chunk-5FFR7U4L.js";
9
+ } from "./chunk-U2OFMIAW.js";
10
10
  import {
11
11
  assertPinnedImage,
12
12
  selectContainerEngine
package/dist/node.cjs CHANGED
@@ -26,6 +26,7 @@ __export(node_exports, {
26
26
  CodeRuntimeControlError: () => CodeRuntimeControlError,
27
27
  CodeRuntimeReconciler: () => CodeRuntimeReconciler,
28
28
  DecompositionError: () => DecompositionError,
29
+ MAX_MEMORY_BODY: () => MAX_MEMORY_BODY,
29
30
  MEASURED_PREMIUM: () => MEASURED_PREMIUM,
30
31
  SYSTEM_PROMPT_FOR: () => SYSTEM_PROMPT_FOR,
31
32
  V1_SYSTEM_PROMPT: () => V1_SYSTEM_PROMPT,
@@ -48,17 +49,23 @@ __export(node_exports, {
48
49
  describePatchFailure: () => describePatchFailure,
49
50
  digestStagedWorkspace: () => digestStagedWorkspace,
50
51
  feedbackIsActionable: () => feedbackIsActionable,
52
+ hazardFromAttempt: () => hazardFromAttempt,
51
53
  installedDependencies: () => installedDependencies,
52
54
  integrateSubGoals: () => integrateSubGoals,
53
55
  isCheckpointEffectCompleted: () => isCheckpointEffectCompleted,
54
56
  materializeCodeRuntimeSource: () => materializeCodeRuntimeSource,
55
57
  materializeCommandWorkspace: () => materializeCommandWorkspace,
56
58
  materializeGitTree: () => materializeGitTree,
59
+ outcomeCloses: () => outcomeCloses,
60
+ outcomeMemory: () => outcomeMemory,
57
61
  patchPaths: () => patchPaths,
58
62
  planReachCollisions: () => planReachCollisions,
59
63
  prepareRuntimeCheckpoint: () => prepareRuntimeCheckpoint,
60
64
  racedAttempt: () => racedAttempt,
65
+ recallAbout: () => recallAbout,
61
66
  registeredFiles: () => registeredFiles,
67
+ renderMemories: () => renderMemories,
68
+ renderOutcome: () => renderOutcome,
62
69
  resolveCodePath: () => resolveCodePath,
63
70
  restoreCodeWorkspaceCheckpoint: () => restoreCodeWorkspaceCheckpoint,
64
71
  runCodeAgent: () => runCodeAgent,
@@ -76,6 +83,7 @@ __export(node_exports, {
76
83
  straySubGoalFiles: () => straySubGoalFiles,
77
84
  stripPatchEnvelope: () => stripPatchEnvelope,
78
85
  validateCodePatch: () => validateCodePatch,
86
+ validateMemory: () => validateMemory,
79
87
  validateRelativePath: () => validateRelativePath,
80
88
  verifyCodeCandidate: () => verifyCodeCandidate,
81
89
  verifyContainerEngineBoundary: () => verifyContainerEngineBoundary,
@@ -2832,6 +2840,55 @@ function createCodeRuntimeToolBroker(input, lease, role) {
2832
2840
  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" }) };
2833
2841
  }
2834
2842
 
2843
+ // src/code-memory.ts
2844
+ var import_graph2 = require("@odla-ai/graph");
2845
+ var MAX_MEMORY_BODY = 4e3;
2846
+ function validateMemory(memory) {
2847
+ if (!memory.subject.includes(":")) {
2848
+ throw new TypeError(`memory subject must be a graph node id, got "${memory.subject}"`);
2849
+ }
2850
+ const body = memory.body.trim();
2851
+ if (!body) throw new TypeError("a memory needs a body");
2852
+ if (body.length > MAX_MEMORY_BODY) throw new TypeError("memory body exceeds its bound");
2853
+ if (!memory.authorId.trim()) throw new TypeError("a memory needs an author");
2854
+ }
2855
+ async function recallAbout(store, subjects, options = {}) {
2856
+ const limit = options.limit ?? 20;
2857
+ const wanted = options.graph ? [...(0, import_graph2.closure)(options.graph, subjects, {
2858
+ direction: "out",
2859
+ maxDepth: options.depth ?? 1,
2860
+ ...options.kinds ? { kinds: options.kinds } : {}
2861
+ })] : [...subjects];
2862
+ const found = await store.recall(wanted, limit * 2);
2863
+ return found.filter((memory) => !memory.supersededBy).slice(0, limit);
2864
+ }
2865
+ function renderMemories(memories) {
2866
+ if (memories.length === 0) return "";
2867
+ const lines = memories.map((memory) => {
2868
+ const source = memory.evidence ? ` [${memory.evidence.kind}:${memory.evidence.ref}]` : " [unverified]";
2869
+ return `- (${memory.kind}) ${memory.subject}${source}
2870
+ ${memory.body.replace(/\s+/g, " ").slice(0, 400)}`;
2871
+ });
2872
+ return [
2873
+ "What previous runs learned about this code. A hazard cost an attempt to find;",
2874
+ "an unverified note is one agent's opinion. Treat them accordingly.",
2875
+ ...lines
2876
+ ].join("\n");
2877
+ }
2878
+ function hazardFromAttempt(input) {
2879
+ const body = [
2880
+ `Attempt ${input.attempt} at "${input.goal.slice(0, 200)}" failed its proof.`,
2881
+ input.feedback.replace(/\s+/g, " ").slice(0, MAX_MEMORY_BODY - 300)
2882
+ ].join(" ");
2883
+ return input.touched.slice(0, 10).map((path) => ({
2884
+ subject: path.includes(":") ? path : `file:${path}`,
2885
+ kind: "hazard",
2886
+ body,
2887
+ evidence: { kind: "gate", ref: input.verificationId },
2888
+ authorId: input.authorId
2889
+ }));
2890
+ }
2891
+
2835
2892
  // src/code-goal-runner.ts
2836
2893
  async function runGoal(spec, attempt) {
2837
2894
  assertBudget(spec.budget);
@@ -3016,6 +3073,9 @@ function pursueRuntimeGoal(input) {
3016
3073
  return { gatePassed: false, feedback: "", tokens: outcome.tokens, error: outcome.error };
3017
3074
  }
3018
3075
  const verdict = await input.gate(attempt);
3076
+ if (!verdict.passed && input.memory) {
3077
+ await rememberFailure(input, attempt, verdict.feedback);
3078
+ }
3019
3079
  return {
3020
3080
  gatePassed: verdict.passed,
3021
3081
  feedback: verdict.feedback,
@@ -3026,6 +3086,25 @@ function pursueRuntimeGoal(input) {
3026
3086
  }
3027
3087
  );
3028
3088
  }
3089
+ async function rememberFailure(input, attempt, feedback) {
3090
+ if (!input.memory || !feedback.trim()) return;
3091
+ try {
3092
+ const touched = await input.touched?.(attempt) ?? [];
3093
+ if (touched.length === 0) return;
3094
+ for (const memory of hazardFromAttempt({
3095
+ goal: input.spec.goal,
3096
+ attempt,
3097
+ feedback,
3098
+ touched,
3099
+ verificationId: `goal-${attempt}`,
3100
+ authorId: input.memory.authorId
3101
+ })) {
3102
+ validateMemory(memory);
3103
+ await input.memory.store.remember(memory);
3104
+ }
3105
+ } catch {
3106
+ }
3107
+ }
3029
3108
  function goalEventLine(event) {
3030
3109
  if (event.type === "attempt_started") return `Goal attempt ${event.attempt} starting.`;
3031
3110
  if (event.type === "attempt_failed") return `Attempt ${event.attempt} did not satisfy the proof.`;
@@ -3351,6 +3430,31 @@ var CodePiRuntimeEngine = class {
3351
3430
  }
3352
3431
  };
3353
3432
 
3433
+ // src/code-goal-outcome.ts
3434
+ function outcomeCloses(outcome) {
3435
+ return outcome.met && outcome.evidence !== void 0;
3436
+ }
3437
+ function renderOutcome(outcome) {
3438
+ const spend = outcome.costUsd === void 0 ? "cost unknown" : `$${outcome.costUsd.toFixed(4)}`;
3439
+ const scale = `${outcome.attempts} attempt(s), ${outcome.tokens.toLocaleString()} tokens, ${spend}`;
3440
+ if (!outcome.met) {
3441
+ return `Goal not met (${outcome.stoppedReason}) after ${scale}. Proof: ${outcome.proof}`;
3442
+ }
3443
+ if (!outcome.evidence) {
3444
+ return `Goal reported met after ${scale}, but no verification receipt was produced. Treat as unverified. Proof: ${outcome.proof}`;
3445
+ }
3446
+ return `Goal met after ${scale}. Verified by ${outcome.evidence.kind}:${outcome.evidence.ref}. Proof: ${outcome.proof}`;
3447
+ }
3448
+ function outcomeMemory(outcome, subject, authorId) {
3449
+ return {
3450
+ subject,
3451
+ kind: "outcome",
3452
+ body: renderOutcome(outcome),
3453
+ ...outcome.evidence ? { evidence: outcome.evidence } : {},
3454
+ authorId
3455
+ };
3456
+ }
3457
+
3354
3458
  // src/code-goal-race.ts
3355
3459
  function selectWinner(outcomes) {
3356
3460
  const ranked = [...outcomes].sort((left, right) => {
@@ -3411,7 +3515,7 @@ function racedAttempt(options) {
3411
3515
  }
3412
3516
 
3413
3517
  // src/code-goal-decompose.ts
3414
- var import_graph2 = require("@odla-ai/graph");
3518
+ var import_graph3 = require("@odla-ai/graph");
3415
3519
  var import_code5 = require("@odla-ai/graph/code");
3416
3520
  var DecompositionError = class extends Error {
3417
3521
  constructor(message2) {
@@ -3499,7 +3603,7 @@ async function integrateSubGoals(options) {
3499
3603
  }
3500
3604
  async function planReachCollisions(plan, workspace) {
3501
3605
  const graph = await (0, import_code5.buildCodeGraph)({ paths: workspace.paths, read: workspace.read });
3502
- return (0, import_graph2.partition)(graph, plan.map((sub) => sub.files.map((file) => `${import_code5.FILE}:${file}`)), {
3606
+ return (0, import_graph3.partition)(graph, plan.map((sub) => sub.files.map((file) => `${import_code5.FILE}:${file}`)), {
3503
3607
  kinds: [import_code5.IMPORTS, import_code5.READS, import_code5.WRITES],
3504
3608
  direction: "out"
3505
3609
  });
@@ -3609,6 +3713,7 @@ async function installedDependencies(repoRoot) {
3609
3713
  CodeRuntimeControlError,
3610
3714
  CodeRuntimeReconciler,
3611
3715
  DecompositionError,
3716
+ MAX_MEMORY_BODY,
3612
3717
  MEASURED_PREMIUM,
3613
3718
  SYSTEM_PROMPT_FOR,
3614
3719
  V1_SYSTEM_PROMPT,
@@ -3631,17 +3736,23 @@ async function installedDependencies(repoRoot) {
3631
3736
  describePatchFailure,
3632
3737
  digestStagedWorkspace,
3633
3738
  feedbackIsActionable,
3739
+ hazardFromAttempt,
3634
3740
  installedDependencies,
3635
3741
  integrateSubGoals,
3636
3742
  isCheckpointEffectCompleted,
3637
3743
  materializeCodeRuntimeSource,
3638
3744
  materializeCommandWorkspace,
3639
3745
  materializeGitTree,
3746
+ outcomeCloses,
3747
+ outcomeMemory,
3640
3748
  patchPaths,
3641
3749
  planReachCollisions,
3642
3750
  prepareRuntimeCheckpoint,
3643
3751
  racedAttempt,
3752
+ recallAbout,
3644
3753
  registeredFiles,
3754
+ renderMemories,
3755
+ renderOutcome,
3645
3756
  resolveCodePath,
3646
3757
  restoreCodeWorkspaceCheckpoint,
3647
3758
  runCodeAgent,
@@ -3659,6 +3770,7 @@ async function installedDependencies(repoRoot) {
3659
3770
  straySubGoalFiles,
3660
3771
  stripPatchEnvelope,
3661
3772
  validateCodePatch,
3773
+ validateMemory,
3662
3774
  validateRelativePath,
3663
3775
  verifyCodeCandidate,
3664
3776
  verifyContainerEngineBoundary,