@odla-ai/harness 0.2.0 → 0.4.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.
@@ -205,6 +205,16 @@ function createCodeRuntimeControlClient(options) {
205
205
  }
206
206
  await call(`/registry/code/runtime/sessions/${validSessionId(sessionId)}/chat/events`, { eventId, event });
207
207
  },
208
+ recallMemories: async (sessionId, subjects, limit) => {
209
+ const response2 = await call(
210
+ `/registry/code/runtime/sessions/${validSessionId(sessionId)}/recall`,
211
+ { subjects: [...subjects], limit }
212
+ );
213
+ return Array.isArray(response2.memories) ? response2.memories : [];
214
+ },
215
+ rememberMemory: async (sessionId, memory) => {
216
+ await call(`/registry/code/runtime/sessions/${validSessionId(sessionId)}/remember`, memory);
217
+ },
208
218
  reportSessionFailure: async (sessionId, message2) => {
209
219
  if (!message2.trim() || message2.length > 2e3) throw new TypeError("invalid Code session failure");
210
220
  await call(`/registry/code/runtime/sessions/${validSessionId(sessionId)}/failure`, { message: message2 });
@@ -1996,6 +2006,55 @@ function validateOptions(options) {
1996
2006
  }
1997
2007
  }
1998
2008
 
2009
+ // src/code-memory.ts
2010
+ import { closure } from "@odla-ai/graph";
2011
+ var MAX_MEMORY_BODY = 4e3;
2012
+ function validateMemory(memory) {
2013
+ if (!memory.subject.includes(":")) {
2014
+ throw new TypeError(`memory subject must be a graph node id, got "${memory.subject}"`);
2015
+ }
2016
+ const body = memory.body.trim();
2017
+ if (!body) throw new TypeError("a memory needs a body");
2018
+ if (body.length > MAX_MEMORY_BODY) throw new TypeError("memory body exceeds its bound");
2019
+ if (!memory.authorId.trim()) throw new TypeError("a memory needs an author");
2020
+ }
2021
+ async function recallAbout(store, subjects, options = {}) {
2022
+ const limit = options.limit ?? 20;
2023
+ const wanted = options.graph ? [...closure(options.graph, subjects, {
2024
+ direction: "out",
2025
+ maxDepth: options.depth ?? 1,
2026
+ ...options.kinds ? { kinds: options.kinds } : {}
2027
+ })] : [...subjects];
2028
+ const found = await store.recall(wanted, limit * 2);
2029
+ return found.filter((memory) => !memory.supersededBy).slice(0, limit);
2030
+ }
2031
+ function renderMemories(memories) {
2032
+ if (memories.length === 0) return "";
2033
+ const lines = memories.map((memory) => {
2034
+ const source = memory.evidence ? ` [${memory.evidence.kind}:${memory.evidence.ref}]` : " [unverified]";
2035
+ return `- (${memory.kind}) ${memory.subject}${source}
2036
+ ${memory.body.replace(/\s+/g, " ").slice(0, 400)}`;
2037
+ });
2038
+ return [
2039
+ "What previous runs learned about this code. A hazard cost an attempt to find;",
2040
+ "an unverified note is one agent's opinion. Treat them accordingly.",
2041
+ ...lines
2042
+ ].join("\n");
2043
+ }
2044
+ function hazardFromAttempt(input) {
2045
+ const body = [
2046
+ `Attempt ${input.attempt} at "${input.goal.slice(0, 200)}" failed its proof.`,
2047
+ input.feedback.replace(/\s+/g, " ").slice(0, MAX_MEMORY_BODY - 300)
2048
+ ].join(" ");
2049
+ return input.touched.slice(0, 10).map((path) => ({
2050
+ subject: path.includes(":") ? path : `file:${path}`,
2051
+ kind: "hazard",
2052
+ body,
2053
+ evidence: { kind: "gate", ref: input.verificationId },
2054
+ authorId: input.authorId
2055
+ }));
2056
+ }
2057
+
1999
2058
  // src/code-goal-runner.ts
2000
2059
  async function runGoal(spec, attempt) {
2001
2060
  assertBudget(spec.budget);
@@ -2192,6 +2251,9 @@ function pursueRuntimeGoal(input) {
2192
2251
  return { gatePassed: false, feedback: "", tokens: outcome.tokens, error: outcome.error };
2193
2252
  }
2194
2253
  const verdict = await input.gate(attempt);
2254
+ if (!verdict.passed && input.memory) {
2255
+ await rememberFailure(input, attempt, verdict.feedback);
2256
+ }
2195
2257
  return {
2196
2258
  gatePassed: verdict.passed,
2197
2259
  feedback: verdict.feedback,
@@ -2202,6 +2264,25 @@ function pursueRuntimeGoal(input) {
2202
2264
  }
2203
2265
  );
2204
2266
  }
2267
+ async function rememberFailure(input, attempt, feedback) {
2268
+ if (!input.memory || !feedback.trim()) return;
2269
+ try {
2270
+ const touched = await input.touched?.(attempt) ?? [];
2271
+ if (touched.length === 0) return;
2272
+ for (const memory of hazardFromAttempt({
2273
+ goal: input.spec.goal,
2274
+ attempt,
2275
+ feedback,
2276
+ touched,
2277
+ verificationId: `goal-${attempt}`,
2278
+ authorId: input.memory.authorId
2279
+ })) {
2280
+ validateMemory(memory);
2281
+ await input.memory.store.remember(memory);
2282
+ }
2283
+ } catch {
2284
+ }
2285
+ }
2205
2286
  function goalEventLine(event) {
2206
2287
  if (event.type === "attempt_started") return `Goal attempt ${event.attempt} starting.`;
2207
2288
  if (event.type === "attempt_failed") return `Attempt ${event.attempt} did not satisfy the proof.`;
@@ -2562,7 +2643,12 @@ export {
2562
2643
  createCodeRuntimeInference,
2563
2644
  registeredFiles,
2564
2645
  createCodeToolBroker,
2646
+ MAX_MEMORY_BODY,
2647
+ validateMemory,
2648
+ recallAbout,
2649
+ renderMemories,
2650
+ hazardFromAttempt,
2565
2651
  runGoal,
2566
2652
  CodePiRuntimeEngine
2567
2653
  };
2568
- //# sourceMappingURL=chunk-5FFR7U4L.js.map
2654
+ //# sourceMappingURL=chunk-ANNX7VGK.js.map