newmark-agent 0.3.10 → 0.3.12
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/config.example.json +6 -0
- package/dist/cli-commands.d.ts +7 -0
- package/dist/cli-commands.js +206 -15
- package/dist/cli-discovery.d.ts +15 -0
- package/dist/cli-discovery.js +182 -0
- package/dist/cli-help.d.ts +4 -0
- package/dist/cli-help.js +46 -0
- package/dist/conversation-utility-host.bundle.cjs +548 -137
- package/dist/core/agent.d.ts +18 -3
- package/dist/core/agent.js +236 -34
- package/dist/core/agentKernelRunner.js +72 -10
- package/dist/core/browserControl.d.ts +8 -0
- package/dist/core/browserUsePageAdapter.d.ts +3 -0
- package/dist/core/browserUsePageAdapter.js +19 -2
- package/dist/core/computerUseSession.d.ts +44 -0
- package/dist/core/computerUseSession.js +105 -0
- package/dist/core/config.d.ts +7 -2
- package/dist/core/config.js +24 -6
- package/dist/core/conversationKernel.d.ts +1 -0
- package/dist/core/conversationKernel.js +39 -1
- package/dist/core/electronBrowserUseHost.js +7 -0
- package/dist/core/electronUtilityAgentClient.js +84 -2
- package/dist/core/electronUtilityRuntimePool.d.ts +11 -0
- package/dist/core/electronUtilityRuntimePool.js +62 -0
- package/dist/core/flow-runner.js +1 -1
- package/dist/core/modelValidationStore.d.ts +4 -1
- package/dist/core/modelValidationStore.js +7 -1
- package/dist/core/utilityHostToolRouter.d.ts +7 -0
- package/dist/core/utilityHostToolRouter.js +25 -33
- package/dist/core/workspace.d.ts +6 -0
- package/dist/core/workspace.js +14 -0
- package/dist/core/wslAgentRuntimePool.d.ts +4 -0
- package/dist/core/wslAgentRuntimePool.js +56 -0
- package/dist/launcher.js +51 -10
- package/dist/llm/provider.d.ts +8 -5
- package/dist/llm/provider.js +85 -33
- package/dist/main.js +297 -61
- package/dist/preload.js +10 -2
- package/dist/providers/chat-completions.adapter.js +1 -5
- package/dist/providers/provider-events.d.ts +7 -0
- package/dist/providers/provider-events.js +44 -0
- package/dist/providers/responses.adapter.js +1 -3
- package/dist/tools/index.js +36 -49
- package/dist/tui/src/adapters/core-runtime-adapter.js +40 -3
- package/dist/tui/src/app.js +47 -13
- package/dist/tui/src/render.js +23 -7
- package/dist/tui/src/state.js +61 -9
- package/dist/ui/index.html +545 -122
- package/dist/wsl-agent-host.bundle.cjs +548 -137
- package/package.json +14 -5
package/dist/llm/provider.js
CHANGED
|
@@ -43,6 +43,19 @@ const child_process_1 = require("child_process");
|
|
|
43
43
|
const agentKernelDiagnostics_1 = require("../core/agentKernelDiagnostics");
|
|
44
44
|
const chat_messages_1 = require("../providers/chat-messages");
|
|
45
45
|
const providers_1 = require("../providers");
|
|
46
|
+
// Keep provider requests below the release-harness/user-visible command
|
|
47
|
+
// deadline. A provider that does not answer must produce one bounded error;
|
|
48
|
+
// it must not restart the same request through every Windows transport.
|
|
49
|
+
const DEFAULT_PROVIDER_REQUEST_TIMEOUT_MS = 90_000;
|
|
50
|
+
const MIN_PROVIDER_REQUEST_TIMEOUT_MS = 50;
|
|
51
|
+
function providerTimeoutError(timeoutMs) {
|
|
52
|
+
const error = new Error(`Provider request timed out after ${timeoutMs}ms`);
|
|
53
|
+
error.name = 'TimeoutError';
|
|
54
|
+
return error;
|
|
55
|
+
}
|
|
56
|
+
function isProviderTimeoutError(error) {
|
|
57
|
+
return error instanceof Error && error.name === 'TimeoutError';
|
|
58
|
+
}
|
|
46
59
|
function abortFailure(signal) {
|
|
47
60
|
const reason = signal?.reason;
|
|
48
61
|
const error = reason instanceof Error ? reason : new Error(reason ? String(reason) : 'LLM request aborted');
|
|
@@ -84,15 +97,37 @@ class LLMProvider {
|
|
|
84
97
|
explicitProtocol;
|
|
85
98
|
openAIMode;
|
|
86
99
|
useProviderAdaptersV2;
|
|
100
|
+
requestTimeoutMs;
|
|
87
101
|
static nodeHttpTransport = null;
|
|
88
102
|
static powershellTransport = null;
|
|
89
|
-
constructor(name, baseUrl, apiKey, explicitProtocol, openAIMode = 'chat_stream', useProviderAdaptersV2 = false) {
|
|
103
|
+
constructor(name, baseUrl, apiKey, explicitProtocol, openAIMode = 'chat_stream', useProviderAdaptersV2 = false, requestTimeoutMs = DEFAULT_PROVIDER_REQUEST_TIMEOUT_MS) {
|
|
90
104
|
this.name = name;
|
|
91
105
|
this.baseUrl = baseUrl;
|
|
92
106
|
this.apiKey = apiKey;
|
|
93
107
|
this.explicitProtocol = explicitProtocol;
|
|
94
108
|
this.openAIMode = openAIMode;
|
|
95
109
|
this.useProviderAdaptersV2 = useProviderAdaptersV2;
|
|
110
|
+
this.requestTimeoutMs = requestTimeoutMs;
|
|
111
|
+
}
|
|
112
|
+
effectiveRequestTimeout(timeoutMs) {
|
|
113
|
+
const requested = Number.isFinite(timeoutMs) && timeoutMs > 0 ? timeoutMs : DEFAULT_PROVIDER_REQUEST_TIMEOUT_MS;
|
|
114
|
+
const configured = Number.isFinite(this.requestTimeoutMs) && this.requestTimeoutMs > 0
|
|
115
|
+
? this.requestTimeoutMs
|
|
116
|
+
: DEFAULT_PROVIDER_REQUEST_TIMEOUT_MS;
|
|
117
|
+
return Math.max(MIN_PROVIDER_REQUEST_TIMEOUT_MS, Math.min(requested, configured));
|
|
118
|
+
}
|
|
119
|
+
async withRequestTimeout(promise, timeoutMs, signal) {
|
|
120
|
+
let timer;
|
|
121
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
122
|
+
timer = setTimeout(() => reject(providerTimeoutError(timeoutMs)), timeoutMs);
|
|
123
|
+
});
|
|
124
|
+
try {
|
|
125
|
+
return await abortable(Promise.race([promise, timeoutPromise]), signal);
|
|
126
|
+
}
|
|
127
|
+
finally {
|
|
128
|
+
if (timer)
|
|
129
|
+
clearTimeout(timer);
|
|
130
|
+
}
|
|
96
131
|
}
|
|
97
132
|
intelligenceConfig(tier) {
|
|
98
133
|
switch (tier) {
|
|
@@ -212,6 +247,7 @@ class LLMProvider {
|
|
|
212
247
|
};
|
|
213
248
|
}
|
|
214
249
|
async postJsonWithFetchFallback(url, headers, body, timeoutMs = 120000, signal) {
|
|
250
|
+
const effectiveTimeout = this.effectiveRequestTimeout(timeoutMs);
|
|
215
251
|
// Electron utility processes can leave an undici response body pending when
|
|
216
252
|
// several isolated workers concurrently call a plain-HTTP local provider.
|
|
217
253
|
// Node's HTTP client owns the full body lifecycle and is deterministic for
|
|
@@ -224,7 +260,7 @@ class LLMProvider {
|
|
|
224
260
|
return '';
|
|
225
261
|
} })();
|
|
226
262
|
this.transportDiagnostic('loopback:start', pathname);
|
|
227
|
-
const local = await this.nodeHttpJson('POST', url, headers, JSON.stringify(body), signal);
|
|
263
|
+
const local = await this.nodeHttpJson('POST', url, headers, JSON.stringify(body), signal, effectiveTimeout);
|
|
228
264
|
this.transportDiagnostic('loopback:complete', `status=${local.status} bytes=${Buffer.byteLength(local.body || '')}`);
|
|
229
265
|
return {
|
|
230
266
|
ok: local.status >= 200 && local.status < 300,
|
|
@@ -240,7 +276,7 @@ class LLMProvider {
|
|
|
240
276
|
forwardAbort();
|
|
241
277
|
else
|
|
242
278
|
signal?.addEventListener('abort', forwardAbort, { once: true });
|
|
243
|
-
const timer = setTimeout(() => abort.abort(),
|
|
279
|
+
const timer = setTimeout(() => abort.abort(providerTimeoutError(effectiveTimeout)), effectiveTimeout);
|
|
244
280
|
try {
|
|
245
281
|
const response = await fetch(url, {
|
|
246
282
|
method: 'POST',
|
|
@@ -253,9 +289,11 @@ class LLMProvider {
|
|
|
253
289
|
catch (e) {
|
|
254
290
|
if (signal?.aborted)
|
|
255
291
|
throw abortFailure(signal);
|
|
292
|
+
if (abort.signal.aborted)
|
|
293
|
+
throw abortFailure(abort.signal);
|
|
256
294
|
if (!this.shouldUseNodeHttpFallback(e))
|
|
257
295
|
throw e;
|
|
258
|
-
const fallback = await this.nodeHttpJson('POST', url, headers, JSON.stringify(body), signal);
|
|
296
|
+
const fallback = await this.nodeHttpJson('POST', url, headers, JSON.stringify(body), signal, effectiveTimeout);
|
|
259
297
|
return {
|
|
260
298
|
ok: fallback.status >= 200 && fallback.status < 300,
|
|
261
299
|
status: fallback.status,
|
|
@@ -270,16 +308,19 @@ class LLMProvider {
|
|
|
270
308
|
}
|
|
271
309
|
}
|
|
272
310
|
async getJsonWithFetchFallback(url, headers, timeoutMs = 30000) {
|
|
311
|
+
const effectiveTimeout = this.effectiveRequestTimeout(timeoutMs);
|
|
273
312
|
const abort = new AbortController();
|
|
274
|
-
const timer = setTimeout(() => abort.abort(),
|
|
313
|
+
const timer = setTimeout(() => abort.abort(providerTimeoutError(effectiveTimeout)), effectiveTimeout);
|
|
275
314
|
try {
|
|
276
315
|
const response = await fetch(url, { method: 'GET', headers, signal: abort.signal });
|
|
277
316
|
return response;
|
|
278
317
|
}
|
|
279
318
|
catch (e) {
|
|
319
|
+
if (abort.signal.aborted)
|
|
320
|
+
throw abortFailure(abort.signal);
|
|
280
321
|
if (!this.shouldUseNodeHttpFallback(e))
|
|
281
322
|
throw e;
|
|
282
|
-
const fallback = await this.nodeHttpJson('GET', url, headers);
|
|
323
|
+
const fallback = await this.nodeHttpJson('GET', url, headers, '', undefined, effectiveTimeout);
|
|
283
324
|
return {
|
|
284
325
|
ok: fallback.status >= 200 && fallback.status < 300,
|
|
285
326
|
status: fallback.status,
|
|
@@ -293,16 +334,21 @@ class LLMProvider {
|
|
|
293
334
|
}
|
|
294
335
|
}
|
|
295
336
|
shouldUseNodeHttpFallback(error) {
|
|
296
|
-
|
|
297
|
-
|
|
337
|
+
// Abort is a completed control decision (user cancellation or our own
|
|
338
|
+
// deadline), not evidence that a second transport can succeed. Retrying it
|
|
339
|
+
// on Windows used to create a second 120s request after the first timeout.
|
|
340
|
+
return error instanceof TypeError && /fetch failed/i.test(error.message);
|
|
298
341
|
}
|
|
299
|
-
nodeHttpJson(method, urlValue, headers, body = '', signal) {
|
|
342
|
+
nodeHttpJson(method, urlValue, headers, body = '', signal, timeoutMs = DEFAULT_PROVIDER_REQUEST_TIMEOUT_MS) {
|
|
343
|
+
const effectiveTimeout = this.effectiveRequestTimeout(timeoutMs);
|
|
300
344
|
if (LLMProvider.nodeHttpTransport) {
|
|
301
|
-
return
|
|
345
|
+
return this.withRequestTimeout(LLMProvider.nodeHttpTransport(method, urlValue, headers, body), effectiveTimeout, signal).catch(error => {
|
|
302
346
|
if (signal?.aborted)
|
|
303
347
|
throw abortFailure(signal);
|
|
348
|
+
if (isProviderTimeoutError(error))
|
|
349
|
+
throw error;
|
|
304
350
|
if (process.platform === 'win32') {
|
|
305
|
-
return this.powershellJson(method, urlValue, headers, body, signal);
|
|
351
|
+
return this.powershellJson(method, urlValue, headers, body, signal, effectiveTimeout);
|
|
306
352
|
}
|
|
307
353
|
throw error;
|
|
308
354
|
});
|
|
@@ -350,8 +396,8 @@ class LLMProvider {
|
|
|
350
396
|
fail(new Error('Node HTTP response closed before completion'));
|
|
351
397
|
});
|
|
352
398
|
});
|
|
353
|
-
req.setTimeout(
|
|
354
|
-
req.destroy(
|
|
399
|
+
req.setTimeout(effectiveTimeout, () => {
|
|
400
|
+
req.destroy(providerTimeoutError(effectiveTimeout));
|
|
355
401
|
});
|
|
356
402
|
req.on('error', reject);
|
|
357
403
|
const onAbort = () => req.destroy(abortFailure(signal));
|
|
@@ -366,15 +412,18 @@ class LLMProvider {
|
|
|
366
412
|
}).catch(error => {
|
|
367
413
|
if (signal?.aborted)
|
|
368
414
|
throw abortFailure(signal);
|
|
415
|
+
if (isProviderTimeoutError(error))
|
|
416
|
+
throw error;
|
|
369
417
|
if (process.platform === 'win32') {
|
|
370
|
-
return this.powershellJson(method, urlValue, headers, body, signal);
|
|
418
|
+
return this.powershellJson(method, urlValue, headers, body, signal, effectiveTimeout);
|
|
371
419
|
}
|
|
372
420
|
throw error;
|
|
373
421
|
});
|
|
374
422
|
}
|
|
375
|
-
powershellJson(method, urlValue, headers, body = '', signal) {
|
|
423
|
+
powershellJson(method, urlValue, headers, body = '', signal, timeoutMs = DEFAULT_PROVIDER_REQUEST_TIMEOUT_MS) {
|
|
424
|
+
const effectiveTimeout = this.effectiveRequestTimeout(timeoutMs);
|
|
376
425
|
if (LLMProvider.powershellTransport) {
|
|
377
|
-
return LLMProvider.powershellTransport(method, urlValue, headers, body);
|
|
426
|
+
return this.withRequestTimeout(LLMProvider.powershellTransport(method, urlValue, headers, body), effectiveTimeout, signal);
|
|
378
427
|
}
|
|
379
428
|
return new Promise((resolve, reject) => {
|
|
380
429
|
const headerJson = JSON.stringify(headers);
|
|
@@ -403,7 +452,7 @@ class LLMProvider {
|
|
|
403
452
|
' $raw = $headerJson | ConvertFrom-Json',
|
|
404
453
|
' foreach ($p in $raw.PSObject.Properties) { $headers[$p.Name] = [string]$p.Value }',
|
|
405
454
|
'}',
|
|
406
|
-
'$params = @{ Uri = $uri; Method = $method; Headers = $headers; UseBasicParsing = $true; TimeoutSec =
|
|
455
|
+
`'$params = @{ Uri = $uri; Method = $method; Headers = $headers; UseBasicParsing = $true; TimeoutSec = ${Math.max(1, Math.ceil(effectiveTimeout / 1000))} }`,
|
|
407
456
|
'if ($method -eq "POST") { $params["Body"] = $bodyJson }',
|
|
408
457
|
'if ($method -eq "POST") { $params["ContentType"] = "application/json; charset=utf-8" }',
|
|
409
458
|
'$resp = Invoke-WebRequest @params',
|
|
@@ -437,8 +486,8 @@ class LLMProvider {
|
|
|
437
486
|
const timer = setTimeout(() => {
|
|
438
487
|
child.kill();
|
|
439
488
|
cleanup();
|
|
440
|
-
reject(
|
|
441
|
-
},
|
|
489
|
+
reject(providerTimeoutError(effectiveTimeout));
|
|
490
|
+
}, effectiveTimeout + 5000);
|
|
442
491
|
child.stdout.setEncoding('utf8');
|
|
443
492
|
child.stderr.setEncoding('utf8');
|
|
444
493
|
child.stdout.on('data', chunk => { stdout += chunk; });
|
|
@@ -926,10 +975,10 @@ class LLMProvider {
|
|
|
926
975
|
return this.shouldUseResponsesFallback(Number(match[1]), errorText);
|
|
927
976
|
}
|
|
928
977
|
/**
|
|
929
|
-
* Loopback-aware transport injected into adapter `execute`.
|
|
930
|
-
*
|
|
931
|
-
*
|
|
932
|
-
*
|
|
978
|
+
* Loopback-aware transport injected into adapter `execute`. Streaming
|
|
979
|
+
* requests retain the fetch-to-node fallback for transport failures, while
|
|
980
|
+
* a local deadline is returned directly so one request cannot become a
|
|
981
|
+
* second Windows fallback request.
|
|
933
982
|
*/
|
|
934
983
|
buildProviderAdapterTransport() {
|
|
935
984
|
return async (request, signal) => {
|
|
@@ -940,7 +989,8 @@ class LLMProvider {
|
|
|
940
989
|
forwardAbort();
|
|
941
990
|
else
|
|
942
991
|
signal?.addEventListener('abort', forwardAbort, { once: true });
|
|
943
|
-
const
|
|
992
|
+
const effectiveTimeout = this.effectiveRequestTimeout(120000);
|
|
993
|
+
const timer = setTimeout(() => abort.abort(providerTimeoutError(effectiveTimeout)), effectiveTimeout);
|
|
944
994
|
try {
|
|
945
995
|
try {
|
|
946
996
|
return await fetch(request.url, {
|
|
@@ -953,11 +1003,13 @@ class LLMProvider {
|
|
|
953
1003
|
catch (error) {
|
|
954
1004
|
if (signal?.aborted)
|
|
955
1005
|
throw abortFailure(signal);
|
|
1006
|
+
if (abort.signal.aborted)
|
|
1007
|
+
throw abortFailure(abort.signal);
|
|
956
1008
|
if (!this.shouldUseNodeHttpFallback(error))
|
|
957
1009
|
throw error;
|
|
958
1010
|
const fallbackHeaders = { ...request.headers };
|
|
959
1011
|
delete fallbackHeaders['Accept'];
|
|
960
|
-
const fallback = await this.postJsonWithFetchFallback(request.url, fallbackHeaders, { ...request.body, stream: false },
|
|
1012
|
+
const fallback = await this.postJsonWithFetchFallback(request.url, fallbackHeaders, { ...request.body, stream: false }, effectiveTimeout, signal);
|
|
961
1013
|
return this.toTransportResponse(fallback);
|
|
962
1014
|
}
|
|
963
1015
|
}
|
|
@@ -1071,7 +1123,8 @@ class LLMProvider {
|
|
|
1071
1123
|
forwardAbort();
|
|
1072
1124
|
else
|
|
1073
1125
|
signal?.addEventListener('abort', forwardAbort, { once: true });
|
|
1074
|
-
const
|
|
1126
|
+
const effectiveTimeout = this.effectiveRequestTimeout(120000);
|
|
1127
|
+
const timeout = setTimeout(() => abort.abort(providerTimeoutError(effectiveTimeout)), effectiveTimeout);
|
|
1075
1128
|
let reader = null;
|
|
1076
1129
|
try {
|
|
1077
1130
|
let response;
|
|
@@ -1084,11 +1137,13 @@ class LLMProvider {
|
|
|
1084
1137
|
});
|
|
1085
1138
|
}
|
|
1086
1139
|
catch (e) {
|
|
1140
|
+
if (signal?.aborted)
|
|
1141
|
+
throw abortFailure(signal);
|
|
1142
|
+
if (abort.signal.aborted)
|
|
1143
|
+
throw abortFailure(abort.signal);
|
|
1087
1144
|
if (!this.shouldUseNodeHttpFallback(e))
|
|
1088
1145
|
throw e;
|
|
1089
1146
|
clearTimeout(timeout);
|
|
1090
|
-
if (signal?.aborted)
|
|
1091
|
-
throw abortFailure(signal);
|
|
1092
1147
|
yield* this.githubModelsChatNonStreaming(url, body, signal);
|
|
1093
1148
|
return;
|
|
1094
1149
|
}
|
|
@@ -1108,12 +1163,9 @@ class LLMProvider {
|
|
|
1108
1163
|
let currentReasoningContent = '';
|
|
1109
1164
|
let contentPolicyBlocked = false;
|
|
1110
1165
|
let emittedContent = false;
|
|
1166
|
+
const streamSignal = signal || new AbortController().signal;
|
|
1111
1167
|
while (true) {
|
|
1112
|
-
|
|
1113
|
-
throw abortFailure(signal);
|
|
1114
|
-
const readPromise = reader.read();
|
|
1115
|
-
const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error('Stream read timeout')), 30000));
|
|
1116
|
-
const { done, value } = await Promise.race([readPromise, timeoutPromise]);
|
|
1168
|
+
const { done, value } = await (0, providers_1.readProviderStreamChunk)(reader, streamSignal);
|
|
1117
1169
|
if (done)
|
|
1118
1170
|
break;
|
|
1119
1171
|
buffer += decoder.decode(value, { stream: true });
|