@odla-ai/harness 0.9.3 → 0.10.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.
@@ -326,7 +326,7 @@ function createCodeRuntimeControlClient(options) {
326
326
  }
327
327
 
328
328
  // src/code-runtime.ts
329
- var CODE_RUNTIME_PROTOCOL_VERSION = 1;
329
+ var CODE_RUNTIME_PROTOCOL_VERSION = 2;
330
330
  async function runCodeRuntimeHeartbeatLoop(options) {
331
331
  const heartbeatMs = options.heartbeatMs ?? 15e3;
332
332
  if (!Number.isSafeInteger(heartbeatMs) || heartbeatMs < 1e3 || heartbeatMs > 3e5) {
@@ -1354,6 +1354,10 @@ function codeCommandMetadata(payload, resume) {
1354
1354
  if (role !== "coding" && role !== "review" || typeof title !== "string" || typeof prompt !== "string") {
1355
1355
  throw new TypeError(`invalid Code ${resume ? "resume" : "start"} metadata`);
1356
1356
  }
1357
+ if (payload.readOnly !== void 0 && typeof payload.readOnly !== "boolean") {
1358
+ throw new TypeError(`invalid Code ${resume ? "resume" : "start"} read-only capability`);
1359
+ }
1360
+ const readOnly = role === "review" || payload.readOnly === true;
1357
1361
  const planning = trusted?.planningInputDigest;
1358
1362
  const attestation = trusted?.attestationDigest;
1359
1363
  const repository = trusted?.repository;
@@ -1367,6 +1371,7 @@ function codeCommandMetadata(payload, resume) {
1367
1371
  }
1368
1372
  return {
1369
1373
  role,
1374
+ readOnly,
1370
1375
  title,
1371
1376
  prompt,
1372
1377
  maxTokensPerInteraction: Number(maxTokensPerInteraction),
@@ -1759,7 +1764,8 @@ function codeSkill(opts) {
1759
1764
  true
1760
1765
  )
1761
1766
  ];
1762
- const tools = opts.surface === "v3" ? [...orientation, searchFiles, read2, applyPatch, runRecipe] : opts.surface === "v2" ? [listFiles, searchFiles, read2, applyPatch, runRecipe] : [read2, applyPatch, runRecipe];
1767
+ const effects = opts.readOnly ? [] : [applyPatch, runRecipe];
1768
+ const tools = opts.surface === "v3" ? [...orientation, searchFiles, read2, ...effects] : opts.surface === "v2" ? [listFiles, searchFiles, read2, ...effects] : [read2, ...effects];
1763
1769
  return { name: "code", tools };
1764
1770
  }
1765
1771
 
@@ -1772,6 +1778,7 @@ async function runCodeAgent(options) {
1772
1778
  lease: options.lease,
1773
1779
  workspaceDir: options.workspaceDir,
1774
1780
  surface,
1781
+ ...options.readOnly === void 0 ? {} : { readOnly: options.readOnly },
1775
1782
  ...options.recipeIds ? { recipeIds: options.recipeIds } : {},
1776
1783
  onToolCall: (call) => {
1777
1784
  toolCalls.push(call);
@@ -1784,7 +1791,7 @@ async function runCodeAgent(options) {
1784
1791
  {
1785
1792
  name: "odla-code",
1786
1793
  model: options.model,
1787
- system: options.system ?? SYSTEM_PROMPT_FOR[surface],
1794
+ system: options.system ?? `${SYSTEM_PROMPT_FOR[surface]}${options.readOnly ? "\n\nThis session is read-only. Inspect and report; repository mutation and recipe execution are intentionally unavailable." : ""}`,
1788
1795
  skills: [skill, ...options.extraSkills ?? []],
1789
1796
  maxSteps: options.maxSteps ?? 24,
1790
1797
  maxTokens: options.maxTokens ?? 16384
@@ -1814,6 +1821,7 @@ async function runCodeAgentAttempt(options) {
1814
1821
  // id only labels the request the control plane is about to rewrite.
1815
1822
  model: "brokered",
1816
1823
  surface,
1824
+ ...options.readOnly === void 0 ? {} : { readOnly: options.readOnly },
1817
1825
  ...options.recipeIds ? { recipeIds: options.recipeIds } : {},
1818
1826
  ...options.extraSkills ? { extraSkills: options.extraSkills } : {},
1819
1827
  ...options.maxSteps === void 0 ? {} : { maxSteps: options.maxSteps },
@@ -2831,7 +2839,16 @@ function createCodeRuntimeToolBroker(input, lease, role) {
2831
2839
  readerId: `code-session:${lease.task.taskId}`,
2832
2840
  readOnlyPrefixes: [".odla-references"]
2833
2841
  });
2834
- 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" }) };
2842
+ const reviewReads = /* @__PURE__ */ new Set([
2843
+ "sandbox.read",
2844
+ "sandbox.list",
2845
+ "sandbox.search",
2846
+ "sandbox.overview",
2847
+ "sandbox.where_is",
2848
+ "sandbox.who_imports",
2849
+ "sandbox.who_touches"
2850
+ ]);
2851
+ return role === "coding" ? broker : { execute: (context, request) => reviewReads.has(request.tool) ? broker.execute(context, request) : Promise.resolve({ requestId: request.requestId, ok: false, content: "review sessions are read-only" }) };
2835
2852
  }
2836
2853
 
2837
2854
  // src/code-memory.ts
@@ -3264,6 +3281,7 @@ var TheseusRuntimeEngine = class {
3264
3281
  acknowledged: false,
3265
3282
  startGate,
3266
3283
  role: metadata.role,
3284
+ readOnly: metadata.readOnly,
3267
3285
  title: metadata.title,
3268
3286
  maxTokensPerInteraction: metadata.maxTokensPerInteraction,
3269
3287
  baseCommitSha: metadata.baseCommitSha,
@@ -3320,6 +3338,7 @@ var TheseusRuntimeEngine = class {
3320
3338
  event: (event) => this.#event(command, event, active.conversationRefs).then(() => void 0, () => void 0),
3321
3339
  attempt: (prompt) => this.#runAttempt(command, {
3322
3340
  role: active.role,
3341
+ readOnly: active.readOnly,
3323
3342
  title: active.title,
3324
3343
  prompt,
3325
3344
  maxTokensPerInteraction: active.maxTokensPerInteraction,
@@ -3362,6 +3381,7 @@ var TheseusRuntimeEngine = class {
3362
3381
  await this.#takeOver(command, "prompt requires an active Code session");
3363
3382
  active.done = this.#runAttempt(command, {
3364
3383
  role: active.role,
3384
+ readOnly: active.readOnly,
3365
3385
  title: active.title,
3366
3386
  prompt,
3367
3387
  maxTokensPerInteraction: active.maxTokensPerInteraction,
@@ -3409,6 +3429,7 @@ var TheseusRuntimeEngine = class {
3409
3429
  workspaceDir: active.workspace.workspaceDir,
3410
3430
  prompt: metadata.prompt,
3411
3431
  signal: active.abort.signal,
3432
+ readOnly: metadata.readOnly,
3412
3433
  recipeIds: this.options.recipes.map((recipe2) => recipe2.id),
3413
3434
  ...extraSkills.length ? { extraSkills } : {}
3414
3435
  });