@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.
Files changed (3) hide show
  1. package/dist/index.cjs +425 -293
  2. package/dist/index.js +426 -294
  3. 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, agentId) {
1001
+ function errorOp(message, agentId, severity = "error", code) {
1002
1002
  return {
1003
1003
  type: "error",
1004
- ctx: {
1005
- error,
1006
- agent: agentId
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 operation;
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.operations && result.operations.length > 0) {
1617
- for (const op of result.operations) {
1618
- if (!op || !op.type || !op.data || Object.keys(op.data).length === 0) {
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
- operation: op
1616
+ summary
1623
1617
  },
1624
1618
  "Skipping empty or invalid structured operation"
1625
1619
  );
1626
1620
  continue;
1627
1621
  }
1628
- const operationToSend = {
1629
- type: "status_update",
1630
- ctx: {
1631
- operationType: op.type,
1632
- label: op.data.label,
1633
- data: Object.fromEntries(
1634
- Object.entries(op.data).filter(([key]) => !["label", "type"].includes(key))
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.writeOperation(operationToSend);
1630
+ await streamHelper.writeSummary(summaryToSend2);
1639
1631
  }
1640
- const summaryTexts = result.operations.map(
1641
- (op) => JSON.stringify({ type: op.type, data: op.data })
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
- if (!operation || !operation.type || !operation.ctx) {
1654
+ {
1672
1655
  logger6.warn(
1673
1656
  {
1674
1657
  sessionId: this.sessionId,
1675
- operation
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
- Describe the ACTUAL finding, result, or specific information discovered (e.g., "Found Slack bot requires admin permissions", "Identified 3 channel types for ingestion", "Configuration requires OAuth token").
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 contain the ACTUAL information discovered ("Found X", "Learned Y", "Discovered Z requires A")
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 operations = [];
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
- operations.push({
1966
+ summaries.push({
1987
1967
  type: componentId,
1988
1968
  data
1989
1969
  });
1990
1970
  }
1991
1971
  }
1992
1972
  span.setAttributes({
1993
- "operations.count": operations.length,
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 { operations };
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 { operations: [] };
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
- artifactType: artifact.metadata?.artifactType,
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.trim()) {
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.trim()) {
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
- var logger8 = getLogger("IncrementalStreamParser");
2723
- var IncrementalStreamParser = class {
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.trim()) {
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 a new object chunk for object streaming (handles JSON objects with artifact references)
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 processObjectChunk(chunk) {
2762
- this.buffer += chunk;
2763
- const parseResult = await this.parseObjectBuffer();
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.buffer = parseResult.remainingBuffer;
2768
- }
2769
- /**
2770
- * Process tool call stream for structured output, streaming components as they complete
2771
- */
2772
- async processToolCallStream(stream2, targetToolName) {
2773
- let jsonBuffer = "";
2774
- let componentBuffer = "";
2775
- let depth = 0;
2776
- let componentsStreamed = 0;
2777
- const MAX_BUFFER_SIZE = 5 * 1024 * 1024;
2778
- for await (const part of stream2) {
2779
- if (part.type === "tool-call-delta" && part.toolName === targetToolName) {
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
- jsonBuffer += delta;
2789
- for (const char of delta) {
2790
- if (componentBuffer.length > MAX_BUFFER_SIZE) {
2791
- logger8.warn(
2792
- { bufferSize: componentBuffer.length, maxSize: MAX_BUFFER_SIZE },
2793
- "Component buffer exceeded maximum size, resetting"
2794
- );
2795
- componentBuffer = "";
2796
- depth = 0;
2797
- continue;
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
- componentBuffer += char;
2800
- if (char === "{") {
2801
- depth++;
2802
- } else if (char === "}") {
2803
- depth--;
2804
- if (depth === 2 && componentBuffer.includes('"id"')) {
2805
- const componentMatch = componentBuffer.match(/\{[^{}]*(?:\{[^{}]*\}[^{}]*)*\}/);
2806
- if (componentMatch) {
2807
- const MAX_COMPONENT_SIZE = 1024 * 1024;
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
- if (componentBuffer.includes('"dataComponents"') && componentBuffer.includes("[")) ;
2796
+ continue;
2841
2797
  }
2842
- } else if (part.type === "tool-call" && part.toolName === targetToolName) {
2843
- if (part.args?.dataComponents) {
2844
- const parts = await this.artifactParser.parseObject(part.args);
2845
- for (const part2 of parts) {
2846
- await this.streamPart(part2);
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
- logger8.debug({ componentsStreamed }, "Finished streaming components");
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.buffer.trim()) {
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.trim()
2899
+ text: this.buffer
2868
2900
  };
2869
2901
  await this.streamPart(part);
2870
2902
  }
2871
- if (this.pendingTextBuffer.trim()) {
2872
- const cleanedText = this.pendingTextBuffer.replace(/<\/?artifact:ref(?:\s[^>]*)?>\/?>/g, "").replace(/<\/?artifact(?:\s[^>]*)?>\/?>/g, "").replace(/<\/(?:\w+:)?artifact>/g, "").trim();
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.trim()) {
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.trim()) {
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 structuredResponse = await generateObject({
5977
- ...structuredModelSettings,
5978
- messages: [
5979
- { role: "user", content: userMessage },
5980
- ...reasoningFlow,
5981
- {
5982
- role: "user",
5983
- content: await this.buildPhase2SystemPrompt()
5984
- }
5985
- ],
5986
- schema: z.object({
5987
- dataComponents: z.array(dataComponentsSchema)
5988
- }),
5989
- experimental_telemetry: {
5990
- isEnabled: true,
5991
- functionId: this.config.id,
5992
- recordInputs: true,
5993
- recordOutputs: true,
5994
- metadata: {
5995
- phase: "structured_generation"
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
- abortSignal: AbortSignal.timeout(phase2TimeoutMs)
5999
- });
6000
- response = {
6001
- ...response,
6002
- object: structuredResponse.object
6003
- };
6004
- textResponse = JSON.stringify(structuredResponse.object, null, 2);
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
- const graph = await getAgentGraph(dbClient_default)({
6058
- scopes: { tenantId: agent.tenantId, projectId: agent.projectId },
6059
- graphId
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, "queuedOperations", []);
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(errorMessage) {
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 writeOperation(operation) {
6812
- if (operation.type === "status_update" && operation.ctx.label) {
6813
- operation = {
6814
- type: operation.type,
6815
- label: operation.ctx.label,
6816
- ctx: operation.ctx.data
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.queuedOperations.push(operation);
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.queuedOperations.length === 0) {
6919
+ if (this.queuedEvents.length === 0) {
6831
6920
  return;
6832
6921
  }
6833
- const operationsToFlush = [...this.queuedOperations];
6834
- this.queuedOperations = [];
6835
- for (const operation of operationsToFlush) {
6836
- await this.writeData("data-operation", operation);
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, "queuedOperations", []);
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(errorMessage) {
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
- this.writer.write({
6976
- type: "error",
6977
- errorText: errorMessage
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.queuedOperations = [];
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
- errorText: `Stream terminated: ${reason}`
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.queuedOperations.push(operation);
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.queuedOperations.length === 0) {
7248
+ if (this.queuedEvents.length === 0) {
7137
7249
  return;
7138
7250
  }
7139
- const operationsToFlush = [...this.queuedOperations];
7140
- this.queuedOperations = [];
7141
- for (const operation of operationsToFlush) {
7251
+ const eventsToFlush = [...this.queuedEvents];
7252
+ this.queuedEvents = [];
7253
+ for (const event of eventsToFlush) {
7142
7254
  this.writer.write({
7143
- id: "id" in operation ? operation.id : void 0,
7144
- type: "data-operation",
7145
- data: operation
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 writeError(errorMessage) {
7183
- this.hasError = true;
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.writeError(`Execution error: ${errorMessage}`);
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.writeError(
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.writeError("Unable to process request");
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.writeError("Internal server error");
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();