llmist 18.1.0 → 18.2.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/dist/index.cjs +134 -52
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +28 -1
- package/dist/index.d.ts +28 -1
- package/dist/index.js +128 -47
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1926,7 +1926,8 @@ function resolveRetryConfig(config) {
|
|
|
1926
1926
|
onRetriesExhausted: config.onRetriesExhausted,
|
|
1927
1927
|
shouldRetry: config.shouldRetry,
|
|
1928
1928
|
respectRetryAfter: config.respectRetryAfter ?? DEFAULT_RETRY_CONFIG.respectRetryAfter,
|
|
1929
|
-
maxRetryAfterMs: config.maxRetryAfterMs ?? DEFAULT_RETRY_CONFIG.maxRetryAfterMs
|
|
1929
|
+
maxRetryAfterMs: config.maxRetryAfterMs ?? DEFAULT_RETRY_CONFIG.maxRetryAfterMs,
|
|
1930
|
+
retryOnEmpty: config.retryOnEmpty ?? DEFAULT_RETRY_CONFIG.retryOnEmpty
|
|
1930
1931
|
};
|
|
1931
1932
|
}
|
|
1932
1933
|
function getErrorStatusCode(error) {
|
|
@@ -2178,8 +2179,9 @@ var init_retry = __esm({
|
|
|
2178
2179
|
factor: 2,
|
|
2179
2180
|
randomize: true,
|
|
2180
2181
|
respectRetryAfter: true,
|
|
2181
|
-
maxRetryAfterMs: 12e4
|
|
2182
|
+
maxRetryAfterMs: 12e4,
|
|
2182
2183
|
// 2 minutes cap
|
|
2184
|
+
retryOnEmpty: true
|
|
2183
2185
|
};
|
|
2184
2186
|
}
|
|
2185
2187
|
});
|
|
@@ -5188,11 +5190,51 @@ var init_output_limit_manager = __esm({
|
|
|
5188
5190
|
}
|
|
5189
5191
|
});
|
|
5190
5192
|
|
|
5193
|
+
// src/core/errors.ts
|
|
5194
|
+
function isAbortError(error) {
|
|
5195
|
+
if (!(error instanceof Error)) return false;
|
|
5196
|
+
if (error.name === "AbortError") return true;
|
|
5197
|
+
if (error.name === "APIConnectionAbortedError") return true;
|
|
5198
|
+
if (error.name === "APIUserAbortError") return true;
|
|
5199
|
+
const message = error.message.toLowerCase();
|
|
5200
|
+
if (message.includes("abort")) return true;
|
|
5201
|
+
if (message.includes("cancelled")) return true;
|
|
5202
|
+
if (message.includes("canceled")) return true;
|
|
5203
|
+
return false;
|
|
5204
|
+
}
|
|
5205
|
+
var EmptyCompletionError;
|
|
5206
|
+
var init_errors = __esm({
|
|
5207
|
+
"src/core/errors.ts"() {
|
|
5208
|
+
"use strict";
|
|
5209
|
+
EmptyCompletionError = class extends Error {
|
|
5210
|
+
/** Agent iteration on which the empty completion was observed. */
|
|
5211
|
+
iteration;
|
|
5212
|
+
/** Finish reason reported alongside the empty body (often null). */
|
|
5213
|
+
finishReason;
|
|
5214
|
+
constructor(params) {
|
|
5215
|
+
super(
|
|
5216
|
+
`LLM returned an empty completion (no text, tool calls, or reasoning) on iteration ${params.iteration}`
|
|
5217
|
+
);
|
|
5218
|
+
this.name = "EmptyCompletionError";
|
|
5219
|
+
this.iteration = params.iteration;
|
|
5220
|
+
this.finishReason = params.finishReason;
|
|
5221
|
+
}
|
|
5222
|
+
};
|
|
5223
|
+
}
|
|
5224
|
+
});
|
|
5225
|
+
|
|
5191
5226
|
// src/agent/retry-orchestrator.ts
|
|
5227
|
+
function isEmptyCompletion(meta) {
|
|
5228
|
+
if (meta.didExecuteGadgets) return false;
|
|
5229
|
+
if (meta.rawResponse?.trim() || meta.finalMessage?.trim()) return false;
|
|
5230
|
+
if (meta.thinkingContent?.trim()) return false;
|
|
5231
|
+
return true;
|
|
5232
|
+
}
|
|
5192
5233
|
var RetryOrchestrator;
|
|
5193
5234
|
var init_retry_orchestrator = __esm({
|
|
5194
5235
|
"src/agent/retry-orchestrator.ts"() {
|
|
5195
5236
|
"use strict";
|
|
5237
|
+
init_errors();
|
|
5196
5238
|
init_retry();
|
|
5197
5239
|
init_safe_observe();
|
|
5198
5240
|
init_tree_hook_bridge();
|
|
@@ -5258,6 +5300,7 @@ var init_retry_orchestrator = __esm({
|
|
|
5258
5300
|
let gadgetCallCount = 0;
|
|
5259
5301
|
const textOutputs = [];
|
|
5260
5302
|
const gadgetResults = [];
|
|
5303
|
+
let emptyFailure = null;
|
|
5261
5304
|
while (streamAttempt < maxStreamAttempts) {
|
|
5262
5305
|
streamAttempt++;
|
|
5263
5306
|
try {
|
|
@@ -5266,6 +5309,7 @@ var init_retry_orchestrator = __esm({
|
|
|
5266
5309
|
for await (const event of processor.process(stream2)) {
|
|
5267
5310
|
if (event.type === "stream_complete") {
|
|
5268
5311
|
streamMetadata = event;
|
|
5312
|
+
continue;
|
|
5269
5313
|
}
|
|
5270
5314
|
if (event.type === "llm_response_end") {
|
|
5271
5315
|
this.tree.endLLMResponse(llmNodeId, {
|
|
@@ -5287,43 +5331,44 @@ var init_retry_orchestrator = __esm({
|
|
|
5287
5331
|
for (const id of processor.getFailedInvocationIds()) {
|
|
5288
5332
|
this.failedInvocationIds.add(id);
|
|
5289
5333
|
}
|
|
5334
|
+
if (this.retryConfig.enabled && this.retryConfig.retryOnEmpty && streamMetadata !== null && !streamMetadata.finishReason && isEmptyCompletion(streamMetadata)) {
|
|
5335
|
+
const emptyError = new EmptyCompletionError({
|
|
5336
|
+
iteration,
|
|
5337
|
+
finishReason: streamMetadata.finishReason
|
|
5338
|
+
});
|
|
5339
|
+
if (streamAttempt < maxStreamAttempts) {
|
|
5340
|
+
await this.backoffBeforeRetry(
|
|
5341
|
+
emptyError,
|
|
5342
|
+
streamAttempt,
|
|
5343
|
+
maxStreamAttempts,
|
|
5344
|
+
iteration,
|
|
5345
|
+
llmNodeId
|
|
5346
|
+
);
|
|
5347
|
+
streamMetadata = null;
|
|
5348
|
+
gadgetCallCount = 0;
|
|
5349
|
+
textOutputs.length = 0;
|
|
5350
|
+
gadgetResults.length = 0;
|
|
5351
|
+
continue;
|
|
5352
|
+
}
|
|
5353
|
+
emptyFailure = emptyError;
|
|
5354
|
+
break;
|
|
5355
|
+
}
|
|
5356
|
+
if (streamMetadata !== null) {
|
|
5357
|
+
yield streamMetadata;
|
|
5358
|
+
}
|
|
5290
5359
|
break;
|
|
5291
5360
|
} catch (streamError) {
|
|
5292
5361
|
const error = streamError;
|
|
5293
5362
|
const canRetry = this.retryConfig.enabled && streamAttempt < maxStreamAttempts;
|
|
5294
5363
|
const shouldRetryError = this.retryConfig.shouldRetry ? this.retryConfig.shouldRetry(error) : isRetryableError(error);
|
|
5295
5364
|
if (canRetry && shouldRetryError) {
|
|
5296
|
-
|
|
5297
|
-
|
|
5298
|
-
|
|
5299
|
-
|
|
5300
|
-
|
|
5301
|
-
|
|
5302
|
-
`Stream iteration failed (attempt ${streamAttempt}/${maxStreamAttempts}), retrying...`,
|
|
5303
|
-
{
|
|
5304
|
-
error: error.message,
|
|
5305
|
-
retriesLeft: maxStreamAttempts - streamAttempt,
|
|
5306
|
-
delayMs: Math.round(finalDelay),
|
|
5307
|
-
retryAfterMs
|
|
5308
|
-
}
|
|
5365
|
+
await this.backoffBeforeRetry(
|
|
5366
|
+
error,
|
|
5367
|
+
streamAttempt,
|
|
5368
|
+
maxStreamAttempts,
|
|
5369
|
+
iteration,
|
|
5370
|
+
llmNodeId
|
|
5309
5371
|
);
|
|
5310
|
-
this.retryConfig.onRetry?.(error, streamAttempt);
|
|
5311
|
-
await safeObserve(async () => {
|
|
5312
|
-
if (this.hooks.observers?.onRetryAttempt) {
|
|
5313
|
-
const subagentContext = getSubagentContextForNode(this.tree, llmNodeId);
|
|
5314
|
-
const hookContext = {
|
|
5315
|
-
iteration,
|
|
5316
|
-
attemptNumber: streamAttempt,
|
|
5317
|
-
retriesLeft: maxStreamAttempts - streamAttempt,
|
|
5318
|
-
error,
|
|
5319
|
-
retryAfterMs: retryAfterMs ?? void 0,
|
|
5320
|
-
logger: this.logger,
|
|
5321
|
-
subagentContext
|
|
5322
|
-
};
|
|
5323
|
-
await this.hooks.observers.onRetryAttempt(hookContext);
|
|
5324
|
-
}
|
|
5325
|
-
}, this.logger);
|
|
5326
|
-
await this.sleep(finalDelay);
|
|
5327
5372
|
streamMetadata = null;
|
|
5328
5373
|
gadgetCallCount = 0;
|
|
5329
5374
|
textOutputs.length = 0;
|
|
@@ -5340,8 +5385,55 @@ var init_retry_orchestrator = __esm({
|
|
|
5340
5385
|
throw error;
|
|
5341
5386
|
}
|
|
5342
5387
|
}
|
|
5388
|
+
if (emptyFailure !== null) {
|
|
5389
|
+
this.logger.error(`LLM returned empty completions on all ${streamAttempt} attempts`, {
|
|
5390
|
+
iteration
|
|
5391
|
+
});
|
|
5392
|
+
this.retryConfig.onRetriesExhausted?.(emptyFailure, streamAttempt);
|
|
5393
|
+
throw emptyFailure;
|
|
5394
|
+
}
|
|
5343
5395
|
return streamMetadata !== null ? { streamMetadata, textOutputs, gadgetResults, gadgetCallCount } : null;
|
|
5344
5396
|
}
|
|
5397
|
+
/**
|
|
5398
|
+
* Apply the configured backoff before a retry attempt: compute the delay
|
|
5399
|
+
* (Retry-After hint or exponential backoff, with optional jitter), emit the
|
|
5400
|
+
* retry log, fire the `onRetry` callback and `onRetryAttempt` observer, then
|
|
5401
|
+
* sleep. Shared by the error-retry and empty-completion-retry paths so both
|
|
5402
|
+
* honour identical backoff and observer semantics.
|
|
5403
|
+
*/
|
|
5404
|
+
async backoffBeforeRetry(error, streamAttempt, maxStreamAttempts, iteration, llmNodeId) {
|
|
5405
|
+
const retryAfterMs = this.retryConfig.respectRetryAfter ? extractRetryAfterMs(error) : null;
|
|
5406
|
+
const baseDelay = this.retryConfig.minTimeout * this.retryConfig.factor ** (streamAttempt - 1);
|
|
5407
|
+
const cappedBaseDelay = Math.min(baseDelay, this.retryConfig.maxTimeout);
|
|
5408
|
+
const delay = retryAfterMs !== null ? Math.min(retryAfterMs, this.retryConfig.maxRetryAfterMs) : cappedBaseDelay;
|
|
5409
|
+
const finalDelay = this.retryConfig.randomize ? delay * (0.5 + Math.random()) : delay;
|
|
5410
|
+
this.logger.warn(
|
|
5411
|
+
`Stream iteration failed (attempt ${streamAttempt}/${maxStreamAttempts}), retrying...`,
|
|
5412
|
+
{
|
|
5413
|
+
error: error.message,
|
|
5414
|
+
retriesLeft: maxStreamAttempts - streamAttempt,
|
|
5415
|
+
delayMs: Math.round(finalDelay),
|
|
5416
|
+
retryAfterMs
|
|
5417
|
+
}
|
|
5418
|
+
);
|
|
5419
|
+
this.retryConfig.onRetry?.(error, streamAttempt);
|
|
5420
|
+
await safeObserve(async () => {
|
|
5421
|
+
if (this.hooks.observers?.onRetryAttempt) {
|
|
5422
|
+
const subagentContext = getSubagentContextForNode(this.tree, llmNodeId);
|
|
5423
|
+
const hookContext = {
|
|
5424
|
+
iteration,
|
|
5425
|
+
attemptNumber: streamAttempt,
|
|
5426
|
+
retriesLeft: maxStreamAttempts - streamAttempt,
|
|
5427
|
+
error,
|
|
5428
|
+
retryAfterMs: retryAfterMs ?? void 0,
|
|
5429
|
+
logger: this.logger,
|
|
5430
|
+
subagentContext
|
|
5431
|
+
};
|
|
5432
|
+
await this.hooks.observers.onRetryAttempt(hookContext);
|
|
5433
|
+
}
|
|
5434
|
+
}, this.logger);
|
|
5435
|
+
await this.sleep(finalDelay);
|
|
5436
|
+
}
|
|
5345
5437
|
};
|
|
5346
5438
|
}
|
|
5347
5439
|
});
|
|
@@ -12483,7 +12575,7 @@ var init_model_registry = __esm({
|
|
|
12483
12575
|
* Register a provider and collect its model specifications
|
|
12484
12576
|
*/
|
|
12485
12577
|
registerProvider(provider) {
|
|
12486
|
-
const specs = provider.getModelSpecs?.() ?? [];
|
|
12578
|
+
const specs = [...provider.getModelSpecs?.() ?? []];
|
|
12487
12579
|
if (specs.length > 0) {
|
|
12488
12580
|
this.modelSpecs.push(...specs);
|
|
12489
12581
|
this.providerMap.set(provider.providerId, specs);
|
|
@@ -12577,7 +12669,7 @@ var init_model_registry = __esm({
|
|
|
12577
12669
|
if (!providerId) {
|
|
12578
12670
|
return [...this.modelSpecs];
|
|
12579
12671
|
}
|
|
12580
|
-
return this.providerMap.get(providerId) ?? [];
|
|
12672
|
+
return [...this.providerMap.get(providerId) ?? []];
|
|
12581
12673
|
}
|
|
12582
12674
|
/**
|
|
12583
12675
|
* Get context window and output limits for a model
|
|
@@ -16772,7 +16864,7 @@ var init_stream_processor_factory = __esm({
|
|
|
16772
16864
|
|
|
16773
16865
|
// src/mcp/errors.ts
|
|
16774
16866
|
var McpError, McpUntrustedCommandError, McpConnectError, McpToolCallError, McpTimeoutError, JsonSchemaConversionError;
|
|
16775
|
-
var
|
|
16867
|
+
var init_errors2 = __esm({
|
|
16776
16868
|
"src/mcp/errors.ts"() {
|
|
16777
16869
|
"use strict";
|
|
16778
16870
|
McpError = class extends Error {
|
|
@@ -16858,7 +16950,7 @@ var init_allowlist = __esm({
|
|
|
16858
16950
|
"src/mcp/allowlist.ts"() {
|
|
16859
16951
|
"use strict";
|
|
16860
16952
|
import_node_path6 = __toESM(require("path"), 1);
|
|
16861
|
-
|
|
16953
|
+
init_errors2();
|
|
16862
16954
|
DEFAULT_MCP_COMMAND_ALLOWLIST = /* @__PURE__ */ new Set([
|
|
16863
16955
|
"npx",
|
|
16864
16956
|
"node",
|
|
@@ -16896,7 +16988,7 @@ var init_client2 = __esm({
|
|
|
16896
16988
|
"src/mcp/client.ts"() {
|
|
16897
16989
|
"use strict";
|
|
16898
16990
|
init_allowlist();
|
|
16899
|
-
|
|
16991
|
+
init_errors2();
|
|
16900
16992
|
cachedSdk = null;
|
|
16901
16993
|
DEFAULT_CLIENT_INFO = { name: "llmist", version: "0.0.0" };
|
|
16902
16994
|
McpClient = class {
|
|
@@ -17478,7 +17570,7 @@ var init_json_schema_to_zod = __esm({
|
|
|
17478
17570
|
"src/mcp/json-schema-to-zod.ts"() {
|
|
17479
17571
|
"use strict";
|
|
17480
17572
|
import_zod4 = require("zod");
|
|
17481
|
-
|
|
17573
|
+
init_errors2();
|
|
17482
17574
|
}
|
|
17483
17575
|
});
|
|
17484
17576
|
|
|
@@ -18485,6 +18577,7 @@ __export(index_exports, {
|
|
|
18485
18577
|
DEFAULT_RATE_LIMIT_CONFIG: () => DEFAULT_RATE_LIMIT_CONFIG,
|
|
18486
18578
|
DEFAULT_RETRY_CONFIG: () => DEFAULT_RETRY_CONFIG,
|
|
18487
18579
|
DEFAULT_SUMMARIZATION_PROMPT: () => DEFAULT_SUMMARIZATION_PROMPT,
|
|
18580
|
+
EmptyCompletionError: () => EmptyCompletionError,
|
|
18488
18581
|
ExecutionTree: () => ExecutionTree,
|
|
18489
18582
|
FALLBACK_CHARS_PER_TOKEN: () => FALLBACK_CHARS_PER_TOKEN,
|
|
18490
18583
|
GADGET_ARG_PREFIX: () => GADGET_ARG_PREFIX,
|
|
@@ -18770,19 +18863,7 @@ init_stream_processor();
|
|
|
18770
18863
|
// src/index.ts
|
|
18771
18864
|
init_client();
|
|
18772
18865
|
init_constants();
|
|
18773
|
-
|
|
18774
|
-
// src/core/errors.ts
|
|
18775
|
-
function isAbortError(error) {
|
|
18776
|
-
if (!(error instanceof Error)) return false;
|
|
18777
|
-
if (error.name === "AbortError") return true;
|
|
18778
|
-
if (error.name === "APIConnectionAbortedError") return true;
|
|
18779
|
-
if (error.name === "APIUserAbortError") return true;
|
|
18780
|
-
const message = error.message.toLowerCase();
|
|
18781
|
-
if (message.includes("abort")) return true;
|
|
18782
|
-
if (message.includes("cancelled")) return true;
|
|
18783
|
-
if (message.includes("canceled")) return true;
|
|
18784
|
-
return false;
|
|
18785
|
-
}
|
|
18866
|
+
init_errors();
|
|
18786
18867
|
|
|
18787
18868
|
// src/core/execution-events.ts
|
|
18788
18869
|
function isLLMEvent(event) {
|
|
@@ -18842,7 +18923,7 @@ init_typed_gadget();
|
|
|
18842
18923
|
// src/mcp/index.ts
|
|
18843
18924
|
init_allowlist();
|
|
18844
18925
|
init_client2();
|
|
18845
|
-
|
|
18926
|
+
init_errors2();
|
|
18846
18927
|
|
|
18847
18928
|
// src/mcp/gadget-exporter.ts
|
|
18848
18929
|
init_schema_to_json();
|
|
@@ -19492,6 +19573,7 @@ function getHostExports2(ctx) {
|
|
|
19492
19573
|
DEFAULT_RATE_LIMIT_CONFIG,
|
|
19493
19574
|
DEFAULT_RETRY_CONFIG,
|
|
19494
19575
|
DEFAULT_SUMMARIZATION_PROMPT,
|
|
19576
|
+
EmptyCompletionError,
|
|
19495
19577
|
ExecutionTree,
|
|
19496
19578
|
FALLBACK_CHARS_PER_TOKEN,
|
|
19497
19579
|
GADGET_ARG_PREFIX,
|