@zhivex-ai/harness 1.4.0-rc.6 → 1.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.
Files changed (92) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +124 -71
  3. package/SECURITY.md +1 -1
  4. package/SUPPORT.md +2 -2
  5. package/contracts/engine-api.json +55 -0
  6. package/contracts/stable-api-signatures.json +33 -33
  7. package/dist/acp-cli.js +18 -15
  8. package/dist/cli/arguments.d.ts +3 -0
  9. package/dist/cli/console/console-budget.d.ts +8 -2
  10. package/dist/{cli-s1rs15vv.js → cli-2h37qyvg.js} +34 -15
  11. package/dist/{cli-entry-d5788aay.js → cli-entry-20w6nh0k.js} +359 -21
  12. package/dist/{cli-entry-9c2k0zwz.js → cli-entry-4ngptr62.js} +2902 -1482
  13. package/dist/{cli-entry-4k1cf0m3.js → cli-entry-w0hterjs.js} +8 -5
  14. package/dist/cli.js +2 -2
  15. package/dist/client/json-contracts.d.ts +95 -2
  16. package/dist/client/local-service.d.ts +2 -2
  17. package/dist/client/protocol.d.ts +3 -0
  18. package/dist/client/stream.d.ts +2 -1
  19. package/dist/compat/code-support.d.ts +6 -0
  20. package/dist/compat/code-support.js +29 -6
  21. package/dist/{config-c002f06f.js → config-j9624t6t.js} +1 -1
  22. package/dist/{config-j3jga5wh.js → config-qt69hkqj.js} +4 -2
  23. package/dist/engine/acp.js +14 -12
  24. package/dist/engine/client.js +11 -10
  25. package/dist/engine/desktop-providers-v1.js +2 -1
  26. package/dist/engine/desktop-state-v1.js +9 -9
  27. package/dist/engine/index.js +48 -46
  28. package/dist/engine/mcp-stdio-v1.js +7 -6
  29. package/dist/engine/protocol.js +30 -2
  30. package/dist/engine/service.js +12 -11
  31. package/dist/hostile-repository-demo.js +4773 -3027
  32. package/dist/{index-49ys3s4q.js → index-5jhgatga.js} +35 -16
  33. package/dist/{index-wq2tax80.js → index-61gthdz6.js} +1 -1
  34. package/dist/index-6dft2vev.js +343 -0
  35. package/dist/{index-gq9xagx2.js → index-8zjmnyw5.js} +25 -138
  36. package/dist/index-937cb7y8.js +705 -0
  37. package/dist/index-bpc596v3.js +154 -0
  38. package/dist/index-fm84men1.js +239 -0
  39. package/dist/{index-e6r04a18.js → index-m34q25jj.js} +1127 -170
  40. package/dist/index-m49jx72n.js +220 -0
  41. package/dist/{index-dj5z774k.js → index-m82cfspw.js} +35 -16
  42. package/dist/{index-qfpz5y2v.js → index-nmjdwd4p.js} +8 -2
  43. package/dist/{index-0g939pfs.js → index-pdmevfxv.js} +10 -7
  44. package/dist/{index-4j1h4j8c.js → index-pp474137.js} +1598 -973
  45. package/dist/{index-2tgb2b4e.js → index-rkbf7dqg.js} +3 -5
  46. package/dist/index-s2k2edts.js +3778 -0
  47. package/dist/{index-z6br6qdn.js → index-tfzta544.js} +28 -11
  48. package/dist/index.js +44 -42
  49. package/dist/persistence/operations.d.ts +3 -0
  50. package/dist/providers/vertex-auth.d.ts +5 -1
  51. package/dist/runtime/config.d.ts +8 -0
  52. package/dist/runtime/context-runtime.d.ts +1 -0
  53. package/dist/runtime/error-diagnostics.d.ts +8 -0
  54. package/dist/runtime/errors.d.ts +10 -0
  55. package/dist/runtime/harness.d.ts +9 -0
  56. package/dist/runtime/policy-inspection.d.ts +1 -0
  57. package/dist/runtime/provider-transient.d.ts +33 -0
  58. package/dist/runtime/runtime-diagnostics.d.ts +3 -0
  59. package/dist/runtime/runtime-policy.d.ts +8 -10
  60. package/dist/runtime/task-acceptance-host.d.ts +1 -1
  61. package/dist/runtime/task-budget-host.d.ts +217 -0
  62. package/dist/runtime/task-budget.d.ts +147 -0
  63. package/dist/runtime/task-continuity.d.ts +434 -0
  64. package/dist/runtime/task-telemetry.d.ts +63 -0
  65. package/dist/runtime/task-transport.d.ts +3 -0
  66. package/dist/runtime/task-usage-context.d.ts +13 -0
  67. package/dist/runtime/time-to-safe-fix.d.ts +8 -0
  68. package/dist/runtime/usage-ledger.d.ts +17 -0
  69. package/dist/service-cli.js +12 -11
  70. package/dist/{service-client-cli-b52c67hx.js → service-client-cli-fn54ev6w.js} +18 -7
  71. package/dist/verify-historical-migrations.js +2426 -652
  72. package/dist/zhx.js +2 -2
  73. package/docs/CLI.md +38 -8
  74. package/docs/CLIENT_PROTOCOL.md +9 -1
  75. package/docs/CODE_RELEASE.md +118 -1
  76. package/docs/DURABLE_OPERATIONS.md +1 -1
  77. package/docs/EXTENSIBILITY.md +1 -1
  78. package/docs/FIRST_USE.md +6 -6
  79. package/docs/MINIMUM_OFFLINE_EVALS.md +31 -0
  80. package/docs/MINIMUM_TASK_AUTHORITY.md +395 -0
  81. package/docs/PROJECT_MEMORY.md +1 -1
  82. package/docs/README.md +2 -0
  83. package/docs/STABILITY.md +1 -1
  84. package/docs/WEB_LIMITS.md +117 -0
  85. package/evaluations/representative-assembly-matrix.json +28 -1
  86. package/examples/README.md +5 -5
  87. package/package.json +8 -5
  88. package/dist/index-8705zxpr.js +0 -145
  89. package/dist/index-a1q355va.js +0 -600
  90. package/dist/index-r0tdj04h.js +0 -976
  91. package/dist/index-rd0s3gqj.js +0 -1669
  92. package/dist/index-vtqfjnab.js +0 -1626
