@inkeep/agents-run-api 0.0.0-dev-20250917222639 → 0.0.0-dev-20250919052931

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 +585 -391
  2. package/dist/index.js +583 -389
  3. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -8,7 +8,7 @@ import { resourceFromAttributes } from '@opentelemetry/resources';
8
8
  import { NodeSDK } from '@opentelemetry/sdk-node';
9
9
  import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';
10
10
  import { ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions';
11
- import { getLogger, getTracer, HeadersScopeSchema, getRequestExecutionContext, getAgentGraphWithDefaultAgent, contextValidationMiddleware, getFullGraph, createOrGetConversation, getActiveAgentForConversation, setActiveAgentForConversation, getAgentById, handleContextResolution, createMessage, commonGetErrorResponses, createDefaultCredentialStores, CredentialStoreRegistry, listTaskIdsByContextId, getTask, getLedgerArtifacts, getAgentGraph, createTask, updateTask, setSpanWithError, updateConversation, handleApiError, TaskState, setActiveAgentForThread, getConversation, getRelatedAgentsForGraph, getToolsForAgent, getDataComponentsForAgent, getArtifactComponentsForAgent, validateAndGetApiKey, getProject, ContextResolver, CredentialStuffer, MCPServerType, getCredentialReference, McpClient, getContextConfigById, getFullGraphDefinition, TemplateEngine, graphHasArtifactComponents, MCPTransportType, getExternalAgent } from '@inkeep/agents-core';
11
+ import { getLogger, getTracer, HeadersScopeSchema, getRequestExecutionContext, getAgentGraphWithDefaultAgent, contextValidationMiddleware, getFullGraph, createOrGetConversation, getActiveAgentForConversation, setActiveAgentForConversation, getAgentById, handleContextResolution, createMessage, commonGetErrorResponses, loggerFactory, createDefaultCredentialStores, CredentialStoreRegistry, listTaskIdsByContextId, getTask, getLedgerArtifacts, getAgentGraphById, createTask, updateTask, setSpanWithError, updateConversation, handleApiError, TaskState, setActiveAgentForThread, getConversation, getRelatedAgentsForGraph, getToolsForAgent, getDataComponentsForAgent, getArtifactComponentsForAgent, validateAndGetApiKey, getProject, ContextResolver, CredentialStuffer, MCPServerType, getCredentialReference, McpClient, getContextConfigById, getFullGraphDefinition, TemplateEngine, graphHasArtifactComponents, MCPTransportType, getExternalAgent } from '@inkeep/agents-core';
12
12
  import { OpenAPIHono, createRoute, z as z$1 } from '@hono/zod-openapi';
13
13
  import { trace, propagation, context, SpanStatusCode } from '@opentelemetry/api';
14
14
  import { Hono } from 'hono';
@@ -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';
@@ -965,7 +965,7 @@ async function getRegisteredAgent(executionContext, credentialStoreRegistry) {
965
965
  throw new Error("Agent ID is required");
966
966
  }
967
967
  const dbAgent = await getAgentById(dbClient_default)({
968
- scopes: { tenantId, projectId },
968
+ scopes: { tenantId, projectId, graphId },
969
969
  agentId
970
970
  });
971
971
  if (!dbAgent) {
@@ -980,6 +980,38 @@ async function getRegisteredAgent(executionContext, credentialStoreRegistry) {
980
980
  apiKey
981
981
  });
982
982
  }
983
+ async function resolveModelConfig(graphId, agent) {
984
+ if (agent.models?.base?.model) {
985
+ return {
986
+ base: agent.models.base,
987
+ structuredOutput: agent.models.structuredOutput || agent.models.base,
988
+ summarizer: agent.models.summarizer || agent.models.base
989
+ };
990
+ }
991
+ const graph = await getAgentGraphById(dbClient_default)({
992
+ scopes: { tenantId: agent.tenantId, projectId: agent.projectId, graphId }
993
+ });
994
+ if (graph?.models?.base?.model) {
995
+ return {
996
+ base: graph.models.base,
997
+ structuredOutput: agent.models?.structuredOutput || graph.models.structuredOutput || graph.models.base,
998
+ summarizer: agent.models?.summarizer || graph.models.summarizer || graph.models.base
999
+ };
1000
+ }
1001
+ const project = await getProject(dbClient_default)({
1002
+ scopes: { tenantId: agent.tenantId, projectId: agent.projectId }
1003
+ });
1004
+ if (project?.models?.base?.model) {
1005
+ return {
1006
+ base: project.models.base,
1007
+ structuredOutput: agent.models?.structuredOutput || project.models.structuredOutput || project.models.base,
1008
+ summarizer: agent.models?.summarizer || project.models.summarizer || project.models.base
1009
+ };
1010
+ }
1011
+ throw new Error(
1012
+ "Base model configuration is required. Please configure models at the project level."
1013
+ );
1014
+ }
983
1015
  function agentInitializingOp(sessionId, graphId) {
984
1016
  return {
985
1017
  type: "agent_initializing",
@@ -998,24 +1030,19 @@ function completionOp(agentId, iterations) {
998
1030
  }
999
1031
  };
1000
1032
  }
