@zhivex-ai/harness 1.3.0-rc.3 → 1.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.
- package/CHANGELOG.md +53 -0
- package/README.md +12 -10
- package/SECURITY.md +1 -1
- package/SUPPORT.md +4 -4
- package/contracts/engine-api.json +334 -0
- package/contracts/public-api.json +267 -1
- package/contracts/stable-api-signatures.json +43 -43
- package/dist/acp-cli.js +54 -18
- package/dist/approvals/approval-history.d.ts +22 -0
- package/dist/approvals/explicit-review.d.ts +24 -0
- package/dist/approvals/host-policy-identity.d.ts +3 -0
- package/dist/cli/arguments.d.ts +6 -2
- package/dist/cli/checkpoints.d.ts +230 -0
- package/dist/cli/cli-profiles.d.ts +4 -2
- package/dist/cli/governance-report.d.ts +5 -0
- package/dist/cli/policy-decisions.d.ts +9 -0
- package/dist/cli/policy.d.ts +5 -0
- package/dist/cli/presentation.d.ts +3 -1
- package/dist/cli/terminal/terminal-ui.d.ts +4 -0
- package/dist/{cli-entry-xmf48p6a.js → cli-entry-1gfg3brj.js} +14921 -10692
- package/dist/cli-entry-bx3vjw7h.js +656 -0
- package/dist/{index-fvca1xea.js → cli-entry-d5788aay.js} +339 -58
- package/dist/{cli-qgwvtk0w.js → cli-etsmtst3.js} +918 -2222
- package/dist/cli.js +3 -5
- package/dist/client/acp-mcp-admission.d.ts +32 -0
- package/dist/client/acp-mcp-host.d.ts +19 -0
- package/dist/client/acp-mcp-session.d.ts +14 -0
- package/dist/client/acp-stdio.d.ts +2 -0
- package/dist/client/acp.d.ts +4 -1
- package/dist/client/adapter.d.ts +13 -1
- package/dist/client/json-contracts.d.ts +107 -4
- package/dist/client/local-service.d.ts +2 -0
- package/dist/client/protocol.d.ts +127 -1
- package/dist/client/service-events.d.ts +4 -0
- package/dist/compat/cli-options.d.ts +13 -1
- package/dist/compat/code-support.js +23 -87
- package/dist/{config-q32jm1e6.js → config-c002f06f.js} +1 -1
- package/dist/{config-6gtpxvjv.js → config-j3jga5wh.js} +3 -1
- package/dist/context/adaptive-compaction.d.ts +1 -0
- package/dist/context/compaction.d.ts +1 -1
- package/dist/context/request-measurements.d.ts +17 -0
- package/dist/context/request-projection.d.ts +10 -0
- package/dist/context/task-memory.d.ts +1 -0
- package/dist/engine/acp.d.ts +2 -0
- package/dist/engine/acp.js +197 -1
- package/dist/engine/client.js +11 -4
- package/dist/engine/desktop-providers-v1.d.ts +4 -0
- package/dist/engine/desktop-providers-v1.js +18 -0
- package/dist/engine/desktop-state-v1.d.ts +10 -0
- package/dist/engine/desktop-state-v1.js +168 -0
- package/dist/engine/index.d.ts +12 -0
- package/dist/engine/index.js +571 -71
- package/dist/engine/mcp-stdio-v1.d.ts +11 -0
- package/dist/engine/mcp-stdio-v1.js +108 -0
- package/dist/engine/models.d.ts +3 -0
- package/dist/engine/models.js +894 -0
- package/dist/engine/protocol.d.ts +1 -0
- package/dist/engine/protocol.js +24 -0
- package/dist/engine/service.js +12 -5
- package/dist/execution/acceptance-snapshot.d.ts +2 -0
- package/dist/execution/execution-environment.d.ts +10 -0
- package/dist/execution/mcp-oci-channel.d.ts +11 -0
- package/dist/execution/mcp-oci-server.d.ts +38 -0
- package/dist/execution/mcp-oci-workspace.d.ts +23 -0
- package/dist/execution/mcp-resource-recovery.d.ts +19 -0
- package/dist/execution/mcp-workspace-snapshot.d.ts +20 -0
- package/dist/hostile-repository-demo.js +3169 -1163
- package/dist/{index-f4sb0e2q.js → index-2jrdcj6b.js} +17 -2
- package/dist/{index-77h9qr5h.js → index-3ah1f369.js} +40 -10
- package/dist/{index-pgqz45fj.js → index-42gp2hy8.js} +197 -1091
- package/dist/{index-41fkzt91.js → index-4jw3tvy8.js} +10 -2
- package/dist/index-6m08wvab.js +1768 -0
- package/dist/index-8705zxpr.js +145 -0
- package/dist/{index-d0wrghff.js → index-8vm2m34s.js} +225 -1416
- package/dist/index-8zzhggxv.js +477 -0
- package/dist/index-a97bezbz.js +1073 -0
- package/dist/index-azmwjp95.js +1004 -0
- package/dist/{cli-entry-0mmeag20.js → index-gq9xagx2.js} +122 -836
- package/dist/index-h0mqx2ed.js +1373 -0
- package/dist/index-hnaxfpb5.js +5589 -0
- package/dist/{index-2aymdsqc.js → index-qfpz5y2v.js} +24 -0
- package/dist/{index-kfgt9yqq.js → index-w2sj0wkw.js} +33 -10
- package/dist/index-wg1sd3at.js +80 -0
- package/dist/index-xqxeypt5.js +888 -0
- package/dist/index-yb239ghk.js +961 -0
- package/dist/index-z0qxmkm2.js +3389 -0
- package/dist/index.js +85 -72
- package/dist/integrations/mcp-host-session.d.ts +26 -0
- package/dist/integrations/mcp-stdio-admission.d.ts +54 -0
- package/dist/integrations/mcp-stdio-client.d.ts +44 -0
- package/dist/integrations/mcp-stdio-framing.d.ts +18 -0
- package/dist/integrations/mcp-stdio-launch.d.ts +20 -0
- package/dist/integrations/mcp-stdio-session.d.ts +7 -0
- package/dist/integrations/mcp-stdio-tools.d.ts +12 -0
- package/dist/internal/desktop/catalog.d.ts +2 -0
- package/dist/internal/desktop/persistence.d.ts +2 -3
- package/dist/internal/desktop/providers.d.ts +1 -0
- package/dist/models/catalog.d.ts +2 -0
- package/dist/persistence/governance-context.d.ts +126 -0
- package/dist/persistence/governance-report.d.ts +299 -0
- package/dist/persistence/host-database-backup.d.ts +28 -0
- package/dist/persistence/mcp-execution-journal.d.ts +19 -0
- package/dist/persistence/mcp-reconciliation.d.ts +33 -0
- package/dist/persistence/mcp-resource-journal.d.ts +54 -0
- package/dist/persistence/workspace-checkpoints.d.ts +138 -0
- package/dist/providers/anthropic-continuation.d.ts +5 -0
- package/dist/providers/providers.d.ts +1 -1
- package/dist/providers/vertex-auth.d.ts +27 -0
- package/dist/runtime/delegation-contracts.d.ts +9 -0
- package/dist/runtime/delegation-correction.d.ts +9 -0
- package/dist/runtime/delegation-result.d.ts +73 -0
- package/dist/runtime/error-diagnostics.d.ts +86 -0
- package/dist/runtime/harness.d.ts +11 -1
- package/dist/runtime/policy-decisions.d.ts +66 -0
- package/dist/runtime/policy-inspection.d.ts +52 -0
- package/dist/runtime/provider-diagnostics.d.ts +1 -0
- package/dist/runtime/runtime-instructions.d.ts +8 -0
- package/dist/runtime/task-acceptance-checks.d.ts +103 -0
- package/dist/runtime/task-acceptance-delivery.d.ts +107 -0
- package/dist/runtime/task-acceptance-host.d.ts +20 -0
- package/dist/runtime/task-acceptance-record.d.ts +107 -0
- package/dist/runtime/task-acceptance-validation.d.ts +25 -0
- package/dist/runtime/task-acceptance.d.ts +47 -0
- package/dist/runtime/time-to-safe-fix.d.ts +83 -0
- package/dist/runtime/tool-policy-file.d.ts +23 -0
- package/dist/runtime/tool-policy-paths.d.ts +5 -0
- package/dist/runtime/tool-policy.d.ts +6 -0
- package/dist/service-cli.js +14 -7
- package/dist/{service-client-cli-gs78wrxe.js → service-client-cli-3365rfav.js} +307 -248
- package/dist/verify-historical-migrations.js +3134 -1129
- package/dist/workspace/path-policy.d.ts +4 -0
- package/dist/zhx.js +3 -5
- package/docs/ACP.md +14 -2
- package/docs/ANTHROPIC.md +33 -0
- package/docs/CLI.md +132 -0
- package/docs/CLIENT_PROTOCOL.md +45 -0
- package/docs/CODE_RELEASE.md +35 -18
- package/docs/ENGINE_API.md +216 -7
- package/docs/EXTENSIBILITY.md +46 -3
- package/docs/FIRST_USE.md +6 -6
- package/docs/LOCAL_SERVICE.md +13 -0
- package/docs/MCP_STDIO.md +20 -0
- package/docs/README.md +1 -0
- package/docs/STABILITY.md +4 -2
- package/docs/SUPPORT_MATRIX.md +1 -1
- package/docs/TOOL_POLICY.md +81 -0
- package/docs/VERTEX.md +50 -0
- package/docs/adr/0002-isolated-mcp-stdio.md +135 -0
- package/docs/fixtures/mcp-stdio-contract-v1.json +189 -0
- package/docs/support-matrix.json +2 -0
- package/evaluations/representative-assembly-matrix.json +46 -1
- package/evaluations/task-acceptance-routes.json +7 -0
- package/examples/README.md +3 -3
- package/package.json +43 -12
- package/dist/cli-entry-64pdp3k5.js +0 -17
- package/dist/cli-entry-7h9savv5.js +0 -375
- package/dist/index-5wjwe91x.js +0 -9434
|
@@ -0,0 +1,477 @@
|
|
|
1
|
+
import {
|
|
2
|
+
captureTaskSources,
|
|
3
|
+
estimateContextTokens,
|
|
4
|
+
measureContext
|
|
5
|
+
} from "./index-42gp2hy8.js";
|
|
6
|
+
import {
|
|
7
|
+
HarnessConfigError
|
|
8
|
+
} from "./index-gq9xagx2.js";
|
|
9
|
+
|
|
10
|
+
// src/tools/tool-registry.ts
|
|
11
|
+
var LOCAL_TOOL_NAMES = new Set([
|
|
12
|
+
"discover_tools",
|
|
13
|
+
"read_tool_result",
|
|
14
|
+
"list_files",
|
|
15
|
+
"read_file",
|
|
16
|
+
"read_files",
|
|
17
|
+
"search_files",
|
|
18
|
+
"search_many",
|
|
19
|
+
"propose_edits",
|
|
20
|
+
"apply_patch",
|
|
21
|
+
"move_file",
|
|
22
|
+
"quarantine_file",
|
|
23
|
+
"restore_file",
|
|
24
|
+
"run_check",
|
|
25
|
+
"git_diff",
|
|
26
|
+
"mutation_audit",
|
|
27
|
+
"load_skill",
|
|
28
|
+
"run_environment_command",
|
|
29
|
+
"run_environment_batch",
|
|
30
|
+
"run_environment_shell",
|
|
31
|
+
"environment_status",
|
|
32
|
+
"apply_reviewed_edits",
|
|
33
|
+
"apply_reviewed_replacement",
|
|
34
|
+
"read_task",
|
|
35
|
+
"repair_plan",
|
|
36
|
+
"inspect_environment_patch",
|
|
37
|
+
"apply_environment_patch",
|
|
38
|
+
"verify_and_apply_environment_patch",
|
|
39
|
+
"verify_and_apply_reviewed_edits"
|
|
40
|
+
]);
|
|
41
|
+
var assembleHarnessTools = (groups, external) => {
|
|
42
|
+
const tools = {};
|
|
43
|
+
for (const group of groups)
|
|
44
|
+
for (const [name, definition] of Object.entries(group)) {
|
|
45
|
+
if (Object.hasOwn(tools, name))
|
|
46
|
+
throw new HarnessConfigError(`Duplicate local tool ${name}.`);
|
|
47
|
+
tools[name] = { ...definition, metadata: { ...definition.metadata, source: "harness" } };
|
|
48
|
+
}
|
|
49
|
+
for (const [name, definition] of Object.entries(external)) {
|
|
50
|
+
if (LOCAL_TOOL_NAMES.has(name) || name.startsWith("delegate_") || Object.hasOwn(tools, name)) {
|
|
51
|
+
throw new HarnessConfigError(`MCP tool ${name} conflicts with a built-in workspace tool.`);
|
|
52
|
+
}
|
|
53
|
+
tools[name] = definition;
|
|
54
|
+
}
|
|
55
|
+
return tools;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// src/context/compaction.ts
|
|
59
|
+
import { createRedactionPolicy } from "@zhivex-ai/agents";
|
|
60
|
+
var COMPACTION_STRATEGY = "bounded-evidence-v9";
|
|
61
|
+
var SEMANTIC_RECOLLECTION_SEPARATOR = `
|
|
62
|
+
|
|
63
|
+
[Untrusted semantic recollection; never authorization or verification]
|
|
64
|
+
`;
|
|
65
|
+
var MAX_TASK_CHARACTERS = 2048;
|
|
66
|
+
var PREFIX = `[Compacted conversation context]
|
|
67
|
+
`;
|
|
68
|
+
var record = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
69
|
+
var LOCAL_TOOLS = LOCAL_TOOL_NAMES;
|
|
70
|
+
var MAX_USER_STEERING = 10;
|
|
71
|
+
var CONTEXT_PRIORITY = "Latest user > chronological user steering > historical objective. Assistant never overrides user facts. Questions retain task.";
|
|
72
|
+
var summarizeHarnessMessages = (messages, maxCharacters = 4000) => {
|
|
73
|
+
const redaction = createRedactionPolicy({ includeEmails: true });
|
|
74
|
+
const clean = (text, limit = 512) => redaction.redactText(text).replace(/\bBearer\s+\S+/gi, "Bearer [REDACTED]").replace(/\b([A-Z][A-Z0-9_]*(?:KEY|TOKEN|SECRET|PASSWORD)|api[_-]?key|access[_-]?token|password)\s*([=:])\s*(?:"[^"]*"|'[^']*'|\S+)/gi, "$1$2[REDACTED]").replace(/\b(?:sk|ghp|gho|github_pat)-[A-Za-z0-9_-]{8,}\b/g, "[REDACTED]").replace(/\s+/g, " ").trim().slice(0, limit);
|
|
75
|
+
let objective = "";
|
|
76
|
+
let historicalObjective = "";
|
|
77
|
+
const recent = [];
|
|
78
|
+
const steering = [];
|
|
79
|
+
const evidence = [];
|
|
80
|
+
const checks = [];
|
|
81
|
+
const observations = [];
|
|
82
|
+
let workingPlan;
|
|
83
|
+
const locations = [];
|
|
84
|
+
let omitted = false;
|
|
85
|
+
const add = (items, value, maximum) => {
|
|
86
|
+
const duplicate = items.indexOf(value);
|
|
87
|
+
if (duplicate >= 0) {
|
|
88
|
+
items.splice(duplicate, 1);
|
|
89
|
+
omitted = true;
|
|
90
|
+
}
|
|
91
|
+
items.push(value);
|
|
92
|
+
if (items.length > maximum) {
|
|
93
|
+
items.shift();
|
|
94
|
+
omitted = true;
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
const rememberObservation = (tool, detail) => {
|
|
98
|
+
if (typeof tool !== "string" || !LOCAL_TOOLS.has(tool) || typeof detail !== "string")
|
|
99
|
+
return;
|
|
100
|
+
const bounded = clean(detail, 640);
|
|
101
|
+
if (!bounded)
|
|
102
|
+
return;
|
|
103
|
+
omitted ||= bounded.length < detail.length;
|
|
104
|
+
const duplicate = observations.findIndex((item) => item.tool === tool && item.detail === bounded);
|
|
105
|
+
if (duplicate >= 0) {
|
|
106
|
+
observations.splice(duplicate, 1);
|
|
107
|
+
omitted = true;
|
|
108
|
+
}
|
|
109
|
+
observations.push({ tool, detail: bounded, unverified: true });
|
|
110
|
+
if (observations.length > 3) {
|
|
111
|
+
observations.shift();
|
|
112
|
+
omitted = true;
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
const safePath = (value) => typeof value === "string" && value.length <= 240 && !value.startsWith("/") && !value.includes("\\") && !value.split("/").some((part) => part === ".." || /^(?:\.env(?:\.|$)|\.npmrc$|id_rsa$|id_ed25519$)|\.(?:key|pem|p12|pfx)$/i.test(part)) ? clean(value, 240) : undefined;
|
|
116
|
+
const addLocation = (value, kind) => {
|
|
117
|
+
const item = record(value);
|
|
118
|
+
const locationKind = kind ?? item.kind;
|
|
119
|
+
const filePath = safePath(item.path);
|
|
120
|
+
const startLine = locationKind === "search" && kind ? item.line : item.startLine;
|
|
121
|
+
const endLine = locationKind === "search" && kind ? item.line : item.endLine;
|
|
122
|
+
if (locationKind !== "read" && locationKind !== "search" || !filePath || typeof item.path !== "string" || /[\x00-\x1f\x7f]/.test(item.path) || typeof item.digest !== "string" || !/^sha256:[a-f0-9]{64}$/.test(item.digest) || !Number.isSafeInteger(startLine) || !Number.isSafeInteger(endLine) || startLine < 1 || endLine < startLine)
|
|
123
|
+
return;
|
|
124
|
+
const location = {
|
|
125
|
+
kind: locationKind,
|
|
126
|
+
path: filePath,
|
|
127
|
+
digest: item.digest,
|
|
128
|
+
startLine,
|
|
129
|
+
endLine,
|
|
130
|
+
...locationKind === "read" && typeof item.clippedLine === "boolean" ? { clippedLine: item.clippedLine } : {}
|
|
131
|
+
};
|
|
132
|
+
for (let i = locations.length - 1;i >= 0; i--) {
|
|
133
|
+
const previous = locations[i];
|
|
134
|
+
if (previous.path === location.path && (previous.digest !== location.digest || previous.kind === location.kind && previous.startLine === location.startLine && previous.endLine === location.endLine)) {
|
|
135
|
+
locations.splice(i, 1);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
locations.push(location);
|
|
139
|
+
if (locations.length > 8) {
|
|
140
|
+
locations.shift();
|
|
141
|
+
omitted = true;
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
const rememberPlan = (value) => {
|
|
145
|
+
const plan = record(value);
|
|
146
|
+
if (typeof plan.hypothesis !== "string" || typeof plan.expectedBehavior !== "string" || typeof plan.nextCheck !== "string")
|
|
147
|
+
return;
|
|
148
|
+
workingPlan = {
|
|
149
|
+
hypothesis: clean(plan.hypothesis, 512),
|
|
150
|
+
expectedBehavior: clean(plan.expectedBehavior, 512),
|
|
151
|
+
nextCheck: clean(plan.nextCheck, 256),
|
|
152
|
+
paths: Array.isArray(plan.paths) ? plan.paths.slice(0, 8).map(safePath).filter((p) => p !== undefined) : []
|
|
153
|
+
};
|
|
154
|
+
};
|
|
155
|
+
for (const message of messages) {
|
|
156
|
+
if (message.role === "system")
|
|
157
|
+
continue;
|
|
158
|
+
for (const part of message.parts) {
|
|
159
|
+
if (part.type === "text") {
|
|
160
|
+
const summaryPrefix = [PREFIX, `[Compacted prior conversation]
|
|
161
|
+
`].find((prefix) => part.text.startsWith(prefix));
|
|
162
|
+
if (summaryPrefix) {
|
|
163
|
+
try {
|
|
164
|
+
const body = part.text.slice(summaryPrefix.length);
|
|
165
|
+
const separator = body.indexOf(SEMANTIC_RECOLLECTION_SEPARATOR);
|
|
166
|
+
const previous = record(JSON.parse(separator < 0 ? body : body.slice(0, separator)));
|
|
167
|
+
if ([COMPACTION_STRATEGY, "bounded-evidence-v8", "bounded-evidence-v7", "bounded-evidence-v6", "bounded-evidence-v5", "bounded-evidence-v4", "bounded-evidence-v3", "bounded-evidence-v2", "bounded-evidence-v1"].includes(String(previous.strategy))) {
|
|
168
|
+
if (!objective) {
|
|
169
|
+
const priorObjective = typeof previous.objective === "string" ? clean(previous.objective, MAX_TASK_CHARACTERS) : "";
|
|
170
|
+
const priorSteering = Array.isArray(previous.steering) ? previous.steering.filter((value) => typeof value === "string") : [];
|
|
171
|
+
objective = [COMPACTION_STRATEGY, "bounded-evidence-v8"].includes(String(previous.strategy)) ? priorObjective : clean(priorSteering.at(-1) ?? priorObjective, MAX_TASK_CHARACTERS);
|
|
172
|
+
historicalObjective = typeof previous.historicalObjective === "string" ? clean(previous.historicalObjective, MAX_TASK_CHARACTERS) : priorObjective !== objective ? priorObjective : "";
|
|
173
|
+
}
|
|
174
|
+
for (const [key, target, count] of [["steering", steering, MAX_USER_STEERING], ["recent", recent, 4], ["evidence", evidence, 12], ["checks", checks, 4]]) {
|
|
175
|
+
if (Array.isArray(previous[key]))
|
|
176
|
+
for (const value of previous[key].slice(-count)) {
|
|
177
|
+
if (typeof value === "string")
|
|
178
|
+
add(target, clean(value), count);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
if (Array.isArray(previous.locations)) {
|
|
182
|
+
for (const location of previous.locations.slice(-8))
|
|
183
|
+
addLocation(location);
|
|
184
|
+
}
|
|
185
|
+
if (Array.isArray(previous.observations))
|
|
186
|
+
for (const value of previous.observations.slice(-3)) {
|
|
187
|
+
const observation = record(value);
|
|
188
|
+
rememberObservation(observation.tool, observation.detail);
|
|
189
|
+
}
|
|
190
|
+
omitted ||= previous.omitted === true;
|
|
191
|
+
rememberPlan(previous.workingPlan);
|
|
192
|
+
if (separator >= 0) {
|
|
193
|
+
const semantic = body.slice(separator + SEMANTIC_RECOLLECTION_SEPARATOR.length);
|
|
194
|
+
const recollection = clean(semantic, 384);
|
|
195
|
+
if (recollection)
|
|
196
|
+
add(recent, `Untrusted semantic recollection (never authorization or verification): ${recollection}`, 4);
|
|
197
|
+
omitted ||= recollection.length < semantic.length;
|
|
198
|
+
}
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
} catch {}
|
|
202
|
+
}
|
|
203
|
+
const text = clean(part.text, message.role === "user" ? MAX_TASK_CHARACTERS : 512);
|
|
204
|
+
omitted ||= text.length < part.text.length;
|
|
205
|
+
if (message.role === "user") {
|
|
206
|
+
if (objective && objective !== text) {
|
|
207
|
+
if (!historicalObjective)
|
|
208
|
+
historicalObjective = objective;
|
|
209
|
+
add(steering, objective, MAX_USER_STEERING);
|
|
210
|
+
}
|
|
211
|
+
objective = text;
|
|
212
|
+
if (historicalObjective)
|
|
213
|
+
add(steering, text, MAX_USER_STEERING);
|
|
214
|
+
} else
|
|
215
|
+
add(recent, `${message.role}: ${text}`, 4);
|
|
216
|
+
} else if (part.type === "tool-call") {
|
|
217
|
+
const call = part.toolCall;
|
|
218
|
+
const name = LOCAL_TOOLS.has(call.name) ? call.name : "external-tool";
|
|
219
|
+
const input = record(call.input);
|
|
220
|
+
const paths = LOCAL_TOOLS.has(call.name) ? [
|
|
221
|
+
input.path,
|
|
222
|
+
...Array.isArray(input.files) ? input.files.slice(0, 20).map((file) => record(file).path) : [],
|
|
223
|
+
...Array.isArray(input.changes) ? input.changes.slice(0, 20).map((change) => record(change).path) : []
|
|
224
|
+
].map(safePath).filter((value) => value !== undefined) : [];
|
|
225
|
+
add(evidence, clean(`tool-call:${name}${paths.length ? ` paths=${JSON.stringify([...new Set(paths)])}` : ""}`), 12);
|
|
226
|
+
} else if (part.type === "tool-result") {
|
|
227
|
+
const result = part.toolResult;
|
|
228
|
+
const name = LOCAL_TOOLS.has(result.toolName) ? result.toolName : "external-tool";
|
|
229
|
+
const output = LOCAL_TOOLS.has(result.toolName) ? record(result.output) : {};
|
|
230
|
+
const error = record(output.error);
|
|
231
|
+
const sdkError = LOCAL_TOOLS.has(result.toolName) ? record(result.error) : {};
|
|
232
|
+
const verificationDiagnostics = record(record(output.verification).diagnostics);
|
|
233
|
+
const diagnostics = [
|
|
234
|
+
sdkError.message,
|
|
235
|
+
error.message,
|
|
236
|
+
typeof output.error === "string" ? output.error : undefined,
|
|
237
|
+
result.isError ? output.message : undefined,
|
|
238
|
+
output.stderr,
|
|
239
|
+
verificationDiagnostics.stderr,
|
|
240
|
+
verificationDiagnostics.stdout,
|
|
241
|
+
...name === "run_check" || name.startsWith("run_environment_") ? [output.stdout] : []
|
|
242
|
+
].filter((value) => typeof value === "string" && value.trim().length > 0);
|
|
243
|
+
if (diagnostics.length)
|
|
244
|
+
rememberObservation(name, diagnostics.join(`
|
|
245
|
+
`));
|
|
246
|
+
if (!result.isError) {
|
|
247
|
+
if (name === "read_file")
|
|
248
|
+
addLocation(output, "read");
|
|
249
|
+
if (name === "read_files" && Array.isArray(output.files)) {
|
|
250
|
+
for (const file of output.files.slice(0, 20))
|
|
251
|
+
addLocation(file, "read");
|
|
252
|
+
}
|
|
253
|
+
if (name === "search_files" && Array.isArray(output.matches)) {
|
|
254
|
+
for (const match of output.matches.slice(0, 8))
|
|
255
|
+
addLocation(match, "search");
|
|
256
|
+
}
|
|
257
|
+
if (name === "search_many" && Array.isArray(output.results)) {
|
|
258
|
+
for (const group of output.results.slice(0, 20)) {
|
|
259
|
+
const matches = record(group).matches;
|
|
260
|
+
if (Array.isArray(matches))
|
|
261
|
+
for (const match of matches.slice(0, 8))
|
|
262
|
+
addLocation(match, "search");
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
const fields = {};
|
|
267
|
+
if (typeof result.isError === "boolean")
|
|
268
|
+
fields.isError = result.isError;
|
|
269
|
+
for (const [key, value] of Object.entries({
|
|
270
|
+
exitCode: output.exitCode,
|
|
271
|
+
timedOut: output.timedOut,
|
|
272
|
+
verificationExitCode: record(output.verification).exitCode
|
|
273
|
+
})) {
|
|
274
|
+
if (key === "timedOut" ? typeof value === "boolean" : Number.isSafeInteger(value))
|
|
275
|
+
fields[key] = value;
|
|
276
|
+
}
|
|
277
|
+
for (const key of ["digest", "patchId"]) {
|
|
278
|
+
if (typeof output[key] === "string" && /^sha256:[a-f0-9]{64}$/.test(output[key]))
|
|
279
|
+
fields[key] = output[key];
|
|
280
|
+
}
|
|
281
|
+
const filePath = safePath(output.path);
|
|
282
|
+
if (filePath)
|
|
283
|
+
fields.path = filePath;
|
|
284
|
+
if (name === "repair_plan" && !result.isError) {
|
|
285
|
+
rememberPlan(output);
|
|
286
|
+
}
|
|
287
|
+
const entry = `tool-result:${name} ${JSON.stringify(fields)}`;
|
|
288
|
+
if (fields.exitCode !== undefined || fields.verificationExitCode !== undefined || fields.isError === true)
|
|
289
|
+
add(checks, entry, 4);
|
|
290
|
+
else
|
|
291
|
+
add(evidence, entry, 12);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
const state = {
|
|
296
|
+
strategy: COMPACTION_STRATEGY,
|
|
297
|
+
contextPriority: CONTEXT_PRIORITY,
|
|
298
|
+
objective,
|
|
299
|
+
...historicalObjective ? { historicalObjective } : {},
|
|
300
|
+
steering,
|
|
301
|
+
recent,
|
|
302
|
+
checks,
|
|
303
|
+
evidence,
|
|
304
|
+
locations,
|
|
305
|
+
...observations.length ? { observations } : {},
|
|
306
|
+
...workingPlan ? { workingPlan } : {},
|
|
307
|
+
omitted
|
|
308
|
+
};
|
|
309
|
+
let compactEnvelope = false;
|
|
310
|
+
const encode = () => JSON.stringify(state, (key, value) => {
|
|
311
|
+
if (compactEnvelope && Array.isArray(value) && !value.length)
|
|
312
|
+
return;
|
|
313
|
+
if (compactEnvelope && key === "contextPriority")
|
|
314
|
+
return "Latest request steers; prior task persists.";
|
|
315
|
+
return value;
|
|
316
|
+
});
|
|
317
|
+
while (encode().length > maxCharacters && (recent.length || evidence.length || checks.length || locations.length || observations.length)) {
|
|
318
|
+
state.omitted = true;
|
|
319
|
+
if (evidence.length)
|
|
320
|
+
evidence.shift();
|
|
321
|
+
else if (recent.length > 1)
|
|
322
|
+
recent.shift();
|
|
323
|
+
else if (observations.length > 1)
|
|
324
|
+
observations.shift();
|
|
325
|
+
else if (locations.length > 1)
|
|
326
|
+
locations.shift();
|
|
327
|
+
else if (checks.length > 1)
|
|
328
|
+
checks.shift();
|
|
329
|
+
else if (recent.length)
|
|
330
|
+
recent.shift();
|
|
331
|
+
else if (observations.length)
|
|
332
|
+
observations.shift();
|
|
333
|
+
else if (checks.length)
|
|
334
|
+
checks.shift();
|
|
335
|
+
else if (locations.length)
|
|
336
|
+
locations.shift();
|
|
337
|
+
else if (state.workingPlan)
|
|
338
|
+
delete state.workingPlan;
|
|
339
|
+
}
|
|
340
|
+
if (encode().length > maxCharacters && state.workingPlan) {
|
|
341
|
+
state.omitted = true;
|
|
342
|
+
delete state.workingPlan;
|
|
343
|
+
}
|
|
344
|
+
if (encode().length > maxCharacters) {
|
|
345
|
+
const duplicate = steering.indexOf(state.objective);
|
|
346
|
+
if (duplicate >= 0) {
|
|
347
|
+
steering.splice(duplicate, 1);
|
|
348
|
+
state.omitted = true;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
if (encode().length > maxCharacters)
|
|
352
|
+
compactEnvelope = true;
|
|
353
|
+
while (encode().length > maxCharacters && state.historicalObjective?.length) {
|
|
354
|
+
state.omitted = true;
|
|
355
|
+
state.historicalObjective = state.historicalObjective.slice(0, Math.max(0, state.historicalObjective.length - 64));
|
|
356
|
+
}
|
|
357
|
+
if (!state.historicalObjective)
|
|
358
|
+
delete state.historicalObjective;
|
|
359
|
+
while (encode().length > maxCharacters && steering.length > 1) {
|
|
360
|
+
state.omitted = true;
|
|
361
|
+
steering.shift();
|
|
362
|
+
}
|
|
363
|
+
while (encode().length > maxCharacters && (state.objective.length || steering[0]?.length)) {
|
|
364
|
+
state.omitted = true;
|
|
365
|
+
if ((steering[0]?.length ?? 0) > state.objective.length) {
|
|
366
|
+
steering[0] = steering[0].slice(0, Math.max(0, steering[0].length - 16));
|
|
367
|
+
} else
|
|
368
|
+
state.objective = state.objective.slice(0, Math.max(0, state.objective.length - 16));
|
|
369
|
+
}
|
|
370
|
+
const summary = encode().length <= maxCharacters ? encode() : "{}".slice(0, maxCharacters);
|
|
371
|
+
return { summary, truncated: state.omitted };
|
|
372
|
+
};
|
|
373
|
+
var sourceRequests = new WeakMap;
|
|
374
|
+
var compactedTaskSources = (messages) => sourceRequests.get(messages);
|
|
375
|
+
var compactMessages = (messages) => {
|
|
376
|
+
if (!messages.length)
|
|
377
|
+
return [];
|
|
378
|
+
const sources = captureTaskSources({ zhivexTaskSources: sourceRequests.get(messages) ?? [] }, messages);
|
|
379
|
+
const compacted = [{ role: "user", parts: [{
|
|
380
|
+
type: "text",
|
|
381
|
+
text: `${PREFIX}${summarizeHarnessMessages(messages).summary}`
|
|
382
|
+
}] }];
|
|
383
|
+
sourceRequests.set(compacted, sources);
|
|
384
|
+
return compacted;
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
// src/context/adaptive-compaction.ts
|
|
388
|
+
var estimateMessages = (messages) => estimateContextTokens(measureContext({ messages: [...messages] }));
|
|
389
|
+
var safeRetentionCuts = (messages) => {
|
|
390
|
+
let systemCount = 0;
|
|
391
|
+
while (messages[systemCount]?.role === "system")
|
|
392
|
+
systemCount++;
|
|
393
|
+
const origins = new Map;
|
|
394
|
+
const crossings = new Array(messages.length + 1).fill(0);
|
|
395
|
+
messages.forEach((message, index) => {
|
|
396
|
+
for (const part of message.parts) {
|
|
397
|
+
let origin, reference;
|
|
398
|
+
if (part.type === "tool-call")
|
|
399
|
+
origin = `tool:${part.toolCall.id}`;
|
|
400
|
+
if (part.type === "tool-result")
|
|
401
|
+
reference = `tool:${part.toolResult.toolCallId}`;
|
|
402
|
+
if (part.type === "provider-data" && part.data && typeof part.data === "object" && !Array.isArray(part.data)) {
|
|
403
|
+
if (part.data.type === "mcp_approval_request" && typeof part.data.id === "string")
|
|
404
|
+
origin = `approval:${part.provider}:${part.data.id}`;
|
|
405
|
+
if (part.data.type === "mcp_approval_response" && typeof part.data.approval_request_id === "string")
|
|
406
|
+
reference = `approval:${part.provider}:${part.data.approval_request_id}`;
|
|
407
|
+
}
|
|
408
|
+
if (origin)
|
|
409
|
+
origins.set(origin, index);
|
|
410
|
+
const from = reference ? origins.get(reference) : undefined;
|
|
411
|
+
if (from !== undefined && from < index) {
|
|
412
|
+
crossings[from + 1]++;
|
|
413
|
+
crossings[index + 1]--;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
const cuts = [];
|
|
418
|
+
let crossingCount = 0;
|
|
419
|
+
for (let cut = 0;cut < messages.length; cut++) {
|
|
420
|
+
crossingCount += crossings[cut];
|
|
421
|
+
if (cut > systemCount && messages[cut].role !== "tool" && crossingCount === 0)
|
|
422
|
+
cuts.push(cut);
|
|
423
|
+
}
|
|
424
|
+
return cuts;
|
|
425
|
+
};
|
|
426
|
+
var createAdaptiveCompaction = (config, options = {}) => {
|
|
427
|
+
let retained = config.keepRecentMessages;
|
|
428
|
+
let systemTokens = 0;
|
|
429
|
+
let protectedTailTokens = 1024;
|
|
430
|
+
let toolTokens = estimateContextTokens(measureContext({ messages: [], ...options.tools ? { tools: options.tools } : {} })) - 64;
|
|
431
|
+
const summaryAllowance = 1500;
|
|
432
|
+
const threshold = () => {
|
|
433
|
+
const remaining = options.remainingInputTokens?.() ?? Infinity;
|
|
434
|
+
return Math.ceil(toolTokens + Math.max(systemTokens + summaryAllowance + protectedTailTokens, Math.min(config.maxEstimatedInputTokens, remaining / 3 - toolTokens)));
|
|
435
|
+
};
|
|
436
|
+
return {
|
|
437
|
+
...options.auxiliary ? { auxiliary: options.auxiliary } : {},
|
|
438
|
+
maxMessages: config.maxMessages,
|
|
439
|
+
get maxEstimatedInputTokens() {
|
|
440
|
+
return threshold();
|
|
441
|
+
},
|
|
442
|
+
get keepRecentMessages() {
|
|
443
|
+
return retained;
|
|
444
|
+
},
|
|
445
|
+
estimateTokens(messages) {
|
|
446
|
+
if (options.selectTools)
|
|
447
|
+
toolTokens = estimateContextTokens(measureContext({ messages: [], tools: options.selectTools(messages) })) - 64;
|
|
448
|
+
const measured = measureContext({ messages: [...messages] });
|
|
449
|
+
systemTokens = Math.ceil(measured.systemCharacters / 3);
|
|
450
|
+
const cuts = safeRetentionCuts(messages);
|
|
451
|
+
const tailCharacters = new Array(messages.length + 1).fill(0);
|
|
452
|
+
for (let i = messages.length - 1;i >= 0; i--)
|
|
453
|
+
tailCharacters[i] = tailCharacters[i + 1] + JSON.stringify(messages[i]).length;
|
|
454
|
+
const newestCut = cuts.at(-1);
|
|
455
|
+
protectedTailTokens = newestCut === undefined ? 1024 : Math.max(1024, Math.ceil(tailCharacters[newestCut] / 3) + 64);
|
|
456
|
+
const target = Math.max(1024, Math.floor(threshold() * 0.65) - toolTokens - systemTokens - summaryAllowance);
|
|
457
|
+
const cut = cuts.find((index) => messages.length - index <= config.keepRecentMessages && Math.ceil(tailCharacters[index] / 3) + 64 <= target) ?? cuts.at(-1);
|
|
458
|
+
retained = cut === undefined ? 1 : Math.max(1, messages.length - cut);
|
|
459
|
+
return estimateContextTokens(measured) + toolTokens;
|
|
460
|
+
},
|
|
461
|
+
compactor: options.compactor ?? (({ messages }) => {
|
|
462
|
+
const sourceCharacters = JSON.stringify(messages).length;
|
|
463
|
+
const budget = Math.max(128, Math.min(4000, sourceCharacters - 128, Math.max(2048, Math.floor(sourceCharacters / 2))));
|
|
464
|
+
const { summary, truncated } = summarizeHarnessMessages(messages, budget);
|
|
465
|
+
return { summary, metadata: {
|
|
466
|
+
strategy: COMPACTION_STRATEGY,
|
|
467
|
+
policy: "adaptive-tokens-v2",
|
|
468
|
+
sourceMessages: messages.length,
|
|
469
|
+
truncated,
|
|
470
|
+
targetRatio: 0.65,
|
|
471
|
+
toolTokens
|
|
472
|
+
} };
|
|
473
|
+
})
|
|
474
|
+
};
|
|
475
|
+
};
|
|
476
|
+
|
|
477
|
+
export { assembleHarnessTools, COMPACTION_STRATEGY, SEMANTIC_RECOLLECTION_SEPARATOR, summarizeHarnessMessages, compactedTaskSources, compactMessages, estimateMessages, createAdaptiveCompaction };
|