@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.
@@ -7,7 +7,7 @@ import {
7
7
  createCodeRuntimeControlClient,
8
8
  createCodeRuntimeSessionSkillLoader,
9
9
  runCodeRuntimeHeartbeatLoop
10
- } from "./chunk-AEAISFY3.js";
10
+ } from "./chunk-5MDYIJXC.js";
11
11
  import "./chunk-FAN2R3GW.js";
12
12
  import {
13
13
  assertPinnedImage,
package/dist/node.cjs CHANGED
@@ -1217,7 +1217,7 @@ function createCodeRuntimeControlClient(options) {
1217
1217
  }
1218
1218
 
1219
1219
  // src/code-runtime.ts
1220
- var CODE_RUNTIME_PROTOCOL_VERSION = 1;
1220
+ var CODE_RUNTIME_PROTOCOL_VERSION = 2;
1221
1221
  async function runCodeRuntimeHeartbeatLoop(options) {
1222
1222
  const heartbeatMs = options.heartbeatMs ?? 15e3;
1223
1223
  if (!Number.isSafeInteger(heartbeatMs) || heartbeatMs < 1e3 || heartbeatMs > 3e5) {
@@ -1940,6 +1940,10 @@ function codeCommandMetadata(payload, resume) {
1940
1940
  if (role !== "coding" && role !== "review" || typeof title !== "string" || typeof prompt !== "string") {
1941
1941
  throw new TypeError(`invalid Code ${resume ? "resume" : "start"} metadata`);
1942
1942
  }
1943
+ if (payload.readOnly !== void 0 && typeof payload.readOnly !== "boolean") {
1944
+ throw new TypeError(`invalid Code ${resume ? "resume" : "start"} read-only capability`);
1945
+ }
1946
+ const readOnly = role === "review" || payload.readOnly === true;
1943
1947
  const planning = trusted?.planningInputDigest;
1944
1948
  const attestation = trusted?.attestationDigest;
1945
1949
  const repository = trusted?.repository;
@@ -1953,6 +1957,7 @@ function codeCommandMetadata(payload, resume) {
1953
1957
  }
1954
1958
  return {
1955
1959
  role,
1960
+ readOnly,
1956
1961
  title,
1957
1962
  prompt,
1958
1963
  maxTokensPerInteraction: Number(maxTokensPerInteraction),
@@ -2345,7 +2350,8 @@ function codeSkill(opts) {
2345
2350
  true
2346
2351
  )
2347
2352
  ];
2348
- const tools = opts.surface === "v3" ? [...orientation, searchFiles, read2, applyPatch, runRecipe] : opts.surface === "v2" ? [listFiles, searchFiles, read2, applyPatch, runRecipe] : [read2, applyPatch, runRecipe];
2353
+ const effects = opts.readOnly ? [] : [applyPatch, runRecipe];
2354
+ const tools = opts.surface === "v3" ? [...orientation, searchFiles, read2, ...effects] : opts.surface === "v2" ? [listFiles, searchFiles, read2, ...effects] : [read2, ...effects];
2349
2355
  return { name: "code", tools };
2350
2356
  }
2351
2357
 
@@ -2358,6 +2364,7 @@ async function runCodeAgent(options) {
2358
2364
  lease: options.lease,
2359
2365
  workspaceDir: options.workspaceDir,
2360
2366
  surface,
2367
+ ...options.readOnly === void 0 ? {} : { readOnly: options.readOnly },
2361
2368
  ...options.recipeIds ? { recipeIds: options.recipeIds } : {},
2362
2369
  onToolCall: (call) => {
2363
2370
  toolCalls.push(call);
@@ -2370,7 +2377,7 @@ async function runCodeAgent(options) {
2370
2377
  {
2371
2378
  name: "odla-code",
2372
2379
  model: options.model,
2373
- system: options.system ?? SYSTEM_PROMPT_FOR[surface],
2380
+ 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." : ""}`,
2374
2381
  skills: [skill, ...options.extraSkills ?? []],
2375
2382
  maxSteps: options.maxSteps ?? 24,
2376
2383
  maxTokens: options.maxTokens ?? 16384
@@ -2400,6 +2407,7 @@ async function runCodeAgentAttempt(options) {
2400
2407
  // id only labels the request the control plane is about to rewrite.
2401
2408
  model: "brokered",
2402
2409
  surface,
2410
+ ...options.readOnly === void 0 ? {} : { readOnly: options.readOnly },
2403
2411
  ...options.recipeIds ? { recipeIds: options.recipeIds } : {},
2404
2412
  ...options.extraSkills ? { extraSkills: options.extraSkills } : {},
2405
2413
  ...options.maxSteps === void 0 ? {} : { maxSteps: options.maxSteps },
@@ -3417,7 +3425,16 @@ function createCodeRuntimeToolBroker(input, lease, role) {
3417
3425
  readerId: `code-session:${lease.task.taskId}`,
3418
3426
  readOnlyPrefixes: [".odla-references"]
3419
3427
  });
3420
- 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" }) };
3428
+ const reviewReads = /* @__PURE__ */ new Set([
3429
+ "sandbox.read",
3430
+ "sandbox.list",
3431
+ "sandbox.search",
3432
+ "sandbox.overview",
3433
+ "sandbox.where_is",
3434
+ "sandbox.who_imports",
3435
+ "sandbox.who_touches"
3436
+ ]);
3437
+ 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" }) };
3421
3438
  }
3422
3439
 
3423
3440
  // src/code-memory.ts
@@ -3873,6 +3890,7 @@ var TheseusRuntimeEngine = class {
3873
3890
  acknowledged: false,
3874
3891
  startGate,
3875
3892
  role: metadata.role,
3893
+ readOnly: metadata.readOnly,
3876
3894
  title: metadata.title,
3877
3895
  maxTokensPerInteraction: metadata.maxTokensPerInteraction,
3878
3896
  baseCommitSha: metadata.baseCommitSha,
@@ -3929,6 +3947,7 @@ var TheseusRuntimeEngine = class {
3929
3947
  event: (event) => this.#event(command, event, active.conversationRefs).then(() => void 0, () => void 0),
3930
3948
  attempt: (prompt) => this.#runAttempt(command, {
3931
3949
  role: active.role,
3950
+ readOnly: active.readOnly,
3932
3951
  title: active.title,
3933
3952
  prompt,
3934
3953
  maxTokensPerInteraction: active.maxTokensPerInteraction,
@@ -3971,6 +3990,7 @@ var TheseusRuntimeEngine = class {
3971
3990
  await this.#takeOver(command, "prompt requires an active Code session");
3972
3991
  active.done = this.#runAttempt(command, {
3973
3992
  role: active.role,
3993
+ readOnly: active.readOnly,
3974
3994
  title: active.title,
3975
3995
  prompt,
3976
3996
  maxTokensPerInteraction: active.maxTokensPerInteraction,
@@ -4018,6 +4038,7 @@ var TheseusRuntimeEngine = class {
4018
4038
  workspaceDir: active.workspace.workspaceDir,
4019
4039
  prompt: metadata.prompt,
4020
4040
  signal: active.abort.signal,
4041
+ readOnly: metadata.readOnly,
4021
4042
  recipeIds: this.options.recipes.map((recipe2) => recipe2.id),
4022
4043
  ...extraSkills.length ? { extraSkills } : {}
4023
4044
  });