@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.
- package/CHANGELOG.md +31 -0
- package/README.md +124 -71
- package/SECURITY.md +1 -1
- package/SUPPORT.md +2 -2
- package/contracts/engine-api.json +55 -0
- package/contracts/stable-api-signatures.json +33 -33
- package/dist/acp-cli.js +18 -15
- package/dist/cli/arguments.d.ts +3 -0
- package/dist/cli/console/console-budget.d.ts +8 -2
- package/dist/{cli-s1rs15vv.js → cli-2h37qyvg.js} +34 -15
- package/dist/{cli-entry-d5788aay.js → cli-entry-20w6nh0k.js} +359 -21
- package/dist/{cli-entry-9c2k0zwz.js → cli-entry-4ngptr62.js} +2902 -1482
- package/dist/{cli-entry-4k1cf0m3.js → cli-entry-w0hterjs.js} +8 -5
- package/dist/cli.js +2 -2
- package/dist/client/json-contracts.d.ts +95 -2
- package/dist/client/local-service.d.ts +2 -2
- package/dist/client/protocol.d.ts +3 -0
- package/dist/client/stream.d.ts +2 -1
- package/dist/compat/code-support.d.ts +6 -0
- package/dist/compat/code-support.js +29 -6
- package/dist/{config-c002f06f.js → config-j9624t6t.js} +1 -1
- package/dist/{config-j3jga5wh.js → config-qt69hkqj.js} +4 -2
- package/dist/engine/acp.js +14 -12
- package/dist/engine/client.js +11 -10
- package/dist/engine/desktop-providers-v1.js +2 -1
- package/dist/engine/desktop-state-v1.js +9 -9
- package/dist/engine/index.js +48 -46
- package/dist/engine/mcp-stdio-v1.js +7 -6
- package/dist/engine/protocol.js +30 -2
- package/dist/engine/service.js +12 -11
- package/dist/hostile-repository-demo.js +4773 -3027
- package/dist/{index-49ys3s4q.js → index-5jhgatga.js} +35 -16
- package/dist/{index-wq2tax80.js → index-61gthdz6.js} +1 -1
- package/dist/index-6dft2vev.js +343 -0
- package/dist/{index-gq9xagx2.js → index-8zjmnyw5.js} +25 -138
- package/dist/index-937cb7y8.js +705 -0
- package/dist/index-bpc596v3.js +154 -0
- package/dist/index-fm84men1.js +239 -0
- package/dist/{index-e6r04a18.js → index-m34q25jj.js} +1127 -170
- package/dist/index-m49jx72n.js +220 -0
- package/dist/{index-dj5z774k.js → index-m82cfspw.js} +35 -16
- package/dist/{index-qfpz5y2v.js → index-nmjdwd4p.js} +8 -2
- package/dist/{index-0g939pfs.js → index-pdmevfxv.js} +10 -7
- package/dist/{index-4j1h4j8c.js → index-pp474137.js} +1598 -973
- package/dist/{index-2tgb2b4e.js → index-rkbf7dqg.js} +3 -5
- package/dist/index-s2k2edts.js +3778 -0
- package/dist/{index-z6br6qdn.js → index-tfzta544.js} +28 -11
- package/dist/index.js +44 -42
- package/dist/persistence/operations.d.ts +3 -0
- package/dist/providers/vertex-auth.d.ts +5 -1
- package/dist/runtime/config.d.ts +8 -0
- package/dist/runtime/context-runtime.d.ts +1 -0
- package/dist/runtime/error-diagnostics.d.ts +8 -0
- package/dist/runtime/errors.d.ts +10 -0
- package/dist/runtime/harness.d.ts +9 -0
- package/dist/runtime/policy-inspection.d.ts +1 -0
- package/dist/runtime/provider-transient.d.ts +33 -0
- package/dist/runtime/runtime-diagnostics.d.ts +3 -0
- package/dist/runtime/runtime-policy.d.ts +8 -10
- package/dist/runtime/task-acceptance-host.d.ts +1 -1
- package/dist/runtime/task-budget-host.d.ts +217 -0
- package/dist/runtime/task-budget.d.ts +147 -0
- package/dist/runtime/task-continuity.d.ts +434 -0
- package/dist/runtime/task-telemetry.d.ts +63 -0
- package/dist/runtime/task-transport.d.ts +3 -0
- package/dist/runtime/task-usage-context.d.ts +13 -0
- package/dist/runtime/time-to-safe-fix.d.ts +8 -0
- package/dist/runtime/usage-ledger.d.ts +17 -0
- package/dist/service-cli.js +12 -11
- package/dist/{service-client-cli-b52c67hx.js → service-client-cli-fn54ev6w.js} +18 -7
- package/dist/verify-historical-migrations.js +2426 -652
- package/dist/zhx.js +2 -2
- package/docs/CLI.md +38 -8
- package/docs/CLIENT_PROTOCOL.md +9 -1
- package/docs/CODE_RELEASE.md +118 -1
- package/docs/DURABLE_OPERATIONS.md +1 -1
- package/docs/EXTENSIBILITY.md +1 -1
- package/docs/FIRST_USE.md +6 -6
- package/docs/MINIMUM_OFFLINE_EVALS.md +31 -0
- package/docs/MINIMUM_TASK_AUTHORITY.md +395 -0
- package/docs/PROJECT_MEMORY.md +1 -1
- package/docs/README.md +2 -0
- package/docs/STABILITY.md +1 -1
- package/docs/WEB_LIMITS.md +117 -0
- package/evaluations/representative-assembly-matrix.json +28 -1
- package/examples/README.md +5 -5
- package/package.json +8 -5
- package/dist/index-8705zxpr.js +0 -145
- package/dist/index-a1q355va.js +0 -600
- package/dist/index-r0tdj04h.js +0 -976
- package/dist/index-rd0s3gqj.js +0 -1669
- package/dist/index-vtqfjnab.js +0 -1626
|
@@ -87,6 +87,8 @@ function providerDiagnostic(body, status) {
|
|
|
87
87
|
reason = "permission";
|
|
88
88
|
else if (["rate_limit_exceeded", "rate_limit_error", "RESOURCE_EXHAUSTED"].includes(code))
|
|
89
89
|
reason = "rate_limit";
|
|
90
|
+
else if (["UNAVAILABLE", "DEADLINE_EXCEEDED", "ABORTED", "INTERNAL"].includes(code))
|
|
91
|
+
reason = "server_error";
|
|
90
92
|
else if (["model_not_found", "model_not_available", "NOT_FOUND"].includes(code))
|
|
91
93
|
reason = "model_unavailable";
|
|
92
94
|
else if (["invalid_request_error", "INVALID_ARGUMENT"].includes(code) || status === 400 || status === 422)
|
|
@@ -97,6 +99,201 @@ function providerDiagnostic(body, status) {
|
|
|
97
99
|
}
|
|
98
100
|
}
|
|
99
101
|
|
|
102
|
+
// src/runtime/provider-transient.ts
|
|
103
|
+
var PROVIDER_STATUS_CATEGORIES = [
|
|
104
|
+
"ABORTED",
|
|
105
|
+
"RESOURCE_EXHAUSTED",
|
|
106
|
+
"UNAVAILABLE",
|
|
107
|
+
"DEADLINE_EXCEEDED",
|
|
108
|
+
"INTERNAL",
|
|
109
|
+
"STREAM_RESET"
|
|
110
|
+
];
|
|
111
|
+
var VERTEX_TRANSIENT_ATTEMPTS = 3;
|
|
112
|
+
var TRANSIENT_HTTP = {
|
|
113
|
+
408: "DEADLINE_EXCEEDED",
|
|
114
|
+
409: "ABORTED",
|
|
115
|
+
425: "UNAVAILABLE",
|
|
116
|
+
429: "RESOURCE_EXHAUSTED",
|
|
117
|
+
500: "INTERNAL",
|
|
118
|
+
502: "UNAVAILABLE",
|
|
119
|
+
503: "UNAVAILABLE",
|
|
120
|
+
504: "DEADLINE_EXCEEDED"
|
|
121
|
+
};
|
|
122
|
+
var TRANSIENT_GRPC = {
|
|
123
|
+
4: "DEADLINE_EXCEEDED",
|
|
124
|
+
8: "RESOURCE_EXHAUSTED",
|
|
125
|
+
10: "ABORTED",
|
|
126
|
+
13: "INTERNAL",
|
|
127
|
+
14: "UNAVAILABLE"
|
|
128
|
+
};
|
|
129
|
+
var CATEGORY_HTTP = {
|
|
130
|
+
ABORTED: 409,
|
|
131
|
+
RESOURCE_EXHAUSTED: 429,
|
|
132
|
+
UNAVAILABLE: 503,
|
|
133
|
+
DEADLINE_EXCEEDED: 504,
|
|
134
|
+
INTERNAL: 500,
|
|
135
|
+
STREAM_RESET: undefined
|
|
136
|
+
};
|
|
137
|
+
var SYMBOLIC = new Set(["ABORTED", "RESOURCE_EXHAUSTED", "UNAVAILABLE", "DEADLINE_EXCEEDED", "INTERNAL"]);
|
|
138
|
+
var STREAM_RESET_CODES = new Set(["ECONNRESET", "ECONNABORTED", "EPIPE", "ETIMEDOUT", "UND_ERR_SOCKET", "ERR_STREAM_PREMATURE_CLOSE"]);
|
|
139
|
+
var HTTP_IN_MESSAGE = /(?:^|[^\d])(408|409|425|429|500|502|503|504)(?=$|[^\d])/;
|
|
140
|
+
var STREAM_RESET_MESSAGE = /stream reset|RST_STREAM|ECONNRESET|socket hang up|ERR_STREAM_PREMATURE_CLOSE|UND_ERR_SOCKET/i;
|
|
141
|
+
var isProviderStatus = (value) => typeof value === "string" && PROVIDER_STATUS_CATEGORIES.includes(value);
|
|
142
|
+
var httpStatusValue = (value) => typeof value === "number" && Number.isInteger(value) && value >= 100 && value <= 599 ? value : undefined;
|
|
143
|
+
var definitiveClientStatus = (status) => status !== undefined && status >= 400 && status < 500 && TRANSIENT_HTTP[status] === undefined;
|
|
144
|
+
function readProviderFailureRecord(record, depth = 0) {
|
|
145
|
+
let retryable = false;
|
|
146
|
+
let clientError = false;
|
|
147
|
+
let httpStatus;
|
|
148
|
+
let providerStatus;
|
|
149
|
+
const noteHttp = (status) => {
|
|
150
|
+
if (status === undefined)
|
|
151
|
+
return;
|
|
152
|
+
httpStatus ??= status;
|
|
153
|
+
const category = TRANSIENT_HTTP[status];
|
|
154
|
+
if (category) {
|
|
155
|
+
retryable = true;
|
|
156
|
+
providerStatus ??= category;
|
|
157
|
+
} else if (status >= 400 && status < 500)
|
|
158
|
+
clientError = true;
|
|
159
|
+
};
|
|
160
|
+
const noteCategory = (category) => {
|
|
161
|
+
if (!category || clientError)
|
|
162
|
+
return;
|
|
163
|
+
retryable = true;
|
|
164
|
+
providerStatus ??= category;
|
|
165
|
+
if (httpStatus === undefined)
|
|
166
|
+
httpStatus = CATEGORY_HTTP[category];
|
|
167
|
+
};
|
|
168
|
+
const absorb = (value) => {
|
|
169
|
+
if (depth >= 2 || !value || typeof value !== "object" || value === record)
|
|
170
|
+
return;
|
|
171
|
+
const signals = readProviderFailureRecord(value, depth + 1);
|
|
172
|
+
noteHttp(signals.httpStatus);
|
|
173
|
+
noteCategory(signals.providerStatus);
|
|
174
|
+
};
|
|
175
|
+
noteHttp(httpStatusValue(record.status) ?? httpStatusValue(record.statusCode) ?? httpStatusValue(record.httpStatusCode));
|
|
176
|
+
if (typeof record.status === "string" && /^\d{3}$/.test(record.status))
|
|
177
|
+
noteHttp(Number(record.status));
|
|
178
|
+
if (typeof record.code === "number" && record.code >= 100 && record.code <= 599)
|
|
179
|
+
noteHttp(record.code);
|
|
180
|
+
if (typeof record.code === "number" && record.code >= 0 && record.code <= 16)
|
|
181
|
+
noteCategory(TRANSIENT_GRPC[record.code]);
|
|
182
|
+
if (typeof record.code === "string") {
|
|
183
|
+
if (STREAM_RESET_CODES.has(record.code))
|
|
184
|
+
noteCategory("STREAM_RESET");
|
|
185
|
+
else if (SYMBOLIC.has(record.code))
|
|
186
|
+
noteCategory(record.code);
|
|
187
|
+
}
|
|
188
|
+
if (typeof record.status === "string" && SYMBOLIC.has(record.status))
|
|
189
|
+
noteCategory(record.status);
|
|
190
|
+
if (isProviderStatus(record.providerStatus))
|
|
191
|
+
noteCategory(record.providerStatus);
|
|
192
|
+
if (record.diagnosticCode === "VERTEX_STREAM_TOOL_TRUNCATED" || record.reason === "stream_truncated")
|
|
193
|
+
noteCategory("STREAM_RESET");
|
|
194
|
+
if (record.code === "PROVIDER_UNAVAILABLE" && record.retryable === true)
|
|
195
|
+
retryable = true;
|
|
196
|
+
const body = record.responseBody ?? record.body;
|
|
197
|
+
if (!clientError) {
|
|
198
|
+
if (typeof body === "string")
|
|
199
|
+
noteCategory(categoryFromBody(body));
|
|
200
|
+
else
|
|
201
|
+
absorb(body);
|
|
202
|
+
absorb(record.error);
|
|
203
|
+
}
|
|
204
|
+
if (!retryable && !clientError && typeof record.message === "string") {
|
|
205
|
+
const match = record.message.match(HTTP_IN_MESSAGE);
|
|
206
|
+
if (match?.[1])
|
|
207
|
+
noteHttp(Number(match[1]));
|
|
208
|
+
else if (STREAM_RESET_MESSAGE.test(record.message))
|
|
209
|
+
noteCategory("STREAM_RESET");
|
|
210
|
+
}
|
|
211
|
+
if (httpStatus !== undefined && definitiveClientStatus(httpStatus))
|
|
212
|
+
return { retryable: false, httpStatus };
|
|
213
|
+
return { retryable, ...httpStatus !== undefined ? { httpStatus } : {}, ...providerStatus ? { providerStatus } : {} };
|
|
214
|
+
}
|
|
215
|
+
function categoryFromBody(body) {
|
|
216
|
+
if (Buffer.byteLength(body) > 8192)
|
|
217
|
+
return;
|
|
218
|
+
try {
|
|
219
|
+
const parsed = JSON.parse(body);
|
|
220
|
+
if (!parsed || typeof parsed !== "object")
|
|
221
|
+
return;
|
|
222
|
+
const detail = parsed.error;
|
|
223
|
+
const source = detail && typeof detail === "object" ? detail : parsed;
|
|
224
|
+
return readProviderFailureRecord(source).providerStatus;
|
|
225
|
+
} catch {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
function classifyProviderFailure(error) {
|
|
230
|
+
if (error && typeof error === "object") {
|
|
231
|
+
const top = readProviderFailureRecord(error);
|
|
232
|
+
if (top.httpStatus !== undefined && definitiveClientStatus(top.httpStatus))
|
|
233
|
+
return { retryable: false, httpStatus: top.httpStatus };
|
|
234
|
+
}
|
|
235
|
+
const seen = new Set;
|
|
236
|
+
let retryable = false;
|
|
237
|
+
let httpStatus;
|
|
238
|
+
let providerStatus;
|
|
239
|
+
const visit = (current, depth) => {
|
|
240
|
+
if (!current || typeof current !== "object" || depth > 5 || seen.has(current))
|
|
241
|
+
return;
|
|
242
|
+
seen.add(current);
|
|
243
|
+
const record = current;
|
|
244
|
+
const signals = readProviderFailureRecord(record);
|
|
245
|
+
httpStatus ??= signals.httpStatus;
|
|
246
|
+
providerStatus ??= signals.providerStatus;
|
|
247
|
+
if (httpStatus !== undefined && providerStatus === undefined)
|
|
248
|
+
providerStatus = TRANSIENT_HTTP[httpStatus];
|
|
249
|
+
if (record.retryable === false)
|
|
250
|
+
return;
|
|
251
|
+
if (signals.retryable)
|
|
252
|
+
retryable = true;
|
|
253
|
+
visit(record.cause, depth + 1);
|
|
254
|
+
if (record.error && typeof record.error === "object")
|
|
255
|
+
visit(record.error, depth + 1);
|
|
256
|
+
if (record.details && typeof record.details === "object")
|
|
257
|
+
visit(record.details, depth + 1);
|
|
258
|
+
if (Array.isArray(record.chain))
|
|
259
|
+
for (const entry of record.chain)
|
|
260
|
+
visit(entry, depth + 1);
|
|
261
|
+
};
|
|
262
|
+
visit(error, 0);
|
|
263
|
+
if (retryable && httpStatus === undefined && providerStatus)
|
|
264
|
+
httpStatus = CATEGORY_HTTP[providerStatus];
|
|
265
|
+
return { retryable, ...httpStatus !== undefined ? { httpStatus } : {}, ...providerStatus ? { providerStatus } : {} };
|
|
266
|
+
}
|
|
267
|
+
function isRetryableProviderFailure(error) {
|
|
268
|
+
return classifyProviderFailure(error).retryable;
|
|
269
|
+
}
|
|
270
|
+
function transientBackoffMs(attempt, baseMs = 250) {
|
|
271
|
+
const exponential = Math.min(baseMs * 2 ** Math.max(0, attempt), 1e4);
|
|
272
|
+
return exponential + Math.floor(Math.random() * exponential);
|
|
273
|
+
}
|
|
274
|
+
var thoughtOnlyText = (text) => {
|
|
275
|
+
try {
|
|
276
|
+
const parsed = JSON.parse(text);
|
|
277
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
278
|
+
return false;
|
|
279
|
+
const record = parsed;
|
|
280
|
+
return record.thought === true && Object.keys(record).every((key) => key === "thought" || key === "thoughtSignature");
|
|
281
|
+
} catch {
|
|
282
|
+
return false;
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
function isEmptyModelTurn(result) {
|
|
286
|
+
if (result.finishReason === "content-filter" || result.finishReason === "error")
|
|
287
|
+
return false;
|
|
288
|
+
if ((result.images?.length ?? 0) > 0 || (result.audio?.length ?? 0) > 0)
|
|
289
|
+
return false;
|
|
290
|
+
const parts = result.messages?.flatMap((message) => message.parts ?? []) ?? [];
|
|
291
|
+
if (parts.some((part) => part.type === "tool-call" || part.type === "image" || part.type === "audio"))
|
|
292
|
+
return false;
|
|
293
|
+
const texts = [result.text ?? "", ...parts.filter((part) => part.type === "text").map((part) => part.text ?? "")];
|
|
294
|
+
return texts.every((text) => text.trim().length === 0 || thoughtOnlyText(text.trim()));
|
|
295
|
+
}
|
|
296
|
+
|
|
100
297
|
// src/providers/vertex-auth.ts
|
|
101
298
|
var CLOUD_PLATFORM_SCOPE = "https://www.googleapis.com/auth/cloud-platform";
|
|
102
299
|
function vertexRoute(env) {
|
|
@@ -146,13 +343,31 @@ class VertexAuthenticationError extends Error {
|
|
|
146
343
|
this.name = "VertexAuthenticationError";
|
|
147
344
|
}
|
|
148
345
|
}
|
|
149
|
-
function createVertexModel(model, env, createAuth) {
|
|
346
|
+
function createVertexModel(model, env, createAuth, retry) {
|
|
150
347
|
const route = vertexRoute(env);
|
|
151
348
|
const adapter = createVertex({
|
|
152
349
|
...route,
|
|
153
350
|
getAccessToken: vertexTokenSource(env, route, createAuth)
|
|
154
351
|
})(model);
|
|
155
|
-
|
|
352
|
+
const attempts = retry?.attempts ?? VERTEX_TRANSIENT_ATTEMPTS;
|
|
353
|
+
const delayFor = (input) => retry?.delayMs ?? ((attempt) => input.retryBackoffMs === 0 ? 0 : transientBackoffMs(attempt, input.retryBackoffMs ?? 250));
|
|
354
|
+
const generate = async (input) => withVertexAttempts(input.abortSignal, vertexAttemptBudget(input, attempts), delayFor(input), async () => {
|
|
355
|
+
try {
|
|
356
|
+
return await adapter.generate({ ...input, maxRetries: 0 });
|
|
357
|
+
} catch (error) {
|
|
358
|
+
throw safeVertexError(error);
|
|
359
|
+
}
|
|
360
|
+
}, (result) => !isEmptyModelTurn(result));
|
|
361
|
+
const innerStream = adapter.stream?.bind(adapter);
|
|
362
|
+
const retrying = innerStream ? {
|
|
363
|
+
...adapter,
|
|
364
|
+
generate,
|
|
365
|
+
async stream(input) {
|
|
366
|
+
const events = await withVertexAttempts(input.abortSignal, vertexAttemptBudget(input, attempts), delayFor(input), () => collectVertexStream(() => innerStream({ ...input, maxRetries: 0 })), (events2) => !isEmptyVertexStream(events2));
|
|
367
|
+
return replayVertexStream(events);
|
|
368
|
+
}
|
|
369
|
+
} : { ...adapter, generate };
|
|
370
|
+
return wrapLanguageModel2(retrying, [{
|
|
156
371
|
name: "harness-vertex-sanitized-errors",
|
|
157
372
|
async wrapGenerate(_context, next) {
|
|
158
373
|
try {
|
|
@@ -178,19 +393,109 @@ function createVertexModel(model, env, createAuth) {
|
|
|
178
393
|
}
|
|
179
394
|
}]);
|
|
180
395
|
}
|
|
396
|
+
async function collectVertexStream(next) {
|
|
397
|
+
let stream;
|
|
398
|
+
try {
|
|
399
|
+
stream = await next();
|
|
400
|
+
} catch (error) {
|
|
401
|
+
throw safeVertexError(error);
|
|
402
|
+
}
|
|
403
|
+
const events = [];
|
|
404
|
+
try {
|
|
405
|
+
for await (const event of stream) {
|
|
406
|
+
if (event.type === "error")
|
|
407
|
+
throw safeVertexError(event.error);
|
|
408
|
+
events.push(event);
|
|
409
|
+
}
|
|
410
|
+
} catch (error) {
|
|
411
|
+
throw error instanceof Error && error.message.startsWith("Vertex request failed.") ? error : safeVertexError(error);
|
|
412
|
+
}
|
|
413
|
+
return events;
|
|
414
|
+
}
|
|
415
|
+
function isEmptyVertexStream(events) {
|
|
416
|
+
let text = "";
|
|
417
|
+
let finishReason;
|
|
418
|
+
let tools = false;
|
|
419
|
+
let media = false;
|
|
420
|
+
for (const event of events) {
|
|
421
|
+
if (event.type === "text-delta")
|
|
422
|
+
text += event.textDelta;
|
|
423
|
+
else if (event.type === "tool-call" || event.type === "tool-approval-request")
|
|
424
|
+
tools = true;
|
|
425
|
+
else if (event.type === "image-generation")
|
|
426
|
+
media = true;
|
|
427
|
+
else if (event.type === "finish")
|
|
428
|
+
finishReason = event.finishReason;
|
|
429
|
+
}
|
|
430
|
+
return isEmptyModelTurn({
|
|
431
|
+
text,
|
|
432
|
+
finishReason,
|
|
433
|
+
...tools ? { messages: [{ parts: [{ type: "tool-call" }] }] } : {},
|
|
434
|
+
...media ? { images: [{}] } : {}
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
function replayVertexStream(events) {
|
|
438
|
+
return async function* () {
|
|
439
|
+
yield* events;
|
|
440
|
+
}();
|
|
441
|
+
}
|
|
442
|
+
async function withVertexAttempts(abortSignal, attempts, delayMs, run, accept) {
|
|
443
|
+
let last;
|
|
444
|
+
for (let attempt = 0;attempt < attempts; attempt += 1) {
|
|
445
|
+
if (abortSignal?.aborted)
|
|
446
|
+
throw new DOMException("Vertex request cancelled.", "AbortError");
|
|
447
|
+
try {
|
|
448
|
+
const value = await run();
|
|
449
|
+
if (accept(value) || attempt === attempts - 1)
|
|
450
|
+
return value;
|
|
451
|
+
last = value;
|
|
452
|
+
} catch (error) {
|
|
453
|
+
const safe = error instanceof Error && (error.name === "AbortError" || error.message.startsWith("Vertex request failed.")) ? error : safeVertexError(error);
|
|
454
|
+
if (safe.name === "AbortError" || abortSignal?.aborted || attempt === attempts - 1 || !isRetryableProviderFailure(safe))
|
|
455
|
+
throw safe;
|
|
456
|
+
}
|
|
457
|
+
await sleep(delayMs(attempt));
|
|
458
|
+
}
|
|
459
|
+
return last;
|
|
460
|
+
}
|
|
461
|
+
var sleep = (ms) => ms > 0 ? new Promise((resolve) => setTimeout(resolve, ms)) : Promise.resolve();
|
|
462
|
+
function vertexAttemptBudget(input, fallback) {
|
|
463
|
+
const requested = [
|
|
464
|
+
typeof input.maxProviderRequests === "number" ? input.maxProviderRequests : undefined,
|
|
465
|
+
typeof input.maxRetries === "number" ? input.maxRetries + 1 : undefined
|
|
466
|
+
].filter((value) => value !== undefined);
|
|
467
|
+
if (requested.length === 0)
|
|
468
|
+
return Math.max(1, fallback);
|
|
469
|
+
return Math.max(1, Math.min(...requested));
|
|
470
|
+
}
|
|
181
471
|
function safeVertexError(error) {
|
|
182
472
|
if (error instanceof VertexAuthenticationError)
|
|
183
473
|
return error;
|
|
184
474
|
const record = error && typeof error === "object" ? error : {};
|
|
185
475
|
if (record.name === "AbortError")
|
|
186
476
|
return new DOMException("Vertex request cancelled.", "AbortError");
|
|
187
|
-
const
|
|
477
|
+
const failure = classifyProviderFailure(error);
|
|
478
|
+
const body = providerBody(record.responseBody) ?? providerBody(record.body);
|
|
479
|
+
const preserved = providerDiagnosticSchema.safeParse(record.provider);
|
|
480
|
+
const provider = body !== undefined ? providerDiagnostic(body, failure.httpStatus) : preserved.success ? preserved.data : providerDiagnostic(undefined, failure.httpStatus);
|
|
188
481
|
return Object.assign(new Error("Vertex request failed. Check the sanitized provider diagnosis."), {
|
|
189
|
-
...
|
|
190
|
-
|
|
191
|
-
|
|
482
|
+
...failure.httpStatus !== undefined ? { status: failure.httpStatus } : {},
|
|
483
|
+
...failure.providerStatus ? { providerStatus: failure.providerStatus } : {},
|
|
484
|
+
provider,
|
|
485
|
+
retryable: failure.retryable
|
|
192
486
|
});
|
|
193
487
|
}
|
|
488
|
+
function providerBody(value) {
|
|
489
|
+
if (typeof value === "string")
|
|
490
|
+
return value;
|
|
491
|
+
if (!value || typeof value !== "object")
|
|
492
|
+
return;
|
|
493
|
+
try {
|
|
494
|
+
return JSON.stringify(value).slice(0, 8192);
|
|
495
|
+
} catch {
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
194
499
|
|
|
195
500
|
// src/providers/qwen-hosted-policy.ts
|
|
196
501
|
import { wrapLanguageModel as wrapLanguageModel3 } from "@zhivex-ai/core";
|
|
@@ -1845,6 +2150,17 @@ function withReasoningEffort(model, value) {
|
|
|
1845
2150
|
}]);
|
|
1846
2151
|
}
|
|
1847
2152
|
|
|
2153
|
+
// src/runtime/task-transport.ts
|
|
2154
|
+
var provenance = Symbol("harness-vetted-task-transport");
|
|
2155
|
+
var capability = Object.freeze({ version: 1 });
|
|
2156
|
+
function markTaskTransportModel(model) {
|
|
2157
|
+
Object.defineProperty(model, provenance, { value: capability, enumerable: true });
|
|
2158
|
+
return model;
|
|
2159
|
+
}
|
|
2160
|
+
function isTaskTransportModel(model) {
|
|
2161
|
+
return Reflect.get(model, provenance) === capability;
|
|
2162
|
+
}
|
|
2163
|
+
|
|
1848
2164
|
// src/runtime/config.ts
|
|
1849
2165
|
import { createHash as createHash2 } from "node:crypto";
|
|
1850
2166
|
import { realpathSync } from "node:fs";
|
|
@@ -1861,6 +2177,18 @@ var HARNESS_ERROR_CODES = [
|
|
|
1861
2177
|
"EXECUTION_FAILED"
|
|
1862
2178
|
];
|
|
1863
2179
|
var HARNESS_ERROR_SCHEMA_VERSION = 1;
|
|
2180
|
+
var providerStreamDiagnostic = (error) => {
|
|
2181
|
+
const seen = new Set;
|
|
2182
|
+
for (let depth = 0;depth < 5 && error && typeof error === "object" && !seen.has(error); depth++) {
|
|
2183
|
+
seen.add(error);
|
|
2184
|
+
const value = error;
|
|
2185
|
+
if (value.provider === "qwen" && value.diagnosticCode === "QWEN_SSE_EVENT_INVALID" && (value.name === "QwenStreamEventError" || value.category === "provider-stream") && (value.transport === "chat" || value.transport === "responses") && (value.reason === "invalid_json" || value.reason === "invalid_event") && value.retryable === false) {
|
|
2186
|
+
return { provider: "qwen", transport: value.transport, diagnosticCode: "QWEN_SSE_EVENT_INVALID", reason: value.reason, retryable: false };
|
|
2187
|
+
}
|
|
2188
|
+
error = value.cause;
|
|
2189
|
+
}
|
|
2190
|
+
return;
|
|
2191
|
+
};
|
|
1864
2192
|
|
|
1865
2193
|
class HarnessError extends Error {
|
|
1866
2194
|
code;
|
|
@@ -1933,30 +2261,35 @@ class HarnessExecutionError extends HarnessError {
|
|
|
1933
2261
|
}
|
|
1934
2262
|
var harnessErrorDocument = (error) => {
|
|
1935
2263
|
const normalized = normalizeHarnessError(error);
|
|
2264
|
+
const diagnostic = providerStreamDiagnostic(error);
|
|
1936
2265
|
return {
|
|
1937
2266
|
schemaVersion: HARNESS_ERROR_SCHEMA_VERSION,
|
|
1938
2267
|
kind: "error",
|
|
1939
2268
|
error: {
|
|
1940
2269
|
code: normalized.code,
|
|
1941
2270
|
category: normalized.category,
|
|
1942
|
-
retryable: normalized.retryable
|
|
2271
|
+
retryable: normalized.retryable,
|
|
2272
|
+
...diagnostic ? { providerDiagnostic: diagnostic } : {}
|
|
1943
2273
|
}
|
|
1944
2274
|
};
|
|
1945
2275
|
};
|
|
1946
|
-
var numericStatuses = (error) => {
|
|
1947
|
-
if (!error || typeof error !== "object")
|
|
1948
|
-
return;
|
|
1949
|
-
const record = error;
|
|
1950
|
-
const values = [record.status, record.statusCode].filter((value) => typeof value === "number" && Number.isSafeInteger(value));
|
|
1951
|
-
return values.length > 0 ? values : undefined;
|
|
1952
|
-
};
|
|
1953
2276
|
var normalizeHarnessError = (error) => {
|
|
2277
|
+
const diagnostic = providerStreamDiagnostic(error);
|
|
2278
|
+
if (diagnostic)
|
|
2279
|
+
return new HarnessProviderError("Provider stream failed.", { cause: error, retryable: false });
|
|
1954
2280
|
if (error instanceof HarnessError)
|
|
1955
2281
|
return error;
|
|
1956
2282
|
const message = error instanceof Error ? error.message : "Harness execution failed.";
|
|
1957
|
-
const
|
|
1958
|
-
if (
|
|
1959
|
-
|
|
2283
|
+
const failure = classifyProviderFailure(error);
|
|
2284
|
+
if (failure.retryable) {
|
|
2285
|
+
const record = error && typeof error === "object" ? error : {};
|
|
2286
|
+
const body = typeof record.responseBody === "string" ? record.responseBody : typeof record.body === "string" ? record.body : undefined;
|
|
2287
|
+
const providerError = new HarnessProviderError("Provider request failed.", { cause: error, retryable: true });
|
|
2288
|
+
return Object.assign(providerError, {
|
|
2289
|
+
...failure.httpStatus !== undefined ? { status: failure.httpStatus } : {},
|
|
2290
|
+
...failure.providerStatus ? { providerStatus: failure.providerStatus } : {},
|
|
2291
|
+
provider: providerDiagnostic(body, failure.httpStatus)
|
|
2292
|
+
});
|
|
1960
2293
|
}
|
|
1961
2294
|
const name = error && typeof error === "object" && typeof error.name === "string" ? error.name : "";
|
|
1962
2295
|
const code = error && typeof error === "object" && typeof error.code === "string" ? error.code : "";
|
|
@@ -2236,12 +2569,15 @@ var resolveHarnessConfig = (input = {}, registry = DEFAULT_PROVIDER_REGISTRY) =>
|
|
|
2236
2569
|
const userId = scopeValue("userId", input.userId ?? process.env.ZHIVEX_HARNESS_USER_ID);
|
|
2237
2570
|
const namespace = scopeValue("namespace", input.namespace ?? process.env.ZHIVEX_HARNESS_NAMESPACE, defaultHarnessNamespace(workspace));
|
|
2238
2571
|
const timeoutMs = integerOption("timeoutMs", input.timeoutMs, process.env.ZHIVEX_HARNESS_TIMEOUT_MS, 15 * 60000, 1000, 24 * 60 * 60000);
|
|
2239
|
-
|
|
2240
|
-
|
|
2572
|
+
for (const key of ["unlimitedTokens", "unlimitedSteps", "unlimitedToolCalls", "unlimitedDuration"]) {
|
|
2573
|
+
if (input[key] !== undefined && typeof input[key] !== "boolean")
|
|
2574
|
+
throw new HarnessConfigError(`${key} must be a boolean.`);
|
|
2241
2575
|
}
|
|
2242
2576
|
const tokenMode = input.unlimitedTokens === undefined ? {} : { unlimitedTokens: input.unlimitedTokens };
|
|
2243
2577
|
const budget = {
|
|
2244
2578
|
...tokenMode,
|
|
2579
|
+
...input.unlimitedSteps === undefined ? {} : { unlimitedSteps: input.unlimitedSteps },
|
|
2580
|
+
...input.unlimitedToolCalls === undefined ? {} : { unlimitedToolCalls: input.unlimitedToolCalls },
|
|
2245
2581
|
maxSteps,
|
|
2246
2582
|
maxToolCalls: integerOption("maxToolCalls", input.maxToolCalls, process.env.ZHIVEX_HARNESS_MAX_TOOL_CALLS, DEFAULT_HARNESS_BUDGET.maxToolCalls, 0, Number.MAX_SAFE_INTEGER),
|
|
2247
2583
|
maxToolErrors: integerOption("maxToolErrors", input.maxToolErrors, process.env.ZHIVEX_HARNESS_MAX_TOOL_ERRORS, DEFAULT_HARNESS_BUDGET.maxToolErrors, 0, 100),
|
|
@@ -2315,6 +2651,7 @@ var resolveHarnessConfig = (input = {}, registry = DEFAULT_PROVIDER_REGISTRY) =>
|
|
|
2315
2651
|
},
|
|
2316
2652
|
maxSteps,
|
|
2317
2653
|
timeoutMs,
|
|
2654
|
+
...input.unlimitedDuration === undefined ? {} : { unlimitedDuration: input.unlimitedDuration },
|
|
2318
2655
|
requireVerifiedDelivery: input.requireVerifiedDelivery ?? false,
|
|
2319
2656
|
budget,
|
|
2320
2657
|
...maxCostUsd === undefined ? {} : {
|
|
@@ -2338,7 +2675,8 @@ var resolveHarnessConfig = (input = {}, registry = DEFAULT_PROVIDER_REGISTRY) =>
|
|
|
2338
2675
|
};
|
|
2339
2676
|
var createProviderModel = (config, env = process.env, registry = DEFAULT_PROVIDER_REGISTRY) => {
|
|
2340
2677
|
try {
|
|
2341
|
-
|
|
2678
|
+
const model = registry.createModel(config, env);
|
|
2679
|
+
return registry === DEFAULT_PROVIDER_REGISTRY && ["anthropic", "openai", "gemini", "vertex", "qwen"].includes(config.provider) ? markTaskTransportModel(model) : model;
|
|
2342
2680
|
} catch (error) {
|
|
2343
2681
|
throw new HarnessProviderError(`Provider ${config.provider} could not be initialized.`, {
|
|
2344
2682
|
cause: error,
|
|
@@ -2347,4 +2685,4 @@ var createProviderModel = (config, env = process.env, registry = DEFAULT_PROVIDE
|
|
|
2347
2685
|
}
|
|
2348
2686
|
};
|
|
2349
2687
|
var providerAvailability = (env = process.env, registry = DEFAULT_PROVIDER_REGISTRY) => registry.availability(env);
|
|
2350
|
-
export { HARNESS_ERROR_CODES, HARNESS_ERROR_SCHEMA_VERSION, HarnessError, HarnessConfigError, HarnessWorkspaceError, HarnessStateConflictError, HarnessProviderError, HarnessExecutionError, harnessErrorDocument, normalizeHarnessError, vertexRoute, vertexConfigured, modelCatalogSchema, bundledModelCatalog, catalogModels, modelDescription, PROVIDERS, createProviderRegistry, BUILTIN_PROVIDER_REGISTRATIONS, DEFAULT_PROVIDER_REGISTRY, PROVIDER_DESCRIPTORS, reasoningEffortSchema, modelReasoningEfforts, withReasoningEffort, DEFAULT_ALLOWED_CHECKS, HARNESS_CONFIG_SCHEMA_VERSION, HARNESS_CONFIG_MIGRATABLE_SCHEMA_VERSIONS, HARNESS_STORE_BACKENDS, HARNESS_EXECUTION_BACKENDS, HARNESS_OCI_RUNTIMES, HARNESS_OCI_SHELL_MODES, HARNESS_EXECUTION_POLICY_VERSION, DEFAULT_OCI_EXECUTION, HARNESS_REQUIRED_CAPABILITIES, HARNESS_SUBAGENT_PROFILES, DEFAULT_HARNESS_MAX_STEPS, DEFAULT_HARNESS_BUDGET, DEFAULT_HARNESS_COMPACTION, DEFAULT_SUBAGENT_BUDGET, migrateHarnessConfigInput, defaultHarnessNamespace, parseProvider, providerDescriptor, resolveHarnessConfig, createProviderModel, providerAvailability };
|
|
2688
|
+
export { HARNESS_ERROR_CODES, HARNESS_ERROR_SCHEMA_VERSION, providerStreamDiagnostic, HarnessError, HarnessConfigError, HarnessWorkspaceError, HarnessStateConflictError, HarnessProviderError, HarnessExecutionError, harnessErrorDocument, normalizeHarnessError, vertexRoute, vertexConfigured, modelCatalogSchema, bundledModelCatalog, catalogModels, modelDescription, PROVIDERS, createProviderRegistry, BUILTIN_PROVIDER_REGISTRATIONS, DEFAULT_PROVIDER_REGISTRY, PROVIDER_DESCRIPTORS, reasoningEffortSchema, modelReasoningEfforts, withReasoningEffort, isTaskTransportModel, DEFAULT_ALLOWED_CHECKS, HARNESS_CONFIG_SCHEMA_VERSION, HARNESS_CONFIG_MIGRATABLE_SCHEMA_VERSIONS, HARNESS_STORE_BACKENDS, HARNESS_EXECUTION_BACKENDS, HARNESS_OCI_RUNTIMES, HARNESS_OCI_SHELL_MODES, HARNESS_EXECUTION_POLICY_VERSION, DEFAULT_OCI_EXECUTION, HARNESS_REQUIRED_CAPABILITIES, HARNESS_SUBAGENT_PROFILES, DEFAULT_HARNESS_MAX_STEPS, DEFAULT_HARNESS_BUDGET, DEFAULT_HARNESS_COMPACTION, DEFAULT_SUBAGENT_BUDGET, migrateHarnessConfigInput, defaultHarnessNamespace, parseProvider, providerDescriptor, resolveHarnessConfig, createProviderModel, providerAvailability };
|