@zhivex-ai/harness 1.4.0 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/CHANGELOG.md +29 -10
  2. package/README.md +7 -5
  3. package/SUPPORT.md +2 -2
  4. package/contracts/client-protocol-v1.schema.json +593 -0
  5. package/contracts/engine-api.json +156 -0
  6. package/contracts/public-api.json +12 -0
  7. package/contracts/stable-api-signatures.json +33 -33
  8. package/dist/acp-cli.js +54 -20
  9. package/dist/audit/index.d.ts +3 -0
  10. package/dist/audit/index.js +482 -0
  11. package/dist/audit/pack.d.ts +72 -0
  12. package/dist/audit-pack-e4vaq7np.js +532 -0
  13. package/dist/cli/arguments.d.ts +3 -1
  14. package/dist/cli/audit-pack.d.ts +24 -0
  15. package/dist/cli/cli-credentials.d.ts +6 -0
  16. package/dist/cli/cli-profiles.d.ts +4 -2
  17. package/dist/cli/node-engine.d.ts +2 -0
  18. package/dist/{cli-2h37qyvg.js → cli-1cf4dcnj.js} +245 -642
  19. package/dist/{cli-entry-w0hterjs.js → cli-entry-3s63zn4w.js} +40 -13
  20. package/dist/cli-entry-7f0cen32.js +9990 -0
  21. package/dist/cli-entry-a890x3kq.js +10348 -0
  22. package/dist/{cli-entry-20w6nh0k.js → cli-entry-hdtfef27.js} +439 -19
  23. package/dist/cli-entry-rgs6bxmy.js +484 -0
  24. package/dist/cli.js +27 -2
  25. package/dist/client/json-contracts.d.ts +4 -0
  26. package/dist/client/protocol.d.ts +133 -0
  27. package/dist/client/task-control-host.d.ts +400 -0
  28. package/dist/client/task-projection-host.d.ts +12 -0
  29. package/dist/client/task-projection.d.ts +168 -0
  30. package/dist/compat/code-support.js +28 -22
  31. package/dist/{config-qt69hkqj.js → config-r9fdhce6.js} +3 -3
  32. package/dist/{config-j9624t6t.js → config-vyajmksy.js} +1 -1
  33. package/dist/engine/acp.js +15 -11
  34. package/dist/engine/client.js +14 -10
  35. package/dist/engine/desktop-providers-v1.d.ts +2 -0
  36. package/dist/engine/desktop-providers-v1.js +23 -3
  37. package/dist/engine/desktop-state-v1.js +11 -8
  38. package/dist/engine/index.d.ts +3 -0
  39. package/dist/engine/index.js +101 -554
  40. package/dist/engine/mcp-stdio-v1.js +8 -6
  41. package/dist/engine/models.js +76 -4
  42. package/dist/engine/protocol.d.ts +2 -0
  43. package/dist/engine/protocol.js +110 -0
  44. package/dist/engine/service.js +15 -11
  45. package/dist/hostile-repository-demo.js +1095 -505
  46. package/dist/{index-937cb7y8.js → index-02pqtbbg.js} +559 -33
  47. package/dist/{index-pp474137.js → index-0zs2dz26.js} +766 -931
  48. package/dist/{index-8zjmnyw5.js → index-1265j7t2.js} +73 -6
  49. package/dist/index-4fx5f3k5.js +269 -0
  50. package/dist/{index-nmjdwd4p.js → index-4gt045j0.js} +109 -1
  51. package/dist/{index-6dft2vev.js → index-6599mpmy.js} +5 -3
  52. package/dist/{index-tfzta544.js → index-74kkpyqk.js} +9 -7
  53. package/dist/{index-61gthdz6.js → index-8sm2a1wa.js} +1 -1
  54. package/dist/index-c39197wq.js +552 -0
  55. package/dist/{index-5jhgatga.js → index-crta5wzv.js} +7 -6
  56. package/dist/{index-m34q25jj.js → index-d9zkmhz3.js} +143 -824
  57. package/dist/{index-pdmevfxv.js → index-dtb2c6ds.js} +5 -259
  58. package/dist/index-f6mqa5gk.js +1535 -0
  59. package/dist/index-j6zxnc8m.js +490 -0
  60. package/dist/{index-rkbf7dqg.js → index-mv8sb1ns.js} +5 -3
  61. package/dist/{index-xqxeypt5.js → index-mzydbzp8.js} +76 -4
  62. package/dist/{index-wg1sd3at.js → index-qfsrrnz6.js} +1 -1
  63. package/dist/{index-m82cfspw.js → index-sk3cap35.js} +877 -963
  64. package/dist/index-sstgcsr0.js +511 -0
  65. package/dist/index-wm9xeq1n.js +329 -0
  66. package/dist/index-xdbkcccf.js +719 -0
  67. package/dist/{index-s2k2edts.js → index-zxg4ve4j.js} +41 -1548
  68. package/dist/index.d.ts +3 -0
  69. package/dist/index.js +93 -77
  70. package/dist/internal/desktop/providers.d.ts +2 -0
  71. package/dist/models/catalog.d.ts +2 -0
  72. package/dist/persistence/sqlite-database.d.ts +1 -0
  73. package/dist/providers/azure-openai.d.ts +14 -0
  74. package/dist/providers/bedrock.d.ts +23 -0
  75. package/dist/providers/providers.d.ts +1 -1
  76. package/dist/runtime/durable-review-group.d.ts +33 -0
  77. package/dist/runtime/harness.d.ts +11 -0
  78. package/dist/runtime/run-interruption.d.ts +7 -0
  79. package/dist/runtime/shared-budget.d.ts +30 -0
  80. package/dist/runtime/task-continuity.d.ts +300 -77
  81. package/dist/service-cli.js +15 -11
  82. package/dist/{service-client-cli-fn54ev6w.js → service-client-cli-eqrdc9zq.js} +400 -305
  83. package/dist/verify-historical-migrations.js +1095 -505
  84. package/dist/zhx.js +27 -2
  85. package/docs/AUDIT_PACK.md +99 -0
  86. package/docs/AZURE_OPENAI.md +53 -0
  87. package/docs/BEDROCK.md +56 -0
  88. package/docs/CLI.md +15 -0
  89. package/docs/CLIENT_PROTOCOL.md +178 -0
  90. package/docs/CODE_RELEASE.md +31 -1
  91. package/docs/CODE_WEB_TASKS.md +116 -0
  92. package/docs/CONTEXT_ENGINEERING.md +59 -0
  93. package/docs/CREDENTIALS.md +21 -0
  94. package/docs/DURABLE_OPERATIONS.md +93 -1
  95. package/docs/ENGINE_API.md +5 -2
  96. package/docs/EXTENSIBILITY.md +2 -2
  97. package/docs/FIRST_USE.md +6 -6
  98. package/docs/MINIMUM_TASK_AUTHORITY.md +3 -3
  99. package/docs/PROJECT_MEMORY.md +1 -1
  100. package/docs/README.md +6 -1
  101. package/docs/STABILITY.md +3 -1
  102. package/docs/SUPPORT_MATRIX.md +1 -1
  103. package/docs/SUPPORT_MATRIX_1_1.md +1 -1
  104. package/docs/USAGE.md +3 -1
  105. package/docs/VERTEX.md +2 -2
  106. package/docs/WEB_LIMITS.md +4 -3
  107. package/docs/adr/0002-isolated-mcp-stdio.md +6 -3
  108. package/docs/support-matrix-1.1.json +3 -1
  109. package/docs/support-matrix.json +6 -4
  110. package/evaluations/code-task-ui.json +20 -0
  111. package/evaluations/representative-assembly-matrix.json +10 -1
  112. package/evaluations/task-projection.json +10 -0
  113. package/evaluations/task-recovery-lab.json +60 -0
  114. package/examples/README.md +3 -3
  115. package/package.json +23 -13
  116. package/dist/cli-entry-4ngptr62.js +0 -19900
  117. package/dist/index-m49jx72n.js +0 -220
