@noetic-tools/core 5.0.0 → 5.1.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/harness/agent-harness.d.ts +6 -3
- package/dist/harness/agent-harness.js +23 -12
- package/dist/harness/model-call.d.ts +7 -0
- package/dist/harness/model-call.js +19 -0
- package/dist/runtime/session-runner.js +12 -0
- package/dist/runtime/session-streams.d.ts +5 -1
- package/dist/runtime/session-streams.js +17 -2
- package/package.json +1 -1
|
@@ -253,9 +253,12 @@ export declare class AgentHarness<TParams extends Record<string, unknown> = Reco
|
|
|
253
253
|
* the same arrangement `executeLLM` builds: harness-level context layers'
|
|
254
254
|
* recall outputs concatenated with the session's accumulated history.
|
|
255
255
|
*
|
|
256
|
-
*
|
|
257
|
-
*
|
|
258
|
-
*
|
|
256
|
+
* Runs layer `init` on the throwaway preview context first — exactly what
|
|
257
|
+
* the next real turn's `ensureLayersInit` would do, re-hydrating thread/
|
|
258
|
+
* resource-scoped state from storage. Without it, every init-bearing layer
|
|
259
|
+
* is treated as disabled by the recall lifecycle and the preview silently
|
|
260
|
+
* degenerates to bare history. The preview execution's store entries are
|
|
261
|
+
* dropped afterwards so repeated previews don't grow the layer-state store.
|
|
259
262
|
*/
|
|
260
263
|
previewRequestItems(scope?: SessionScope): Promise<ReadonlyArray<Item>>;
|
|
261
264
|
storeLayers(layers: ContextLayer[], response: LLMResponse, ctx: Context): Promise<void>;
|
|
@@ -631,9 +631,12 @@ export class AgentHarness {
|
|
|
631
631
|
* the same arrangement `executeLLM` builds: harness-level context layers'
|
|
632
632
|
* recall outputs concatenated with the session's accumulated history.
|
|
633
633
|
*
|
|
634
|
-
*
|
|
635
|
-
*
|
|
636
|
-
*
|
|
634
|
+
* Runs layer `init` on the throwaway preview context first — exactly what
|
|
635
|
+
* the next real turn's `ensureLayersInit` would do, re-hydrating thread/
|
|
636
|
+
* resource-scoped state from storage. Without it, every init-bearing layer
|
|
637
|
+
* is treated as disabled by the recall lifecycle and the preview silently
|
|
638
|
+
* degenerates to bare history. The preview execution's store entries are
|
|
639
|
+
* dropped afterwards so repeated previews don't grow the layer-state store.
|
|
637
640
|
*/
|
|
638
641
|
async previewRequestItems(scope) {
|
|
639
642
|
const threadId = scope?.threadId ?? DEFAULT_THREAD_ID;
|
|
@@ -654,16 +657,24 @@ export class AgentHarness {
|
|
|
654
657
|
if (layers.length === 0) {
|
|
655
658
|
return historyItems;
|
|
656
659
|
}
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
660
|
+
try {
|
|
661
|
+
await this.ensureLayersInit(ctx);
|
|
662
|
+
const recallResults = await this.recallLayers(layers, '', ctx);
|
|
663
|
+
const layerOutputItems = recallResults.flatMap((r) => r.items);
|
|
664
|
+
if (layerOutputItems.length === 0) {
|
|
665
|
+
return historyItems;
|
|
666
|
+
}
|
|
667
|
+
return assembleView({
|
|
668
|
+
systemPromptItems: [],
|
|
669
|
+
layerOutputItems,
|
|
670
|
+
historyItems,
|
|
671
|
+
});
|
|
672
|
+
}
|
|
673
|
+
finally {
|
|
674
|
+
await this.layerStateStore.flush?.(ctx.id);
|
|
675
|
+
this.layerStateStore.cleanup(ctx.id);
|
|
676
|
+
this.initializedExecutions.delete(ctx.id);
|
|
661
677
|
}
|
|
662
|
-
return assembleView({
|
|
663
|
-
systemPromptItems: [],
|
|
664
|
-
layerOutputItems,
|
|
665
|
-
historyItems,
|
|
666
|
-
});
|
|
667
678
|
}
|
|
668
679
|
async storeLayers(layers, response, ctx) {
|
|
669
680
|
const storage = this.config.storage;
|
|
@@ -34,6 +34,13 @@ export declare class AgentHarnessModelCaller {
|
|
|
34
34
|
private readonly opts;
|
|
35
35
|
constructor(opts: AgentHarnessModelCallerOpts);
|
|
36
36
|
private newSpanCollector;
|
|
37
|
+
/**
|
|
38
|
+
* Broadcast a framework-authored item so `getItemStream` carries it — tool
|
|
39
|
+
* results and injected messages never appear in the SDK stream. Emitted
|
|
40
|
+
* unconditionally: item streaming, like the SDK item events, is not subject
|
|
41
|
+
* to `step.emit` filtering.
|
|
42
|
+
*/
|
|
43
|
+
private emitItemAppended;
|
|
37
44
|
private callOverriddenModel;
|
|
38
45
|
private requireModelClient;
|
|
39
46
|
callModel(request: CallModelRequest): Promise<LLMResponse>;
|
|
@@ -302,6 +302,22 @@ export class AgentHarnessModelCaller {
|
|
|
302
302
|
newSpanCollector(request) {
|
|
303
303
|
return new CallSpanCollector(this.opts.harness, this.opts.traceExporter, request.parentSpan ?? request.ctx?.span ?? null, request.nodeId);
|
|
304
304
|
}
|
|
305
|
+
/**
|
|
306
|
+
* Broadcast a framework-authored item so `getItemStream` carries it — tool
|
|
307
|
+
* results and injected messages never appear in the SDK stream. Emitted
|
|
308
|
+
* unconditionally: item streaming, like the SDK item events, is not subject
|
|
309
|
+
* to `step.emit` filtering.
|
|
310
|
+
*/
|
|
311
|
+
emitItemAppended(ctx, item) {
|
|
312
|
+
emitFrameworkEvent({
|
|
313
|
+
broadcaster: getBroadcaster(ctx),
|
|
314
|
+
agentName: this.opts.agentName,
|
|
315
|
+
eventType: 'item_appended',
|
|
316
|
+
data: {
|
|
317
|
+
item,
|
|
318
|
+
},
|
|
319
|
+
});
|
|
320
|
+
}
|
|
305
321
|
async callOverriddenModel(request) {
|
|
306
322
|
if (!this.opts.callModelOverride) {
|
|
307
323
|
throw new Error('No callModel override configured.');
|
|
@@ -557,6 +573,7 @@ export class AgentHarnessModelCaller {
|
|
|
557
573
|
],
|
|
558
574
|
});
|
|
559
575
|
ctx.itemLog.append(userItem);
|
|
576
|
+
this.emitItemAppended(ctx, userItem);
|
|
560
577
|
}
|
|
561
578
|
emitIfAllowed('inbox_injected', {
|
|
562
579
|
round,
|
|
@@ -706,6 +723,7 @@ export class AgentHarnessModelCaller {
|
|
|
706
723
|
callId: fc.callId,
|
|
707
724
|
output: toolResult.output,
|
|
708
725
|
});
|
|
726
|
+
this.emitItemAppended(request.ctx, outputItem);
|
|
709
727
|
params.emitIfAllowed('tool_call_completed', {
|
|
710
728
|
name: fc.name,
|
|
711
729
|
callId: fc.callId,
|
|
@@ -731,6 +749,7 @@ export class AgentHarnessModelCaller {
|
|
|
731
749
|
callId: fc.callId,
|
|
732
750
|
output: errorOutput,
|
|
733
751
|
});
|
|
752
|
+
this.emitItemAppended(request.ctx, outputItem);
|
|
734
753
|
params.emitIfAllowed('tool_call_completed', {
|
|
735
754
|
name: fc.name,
|
|
736
755
|
callId: fc.callId,
|
|
@@ -174,6 +174,18 @@ export class SessionRunner {
|
|
|
174
174
|
messageIds: messages.map((m) => m.id),
|
|
175
175
|
},
|
|
176
176
|
});
|
|
177
|
+
// Input items never appear in the SDK stream — item_appended is what
|
|
178
|
+
// carries them into getItemStream (and any other log-faithful consumer).
|
|
179
|
+
for (const item of items) {
|
|
180
|
+
emitFrameworkEvent({
|
|
181
|
+
broadcaster: this.broadcaster,
|
|
182
|
+
agentName: this.agentName,
|
|
183
|
+
eventType: 'item_appended',
|
|
184
|
+
data: {
|
|
185
|
+
item,
|
|
186
|
+
},
|
|
187
|
+
});
|
|
188
|
+
}
|
|
177
189
|
const turn = {
|
|
178
190
|
turnId,
|
|
179
191
|
session: this,
|
|
@@ -6,5 +6,9 @@ export declare function filterTextStream(broadcaster: EventBroadcaster): AsyncIt
|
|
|
6
6
|
export declare function filterReasoningStream(broadcaster: EventBroadcaster): AsyncIterable<string>;
|
|
7
7
|
/** @internal Yield cumulative StreamingItem snapshots. Uses roundOffset keyed by
|
|
8
8
|
* response.created so accumulators across multiple tool rounds and across
|
|
9
|
-
* multiple turns within a session don't collide.
|
|
9
|
+
* multiple turns within a session don't collide.
|
|
10
|
+
*
|
|
11
|
+
* SDK events cover model output only; framework-authored items — turn input
|
|
12
|
+
* messages, between-rounds injections, tool results — arrive via the
|
|
13
|
+
* `item_appended` framework event and are yielded already complete. */
|
|
10
14
|
export declare function buildItemStream(broadcaster: EventBroadcaster, itemSchemas?: ItemSchemaRegistry): AsyncIterable<StreamingItem>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defaultItemSchemaRegistry } from '@noetic-tools/types';
|
|
1
|
+
import { defaultItemSchemaRegistry, frameworkCast } from '@noetic-tools/types';
|
|
2
2
|
//#endregion
|
|
3
3
|
//#region Helpers
|
|
4
4
|
function isItemRecord(value) {
|
|
@@ -138,11 +138,26 @@ export async function* filterReasoningStream(broadcaster) {
|
|
|
138
138
|
}
|
|
139
139
|
/** @internal Yield cumulative StreamingItem snapshots. Uses roundOffset keyed by
|
|
140
140
|
* response.created so accumulators across multiple tool rounds and across
|
|
141
|
-
* multiple turns within a session don't collide.
|
|
141
|
+
* multiple turns within a session don't collide.
|
|
142
|
+
*
|
|
143
|
+
* SDK events cover model output only; framework-authored items — turn input
|
|
144
|
+
* messages, between-rounds injections, tool results — arrive via the
|
|
145
|
+
* `item_appended` framework event and are yielded already complete. */
|
|
142
146
|
export async function* buildItemStream(broadcaster, itemSchemas = defaultItemSchemaRegistry) {
|
|
143
147
|
const accumulators = new Map();
|
|
144
148
|
let roundOffset = 0;
|
|
145
149
|
for await (const event of broadcaster) {
|
|
150
|
+
if (event.source === 'framework') {
|
|
151
|
+
if (event.type.endsWith(':item_appended') &&
|
|
152
|
+
typeof event.data.item === 'object' &&
|
|
153
|
+
event.data.item !== null) {
|
|
154
|
+
yield {
|
|
155
|
+
...frameworkCast(event.data.item),
|
|
156
|
+
isComplete: true,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
146
161
|
if (event.source !== 'sdk') {
|
|
147
162
|
continue;
|
|
148
163
|
}
|