@zhivex-ai/harness 1.4.0-rc.8 → 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.
- package/CHANGELOG.md +13 -0
- package/README.md +124 -72
- package/SECURITY.md +1 -1
- package/SUPPORT.md +2 -2
- package/dist/acp-cli.js +13 -12
- package/dist/{cli-3bzvq594.js → cli-2h37qyvg.js} +4 -4
- package/dist/{cli-entry-yqwa1943.js → cli-entry-20w6nh0k.js} +321 -16
- package/dist/{cli-entry-25xefnws.js → cli-entry-4ngptr62.js} +3 -3
- package/dist/{cli-entry-qav71mxw.js → cli-entry-w0hterjs.js} +1 -1
- package/dist/cli.js +2 -2
- package/dist/compat/code-support.js +8 -7
- package/dist/{config-pwbnze4g.js → config-j9624t6t.js} +1 -1
- package/dist/{config-depqpsae.js → config-qt69hkqj.js} +4 -3
- package/dist/engine/acp.js +12 -11
- package/dist/engine/client.js +11 -10
- package/dist/engine/desktop-providers-v1.js +2 -1
- package/dist/engine/desktop-state-v1.js +8 -7
- package/dist/engine/index.js +15 -14
- package/dist/engine/mcp-stdio-v1.js +7 -6
- package/dist/engine/protocol.js +12 -0
- package/dist/engine/service.js +12 -11
- package/dist/hostile-repository-demo.js +322 -17
- package/dist/{index-1k248k0w.js → index-5jhgatga.js} +5 -5
- package/dist/{index-pcn2bk8j.js → index-61gthdz6.js} +1 -1
- package/dist/{index-sbzvrpm7.js → index-6dft2vev.js} +2 -2
- package/dist/{index-09zphhwt.js → index-8zjmnyw5.js} +2 -2
- package/dist/{index-txrqqd2r.js → index-937cb7y8.js} +6 -6
- package/dist/{index-jdb1q8yn.js → index-bpc596v3.js} +15 -10
- package/dist/index-fm84men1.js +239 -0
- package/dist/{index-zmx264xy.js → index-m34q25jj.js} +2 -2
- package/dist/index-m49jx72n.js +220 -0
- package/dist/{index-9v72fpya.js → index-m82cfspw.js} +16 -10
- package/dist/{index-ngg2168h.js → index-nmjdwd4p.js} +1 -1
- package/dist/{index-w9pjt7td.js → index-pdmevfxv.js} +3 -3
- package/dist/{index-nqhnh1hz.js → index-pp474137.js} +5 -5
- package/dist/{index-vga76vmb.js → index-rkbf7dqg.js} +2 -2
- package/dist/{index-fny13znr.js → index-s2k2edts.js} +3 -3
- package/dist/{index-7y6b4yjx.js → index-tfzta544.js} +4 -4
- package/dist/index.js +15 -14
- package/dist/providers/vertex-auth.d.ts +5 -1
- package/dist/runtime/error-diagnostics.d.ts +8 -0
- package/dist/runtime/provider-transient.d.ts +33 -0
- package/dist/runtime/time-to-safe-fix.d.ts +8 -0
- package/dist/service-cli.js +12 -11
- package/dist/{service-client-cli-ra3yzvjg.js → service-client-cli-fn54ev6w.js} +3 -3
- package/dist/verify-historical-migrations.js +322 -17
- package/dist/zhx.js +2 -2
- package/docs/CLI.md +1 -1
- package/docs/CODE_RELEASE.md +38 -1
- package/docs/FIRST_USE.md +6 -6
- package/docs/PROJECT_MEMORY.md +1 -1
- package/evaluations/representative-assembly-matrix.json +10 -1
- package/examples/README.md +5 -5
- package/package.json +1 -1
- package/dist/index-8705zxpr.js +0 -145
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
openWorkspaceCheckpointStore
|
|
3
|
-
} from "./index-
|
|
3
|
+
} from "./index-6dft2vev.js";
|
|
4
4
|
import {
|
|
5
5
|
APPROVAL_HISTORY_KEY,
|
|
6
6
|
appendUserMessage,
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
readApprovalDecisions,
|
|
17
17
|
requiresExplicitHostReview,
|
|
18
18
|
runHarness
|
|
19
|
-
} from "./index-
|
|
19
|
+
} from "./index-pp474137.js";
|
|
20
20
|
import {
|
|
21
21
|
ASSISTANT_RESPONSE_KEY,
|
|
22
22
|
SESSION_RUN_STATUSES,
|
|
@@ -25,21 +25,21 @@ import {
|
|
|
25
25
|
cancelHarnessRun,
|
|
26
26
|
inspectUsageLedger,
|
|
27
27
|
openCliSessionStore
|
|
28
|
-
} from "./index-
|
|
28
|
+
} from "./index-s2k2edts.js";
|
|
29
29
|
import {
|
|
30
30
|
createEditProposal,
|
|
31
31
|
editProposalInputSchema,
|
|
32
32
|
fileDigestSchema
|
|
33
|
-
} from "./index-
|
|
33
|
+
} from "./index-m34q25jj.js";
|
|
34
34
|
import {
|
|
35
35
|
CLI_JSON_SCHEMA_VERSION,
|
|
36
36
|
harnessClientRequestSchema
|
|
37
|
-
} from "./index-
|
|
37
|
+
} from "./index-nmjdwd4p.js";
|
|
38
38
|
import {
|
|
39
39
|
HarnessStateConflictError,
|
|
40
40
|
harnessErrorDocument,
|
|
41
41
|
providerStreamDiagnostic
|
|
42
|
-
} from "./index-
|
|
42
|
+
} from "./index-bpc596v3.js";
|
|
43
43
|
|
|
44
44
|
// src/client/continuation.ts
|
|
45
45
|
function terminalContinuationMessages(messages) {
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import {
|
|
2
|
+
classifyProviderFailure,
|
|
3
|
+
providerDiagnostic
|
|
4
|
+
} from "./index-fm84men1.js";
|
|
5
|
+
|
|
1
6
|
// src/runtime/errors.ts
|
|
2
7
|
var HARNESS_ERROR_CODES = [
|
|
3
8
|
"CONFIG_INVALID",
|
|
@@ -117,13 +122,6 @@ var harnessErrorDocument = (error) => {
|
|
|
117
122
|
}
|
|
118
123
|
};
|
|
119
124
|
};
|
|
120
|
-
var numericStatuses = (error) => {
|
|
121
|
-
if (!error || typeof error !== "object")
|
|
122
|
-
return;
|
|
123
|
-
const record = error;
|
|
124
|
-
const values = [record.status, record.statusCode].filter((value) => typeof value === "number" && Number.isSafeInteger(value));
|
|
125
|
-
return values.length > 0 ? values : undefined;
|
|
126
|
-
};
|
|
127
125
|
var normalizeHarnessError = (error) => {
|
|
128
126
|
const diagnostic = providerStreamDiagnostic(error);
|
|
129
127
|
if (diagnostic)
|
|
@@ -131,9 +129,16 @@ var normalizeHarnessError = (error) => {
|
|
|
131
129
|
if (error instanceof HarnessError)
|
|
132
130
|
return error;
|
|
133
131
|
const message = error instanceof Error ? error.message : "Harness execution failed.";
|
|
134
|
-
const
|
|
135
|
-
if (
|
|
136
|
-
|
|
132
|
+
const failure = classifyProviderFailure(error);
|
|
133
|
+
if (failure.retryable) {
|
|
134
|
+
const record = error && typeof error === "object" ? error : {};
|
|
135
|
+
const body = typeof record.responseBody === "string" ? record.responseBody : typeof record.body === "string" ? record.body : undefined;
|
|
136
|
+
const providerError = new HarnessProviderError("Provider request failed.", { cause: error, retryable: true });
|
|
137
|
+
return Object.assign(providerError, {
|
|
138
|
+
...failure.httpStatus !== undefined ? { status: failure.httpStatus } : {},
|
|
139
|
+
...failure.providerStatus ? { providerStatus: failure.providerStatus } : {},
|
|
140
|
+
provider: providerDiagnostic(body, failure.httpStatus)
|
|
141
|
+
});
|
|
137
142
|
}
|
|
138
143
|
const name = error && typeof error === "object" && typeof error.name === "string" ? error.name : "";
|
|
139
144
|
const code = error && typeof error === "object" && typeof error.code === "string" ? error.code : "";
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
// src/runtime/provider-diagnostics.ts
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
var providerDiagnosticSchema = z.strictObject({
|
|
4
|
+
reason: z.enum(["previous_response_unavailable", "context_length_exceeded", "authentication", "payment_required", "permission", "rate_limit", "model_unavailable", "invalid_request", "server_error", "unknown"]),
|
|
5
|
+
parameter: z.enum(["previous_response_id", "input", "messages", "tools", "model", "max_output_tokens", "max_tokens", "temperature", "other", "none"]),
|
|
6
|
+
bodyState: z.enum(["parsed", "malformed", "too_large", "unavailable", "read_timeout"])
|
|
7
|
+
});
|
|
8
|
+
function providerDiagnostic(body, status) {
|
|
9
|
+
let reason = status === 401 ? "authentication" : status === 402 ? "payment_required" : status === 403 ? "permission" : status === 429 ? "rate_limit" : status && status >= 500 ? "server_error" : "unknown";
|
|
10
|
+
let parameter = "none";
|
|
11
|
+
if (typeof body !== "string")
|
|
12
|
+
return { reason, parameter, bodyState: "unavailable" };
|
|
13
|
+
if (Buffer.byteLength(body) > 8192)
|
|
14
|
+
return { reason, parameter, bodyState: "too_large" };
|
|
15
|
+
try {
|
|
16
|
+
const parsed = JSON.parse(body);
|
|
17
|
+
const detail = parsed?.error ?? parsed;
|
|
18
|
+
const code = [detail?.code, detail?.status, detail?.type].find((value) => typeof value === "string") ?? "";
|
|
19
|
+
const message = typeof detail?.message === "string" ? detail.message : "";
|
|
20
|
+
const param = providerDiagnosticSchema.shape.parameter.safeParse(detail?.param);
|
|
21
|
+
parameter = param.success ? param.data : detail?.param == null ? "none" : "other";
|
|
22
|
+
if (/response/i.test(message) && /not found|expired/i.test(message) && (parameter === "previous_response_id" || parameter === "none"))
|
|
23
|
+
reason = "previous_response_unavailable";
|
|
24
|
+
else if (["context_length_exceeded", "context_window_exceeded"].includes(code))
|
|
25
|
+
reason = "context_length_exceeded";
|
|
26
|
+
else if (["invalid_api_key", "authentication_error", "UNAUTHENTICATED"].includes(code))
|
|
27
|
+
reason = "authentication";
|
|
28
|
+
else if (["permission_denied", "permission_error", "PERMISSION_DENIED"].includes(code))
|
|
29
|
+
reason = "permission";
|
|
30
|
+
else if (["rate_limit_exceeded", "rate_limit_error", "RESOURCE_EXHAUSTED"].includes(code))
|
|
31
|
+
reason = "rate_limit";
|
|
32
|
+
else if (["UNAVAILABLE", "DEADLINE_EXCEEDED", "ABORTED", "INTERNAL"].includes(code))
|
|
33
|
+
reason = "server_error";
|
|
34
|
+
else if (["model_not_found", "model_not_available", "NOT_FOUND"].includes(code))
|
|
35
|
+
reason = "model_unavailable";
|
|
36
|
+
else if (["invalid_request_error", "INVALID_ARGUMENT"].includes(code) || status === 400 || status === 422)
|
|
37
|
+
reason = "invalid_request";
|
|
38
|
+
return { reason, parameter, bodyState: "parsed" };
|
|
39
|
+
} catch {
|
|
40
|
+
return { reason, parameter, bodyState: "malformed" };
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// src/runtime/provider-transient.ts
|
|
45
|
+
var PROVIDER_STATUS_CATEGORIES = [
|
|
46
|
+
"ABORTED",
|
|
47
|
+
"RESOURCE_EXHAUSTED",
|
|
48
|
+
"UNAVAILABLE",
|
|
49
|
+
"DEADLINE_EXCEEDED",
|
|
50
|
+
"INTERNAL",
|
|
51
|
+
"STREAM_RESET"
|
|
52
|
+
];
|
|
53
|
+
var VERTEX_TRANSIENT_ATTEMPTS = 3;
|
|
54
|
+
var TRANSIENT_HTTP = {
|
|
55
|
+
408: "DEADLINE_EXCEEDED",
|
|
56
|
+
409: "ABORTED",
|
|
57
|
+
425: "UNAVAILABLE",
|
|
58
|
+
429: "RESOURCE_EXHAUSTED",
|
|
59
|
+
500: "INTERNAL",
|
|
60
|
+
502: "UNAVAILABLE",
|
|
61
|
+
503: "UNAVAILABLE",
|
|
62
|
+
504: "DEADLINE_EXCEEDED"
|
|
63
|
+
};
|
|
64
|
+
var TRANSIENT_GRPC = {
|
|
65
|
+
4: "DEADLINE_EXCEEDED",
|
|
66
|
+
8: "RESOURCE_EXHAUSTED",
|
|
67
|
+
10: "ABORTED",
|
|
68
|
+
13: "INTERNAL",
|
|
69
|
+
14: "UNAVAILABLE"
|
|
70
|
+
};
|
|
71
|
+
var CATEGORY_HTTP = {
|
|
72
|
+
ABORTED: 409,
|
|
73
|
+
RESOURCE_EXHAUSTED: 429,
|
|
74
|
+
UNAVAILABLE: 503,
|
|
75
|
+
DEADLINE_EXCEEDED: 504,
|
|
76
|
+
INTERNAL: 500,
|
|
77
|
+
STREAM_RESET: undefined
|
|
78
|
+
};
|
|
79
|
+
var SYMBOLIC = new Set(["ABORTED", "RESOURCE_EXHAUSTED", "UNAVAILABLE", "DEADLINE_EXCEEDED", "INTERNAL"]);
|
|
80
|
+
var STREAM_RESET_CODES = new Set(["ECONNRESET", "ECONNABORTED", "EPIPE", "ETIMEDOUT", "UND_ERR_SOCKET", "ERR_STREAM_PREMATURE_CLOSE"]);
|
|
81
|
+
var HTTP_IN_MESSAGE = /(?:^|[^\d])(408|409|425|429|500|502|503|504)(?=$|[^\d])/;
|
|
82
|
+
var STREAM_RESET_MESSAGE = /stream reset|RST_STREAM|ECONNRESET|socket hang up|ERR_STREAM_PREMATURE_CLOSE|UND_ERR_SOCKET/i;
|
|
83
|
+
var isProviderStatus = (value) => typeof value === "string" && PROVIDER_STATUS_CATEGORIES.includes(value);
|
|
84
|
+
var httpStatusValue = (value) => typeof value === "number" && Number.isInteger(value) && value >= 100 && value <= 599 ? value : undefined;
|
|
85
|
+
var definitiveClientStatus = (status) => status !== undefined && status >= 400 && status < 500 && TRANSIENT_HTTP[status] === undefined;
|
|
86
|
+
function readProviderFailureRecord(record, depth = 0) {
|
|
87
|
+
let retryable = false;
|
|
88
|
+
let clientError = false;
|
|
89
|
+
let httpStatus;
|
|
90
|
+
let providerStatus;
|
|
91
|
+
const noteHttp = (status) => {
|
|
92
|
+
if (status === undefined)
|
|
93
|
+
return;
|
|
94
|
+
httpStatus ??= status;
|
|
95
|
+
const category = TRANSIENT_HTTP[status];
|
|
96
|
+
if (category) {
|
|
97
|
+
retryable = true;
|
|
98
|
+
providerStatus ??= category;
|
|
99
|
+
} else if (status >= 400 && status < 500)
|
|
100
|
+
clientError = true;
|
|
101
|
+
};
|
|
102
|
+
const noteCategory = (category) => {
|
|
103
|
+
if (!category || clientError)
|
|
104
|
+
return;
|
|
105
|
+
retryable = true;
|
|
106
|
+
providerStatus ??= category;
|
|
107
|
+
if (httpStatus === undefined)
|
|
108
|
+
httpStatus = CATEGORY_HTTP[category];
|
|
109
|
+
};
|
|
110
|
+
const absorb = (value) => {
|
|
111
|
+
if (depth >= 2 || !value || typeof value !== "object" || value === record)
|
|
112
|
+
return;
|
|
113
|
+
const signals = readProviderFailureRecord(value, depth + 1);
|
|
114
|
+
noteHttp(signals.httpStatus);
|
|
115
|
+
noteCategory(signals.providerStatus);
|
|
116
|
+
};
|
|
117
|
+
noteHttp(httpStatusValue(record.status) ?? httpStatusValue(record.statusCode) ?? httpStatusValue(record.httpStatusCode));
|
|
118
|
+
if (typeof record.status === "string" && /^\d{3}$/.test(record.status))
|
|
119
|
+
noteHttp(Number(record.status));
|
|
120
|
+
if (typeof record.code === "number" && record.code >= 100 && record.code <= 599)
|
|
121
|
+
noteHttp(record.code);
|
|
122
|
+
if (typeof record.code === "number" && record.code >= 0 && record.code <= 16)
|
|
123
|
+
noteCategory(TRANSIENT_GRPC[record.code]);
|
|
124
|
+
if (typeof record.code === "string") {
|
|
125
|
+
if (STREAM_RESET_CODES.has(record.code))
|
|
126
|
+
noteCategory("STREAM_RESET");
|
|
127
|
+
else if (SYMBOLIC.has(record.code))
|
|
128
|
+
noteCategory(record.code);
|
|
129
|
+
}
|
|
130
|
+
if (typeof record.status === "string" && SYMBOLIC.has(record.status))
|
|
131
|
+
noteCategory(record.status);
|
|
132
|
+
if (isProviderStatus(record.providerStatus))
|
|
133
|
+
noteCategory(record.providerStatus);
|
|
134
|
+
if (record.diagnosticCode === "VERTEX_STREAM_TOOL_TRUNCATED" || record.reason === "stream_truncated")
|
|
135
|
+
noteCategory("STREAM_RESET");
|
|
136
|
+
if (record.code === "PROVIDER_UNAVAILABLE" && record.retryable === true)
|
|
137
|
+
retryable = true;
|
|
138
|
+
const body = record.responseBody ?? record.body;
|
|
139
|
+
if (!clientError) {
|
|
140
|
+
if (typeof body === "string")
|
|
141
|
+
noteCategory(categoryFromBody(body));
|
|
142
|
+
else
|
|
143
|
+
absorb(body);
|
|
144
|
+
absorb(record.error);
|
|
145
|
+
}
|
|
146
|
+
if (!retryable && !clientError && typeof record.message === "string") {
|
|
147
|
+
const match = record.message.match(HTTP_IN_MESSAGE);
|
|
148
|
+
if (match?.[1])
|
|
149
|
+
noteHttp(Number(match[1]));
|
|
150
|
+
else if (STREAM_RESET_MESSAGE.test(record.message))
|
|
151
|
+
noteCategory("STREAM_RESET");
|
|
152
|
+
}
|
|
153
|
+
if (httpStatus !== undefined && definitiveClientStatus(httpStatus))
|
|
154
|
+
return { retryable: false, httpStatus };
|
|
155
|
+
return { retryable, ...httpStatus !== undefined ? { httpStatus } : {}, ...providerStatus ? { providerStatus } : {} };
|
|
156
|
+
}
|
|
157
|
+
function categoryFromBody(body) {
|
|
158
|
+
if (Buffer.byteLength(body) > 8192)
|
|
159
|
+
return;
|
|
160
|
+
try {
|
|
161
|
+
const parsed = JSON.parse(body);
|
|
162
|
+
if (!parsed || typeof parsed !== "object")
|
|
163
|
+
return;
|
|
164
|
+
const detail = parsed.error;
|
|
165
|
+
const source = detail && typeof detail === "object" ? detail : parsed;
|
|
166
|
+
return readProviderFailureRecord(source).providerStatus;
|
|
167
|
+
} catch {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
function classifyProviderFailure(error) {
|
|
172
|
+
if (error && typeof error === "object") {
|
|
173
|
+
const top = readProviderFailureRecord(error);
|
|
174
|
+
if (top.httpStatus !== undefined && definitiveClientStatus(top.httpStatus))
|
|
175
|
+
return { retryable: false, httpStatus: top.httpStatus };
|
|
176
|
+
}
|
|
177
|
+
const seen = new Set;
|
|
178
|
+
let retryable = false;
|
|
179
|
+
let httpStatus;
|
|
180
|
+
let providerStatus;
|
|
181
|
+
const visit = (current, depth) => {
|
|
182
|
+
if (!current || typeof current !== "object" || depth > 5 || seen.has(current))
|
|
183
|
+
return;
|
|
184
|
+
seen.add(current);
|
|
185
|
+
const record = current;
|
|
186
|
+
const signals = readProviderFailureRecord(record);
|
|
187
|
+
httpStatus ??= signals.httpStatus;
|
|
188
|
+
providerStatus ??= signals.providerStatus;
|
|
189
|
+
if (httpStatus !== undefined && providerStatus === undefined)
|
|
190
|
+
providerStatus = TRANSIENT_HTTP[httpStatus];
|
|
191
|
+
if (record.retryable === false)
|
|
192
|
+
return;
|
|
193
|
+
if (signals.retryable)
|
|
194
|
+
retryable = true;
|
|
195
|
+
visit(record.cause, depth + 1);
|
|
196
|
+
if (record.error && typeof record.error === "object")
|
|
197
|
+
visit(record.error, depth + 1);
|
|
198
|
+
if (record.details && typeof record.details === "object")
|
|
199
|
+
visit(record.details, depth + 1);
|
|
200
|
+
if (Array.isArray(record.chain))
|
|
201
|
+
for (const entry of record.chain)
|
|
202
|
+
visit(entry, depth + 1);
|
|
203
|
+
};
|
|
204
|
+
visit(error, 0);
|
|
205
|
+
if (retryable && httpStatus === undefined && providerStatus)
|
|
206
|
+
httpStatus = CATEGORY_HTTP[providerStatus];
|
|
207
|
+
return { retryable, ...httpStatus !== undefined ? { httpStatus } : {}, ...providerStatus ? { providerStatus } : {} };
|
|
208
|
+
}
|
|
209
|
+
function isRetryableProviderFailure(error) {
|
|
210
|
+
return classifyProviderFailure(error).retryable;
|
|
211
|
+
}
|
|
212
|
+
function transientBackoffMs(attempt, baseMs = 250) {
|
|
213
|
+
const exponential = Math.min(baseMs * 2 ** Math.max(0, attempt), 1e4);
|
|
214
|
+
return exponential + Math.floor(Math.random() * exponential);
|
|
215
|
+
}
|
|
216
|
+
var thoughtOnlyText = (text) => {
|
|
217
|
+
try {
|
|
218
|
+
const parsed = JSON.parse(text);
|
|
219
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
220
|
+
return false;
|
|
221
|
+
const record = parsed;
|
|
222
|
+
return record.thought === true && Object.keys(record).every((key) => key === "thought" || key === "thoughtSignature");
|
|
223
|
+
} catch {
|
|
224
|
+
return false;
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
function isEmptyModelTurn(result) {
|
|
228
|
+
if (result.finishReason === "content-filter" || result.finishReason === "error")
|
|
229
|
+
return false;
|
|
230
|
+
if ((result.images?.length ?? 0) > 0 || (result.audio?.length ?? 0) > 0)
|
|
231
|
+
return false;
|
|
232
|
+
const parts = result.messages?.flatMap((message) => message.parts ?? []) ?? [];
|
|
233
|
+
if (parts.some((part) => part.type === "tool-call" || part.type === "image" || part.type === "audio"))
|
|
234
|
+
return false;
|
|
235
|
+
const texts = [result.text ?? "", ...parts.filter((part) => part.type === "text").map((part) => part.text ?? "")];
|
|
236
|
+
return texts.every((text) => text.trim().length === 0 || thoughtOnlyText(text.trim()));
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
export { providerDiagnosticSchema, providerDiagnostic, PROVIDER_STATUS_CATEGORIES, VERTEX_TRANSIENT_ATTEMPTS, readProviderFailureRecord, classifyProviderFailure, isRetryableProviderFailure, transientBackoffMs, isEmptyModelTurn };
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
HARNESS_EXECUTION_POLICY_VERSION
|
|
3
|
-
} from "./index-
|
|
3
|
+
} from "./index-8zjmnyw5.js";
|
|
4
4
|
import {
|
|
5
5
|
HarnessError,
|
|
6
6
|
HarnessExecutionError,
|
|
7
7
|
HarnessStateConflictError,
|
|
8
8
|
HarnessWorkspaceError
|
|
9
|
-
} from "./index-
|
|
9
|
+
} from "./index-bpc596v3.js";
|
|
10
10
|
|
|
11
11
|
// src/workspace/edit-contracts.ts
|
|
12
12
|
import { createHash } from "node:crypto";
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import {
|
|
2
|
+
VERTEX_TRANSIENT_ATTEMPTS,
|
|
3
|
+
classifyProviderFailure,
|
|
4
|
+
isEmptyModelTurn,
|
|
5
|
+
isRetryableProviderFailure,
|
|
6
|
+
providerDiagnostic,
|
|
7
|
+
providerDiagnosticSchema,
|
|
8
|
+
transientBackoffMs
|
|
9
|
+
} from "./index-fm84men1.js";
|
|
10
|
+
|
|
11
|
+
// src/providers/vertex-auth.ts
|
|
12
|
+
import { GoogleAuth } from "google-auth-library";
|
|
13
|
+
import { createVertex } from "@zhivex-ai/vertex";
|
|
14
|
+
import { wrapLanguageModel } from "@zhivex-ai/core";
|
|
15
|
+
var CLOUD_PLATFORM_SCOPE = "https://www.googleapis.com/auth/cloud-platform";
|
|
16
|
+
function vertexRoute(env) {
|
|
17
|
+
const projectId = (env.GOOGLE_CLOUD_PROJECT ?? "").trim();
|
|
18
|
+
const location = (env.VERTEX_LOCATION ?? "").trim();
|
|
19
|
+
if (!/^(?:[a-z][a-z0-9-]{4,61}[a-z0-9]|[0-9]{6,20})$/.test(projectId)) {
|
|
20
|
+
throw new Error("Vertex requires a valid GOOGLE_CLOUD_PROJECT.");
|
|
21
|
+
}
|
|
22
|
+
if (!/^(?:global|us|eu|[a-z]+-[a-z]+[0-9]+)$/.test(location)) {
|
|
23
|
+
throw new Error("Vertex requires an explicit valid VERTEX_LOCATION.");
|
|
24
|
+
}
|
|
25
|
+
return Object.freeze({ projectId, location });
|
|
26
|
+
}
|
|
27
|
+
function vertexConfigured(env) {
|
|
28
|
+
try {
|
|
29
|
+
vertexRoute(env);
|
|
30
|
+
return true;
|
|
31
|
+
} catch {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
var VERTEX_ENVIRONMENT = ["GOOGLE_CLOUD_PROJECT", "VERTEX_LOCATION", "GOOGLE_APPLICATION_CREDENTIALS"];
|
|
36
|
+
function vertexEnvironment(env) {
|
|
37
|
+
return Object.fromEntries(VERTEX_ENVIRONMENT.flatMap((name) => env[name] ? [[name, env[name]]] : []));
|
|
38
|
+
}
|
|
39
|
+
function vertexTokenSource(env, route, createAuth = (options) => new GoogleAuth(options)) {
|
|
40
|
+
const keyFilename = env.GOOGLE_APPLICATION_CREDENTIALS?.trim();
|
|
41
|
+
const auth = createAuth({
|
|
42
|
+
projectId: route.projectId,
|
|
43
|
+
scopes: [CLOUD_PLATFORM_SCOPE],
|
|
44
|
+
...keyFilename ? { keyFilename } : {}
|
|
45
|
+
});
|
|
46
|
+
return async () => {
|
|
47
|
+
try {
|
|
48
|
+
const token = await auth.getAccessToken();
|
|
49
|
+
if (!token)
|
|
50
|
+
throw new Error("Empty ADC token");
|
|
51
|
+
return token;
|
|
52
|
+
} catch {
|
|
53
|
+
throw new VertexAuthenticationError;
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
class VertexAuthenticationError extends Error {
|
|
59
|
+
status = 401;
|
|
60
|
+
retryable = false;
|
|
61
|
+
constructor() {
|
|
62
|
+
super("Vertex ADC credentials are unavailable or could not be refreshed. Configure Application Default Credentials and retry.");
|
|
63
|
+
this.name = "VertexAuthenticationError";
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function createVertexModel(model, env, createAuth, retry) {
|
|
67
|
+
const route = vertexRoute(env);
|
|
68
|
+
const adapter = createVertex({
|
|
69
|
+
...route,
|
|
70
|
+
getAccessToken: vertexTokenSource(env, route, createAuth)
|
|
71
|
+
})(model);
|
|
72
|
+
const attempts = retry?.attempts ?? VERTEX_TRANSIENT_ATTEMPTS;
|
|
73
|
+
const delayFor = (input) => retry?.delayMs ?? ((attempt) => input.retryBackoffMs === 0 ? 0 : transientBackoffMs(attempt, input.retryBackoffMs ?? 250));
|
|
74
|
+
const generate = async (input) => withVertexAttempts(input.abortSignal, vertexAttemptBudget(input, attempts), delayFor(input), async () => {
|
|
75
|
+
try {
|
|
76
|
+
return await adapter.generate({ ...input, maxRetries: 0 });
|
|
77
|
+
} catch (error) {
|
|
78
|
+
throw safeVertexError(error);
|
|
79
|
+
}
|
|
80
|
+
}, (result) => !isEmptyModelTurn(result));
|
|
81
|
+
const innerStream = adapter.stream?.bind(adapter);
|
|
82
|
+
const retrying = innerStream ? {
|
|
83
|
+
...adapter,
|
|
84
|
+
generate,
|
|
85
|
+
async stream(input) {
|
|
86
|
+
const events = await withVertexAttempts(input.abortSignal, vertexAttemptBudget(input, attempts), delayFor(input), () => collectVertexStream(() => innerStream({ ...input, maxRetries: 0 })), (events2) => !isEmptyVertexStream(events2));
|
|
87
|
+
return replayVertexStream(events);
|
|
88
|
+
}
|
|
89
|
+
} : { ...adapter, generate };
|
|
90
|
+
return wrapLanguageModel(retrying, [{
|
|
91
|
+
name: "harness-vertex-sanitized-errors",
|
|
92
|
+
async wrapGenerate(_context, next) {
|
|
93
|
+
try {
|
|
94
|
+
return await next();
|
|
95
|
+
} catch (error) {
|
|
96
|
+
throw safeVertexError(error);
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
async wrapStream(_context, next) {
|
|
100
|
+
let stream;
|
|
101
|
+
try {
|
|
102
|
+
stream = await next();
|
|
103
|
+
} catch (error) {
|
|
104
|
+
throw safeVertexError(error);
|
|
105
|
+
}
|
|
106
|
+
return async function* () {
|
|
107
|
+
try {
|
|
108
|
+
yield* stream;
|
|
109
|
+
} catch (error) {
|
|
110
|
+
throw safeVertexError(error);
|
|
111
|
+
}
|
|
112
|
+
}();
|
|
113
|
+
}
|
|
114
|
+
}]);
|
|
115
|
+
}
|
|
116
|
+
async function collectVertexStream(next) {
|
|
117
|
+
let stream;
|
|
118
|
+
try {
|
|
119
|
+
stream = await next();
|
|
120
|
+
} catch (error) {
|
|
121
|
+
throw safeVertexError(error);
|
|
122
|
+
}
|
|
123
|
+
const events = [];
|
|
124
|
+
try {
|
|
125
|
+
for await (const event of stream) {
|
|
126
|
+
if (event.type === "error")
|
|
127
|
+
throw safeVertexError(event.error);
|
|
128
|
+
events.push(event);
|
|
129
|
+
}
|
|
130
|
+
} catch (error) {
|
|
131
|
+
throw error instanceof Error && error.message.startsWith("Vertex request failed.") ? error : safeVertexError(error);
|
|
132
|
+
}
|
|
133
|
+
return events;
|
|
134
|
+
}
|
|
135
|
+
function isEmptyVertexStream(events) {
|
|
136
|
+
let text = "";
|
|
137
|
+
let finishReason;
|
|
138
|
+
let tools = false;
|
|
139
|
+
let media = false;
|
|
140
|
+
for (const event of events) {
|
|
141
|
+
if (event.type === "text-delta")
|
|
142
|
+
text += event.textDelta;
|
|
143
|
+
else if (event.type === "tool-call" || event.type === "tool-approval-request")
|
|
144
|
+
tools = true;
|
|
145
|
+
else if (event.type === "image-generation")
|
|
146
|
+
media = true;
|
|
147
|
+
else if (event.type === "finish")
|
|
148
|
+
finishReason = event.finishReason;
|
|
149
|
+
}
|
|
150
|
+
return isEmptyModelTurn({
|
|
151
|
+
text,
|
|
152
|
+
finishReason,
|
|
153
|
+
...tools ? { messages: [{ parts: [{ type: "tool-call" }] }] } : {},
|
|
154
|
+
...media ? { images: [{}] } : {}
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
function replayVertexStream(events) {
|
|
158
|
+
return async function* () {
|
|
159
|
+
yield* events;
|
|
160
|
+
}();
|
|
161
|
+
}
|
|
162
|
+
async function withVertexAttempts(abortSignal, attempts, delayMs, run, accept) {
|
|
163
|
+
let last;
|
|
164
|
+
for (let attempt = 0;attempt < attempts; attempt += 1) {
|
|
165
|
+
if (abortSignal?.aborted)
|
|
166
|
+
throw new DOMException("Vertex request cancelled.", "AbortError");
|
|
167
|
+
try {
|
|
168
|
+
const value = await run();
|
|
169
|
+
if (accept(value) || attempt === attempts - 1)
|
|
170
|
+
return value;
|
|
171
|
+
last = value;
|
|
172
|
+
} catch (error) {
|
|
173
|
+
const safe = error instanceof Error && (error.name === "AbortError" || error.message.startsWith("Vertex request failed.")) ? error : safeVertexError(error);
|
|
174
|
+
if (safe.name === "AbortError" || abortSignal?.aborted || attempt === attempts - 1 || !isRetryableProviderFailure(safe))
|
|
175
|
+
throw safe;
|
|
176
|
+
}
|
|
177
|
+
await sleep(delayMs(attempt));
|
|
178
|
+
}
|
|
179
|
+
return last;
|
|
180
|
+
}
|
|
181
|
+
var sleep = (ms) => ms > 0 ? new Promise((resolve) => setTimeout(resolve, ms)) : Promise.resolve();
|
|
182
|
+
function vertexAttemptBudget(input, fallback) {
|
|
183
|
+
const requested = [
|
|
184
|
+
typeof input.maxProviderRequests === "number" ? input.maxProviderRequests : undefined,
|
|
185
|
+
typeof input.maxRetries === "number" ? input.maxRetries + 1 : undefined
|
|
186
|
+
].filter((value) => value !== undefined);
|
|
187
|
+
if (requested.length === 0)
|
|
188
|
+
return Math.max(1, fallback);
|
|
189
|
+
return Math.max(1, Math.min(...requested));
|
|
190
|
+
}
|
|
191
|
+
function safeVertexError(error) {
|
|
192
|
+
if (error instanceof VertexAuthenticationError)
|
|
193
|
+
return error;
|
|
194
|
+
const record = error && typeof error === "object" ? error : {};
|
|
195
|
+
if (record.name === "AbortError")
|
|
196
|
+
return new DOMException("Vertex request cancelled.", "AbortError");
|
|
197
|
+
const failure = classifyProviderFailure(error);
|
|
198
|
+
const body = providerBody(record.responseBody) ?? providerBody(record.body);
|
|
199
|
+
const preserved = providerDiagnosticSchema.safeParse(record.provider);
|
|
200
|
+
const provider = body !== undefined ? providerDiagnostic(body, failure.httpStatus) : preserved.success ? preserved.data : providerDiagnostic(undefined, failure.httpStatus);
|
|
201
|
+
return Object.assign(new Error("Vertex request failed. Check the sanitized provider diagnosis."), {
|
|
202
|
+
...failure.httpStatus !== undefined ? { status: failure.httpStatus } : {},
|
|
203
|
+
...failure.providerStatus ? { providerStatus: failure.providerStatus } : {},
|
|
204
|
+
provider,
|
|
205
|
+
retryable: failure.retryable
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
function providerBody(value) {
|
|
209
|
+
if (typeof value === "string")
|
|
210
|
+
return value;
|
|
211
|
+
if (!value || typeof value !== "object")
|
|
212
|
+
return;
|
|
213
|
+
try {
|
|
214
|
+
return JSON.stringify(value).slice(0, 8192);
|
|
215
|
+
} catch {
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export { vertexRoute, vertexConfigured, VERTEX_ENVIRONMENT, vertexEnvironment, vertexTokenSource, createVertexModel };
|
|
@@ -1,23 +1,25 @@
|
|
|
1
1
|
import {
|
|
2
2
|
fileDigestSchema
|
|
3
|
-
} from "./index-
|
|
3
|
+
} from "./index-m34q25jj.js";
|
|
4
4
|
import {
|
|
5
5
|
PROVIDERS,
|
|
6
6
|
reasoningEffortSchema
|
|
7
|
-
} from "./index-
|
|
8
|
-
import {
|
|
9
|
-
providerDiagnostic,
|
|
10
|
-
providerDiagnosticSchema
|
|
11
|
-
} from "./index-8705zxpr.js";
|
|
7
|
+
} from "./index-8zjmnyw5.js";
|
|
12
8
|
import {
|
|
13
9
|
CLI_EVENT_SCHEMA_VERSION,
|
|
14
10
|
CLI_JSON_SCHEMA_VERSION
|
|
15
|
-
} from "./index-
|
|
11
|
+
} from "./index-nmjdwd4p.js";
|
|
16
12
|
import {
|
|
17
13
|
HARNESS_ERROR_CODES,
|
|
18
14
|
HARNESS_ERROR_SCHEMA_VERSION,
|
|
19
15
|
HarnessError
|
|
20
|
-
} from "./index-
|
|
16
|
+
} from "./index-bpc596v3.js";
|
|
17
|
+
import {
|
|
18
|
+
PROVIDER_STATUS_CATEGORIES,
|
|
19
|
+
providerDiagnostic,
|
|
20
|
+
providerDiagnosticSchema,
|
|
21
|
+
readProviderFailureRecord
|
|
22
|
+
} from "./index-fm84men1.js";
|
|
21
23
|
|
|
22
24
|
// src/workspace/change-envelope.ts
|
|
23
25
|
import { createHash } from "node:crypto";
|
|
@@ -1245,6 +1247,7 @@ var errorDetailsSchema = z3.strictObject({
|
|
|
1245
1247
|
checkpoint: z3.enum(checkpoints).optional(),
|
|
1246
1248
|
code: z3.enum([...HARNESS_ERROR_CODES, ...systemCodes]).optional(),
|
|
1247
1249
|
provider: providerDiagnosticSchema.optional(),
|
|
1250
|
+
providerStatus: z3.enum(PROVIDER_STATUS_CATEGORIES).optional(),
|
|
1248
1251
|
status: z3.number().int().min(100).max(599).optional(),
|
|
1249
1252
|
retryable: z3.boolean().optional(),
|
|
1250
1253
|
acceptanceReason: z3.enum(acceptanceReasons).optional(),
|
|
@@ -1335,11 +1338,14 @@ var sanitizedErrorDetails = (error) => {
|
|
|
1335
1338
|
const allowedCodes = [...HARNESS_ERROR_CODES, ...systemCodes];
|
|
1336
1339
|
if (allowedCodes.includes(record.code))
|
|
1337
1340
|
entry.code = record.code;
|
|
1338
|
-
const
|
|
1341
|
+
const signals = readProviderFailureRecord(record);
|
|
1342
|
+
const status = [record.status, record.statusCode, record.httpStatusCode, signals.httpStatus].find((value) => typeof value === "number" && Number.isInteger(value) && value >= 100 && value <= 599);
|
|
1339
1343
|
if (typeof status === "number") {
|
|
1340
1344
|
entry.status = status;
|
|
1341
|
-
entry.provider = providerDiagnostic(record.responseBody ?? record.body, status);
|
|
1345
|
+
entry.provider = providerDiagnostic(typeof record.responseBody === "string" || typeof record.body === "string" ? record.responseBody ?? record.body : undefined, status);
|
|
1342
1346
|
}
|
|
1347
|
+
if (signals.providerStatus)
|
|
1348
|
+
entry.providerStatus = signals.providerStatus;
|
|
1343
1349
|
const provider = providerDiagnosticSchema.safeParse(record.provider);
|
|
1344
1350
|
if (provider.success)
|
|
1345
1351
|
entry.provider = provider.data;
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import {
|
|
2
2
|
readRegularFileNoFollow
|
|
3
|
-
} from "./index-
|
|
3
|
+
} from "./index-m34q25jj.js";
|
|
4
4
|
import {
|
|
5
5
|
HarnessConfigError,
|
|
6
6
|
HarnessError,
|
|
7
7
|
HarnessExecutionError,
|
|
8
8
|
HarnessProviderError,
|
|
9
9
|
HarnessWorkspaceError
|
|
10
|
-
} from "./index-
|
|
10
|
+
} from "./index-bpc596v3.js";
|
|
11
11
|
// package.json
|
|
12
12
|
var package_default = {
|
|
13
13
|
name: "@zhivex-ai/harness",
|
|
14
|
-
version: "1.4.0
|
|
14
|
+
version: "1.4.0",
|
|
15
15
|
description: "Governed, provider-portable runtime for coding agents with durable approvals and isolated repository execution.",
|
|
16
16
|
type: "module",
|
|
17
17
|
license: "MIT",
|