1001
- function errorOp(error, agentId) {
1033
+ function errorOp(message, agentId, severity = "error", code) {
1002
1034
  return {
1003
1035
  type: "error",
1004
- ctx: {
1005
- error,
1006
- agent: agentId
1007
- }
1036
+ message,
1037
+ agent: agentId,
1038
+ severity,
1039
+ code,
1040
+ timestamp: Date.now()
1008
1041
  };
1009
1042
  }
1010
1043
  function generateToolId() {
1011
1044
  return `tool_${nanoid(8)}`;
1012
1045
  }
1013
- function statusUpdateOp(ctx) {
1014
- return {
1015
- type: "status_update",
1016
- ctx
1017
- };
1018
- }
1019
1046
  var logger4 = getLogger("DataComponentSchema");
1020
1047
  function jsonSchemaToZod(jsonSchema) {
1021
1048
  if (!jsonSchema || typeof jsonSchema !== "object") {
@@ -1145,6 +1172,9 @@ var _ModelFactory = class _ModelFactory {
1145
1172
  );
1146
1173
  }
1147
1174
  const modelSettings = config;
1175
+ if (!modelSettings.model) {
1176
+ throw new Error("Model configuration is required");
1177
+ }
1148
1178
  const modelString = modelSettings.model.trim();
1149
1179
  const { provider, modelName } = _ModelFactory.parseModelString(modelString);
1150
1180
  logger5.debug(
@@ -1267,7 +1297,6 @@ var _ModelFactory = class _ModelFactory {
1267
1297
  */
1268
1298
  __publicField(_ModelFactory, "SUPPORTED_PROVIDERS", ["anthropic", "openai", "google"]);
1269
1299
  var ModelFactory = _ModelFactory;
1270
- var tracer = getTracer("agents-run-api");
1271
1300
 
1272
1301
  // src/utils/stream-registry.ts
1273
1302
  var streamHelperRegistry = /* @__PURE__ */ new Map();
@@ -1283,6 +1312,7 @@ function getStreamHelper(requestId2) {
1283
1312
  function unregisterStreamHelper(requestId2) {
1284
1313
  streamHelperRegistry.delete(requestId2);
1285
1314
  }
1315
+ var tracer = getTracer("agents-run-api");
1286
1316
 
1287
1317
  // src/utils/graph-session.ts
1288
1318
  var logger6 = getLogger("GraphSession");
@@ -1591,7 +1621,6 @@ var GraphSession = class {
1591
1621
  }
1592
1622
  this.isGeneratingUpdate = true;
1593
1623
  const statusUpdateState = this.statusUpdateState;
1594
- const graphId = this.graphId;
1595
1624
  try {
1596
1625
  const streamHelper = getStreamHelper(this.sessionId);
1597
1626
  if (!streamHelper) {
@@ -1604,7 +1633,7 @@ var GraphSession = class {
1604
1633
  }
1605
1634
  const now = Date.now();
1606
1635
  const elapsedTime = now - statusUpdateState.startTime;
1607
- let operation;
1636
+ let summaryToSend;
1608
1637
  if (statusUpdateState.config.statusComponents && statusUpdateState.config.statusComponents.length > 0) {
1609
1638
  const result = await this.generateStructuredStatusUpdate(
1610
1639
  this.events.slice(statusUpdateState.lastEventCount),
@@ -1613,32 +1642,30 @@ var GraphSession = class {
1613
1642
  statusUpdateState.summarizerModel,
1614
1643
  this.previousSummaries
1615
1644
  );
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) {
1645
+ if (result.summaries && result.summaries.length > 0) {
1646
+ for (const summary of result.summaries) {
1647
+ if (!summary || !summary.type || !summary.data || !summary.data.label || Object.keys(summary.data).length === 0) {
1619
1648
  logger6.warn(
1620
1649
  {
1621
1650
  sessionId: this.sessionId,
1622
- operation: op
1651
+ summary
1623
1652
  },
1624
1653
  "Skipping empty or invalid structured operation"
1625
1654
  );
1626
1655
  continue;
1627
1656
  }
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
- }
1657
+ const summaryToSend2 = {
1658
+ type: summary.data.type || summary.type,
1659
+ // Preserve the actual custom type from LLM
1660
+ label: summary.data.label,
1661
+ details: Object.fromEntries(
1662
+ Object.entries(summary.data).filter(([key]) => !["label", "type"].includes(key))
1663
+ )
1637
1664
  };
1638
- await streamHelper.writeOperation(operationToSend);
1665
+ await streamHelper.writeSummary(summaryToSend2);
1639
1666
  }
1640
- const summaryTexts = result.operations.map(
1641
- (op) => JSON.stringify({ type: op.type, data: op.data })
1667
+ const summaryTexts = result.summaries.map(
1668
+ (summary) => JSON.stringify({ type: summary.type, data: summary.data })
1642
1669
  );
1643
1670
  this.previousSummaries.push(...summaryTexts);
1644
1671
  if (this.statusUpdateState) {
@@ -1655,34 +1682,20 @@ var GraphSession = class {
1655
1682
  this.previousSummaries
1656
1683
  );
1657
1684
  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
1685
  }
1668
1686
  if (this.previousSummaries.length > 3) {
1669
1687
  this.previousSummaries.shift();
1670
1688
  }
1671
- if (!operation || !operation.type || !operation.ctx) {
1689
+ {
1672
1690
  logger6.warn(
1673
1691
  {
1674
1692
  sessionId: this.sessionId,
1675
- operation
1693
+ summaryToSend
1676
1694
  },
1677
1695
  "Skipping empty or invalid status update operation"
1678
1696
  );
1679
1697
  return;
1680
1698
  }
1681
- await streamHelper.writeOperation(operation);
1682
- if (this.statusUpdateState) {
1683
- this.statusUpdateState.lastUpdateTime = now;
1684
- this.statusUpdateState.lastEventCount = this.events.length;
1685
- }
1686
1699
  } catch (error) {
1687
1700
  logger6.error(
1688
1701
  {
@@ -1815,7 +1828,7 @@ ${previousSummaryContext}` : ""}
1815
1828
  Activities:
1816
1829
  ${userVisibleActivities.join("\n") || "No New Activities"}
1817
1830
 
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").
1831
+ 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
1832
 
1820
1833
  ${this.statusUpdateState?.config.prompt?.trim() || ""}`;
1821
1834
  const prompt = basePrompt;
@@ -1828,6 +1841,9 @@ ${this.statusUpdateState?.config.prompt?.trim() || ""}`;
1828
1841
  }
1829
1842
  modelToUse = this.statusUpdateState.baseModel;
1830
1843
  }
1844
+ if (!modelToUse) {
1845
+ throw new Error("No model configuration available");
1846
+ }
1831
1847
  const model = ModelFactory.createModel(modelToUse);
1832
1848
  const { text } = await generateText({
1833
1849
  model,
@@ -1937,14 +1953,16 @@ Rules:
1937
1953
  - Fill in data for relevant components only
1938
1954
  - Use 'no_relevant_updates' if nothing substantially new to report. DO NOT WRITE LABELS OR USE OTHER COMPONENTS IF YOU USE THIS COMPONENT.
1939
1955
  - 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")
1956
+ - Labels MUST be short 3-5 word phrases with ACTUAL information discovered. NEVER MAKE UP SOMETHING WITHOUT BACKING IT UP WITH ACTUAL INFORMATION.
1957
+ - 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
1958
  - DO NOT use action words like "Searching", "Processing", "Analyzing" - state what was FOUND
1942
1959
  - Include specific details, numbers, requirements, or insights discovered
1960
+ - Examples: "Admin permissions required", "Three OAuth steps found", "Token expires daily"
1943
1961
  - 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
1962
+ - 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
1963
  - Present all operations as seamless actions by a single system
1946
1964
  - 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
1965
+ - 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
1966
  - 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
1967
 
1950
1968
  REMEMBER YOU CAN ONLY USE 'no_relevant_updates' ALONE! IT CANNOT BE CONCATENATED WITH OTHER STATUS UPDATES!
@@ -1960,6 +1978,9 @@ ${this.statusUpdateState?.config.prompt?.trim() || ""}`;
1960
1978
  }
1961
1979
  modelToUse = this.statusUpdateState.baseModel;
1962
1980
  }
1981
+ if (!modelToUse) {
1982
+ throw new Error("No model configuration available");
1983
+ }
1963
1984
  const model = ModelFactory.createModel(modelToUse);
1964
1985
  const { object } = await generateObject({
1965
1986
  model,
@@ -1977,29 +1998,29 @@ ${this.statusUpdateState?.config.prompt?.trim() || ""}`;
1977
1998
  }
1978
1999
  });
1979
2000
  const result = object;
1980
- const operations = [];
2001
+ const summaries = [];
1981
2002
  for (const [componentId, data] of Object.entries(result)) {
1982
2003
  if (componentId === "no_relevant_updates") {
1983
2004
  continue;
1984
2005
  }
1985
2006
  if (data && typeof data === "object" && Object.keys(data).length > 0) {
1986
- operations.push({
2007
+ summaries.push({
1987
2008
  type: componentId,
1988
2009
  data
1989
2010
  });
1990
2011
  }
1991
2012
  }
1992
2013
  span.setAttributes({
1993
- "operations.count": operations.length,
2014
+ "summaries.count": summaries.length,
1994
2015
  "user_activities.count": userVisibleActivities.length,
1995
2016
  "result_keys.count": Object.keys(result).length
1996
2017
  });
1997
2018
  span.setStatus({ code: SpanStatusCode.OK });
1998
- return { operations };
2019
+ return { summaries };
1999
2020
  } catch (error) {
2000
2021
  setSpanWithError(span, error);
2001
2022
  logger6.error({ error }, "Failed to generate structured update, using fallback");
2002
- return { operations: [] };
2023
+ return { summaries: [] };
2003
2024
  } finally {
2004
2025
  span.end();
2005
2026
  }
@@ -2250,6 +2271,9 @@ Make it specific and relevant.`;
2250
2271
  }
2251
2272
  modelToUse = this.statusUpdateState.baseModel;
2252
2273
  }
2274
+ if (!modelToUse) {
2275
+ throw new Error("No model configuration available");
2276
+ }
2253
2277
  const model = ModelFactory.createModel(modelToUse);
2254
2278
  const schema = z.object({
2255
2279
  name: z.string().max(50).describe("Concise, descriptive name for the artifact"),
@@ -2528,6 +2552,7 @@ var _ArtifactParser = class _ArtifactParser {
2528
2552
  }
2529
2553
  for (let i = matches.length - 1; i >= 0; i--) {
2530
2554
  const match = matches[i];
2555
+ if (match.index === void 0) continue;
2531
2556
  const startIdx = match.index;
2532
2557
  const textAfterMatch = text.slice(startIdx);
2533
2558
  if (!textAfterMatch.includes("/>")) {
@@ -2577,7 +2602,8 @@ var _ArtifactParser = class _ArtifactParser {
2577
2602
  taskId,
2578
2603
  name: artifact.name || "Processing...",
2579
2604
  description: artifact.description || "Name and description being generated...",
2580
- artifactType: artifact.metadata?.artifactType,
2605
+ type: artifact.metadata?.artifactType || artifact.artifactType,
2606
+ // Map artifactType to type for consistency
2581
2607
  artifactSummary: artifact.parts?.[0]?.data?.summary || {}
2582
2608
  };
2583
2609
  }
@@ -2594,10 +2620,11 @@ var _ArtifactParser = class _ArtifactParser {
2594
2620
  let lastIndex = 0;
2595
2621
  for (const match of matches) {
2596
2622
  const [fullMatch, artifactId, taskId] = match;
2623
+ if (match.index === void 0) continue;
2597
2624
  const matchStart = match.index;
2598
2625
  if (matchStart > lastIndex) {
2599
2626
  const textBefore = text.slice(lastIndex, matchStart);
2600
- if (textBefore.trim()) {
2627
+ if (textBefore) {
2601
2628
  parts.push({ kind: "text", text: textBefore });
2602
2629
  }
2603
2630
  }
@@ -2609,7 +2636,7 @@ var _ArtifactParser = class _ArtifactParser {
2609
2636
  }
2610
2637
  if (lastIndex < text.length) {
2611
2638
  const remainingText = text.slice(lastIndex);
2612
- if (remainingText.trim()) {
2639
+ if (remainingText) {
2613
2640
  parts.push({ kind: "text", text: remainingText });
2614
2641
  }
2615
2642
  }
@@ -2719,8 +2746,9 @@ __publicField(_ArtifactParser, "INCOMPLETE_ARTIFACT_REGEX", /<(a(r(t(i(f(a(c(t(:
2719
2746
  var ArtifactParser = _ArtifactParser;
2720
2747
 
2721
2748
  // src/utils/incremental-stream-parser.ts
2722
- var logger8 = getLogger("IncrementalStreamParser");
2723
- var IncrementalStreamParser = class {
2749
+ getLogger("IncrementalStreamParser");
2750
+ var _IncrementalStreamParser = class _IncrementalStreamParser {
2751
+ // Max number of streamed component IDs to track
2724
2752
  constructor(streamHelper, tenantId, contextId) {
2725
2753
  __publicField(this, "buffer", "");
2726
2754
  __publicField(this, "pendingTextBuffer", "");
@@ -2730,6 +2758,9 @@ var IncrementalStreamParser = class {
2730
2758
  __publicField(this, "collectedParts", []);
2731
2759
  __publicField(this, "contextId");
2732
2760
  __publicField(this, "lastChunkWasToolResult", false);
2761
+ __publicField(this, "componentAccumulator", {});
2762
+ __publicField(this, "lastStreamedComponents", /* @__PURE__ */ new Map());
2763
+ __publicField(this, "componentSnapshots", /* @__PURE__ */ new Map());
2733
2764
  this.streamHelper = streamHelper;
2734
2765
  this.contextId = contextId;
2735
2766
  this.artifactParser = new ArtifactParser(tenantId);
@@ -2744,7 +2775,7 @@ var IncrementalStreamParser = class {
2744
2775
  * Process a new text chunk for text streaming (handles artifact markers)
2745
2776
  */
2746
2777
  async processTextChunk(chunk) {
2747
- if (this.lastChunkWasToolResult && this.buffer === "" && chunk.trim()) {
2778
+ if (this.lastChunkWasToolResult && this.buffer === "" && chunk) {
2748
2779
  chunk = "\n\n" + chunk;
2749
2780
  this.lastChunkWasToolResult = false;
2750
2781
  }
@@ -2756,100 +2787,122 @@ var IncrementalStreamParser = class {
2756
2787
  this.buffer = parseResult.remainingBuffer;
2757
2788
  }
2758
2789
  /**
2759
- * Process a new object chunk for object streaming (handles JSON objects with artifact references)
2790
+ * Process object deltas directly from Vercel AI SDK's fullStream
2791
+ * Accumulates components and streams them when they're stable (unchanged between deltas)
2760
2792
  */
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);
2793
+ async processObjectDelta(delta) {
2794
+ if (!delta || typeof delta !== "object") {
2795
+ return;
2766
2796
  }
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);
2797
+ this.componentAccumulator = this.deepMerge(this.componentAccumulator, delta);
2798
+ if (this.componentAccumulator.dataComponents && Array.isArray(this.componentAccumulator.dataComponents)) {
2799
+ const components = this.componentAccumulator.dataComponents;
2800
+ const currentComponentIds = new Set(components.filter((c) => c?.id).map((c) => c.id));
2801
+ for (const [componentId, snapshot] of this.componentSnapshots.entries()) {
2802
+ if (!currentComponentIds.has(componentId) && !this.lastStreamedComponents.has(componentId)) {
2803
+ try {
2804
+ const component = JSON.parse(snapshot);
2805
+ if (this.isComponentComplete(component)) {
2806
+ await this.streamComponent(component);
2807
+ }
2808
+ } catch (e) {
2809
+ }
2787
2810
  }
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;
2811
+ }
2812
+ for (let i = 0; i < components.length; i++) {
2813
+ const component = components[i];
2814
+ if (!component?.id) continue;
2815
+ const componentKey = component.id;
2816
+ const hasBeenStreamed = this.lastStreamedComponents.has(componentKey);
2817
+ if (hasBeenStreamed) continue;
2818
+ const currentSnapshot = JSON.stringify(component);
2819
+ const previousSnapshot = this.componentSnapshots.get(componentKey);
2820
+ this.componentSnapshots.set(componentKey, currentSnapshot);
2821
+ if (this.componentSnapshots.size > _IncrementalStreamParser.MAX_SNAPSHOT_SIZE) {
2822
+ const firstKey = this.componentSnapshots.keys().next().value;
2823
+ if (firstKey) {
2824
+ this.componentSnapshots.delete(firstKey);
2798
2825
  }
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
- }
2826
+ }
2827
+ if (component.name === "Text" && component.props?.text) {
2828
+ const previousTextContent = previousSnapshot ? JSON.parse(previousSnapshot).props?.text || "" : "";
2829
+ const currentTextContent = component.props.text || "";
2830
+ if (currentTextContent.length > previousTextContent.length) {
2831
+ const newText = currentTextContent.slice(previousTextContent.length);
2832
+ if (!this.hasStartedRole) {
2833
+ await this.streamHelper.writeRole("assistant");
2834
+ this.hasStartedRole = true;
2838
2835
  }
2836
+ await this.streamHelper.streamText(newText, 50);
2837
+ this.collectedParts.push({
2838
+ kind: "text",
2839
+ text: newText
2840
+ });
2839
2841
  }
2840
- if (componentBuffer.includes('"dataComponents"') && componentBuffer.includes("[")) ;
2842
+ continue;
2841
2843
  }
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);
2844
+ if (this.isComponentComplete(component)) {
2845
+ const currentPropsSnapshot = JSON.stringify(component.props);
2846
+ const previousPropsSnapshot = previousSnapshot ? JSON.stringify(JSON.parse(previousSnapshot).props) : null;
2847
+ if (previousPropsSnapshot === currentPropsSnapshot) {
2848
+ await this.streamComponent(component);
2847
2849
  }
2848
2850
  }
2849
- break;
2850
2851
  }
2851
2852
  }
2852
- logger8.debug({ componentsStreamed }, "Finished streaming components");
2853
+ }
2854
+ /**
2855
+ * Stream a component and mark it as streamed
2856
+ * Note: Text components are handled separately with incremental streaming
2857
+ */
2858
+ async streamComponent(component) {
2859
+ const parts = await this.artifactParser.parseObject({
2860
+ dataComponents: [component]
2861
+ });
2862
+ for (const part of parts) {
2863
+ await this.streamPart(part);
2864
+ }
2865
+ this.lastStreamedComponents.set(component.id, true);
2866
+ if (this.lastStreamedComponents.size > _IncrementalStreamParser.MAX_STREAMED_SIZE) {
2867
+ const firstKey = this.lastStreamedComponents.keys().next().value;
2868
+ if (firstKey) {
2869
+ this.lastStreamedComponents.delete(firstKey);
2870
+ }
2871
+ }
2872
+ this.componentSnapshots.delete(component.id);
2873
+ }
2874
+ /**
2875
+ * Check if a component has the basic structure required for streaming
2876
+ * Requires id, name, and props object with content
2877
+ */
2878
+ isComponentComplete(component) {
2879
+ if (!component || !component.id || !component.name) {
2880
+ return false;
2881
+ }
2882
+ if (!component.props || typeof component.props !== "object") {
2883
+ return false;
2884
+ }
2885
+ const isArtifact = component.name === "Artifact" || component.props.artifact_id && component.props.task_id;
2886
+ if (isArtifact) {
2887
+ return Boolean(component.props.artifact_id && component.props.task_id);
2888
+ }
2889
+ return true;
2890
+ }
2891
+ /**
2892
+ * Deep merge helper for object deltas
2893
+ */
2894
+ deepMerge(target, source) {
2895
+ if (!source) return target;
2896
+ if (!target) return source;
2897
+ const result = { ...target };
2898
+ for (const key in source) {
2899
+ if (source[key] && typeof source[key] === "object" && !Array.isArray(source[key])) {
2900
+ result[key] = this.deepMerge(target[key], source[key]);
2901
+ } else {
2902
+ result[key] = source[key];
2903
+ }
2904
+ }
2905
+ return result;
2853
2906
  }
2854
2907
  /**
2855
2908
  * Legacy method for backward compatibility - defaults to text processing
@@ -2861,15 +2914,40 @@ var IncrementalStreamParser = class {
2861
2914
  * Process any remaining buffer content at the end of stream
2862
2915
  */
2863
2916
  async finalize() {
2864
- if (this.buffer.trim()) {
2917
+ if (this.componentAccumulator.dataComponents && Array.isArray(this.componentAccumulator.dataComponents)) {
2918
+ const components = this.componentAccumulator.dataComponents;
2919
+ for (let i = 0; i < components.length; i++) {
2920
+ const component = components[i];
2921
+ if (!component?.id) continue;
2922
+ const componentKey = component.id;
2923
+ const hasBeenStreamed = this.lastStreamedComponents.has(componentKey);
2924
+ if (!hasBeenStreamed && this.isComponentComplete(component) && component.name !== "Text") {
2925
+ const parts = await this.artifactParser.parseObject({
2926
+ dataComponents: [component]
2927
+ });
2928
+ for (const part of parts) {
2929
+ await this.streamPart(part);
2930
+ }
2931
+ this.lastStreamedComponents.set(componentKey, true);
2932
+ if (this.lastStreamedComponents.size > _IncrementalStreamParser.MAX_STREAMED_SIZE) {
2933
+ const firstKey = this.lastStreamedComponents.keys().next().value;
2934
+ if (firstKey) {
2935
+ this.lastStreamedComponents.delete(firstKey);
2936
+ }
2937
+ }
2938
+ this.componentSnapshots.delete(componentKey);
2939
+ }
2940
+ }
2941
+ }
2942
+ if (this.buffer) {
2865
2943
  const part = {
2866
2944
  kind: "text",
2867
- text: this.buffer.trim()
2945
+ text: this.buffer
2868
2946
  };
2869
2947
  await this.streamPart(part);
2870
2948
  }
2871
- if (this.pendingTextBuffer.trim()) {
2872
- const cleanedText = this.pendingTextBuffer.replace(/<\/?artifact:ref(?:\s[^>]*)?>\/?>/g, "").replace(/<\/?artifact(?:\s[^>]*)?>\/?>/g, "").replace(/<\/(?:\w+:)?artifact>/g, "").trim();
2949
+ if (this.pendingTextBuffer) {
2950
+ const cleanedText = this.pendingTextBuffer.replace(/<\/?artifact:ref(?:\s[^>]*)?>\/?>/g, "").replace(/<\/?artifact(?:\s[^>]*)?>\/?>/g, "").replace(/<\/(?:\w+:)?artifact>/g, "");
2873
2951
  if (cleanedText) {
2874
2952
  this.collectedParts.push({
2875
2953
  kind: "text",
@@ -2879,6 +2957,9 @@ var IncrementalStreamParser = class {
2879
2957
  }
2880
2958
  this.pendingTextBuffer = "";
2881
2959
  }
2960
+ this.componentSnapshots.clear();
2961
+ this.lastStreamedComponents.clear();
2962
+ this.componentAccumulator = {};
2882
2963
  }
2883
2964
  /**
2884
2965
  * Get all collected parts for building the final response
@@ -2925,30 +3006,6 @@ var IncrementalStreamParser = class {
2925
3006
  remainingBuffer: ""
2926
3007
  };
2927
3008
  }
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
3009
  /**
2953
3010
  * Check if text might be the start of an artifact marker
2954
3011
  */
@@ -2969,7 +3026,7 @@ var IncrementalStreamParser = class {
2969
3026
  this.pendingTextBuffer += part.text;
2970
3027
  if (!this.artifactParser.hasIncompleteArtifact(this.pendingTextBuffer)) {
2971
3028
  const cleanedText = this.pendingTextBuffer.replace(/<\/?artifact:ref(?:\s[^>]*)?>\/?>/g, "").replace(/<\/?artifact(?:\s[^>]*)?>\/?>/g, "").replace(/<\/(?:\w+:)?artifact>/g, "");
2972
- if (cleanedText.trim()) {
3029
+ if (cleanedText) {
2973
3030
  await this.streamHelper.streamText(cleanedText, 50);
2974
3031
  }
2975
3032
  this.pendingTextBuffer = "";
@@ -2977,7 +3034,7 @@ var IncrementalStreamParser = class {
2977
3034
  } else if (part.kind === "data" && part.data) {
2978
3035
  if (this.pendingTextBuffer) {
2979
3036
  const cleanedText = this.pendingTextBuffer.replace(/<\/?artifact:ref(?:\s[^>]*)?>\/?>/g, "").replace(/<\/?artifact(?:\s[^>]*)?>\/?>/g, "").replace(/<\/(?:\w+:)?artifact>/g, "");
2980
- if (cleanedText.trim()) {
3037
+ if (cleanedText) {
2981
3038
  await this.streamHelper.streamText(cleanedText, 50);
2982
3039
  }
2983
3040
  this.pendingTextBuffer = "";
@@ -2991,6 +3048,11 @@ var IncrementalStreamParser = class {
2991
3048
  }
2992
3049
  }
2993
3050
  };
3051
+ // Memory management constants
3052
+ __publicField(_IncrementalStreamParser, "MAX_SNAPSHOT_SIZE", 100);
3053
+ // Max number of snapshots to keep
3054
+ __publicField(_IncrementalStreamParser, "MAX_STREAMED_SIZE", 1e3);
3055
+ var IncrementalStreamParser = _IncrementalStreamParser;
2994
3056
 
2995
3057
  // src/utils/response-formatter.ts
2996
3058
  var logger9 = getLogger("ResponseFormatter");
@@ -4377,7 +4439,8 @@ function createDelegateToAgentTool({
4377
4439
  const externalAgent = await getExternalAgent(dbClient_default)({
4378
4440
  scopes: {
4379
4441
  tenantId,
4380
- projectId
4442
+ projectId,
4443
+ graphId
4381
4444
  },
4382
4445
  agentId: delegateConfig.config.id
4383
4446
  });
@@ -4979,6 +5042,23 @@ var Agent = class {
4979
5042
  __publicField(this, "credentialStoreRegistry");
4980
5043
  this.artifactComponents = config.artifactComponents || [];
4981
5044
  let processedDataComponents = config.dataComponents || [];
5045
+ if (processedDataComponents.length > 0) {
5046
+ processedDataComponents.push({
5047
+ id: "text-content",
5048
+ name: "Text",
5049
+ description: "Natural conversational text for the user - write naturally without mentioning technical details. Avoid redundancy and repetition with data components.",
5050
+ props: {
5051
+ type: "object",
5052
+ properties: {
5053
+ text: {
5054
+ type: "string",
5055
+ 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."
5056
+ }
5057
+ },
5058
+ required: ["text"]
5059
+ }
5060
+ });
5061
+ }
4982
5062
  if (this.artifactComponents.length > 0 && config.dataComponents && config.dataComponents.length > 0) {
4983
5063
  processedDataComponents = [
4984
5064
  ArtifactReferenceSchema.getDataComponent(config.tenantId, config.projectId),
@@ -5249,8 +5329,12 @@ var Agent = class {
5249
5329
  async getMcpTool(tool4) {
5250
5330
  const credentialReferenceId = tool4.credentialReferenceId;
5251
5331
  const toolsForAgent = await getToolsForAgent(dbClient_default)({
5252
- scopes: { tenantId: this.config.tenantId, projectId: this.config.projectId },
5253
- agentId: this.config.id
5332
+ scopes: {
5333
+ tenantId: this.config.tenantId,
5334
+ projectId: this.config.projectId,
5335
+ graphId: this.config.graphId,
5336
+ agentId: this.config.id
5337
+ }
5254
5338
  });
5255
5339
  const selectedTools = toolsForAgent.data.find((t) => t.toolId === tool4.id)?.selectedTools || void 0;
5256
5340
  let serverConfig;
@@ -5397,9 +5481,9 @@ var Agent = class {
5397
5481
  const graphDefinition = await getFullGraphDefinition(dbClient_default)({
5398
5482
  scopes: {
5399
5483
  tenantId: this.config.tenantId,
5400
- projectId: this.config.projectId
5401
- },
5402
- graphId: this.config.graphId
5484
+ projectId: this.config.projectId,
5485
+ graphId: this.config.graphId
5486
+ }
5403
5487
  });
5404
5488
  return graphDefinition?.graphPrompt || void 0;
5405
5489
  } catch (error) {
@@ -5421,14 +5505,16 @@ var Agent = class {
5421
5505
  const graphDefinition = await getFullGraphDefinition(dbClient_default)({
5422
5506
  scopes: {
5423
5507
  tenantId: this.config.tenantId,
5424
- projectId: this.config.projectId
5425
- },
5426
- graphId: this.config.graphId
5508
+ projectId: this.config.projectId,
5509
+ graphId: this.config.graphId
5510
+ }
5427
5511
  });
5428
5512
  if (!graphDefinition) {
5429
5513
  return false;
5430
5514
  }
5431
- return !!(graphDefinition.artifactComponents && Object.keys(graphDefinition.artifactComponents).length > 0);
5515
+ return Object.values(graphDefinition.agents).some(
5516
+ (agent) => "artifactComponents" in agent && agent.artifactComponents && agent.artifactComponents.length > 0
5517
+ );
5432
5518
  } catch (error) {
5433
5519
  logger15.warn(
5434
5520
  {
@@ -5456,7 +5542,8 @@ Key requirements:
5456
5542
  - Mix artifact references throughout your dataComponents array
5457
5543
  - Each artifact reference must use EXACT IDs from tool outputs
5458
5544
  - Reference artifacts that directly support the adjacent information
5459
- - Follow the pattern: Data \u2192 Supporting Artifact \u2192 Next Data \u2192 Next Artifact`;
5545
+ - Follow the pattern: Data \u2192 Supporting Artifact \u2192 Next Data \u2192 Next Artifact
5546
+ - 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
5547
  }
5461
5548
  if (hasDataComponents && !hasArtifactComponents) {
5462
5549
  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 +5551,8 @@ Key requirements:
5464
5551
  Key requirements:
5465
5552
  - Use the exact component structure and property names
5466
5553
  - Fill in all relevant data from the research
5467
- - Ensure data is organized logically and completely`;
5554
+ - Ensure data is organized logically and completely
5555
+ - 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
5556
  }
5469
5557
  if (!hasDataComponents && hasArtifactComponents) {
5470
5558
  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 +5562,7 @@ Key requirements:
5474
5562
  - Reference artifacts that support your response
5475
5563
  - Never make up or modify artifact IDs`;
5476
5564
  }
5477
- return `Generate the final response based on the research above.`;
5565
+ return `Generate the final response based on the research above. Write naturally as if having a conversation.`;
5478
5566
  }
5479
5567
  async buildSystemPrompt(runtimeContext, excludeDataComponents = false) {
5480
5568
  const conversationId = runtimeContext?.metadata?.conversationId || runtimeContext?.contextId;
@@ -5625,9 +5713,9 @@ Key requirements:
5625
5713
  return await graphHasArtifactComponents(dbClient_default)({
5626
5714
  scopes: {
5627
5715
  tenantId: this.config.tenantId,
5628
- projectId: this.config.projectId
5629
- },
5630
- graphId: this.config.graphId
5716
+ projectId: this.config.projectId,
5717
+ graphId: this.config.graphId
5718
+ }
5631
5719
  });
5632
5720
  } catch (error) {
5633
5721
  logger15.error(
@@ -5973,35 +6061,94 @@ ${output}`;
5973
6061
  this.getStructuredOutputModel()
5974
6062
  );
5975
6063
  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"
6064
+ const shouldStreamPhase2 = this.getStreamingHelper();
6065
+ if (shouldStreamPhase2) {
6066
+ const streamResult = streamObject({
6067
+ ...structuredModelSettings,
6068
+ messages: [
6069
+ { role: "user", content: userMessage },
6070
+ ...reasoningFlow,
6071
+ {
6072
+ role: "user",
6073
+ content: await this.buildPhase2SystemPrompt()
6074
+ }
6075
+ ],
6076
+ schema: z.object({
6077
+ dataComponents: z.array(dataComponentsSchema)
6078
+ }),
6079
+ experimental_telemetry: {
6080
+ isEnabled: true,
6081
+ functionId: this.config.id,
6082
+ recordInputs: true,
6083
+ recordOutputs: true,
6084
+ metadata: {
6085
+ phase: "structured_generation"
6086
+ }
6087
+ },
6088
+ abortSignal: AbortSignal.timeout(phase2TimeoutMs)
6089
+ });
6090
+ const streamHelper = this.getStreamingHelper();
6091
+ if (!streamHelper) {
6092
+ throw new Error("Stream helper is unexpectedly undefined in streaming context");
6093
+ }
6094
+ const parser = new IncrementalStreamParser(
6095
+ streamHelper,
6096
+ this.config.tenantId,
6097
+ contextId
6098
+ );
6099
+ for await (const delta of streamResult.partialObjectStream) {
6100
+ if (delta) {
6101
+ await parser.processObjectDelta(delta);
5996
6102
  }
5997
- },
5998
- abortSignal: AbortSignal.timeout(phase2TimeoutMs)
5999
- });
6000
- response = {
6001
- ...response,
6002
- object: structuredResponse.object
6003
- };
6004
- textResponse = JSON.stringify(structuredResponse.object, null, 2);
6103
+ }
6104
+ await parser.finalize();
6105
+ const structuredResponse = await streamResult;
6106
+ const collectedParts = parser.getCollectedParts();
6107
+ if (collectedParts.length > 0) {
6108
+ response.formattedContent = {
6109
+ parts: collectedParts.map((part) => ({
6110
+ kind: part.kind,
6111
+ ...part.kind === "text" && { text: part.text },
6112
+ ...part.kind === "data" && { data: part.data }
6113
+ }))
6114
+ };
6115
+ }
6116
+ response = {
6117
+ ...response,
6118
+ object: structuredResponse.object
6119
+ };
6120
+ textResponse = JSON.stringify(structuredResponse.object, null, 2);
6121
+ } else {
6122
+ const structuredResponse = await generateObject({
6123
+ ...structuredModelSettings,
6124
+ messages: [
6125
+ { role: "user", content: userMessage },
6126
+ ...reasoningFlow,
6127
+ {
6128
+ role: "user",
6129
+ content: await this.buildPhase2SystemPrompt()
6130
+ }
6131
+ ],
6132
+ schema: z.object({
6133
+ dataComponents: z.array(dataComponentsSchema)
6134
+ }),
6135
+ experimental_telemetry: {
6136
+ isEnabled: true,
6137
+ functionId: this.config.id,
6138
+ recordInputs: true,
6139
+ recordOutputs: true,
6140
+ metadata: {
6141
+ phase: "structured_generation"
6142
+ }
6143
+ },
6144
+ abortSignal: AbortSignal.timeout(phase2TimeoutMs)
6145
+ });
6146
+ response = {
6147
+ ...response,
6148
+ object: structuredResponse.object
6149
+ };
6150
+ textResponse = JSON.stringify(structuredResponse.object, null, 2);
6151
+ }
6005
6152
  } else {
6006
6153
  textResponse = response.text || "";
6007
6154
  }
@@ -6046,39 +6193,6 @@ ${output}`;
6046
6193
  });
6047
6194
  }
6048
6195
  };
6049
- async function resolveModelConfig(graphId, agent) {
6050
- if (agent.models?.base?.model) {
6051
- return {
6052
- base: agent.models.base,
6053
- structuredOutput: agent.models.structuredOutput || agent.models.base,
6054
- summarizer: agent.models.summarizer || agent.models.base
6055
- };
6056
- }
6057
- const graph = await getAgentGraph(dbClient_default)({
6058
- scopes: { tenantId: agent.tenantId, projectId: agent.projectId },
6059
- graphId
6060
- });
6061
- if (graph?.models?.base?.model) {
6062
- return {
6063
- base: graph.models.base,
6064
- structuredOutput: agent.models?.structuredOutput || graph.models.structuredOutput || graph.models.base,
6065
- summarizer: agent.models?.summarizer || graph.models.summarizer || graph.models.base
6066
- };
6067
- }
6068
- const project = await getProject(dbClient_default)({
6069
- scopes: { tenantId: agent.tenantId, projectId: agent.projectId }
6070
- });
6071
- if (project?.models?.base?.model) {
6072
- return {
6073
- base: project.models.base,
6074
- structuredOutput: agent.models?.structuredOutput || project.models.structuredOutput || project.models.base,
6075
- summarizer: agent.models?.summarizer || project.models.summarizer || project.models.base
6076
- };
6077
- }
6078
- throw new Error(
6079
- "Base model configuration is required. Please configure models at the project level."
6080
- );
6081
- }
6082
6196
 
6083
6197
  // src/agents/generateTaskHandler.ts
6084
6198
  function parseEmbeddedJson(data) {
@@ -6114,31 +6228,34 @@ var createTaskHandler = (config, credentialStoreRegistry) => {
6114
6228
  getRelatedAgentsForGraph(dbClient_default)({
6115
6229
  scopes: {
6116
6230
  tenantId: config.tenantId,
6117
- projectId: config.projectId
6231
+ projectId: config.projectId,
6232
+ graphId: config.graphId
6118
6233
  },
6119
- graphId: config.graphId,
6120
6234
  agentId: config.agentId
6121
6235
  }),
6122
6236
  getToolsForAgent(dbClient_default)({
6123
6237
  scopes: {
6124
6238
  tenantId: config.tenantId,
6125
- projectId: config.projectId
6126
- },
6127
- agentId: config.agentId
6239
+ projectId: config.projectId,
6240
+ graphId: config.graphId,
6241
+ agentId: config.agentId
6242
+ }
6128
6243
  }),
6129
6244
  getDataComponentsForAgent(dbClient_default)({
6130
6245
  scopes: {
6131
6246
  tenantId: config.tenantId,
6132
- projectId: config.projectId
6133
- },
6134
- agentId: config.agentId
6247
+ projectId: config.projectId,
6248
+ graphId: config.graphId,
6249
+ agentId: config.agentId
6250
+ }
6135
6251
  }),
6136
6252
  getArtifactComponentsForAgent(dbClient_default)({
6137
6253
  scopes: {
6138
6254
  tenantId: config.tenantId,
6139
- projectId: config.projectId
6140
- },
6141
- agentId: config.agentId
6255
+ projectId: config.projectId,
6256
+ graphId: config.graphId,
6257
+ agentId: config.agentId
6258
+ }
6142
6259
  })
6143
6260
  ]);
6144
6261
  logger16.info({ toolsForAgent, internalRelations, externalRelations }, "agent stuff");
@@ -6146,13 +6263,16 @@ var createTaskHandler = (config, credentialStoreRegistry) => {
6146
6263
  internalRelations.map(async (relation) => {
6147
6264
  try {
6148
6265
  const relatedAgent = await getAgentById(dbClient_default)({
6149
- scopes: { tenantId: config.tenantId, projectId: config.projectId },
6266
+ scopes: {
6267
+ tenantId: config.tenantId,
6268
+ projectId: config.projectId,
6269
+ graphId: config.graphId
6270
+ },
6150
6271
  agentId: relation.id
6151
6272
  });
6152
6273
  if (relatedAgent) {
6153
6274
  const relatedAgentRelations = await getRelatedAgentsForGraph(dbClient_default)({
6154
- scopes: { tenantId: config.tenantId, projectId: config.projectId },
6155
- graphId: config.graphId,
6275
+ scopes: { tenantId: config.tenantId, projectId: config.projectId, graphId: config.graphId },
6156
6276
  agentId: relation.id
6157
6277
  });
6158
6278
  const enhancedDescription = generateDescriptionWithTransfers(
@@ -6375,16 +6495,17 @@ var createTaskHandlerConfig = async (params) => {
6375
6495
  const agent = await getAgentById(dbClient_default)({
6376
6496
  scopes: {
6377
6497
  tenantId: params.tenantId,
6378
- projectId: params.projectId
6498
+ projectId: params.projectId,
6499
+ graphId: params.graphId
6379
6500
  },
6380
6501
  agentId: params.agentId
6381
6502
  });
6382
- const agentGraph = await getAgentGraph(dbClient_default)({
6503
+ const agentGraph = await getAgentGraphById(dbClient_default)({
6383
6504
  scopes: {
6384
6505
  tenantId: params.tenantId,
6385
- projectId: params.projectId
6386
- },
6387
- graphId: params.graphId
6506
+ projectId: params.projectId,
6507
+ graphId: params.graphId
6508
+ }
6388
6509
  });
6389
6510
  if (!agent) {
6390
6511
  throw new Error(`Agent not found: ${params.agentId}`);
@@ -6423,10 +6544,14 @@ async function hydrateGraph({
6423
6544
  apiKey
6424
6545
  }) {
6425
6546
  try {
6547
+ if (!dbGraph.defaultAgentId) {
6548
+ throw new Error(`Graph ${dbGraph.id} does not have a default agent configured`);
6549
+ }
6426
6550
  const defaultAgent = await getAgentById(dbClient_default)({
6427
6551
  scopes: {
6428
6552
  tenantId: dbGraph.tenantId,
6429
- projectId: dbGraph.projectId
6553
+ projectId: dbGraph.projectId,
6554
+ graphId: dbGraph.id
6430
6555
  },
6431
6556
  agentId: dbGraph.defaultAgentId
6432
6557
  });
@@ -6481,7 +6606,7 @@ async function hydrateGraph({
6481
6606
  }
6482
6607
  async function getRegisteredGraph(executionContext) {
6483
6608
  const { tenantId, projectId, graphId, baseUrl, apiKey } = executionContext;
6484
- const dbGraph = await getAgentGraph(dbClient_default)({ scopes: { tenantId, projectId }, graphId });
6609
+ const dbGraph = await getAgentGraphById(dbClient_default)({ scopes: { tenantId, projectId, graphId } });
6485
6610
  if (!dbGraph) {
6486
6611
  return null;
6487
6612
  }
@@ -6539,6 +6664,7 @@ app.openapi(
6539
6664
  );
6540
6665
  const executionContext = getRequestExecutionContext(c);
6541
6666
  const { tenantId, projectId, graphId, agentId } = executionContext;
6667
+ console.dir("executionContext", executionContext);
6542
6668
  if (agentId) {
6543
6669
  logger17.info(
6544
6670
  {
@@ -6626,8 +6752,7 @@ app.post("/a2a", async (c) => {
6626
6752
  "graph-level a2a endpoint"
6627
6753
  );
6628
6754
  const graph = await getAgentGraphWithDefaultAgent(dbClient_default)({
6629
- scopes: { tenantId, projectId },
6630
- graphId
6755
+ scopes: { tenantId, projectId, graphId }
6631
6756
  });
6632
6757
  if (!graph) {
6633
6758
  return c.json(
@@ -6639,6 +6764,16 @@ app.post("/a2a", async (c) => {
6639
6764
  404
6640
6765
  );
6641
6766
  }
6767
+ if (!graph.defaultAgentId) {
6768
+ return c.json(
6769
+ {
6770
+ jsonrpc: "2.0",
6771
+ error: { code: -32004, message: "Graph does not have a default agent configured" },
6772
+ id: null
6773
+ },
6774
+ 400
6775
+ );
6776
+ }
6642
6777
  executionContext.agentId = graph.defaultAgentId;
6643
6778
  const credentialStores = c.get("credentialStores");
6644
6779
  const defaultAgent = await getRegisteredAgent(executionContext, credentialStores);
@@ -6683,7 +6818,7 @@ var SSEStreamHelper = class {
6683
6818
  this.timestamp = timestamp;
6684
6819
  // Stream queuing for proper event ordering
6685
6820
  __publicField(this, "isTextStreaming", false);
6686
- __publicField(this, "queuedOperations", []);
6821
+ __publicField(this, "queuedEvents", []);
6687
6822
  }
6688
6823
  /**
6689
6824
  * Write the initial role message
@@ -6748,9 +6883,10 @@ var SSEStreamHelper = class {
6748
6883
  await this.writeContent(JSON.stringify(data));
6749
6884
  }
6750
6885
  /**
6751
- * Write error message
6886
+ * Write error message or error event
6752
6887
  */
6753
- async writeError(errorMessage) {
6888
+ async writeError(error) {
6889
+ const errorMessage = typeof error === "string" ? error : error.message;
6754
6890
  await this.writeContent(`
6755
6891
 
6756
6892
  ${errorMessage}`);
@@ -6774,22 +6910,6 @@ ${errorMessage}`);
6774
6910
  })
6775
6911
  });
6776
6912
  }
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
6913
  async writeData(type, data) {
6794
6914
  await this.stream.writeSSE({
6795
6915
  data: JSON.stringify({
@@ -6808,16 +6928,23 @@ ${errorMessage}`);
6808
6928
  })
6809
6929
  });
6810
6930
  }
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
- };
6931
+ async writeSummary(summary) {
6932
+ if (this.isTextStreaming) {
6933
+ this.queuedEvents.push({
6934
+ type: "data-summary",
6935
+ event: summary
6936
+ });
6937
+ return;
6818
6938
  }
6939
+ await this.flushQueuedOperations();
6940
+ await this.writeData("data-summary", summary);
6941
+ }
6942
+ async writeOperation(operation) {
6819
6943
  if (this.isTextStreaming) {
6820
- this.queuedOperations.push(operation);
6944
+ this.queuedEvents.push({
6945
+ type: "data-operation",
6946
+ event: operation
6947
+ });
6821
6948
  return;
6822
6949
  }
6823
6950
  await this.flushQueuedOperations();
@@ -6827,15 +6954,31 @@ ${errorMessage}`);
6827
6954
  * Flush all queued operations in order after text streaming completes
6828
6955
  */
6829
6956
  async flushQueuedOperations() {
6830
- if (this.queuedOperations.length === 0) {
6957
+ if (this.queuedEvents.length === 0) {
6831
6958
  return;
6832
6959
  }
6833
- const operationsToFlush = [...this.queuedOperations];
6834
- this.queuedOperations = [];
6835
- for (const operation of operationsToFlush) {
6836
- await this.writeData("data-operation", operation);
6960
+ const eventsToFlush = [...this.queuedEvents];
6961
+ this.queuedEvents = [];
6962
+ for (const event of eventsToFlush) {
6963
+ await this.writeData(event.type, event.event);
6837
6964
  }
6838
6965
  }
6966
+ /**
6967
+ * Write the final [DONE] message
6968
+ */
6969
+ async writeDone() {
6970
+ await this.stream.writeSSE({
6971
+ data: "[DONE]"
6972
+ });
6973
+ }
6974
+ /**
6975
+ * Complete the stream with finish reason and done message
6976
+ */
6977
+ async complete(finishReason = "stop") {
6978
+ await this.flushQueuedOperations();
6979
+ await this.writeCompletion(finishReason);
6980
+ await this.writeDone();
6981
+ }
6839
6982
  };
6840
6983
  function createSSEStreamHelper(stream2, requestId2, timestamp) {
6841
6984
  return new SSEStreamHelper(stream2, requestId2, timestamp);
@@ -6855,7 +6998,7 @@ var _VercelDataStreamHelper = class _VercelDataStreamHelper {
6855
6998
  __publicField(this, "isCompleted", false);
6856
6999
  // Stream queuing for proper event ordering
6857
7000
  __publicField(this, "isTextStreaming", false);
6858
- __publicField(this, "queuedOperations", []);
7001
+ __publicField(this, "queuedEvents", []);
6859
7002
  // Timing tracking for text sequences (text-end to text-start gap)
6860
7003
  __publicField(this, "lastTextEndTimestamp", 0);
6861
7004
  __publicField(this, "TEXT_GAP_THRESHOLD", 50);
@@ -6967,15 +7110,24 @@ var _VercelDataStreamHelper = class _VercelDataStreamHelper {
6967
7110
  data
6968
7111
  });
6969
7112
  }
6970
- async writeError(errorMessage) {
7113
+ async writeError(error) {
6971
7114
  if (this.isCompleted) {
6972
7115
  console.warn("Attempted to write error to completed stream");
6973
7116
  return;
6974
7117
  }
6975
- this.writer.write({
6976
- type: "error",
6977
- errorText: errorMessage
6978
- });
7118
+ if (typeof error === "string") {
7119
+ this.writer.write({
7120
+ type: "error",
7121
+ message: error,
7122
+ severity: "error",
7123
+ timestamp: Date.now()
7124
+ });
7125
+ } else {
7126
+ this.writer.write({
7127
+ ...error,
7128
+ type: "error"
7129
+ });
7130
+ }
6979
7131
  }
6980
7132
  async streamData(data) {
6981
7133
  await this.writeContent(JSON.stringify(data));
@@ -6987,20 +7139,6 @@ var _VercelDataStreamHelper = class _VercelDataStreamHelper {
6987
7139
  }
6988
7140
  this.writer.merge(stream2);
6989
7141
  }
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
7142
  /**
7005
7143
  * Clean up all memory allocations
7006
7144
  * Should be called when the stream helper is no longer needed
@@ -7014,7 +7152,7 @@ var _VercelDataStreamHelper = class _VercelDataStreamHelper {
7014
7152
  this.sentItems.clear();
7015
7153
  this.completedItems.clear();
7016
7154
  this.textId = null;
7017
- this.queuedOperations = [];
7155
+ this.queuedEvents = [];
7018
7156
  this.isTextStreaming = false;
7019
7157
  }
7020
7158
  /**
@@ -7080,7 +7218,9 @@ var _VercelDataStreamHelper = class _VercelDataStreamHelper {
7080
7218
  if (this.writer && !this.isCompleted) {
7081
7219
  this.writer.write({
7082
7220
  type: "error",
7083
- errorText: `Stream terminated: ${reason}`
7221
+ message: `Stream terminated: ${reason}`,
7222
+ severity: "error",
7223
+ timestamp: Date.now()
7084
7224
  });
7085
7225
  }
7086
7226
  } catch (e) {
@@ -7103,23 +7243,33 @@ var _VercelDataStreamHelper = class _VercelDataStreamHelper {
7103
7243
  isCompleted: this.isCompleted
7104
7244
  };
7105
7245
  }
7246
+ async writeSummary(summary) {
7247
+ if (this.isCompleted) {
7248
+ console.warn("Attempted to write summary to completed stream");
7249
+ return;
7250
+ }
7251
+ const now = Date.now();
7252
+ const gapFromLastTextEnd = this.lastTextEndTimestamp > 0 ? now - this.lastTextEndTimestamp : Number.MAX_SAFE_INTEGER;
7253
+ if (this.isTextStreaming || gapFromLastTextEnd < this.TEXT_GAP_THRESHOLD) {
7254
+ this.queuedEvents.push({ type: "data-summary", event: summary });
7255
+ return;
7256
+ }
7257
+ await this.flushQueuedOperations();
7258
+ await this.writer.write({
7259
+ id: "id" in summary ? summary.id : void 0,
7260
+ type: "data-summary",
7261
+ data: summary
7262
+ });
7263
+ }
7106
7264
  async writeOperation(operation) {
7107
7265
  if (this.isCompleted) {
7108
7266
  console.warn("Attempted to write operation to completed stream");
7109
7267
  return;
7110
7268
  }
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
7269
  const now = Date.now();
7120
7270
  const gapFromLastTextEnd = this.lastTextEndTimestamp > 0 ? now - this.lastTextEndTimestamp : Number.MAX_SAFE_INTEGER;
7121
7271
  if (this.isTextStreaming || gapFromLastTextEnd < this.TEXT_GAP_THRESHOLD) {
7122
- this.queuedOperations.push(operation);
7272
+ this.queuedEvents.push({ type: "data-operation", event: operation });
7123
7273
  return;
7124
7274
  }
7125
7275
  await this.flushQueuedOperations();
@@ -7133,19 +7283,33 @@ var _VercelDataStreamHelper = class _VercelDataStreamHelper {
7133
7283
  * Flush all queued operations in order after text streaming completes
7134
7284
  */
7135
7285
  async flushQueuedOperations() {
7136
- if (this.queuedOperations.length === 0) {
7286
+ if (this.queuedEvents.length === 0) {
7137
7287
  return;
7138
7288
  }
7139
- const operationsToFlush = [...this.queuedOperations];
7140
- this.queuedOperations = [];
7141
- for (const operation of operationsToFlush) {
7289
+ const eventsToFlush = [...this.queuedEvents];
7290
+ this.queuedEvents = [];
7291
+ for (const event of eventsToFlush) {
7142
7292
  this.writer.write({
7143
- id: "id" in operation ? operation.id : void 0,
7144
- type: "data-operation",
7145
- data: operation
7293
+ id: "id" in event.event ? event.event.id : void 0,
7294
+ type: event.type,
7295
+ data: event.event
7146
7296
  });
7147
7297
  }
7148
7298
  }
7299
+ async writeCompletion(_finishReason = "stop") {
7300
+ }
7301
+ async writeDone() {
7302
+ }
7303
+ /**
7304
+ * Complete the stream and clean up all memory
7305
+ * This is the primary cleanup point to prevent memory leaks between requests
7306
+ */
7307
+ async complete() {
7308
+ if (this.isCompleted) return;
7309
+ await this.flushQueuedOperations();
7310
+ this.isCompleted = true;
7311
+ this.cleanup();
7312
+ }
7149
7313
  };
7150
7314
  // Memory management - focused on connection completion cleanup
7151
7315
  __publicField(_VercelDataStreamHelper, "MAX_BUFFER_SIZE", 5 * 1024 * 1024);
@@ -7158,6 +7322,7 @@ var MCPStreamHelper = class {
7158
7322
  __publicField(this, "capturedText", "");
7159
7323
  __publicField(this, "capturedData", []);
7160
7324
  __publicField(this, "capturedOperations", []);
7325
+ __publicField(this, "capturedSummaries", []);
7161
7326
  __publicField(this, "hasError", false);
7162
7327
  __publicField(this, "errorMessage", "");
7163
7328
  __publicField(this, "sessionId");
@@ -7176,18 +7341,27 @@ var MCPStreamHelper = class {
7176
7341
  async streamData(data) {
7177
7342
  this.capturedData.push(data);
7178
7343
  }
7344
+ async streamSummary(summary) {
7345
+ this.capturedSummaries.push(summary);
7346
+ }
7347
+ async streamOperation(operation) {
7348
+ this.capturedOperations.push(operation);
7349
+ }
7179
7350
  async writeData(_type, data) {
7180
7351
  this.capturedData.push(data);
7181
7352
  }
7182
- async writeError(errorMessage) {
7183
- this.hasError = true;
7184
- this.errorMessage = errorMessage;
7185
- }
7186
- async complete() {
7353
+ async writeSummary(summary) {
7354
+ this.capturedSummaries.push(summary);
7187
7355
  }
7188
7356
  async writeOperation(operation) {
7189
7357
  this.capturedOperations.push(operation);
7190
7358
  }
7359
+ async writeError(error) {
7360
+ this.hasError = true;
7361
+ this.errorMessage = typeof error === "string" ? error : error.message;
7362
+ }
7363
+ async complete() {
7364
+ }
7191
7365
  /**
7192
7366
  * Get the captured response for MCP tool result
7193
7367
  */
@@ -7204,6 +7378,8 @@ var MCPStreamHelper = class {
7204
7378
  function createMCPStreamHelper() {
7205
7379
  return new MCPStreamHelper();
7206
7380
  }
7381
+
7382
+ // src/handlers/executionHandler.ts
7207
7383
  var logger19 = getLogger("ExecutionHandler");
7208
7384
  var ExecutionHandler = class {
7209
7385
  constructor() {
@@ -7232,7 +7408,7 @@ var ExecutionHandler = class {
7232
7408
  logger19.info({ sessionId: requestId2, graphId }, "Created GraphSession for message execution");
7233
7409
  let graphConfig = null;
7234
7410
  try {
7235
- graphConfig = await getFullGraph(dbClient_default)({ scopes: { tenantId, projectId }, graphId });
7411
+ graphConfig = await getFullGraph(dbClient_default)({ scopes: { tenantId, projectId, graphId } });
7236
7412
  if (graphConfig?.statusUpdates && graphConfig.statusUpdates.enabled !== false) {
7237
7413
  graphSessionManager.initializeStatusUpdates(
7238
7414
  requestId2,
@@ -7386,7 +7562,6 @@ var ExecutionHandler = class {
7386
7562
  if (errorCount >= this.MAX_ERRORS) {
7387
7563
  const errorMessage2 = `Maximum error limit (${this.MAX_ERRORS}) reached`;
7388
7564
  logger19.error({ maxErrors: this.MAX_ERRORS, errorCount }, errorMessage2);
7389
- await sseHelper.writeError(errorMessage2);
7390
7565
  await sseHelper.writeOperation(errorOp(errorMessage2, currentAgentId || "system"));
7391
7566
  if (task) {
7392
7567
  await updateTask(dbClient_default)({
@@ -7527,7 +7702,6 @@ var ExecutionHandler = class {
7527
7702
  if (errorCount >= this.MAX_ERRORS) {
7528
7703
  const errorMessage2 = `Maximum error limit (${this.MAX_ERRORS}) reached`;
7529
7704
  logger19.error({ maxErrors: this.MAX_ERRORS, errorCount }, errorMessage2);
7530
- await sseHelper.writeError(errorMessage2);
7531
7705
  await sseHelper.writeOperation(errorOp(errorMessage2, currentAgentId || "system"));
7532
7706
  if (task) {
7533
7707
  await updateTask(dbClient_default)({
@@ -7549,7 +7723,6 @@ var ExecutionHandler = class {
7549
7723
  }
7550
7724
  const errorMessage = `Maximum transfer limit (${maxTransfers}) reached without completion`;
7551
7725
  logger19.error({ maxTransfers, iterations }, errorMessage);
7552
- await sseHelper.writeError(errorMessage);
7553
7726
  await sseHelper.writeOperation(errorOp(errorMessage, currentAgentId || "system"));
7554
7727
  if (task) {
7555
7728
  await updateTask(dbClient_default)({
@@ -7570,8 +7743,7 @@ var ExecutionHandler = class {
7570
7743
  } catch (error) {
7571
7744
  logger19.error({ error }, "Error in execution handler");
7572
7745
  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"));
7746
+ await sseHelper.writeOperation(errorOp(`Execution error: ${errorMessage}`, currentAgentId || "system"));
7575
7747
  if (task) {
7576
7748
  await updateTask(dbClient_default)({
7577
7749
  taskId: task.id,
@@ -7733,8 +7905,7 @@ app2.openapi(chatCompletionsRoute, async (c) => {
7733
7905
  const body = c.get("requestBody") || {};
7734
7906
  const conversationId = body.conversationId || nanoid();
7735
7907
  const fullGraph = await getFullGraph(dbClient_default)({
7736
- scopes: { tenantId, projectId },
7737
- graphId
7908
+ scopes: { tenantId, projectId, graphId }
7738
7909
  });
7739
7910
  let agentGraph;
7740
7911
  let defaultAgentId;
@@ -7751,8 +7922,7 @@ app2.openapi(chatCompletionsRoute, async (c) => {
7751
7922
  defaultAgentId = fullGraph.defaultAgentId || firstAgentId;
7752
7923
  } else {
7753
7924
  agentGraph = await getAgentGraphWithDefaultAgent(dbClient_default)({
7754
- scopes: { tenantId, projectId },
7755
- graphId
7925
+ scopes: { tenantId, projectId, graphId }
7756
7926
  });
7757
7927
  if (!agentGraph) {
7758
7928
  return c.json({ error: "Agent graph not found" }, 404);
@@ -7781,7 +7951,7 @@ app2.openapi(chatCompletionsRoute, async (c) => {
7781
7951
  }
7782
7952
  const agentId = activeAgent?.activeAgentId || defaultAgentId;
7783
7953
  const agentInfo = await getAgentById(dbClient_default)({
7784
- scopes: { tenantId, projectId },
7954
+ scopes: { tenantId, projectId, graphId },
7785
7955
  agentId
7786
7956
  });
7787
7957
  if (!agentInfo) {
@@ -7789,18 +7959,19 @@ app2.openapi(chatCompletionsRoute, async (c) => {
7789
7959
  }
7790
7960
  const validatedContext = c.get("validatedContext") || body.requestContext || {};
7791
7961
  const credentialStores = c.get("credentialStores");
7792
- await handleContextResolution(
7962
+ await handleContextResolution({
7793
7963
  tenantId,
7794
7964
  projectId,
7795
- conversationId,
7796
7965
  graphId,
7797
- validatedContext,
7798
- dbClient_default,
7966
+ conversationId,
7967
+ requestContext: validatedContext,
7968
+ dbClient: dbClient_default,
7799
7969
  credentialStores
7800
- );
7970
+ });
7801
7971
  logger20.info(
7802
7972
  {
7803
7973
  tenantId,
7974
+ projectId,
7804
7975
  graphId,
7805
7976
  conversationId,
7806
7977
  defaultAgentId,
@@ -7859,8 +8030,8 @@ app2.openapi(chatCompletionsRoute, async (c) => {
7859
8030
  `Execution completed: ${result.success ? "success" : "failed"} after ${result.iterations} iterations`
7860
8031
  );
7861
8032
  if (!result.success) {
7862
- await sseHelper.writeError(
7863
- "Sorry, I was unable to process your request at this time. Please try again."
8033
+ await sseHelper.writeOperation(
8034
+ errorOp("Sorry, I was unable to process your request at this time. Please try again.", "system")
7864
8035
  );
7865
8036
  }
7866
8037
  await sseHelper.complete();
@@ -7940,6 +8111,7 @@ app3.openapi(chatDataStreamRoute, async (c) => {
7940
8111
  try {
7941
8112
  const executionContext = getRequestExecutionContext(c);
7942
8113
  const { tenantId, projectId, graphId } = executionContext;
8114
+ loggerFactory.getLogger("chatDataStream").debug({ tenantId, projectId, graphId }, "Extracted chatDataStream parameters");
7943
8115
  const body = c.get("requestBody") || {};
7944
8116
  const conversationId = body.conversationId || nanoid();
7945
8117
  const activeSpan = trace.getActiveSpan();
@@ -7952,14 +8124,16 @@ app3.openapi(chatDataStreamRoute, async (c) => {
7952
8124
  });
7953
8125
  }
7954
8126
  const agentGraph = await getAgentGraphWithDefaultAgent(dbClient_default)({
7955
- scopes: { tenantId, projectId },
7956
- graphId
8127
+ scopes: { tenantId, projectId, graphId }
7957
8128
  });
7958
8129
  if (!agentGraph) {
7959
8130
  return c.json({ error: "Agent graph not found" }, 404);
7960
8131
  }
7961
8132
  const defaultAgentId = agentGraph.defaultAgentId;
7962
8133
  const graphName = agentGraph.name;
8134
+ if (!defaultAgentId) {
8135
+ return c.json({ error: "Graph does not have a default agent configured" }, 400);
8136
+ }
7963
8137
  const activeAgent = await getActiveAgentForConversation(dbClient_default)({
7964
8138
  scopes: { tenantId, projectId },
7965
8139
  conversationId
@@ -7973,7 +8147,7 @@ app3.openapi(chatDataStreamRoute, async (c) => {
7973
8147
  }
7974
8148
  const agentId = activeAgent?.activeAgentId || defaultAgentId;
7975
8149
  const agentInfo = await getAgentById(dbClient_default)({
7976
- scopes: { tenantId, projectId },
8150
+ scopes: { tenantId, projectId, graphId },
7977
8151
  agentId
7978
8152
  });
7979
8153
  if (!agentInfo) {
@@ -7981,15 +8155,15 @@ app3.openapi(chatDataStreamRoute, async (c) => {
7981
8155
  }
7982
8156
  const validatedContext = c.get("validatedContext") || body.requestContext || {};
7983
8157
  const credentialStores = c.get("credentialStores");
7984
- await handleContextResolution(
8158
+ await handleContextResolution({
7985
8159
  tenantId,
7986
8160
  projectId,
7987
- conversationId,
7988
8161
  graphId,
7989
- validatedContext,
7990
- dbClient_default,
8162
+ conversationId,
8163
+ requestContext: validatedContext,
8164
+ dbClient: dbClient_default,
7991
8165
  credentialStores
7992
- );
8166
+ });
7993
8167
  const lastUserMessage = body.messages.filter((m) => m.role === "user").slice(-1)[0];
7994
8168
  const userText = typeof lastUserMessage?.content === "string" ? lastUserMessage.content : lastUserMessage?.parts?.map((p) => p.text).join("") || "";
7995
8169
  logger21.info({ userText, lastUserMessage }, "userText");
@@ -8031,11 +8205,11 @@ app3.openapi(chatDataStreamRoute, async (c) => {
8031
8205
  sseHelper: streamHelper
8032
8206
  });
8033
8207
  if (!result.success) {
8034
- await streamHelper.writeError("Unable to process request");
8208
+ await streamHelper.writeOperation(errorOp("Unable to process request", "system"));
8035
8209
  }
8036
8210
  } catch (err) {
8037
8211
  logger21.error({ err }, "Streaming error");
8038
- await streamHelper.writeError("Internal server error");
8212
+ await streamHelper.writeOperation(errorOp("Internal server error", "system"));
8039
8213
  } finally {
8040
8214
  if ("cleanup" in streamHelper && typeof streamHelper.cleanup === "function") {
8041
8215
  streamHelper.cleanup();
@@ -8258,8 +8432,7 @@ var getServer = async (requestContext, executionContext, conversationId, credent
8258
8432
  const { tenantId, projectId, graphId } = executionContext;
8259
8433
  setupTracing(conversationId, tenantId, graphId);
8260
8434
  const agentGraph = await getAgentGraphWithDefaultAgent(dbClient_default)({
8261
- scopes: { tenantId, projectId },
8262
- graphId
8435
+ scopes: { tenantId, projectId, graphId }
8263
8436
  });
8264
8437
  if (!agentGraph) {
8265
8438
  throw new Error("Agent graph not found");
@@ -8279,9 +8452,20 @@ var getServer = async (requestContext, executionContext, conversationId, credent
8279
8452
  },
8280
8453
  async ({ query }) => {
8281
8454
  try {
8455
+ if (!agentGraph.defaultAgentId) {
8456
+ return {
8457
+ content: [
8458
+ {
8459
+ type: "text",
8460
+ text: `Graph does not have a default agent configured`
8461
+ }
8462
+ ],
8463
+ isError: true
8464
+ };
8465
+ }
8282
8466
  const defaultAgentId = agentGraph.defaultAgentId;
8283
8467
  const agentInfo = await getAgentById(dbClient_default)({
8284
- scopes: { tenantId, projectId },
8468
+ scopes: { tenantId, projectId, graphId },
8285
8469
  agentId: defaultAgentId
8286
8470
  });
8287
8471
  if (!agentInfo) {
@@ -8295,18 +8479,19 @@ var getServer = async (requestContext, executionContext, conversationId, credent
8295
8479
  isError: true
8296
8480
  };
8297
8481
  }
8298
- const resolvedContext = await handleContextResolution(
8482
+ const resolvedContext = await handleContextResolution({
8299
8483
  tenantId,
8300
8484
  projectId,
8301
- conversationId,
8302
8485
  graphId,
8486
+ conversationId,
8303
8487
  requestContext,
8304
- dbClient_default,
8488
+ dbClient: dbClient_default,
8305
8489
  credentialStores
8306
- );
8490
+ });
8307
8491
  logger22.info(
8308
8492
  {
8309
8493
  tenantId,
8494
+ projectId,
8310
8495
  graphId,
8311
8496
  conversationId,
8312
8497
  hasContextConfig: !!agentGraph.contextConfigId,
@@ -8368,8 +8553,7 @@ var handleInitializationRequest = async (body, executionContext, validatedContex
8368
8553
  logger22.info({ body }, "Received initialization request");
8369
8554
  const sessionId = nanoid();
8370
8555
  const agentGraph = await getAgentGraphWithDefaultAgent(dbClient_default)({
8371
- scopes: { tenantId, projectId },
8372
- graphId
8556
+ scopes: { tenantId, projectId, graphId }
8373
8557
  });
8374
8558
  if (!agentGraph) {
8375
8559
  return c.json(
@@ -8381,6 +8565,16 @@ var handleInitializationRequest = async (body, executionContext, validatedContex
8381
8565
  { status: 404 }
8382
8566
  );
8383
8567
  }
8568
+ if (!agentGraph.defaultAgentId) {
8569
+ return c.json(
8570
+ {
8571
+ jsonrpc: "2.0",
8572
+ error: { code: -32001, message: "Graph does not have a default agent configured" },
8573
+ id: body.id || null
8574
+ },
8575
+ { status: 400 }
8576
+ );
8577
+ }
8384
8578
  const conversation = await createOrGetConversation(dbClient_default)({
8385
8579
  id: sessionId,
8386
8580
  tenantId,