llmist 18.2.0 → 18.3.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 +205 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +120 -2
- package/dist/index.d.ts +120 -2
- package/dist/index.js +205 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2467,6 +2467,18 @@ async function runWithHandlers(agentGenerator, handlers) {
|
|
|
2467
2467
|
});
|
|
2468
2468
|
}
|
|
2469
2469
|
break;
|
|
2470
|
+
case "gadget_args_partial":
|
|
2471
|
+
if (handlers.onGadgetArgsPartial) {
|
|
2472
|
+
await handlers.onGadgetArgsPartial({
|
|
2473
|
+
gadgetName: event.gadgetName,
|
|
2474
|
+
invocationId: event.invocationId,
|
|
2475
|
+
fieldPath: event.fieldPath,
|
|
2476
|
+
value: event.value,
|
|
2477
|
+
delta: event.delta,
|
|
2478
|
+
isFieldComplete: event.isFieldComplete
|
|
2479
|
+
});
|
|
2480
|
+
}
|
|
2481
|
+
break;
|
|
2470
2482
|
case "gadget_result":
|
|
2471
2483
|
if (handlers.onGadgetResult) {
|
|
2472
2484
|
await handlers.onGadgetResult(event.result);
|
|
@@ -13154,13 +13166,22 @@ var init_parser2 = __esm({
|
|
|
13154
13166
|
GadgetCallParser = class {
|
|
13155
13167
|
buffer = "";
|
|
13156
13168
|
lastEmittedTextOffset = 0;
|
|
13169
|
+
/** Non-null only while a single trailing gadget block is mid-stream. */
|
|
13170
|
+
currentPartial = null;
|
|
13157
13171
|
startPrefix;
|
|
13158
13172
|
endPrefix;
|
|
13159
13173
|
argPrefix;
|
|
13174
|
+
/** Length of the longest marker; `maxMarkerLength - 1` is the scan-resume overlap. */
|
|
13175
|
+
maxMarkerLength;
|
|
13160
13176
|
constructor(options = {}) {
|
|
13161
13177
|
this.startPrefix = options.startPrefix ?? GADGET_START_PREFIX;
|
|
13162
13178
|
this.endPrefix = options.endPrefix ?? GADGET_END_PREFIX;
|
|
13163
13179
|
this.argPrefix = options.argPrefix ?? GADGET_ARG_PREFIX;
|
|
13180
|
+
this.maxMarkerLength = Math.max(
|
|
13181
|
+
this.startPrefix.length,
|
|
13182
|
+
this.endPrefix.length,
|
|
13183
|
+
this.argPrefix.length
|
|
13184
|
+
);
|
|
13164
13185
|
}
|
|
13165
13186
|
/**
|
|
13166
13187
|
* Extract and consume text up to the given index.
|
|
@@ -13247,12 +13268,13 @@ var init_parser2 = __esm({
|
|
|
13247
13268
|
const metadataEndIndex = this.buffer.indexOf("\n", metadataStartIndex);
|
|
13248
13269
|
if (metadataEndIndex === -1) break;
|
|
13249
13270
|
const headerLine = this.buffer.substring(metadataStartIndex, metadataEndIndex).trim();
|
|
13250
|
-
const { gadgetName, invocationId, dependencies } = this.parseInvocationMetadata(headerLine);
|
|
13271
|
+
const { gadgetName, invocationId, dependencies } = this.currentPartial ? this.currentPartial : this.parseInvocationMetadata(headerLine);
|
|
13251
13272
|
const contentStartIndex = metadataEndIndex + 1;
|
|
13252
13273
|
let partEndIndex;
|
|
13253
13274
|
let endMarkerLength = 0;
|
|
13254
|
-
const
|
|
13255
|
-
const
|
|
13275
|
+
const bodySearchStart = this.currentPartial ? contentStartIndex + Math.max(0, this.currentPartial.bodyScannedLen - (this.maxMarkerLength - 1)) : contentStartIndex;
|
|
13276
|
+
const nextStartPos = this.buffer.indexOf(this.startPrefix, bodySearchStart);
|
|
13277
|
+
const endPos = this.buffer.indexOf(this.endPrefix, bodySearchStart);
|
|
13256
13278
|
if (nextStartPos !== -1 && (endPos === -1 || nextStartPos < endPos)) {
|
|
13257
13279
|
partEndIndex = nextStartPos;
|
|
13258
13280
|
endMarkerLength = 0;
|
|
@@ -13260,9 +13282,22 @@ var init_parser2 = __esm({
|
|
|
13260
13282
|
partEndIndex = endPos;
|
|
13261
13283
|
endMarkerLength = this.endPrefix.length;
|
|
13262
13284
|
} else {
|
|
13285
|
+
if (!this.currentPartial) {
|
|
13286
|
+
this.currentPartial = this.newPartialState(gadgetName, invocationId, dependencies);
|
|
13287
|
+
}
|
|
13288
|
+
yield* this.emitArgPartials(
|
|
13289
|
+
this.currentPartial,
|
|
13290
|
+
contentStartIndex,
|
|
13291
|
+
this.buffer.length,
|
|
13292
|
+
false
|
|
13293
|
+
);
|
|
13263
13294
|
break;
|
|
13264
13295
|
}
|
|
13265
|
-
const
|
|
13296
|
+
const rawSlice = this.buffer.substring(contentStartIndex, partEndIndex);
|
|
13297
|
+
if (this.currentPartial) {
|
|
13298
|
+
yield* this.emitArgPartials(this.currentPartial, contentStartIndex, partEndIndex, true);
|
|
13299
|
+
}
|
|
13300
|
+
const parametersRaw = rawSlice.trim();
|
|
13266
13301
|
const { parameters, parseError } = this.parseParameters(parametersRaw);
|
|
13267
13302
|
yield {
|
|
13268
13303
|
type: "gadget_call",
|
|
@@ -13275,6 +13310,7 @@ var init_parser2 = __esm({
|
|
|
13275
13310
|
dependencies
|
|
13276
13311
|
}
|
|
13277
13312
|
};
|
|
13313
|
+
this.currentPartial = null;
|
|
13278
13314
|
startIndex = partEndIndex + endMarkerLength;
|
|
13279
13315
|
this.lastEmittedTextOffset = startIndex;
|
|
13280
13316
|
}
|
|
@@ -13283,6 +13319,117 @@ var init_parser2 = __esm({
|
|
|
13283
13319
|
this.lastEmittedTextOffset = 0;
|
|
13284
13320
|
}
|
|
13285
13321
|
}
|
|
13322
|
+
/** Create fresh partial-tracking state for a newly-started streaming gadget. */
|
|
13323
|
+
newPartialState(gadgetName, invocationId, dependencies) {
|
|
13324
|
+
return {
|
|
13325
|
+
gadgetName,
|
|
13326
|
+
invocationId,
|
|
13327
|
+
dependencies,
|
|
13328
|
+
emittedFieldLengths: /* @__PURE__ */ new Map(),
|
|
13329
|
+
completedFields: /* @__PURE__ */ new Set(),
|
|
13330
|
+
bodyScannedLen: 0,
|
|
13331
|
+
lastArgRelOffset: -1
|
|
13332
|
+
};
|
|
13333
|
+
}
|
|
13334
|
+
/**
|
|
13335
|
+
* Emit per-field "growing value" partials for an in-progress (or, when
|
|
13336
|
+
* `allComplete`, a just-completed) gadget body delimited by [bodyStart, bodyEnd).
|
|
13337
|
+
*
|
|
13338
|
+
* Incremental by design: each call resumes the `!!!ARG:` scan near where the last
|
|
13339
|
+
* one stopped (backing off by one marker's worth so a marker split across a chunk
|
|
13340
|
+
* boundary is still found) and only re-touches the in-progress field, so a long
|
|
13341
|
+
* streamed body costs O(new bytes) per feed instead of O(body). Every field except
|
|
13342
|
+
* the in-progress (last) one is complete — a following `!!!ARG:` terminated it; the
|
|
13343
|
+
* last field is tentative unless `allComplete`. The tentative field holds back any
|
|
13344
|
+
* suffix that is a partial prefix of a gadget marker so it never leaks into a value.
|
|
13345
|
+
*
|
|
13346
|
+
* We deliberately do NOT run stripMarkdownFences here: an unbalanced opening fence
|
|
13347
|
+
* sits before the first `!!!ARG:` (never emitted) and the authoritative gadget_call
|
|
13348
|
+
* still strips fences from the full raw parameters.
|
|
13349
|
+
*/
|
|
13350
|
+
*emitArgPartials(state, bodyStart, bodyEnd, allComplete) {
|
|
13351
|
+
const argLen = this.argPrefix.length;
|
|
13352
|
+
let searchAbs = bodyStart + Math.max(0, state.bodyScannedLen - (this.maxMarkerLength - 1));
|
|
13353
|
+
if (state.lastArgRelOffset >= 0) {
|
|
13354
|
+
searchAbs = Math.max(searchAbs, bodyStart + state.lastArgRelOffset + argLen);
|
|
13355
|
+
}
|
|
13356
|
+
while (true) {
|
|
13357
|
+
const argAbs = this.buffer.indexOf(this.argPrefix, searchAbs);
|
|
13358
|
+
if (argAbs === -1 || argAbs >= bodyEnd) break;
|
|
13359
|
+
if (state.lastArgRelOffset >= 0) {
|
|
13360
|
+
yield* this.emitFieldRange(state, bodyStart + state.lastArgRelOffset, argAbs, true);
|
|
13361
|
+
}
|
|
13362
|
+
state.lastArgRelOffset = argAbs - bodyStart;
|
|
13363
|
+
searchAbs = argAbs + argLen;
|
|
13364
|
+
}
|
|
13365
|
+
if (state.lastArgRelOffset >= 0) {
|
|
13366
|
+
yield* this.emitFieldRange(state, bodyStart + state.lastArgRelOffset, bodyEnd, allComplete);
|
|
13367
|
+
}
|
|
13368
|
+
state.bodyScannedLen = bodyEnd - bodyStart;
|
|
13369
|
+
}
|
|
13370
|
+
/**
|
|
13371
|
+
* Emit a single field whose `!!!ARG:` marker starts at `markerAbs` and whose value
|
|
13372
|
+
* runs to `valueEndAbs` (the next marker, or the body end). Mirrors the per-field
|
|
13373
|
+
* semantics of the old split-based emitter: field-path line, hold-back for a
|
|
13374
|
+
* tentative value, single trailing-newline strip.
|
|
13375
|
+
*/
|
|
13376
|
+
*emitFieldRange(state, markerAbs, valueEndAbs, complete2) {
|
|
13377
|
+
const pathStart = markerAbs + this.argPrefix.length;
|
|
13378
|
+
const newlineAbs = this.buffer.indexOf("\n", pathStart);
|
|
13379
|
+
if (newlineAbs === -1 || newlineAbs >= valueEndAbs) {
|
|
13380
|
+
if (!complete2) return;
|
|
13381
|
+
const pointer = this.buffer.substring(pathStart, valueEndAbs).trim();
|
|
13382
|
+
if (pointer) yield* this.emitFieldDelta(state, pointer, "", true);
|
|
13383
|
+
return;
|
|
13384
|
+
}
|
|
13385
|
+
const fieldPath = this.buffer.substring(pathStart, newlineAbs).trim();
|
|
13386
|
+
if (!fieldPath) return;
|
|
13387
|
+
let value = this.buffer.substring(newlineAbs + 1, valueEndAbs);
|
|
13388
|
+
if (!complete2) {
|
|
13389
|
+
const hold = this.trailingPartialMarkerLength(value);
|
|
13390
|
+
if (hold > 0) value = value.slice(0, value.length - hold);
|
|
13391
|
+
}
|
|
13392
|
+
if (value.endsWith("\n")) value = value.slice(0, -1);
|
|
13393
|
+
yield* this.emitFieldDelta(state, fieldPath, value, complete2);
|
|
13394
|
+
}
|
|
13395
|
+
/**
|
|
13396
|
+
* Emit a single partial for a field, but only when its value grew or it newly
|
|
13397
|
+
* completed — keeping event volume proportional to field growth, not characters.
|
|
13398
|
+
*/
|
|
13399
|
+
*emitFieldDelta(state, fieldPath, value, fieldComplete) {
|
|
13400
|
+
const previousLength = state.emittedFieldLengths.get(fieldPath) ?? -1;
|
|
13401
|
+
const grew = value.length > previousLength;
|
|
13402
|
+
const newlyComplete = fieldComplete && !state.completedFields.has(fieldPath);
|
|
13403
|
+
if (!grew && !newlyComplete) return;
|
|
13404
|
+
const delta = previousLength < 0 ? value : value.slice(Math.min(previousLength, value.length));
|
|
13405
|
+
state.emittedFieldLengths.set(fieldPath, value.length);
|
|
13406
|
+
if (fieldComplete) state.completedFields.add(fieldPath);
|
|
13407
|
+
yield {
|
|
13408
|
+
type: "gadget_args_partial",
|
|
13409
|
+
invocationId: state.invocationId,
|
|
13410
|
+
gadgetName: state.gadgetName,
|
|
13411
|
+
fieldPath,
|
|
13412
|
+
value,
|
|
13413
|
+
delta,
|
|
13414
|
+
isFieldComplete: fieldComplete
|
|
13415
|
+
};
|
|
13416
|
+
}
|
|
13417
|
+
/**
|
|
13418
|
+
* Length of the longest suffix of `value` that is a proper prefix of any gadget
|
|
13419
|
+
* marker (start/end/arg). Used to hold back the beginning of an incoming marker
|
|
13420
|
+
* so it never appears inside a streamed value.
|
|
13421
|
+
*/
|
|
13422
|
+
trailingPartialMarkerLength(value) {
|
|
13423
|
+
const markers = [this.startPrefix, this.endPrefix, this.argPrefix];
|
|
13424
|
+
const limit = Math.min(this.maxMarkerLength - 1, value.length);
|
|
13425
|
+
for (let len = limit; len >= 1; len--) {
|
|
13426
|
+
const suffix = value.slice(value.length - len);
|
|
13427
|
+
for (const marker of markers) {
|
|
13428
|
+
if (suffix.length < marker.length && marker.startsWith(suffix)) return len;
|
|
13429
|
+
}
|
|
13430
|
+
}
|
|
13431
|
+
return 0;
|
|
13432
|
+
}
|
|
13286
13433
|
// Finalize parsing and return remaining text or incomplete gadgets
|
|
13287
13434
|
*finalize() {
|
|
13288
13435
|
const startIndex = this.buffer.indexOf(this.startPrefix, this.lastEmittedTextOffset);
|
|
@@ -13295,9 +13442,18 @@ var init_parser2 = __esm({
|
|
|
13295
13442
|
const metadataEndIndex = this.buffer.indexOf("\n", metadataStartIndex);
|
|
13296
13443
|
if (metadataEndIndex !== -1) {
|
|
13297
13444
|
const headerLine = this.buffer.substring(metadataStartIndex, metadataEndIndex).trim();
|
|
13298
|
-
const { gadgetName, invocationId, dependencies } = this.parseInvocationMetadata(headerLine);
|
|
13445
|
+
const { gadgetName, invocationId, dependencies } = this.currentPartial ? this.currentPartial : this.parseInvocationMetadata(headerLine);
|
|
13299
13446
|
const contentStartIndex = metadataEndIndex + 1;
|
|
13300
|
-
const
|
|
13447
|
+
const contentRaw = this.buffer.substring(contentStartIndex);
|
|
13448
|
+
if (this.currentPartial) {
|
|
13449
|
+
yield* this.emitArgPartials(
|
|
13450
|
+
this.currentPartial,
|
|
13451
|
+
contentStartIndex,
|
|
13452
|
+
this.buffer.length,
|
|
13453
|
+
true
|
|
13454
|
+
);
|
|
13455
|
+
}
|
|
13456
|
+
const parametersRaw = contentRaw.trim();
|
|
13301
13457
|
const { parameters, parseError } = this.parseParameters(parametersRaw);
|
|
13302
13458
|
yield {
|
|
13303
13459
|
type: "gadget_call",
|
|
@@ -13310,6 +13466,7 @@ var init_parser2 = __esm({
|
|
|
13310
13466
|
dependencies
|
|
13311
13467
|
}
|
|
13312
13468
|
};
|
|
13469
|
+
this.currentPartial = null;
|
|
13313
13470
|
return;
|
|
13314
13471
|
}
|
|
13315
13472
|
}
|
|
@@ -13322,6 +13479,7 @@ var init_parser2 = __esm({
|
|
|
13322
13479
|
reset() {
|
|
13323
13480
|
this.buffer = "";
|
|
13324
13481
|
this.lastEmittedTextOffset = 0;
|
|
13482
|
+
this.currentPartial = null;
|
|
13325
13483
|
}
|
|
13326
13484
|
};
|
|
13327
13485
|
}
|
|
@@ -14247,6 +14405,29 @@ async function notifyGadgetStart(ctx) {
|
|
|
14247
14405
|
await safeObserve(() => hookFn(context), ctx.logger);
|
|
14248
14406
|
}
|
|
14249
14407
|
}
|
|
14408
|
+
async function notifyGadgetArgsPartial(ctx) {
|
|
14409
|
+
if (!ctx.hooks?.onGadgetArgsPartial && !ctx.parentObservers?.onGadgetArgsPartial) return;
|
|
14410
|
+
const subagentContext = ctx.tree && ctx.parentNodeId ? getSubagentContextForNode(ctx.tree, ctx.parentNodeId) : void 0;
|
|
14411
|
+
const context = {
|
|
14412
|
+
iteration: ctx.iteration,
|
|
14413
|
+
invocationId: ctx.event.invocationId,
|
|
14414
|
+
gadgetName: ctx.event.gadgetName,
|
|
14415
|
+
fieldPath: ctx.event.fieldPath,
|
|
14416
|
+
value: ctx.event.value,
|
|
14417
|
+
delta: ctx.event.delta,
|
|
14418
|
+
isFieldComplete: ctx.event.isFieldComplete,
|
|
14419
|
+
logger: ctx.logger,
|
|
14420
|
+
subagentContext
|
|
14421
|
+
};
|
|
14422
|
+
if (ctx.hooks?.onGadgetArgsPartial) {
|
|
14423
|
+
const hookFn = ctx.hooks.onGadgetArgsPartial;
|
|
14424
|
+
await safeObserve(() => hookFn(context), ctx.logger);
|
|
14425
|
+
}
|
|
14426
|
+
if (ctx.parentObservers?.onGadgetArgsPartial) {
|
|
14427
|
+
const hookFn = ctx.parentObservers.onGadgetArgsPartial;
|
|
14428
|
+
await safeObserve(() => hookFn(context), ctx.logger);
|
|
14429
|
+
}
|
|
14430
|
+
}
|
|
14250
14431
|
async function notifyGadgetComplete(ctx) {
|
|
14251
14432
|
const gadgetNode = ctx.tree?.getNodeByInvocationId(ctx.invocationId);
|
|
14252
14433
|
const subagentContext = ctx.tree && gadgetNode ? getSubagentContextForNode(ctx.tree, gadgetNode.id) : void 0;
|
|
@@ -15055,6 +15236,7 @@ var init_stream_processor = __esm({
|
|
|
15055
15236
|
init_gadget_dispatcher();
|
|
15056
15237
|
init_gadget_hook_lifecycle();
|
|
15057
15238
|
init_gadget_limit_guard();
|
|
15239
|
+
init_observer_notifier();
|
|
15058
15240
|
init_safe_observe();
|
|
15059
15241
|
StreamProcessor = class {
|
|
15060
15242
|
iteration;
|
|
@@ -15063,6 +15245,10 @@ var init_stream_processor = __esm({
|
|
|
15063
15245
|
parser;
|
|
15064
15246
|
// Execution Tree context
|
|
15065
15247
|
tree;
|
|
15248
|
+
/** LLM-call node these gadgets hang off; used to derive subagentContext for partials. */
|
|
15249
|
+
parentNodeId;
|
|
15250
|
+
/** Parent agent observers (subagent visibility) — also notified for arg partials. */
|
|
15251
|
+
parentObservers;
|
|
15066
15252
|
responseText = "";
|
|
15067
15253
|
// Dependency resolution is delegated to GadgetDependencyResolver
|
|
15068
15254
|
dependencyResolver;
|
|
@@ -15076,6 +15262,8 @@ var init_stream_processor = __esm({
|
|
|
15076
15262
|
this.hooks = options.hooks ?? {};
|
|
15077
15263
|
this.logger = options.logger ?? createLogger({ name: "llmist:stream-processor" });
|
|
15078
15264
|
this.tree = options.tree;
|
|
15265
|
+
this.parentNodeId = options.parentNodeId;
|
|
15266
|
+
this.parentObservers = options.parentObservers;
|
|
15079
15267
|
this.dependencyResolver = new GadgetDependencyResolver({
|
|
15080
15268
|
priorCompletedInvocations: options.priorCompletedInvocations,
|
|
15081
15269
|
priorFailedInvocations: options.priorFailedInvocations
|
|
@@ -15277,6 +15465,17 @@ var init_stream_processor = __esm({
|
|
|
15277
15465
|
for await (const e of this.dispatcher.dispatch(event.call)) {
|
|
15278
15466
|
yield e;
|
|
15279
15467
|
}
|
|
15468
|
+
} else if (event.type === "gadget_args_partial") {
|
|
15469
|
+
await notifyGadgetArgsPartial({
|
|
15470
|
+
tree: this.tree,
|
|
15471
|
+
hooks: this.hooks.observers,
|
|
15472
|
+
parentObservers: this.parentObservers,
|
|
15473
|
+
logger: this.logger,
|
|
15474
|
+
iteration: this.iteration,
|
|
15475
|
+
parentNodeId: this.parentNodeId,
|
|
15476
|
+
event
|
|
15477
|
+
});
|
|
15478
|
+
yield event;
|
|
15280
15479
|
} else {
|
|
15281
15480
|
yield event;
|
|
15282
15481
|
}
|