@@ -0,0 +1,552 @@
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
+ // src/providers/azure-openai.ts
221
+ import { createAzureOpenAI } from "@zhivex-ai/azure-openai";
222
+ import { wrapLanguageModel as wrapLanguageModel2 } from "@zhivex-ai/core";
223
+ var AZURE_OPENAI_TRANSPORT_ENVIRONMENT = [
224
+ "AZURE_OPENAI_ENDPOINT",
225
+ "AZURE_OPENAI_API_VERSION",
226
+ "AZURE_OPENAI_DEPLOYMENTS"
227
+ ];
228
+ var API_VERSION = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
229
+ var DEPLOYMENT_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
230
+ var MODEL_ID = /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,159}$/;
231
+ function azureOpenAIEndpoint(env) {
232
+ const value = env.AZURE_OPENAI_ENDPOINT?.trim() ?? "";
233
+ if (!value)
234
+ throw new Error("Azure OpenAI requires AZURE_OPENAI_ENDPOINT.");
235
+ let url;
236
+ try {
237
+ url = new URL(value);
238
+ } catch {
239
+ throw new Error("AZURE_OPENAI_ENDPOINT must be an https URL.");
240
+ }
241
+ if (url.protocol !== "https:" || url.username || url.password || url.hash || url.search) {
242
+ throw new Error("AZURE_OPENAI_ENDPOINT must be an https URL without credentials or a query.");
243
+ }
244
+ return url.toString().replace(/\/+$/, "");
245
+ }
246
+ function azureOpenAIApiVersion(env) {
247
+ const value = env.AZURE_OPENAI_API_VERSION?.trim() ?? "";
248
+ if (!value)
249
+ return;
250
+ if (!API_VERSION.test(value))
251
+ throw new Error("AZURE_OPENAI_API_VERSION is invalid.");
252
+ return value;
253
+ }
254
+ function azureOpenAIDeployments(env) {
255
+ const raw = env.AZURE_OPENAI_DEPLOYMENTS?.trim() ?? "";
256
+ if (!raw)
257
+ return Object.freeze({});
258
+ if (raw.length > 8192)
259
+ throw new Error("AZURE_OPENAI_DEPLOYMENTS is too large.");
260
+ let parsed;
261
+ try {
262
+ parsed = JSON.parse(raw);
263
+ } catch {
264
+ throw new Error("AZURE_OPENAI_DEPLOYMENTS must be a JSON object.");
265
+ }
266
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
267
+ throw new Error("AZURE_OPENAI_DEPLOYMENTS must be a JSON object.");
268
+ }
269
+ const entries = Object.entries(parsed);
270
+ if (entries.length > 32)
271
+ throw new Error("AZURE_OPENAI_DEPLOYMENTS lists too many deployments.");
272
+ const deployments = {};
273
+ for (const [name, value] of entries) {
274
+ if (!DEPLOYMENT_NAME.test(name))
275
+ throw new Error("AZURE_OPENAI_DEPLOYMENTS contains an invalid deployment name.");
276
+ const model = typeof value === "string" ? value : value && typeof value === "object" && !Array.isArray(value) && typeof value.model === "string" ? value.model : "";
277
+ const normalized = model.trim();
278
+ if (!MODEL_ID.test(normalized))
279
+ throw new Error("AZURE_OPENAI_DEPLOYMENTS contains an invalid base model.");
280
+ deployments[name] = Object.freeze({ model: normalized });
281
+ }
282
+ return Object.freeze(deployments);
283
+ }
284
+ function azureOpenAIConfigured(env) {
285
+ try {
286
+ azureOpenAIEndpoint(env);
287
+ azureOpenAIApiVersion(env);
288
+ azureOpenAIDeployments(env);
289
+ return Boolean(env.AZURE_OPENAI_API_KEY?.trim());
290
+ } catch {
291
+ return false;
292
+ }
293
+ }
294
+ function azureOpenAIEnvironment(env, secret) {
295
+ const picked = {};
296
+ for (const name of [...AZURE_OPENAI_TRANSPORT_ENVIRONMENT, "AZURE_OPENAI_API_KEY"]) {
297
+ const value = env[name]?.trim();
298
+ if (value)
299
+ picked[name] = value;
300
+ }
301
+ if (secret && !picked.AZURE_OPENAI_API_KEY)
302
+ picked.AZURE_OPENAI_API_KEY = secret;
303
+ return picked;
304
+ }
305
+ function createAzureOpenAIModel(model, env) {
306
+ const endpoint = azureOpenAIEndpoint(env);
307
+ const apiVersion = azureOpenAIApiVersion(env);
308
+ const deployments = azureOpenAIDeployments(env);
309
+ const apiKey = env.AZURE_OPENAI_API_KEY?.trim();
310
+ if (!apiKey)
311
+ throw new Error("Missing credentials for azure-openai. Set AZURE_OPENAI_API_KEY in the environment.");
312
+ const settings = {
313
+ apiKey,
314
+ endpoint,
315
+ ...apiVersion ? { apiVersion } : {},
316
+ ...Object.keys(deployments).length ? { deployments } : {}
317
+ };
318
+ const azure = apiVersion ? createAzureOpenAI(settings) : withoutProcessEnv(["AZURE_OPENAI_API_VERSION"], () => createAzureOpenAI(settings));
319
+ const deployed = sanitizeAzureModel(azure(model), apiKey);
320
+ const baseModel = deployments[model]?.model;
321
+ if (!baseModel || baseModel === model)
322
+ return deployed;
323
+ return withBaseModelCapabilities(deployed, azure(baseModel));
324
+ }
325
+ function withoutProcessEnv(names, run) {
326
+ const saved = new Map;
327
+ for (const name of names) {
328
+ saved.set(name, process.env[name]);
329
+ delete process.env[name];
330
+ }
331
+ try {
332
+ return run();
333
+ } finally {
334
+ for (const [name, value] of saved) {
335
+ if (value === undefined)
336
+ delete process.env[name];
337
+ else
338
+ process.env[name] = value;
339
+ }
340
+ }
341
+ }
342
+ function withBaseModelCapabilities(deployed, reference) {
343
+ return new Proxy(deployed, {
344
+ get(target, property, receiver) {
345
+ if (property === "capabilities")
346
+ return reference.capabilities;
347
+ const value = Reflect.get(target, property, receiver);
348
+ return typeof value === "function" ? value.bind(target) : value;
349
+ }
350
+ });
351
+ }
352
+ function sanitizeAzureModel(model, secret) {
353
+ const clean = (error) => {
354
+ if (error instanceof Error && error.name === "AbortError") {
355
+ return new DOMException("Azure OpenAI request cancelled.", "AbortError");
356
+ }
357
+ const record = error && typeof error === "object" ? error : {};
358
+ const safe = new Error("Azure OpenAI request failed. Check the endpoint, deployment, and credentials.");
359
+ if (secret && safe.message.includes(secret))
360
+ safe.message = safe.message.split(secret).join("[REDACTED]");
361
+ if (typeof record.status === "number")
362
+ Object.assign(safe, { status: record.status });
363
+ if (typeof record.retryable === "boolean")
364
+ Object.assign(safe, { retryable: record.retryable });
365
+ return safe;
366
+ };
367
+ return wrapLanguageModel2(model, [{
368
+ name: "harness-azure-openai-sanitized-errors",
369
+ async wrapGenerate(_context, next) {
370
+ try {
371
+ return await next();
372
+ } catch (error) {
373
+ throw clean(error);
374
+ }
375
+ },
376
+ async wrapStream(_context, next) {
377
+ let stream;
378
+ try {
379
+ stream = await next();
380
+ } catch (error) {
381
+ throw clean(error);
382
+ }
383
+ return async function* () {
384
+ try {
385
+ for await (const event of stream) {
386
+ if (event.type === "error")
387
+ throw clean(event.error);
388
+ yield event;
389
+ }
390
+ } catch (error) {
391
+ throw clean(error);
392
+ }
393
+ }();
394
+ }
395
+ }]);
396
+ }
397
+
398
+ // src/providers/bedrock.ts
399
+ import { createBedrock } from "@zhivex-ai/bedrock";
400
+ import { wrapLanguageModel as wrapLanguageModel3 } from "@zhivex-ai/core";
401
+ var BEDROCK_TRANSPORT_ENVIRONMENT = [
402
+ "AWS_REGION",
403
+ "AWS_DEFAULT_REGION",
404
+ "AWS_PROFILE",
405
+ "BEDROCK_RUNTIME",
406
+ "BEDROCK_OPENAI_BASE_URL"
407
+ ];
408
+ var BEDROCK_CREDENTIAL_ENVIRONMENT = [
409
+ "BEDROCK_API_KEY",
410
+ "AWS_BEARER_TOKEN_BEDROCK"
411
+ ];
412
+ var REGION = /^[a-z]{2}(?:-[a-z0-9]+){1,3}$/;
413
+ function bedrockRuntime(env) {
414
+ const value = env.BEDROCK_RUNTIME?.trim() ?? "";
415
+ if (!value || value === "converse")
416
+ return "converse";
417
+ if (value === "openai")
418
+ return "openai";
419
+ throw new Error("BEDROCK_RUNTIME must be converse or openai.");
420
+ }
421
+ function bedrockRegion(env) {
422
+ const region = env.AWS_REGION?.trim() || env.AWS_DEFAULT_REGION?.trim() || "";
423
+ if (!REGION.test(region)) {
424
+ throw new Error("Bedrock requires a valid AWS_REGION or AWS_DEFAULT_REGION.");
425
+ }
426
+ return region;
427
+ }
428
+ function bedrockOpenAIBaseURL(env) {
429
+ const baseURL = env.BEDROCK_OPENAI_BASE_URL?.trim() ?? "";
430
+ if (!baseURL)
431
+ throw new Error("Bedrock OpenAI-compatible runtime requires BEDROCK_OPENAI_BASE_URL.");
432
+ let url;
433
+ try {
434
+ url = new URL(baseURL);
435
+ } catch {
436
+ throw new Error("BEDROCK_OPENAI_BASE_URL must be an https URL.");
437
+ }
438
+ if (url.protocol !== "https:" || url.username || url.password || url.hash) {
439
+ throw new Error("BEDROCK_OPENAI_BASE_URL must be an https URL without credentials.");
440
+ }
441
+ return url.toString().replace(/\/+$/, "");
442
+ }
443
+ function openAIRoute(env) {
444
+ const apiKey = env.BEDROCK_API_KEY?.trim() || env.AWS_BEARER_TOKEN_BEDROCK?.trim() || "";
445
+ if (!apiKey) {
446
+ throw new Error("Bedrock OpenAI-compatible runtime requires BEDROCK_API_KEY or AWS_BEARER_TOKEN_BEDROCK.");
447
+ }
448
+ return { apiKey, baseURL: bedrockOpenAIBaseURL(env) };
449
+ }
450
+ function bedrockConfigured(env) {
451
+ try {
452
+ if (bedrockRuntime(env) === "openai") {
453
+ openAIRoute(env);
454
+ return true;
455
+ }
456
+ bedrockRegion(env);
457
+ return true;
458
+ } catch {
459
+ return false;
460
+ }
461
+ }
462
+ var BEDROCK_STATIC_CREDENTIALS = ["AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_SESSION_TOKEN"];
463
+ function bedrockEnvironment(env, secret) {
464
+ const names = [...BEDROCK_TRANSPORT_ENVIRONMENT, ...BEDROCK_CREDENTIAL_ENVIRONMENT, ...BEDROCK_STATIC_CREDENTIALS];
465
+ const picked = {};
466
+ for (const name of names) {
467
+ const value = env[name]?.trim();
468
+ if (value)
469
+ picked[name] = value;
470
+ }
471
+ let runtime = "converse";
472
+ try {
473
+ runtime = bedrockRuntime(picked);
474
+ } catch {
475
+ runtime = "converse";
476
+ }
477
+ if (secret && runtime === "openai" && !picked.BEDROCK_API_KEY && !picked.AWS_BEARER_TOKEN_BEDROCK) {
478
+ picked.BEDROCK_API_KEY = secret;
479
+ }
480
+ return picked;
481
+ }
482
+ function createBedrockModel(model, env) {
483
+ const runtime = bedrockRuntime(env);
484
+ if (runtime === "openai") {
485
+ const route = openAIRoute(env);
486
+ return sanitizeBedrockModel(createBedrock({
487
+ runtime: "openai",
488
+ apiKey: route.apiKey,
489
+ baseURL: route.baseURL
490
+ })(model), [route.apiKey]);
491
+ }
492
+ const region = bedrockRegion(env);
493
+ const bearer = env.AWS_BEARER_TOKEN_BEDROCK?.trim();
494
+ const accessKeyId = env.AWS_ACCESS_KEY_ID?.trim();
495
+ const secretAccessKey = env.AWS_SECRET_ACCESS_KEY?.trim();
496
+ const sessionToken = env.AWS_SESSION_TOKEN?.trim();
497
+ const staticCredentials = !bearer && accessKeyId && secretAccessKey ? { accessKeyId, secretAccessKey, ...sessionToken ? { sessionToken } : {} } : undefined;
498
+ return sanitizeBedrockModel(createBedrock({
499
+ region,
500
+ ...bearer ? { apiKey: bearer } : {},
501
+ ...staticCredentials ? { credentials: staticCredentials } : {}
502
+ })(model), [bearer, secretAccessKey, sessionToken].filter((value) => Boolean(value)));
503
+ }
504
+ function sanitizeBedrockModel(model, secrets) {
505
+ const clean = (error) => {
506
+ if (error instanceof Error && error.name === "AbortError") {
507
+ return new DOMException("Bedrock request cancelled.", "AbortError");
508
+ }
509
+ const record = error && typeof error === "object" ? error : {};
510
+ const safe = new Error("Bedrock request failed. Check region, model access, and credentials.");
511
+ if (typeof record.status === "number")
512
+ Object.assign(safe, { status: record.status });
513
+ if (typeof record.retryable === "boolean")
514
+ Object.assign(safe, { retryable: record.retryable });
515
+ for (const secret of secrets) {
516
+ if (secret && safe.message.includes(secret))
517
+ safe.message = safe.message.split(secret).join("[REDACTED]");
518
+ }
519
+ return safe;
520
+ };
521
+ return wrapLanguageModel3(model, [{
522
+ name: "harness-bedrock-sanitized-errors",
523
+ async wrapGenerate(_context, next) {
524
+ try {
525
+ return await next();
526
+ } catch (error) {
527
+ throw clean(error);
528
+ }
529
+ },
530
+ async wrapStream(_context, next) {
531
+ let stream;
532
+ try {
533
+ stream = await next();
534
+ } catch (error) {
535
+ throw clean(error);
536
+ }
537
+ return async function* () {
538
+ try {
539
+ for await (const event of stream) {
540
+ if (event.type === "error")
541
+ throw clean(event.error);
542
+ yield event;
543
+ }
544
+ } catch (error) {
545
+ throw clean(error);
546
+ }
547
+ }();
548
+ }
549
+ }]);
550
+ }
551
+
552
+ export { vertexRoute, vertexConfigured, VERTEX_ENVIRONMENT, vertexEnvironment, vertexTokenSource, createVertexModel, azureOpenAIEndpoint, azureOpenAIApiVersion, azureOpenAIDeployments, azureOpenAIConfigured, azureOpenAIEnvironment, createAzureOpenAIModel, bedrockRuntime, bedrockRegion, bedrockOpenAIBaseURL, bedrockConfigured, bedrockEnvironment, createBedrockModel };
@@ -1,19 +1,19 @@
1
1
  import {
2
2
  createHarnessClientAdapter
3
- } from "./index-937cb7y8.js";
3
+ } from "./index-02pqtbbg.js";
4
4
  import {
5
5
  harnessPolicyDecisionEventSchema
6
- } from "./index-pp474137.js";
6
+ } from "./index-wm9xeq1n.js";
7
7
  import {
8
8
  openCliSessionStore
9
- } from "./index-s2k2edts.js";
9
+ } from "./index-zxg4ve4j.js";
10
10
  import {
11
11
  SqliteDatabase
12
- } from "./index-m34q25jj.js";
12
+ } from "./index-xdbkcccf.js";
13
13
  import {
14
14
  harnessClientRequestSchema,
15
15
  streamEventDocument
16
- } from "./index-nmjdwd4p.js";
16
+ } from "./index-4gt045j0.js";
17
17
  import {
18
18
  __require
19
19
  } from "./index-1bx83sw4.js";
