@inkeep/agents-run-api 0.0.0-dev-20250917205552 → 0.0.0-dev-20250919020857
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 +425 -293
- package/dist/index.js +426 -294
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -22,7 +22,7 @@ import { streamSSE, stream } from 'hono/streaming';
|
|
|
22
22
|
import { nanoid } from 'nanoid';
|
|
23
23
|
import destr from 'destr';
|
|
24
24
|
import traverse from 'traverse';
|
|
25
|
-
import { createUIMessageStream, JsonToSseTransformStream, parsePartialJson, generateText, generateObject, tool, streamText } from 'ai';
|
|
25
|
+
import { createUIMessageStream, JsonToSseTransformStream, parsePartialJson, generateText, generateObject, tool, streamText, streamObject } from 'ai';
|
|
26
26
|
import { createAnthropic, anthropic } from '@ai-sdk/anthropic';
|
|
27
27
|
import { createGoogleGenerativeAI, google } from '@ai-sdk/google';
|
|
28
28
|
import { createOpenAI, openai } from '@ai-sdk/openai';
|
|
@@ -998,24 +998,19 @@ function completionOp(agentId, iterations) {
|
|
|
998
998
|
}
|
|
999
999
|
};
|
|
1000
1000
|
}
|
|
1001
|
-
function errorOp(error,
|
|
1001
|
+
function errorOp(message, agentId, severity = "error", code) {
|
|
1002
1002
|
return {
|
|
1003
1003
|
type: "error",
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1004
|
+
message,
|
|
1005
|
+
agent: agentId,
|
|
1006
|
+
severity,
|
|
1007
|
+
code,
|
|
1008
|
+
timestamp: Date.now()
|
|
1008
1009
|
};
|
|
1009
1010
|
}
|
|
1010
1011
|
function generateToolId() {
|
|
1011
1012
|
return `tool_${nanoid(8)}`;
|
|
1012
1013
|
}
|
|
1013
|
-
function statusUpdateOp(ctx) {
|
|
1014
|
-
return {
|
|
1015
|
-
type: "status_update",
|
|
1016
|
-
ctx
|
|
1017
|
-
};
|
|
1018
|
-
}
|
|
1019
1014
|
var logger4 = getLogger("DataComponentSchema");
|
|
1020
1015
|
function jsonSchemaToZod(jsonSchema) {
|
|
1021
1016
|
if (!jsonSchema || typeof jsonSchema !== "object") {
|
|
@@ -1267,7 +1262,6 @@ var _ModelFactory = class _ModelFactory {
|
|
|
1267
1262
|
*/
|
|
1268
1263
|
__publicField(_ModelFactory, "SUPPORTED_PROVIDERS", ["anthropic", "openai", "google"]);
|
|
1269
1264
|
var ModelFactory = _ModelFactory;
|
|
1270
|
-
var tracer = getTracer("agents-run-api");
|
|
1271
1265
|
|
|
1272
1266
|
// src/utils/stream-registry.ts
|
|
1273
1267
|
var streamHelperRegistry = /* @__PURE__ */ new Map();
|
|
@@ -1283,6 +1277,7 @@ function getStreamHelper(requestId2) {
|
|
|
1283
1277
|
function unregisterStreamHelper(requestId2) {
|
|
1284
1278
|
streamHelperRegistry.delete(requestId2);
|
|
1285
1279
|
}
|
|
1280
|
+
var tracer = getTracer("agents-run-api");
|
|
1286
1281
|
|
|
1287
1282
|
// src/utils/graph-session.ts
|
|
1288
1283
|
var logger6 = getLogger("GraphSession");
|
|
@@ -1591,7 +1586,6 @@ var GraphSession = class {
|
|
|
1591
1586
|
}
|
|
1592
1587
|
this.isGeneratingUpdate = true;
|
|
1593
1588
|
const statusUpdateState = this.statusUpdateState;
|
|
1594
|
-
const graphId = this.graphId;
|
|
1595
1589
|
try {
|
|
1596
1590
|
const streamHelper = getStreamHelper(this.sessionId);
|
|
1597
1591
|
if (!streamHelper) {
|
|
@@ -1604,7 +1598,7 @@ var GraphSession = class {
|
|
|
1604
1598
|
}
|
|
1605
1599
|
const now = Date.now();
|
|
1606
1600
|
const elapsedTime = now - statusUpdateState.startTime;
|
|
1607
|
-
let
|
|
1601
|
+
let summaryToSend;
|
|
1608
1602
|
if (statusUpdateState.config.statusComponents && statusUpdateState.config.statusComponents.length > 0) {
|
|
1609
1603
|
const result = await this.generateStructuredStatusUpdate(
|
|
1610
1604
|
this.events.slice(statusUpdateState.lastEventCount),
|
|
@@ -1613,32 +1607,30 @@ var GraphSession = class {
|
|
|
1613
1607
|
statusUpdateState.summarizerModel,
|
|
1614
1608
|
this.previousSummaries
|
|
1615
1609
|
);
|
|
1616
|
-
if (result.
|
|
1617
|
-
for (const
|
|
1618
|
-
if (!
|
|
1610
|
+
if (result.summaries && result.summaries.length > 0) {
|
|
1611
|
+
for (const summary of result.summaries) {
|
|
1612
|
+
if (!summary || !summary.type || !summary.data || !summary.data.label || Object.keys(summary.data).length === 0) {
|
|
1619
1613
|
logger6.warn(
|
|
1620
1614
|
{
|
|
1621
1615
|
sessionId: this.sessionId,
|
|
1622
|
-
|
|
1616
|
+
summary
|
|
1623
1617
|
},
|
|
1624
1618
|
"Skipping empty or invalid structured operation"
|
|
1625
1619
|
);
|
|
1626
1620
|
continue;
|
|
1627
1621
|
}
|
|
1628
|
-
const
|
|
1629
|
-
type:
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
data
|
|
1634
|
-
|
|
1635
|
-
)
|
|
1636
|
-
}
|
|
1622
|
+
const summaryToSend2 = {
|
|
1623
|
+
type: summary.data.type || summary.type,
|
|
1624
|
+
// Preserve the actual custom type from LLM
|
|
1625
|
+
label: summary.data.label,
|
|
1626
|
+
details: Object.fromEntries(
|
|
1627
|
+
Object.entries(summary.data).filter(([key]) => !["label", "type"].includes(key))
|
|
1628
|
+
)
|
|
1637
1629
|
};
|
|
1638
|
-
await streamHelper.
|
|
1630
|
+
await streamHelper.writeSummary(summaryToSend2);
|
|
1639
1631
|
}
|
|
1640
|
-
const summaryTexts = result.
|
|
1641
|
-
(
|
|
1632
|
+
const summaryTexts = result.summaries.map(
|
|
1633
|
+
(summary) => JSON.stringify({ type: summary.type, data: summary.data })
|
|
1642
1634
|
);
|
|
1643
1635
|
this.previousSummaries.push(...summaryTexts);
|
|
1644
1636
|
if (this.statusUpdateState) {
|
|
@@ -1655,34 +1647,20 @@ var GraphSession = class {
|
|
|
1655
1647
|
this.previousSummaries
|
|
1656
1648
|
);
|
|
1657
1649
|
this.previousSummaries.push(summary);
|
|
1658
|
-
operation = statusUpdateOp({
|
|
1659
|
-
summary,
|
|
1660
|
-
eventCount: this.events.length,
|
|
1661
|
-
elapsedTime,
|
|
1662
|
-
currentPhase: "processing",
|
|
1663
|
-
activeAgent: "system",
|
|
1664
|
-
graphId,
|
|
1665
|
-
sessionId: this.sessionId
|
|
1666
|
-
});
|
|
1667
1650
|
}
|
|
1668
1651
|
if (this.previousSummaries.length > 3) {
|
|
1669
1652
|
this.previousSummaries.shift();
|
|
1670
1653
|
}
|
|
1671
|
-
|
|
1654
|
+
{
|
|
1672
1655
|
logger6.warn(
|
|
1673
1656
|
{
|
|
1674
1657
|
sessionId: this.sessionId,
|
|
1675
|
-
|
|
1658
|
+
summaryToSend
|
|
1676
1659
|
},
|
|
1677
1660
|
"Skipping empty or invalid status update operation"
|
|
1678
1661
|
);
|
|
1679
1662
|
return;
|
|
1680
1663
|
}
|
|
1681
|
-
await streamHelper.writeOperation(operation);
|
|
1682
|
-
if (this.statusUpdateState) {
|
|
1683
|
-
this.statusUpdateState.lastUpdateTime = now;
|
|
1684
|
-
this.statusUpdateState.lastEventCount = this.events.length;
|
|
1685
|
-
}
|
|
1686
1664
|
} catch (error) {
|
|
1687
1665
|
logger6.error(
|
|
1688
1666
|
{
|
|
@@ -1815,7 +1793,7 @@ ${previousSummaryContext}` : ""}
|
|
|
1815
1793
|
Activities:
|
|
1816
1794
|
${userVisibleActivities.join("\n") || "No New Activities"}
|
|
1817
1795
|
|
|
1818
|
-
|
|
1796
|
+
Create a short 3-5 word label describing the ACTUAL finding. Use sentence case (only capitalize the first word and proper nouns). Examples: "Found admin permissions needed", "Identified three channel types", "OAuth token required".
|
|
1819
1797
|
|
|
1820
1798
|
${this.statusUpdateState?.config.prompt?.trim() || ""}`;
|
|
1821
1799
|
const prompt = basePrompt;
|
|
@@ -1937,14 +1915,16 @@ Rules:
|
|
|
1937
1915
|
- Fill in data for relevant components only
|
|
1938
1916
|
- Use 'no_relevant_updates' if nothing substantially new to report. DO NOT WRITE LABELS OR USE OTHER COMPONENTS IF YOU USE THIS COMPONENT.
|
|
1939
1917
|
- Never repeat previous values, make every update EXTREMELY unique. If you cannot do that the update is not worth mentioning.
|
|
1940
|
-
- Labels MUST
|
|
1918
|
+
- Labels MUST be short 3-5 word phrases with ACTUAL information discovered. NEVER MAKE UP SOMETHING WITHOUT BACKING IT UP WITH ACTUAL INFORMATION.
|
|
1919
|
+
- Use sentence case: only capitalize the first word and proper nouns (e.g., "Admin permissions required", not "Admin Permissions Required"). ALWAYS capitalize the first word of the label.
|
|
1941
1920
|
- DO NOT use action words like "Searching", "Processing", "Analyzing" - state what was FOUND
|
|
1942
1921
|
- Include specific details, numbers, requirements, or insights discovered
|
|
1922
|
+
- Examples: "Admin permissions required", "Three OAuth steps found", "Token expires daily"
|
|
1943
1923
|
- You are ONE unified AI system - NEVER mention agents, transfers, delegations, or routing
|
|
1944
|
-
- CRITICAL: NEVER use the words "transfer", "delegation", "agent", "routing", or any internal system terminology in labels
|
|
1924
|
+
- CRITICAL: NEVER use the words "transfer", "delegation", "agent", "routing", "artifact", or any internal system terminology in labels or any names of agents, tools, or systems.
|
|
1945
1925
|
- Present all operations as seamless actions by a single system
|
|
1946
1926
|
- Anonymize all internal operations so that the information appears descriptive and USER FRIENDLY. HIDE ALL INTERNAL OPERATIONS!
|
|
1947
|
-
- Bad examples: "Transferring to search agent", "Delegating task", "Routing request", "Processing request", or not using the no_relevant_updates
|
|
1927
|
+
- Bad examples: "Transferring to search agent", "continuing transfer to qa agent", "Delegating task", "Routing request", "Processing request", "Artifact found", "Artifact saved", or not using the no_relevant_updates
|
|
1948
1928
|
- Good examples: "Slack bot needs admin privileges", "Found 3-step OAuth flow required", "Channel limit is 500 per workspace", or use the no_relevant_updates component if nothing new to report.
|
|
1949
1929
|
|
|
1950
1930
|
REMEMBER YOU CAN ONLY USE 'no_relevant_updates' ALONE! IT CANNOT BE CONCATENATED WITH OTHER STATUS UPDATES!
|
|
@@ -1977,29 +1957,29 @@ ${this.statusUpdateState?.config.prompt?.trim() || ""}`;
|
|
|
1977
1957
|
}
|
|
1978
1958
|
});
|
|
1979
1959
|
const result = object;
|
|
1980
|
-
const
|
|
1960
|
+
const summaries = [];
|
|
1981
1961
|
for (const [componentId, data] of Object.entries(result)) {
|
|
1982
1962
|
if (componentId === "no_relevant_updates") {
|
|
1983
1963
|
continue;
|
|
1984
1964
|
}
|
|
1985
1965
|
if (data && typeof data === "object" && Object.keys(data).length > 0) {
|
|
1986
|
-
|
|
1966
|
+
summaries.push({
|
|
1987
1967
|
type: componentId,
|
|
1988
1968
|
data
|
|
1989
1969
|
});
|
|
1990
1970
|
}
|
|
1991
1971
|
}
|
|
1992
1972
|
span.setAttributes({
|
|
1993
|
-
"
|
|
1973
|
+
"summaries.count": summaries.length,
|
|
1994
1974
|
"user_activities.count": userVisibleActivities.length,
|
|
1995
1975
|
"result_keys.count": Object.keys(result).length
|
|
1996
1976
|
});
|
|
1997
1977
|
span.setStatus({ code: SpanStatusCode.OK });
|
|
1998
|
-
return {
|
|
1978
|
+
return { summaries };
|
|
1999
1979
|
} catch (error) {
|
|
2000
1980
|
setSpanWithError(span, error);
|
|
2001
1981
|
logger6.error({ error }, "Failed to generate structured update, using fallback");
|
|
2002
|
-
return {
|
|
1982
|
+
return { summaries: [] };
|
|
2003
1983
|
} finally {
|
|
2004
1984
|
span.end();
|
|
2005
1985
|
}
|
|
@@ -2577,7 +2557,8 @@ var _ArtifactParser = class _ArtifactParser {
|
|
|
2577
2557
|
taskId,
|
|
2578
2558
|
name: artifact.name || "Processing...",
|
|
2579
2559
|
description: artifact.description || "Name and description being generated...",
|
|
2580
|
-
|
|
2560
|
+
type: artifact.metadata?.artifactType || artifact.artifactType,
|
|
2561
|
+
// Map artifactType to type for consistency
|
|
2581
2562
|
artifactSummary: artifact.parts?.[0]?.data?.summary || {}
|
|
2582
2563
|
};
|
|
2583
2564
|
}
|
|
@@ -2597,7 +2578,7 @@ var _ArtifactParser = class _ArtifactParser {
|
|
|
2597
2578
|
const matchStart = match.index;
|
|
2598
2579
|
if (matchStart > lastIndex) {
|
|
2599
2580
|
const textBefore = text.slice(lastIndex, matchStart);
|
|
2600
|
-
if (textBefore
|
|
2581
|
+
if (textBefore) {
|
|
2601
2582
|
parts.push({ kind: "text", text: textBefore });
|
|
2602
2583
|
}
|
|
2603
2584
|
}
|
|
@@ -2609,7 +2590,7 @@ var _ArtifactParser = class _ArtifactParser {
|
|
|
2609
2590
|
}
|
|
2610
2591
|
if (lastIndex < text.length) {
|
|
2611
2592
|
const remainingText = text.slice(lastIndex);
|
|
2612
|
-
if (remainingText
|
|
2593
|
+
if (remainingText) {
|
|
2613
2594
|
parts.push({ kind: "text", text: remainingText });
|
|
2614
2595
|
}
|
|
2615
2596
|
}
|
|
@@ -2719,8 +2700,9 @@ __publicField(_ArtifactParser, "INCOMPLETE_ARTIFACT_REGEX", /<(a(r(t(i(f(a(c(t(:
|
|
|
2719
2700
|
var ArtifactParser = _ArtifactParser;
|
|
2720
2701
|
|
|
2721
2702
|
// src/utils/incremental-stream-parser.ts
|
|
2722
|
-
|
|
2723
|
-
var
|
|
2703
|
+
getLogger("IncrementalStreamParser");
|
|
2704
|
+
var _IncrementalStreamParser = class _IncrementalStreamParser {
|
|
2705
|
+
// Max number of streamed component IDs to track
|
|
2724
2706
|
constructor(streamHelper, tenantId, contextId) {
|
|
2725
2707
|
__publicField(this, "buffer", "");
|
|
2726
2708
|
__publicField(this, "pendingTextBuffer", "");
|
|
@@ -2730,6 +2712,9 @@ var IncrementalStreamParser = class {
|
|
|
2730
2712
|
__publicField(this, "collectedParts", []);
|
|
2731
2713
|
__publicField(this, "contextId");
|
|
2732
2714
|
__publicField(this, "lastChunkWasToolResult", false);
|
|
2715
|
+
__publicField(this, "componentAccumulator", {});
|
|
2716
|
+
__publicField(this, "lastStreamedComponents", /* @__PURE__ */ new Map());
|
|
2717
|
+
__publicField(this, "componentSnapshots", /* @__PURE__ */ new Map());
|
|
2733
2718
|
this.streamHelper = streamHelper;
|
|
2734
2719
|
this.contextId = contextId;
|
|
2735
2720
|
this.artifactParser = new ArtifactParser(tenantId);
|
|
@@ -2744,7 +2729,7 @@ var IncrementalStreamParser = class {
|
|
|
2744
2729
|
* Process a new text chunk for text streaming (handles artifact markers)
|
|
2745
2730
|
*/
|
|
2746
2731
|
async processTextChunk(chunk) {
|
|
2747
|
-
if (this.lastChunkWasToolResult && this.buffer === "" && chunk
|
|
2732
|
+
if (this.lastChunkWasToolResult && this.buffer === "" && chunk) {
|
|
2748
2733
|
chunk = "\n\n" + chunk;
|
|
2749
2734
|
this.lastChunkWasToolResult = false;
|
|
2750
2735
|
}
|
|
@@ -2756,100 +2741,122 @@ var IncrementalStreamParser = class {
|
|
|
2756
2741
|
this.buffer = parseResult.remainingBuffer;
|
|
2757
2742
|
}
|
|
2758
2743
|
/**
|
|
2759
|
-
* Process
|
|
2744
|
+
* Process object deltas directly from Vercel AI SDK's fullStream
|
|
2745
|
+
* Accumulates components and streams them when they're stable (unchanged between deltas)
|
|
2760
2746
|
*/
|
|
2761
|
-
async
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
for (const part of parseResult.completeParts) {
|
|
2765
|
-
await this.streamPart(part);
|
|
2747
|
+
async processObjectDelta(delta) {
|
|
2748
|
+
if (!delta || typeof delta !== "object") {
|
|
2749
|
+
return;
|
|
2766
2750
|
}
|
|
2767
|
-
this.
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
const delta = part.argsTextDelta || "";
|
|
2781
|
-
if (jsonBuffer.length + delta.length > MAX_BUFFER_SIZE) {
|
|
2782
|
-
logger8.warn(
|
|
2783
|
-
{ bufferSize: jsonBuffer.length + delta.length, maxSize: MAX_BUFFER_SIZE },
|
|
2784
|
-
"JSON buffer exceeded maximum size, truncating"
|
|
2785
|
-
);
|
|
2786
|
-
jsonBuffer = jsonBuffer.slice(-MAX_BUFFER_SIZE / 2);
|
|
2751
|
+
this.componentAccumulator = this.deepMerge(this.componentAccumulator, delta);
|
|
2752
|
+
if (this.componentAccumulator.dataComponents && Array.isArray(this.componentAccumulator.dataComponents)) {
|
|
2753
|
+
const components = this.componentAccumulator.dataComponents;
|
|
2754
|
+
const currentComponentIds = new Set(components.filter((c) => c?.id).map((c) => c.id));
|
|
2755
|
+
for (const [componentId, snapshot] of this.componentSnapshots.entries()) {
|
|
2756
|
+
if (!currentComponentIds.has(componentId) && !this.lastStreamedComponents.has(componentId)) {
|
|
2757
|
+
try {
|
|
2758
|
+
const component = JSON.parse(snapshot);
|
|
2759
|
+
if (this.isComponentComplete(component)) {
|
|
2760
|
+
await this.streamComponent(component);
|
|
2761
|
+
}
|
|
2762
|
+
} catch (e) {
|
|
2763
|
+
}
|
|
2787
2764
|
}
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2765
|
+
}
|
|
2766
|
+
for (let i = 0; i < components.length; i++) {
|
|
2767
|
+
const component = components[i];
|
|
2768
|
+
if (!component?.id) continue;
|
|
2769
|
+
const componentKey = component.id;
|
|
2770
|
+
const hasBeenStreamed = this.lastStreamedComponents.has(componentKey);
|
|
2771
|
+
if (hasBeenStreamed) continue;
|
|
2772
|
+
const currentSnapshot = JSON.stringify(component);
|
|
2773
|
+
const previousSnapshot = this.componentSnapshots.get(componentKey);
|
|
2774
|
+
this.componentSnapshots.set(componentKey, currentSnapshot);
|
|
2775
|
+
if (this.componentSnapshots.size > _IncrementalStreamParser.MAX_SNAPSHOT_SIZE) {
|
|
2776
|
+
const firstKey = this.componentSnapshots.keys().next().value;
|
|
2777
|
+
if (firstKey) {
|
|
2778
|
+
this.componentSnapshots.delete(firstKey);
|
|
2798
2779
|
}
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
if (componentMatch[0].length > MAX_COMPONENT_SIZE) {
|
|
2809
|
-
logger8.warn(
|
|
2810
|
-
{
|
|
2811
|
-
size: componentMatch[0].length,
|
|
2812
|
-
maxSize: MAX_COMPONENT_SIZE
|
|
2813
|
-
},
|
|
2814
|
-
"Component exceeds size limit, skipping"
|
|
2815
|
-
);
|
|
2816
|
-
componentBuffer = "";
|
|
2817
|
-
continue;
|
|
2818
|
-
}
|
|
2819
|
-
try {
|
|
2820
|
-
const component = JSON.parse(componentMatch[0]);
|
|
2821
|
-
if (typeof component !== "object" || !component.id) {
|
|
2822
|
-
logger8.warn({ component }, "Invalid component structure, skipping");
|
|
2823
|
-
componentBuffer = "";
|
|
2824
|
-
continue;
|
|
2825
|
-
}
|
|
2826
|
-
const parts = await this.artifactParser.parseObject({
|
|
2827
|
-
dataComponents: [component]
|
|
2828
|
-
});
|
|
2829
|
-
for (const part2 of parts) {
|
|
2830
|
-
await this.streamPart(part2);
|
|
2831
|
-
}
|
|
2832
|
-
componentsStreamed++;
|
|
2833
|
-
componentBuffer = "";
|
|
2834
|
-
} catch (e) {
|
|
2835
|
-
logger8.debug({ error: e }, "Failed to parse component, continuing to accumulate");
|
|
2836
|
-
}
|
|
2837
|
-
}
|
|
2780
|
+
}
|
|
2781
|
+
if (component.name === "Text" && component.props?.text) {
|
|
2782
|
+
const previousTextContent = previousSnapshot ? JSON.parse(previousSnapshot).props?.text || "" : "";
|
|
2783
|
+
const currentTextContent = component.props.text || "";
|
|
2784
|
+
if (currentTextContent.length > previousTextContent.length) {
|
|
2785
|
+
const newText = currentTextContent.slice(previousTextContent.length);
|
|
2786
|
+
if (!this.hasStartedRole) {
|
|
2787
|
+
await this.streamHelper.writeRole("assistant");
|
|
2788
|
+
this.hasStartedRole = true;
|
|
2838
2789
|
}
|
|
2790
|
+
await this.streamHelper.streamText(newText, 50);
|
|
2791
|
+
this.collectedParts.push({
|
|
2792
|
+
kind: "text",
|
|
2793
|
+
text: newText
|
|
2794
|
+
});
|
|
2839
2795
|
}
|
|
2840
|
-
|
|
2796
|
+
continue;
|
|
2841
2797
|
}
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
const
|
|
2845
|
-
|
|
2846
|
-
await this.
|
|
2798
|
+
if (this.isComponentComplete(component)) {
|
|
2799
|
+
const currentPropsSnapshot = JSON.stringify(component.props);
|
|
2800
|
+
const previousPropsSnapshot = previousSnapshot ? JSON.stringify(JSON.parse(previousSnapshot).props) : null;
|
|
2801
|
+
if (previousPropsSnapshot === currentPropsSnapshot) {
|
|
2802
|
+
await this.streamComponent(component);
|
|
2847
2803
|
}
|
|
2848
2804
|
}
|
|
2849
|
-
break;
|
|
2850
2805
|
}
|
|
2851
2806
|
}
|
|
2852
|
-
|
|
2807
|
+
}
|
|
2808
|
+
/**
|
|
2809
|
+
* Stream a component and mark it as streamed
|
|
2810
|
+
* Note: Text components are handled separately with incremental streaming
|
|
2811
|
+
*/
|
|
2812
|
+
async streamComponent(component) {
|
|
2813
|
+
const parts = await this.artifactParser.parseObject({
|
|
2814
|
+
dataComponents: [component]
|
|
2815
|
+
});
|
|
2816
|
+
for (const part of parts) {
|
|
2817
|
+
await this.streamPart(part);
|
|
2818
|
+
}
|
|
2819
|
+
this.lastStreamedComponents.set(component.id, true);
|
|
2820
|
+
if (this.lastStreamedComponents.size > _IncrementalStreamParser.MAX_STREAMED_SIZE) {
|
|
2821
|
+
const firstKey = this.lastStreamedComponents.keys().next().value;
|
|
2822
|
+
if (firstKey) {
|
|
2823
|
+
this.lastStreamedComponents.delete(firstKey);
|
|
2824
|
+
}
|
|
2825
|
+
}
|
|
2826
|
+
this.componentSnapshots.delete(component.id);
|
|
2827
|
+
}
|
|
2828
|
+
/**
|
|
2829
|
+
* Check if a component has the basic structure required for streaming
|
|
2830
|
+
* Requires id, name, and props object with content
|
|
2831
|
+
*/
|
|
2832
|
+
isComponentComplete(component) {
|
|
2833
|
+
if (!component || !component.id || !component.name) {
|
|
2834
|
+
return false;
|
|
2835
|
+
}
|
|
2836
|
+
if (!component.props || typeof component.props !== "object") {
|
|
2837
|
+
return false;
|
|
2838
|
+
}
|
|
2839
|
+
const isArtifact = component.name === "Artifact" || component.props.artifact_id && component.props.task_id;
|
|
2840
|
+
if (isArtifact) {
|
|
2841
|
+
return Boolean(component.props.artifact_id && component.props.task_id);
|
|
2842
|
+
}
|
|
2843
|
+
return true;
|
|
2844
|
+
}
|
|
2845
|
+
/**
|
|
2846
|
+
* Deep merge helper for object deltas
|
|
2847
|
+
*/
|
|
2848
|
+
deepMerge(target, source) {
|
|
2849
|
+
if (!source) return target;
|
|
2850
|
+
if (!target) return source;
|
|
2851
|
+
const result = { ...target };
|
|
2852
|
+
for (const key in source) {
|
|
2853
|
+
if (source[key] && typeof source[key] === "object" && !Array.isArray(source[key])) {
|
|
2854
|
+
result[key] = this.deepMerge(target[key], source[key]);
|
|
2855
|
+
} else {
|
|
2856
|
+
result[key] = source[key];
|
|
2857
|
+
}
|
|
2858
|
+
}
|
|
2859
|
+
return result;
|
|
2853
2860
|
}
|
|
2854
2861
|
/**
|
|
2855
2862
|
* Legacy method for backward compatibility - defaults to text processing
|
|
@@ -2861,15 +2868,40 @@ var IncrementalStreamParser = class {
|
|
|
2861
2868
|
* Process any remaining buffer content at the end of stream
|
|
2862
2869
|
*/
|
|
2863
2870
|
async finalize() {
|
|
2864
|
-
if (this.
|
|
2871
|
+
if (this.componentAccumulator.dataComponents && Array.isArray(this.componentAccumulator.dataComponents)) {
|
|
2872
|
+
const components = this.componentAccumulator.dataComponents;
|
|
2873
|
+
for (let i = 0; i < components.length; i++) {
|
|
2874
|
+
const component = components[i];
|
|
2875
|
+
if (!component?.id) continue;
|
|
2876
|
+
const componentKey = component.id;
|
|
2877
|
+
const hasBeenStreamed = this.lastStreamedComponents.has(componentKey);
|
|
2878
|
+
if (!hasBeenStreamed && this.isComponentComplete(component) && component.name !== "Text") {
|
|
2879
|
+
const parts = await this.artifactParser.parseObject({
|
|
2880
|
+
dataComponents: [component]
|
|
2881
|
+
});
|
|
2882
|
+
for (const part of parts) {
|
|
2883
|
+
await this.streamPart(part);
|
|
2884
|
+
}
|
|
2885
|
+
this.lastStreamedComponents.set(componentKey, true);
|
|
2886
|
+
if (this.lastStreamedComponents.size > _IncrementalStreamParser.MAX_STREAMED_SIZE) {
|
|
2887
|
+
const firstKey = this.lastStreamedComponents.keys().next().value;
|
|
2888
|
+
if (firstKey) {
|
|
2889
|
+
this.lastStreamedComponents.delete(firstKey);
|
|
2890
|
+
}
|
|
2891
|
+
}
|
|
2892
|
+
this.componentSnapshots.delete(componentKey);
|
|
2893
|
+
}
|
|
2894
|
+
}
|
|
2895
|
+
}
|
|
2896
|
+
if (this.buffer) {
|
|
2865
2897
|
const part = {
|
|
2866
2898
|
kind: "text",
|
|
2867
|
-
text: this.buffer
|
|
2899
|
+
text: this.buffer
|
|
2868
2900
|
};
|
|
2869
2901
|
await this.streamPart(part);
|
|
2870
2902
|
}
|
|
2871
|
-
if (this.pendingTextBuffer
|
|
2872
|
-
const cleanedText = this.pendingTextBuffer.replace(/<\/?artifact:ref(?:\s[^>]*)?>\/?>/g, "").replace(/<\/?artifact(?:\s[^>]*)?>\/?>/g, "").replace(/<\/(?:\w+:)?artifact>/g, "")
|
|
2903
|
+
if (this.pendingTextBuffer) {
|
|
2904
|
+
const cleanedText = this.pendingTextBuffer.replace(/<\/?artifact:ref(?:\s[^>]*)?>\/?>/g, "").replace(/<\/?artifact(?:\s[^>]*)?>\/?>/g, "").replace(/<\/(?:\w+:)?artifact>/g, "");
|
|
2873
2905
|
if (cleanedText) {
|
|
2874
2906
|
this.collectedParts.push({
|
|
2875
2907
|
kind: "text",
|
|
@@ -2879,6 +2911,9 @@ var IncrementalStreamParser = class {
|
|
|
2879
2911
|
}
|
|
2880
2912
|
this.pendingTextBuffer = "";
|
|
2881
2913
|
}
|
|
2914
|
+
this.componentSnapshots.clear();
|
|
2915
|
+
this.lastStreamedComponents.clear();
|
|
2916
|
+
this.componentAccumulator = {};
|
|
2882
2917
|
}
|
|
2883
2918
|
/**
|
|
2884
2919
|
* Get all collected parts for building the final response
|
|
@@ -2925,30 +2960,6 @@ var IncrementalStreamParser = class {
|
|
|
2925
2960
|
remainingBuffer: ""
|
|
2926
2961
|
};
|
|
2927
2962
|
}
|
|
2928
|
-
/**
|
|
2929
|
-
* Parse buffer for complete JSON objects with artifact references (for object streaming)
|
|
2930
|
-
*/
|
|
2931
|
-
async parseObjectBuffer() {
|
|
2932
|
-
const completeParts = [];
|
|
2933
|
-
try {
|
|
2934
|
-
const parsed = JSON.parse(this.buffer);
|
|
2935
|
-
const parts = await this.artifactParser.parseObject(parsed);
|
|
2936
|
-
return {
|
|
2937
|
-
completeParts: parts,
|
|
2938
|
-
remainingBuffer: ""
|
|
2939
|
-
};
|
|
2940
|
-
} catch {
|
|
2941
|
-
const { complete, remaining } = this.artifactParser.parsePartialJSON(this.buffer);
|
|
2942
|
-
for (const obj of complete) {
|
|
2943
|
-
const parts = await this.artifactParser.parseObject(obj);
|
|
2944
|
-
completeParts.push(...parts);
|
|
2945
|
-
}
|
|
2946
|
-
return {
|
|
2947
|
-
completeParts,
|
|
2948
|
-
remainingBuffer: remaining
|
|
2949
|
-
};
|
|
2950
|
-
}
|
|
2951
|
-
}
|
|
2952
2963
|
/**
|
|
2953
2964
|
* Check if text might be the start of an artifact marker
|
|
2954
2965
|
*/
|
|
@@ -2969,7 +2980,7 @@ var IncrementalStreamParser = class {
|
|
|
2969
2980
|
this.pendingTextBuffer += part.text;
|
|
2970
2981
|
if (!this.artifactParser.hasIncompleteArtifact(this.pendingTextBuffer)) {
|
|
2971
2982
|
const cleanedText = this.pendingTextBuffer.replace(/<\/?artifact:ref(?:\s[^>]*)?>\/?>/g, "").replace(/<\/?artifact(?:\s[^>]*)?>\/?>/g, "").replace(/<\/(?:\w+:)?artifact>/g, "");
|
|
2972
|
-
if (cleanedText
|
|
2983
|
+
if (cleanedText) {
|
|
2973
2984
|
await this.streamHelper.streamText(cleanedText, 50);
|
|
2974
2985
|
}
|
|
2975
2986
|
this.pendingTextBuffer = "";
|
|
@@ -2977,7 +2988,7 @@ var IncrementalStreamParser = class {
|
|
|
2977
2988
|
} else if (part.kind === "data" && part.data) {
|
|
2978
2989
|
if (this.pendingTextBuffer) {
|
|
2979
2990
|
const cleanedText = this.pendingTextBuffer.replace(/<\/?artifact:ref(?:\s[^>]*)?>\/?>/g, "").replace(/<\/?artifact(?:\s[^>]*)?>\/?>/g, "").replace(/<\/(?:\w+:)?artifact>/g, "");
|
|
2980
|
-
if (cleanedText
|
|
2991
|
+
if (cleanedText) {
|
|
2981
2992
|
await this.streamHelper.streamText(cleanedText, 50);
|
|
2982
2993
|
}
|
|
2983
2994
|
this.pendingTextBuffer = "";
|
|
@@ -2991,6 +3002,11 @@ var IncrementalStreamParser = class {
|
|
|
2991
3002
|
}
|
|
2992
3003
|
}
|
|
2993
3004
|
};
|
|
3005
|
+
// Memory management constants
|
|
3006
|
+
__publicField(_IncrementalStreamParser, "MAX_SNAPSHOT_SIZE", 100);
|
|
3007
|
+
// Max number of snapshots to keep
|
|
3008
|
+
__publicField(_IncrementalStreamParser, "MAX_STREAMED_SIZE", 1e3);
|
|
3009
|
+
var IncrementalStreamParser = _IncrementalStreamParser;
|
|
2994
3010
|
|
|
2995
3011
|
// src/utils/response-formatter.ts
|
|
2996
3012
|
var logger9 = getLogger("ResponseFormatter");
|
|
@@ -4979,6 +4995,23 @@ var Agent = class {
|
|
|
4979
4995
|
__publicField(this, "credentialStoreRegistry");
|
|
4980
4996
|
this.artifactComponents = config.artifactComponents || [];
|
|
4981
4997
|
let processedDataComponents = config.dataComponents || [];
|
|
4998
|
+
if (processedDataComponents.length > 0) {
|
|
4999
|
+
processedDataComponents.push({
|
|
5000
|
+
id: "text-content",
|
|
5001
|
+
name: "Text",
|
|
5002
|
+
description: "Natural conversational text for the user - write naturally without mentioning technical details. Avoid redundancy and repetition with data components.",
|
|
5003
|
+
props: {
|
|
5004
|
+
type: "object",
|
|
5005
|
+
properties: {
|
|
5006
|
+
text: {
|
|
5007
|
+
type: "string",
|
|
5008
|
+
description: "Natural conversational text - respond as if having a normal conversation, never mention JSON, components, schemas, or technical implementation. Avoid redundancy and repetition with data components."
|
|
5009
|
+
}
|
|
5010
|
+
},
|
|
5011
|
+
required: ["text"]
|
|
5012
|
+
}
|
|
5013
|
+
});
|
|
5014
|
+
}
|
|
4982
5015
|
if (this.artifactComponents.length > 0 && config.dataComponents && config.dataComponents.length > 0) {
|
|
4983
5016
|
processedDataComponents = [
|
|
4984
5017
|
ArtifactReferenceSchema.getDataComponent(config.tenantId, config.projectId),
|
|
@@ -5456,7 +5489,8 @@ Key requirements:
|
|
|
5456
5489
|
- Mix artifact references throughout your dataComponents array
|
|
5457
5490
|
- Each artifact reference must use EXACT IDs from tool outputs
|
|
5458
5491
|
- Reference artifacts that directly support the adjacent information
|
|
5459
|
-
- Follow the pattern: Data \u2192 Supporting Artifact \u2192 Next Data \u2192 Next Artifact
|
|
5492
|
+
- Follow the pattern: Data \u2192 Supporting Artifact \u2192 Next Data \u2192 Next Artifact
|
|
5493
|
+
- IMPORTANT: In Text components, write naturally as if having a conversation - do NOT mention components, schemas, JSON, structured data, or any technical implementation details`;
|
|
5460
5494
|
}
|
|
5461
5495
|
if (hasDataComponents && !hasArtifactComponents) {
|
|
5462
5496
|
return `Generate the final structured JSON response using the configured data components. Organize the information from the research above into the appropriate structured format based on the available component schemas.
|
|
@@ -5464,7 +5498,8 @@ Key requirements:
|
|
|
5464
5498
|
Key requirements:
|
|
5465
5499
|
- Use the exact component structure and property names
|
|
5466
5500
|
- Fill in all relevant data from the research
|
|
5467
|
-
- Ensure data is organized logically and completely
|
|
5501
|
+
- Ensure data is organized logically and completely
|
|
5502
|
+
- IMPORTANT: In Text components, write naturally as if having a conversation - do NOT mention components, schemas, JSON, structured data, or any technical implementation details`;
|
|
5468
5503
|
}
|
|
5469
5504
|
if (!hasDataComponents && hasArtifactComponents) {
|
|
5470
5505
|
return `Generate the final structured response with artifact references based on the research above. Use the artifact reference component to cite relevant information with exact artifact_id and task_id values from the tool outputs.
|
|
@@ -5474,7 +5509,7 @@ Key requirements:
|
|
|
5474
5509
|
- Reference artifacts that support your response
|
|
5475
5510
|
- Never make up or modify artifact IDs`;
|
|
5476
5511
|
}
|
|
5477
|
-
return `Generate the final response based on the research above.`;
|
|
5512
|
+
return `Generate the final response based on the research above. Write naturally as if having a conversation.`;
|
|
5478
5513
|
}
|
|
5479
5514
|
async buildSystemPrompt(runtimeContext, excludeDataComponents = false) {
|
|
5480
5515
|
const conversationId = runtimeContext?.metadata?.conversationId || runtimeContext?.contextId;
|
|
@@ -5973,35 +6008,94 @@ ${output}`;
|
|
|
5973
6008
|
this.getStructuredOutputModel()
|
|
5974
6009
|
);
|
|
5975
6010
|
const phase2TimeoutMs = structuredModelSettings.maxDuration ? structuredModelSettings.maxDuration * 1e3 : CONSTANTS.PHASE_2_TIMEOUT_MS;
|
|
5976
|
-
const
|
|
5977
|
-
|
|
5978
|
-
|
|
5979
|
-
|
|
5980
|
-
|
|
5981
|
-
|
|
5982
|
-
|
|
5983
|
-
|
|
5984
|
-
|
|
5985
|
-
|
|
5986
|
-
|
|
5987
|
-
|
|
5988
|
-
|
|
5989
|
-
|
|
5990
|
-
|
|
5991
|
-
|
|
5992
|
-
|
|
5993
|
-
|
|
5994
|
-
|
|
5995
|
-
|
|
6011
|
+
const shouldStreamPhase2 = this.getStreamingHelper();
|
|
6012
|
+
if (shouldStreamPhase2) {
|
|
6013
|
+
const streamResult = streamObject({
|
|
6014
|
+
...structuredModelSettings,
|
|
6015
|
+
messages: [
|
|
6016
|
+
{ role: "user", content: userMessage },
|
|
6017
|
+
...reasoningFlow,
|
|
6018
|
+
{
|
|
6019
|
+
role: "user",
|
|
6020
|
+
content: await this.buildPhase2SystemPrompt()
|
|
6021
|
+
}
|
|
6022
|
+
],
|
|
6023
|
+
schema: z.object({
|
|
6024
|
+
dataComponents: z.array(dataComponentsSchema)
|
|
6025
|
+
}),
|
|
6026
|
+
experimental_telemetry: {
|
|
6027
|
+
isEnabled: true,
|
|
6028
|
+
functionId: this.config.id,
|
|
6029
|
+
recordInputs: true,
|
|
6030
|
+
recordOutputs: true,
|
|
6031
|
+
metadata: {
|
|
6032
|
+
phase: "structured_generation"
|
|
6033
|
+
}
|
|
6034
|
+
},
|
|
6035
|
+
abortSignal: AbortSignal.timeout(phase2TimeoutMs)
|
|
6036
|
+
});
|
|
6037
|
+
const streamHelper = this.getStreamingHelper();
|
|
6038
|
+
if (!streamHelper) {
|
|
6039
|
+
throw new Error("Stream helper is unexpectedly undefined in streaming context");
|
|
6040
|
+
}
|
|
6041
|
+
const parser = new IncrementalStreamParser(
|
|
6042
|
+
streamHelper,
|
|
6043
|
+
this.config.tenantId,
|
|
6044
|
+
contextId
|
|
6045
|
+
);
|
|
6046
|
+
for await (const delta of streamResult.partialObjectStream) {
|
|
6047
|
+
if (delta) {
|
|
6048
|
+
await parser.processObjectDelta(delta);
|
|
5996
6049
|
}
|
|
5997
|
-
}
|
|
5998
|
-
|
|
5999
|
-
|
|
6000
|
-
|
|
6001
|
-
|
|
6002
|
-
|
|
6003
|
-
|
|
6004
|
-
|
|
6050
|
+
}
|
|
6051
|
+
await parser.finalize();
|
|
6052
|
+
const structuredResponse = await streamResult;
|
|
6053
|
+
const collectedParts = parser.getCollectedParts();
|
|
6054
|
+
if (collectedParts.length > 0) {
|
|
6055
|
+
response.formattedContent = {
|
|
6056
|
+
parts: collectedParts.map((part) => ({
|
|
6057
|
+
kind: part.kind,
|
|
6058
|
+
...part.kind === "text" && { text: part.text },
|
|
6059
|
+
...part.kind === "data" && { data: part.data }
|
|
6060
|
+
}))
|
|
6061
|
+
};
|
|
6062
|
+
}
|
|
6063
|
+
response = {
|
|
6064
|
+
...response,
|
|
6065
|
+
object: structuredResponse.object
|
|
6066
|
+
};
|
|
6067
|
+
textResponse = JSON.stringify(structuredResponse.object, null, 2);
|
|
6068
|
+
} else {
|
|
6069
|
+
const structuredResponse = await generateObject({
|
|
6070
|
+
...structuredModelSettings,
|
|
6071
|
+
messages: [
|
|
6072
|
+
{ role: "user", content: userMessage },
|
|
6073
|
+
...reasoningFlow,
|
|
6074
|
+
{
|
|
6075
|
+
role: "user",
|
|
6076
|
+
content: await this.buildPhase2SystemPrompt()
|
|
6077
|
+
}
|
|
6078
|
+
],
|
|
6079
|
+
schema: z.object({
|
|
6080
|
+
dataComponents: z.array(dataComponentsSchema)
|
|
6081
|
+
}),
|
|
6082
|
+
experimental_telemetry: {
|
|
6083
|
+
isEnabled: true,
|
|
6084
|
+
functionId: this.config.id,
|
|
6085
|
+
recordInputs: true,
|
|
6086
|
+
recordOutputs: true,
|
|
6087
|
+
metadata: {
|
|
6088
|
+
phase: "structured_generation"
|
|
6089
|
+
}
|
|
6090
|
+
},
|
|
6091
|
+
abortSignal: AbortSignal.timeout(phase2TimeoutMs)
|
|
6092
|
+
});
|
|
6093
|
+
response = {
|
|
6094
|
+
...response,
|
|
6095
|
+
object: structuredResponse.object
|
|
6096
|
+
};
|
|
6097
|
+
textResponse = JSON.stringify(structuredResponse.object, null, 2);
|
|
6098
|
+
}
|
|
6005
6099
|
} else {
|
|
6006
6100
|
textResponse = response.text || "";
|
|
6007
6101
|
}
|
|
@@ -6054,10 +6148,13 @@ async function resolveModelConfig(graphId, agent) {
|
|
|
6054
6148
|
summarizer: agent.models.summarizer || agent.models.base
|
|
6055
6149
|
};
|
|
6056
6150
|
}
|
|
6057
|
-
|
|
6058
|
-
|
|
6059
|
-
|
|
6060
|
-
|
|
6151
|
+
let graph = null;
|
|
6152
|
+
if (graphId) {
|
|
6153
|
+
graph = await getAgentGraph(dbClient_default)({
|
|
6154
|
+
scopes: { tenantId: agent.tenantId, projectId: agent.projectId },
|
|
6155
|
+
graphId
|
|
6156
|
+
});
|
|
6157
|
+
}
|
|
6061
6158
|
if (graph?.models?.base?.model) {
|
|
6062
6159
|
return {
|
|
6063
6160
|
base: graph.models.base,
|
|
@@ -6683,7 +6780,7 @@ var SSEStreamHelper = class {
|
|
|
6683
6780
|
this.timestamp = timestamp;
|
|
6684
6781
|
// Stream queuing for proper event ordering
|
|
6685
6782
|
__publicField(this, "isTextStreaming", false);
|
|
6686
|
-
__publicField(this, "
|
|
6783
|
+
__publicField(this, "queuedEvents", []);
|
|
6687
6784
|
}
|
|
6688
6785
|
/**
|
|
6689
6786
|
* Write the initial role message
|
|
@@ -6748,9 +6845,10 @@ var SSEStreamHelper = class {
|
|
|
6748
6845
|
await this.writeContent(JSON.stringify(data));
|
|
6749
6846
|
}
|
|
6750
6847
|
/**
|
|
6751
|
-
* Write error message
|
|
6848
|
+
* Write error message or error event
|
|
6752
6849
|
*/
|
|
6753
|
-
async writeError(
|
|
6850
|
+
async writeError(error) {
|
|
6851
|
+
const errorMessage = typeof error === "string" ? error : error.message;
|
|
6754
6852
|
await this.writeContent(`
|
|
6755
6853
|
|
|
6756
6854
|
${errorMessage}`);
|
|
@@ -6774,22 +6872,6 @@ ${errorMessage}`);
|
|
|
6774
6872
|
})
|
|
6775
6873
|
});
|
|
6776
6874
|
}
|
|
6777
|
-
/**
|
|
6778
|
-
* Write the final [DONE] message
|
|
6779
|
-
*/
|
|
6780
|
-
async writeDone() {
|
|
6781
|
-
await this.stream.writeSSE({
|
|
6782
|
-
data: "[DONE]"
|
|
6783
|
-
});
|
|
6784
|
-
}
|
|
6785
|
-
/**
|
|
6786
|
-
* Complete the stream with finish reason and done message
|
|
6787
|
-
*/
|
|
6788
|
-
async complete(finishReason = "stop") {
|
|
6789
|
-
await this.flushQueuedOperations();
|
|
6790
|
-
await this.writeCompletion(finishReason);
|
|
6791
|
-
await this.writeDone();
|
|
6792
|
-
}
|
|
6793
6875
|
async writeData(type, data) {
|
|
6794
6876
|
await this.stream.writeSSE({
|
|
6795
6877
|
data: JSON.stringify({
|
|
@@ -6808,16 +6890,23 @@ ${errorMessage}`);
|
|
|
6808
6890
|
})
|
|
6809
6891
|
});
|
|
6810
6892
|
}
|
|
6811
|
-
async
|
|
6812
|
-
if (
|
|
6813
|
-
|
|
6814
|
-
type:
|
|
6815
|
-
|
|
6816
|
-
|
|
6817
|
-
|
|
6893
|
+
async writeSummary(summary) {
|
|
6894
|
+
if (this.isTextStreaming) {
|
|
6895
|
+
this.queuedEvents.push({
|
|
6896
|
+
type: "data-summary",
|
|
6897
|
+
event: summary
|
|
6898
|
+
});
|
|
6899
|
+
return;
|
|
6818
6900
|
}
|
|
6901
|
+
await this.flushQueuedOperations();
|
|
6902
|
+
await this.writeData("data-summary", summary);
|
|
6903
|
+
}
|
|
6904
|
+
async writeOperation(operation) {
|
|
6819
6905
|
if (this.isTextStreaming) {
|
|
6820
|
-
this.
|
|
6906
|
+
this.queuedEvents.push({
|
|
6907
|
+
type: "data-operation",
|
|
6908
|
+
event: operation
|
|
6909
|
+
});
|
|
6821
6910
|
return;
|
|
6822
6911
|
}
|
|
6823
6912
|
await this.flushQueuedOperations();
|
|
@@ -6827,15 +6916,31 @@ ${errorMessage}`);
|
|
|
6827
6916
|
* Flush all queued operations in order after text streaming completes
|
|
6828
6917
|
*/
|
|
6829
6918
|
async flushQueuedOperations() {
|
|
6830
|
-
if (this.
|
|
6919
|
+
if (this.queuedEvents.length === 0) {
|
|
6831
6920
|
return;
|
|
6832
6921
|
}
|
|
6833
|
-
const
|
|
6834
|
-
this.
|
|
6835
|
-
for (const
|
|
6836
|
-
await this.writeData(
|
|
6922
|
+
const eventsToFlush = [...this.queuedEvents];
|
|
6923
|
+
this.queuedEvents = [];
|
|
6924
|
+
for (const event of eventsToFlush) {
|
|
6925
|
+
await this.writeData(event.type, event.event);
|
|
6837
6926
|
}
|
|
6838
6927
|
}
|
|
6928
|
+
/**
|
|
6929
|
+
* Write the final [DONE] message
|
|
6930
|
+
*/
|
|
6931
|
+
async writeDone() {
|
|
6932
|
+
await this.stream.writeSSE({
|
|
6933
|
+
data: "[DONE]"
|
|
6934
|
+
});
|
|
6935
|
+
}
|
|
6936
|
+
/**
|
|
6937
|
+
* Complete the stream with finish reason and done message
|
|
6938
|
+
*/
|
|
6939
|
+
async complete(finishReason = "stop") {
|
|
6940
|
+
await this.flushQueuedOperations();
|
|
6941
|
+
await this.writeCompletion(finishReason);
|
|
6942
|
+
await this.writeDone();
|
|
6943
|
+
}
|
|
6839
6944
|
};
|
|
6840
6945
|
function createSSEStreamHelper(stream2, requestId2, timestamp) {
|
|
6841
6946
|
return new SSEStreamHelper(stream2, requestId2, timestamp);
|
|
@@ -6855,7 +6960,7 @@ var _VercelDataStreamHelper = class _VercelDataStreamHelper {
|
|
|
6855
6960
|
__publicField(this, "isCompleted", false);
|
|
6856
6961
|
// Stream queuing for proper event ordering
|
|
6857
6962
|
__publicField(this, "isTextStreaming", false);
|
|
6858
|
-
__publicField(this, "
|
|
6963
|
+
__publicField(this, "queuedEvents", []);
|
|
6859
6964
|
// Timing tracking for text sequences (text-end to text-start gap)
|
|
6860
6965
|
__publicField(this, "lastTextEndTimestamp", 0);
|
|
6861
6966
|
__publicField(this, "TEXT_GAP_THRESHOLD", 50);
|
|
@@ -6967,15 +7072,24 @@ var _VercelDataStreamHelper = class _VercelDataStreamHelper {
|
|
|
6967
7072
|
data
|
|
6968
7073
|
});
|
|
6969
7074
|
}
|
|
6970
|
-
async writeError(
|
|
7075
|
+
async writeError(error) {
|
|
6971
7076
|
if (this.isCompleted) {
|
|
6972
7077
|
console.warn("Attempted to write error to completed stream");
|
|
6973
7078
|
return;
|
|
6974
7079
|
}
|
|
6975
|
-
|
|
6976
|
-
|
|
6977
|
-
|
|
6978
|
-
|
|
7080
|
+
if (typeof error === "string") {
|
|
7081
|
+
this.writer.write({
|
|
7082
|
+
type: "error",
|
|
7083
|
+
message: error,
|
|
7084
|
+
severity: "error",
|
|
7085
|
+
timestamp: Date.now()
|
|
7086
|
+
});
|
|
7087
|
+
} else {
|
|
7088
|
+
this.writer.write({
|
|
7089
|
+
type: "error",
|
|
7090
|
+
...error
|
|
7091
|
+
});
|
|
7092
|
+
}
|
|
6979
7093
|
}
|
|
6980
7094
|
async streamData(data) {
|
|
6981
7095
|
await this.writeContent(JSON.stringify(data));
|
|
@@ -6987,20 +7101,6 @@ var _VercelDataStreamHelper = class _VercelDataStreamHelper {
|
|
|
6987
7101
|
}
|
|
6988
7102
|
this.writer.merge(stream2);
|
|
6989
7103
|
}
|
|
6990
|
-
async writeCompletion(_finishReason = "stop") {
|
|
6991
|
-
}
|
|
6992
|
-
async writeDone() {
|
|
6993
|
-
}
|
|
6994
|
-
/**
|
|
6995
|
-
* Complete the stream and clean up all memory
|
|
6996
|
-
* This is the primary cleanup point to prevent memory leaks between requests
|
|
6997
|
-
*/
|
|
6998
|
-
async complete() {
|
|
6999
|
-
if (this.isCompleted) return;
|
|
7000
|
-
await this.flushQueuedOperations();
|
|
7001
|
-
this.isCompleted = true;
|
|
7002
|
-
this.cleanup();
|
|
7003
|
-
}
|
|
7004
7104
|
/**
|
|
7005
7105
|
* Clean up all memory allocations
|
|
7006
7106
|
* Should be called when the stream helper is no longer needed
|
|
@@ -7014,7 +7114,7 @@ var _VercelDataStreamHelper = class _VercelDataStreamHelper {
|
|
|
7014
7114
|
this.sentItems.clear();
|
|
7015
7115
|
this.completedItems.clear();
|
|
7016
7116
|
this.textId = null;
|
|
7017
|
-
this.
|
|
7117
|
+
this.queuedEvents = [];
|
|
7018
7118
|
this.isTextStreaming = false;
|
|
7019
7119
|
}
|
|
7020
7120
|
/**
|
|
@@ -7080,7 +7180,9 @@ var _VercelDataStreamHelper = class _VercelDataStreamHelper {
|
|
|
7080
7180
|
if (this.writer && !this.isCompleted) {
|
|
7081
7181
|
this.writer.write({
|
|
7082
7182
|
type: "error",
|
|
7083
|
-
|
|
7183
|
+
message: `Stream terminated: ${reason}`,
|
|
7184
|
+
severity: "error",
|
|
7185
|
+
timestamp: Date.now()
|
|
7084
7186
|
});
|
|
7085
7187
|
}
|
|
7086
7188
|
} catch (e) {
|
|
@@ -7103,23 +7205,33 @@ var _VercelDataStreamHelper = class _VercelDataStreamHelper {
|
|
|
7103
7205
|
isCompleted: this.isCompleted
|
|
7104
7206
|
};
|
|
7105
7207
|
}
|
|
7208
|
+
async writeSummary(summary) {
|
|
7209
|
+
if (this.isCompleted) {
|
|
7210
|
+
console.warn("Attempted to write summary to completed stream");
|
|
7211
|
+
return;
|
|
7212
|
+
}
|
|
7213
|
+
const now = Date.now();
|
|
7214
|
+
const gapFromLastTextEnd = this.lastTextEndTimestamp > 0 ? now - this.lastTextEndTimestamp : Number.MAX_SAFE_INTEGER;
|
|
7215
|
+
if (this.isTextStreaming || gapFromLastTextEnd < this.TEXT_GAP_THRESHOLD) {
|
|
7216
|
+
this.queuedEvents.push({ type: "data-summary", event: summary });
|
|
7217
|
+
return;
|
|
7218
|
+
}
|
|
7219
|
+
await this.flushQueuedOperations();
|
|
7220
|
+
await this.writer.write({
|
|
7221
|
+
id: "id" in summary ? summary.id : void 0,
|
|
7222
|
+
type: "data-summary",
|
|
7223
|
+
data: summary
|
|
7224
|
+
});
|
|
7225
|
+
}
|
|
7106
7226
|
async writeOperation(operation) {
|
|
7107
7227
|
if (this.isCompleted) {
|
|
7108
7228
|
console.warn("Attempted to write operation to completed stream");
|
|
7109
7229
|
return;
|
|
7110
7230
|
}
|
|
7111
|
-
if (operation.type === "status_update" && operation.ctx.label) {
|
|
7112
|
-
operation = {
|
|
7113
|
-
type: operation.type,
|
|
7114
|
-
label: operation.ctx.label,
|
|
7115
|
-
// Preserve the label for the UI
|
|
7116
|
-
ctx: operation.ctx.data
|
|
7117
|
-
};
|
|
7118
|
-
}
|
|
7119
7231
|
const now = Date.now();
|
|
7120
7232
|
const gapFromLastTextEnd = this.lastTextEndTimestamp > 0 ? now - this.lastTextEndTimestamp : Number.MAX_SAFE_INTEGER;
|
|
7121
7233
|
if (this.isTextStreaming || gapFromLastTextEnd < this.TEXT_GAP_THRESHOLD) {
|
|
7122
|
-
this.
|
|
7234
|
+
this.queuedEvents.push({ type: "data-operation", event: operation });
|
|
7123
7235
|
return;
|
|
7124
7236
|
}
|
|
7125
7237
|
await this.flushQueuedOperations();
|
|
@@ -7133,19 +7245,33 @@ var _VercelDataStreamHelper = class _VercelDataStreamHelper {
|
|
|
7133
7245
|
* Flush all queued operations in order after text streaming completes
|
|
7134
7246
|
*/
|
|
7135
7247
|
async flushQueuedOperations() {
|
|
7136
|
-
if (this.
|
|
7248
|
+
if (this.queuedEvents.length === 0) {
|
|
7137
7249
|
return;
|
|
7138
7250
|
}
|
|
7139
|
-
const
|
|
7140
|
-
this.
|
|
7141
|
-
for (const
|
|
7251
|
+
const eventsToFlush = [...this.queuedEvents];
|
|
7252
|
+
this.queuedEvents = [];
|
|
7253
|
+
for (const event of eventsToFlush) {
|
|
7142
7254
|
this.writer.write({
|
|
7143
|
-
id: "id" in
|
|
7144
|
-
type:
|
|
7145
|
-
data:
|
|
7255
|
+
id: "id" in event.event ? event.event.id : void 0,
|
|
7256
|
+
type: event.type,
|
|
7257
|
+
data: event.event
|
|
7146
7258
|
});
|
|
7147
7259
|
}
|
|
7148
7260
|
}
|
|
7261
|
+
async writeCompletion(_finishReason = "stop") {
|
|
7262
|
+
}
|
|
7263
|
+
async writeDone() {
|
|
7264
|
+
}
|
|
7265
|
+
/**
|
|
7266
|
+
* Complete the stream and clean up all memory
|
|
7267
|
+
* This is the primary cleanup point to prevent memory leaks between requests
|
|
7268
|
+
*/
|
|
7269
|
+
async complete() {
|
|
7270
|
+
if (this.isCompleted) return;
|
|
7271
|
+
await this.flushQueuedOperations();
|
|
7272
|
+
this.isCompleted = true;
|
|
7273
|
+
this.cleanup();
|
|
7274
|
+
}
|
|
7149
7275
|
};
|
|
7150
7276
|
// Memory management - focused on connection completion cleanup
|
|
7151
7277
|
__publicField(_VercelDataStreamHelper, "MAX_BUFFER_SIZE", 5 * 1024 * 1024);
|
|
@@ -7158,6 +7284,7 @@ var MCPStreamHelper = class {
|
|
|
7158
7284
|
__publicField(this, "capturedText", "");
|
|
7159
7285
|
__publicField(this, "capturedData", []);
|
|
7160
7286
|
__publicField(this, "capturedOperations", []);
|
|
7287
|
+
__publicField(this, "capturedSummaries", []);
|
|
7161
7288
|
__publicField(this, "hasError", false);
|
|
7162
7289
|
__publicField(this, "errorMessage", "");
|
|
7163
7290
|
__publicField(this, "sessionId");
|
|
@@ -7176,18 +7303,27 @@ var MCPStreamHelper = class {
|
|
|
7176
7303
|
async streamData(data) {
|
|
7177
7304
|
this.capturedData.push(data);
|
|
7178
7305
|
}
|
|
7306
|
+
async streamSummary(summary) {
|
|
7307
|
+
this.capturedSummaries.push(summary);
|
|
7308
|
+
}
|
|
7309
|
+
async streamOperation(operation) {
|
|
7310
|
+
this.capturedOperations.push(operation);
|
|
7311
|
+
}
|
|
7179
7312
|
async writeData(_type, data) {
|
|
7180
7313
|
this.capturedData.push(data);
|
|
7181
7314
|
}
|
|
7182
|
-
async
|
|
7183
|
-
this.
|
|
7184
|
-
this.errorMessage = errorMessage;
|
|
7185
|
-
}
|
|
7186
|
-
async complete() {
|
|
7315
|
+
async writeSummary(summary) {
|
|
7316
|
+
this.capturedSummaries.push(summary);
|
|
7187
7317
|
}
|
|
7188
7318
|
async writeOperation(operation) {
|
|
7189
7319
|
this.capturedOperations.push(operation);
|
|
7190
7320
|
}
|
|
7321
|
+
async writeError(error) {
|
|
7322
|
+
this.hasError = true;
|
|
7323
|
+
this.errorMessage = typeof error === "string" ? error : error.message;
|
|
7324
|
+
}
|
|
7325
|
+
async complete() {
|
|
7326
|
+
}
|
|
7191
7327
|
/**
|
|
7192
7328
|
* Get the captured response for MCP tool result
|
|
7193
7329
|
*/
|
|
@@ -7386,7 +7522,6 @@ var ExecutionHandler = class {
|
|
|
7386
7522
|
if (errorCount >= this.MAX_ERRORS) {
|
|
7387
7523
|
const errorMessage2 = `Maximum error limit (${this.MAX_ERRORS}) reached`;
|
|
7388
7524
|
logger19.error({ maxErrors: this.MAX_ERRORS, errorCount }, errorMessage2);
|
|
7389
|
-
await sseHelper.writeError(errorMessage2);
|
|
7390
7525
|
await sseHelper.writeOperation(errorOp(errorMessage2, currentAgentId || "system"));
|
|
7391
7526
|
if (task) {
|
|
7392
7527
|
await updateTask(dbClient_default)({
|
|
@@ -7527,7 +7662,6 @@ var ExecutionHandler = class {
|
|
|
7527
7662
|
if (errorCount >= this.MAX_ERRORS) {
|
|
7528
7663
|
const errorMessage2 = `Maximum error limit (${this.MAX_ERRORS}) reached`;
|
|
7529
7664
|
logger19.error({ maxErrors: this.MAX_ERRORS, errorCount }, errorMessage2);
|
|
7530
|
-
await sseHelper.writeError(errorMessage2);
|
|
7531
7665
|
await sseHelper.writeOperation(errorOp(errorMessage2, currentAgentId || "system"));
|
|
7532
7666
|
if (task) {
|
|
7533
7667
|
await updateTask(dbClient_default)({
|
|
@@ -7549,7 +7683,6 @@ var ExecutionHandler = class {
|
|
|
7549
7683
|
}
|
|
7550
7684
|
const errorMessage = `Maximum transfer limit (${maxTransfers}) reached without completion`;
|
|
7551
7685
|
logger19.error({ maxTransfers, iterations }, errorMessage);
|
|
7552
|
-
await sseHelper.writeError(errorMessage);
|
|
7553
7686
|
await sseHelper.writeOperation(errorOp(errorMessage, currentAgentId || "system"));
|
|
7554
7687
|
if (task) {
|
|
7555
7688
|
await updateTask(dbClient_default)({
|
|
@@ -7570,8 +7703,7 @@ var ExecutionHandler = class {
|
|
|
7570
7703
|
} catch (error) {
|
|
7571
7704
|
logger19.error({ error }, "Error in execution handler");
|
|
7572
7705
|
const errorMessage = error instanceof Error ? error.message : "Unknown execution error";
|
|
7573
|
-
await sseHelper.
|
|
7574
|
-
await sseHelper.writeOperation(errorOp(errorMessage, currentAgentId || "system"));
|
|
7706
|
+
await sseHelper.writeOperation(errorOp(`Execution error: ${errorMessage}`, currentAgentId || "system"));
|
|
7575
7707
|
if (task) {
|
|
7576
7708
|
await updateTask(dbClient_default)({
|
|
7577
7709
|
taskId: task.id,
|
|
@@ -7859,8 +7991,8 @@ app2.openapi(chatCompletionsRoute, async (c) => {
|
|
|
7859
7991
|
`Execution completed: ${result.success ? "success" : "failed"} after ${result.iterations} iterations`
|
|
7860
7992
|
);
|
|
7861
7993
|
if (!result.success) {
|
|
7862
|
-
await sseHelper.
|
|
7863
|
-
"Sorry, I was unable to process your request at this time. Please try again."
|
|
7994
|
+
await sseHelper.writeOperation(
|
|
7995
|
+
errorOp("Sorry, I was unable to process your request at this time. Please try again.", "system")
|
|
7864
7996
|
);
|
|
7865
7997
|
}
|
|
7866
7998
|
await sseHelper.complete();
|
|
@@ -8031,11 +8163,11 @@ app3.openapi(chatDataStreamRoute, async (c) => {
|
|
|
8031
8163
|
sseHelper: streamHelper
|
|
8032
8164
|
});
|
|
8033
8165
|
if (!result.success) {
|
|
8034
|
-
await streamHelper.
|
|
8166
|
+
await streamHelper.writeOperation(errorOp("Unable to process request", "system"));
|
|
8035
8167
|
}
|
|
8036
8168
|
} catch (err) {
|
|
8037
8169
|
logger21.error({ err }, "Streaming error");
|
|
8038
|
-
await streamHelper.
|
|
8170
|
+
await streamHelper.writeOperation(errorOp("Internal server error", "system"));
|
|
8039
8171
|
} finally {
|
|
8040
8172
|
if ("cleanup" in streamHelper && typeof streamHelper.cleanup === "function") {
|
|
8041
8173
|
streamHelper.cleanup();
|