llmist 18.0.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 +155 -57
- 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 +149 -52
- 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
|
});
|
|
@@ -5548,15 +5640,30 @@ function createLoadSkillGadget(registry) {
|
|
|
5548
5640
|
const summaries = registry.getMetadataSummaries();
|
|
5549
5641
|
const skillNames = registry.getModelInvocable().map((s) => s.name);
|
|
5550
5642
|
const description = [
|
|
5551
|
-
"Load one or more skill bodies into context. Pass
|
|
5552
|
-
|
|
5553
|
-
"
|
|
5554
|
-
"
|
|
5555
|
-
"
|
|
5643
|
+
"Load one or more skill bodies into context. Pass `skills` as a JSON",
|
|
5644
|
+
"array of skill-name strings \u2014 NOT a string of a JSON-encoded array.",
|
|
5645
|
+
'Right: `{"skills": ["alpha"]}` or `{"skills": ["alpha", "beta"]}`.',
|
|
5646
|
+
'Wrong: `{"skills": "[\\"alpha\\"]"}` (the value is a string, not an array).',
|
|
5647
|
+
"**This gadget is an iteration barrier \u2014 no other gadgets in the same",
|
|
5648
|
+
"tool batch will execute, so load every skill you know you'll need in",
|
|
5649
|
+
"one shot.** The loaded bodies are sticky and survive context compaction.",
|
|
5556
5650
|
"",
|
|
5557
5651
|
"Available skills:",
|
|
5558
5652
|
summaries
|
|
5559
5653
|
].join("\n");
|
|
5654
|
+
const examples = [];
|
|
5655
|
+
if (skillNames.length >= 1) {
|
|
5656
|
+
examples.push({
|
|
5657
|
+
params: { skills: [skillNames[0]] },
|
|
5658
|
+
comment: "Single-skill call \u2014 `skills` is still an array of length 1."
|
|
5659
|
+
});
|
|
5660
|
+
}
|
|
5661
|
+
if (skillNames.length >= 2) {
|
|
5662
|
+
examples.push({
|
|
5663
|
+
params: { skills: [skillNames[0], skillNames[1]] },
|
|
5664
|
+
comment: "Multi-skill call \u2014 load several skills in one shot to avoid round-trips."
|
|
5665
|
+
});
|
|
5666
|
+
}
|
|
5560
5667
|
return createGadget({
|
|
5561
5668
|
name: LOAD_SKILL_GADGET_NAME,
|
|
5562
5669
|
description,
|
|
@@ -5570,6 +5677,7 @@ function createLoadSkillGadget(registry) {
|
|
|
5570
5677
|
}),
|
|
5571
5678
|
stickyResult: true,
|
|
5572
5679
|
iterationBarrier: true,
|
|
5680
|
+
examples,
|
|
5573
5681
|
execute: async ({ skills: skillNamesArg, arguments: args }) => {
|
|
5574
5682
|
const sections = [];
|
|
5575
5683
|
for (const skillName of skillNamesArg) {
|
|
@@ -12467,7 +12575,7 @@ var init_model_registry = __esm({
|
|
|
12467
12575
|
* Register a provider and collect its model specifications
|
|
12468
12576
|
*/
|
|
12469
12577
|
registerProvider(provider) {
|
|
12470
|
-
const specs = provider.getModelSpecs?.() ?? [];
|
|
12578
|
+
const specs = [...provider.getModelSpecs?.() ?? []];
|
|
12471
12579
|
if (specs.length > 0) {
|
|
12472
12580
|
this.modelSpecs.push(...specs);
|
|
12473
12581
|
this.providerMap.set(provider.providerId, specs);
|
|
@@ -12561,7 +12669,7 @@ var init_model_registry = __esm({
|
|
|
12561
12669
|
if (!providerId) {
|
|
12562
12670
|
return [...this.modelSpecs];
|
|
12563
12671
|
}
|
|
12564
|
-
return this.providerMap.get(providerId) ?? [];
|
|
12672
|
+
return [...this.providerMap.get(providerId) ?? []];
|
|
12565
12673
|
}
|
|
12566
12674
|
/**
|
|
12567
12675
|
* Get context window and output limits for a model
|
|
@@ -16756,7 +16864,7 @@ var init_stream_processor_factory = __esm({
|
|
|
16756
16864
|
|
|
16757
16865
|
// src/mcp/errors.ts
|
|
16758
16866
|
var McpError, McpUntrustedCommandError, McpConnectError, McpToolCallError, McpTimeoutError, JsonSchemaConversionError;
|
|
16759
|
-
var
|
|
16867
|
+
var init_errors2 = __esm({
|
|
16760
16868
|
"src/mcp/errors.ts"() {
|
|
16761
16869
|
"use strict";
|
|
16762
16870
|
McpError = class extends Error {
|
|
@@ -16842,7 +16950,7 @@ var init_allowlist = __esm({
|
|
|
16842
16950
|
"src/mcp/allowlist.ts"() {
|
|
16843
16951
|
"use strict";
|
|
16844
16952
|
import_node_path6 = __toESM(require("path"), 1);
|
|
16845
|
-
|
|
16953
|
+
init_errors2();
|
|
16846
16954
|
DEFAULT_MCP_COMMAND_ALLOWLIST = /* @__PURE__ */ new Set([
|
|
16847
16955
|
"npx",
|
|
16848
16956
|
"node",
|
|
@@ -16880,7 +16988,7 @@ var init_client2 = __esm({
|
|
|
16880
16988
|
"src/mcp/client.ts"() {
|
|
16881
16989
|
"use strict";
|
|
16882
16990
|
init_allowlist();
|
|
16883
|
-
|
|
16991
|
+
init_errors2();
|
|
16884
16992
|
cachedSdk = null;
|
|
16885
16993
|
DEFAULT_CLIENT_INFO = { name: "llmist", version: "0.0.0" };
|
|
16886
16994
|
McpClient = class {
|
|
@@ -17462,7 +17570,7 @@ var init_json_schema_to_zod = __esm({
|
|
|
17462
17570
|
"src/mcp/json-schema-to-zod.ts"() {
|
|
17463
17571
|
"use strict";
|
|
17464
17572
|
import_zod4 = require("zod");
|
|
17465
|
-
|
|
17573
|
+
init_errors2();
|
|
17466
17574
|
}
|
|
17467
17575
|
});
|
|
17468
17576
|
|
|
@@ -18469,6 +18577,7 @@ __export(index_exports, {
|
|
|
18469
18577
|
DEFAULT_RATE_LIMIT_CONFIG: () => DEFAULT_RATE_LIMIT_CONFIG,
|
|
18470
18578
|
DEFAULT_RETRY_CONFIG: () => DEFAULT_RETRY_CONFIG,
|
|
18471
18579
|
DEFAULT_SUMMARIZATION_PROMPT: () => DEFAULT_SUMMARIZATION_PROMPT,
|
|
18580
|
+
EmptyCompletionError: () => EmptyCompletionError,
|
|
18472
18581
|
ExecutionTree: () => ExecutionTree,
|
|
18473
18582
|
FALLBACK_CHARS_PER_TOKEN: () => FALLBACK_CHARS_PER_TOKEN,
|
|
18474
18583
|
GADGET_ARG_PREFIX: () => GADGET_ARG_PREFIX,
|
|
@@ -18754,19 +18863,7 @@ init_stream_processor();
|
|
|
18754
18863
|
// src/index.ts
|
|
18755
18864
|
init_client();
|
|
18756
18865
|
init_constants();
|
|
18757
|
-
|
|
18758
|
-
// src/core/errors.ts
|
|
18759
|
-
function isAbortError(error) {
|
|
18760
|
-
if (!(error instanceof Error)) return false;
|
|
18761
|
-
if (error.name === "AbortError") return true;
|
|
18762
|
-
if (error.name === "APIConnectionAbortedError") return true;
|
|
18763
|
-
if (error.name === "APIUserAbortError") return true;
|
|
18764
|
-
const message = error.message.toLowerCase();
|
|
18765
|
-
if (message.includes("abort")) return true;
|
|
18766
|
-
if (message.includes("cancelled")) return true;
|
|
18767
|
-
if (message.includes("canceled")) return true;
|
|
18768
|
-
return false;
|
|
18769
|
-
}
|
|
18866
|
+
init_errors();
|
|
18770
18867
|
|
|
18771
18868
|
// src/core/execution-events.ts
|
|
18772
18869
|
function isLLMEvent(event) {
|
|
@@ -18826,7 +18923,7 @@ init_typed_gadget();
|
|
|
18826
18923
|
// src/mcp/index.ts
|
|
18827
18924
|
init_allowlist();
|
|
18828
18925
|
init_client2();
|
|
18829
|
-
|
|
18926
|
+
init_errors2();
|
|
18830
18927
|
|
|
18831
18928
|
// src/mcp/gadget-exporter.ts
|
|
18832
18929
|
init_schema_to_json();
|
|
@@ -19476,6 +19573,7 @@ function getHostExports2(ctx) {
|
|
|
19476
19573
|
DEFAULT_RATE_LIMIT_CONFIG,
|
|
19477
19574
|
DEFAULT_RETRY_CONFIG,
|
|
19478
19575
|
DEFAULT_SUMMARIZATION_PROMPT,
|
|
19576
|
+
EmptyCompletionError,
|
|
19479
19577
|
ExecutionTree,
|
|
19480
19578
|
FALLBACK_CHARS_PER_TOKEN,
|
|
19481
19579
|
GADGET_ARG_PREFIX,
|