package/dist/acp-cli.js CHANGED
@@ -5,42 +5,45 @@ import {
5
5
  parseHarnessModelRoute,
6
6
  resolveHarnessModelRoutes,
7
7
  validateCliCommandOptions
8
- } from "./index-wq2tax80.js";
8
+ } from "./index-61gthdz6.js";
9
9
  import {
10
10
  serveAcpStdio
11
11
  } from "./index-3ah1f369.js";
12
12
  import {
13
- createHarness,
14
13
  createHarnessClientAdapter
15
- } from "./index-4j1h4j8c.js";
16
- import"./index-rd0s3gqj.js";
17
- import"./index-a1q355va.js";
14
+ } from "./index-937cb7y8.js";
15
+ import"./index-6dft2vev.js";
16
+ import {
17
+ createHarness
18
+ } from "./index-pp474137.js";
18
19
  import {
19
20
  usagePricingSchema
20
- } from "./index-vtqfjnab.js";
21
- import"./index-0g939pfs.js";
22
- import"./index-e6r04a18.js";
21
+ } from "./index-s2k2edts.js";
22
+ import"./index-pdmevfxv.js";
23
23
  import {
24
24
  FileChangedWhileReadingError,
25
25
  FileSizeLimitError,
26
26
  UnsafeFileTypeError,
27
27
  readRegularFileNoFollow
28
- } from "./index-r0tdj04h.js";
28
+ } from "./index-m34q25jj.js";
29
29
  import {
30
30
  HARNESS_REQUIRED_CAPABILITIES,
31
31
  HARNESS_SUBAGENT_PROFILES,
32
- HarnessConfigError,
33
- HarnessError,
34
32
  PROVIDERS,
35
33
  createProviderModel,
36
34
  parseProvider,
37
35
  providerDescriptor,
38
36
  reasoningEffortSchema,
39
37
  resolveHarnessConfig
40
- } from "./index-gq9xagx2.js";
41
- import"./index-8705zxpr.js";
38
+ } from "./index-8zjmnyw5.js";
39
+ import"./index-m49jx72n.js";
42
40
  import"./index-xqxeypt5.js";
