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.cjs
CHANGED
|
@@ -3258,6 +3258,18 @@ async function runWithHandlers(agentGenerator, handlers) {
|
|
|
3258
3258
|
});
|
|
3259
3259
|
}
|
|
3260
3260
|
break;
|
|
3261
|
+
case "gadget_args_partial":
|
|
3262
|
+
if (handlers.onGadgetArgsPartial) {
|
|
3263
|
+
await handlers.onGadgetArgsPartial({
|
|
3264
|
+
gadgetName: event.gadgetName,
|
|
3265
|
+
invocationId: event.invocationId,
|
|
3266
|
+
fieldPath: event.fieldPath,
|
|
3267
|
+
value: event.value,
|
|
3268
|
+
delta: event.delta,
|
|
3269
|
+
isFieldComplete: event.isFieldComplete
|
|
3270
|
+
});
|
|
3271
|
+
}
|
|
3272
|
+
break;
|
|
3261
3273
|
case "gadget_result":
|
|
3262
3274
|
if (handlers.onGadgetResult) {
|
|
3263
3275
|
await handlers.onGadgetResult(event.result);
|
|
@@ -14570,13 +14582,22 @@ var init_parser2 = __esm({
|
|
|
14570
14582
|
GadgetCallParser = class {
|
|
14571
14583
|
buffer = "";
|
|
14572
14584
|
lastEmittedTextOffset = 0;
|
|
14585
|
+
/** Non-null only while a single trailing gadget block is mid-stream. */
|
|
14586
|
+
currentPartial = null;
|
|
14573
14587
|
startPrefix;
|
|
14574
14588
|
endPrefix;
|
|
14575
14589
|
argPrefix;
|
|
14590
|
+
/** Length of the longest marker; `maxMarkerLength - 1` is the scan-resume overlap. */
|
|
14591
|
+
maxMarkerLength;
|
|
14576
14592
|
constructor(options = {}) {
|
|
14577
14593
|
this.startPrefix = options.startPrefix ?? GADGET_START_PREFIX;
|
|
14578
14594
|
this.endPrefix = options.endPrefix ?? GADGET_END_PREFIX;
|
|
14579
14595
|
this.argPrefix = options.argPrefix ?? GADGET_ARG_PREFIX;
|
|
14596
|
+
this.maxMarkerLength = Math.max(
|
|
14597
|
+
this.startPrefix.length,
|
|
14598
|
+
this.endPrefix.length,
|
|
14599
|
+
this.argPrefix.length
|
|
14600
|
+
);
|
|
14580
14601
|
}
|
|
14581
14602
|
/**
|
|
14582
14603
|
* Extract and consume text up to the given index.
|
|
@@ -14663,12 +14684,13 @@ var init_parser2 = __esm({
|
|
|
14663
14684
|
const metadataEndIndex = this.buffer.indexOf("\n", metadataStartIndex);
|
|
14664
14685
|
if (metadataEndIndex === -1) break;
|
|
14665
14686
|
const headerLine = this.buffer.substring(metadataStartIndex, metadataEndIndex).trim();
|
|
14666
|
-
const { gadgetName, invocationId, dependencies } = this.parseInvocationMetadata(headerLine);
|
|
14687
|
+
const { gadgetName, invocationId, dependencies } = this.currentPartial ? this.currentPartial : this.parseInvocationMetadata(headerLine);
|
|
14667
14688
|
const contentStartIndex = metadataEndIndex + 1;
|
|
14668
14689
|
let partEndIndex;
|
|
14669
14690
|
let endMarkerLength = 0;
|
|
14670
|
-
const
|
|
14671
|
-
const
|
|
14691
|
+
const bodySearchStart = this.currentPartial ? contentStartIndex + Math.max(0, this.currentPartial.bodyScannedLen - (this.maxMarkerLength - 1)) : contentStartIndex;
|
|
14692
|
+
const nextStartPos = this.buffer.indexOf(this.startPrefix, bodySearchStart);
|
|
14693
|
+
const endPos = this.buffer.indexOf(this.endPrefix, bodySearchStart);
|
|
14672
14694
|
if (nextStartPos !== -1 && (endPos === -1 || nextStartPos < endPos)) {
|
|
14673
14695
|
partEndIndex = nextStartPos;
|
|
14674
14696
|
endMarkerLength = 0;
|
|
@@ -14676,9 +14698,22 @@ var init_parser2 = __esm({
|
|
|
14676
14698
|
partEndIndex = endPos;
|
|
14677
14699
|
endMarkerLength = this.endPrefix.length;
|
|
14678
14700
|
} else {
|
|
14701
|
+
if (!this.currentPartial) {
|
|
14702
|
+
this.currentPartial = this.newPartialState(gadgetName, invocationId, dependencies);
|
|
14703
|
+
}
|
|
14704
|
+
yield* this.emitArgPartials(
|
|
14705
|
+
this.currentPartial,
|
|
14706
|
+
contentStartIndex,
|
|
14707
|
+
this.buffer.length,
|
|
14708
|
+
false
|
|
14709
|
+
);
|
|
14679
14710
|
break;
|
|
14680
14711
|
}
|
|
14681
|
-
const
|
|
14712
|
+
const rawSlice = this.buffer.substring(contentStartIndex, partEndIndex);
|
|
14713
|
+
if (this.currentPartial) {
|
|
14714
|
+
yield* this.emitArgPartials(this.currentPartial, contentStartIndex, partEndIndex, true);
|
|
14715
|
+
}
|
|
14716
|
+
const parametersRaw = rawSlice.trim();
|
|
14682
14717
|
const { parameters, parseError } = this.parseParameters(parametersRaw);
|
|
14683
14718
|
yield {
|
|
14684
14719
|
type: "gadget_call",
|
|
@@ -14691,6 +14726,7 @@ var init_parser2 = __esm({
|
|
|
14691
14726
|
dependencies
|
|
14692
14727
|
}
|
|
14693
14728
|
};
|
|
14729
|
+
this.currentPartial = null;
|
|
14694
14730
|
startIndex = partEndIndex + endMarkerLength;
|
|
14695
14731
|
this.lastEmittedTextOffset = startIndex;
|
|
14696
14732
|
}
|
|
@@ -14699,6 +14735,117 @@ var init_parser2 = __esm({
|
|
|
14699
14735
|
this.lastEmittedTextOffset = 0;
|
|
14700
14736
|
}
|
|
14701
14737
|
}
|
|
14738
|
+
/** Create fresh partial-tracking state for a newly-started streaming gadget. */
|
|
14739
|
+
newPartialState(gadgetName, invocationId, dependencies) {
|
|
14740
|
+
return {
|
|
14741
|
+
gadgetName,
|
|
14742
|
+
invocationId,
|
|
14743
|
+
dependencies,
|
|
14744
|
+
emittedFieldLengths: /* @__PURE__ */ new Map(),
|
|
14745
|
+
completedFields: /* @__PURE__ */ new Set(),
|
|
14746
|
+
bodyScannedLen: 0,
|
|
14747
|
+
lastArgRelOffset: -1
|
|
14748
|
+
};
|
|
14749
|
+
}
|
|
14750
|
+
/**
|
|
14751
|
+
* Emit per-field "growing value" partials for an in-progress (or, when
|
|
14752
|
+
* `allComplete`, a just-completed) gadget body delimited by [bodyStart, bodyEnd).
|
|
14753
|
+
*
|
|
14754
|
+
* Incremental by design: each call resumes the `!!!ARG:` scan near where the last
|
|
14755
|
+
* one stopped (backing off by one marker's worth so a marker split across a chunk
|
|
14756
|
+
* boundary is still found) and only re-touches the in-progress field, so a long
|
|
14757
|
+
* streamed body costs O(new bytes) per feed instead of O(body). Every field except
|
|
14758
|
+
* the in-progress (last) one is complete — a following `!!!ARG:` terminated it; the
|
|
14759
|
+
* last field is tentative unless `allComplete`. The tentative field holds back any
|
|
14760
|
+
* suffix that is a partial prefix of a gadget marker so it never leaks into a value.
|
|
14761
|
+
*
|
|
14762
|
+
* We deliberately do NOT run stripMarkdownFences here: an unbalanced opening fence
|
|
14763
|
+
* sits before the first `!!!ARG:` (never emitted) and the authoritative gadget_call
|
|
14764
|
+
* still strips fences from the full raw parameters.
|
|
14765
|
+
*/
|
|
14766
|
+
*emitArgPartials(state, bodyStart, bodyEnd, allComplete) {
|
|
14767
|
+
const argLen = this.argPrefix.length;
|
|
14768
|
+
let searchAbs = bodyStart + Math.max(0, state.bodyScannedLen - (this.maxMarkerLength - 1));
|
|
14769
|
+
if (state.lastArgRelOffset >= 0) {
|
|
14770
|
+
searchAbs = Math.max(searchAbs, bodyStart + state.lastArgRelOffset + argLen);
|
|
14771
|
+
}
|
|
14772
|
+
while (true) {
|
|
14773
|
+
const argAbs = this.buffer.indexOf(this.argPrefix, searchAbs);
|
|
14774
|
+
if (argAbs === -1 || argAbs >= bodyEnd) break;
|
|
14775
|
+
if (state.lastArgRelOffset >= 0) {
|
|
14776
|
+
yield* this.emitFieldRange(state, bodyStart + state.lastArgRelOffset, argAbs, true);
|
|
14777
|
+
}
|
|
14778
|
+
state.lastArgRelOffset = argAbs - bodyStart;
|
|
14779
|
+
searchAbs = argAbs + argLen;
|
|
14780
|
+
}
|
|
14781
|
+
if (state.lastArgRelOffset >= 0) {
|
|
14782
|
+
yield* this.emitFieldRange(state, bodyStart + state.lastArgRelOffset, bodyEnd, allComplete);
|
|
14783
|
+
}
|
|
14784
|
+
state.bodyScannedLen = bodyEnd - bodyStart;
|
|
14785
|
+
}
|
|
14786
|
+
/**
|
|
14787
|
+
* Emit a single field whose `!!!ARG:` marker starts at `markerAbs` and whose value
|
|
14788
|
+
* runs to `valueEndAbs` (the next marker, or the body end). Mirrors the per-field
|
|
14789
|
+
* semantics of the old split-based emitter: field-path line, hold-back for a
|
|
14790
|
+
* tentative value, single trailing-newline strip.
|
|
14791
|
+
*/
|
|
14792
|
+
*emitFieldRange(state, markerAbs, valueEndAbs, complete2) {
|
|
14793
|
+
const pathStart = markerAbs + this.argPrefix.length;
|
|
14794
|
+
const newlineAbs = this.buffer.indexOf("\n", pathStart);
|
|
14795
|
+
if (newlineAbs === -1 || newlineAbs >= valueEndAbs) {
|
|
14796
|
+
if (!complete2) return;
|
|
14797
|
+
const pointer = this.buffer.substring(pathStart, valueEndAbs).trim();
|
|
14798
|
+
if (pointer) yield* this.emitFieldDelta(state, pointer, "", true);
|
|
14799
|
+
return;
|
|
14800
|
+
}
|
|
14801
|
+
const fieldPath = this.buffer.substring(pathStart, newlineAbs).trim();
|
|
14802
|
+
if (!fieldPath) return;
|
|
14803
|
+
let value = this.buffer.substring(newlineAbs + 1, valueEndAbs);
|
|
14804
|
+
if (!complete2) {
|
|
14805
|
+
const hold = this.trailingPartialMarkerLength(value);
|
|
14806
|
+
if (hold > 0) value = value.slice(0, value.length - hold);
|
|
14807
|
+
}
|
|
14808
|
+
if (value.endsWith("\n")) value = value.slice(0, -1);
|
|
14809
|
+
yield* this.emitFieldDelta(state, fieldPath, value, complete2);
|
|
14810
|
+
}
|
|
14811
|
+
/**
|
|
14812
|
+
* Emit a single partial for a field, but only when its value grew or it newly
|
|
14813
|
+
* completed — keeping event volume proportional to field growth, not characters.
|
|
14814
|
+
*/
|
|
14815
|
+
*emitFieldDelta(state, fieldPath, value, fieldComplete) {
|
|
14816
|
+
const previousLength = state.emittedFieldLengths.get(fieldPath) ?? -1;
|
|
14817
|
+
const grew = value.length > previousLength;
|
|
14818
|
+
const newlyComplete = fieldComplete && !state.completedFields.has(fieldPath);
|
|
14819
|
+
if (!grew && !newlyComplete) return;
|
|
14820
|
+
const delta = previousLength < 0 ? value : value.slice(Math.min(previousLength, value.length));
|
|
14821
|
+
state.emittedFieldLengths.set(fieldPath, value.length);
|
|
14822
|
+
if (fieldComplete) state.completedFields.add(fieldPath);
|
|
14823
|
+
yield {
|
|
14824
|
+
type: "gadget_args_partial",
|
|
14825
|
+
invocationId: state.invocationId,
|
|
14826
|
+
gadgetName: state.gadgetName,
|
|
14827
|
+
fieldPath,
|
|
14828
|
+
value,
|
|
14829
|
+
delta,
|
|
14830
|
+
isFieldComplete: fieldComplete
|
|
14831
|
+
};
|
|
14832
|
+
}
|
|
14833
|
+
/**
|
|
14834
|
+
* Length of the longest suffix of `value` that is a proper prefix of any gadget
|
|
14835
|
+
* marker (start/end/arg). Used to hold back the beginning of an incoming marker
|
|
14836
|
+
* so it never appears inside a streamed value.
|
|
14837
|
+
*/
|
|
14838
|
+
trailingPartialMarkerLength(value) {
|
|
14839
|
+
const markers = [this.startPrefix, this.endPrefix, this.argPrefix];
|
|
14840
|
+
const limit = Math.min(this.maxMarkerLength - 1, value.length);
|
|
14841
|
+
for (let len = limit; len >= 1; len--) {
|
|
14842
|
+
const suffix = value.slice(value.length - len);
|
|
14843
|
+
for (const marker of markers) {
|
|
14844
|
+
if (suffix.length < marker.length && marker.startsWith(suffix)) return len;
|
|
14845
|
+
}
|
|
14846
|
+
}
|
|
14847
|
+
return 0;
|
|
14848
|
+
}
|
|
14702
14849
|
// Finalize parsing and return remaining text or incomplete gadgets
|
|
14703
14850
|
*finalize() {
|
|
14704
14851
|
const startIndex = this.buffer.indexOf(this.startPrefix, this.lastEmittedTextOffset);
|
|
@@ -14711,9 +14858,18 @@ var init_parser2 = __esm({
|
|
|
14711
14858
|
const metadataEndIndex = this.buffer.indexOf("\n", metadataStartIndex);
|
|
14712
14859
|
if (metadataEndIndex !== -1) {
|
|
14713
14860
|
const headerLine = this.buffer.substring(metadataStartIndex, metadataEndIndex).trim();
|
|
14714
|
-
const { gadgetName, invocationId, dependencies } = this.parseInvocationMetadata(headerLine);
|
|
14861
|
+
const { gadgetName, invocationId, dependencies } = this.currentPartial ? this.currentPartial : this.parseInvocationMetadata(headerLine);
|
|
14715
14862
|
const contentStartIndex = metadataEndIndex + 1;
|
|
14716
|
-
const
|
|
14863
|
+
const contentRaw = this.buffer.substring(contentStartIndex);
|
|
14864
|
+
if (this.currentPartial) {
|
|
14865
|
+
yield* this.emitArgPartials(
|
|
14866
|
+
this.currentPartial,
|
|
14867
|
+
contentStartIndex,
|
|
14868
|
+
this.buffer.length,
|
|
14869
|
+
true
|
|
14870
|
+
);
|
|
14871
|
+
}
|
|
14872
|
+
const parametersRaw = contentRaw.trim();
|
|
14717
14873
|
const { parameters, parseError } = this.parseParameters(parametersRaw);
|
|
14718
14874
|
yield {
|
|
14719
14875
|
type: "gadget_call",
|
|
@@ -14726,6 +14882,7 @@ var init_parser2 = __esm({
|
|
|
14726
14882
|
dependencies
|
|
14727
14883
|
}
|
|
14728
14884
|
};
|
|
14885
|
+
this.currentPartial = null;
|
|
14729
14886
|
return;
|
|
14730
14887
|
}
|
|
14731
14888
|
}
|
|
@@ -14738,6 +14895,7 @@ var init_parser2 = __esm({
|
|
|
14738
14895
|
reset() {
|
|
14739
14896
|
this.buffer = "";
|
|
14740
14897
|
this.lastEmittedTextOffset = 0;
|
|
14898
|
+
this.currentPartial = null;
|
|
14741
14899
|
}
|
|
14742
14900
|
};
|
|
14743
14901
|
}
|
|
@@ -15663,6 +15821,29 @@ async function notifyGadgetStart(ctx) {
|
|
|
15663
15821
|
await safeObserve(() => hookFn(context), ctx.logger);
|
|
15664
15822
|
}
|
|
15665
15823
|
}
|
|
15824
|
+
async function notifyGadgetArgsPartial(ctx) {
|
|
15825
|
+
if (!ctx.hooks?.onGadgetArgsPartial && !ctx.parentObservers?.onGadgetArgsPartial) return;
|
|
15826
|
+
const subagentContext = ctx.tree && ctx.parentNodeId ? getSubagentContextForNode(ctx.tree, ctx.parentNodeId) : void 0;
|
|
15827
|
+
const context = {
|
|
15828
|
+
iteration: ctx.iteration,
|
|
15829
|
+
invocationId: ctx.event.invocationId,
|
|
15830
|
+
gadgetName: ctx.event.gadgetName,
|
|
15831
|
+
fieldPath: ctx.event.fieldPath,
|
|
15832
|
+
value: ctx.event.value,
|
|
15833
|
+
delta: ctx.event.delta,
|
|
15834
|
+
isFieldComplete: ctx.event.isFieldComplete,
|
|
15835
|
+
logger: ctx.logger,
|
|
15836
|
+
subagentContext
|
|
15837
|
+
};
|
|
15838
|
+
if (ctx.hooks?.onGadgetArgsPartial) {
|
|
15839
|
+
const hookFn = ctx.hooks.onGadgetArgsPartial;
|
|
15840
|
+
await safeObserve(() => hookFn(context), ctx.logger);
|
|
15841
|
+
}
|
|
15842
|
+
if (ctx.parentObservers?.onGadgetArgsPartial) {
|
|
15843
|
+
const hookFn = ctx.parentObservers.onGadgetArgsPartial;
|
|
15844
|
+
await safeObserve(() => hookFn(context), ctx.logger);
|
|
15845
|
+
}
|
|
15846
|
+
}
|
|
15666
15847
|
async function notifyGadgetComplete(ctx) {
|
|
15667
15848
|
const gadgetNode = ctx.tree?.getNodeByInvocationId(ctx.invocationId);
|
|
15668
15849
|
const subagentContext = ctx.tree && gadgetNode ? getSubagentContextForNode(ctx.tree, gadgetNode.id) : void 0;
|
|
@@ -16471,6 +16652,7 @@ var init_stream_processor = __esm({
|
|
|
16471
16652
|
init_gadget_dispatcher();
|
|
16472
16653
|
init_gadget_hook_lifecycle();
|
|
16473
16654
|
init_gadget_limit_guard();
|
|
16655
|
+
init_observer_notifier();
|
|
16474
16656
|
init_safe_observe();
|
|
16475
16657
|
StreamProcessor = class {
|
|
16476
16658
|
iteration;
|
|
@@ -16479,6 +16661,10 @@ var init_stream_processor = __esm({
|
|
|
16479
16661
|
parser;
|
|
16480
16662
|
// Execution Tree context
|
|
16481
16663
|
tree;
|
|
16664
|
+
/** LLM-call node these gadgets hang off; used to derive subagentContext for partials. */
|
|
16665
|
+
parentNodeId;
|
|
16666
|
+
/** Parent agent observers (subagent visibility) — also notified for arg partials. */
|
|
16667
|
+
parentObservers;
|
|
16482
16668
|
responseText = "";
|
|
16483
16669
|
// Dependency resolution is delegated to GadgetDependencyResolver
|
|
16484
16670
|
dependencyResolver;
|
|
@@ -16492,6 +16678,8 @@ var init_stream_processor = __esm({
|
|
|
16492
16678
|
this.hooks = options.hooks ?? {};
|
|
16493
16679
|
this.logger = options.logger ?? createLogger({ name: "llmist:stream-processor" });
|
|
16494
16680
|
this.tree = options.tree;
|
|
16681
|
+
this.parentNodeId = options.parentNodeId;
|
|
16682
|
+
this.parentObservers = options.parentObservers;
|
|
16495
16683
|
this.dependencyResolver = new GadgetDependencyResolver({
|
|
16496
16684
|
priorCompletedInvocations: options.priorCompletedInvocations,
|
|
16497
16685
|
priorFailedInvocations: options.priorFailedInvocations
|
|
@@ -16693,6 +16881,17 @@ var init_stream_processor = __esm({
|
|
|
16693
16881
|
for await (const e of this.dispatcher.dispatch(event.call)) {
|
|
16694
16882
|
yield e;
|
|
16695
16883
|
}
|
|
16884
|
+
} else if (event.type === "gadget_args_partial") {
|
|
16885
|
+
await notifyGadgetArgsPartial({
|
|
16886
|
+
tree: this.tree,
|
|
16887
|
+
hooks: this.hooks.observers,
|
|
16888
|
+
parentObservers: this.parentObservers,
|
|
16889
|
+
logger: this.logger,
|
|
16890
|
+
iteration: this.iteration,
|
|
16891
|
+
parentNodeId: this.parentNodeId,
|
|
16892
|
+
event
|
|
16893
|
+
});
|
|
16894
|
+
yield event;
|
|
16696
16895
|
} else {
|
|
16697
16896
|
yield event;
|
|
16698
16897
|
}
|