@@ -378,7 +378,7 @@ var startHarnessLocalService = async (harness, options) => {
378
378
  }
379
379
  const parsed = harnessClientRequestSchema.safeParse(value);
380
380
  const method = parsed.success ? parsed.data.command.method : undefined;
381
- const mutation = method !== undefined && !["project.get", "policy.get", "session.list", "session.get", "run.get", "checkpoint.list", "checkpoint.inspect", "restore.get"].includes(method);
381
+ const mutation = method !== undefined && !["task.get", "task.review", "project.get", "policy.get", "session.list", "session.get", "run.get", "checkpoint.list", "checkpoint.inspect", "restore.get"].includes(method);
382
382
  if (paused && mutation && method !== "run.cancel")
383
383
  return send(res, 503, fault("SERVICE_PAUSED"));
384
384
  if (mutation)
@@ -424,6 +424,7 @@ var startHarnessLocalService = async (harness, options) => {
424
424
  ...options.retentionMs === undefined ? {} : { retentionMs: options.retentionMs }
425
425
  });
426
426
  adapter = await createHarnessClientAdapter(harness, {
427
+ taskProjectionSensitiveValues: [token, ...options.sensitiveValues ?? [], ...Object.entries(process.env).filter(([k, v]) => /(?:API_KEY|TOKEN|SECRET|PASSWORD)$/.test(k) && v && v.length >= 8).map(([, v]) => v)],
427
428
  ...options.approvalNow ? { now: options.approvalNow } : {},
428
429
  onPolicyDecision: (sessionId, runId, event) => activity.policyDecision(sessionId, runId, event),
429
430
  onPrompt: async (sessionId, runId, prompt) => {