43
- import"./index-qfpz5y2v.js";
41
+ import"./index-nmjdwd4p.js";
42
+ import {
43
+ HarnessConfigError,
44
+ HarnessError
45
+ } from "./index-bpc596v3.js";
46
+ import"./index-fm84men1.js";
44
47
  import {
45
48
  __require
46
49
  } from "./index-1bx83sw4.js";
@@ -924,7 +927,7 @@ var parseCliArgs = (argv) => {
924
927
 
925
928
  // src/cli/cli-credentials.ts
926
929
  async function credentialModel(config, env, modelFactory) {
927
- const { createProviderModel: createProviderModel2 } = await import("./config-j3jga5wh.js");
930
+ const { createProviderModel: createProviderModel2 } = await import("./config-qt69hkqj.js");
928
931
  const { wrapLanguageModel } = await import("@zhivex-ai/core");
929
932
  const secrets = providerDescriptor(config.provider).credentialNames.map((name) => env[name]).filter((value) => !!value);
930
933
  const safeError = (error) => {
@@ -34,6 +34,9 @@ export interface CliOptions {
34
34
  maxToolCalls?: number;
35
35
  maxToolErrors?: number;
36
36
  unlimitedTokens?: boolean;
37
+ unlimitedSteps?: boolean;
38
+ unlimitedToolCalls?: boolean;
39
+ unlimitedDuration?: boolean;
37
40
  compactionMaxEstimatedInputTokens?: number;
38
41
  maxInputTokens?: number;
39
42
  maxOutputTokens?: number;
@@ -1,9 +1,15 @@
1
1
  import type { CliOptions } from "../arguments.js";
2
- import { type HarnessConfig } from "../../runtime/config.js";
2
+ import { type HarnessConfig, type HarnessConfigInput } from "../../runtime/config.js";
3
3
  import type { TokenUsage } from "@zhivex-ai/core";
4
4
  /** Only new local console sessions change defaults. Explicit limits always opt
5
5
  * into bounded execution; SDK, service hosts and automation retain their policy. */
6
- export declare const consoleBudgetOptions: (options: CliOptions, env?: NodeJS.ProcessEnv) => CliOptions;
6
+ export declare const consoleBudgetOptions: <T extends HarnessConfigInput>(options: T, env?: NodeJS.ProcessEnv) => T & {
7
+ maxToolErrors?: number;
8
+ unlimitedSteps: boolean;
9
+ unlimitedToolCalls: boolean;
10
+ unlimitedDuration: boolean;
11
+ unlimitedTokens: boolean;
12
+ };
7
13
  /** A saved run owns its budget, including legacy runs without a mode flag. */
8
14
  export declare const restoreConsoleOptions: (current: CliOptions, saved: Partial<CliOptions>) => CliOptions;
9
15
  export declare const formatConsoleBudget: (config: HarnessConfig, usage?: TokenUsage) => string;
@@ -35,6 +35,7 @@ import {
35
35
  approvalDecisionViews,
36
36
  approvalResponses,
37
37
  assertRoutePricingIsSafe,
38
+ assertTaskBudgetBackupLinks,
38
39
  cancelHarnessRun,
39
40
  canonicalizeChangeEnvelope,
40
41
  changeEnvelopePreconditionsSchema,
@@ -123,16 +124,15 @@ import {
123
124
  withTemporaryHarnessProfiles,
124
125
  workspaceCheckpointSchema,
125
126
  workspaceRestoreOperationSchema
126
- } from "./cli-entry-9c2k0zwz.js";
127
+ } from "./cli-entry-4ngptr62.js";
127
128
  import {
128
129
  BUN_ENGINE_RANGE,
129
130
  HARNESS_VERSION,
130
131
  NODE_ENGINE_RANGE,
131
132
  formatCliHelp,
132
133
  shortCliHelp
133
- } from "./cli-entry-4k1cf0m3.js";
134
+ } from "./cli-entry-w0hterjs.js";
134
135
  import {
135
- DEFAULT_HARNESS_MAX_STEPS,
136
136
  DEFAULT_PROVIDER_REGISTRY,
137
137
  HARNESS_SUBAGENT_PROFILES,
138
138
  HarnessConfigError,
@@ -147,7 +147,7 @@ import {
147
147
  providerDescriptor,
148
148
  reasoningEffortSchema,
149
149
  resolveHarnessConfig
150
- } from "./cli-entry-d5788aay.js";
150
+ } from "./cli-entry-20w6nh0k.js";
151
151
  import {
152
152
  __require
153
153
  } from "./cli-entry-1bx83sw4.js";
@@ -953,21 +953,24 @@ var tokenEnvironment = [
953
953
  ];
954
954
  var consoleBudgetOptions = (options, env = process.env) => ({
955
955
  ...options,
956
- ...options.maxSteps === undefined && env.ZHIVEX_HARNESS_MAX_STEPS === undefined ? { maxSteps: DEFAULT_HARNESS_MAX_STEPS } : {},
957
- ...options.maxToolCalls === undefined && env.ZHIVEX_HARNESS_MAX_TOOL_CALLS === undefined ? { maxToolCalls: 200 } : {},
958
956
  ...options.maxToolErrors === undefined && env.ZHIVEX_HARNESS_MAX_TOOL_ERRORS === undefined ? { maxToolErrors: 20 } : {},
959
- ...options.timeoutMs === undefined && env.ZHIVEX_HARNESS_TIMEOUT_MS === undefined ? { timeoutMs: 60 * 60000 } : {},
957
+ unlimitedSteps: options.unlimitedSteps ?? (options.maxSteps === undefined && env.ZHIVEX_HARNESS_MAX_STEPS === undefined),
958
+ unlimitedToolCalls: options.unlimitedToolCalls ?? (options.maxToolCalls === undefined && env.ZHIVEX_HARNESS_MAX_TOOL_CALLS === undefined),
959
+ unlimitedDuration: options.unlimitedDuration ?? (options.timeoutMs === undefined && env.ZHIVEX_HARNESS_TIMEOUT_MS === undefined),
960
960
  unlimitedTokens: options.unlimitedTokens ?? !(tokenOptions.some((key) => options[key] !== undefined) || tokenEnvironment.some((key) => env[key] !== undefined))
961
961
  });
962
962
  var restoreConsoleOptions = (current, saved) => ({
963
963
  ...current,
964
964
  ...saved,
965
965
  reasoningEffort: saved.reasoningEffort ?? "default",
966
- unlimitedTokens: saved.unlimitedTokens ?? false
966
+ unlimitedTokens: saved.unlimitedTokens ?? false,
967
+ unlimitedSteps: saved.unlimitedSteps ?? false,
968
+ unlimitedToolCalls: saved.unlimitedToolCalls ?? false,
969
+ unlimitedDuration: saved.unlimitedDuration ?? false
967
970
  });
968
971
  var formatConsoleBudget = (config, usage) => {
969
- const lines = [`Step limit: ${config.maxSteps} model iterations per turn.`, config.budget.unlimitedTokens ? "Cumulative token budget: unlimited (step, tool, time and monetary limits still apply)." : `Cumulative token limits per run: input ${config.budget.maxInputTokens}; output ${config.budget.maxOutputTokens}; total ${config.budget.maxTotalTokens}.`];
970
- lines.push(`Tool limits: ${config.budget.maxToolCalls} calls / ${config.budget.maxToolErrors} errors; time: ${Math.round(config.timeoutMs / 60000)} minutes per run.`);
972
+ const lines = [`Step limit: ${config.budget.unlimitedSteps ? "none" : config.maxSteps} model iterations per turn.`, config.budget.unlimitedTokens ? "Cumulative token budget: unlimited; operation, model, state and safety controls still apply." : `Cumulative token limits per run: input ${config.budget.maxInputTokens}; output ${config.budget.maxOutputTokens}; total ${config.budget.maxTotalTokens}.`];
973
+ lines.push(`Tool limits: ${config.budget.unlimitedToolCalls ? "no cumulative cap on" : config.budget.maxToolCalls} calls / ${config.budget.maxToolErrors} errors; time: ${config.unlimitedDuration ? "no cumulative deadline" : `${Math.round(config.timeoutMs / 60000)} minutes per run`}.`);
971
974
  if (!usage)
972
975
  return [...lines, "Latest run usage: unavailable."].join(`
973
976
  `);
@@ -1732,7 +1735,7 @@ ${summarizeApproval(approval)}
1732
1735
  continue;
1733
1736
  if (command === "/limits" || command.startsWith("/limits ")) {
1734
1737
  const requested = command.slice("/limits".length).trim();
1735
- process.stderr.write(`Step limit: ${harness.config.maxSteps} model iterations per turn.
1738
+ process.stderr.write(`Step limit: ${harness.config.budget.unlimitedSteps ? "none" : harness.config.maxSteps} model iterations per turn.
1736
1739
  `);
1737
1740
  if (await hasActiveTurn()) {
1738
1741
  process.stderr.write(`Finish or deny pending work before changing limits.
@@ -1752,7 +1755,7 @@ ${summarizeApproval(approval)}
1752
1755
  `);
1753
1756
  continue;
1754
1757
  }
1755
- await replaceHarness({ ...runtimeOptions, maxSteps: Number(next) }, routes);
1758
+ await replaceHarness({ ...runtimeOptions, maxSteps: Number(next), unlimitedSteps: false }, routes);
1756
1759
  process.stderr.write(`Step limit updated: ${harness.config.maxSteps} for next turns.
1757
1760
  `);
1758
1761
  continue;
@@ -3718,6 +3721,7 @@ var readPayload = async (config, recordedWorkspace, accessLease) => {
3718
3721
  assertTerminalState(state, `Run ${row.run_id}`);
3719
3722
  return { key: row.run_id, state, updatedAt: row.updated_at_ms };
3720
3723
  });
3724
+ assertTaskBudgetBackupLinks(runs.map((run) => run.state));
3721
3725
  const identities = coordinatorIds(runs);
3722
3726
  const budgetLedgers = allRunRows.flatMap((row) => {
3723
3727
  const state = parseJsonRecord(row.state_json, `Run ${row.run_id}`);
@@ -3975,6 +3979,7 @@ var validateBundleBinding = async (config, bundle) => {
3975
3979
  throw new HarnessStateConflictError(`Run ${run.key} does not match its bound scope and runId.`);
3976
3980
  }
3977
3981
  }
3982
+ assertTaskBudgetBackupLinks(bundle.records.runs.map((run) => validatedRunState(run.state, `Run ${run.key}`)));
3978
3983
  const identities = coordinatorIds(bundle.records.runs);
3979
3984
  const ledgerIdentities = new Set;
3980
3985
  const ledgerKeys = new Set;
@@ -4177,8 +4182,22 @@ var importHarnessStateBackup = async (config, bundle, options = {}) => {
4177
4182
  if (destinationHasState && Object.keys(expectedKeys).some((name) => !setEquals(destinationKeys[name], expectedKeys[name]))) {
4178
4183
  throw new HarnessStateConflictError("State import requires an empty destination or an exactly identical prior import.");
4179
4184
  }
4180
- for (const run of [...bundle.records.runs, ...bundle.records.budgetLedgers ?? []])
4181
- insertOrCompare("zhivex_agent_runs", "run_id = ?", [run.key], "state_json, updated_at_ms", [JSON.stringify(run.state), run.updatedAt], "INSERT INTO zhivex_agent_runs (run_id, state_json, updated_at_ms) VALUES (?, ?, ?)", [run.key, JSON.stringify(run.state), run.updatedAt]);
4185
+ for (const run of [...bundle.records.runs, ...bundle.records.budgetLedgers ?? []]) {
4186
+ const metadata = run.state.metadata;
4187
+ const draftOwner = metadata?.zhivexTaskDraftV1 !== undefined ? metadata.taskDraftOwnerId : undefined;
4188
+ if (metadata?.zhivexTaskDraftV1 !== undefined && (typeof draftOwner !== "string" || !draftOwner))
4189
+ throw new HarnessStateConflictError("TASK_DRAFT_IMPORT_OWNER_REQUIRED");
4190
+ const importingDraft = !options.dryRun && typeof draftOwner === "string" && !database.query("SELECT run_id FROM zhivex_agent_runs WHERE run_id = ?").get(run.key);
4191
+ if (importingDraft)
4192
+ database.query(`INSERT INTO zhivex_agent_runs_leases (run_key, run_id, owner_id, expires_at_ms)
4193
+ VALUES (?, ?, ?, ?) ON CONFLICT(run_key) DO UPDATE SET owner_id=excluded.owner_id, expires_at_ms=excluded.expires_at_ms`).run(run.key, run.state.runId, draftOwner, Date.now() + 30000);
4194
+ try {
4195
+ insertOrCompare("zhivex_agent_runs", "run_id = ?", [run.key], "state_json, updated_at_ms", [JSON.stringify(run.state), run.updatedAt], "INSERT INTO zhivex_agent_runs (run_id, state_json, updated_at_ms) VALUES (?, ?, ?)", [run.key, JSON.stringify(run.state), run.updatedAt]);
4196
+ } finally {
4197
+ if (importingDraft)
4198
+ database.query("DELETE FROM zhivex_agent_runs_leases WHERE run_key = ? AND owner_id = ?").run(run.key, draftOwner);
4199
+ }
4200
+ }
4182
4201
  for (const entry of bundle.records.idempotency)
4183
4202
  insertOrCompare("zhivex_agent_runs_idempotency", "idempotency_key = ?", [entry.key], "run_id, updated_at_ms", [entry.runKey, entry.updatedAt], "INSERT INTO zhivex_agent_runs_idempotency (idempotency_key, run_id, updated_at_ms) VALUES (?, ?, ?)", [entry.key, entry.runKey, entry.updatedAt]);
4184
4203
  for (const entry of bundle.records.parents)
@@ -4469,7 +4488,7 @@ var main = async (argv = process.argv.slice(2)) => {
4469
4488
  parsedOptions = { ...parsedOptions, prompt: await readStdinTask() };
4470
4489
  }
4471
4490
  if (parsedOptions.serviceFile) {
4472
- const { runServiceCli } = await import("./service-client-cli-b52c67hx.js");
4491
+ const { runServiceCli } = await import("./service-client-cli-fn54ev6w.js");
4473
4492
  await runServiceCli(parsedOptions, annotateCliStreamError);
4474
4493
  return;
4475
4494
  }