@inkeep/agents-run-api 0.2.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,14 +1,8 @@
1
- import { env, __publicField, dbClient_default, getFormattedConversationHistory, createDefaultConversationHistoryConfig, saveA2AMessageResponse } from './chunk-7PHUFKNP.js';
2
- import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
3
- import { BaggageSpanProcessor, ALLOW_ALL_BAGGAGE_KEYS } from '@opentelemetry/baggage-span-processor';
4
- import { AsyncLocalStorageContextManager } from '@opentelemetry/context-async-hooks';
5
- import { CompositePropagator, W3CTraceContextPropagator, W3CBaggagePropagator } from '@opentelemetry/core';
6
- import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
7
- import { resourceFromAttributes } from '@opentelemetry/resources';
8
- import { NodeSDK } from '@opentelemetry/sdk-node';
9
- import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';
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';
1
+ import { defaultBatchProcessor } from './chunk-5RGAMXUL.js';
2
+ import { dbClient_default, getFormattedConversationHistory, env, createDefaultConversationHistoryConfig, saveA2AMessageResponse } from './chunk-HIGMADTA.js';
3
+ import { __publicField } from './chunk-PKBMQBKP.js';
4
+ import { getLogger, getTracer, HeadersScopeSchema, getRequestExecutionContext, createApiError, 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';
5
+ import { otel } from '@hono/otel';
12
6
  import { OpenAPIHono, createRoute, z as z$1 } from '@hono/zod-openapi';
13
7
  import { trace, propagation, context, SpanStatusCode } from '@opentelemetry/api';
14
8
  import { Hono } from 'hono';
@@ -22,56 +16,17 @@ import { streamSSE, stream } from 'hono/streaming';
22
16
  import { nanoid } from 'nanoid';
23
17
  import destr from 'destr';
24
18
  import traverse from 'traverse';
25
- import { createUIMessageStream, JsonToSseTransformStream, parsePartialJson, generateText, generateObject, tool, streamText } from 'ai';
19
+ import { createUIMessageStream, JsonToSseTransformStream, parsePartialJson, generateObject, tool, streamText, generateText, streamObject } from 'ai';
26
20
  import { createAnthropic, anthropic } from '@ai-sdk/anthropic';
21
+ import { createGateway, gateway } from '@ai-sdk/gateway';
27
22
  import { createGoogleGenerativeAI, google } from '@ai-sdk/google';
28
23
  import { createOpenAI, openai } from '@ai-sdk/openai';
24
+ import { createOpenRouter, openrouter } from '@openrouter/ai-sdk-provider';
29
25
  import jmespath from 'jmespath';
30
26
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
31
27
  import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
32
28
  import { z as z$2 } from 'zod/v3';
33
29
  import { toReqRes, toFetchResponse } from 'fetch-to-node';
34
- import { otel } from '@hono/otel';
35
-
36
- var maxExportBatchSize = env.OTEL_MAX_EXPORT_BATCH_SIZE ?? (env.ENVIRONMENT === "development" ? 1 : 512);
37
- var otlpExporter = new OTLPTraceExporter();
38
- var batchProcessor = new BatchSpanProcessor(otlpExporter, {
39
- maxExportBatchSize
40
- });
41
- var resource = resourceFromAttributes({
42
- [ATTR_SERVICE_NAME]: "inkeep-agents-run-api"
43
- });
44
- var sdk = new NodeSDK({
45
- resource,
46
- contextManager: new AsyncLocalStorageContextManager(),
47
- textMapPropagator: new CompositePropagator({
48
- propagators: [new W3CTraceContextPropagator(), new W3CBaggagePropagator()]
49
- }),
50
- spanProcessors: [new BaggageSpanProcessor(ALLOW_ALL_BAGGAGE_KEYS), batchProcessor],
51
- instrumentations: [
52
- getNodeAutoInstrumentations({
53
- "@opentelemetry/instrumentation-http": {
54
- enabled: true,
55
- requestHook: (span, request) => {
56
- const url = request?.url ?? request?.path;
57
- if (!url) return;
58
- const u = new URL(url, "http://localhost");
59
- span.updateName(`${request?.method || "UNKNOWN"} ${u.pathname}`);
60
- }
61
- },
62
- "@opentelemetry/instrumentation-undici": {
63
- requestHook: (span) => {
64
- const method = span.attributes?.["http.request.method"];
65
- const host = span.attributes?.["server.address"];
66
- const path = span.attributes?.["url.path"];
67
- if (method && path)
68
- span.updateName(host ? `${method} ${host}${path}` : `${method} ${path}`);
69
- }
70
- }
71
- })
72
- ]
73
- });
74
- sdk.start();
75
30
 
76
31
  // src/types/execution-context.ts
77
32
  function createExecutionContext(params) {
@@ -965,7 +920,7 @@ async function getRegisteredAgent(executionContext, credentialStoreRegistry) {
965
920
  throw new Error("Agent ID is required");
966
921
  }
967
922
  const dbAgent = await getAgentById(dbClient_default)({
968
- scopes: { tenantId, projectId },
923
+ scopes: { tenantId, projectId, graphId },
969
924
  agentId
970
925
  });
971
926
  if (!dbAgent) {
@@ -980,6 +935,38 @@ async function getRegisteredAgent(executionContext, credentialStoreRegistry) {
980
935
  apiKey
981
936
  });
982
937
  }
938
+ async function resolveModelConfig(graphId, agent) {
939
+ if (agent.models?.base?.model) {
940
+ return {
941
+ base: agent.models.base,
942
+ structuredOutput: agent.models.structuredOutput || agent.models.base,
943
+ summarizer: agent.models.summarizer || agent.models.base
944
+ };
945
+ }
946
+ const graph = await getAgentGraphById(dbClient_default)({
947
+ scopes: { tenantId: agent.tenantId, projectId: agent.projectId, graphId }
948
+ });
949
+ if (graph?.models?.base?.model) {
950
+ return {
951
+ base: graph.models.base,
952
+ structuredOutput: agent.models?.structuredOutput || graph.models.structuredOutput || graph.models.base,
953
+ summarizer: agent.models?.summarizer || graph.models.summarizer || graph.models.base
954
+ };
955
+ }
956
+ const project = await getProject(dbClient_default)({
957
+ scopes: { tenantId: agent.tenantId, projectId: agent.projectId }
958
+ });
959
+ if (project?.models?.base?.model) {
960
+ return {
961
+ base: project.models.base,
962
+ structuredOutput: agent.models?.structuredOutput || project.models.structuredOutput || project.models.base,
963
+ summarizer: agent.models?.summarizer || project.models.summarizer || project.models.base
964
+ };
965
+ }
966
+ throw new Error(
967
+ "Base model configuration is required. Please configure models at the project level."
968
+ );
969
+ }
983
970
  function agentInitializingOp(sessionId, graphId) {
984
971
  return {
985
972
  type: "agent_initializing",
@@ -998,24 +985,19 @@ function completionOp(agentId, iterations) {
998
985
  }
999
986
  };
1000
987
  }
1001
- function errorOp(error, agentId) {
988
+ function errorOp(message, agentId, severity = "error", code) {
1002
989
  return {
1003
990
  type: "error",
1004
- ctx: {
1005
- error,
1006
- agent: agentId
1007
- }
991
+ message,
992
+ agent: agentId,
993
+ severity,
994
+ code,
995
+ timestamp: Date.now()
1008
996
  };
1009
997
  }
1010
998
  function generateToolId() {
1011
999
  return `tool_${nanoid(8)}`;
1012
1000
  }
1013
- function statusUpdateOp(ctx) {
1014
- return {
1015
- type: "status_update",
1016
- ctx
1017
- };
1018
- }
1019
1001
  var logger4 = getLogger("DataComponentSchema");
1020
1002
  function jsonSchemaToZod(jsonSchema) {
1021
1003
  if (!jsonSchema || typeof jsonSchema !== "object") {
@@ -1100,6 +1082,17 @@ __publicField(_ArtifactReferenceSchema, "ARTIFACT_PROPS_SCHEMA", {
1100
1082
  required: ["artifact_id", "task_id"]
1101
1083
  });
1102
1084
  var ArtifactReferenceSchema = _ArtifactReferenceSchema;
1085
+
1086
+ // src/utils/default-status-schemas.ts
1087
+ var retrieveStatusSchema = {
1088
+ type: "retrieve",
1089
+ description: 'Use this when the system found or retrieved specific information from searches, queries, or lookups. ONLY report ACTUAL findings that appear explicitly in the tool results - never make up data, names, numbers, or details. The label must state the SPECIFIC discovery (e.g., "Found 3 authentication methods", "Database contains 500 records", "API supports JSON format") not the act of searching. Every detail must be traceable to actual tool output. NEVER invent placeholder names, fictional data, or information not present in the activities.'
1090
+ };
1091
+ var actionStatusSchema = {
1092
+ type: "action",
1093
+ description: 'Use this when the system executed a tool or performed an operation that modified state or had side effects. ONLY report ACTUAL tool executions and their results as they appear in the tool outputs - never make up tool names, parameters, or outcomes. The label must describe what specific action was performed and its concrete result based on actual tool execution data. DO NOT make up examples like "Ran test suite with X passes" unless a test suite was ACTUALLY run and reported X passes. DO NOT say "Executed database query" unless a database query was ACTUALLY executed. Only report what literally happened. NEVER invent tool names, execution results, or details not explicitly present in the tool execution activities. If a tool failed, report the actual failure, not imagined success.'
1094
+ };
1095
+ var defaultStatusSchemas = [retrieveStatusSchema, actionStatusSchema];
1103
1096
  var logger5 = getLogger("ModelFactory");
1104
1097
  var _ModelFactory = class _ModelFactory {
1105
1098
  /**
@@ -1113,6 +1106,18 @@ var _ModelFactory = class _ModelFactory {
1113
1106
  return createOpenAI(config);
1114
1107
  case "google":
1115
1108
  return createGoogleGenerativeAI(config);
1109
+ case "openrouter":
1110
+ return {
1111
+ ...createOpenRouter(config),
1112
+ textEmbeddingModel: () => {
1113
+ throw new Error("OpenRouter does not support text embeddings");
1114
+ },
1115
+ imageModel: () => {
1116
+ throw new Error("OpenRouter does not support image generation");
1117
+ }
1118
+ };
1119
+ case "gateway":
1120
+ return createGateway(config);
1116
1121
  default:
1117
1122
  throw new Error(`Unsupported provider: ${provider}`);
1118
1123
  }
@@ -1145,6 +1150,9 @@ var _ModelFactory = class _ModelFactory {
1145
1150
  );
1146
1151
  }
1147
1152
  const modelSettings = config;
1153
+ if (!modelSettings.model) {
1154
+ throw new Error("Model configuration is required");
1155
+ }
1148
1156
  const modelString = modelSettings.model.trim();
1149
1157
  const { provider, modelName } = _ModelFactory.parseModelString(modelString);
1150
1158
  logger5.debug(
@@ -1169,26 +1177,29 @@ var _ModelFactory = class _ModelFactory {
1169
1177
  return openai(modelName);
1170
1178
  case "google":
1171
1179
  return google(modelName);
1180
+ case "openrouter":
1181
+ return openrouter(modelName);
1182
+ case "gateway":
1183
+ return gateway(modelName);
1172
1184
  default:
1173
- throw new Error(`Unsupported provider: ${provider}`);
1185
+ throw new Error(
1186
+ `Unsupported provider: ${provider}. Supported providers are: ${_ModelFactory.BUILT_IN_PROVIDERS.join(", ")}. To access other models, use OpenRouter (openrouter/model-id) or Vercel AI Gateway (gateway/model-id).`
1187
+ );
1174
1188
  }
1175
1189
  }
1176
1190
  /**
1177
1191
  * Parse model string to extract provider and model name
1178
1192
  * Examples: "anthropic/claude-sonnet-4" -> { provider: "anthropic", modelName: "claude-sonnet-4" }
1193
+ * "openrouter/anthropic/claude-sonnet-4" -> { provider: "openrouter", modelName: "anthropic/claude-sonnet-4" }
1179
1194
  * "claude-sonnet-4" -> { provider: "anthropic", modelName: "claude-sonnet-4" } (default to anthropic)
1180
1195
  */
1181
1196
  static parseModelString(modelString) {
1182
1197
  if (modelString.includes("/")) {
1183
1198
  const [provider, ...modelParts] = modelString.split("/");
1184
1199
  const normalizedProvider = provider.toLowerCase();
1185
- if (!_ModelFactory.SUPPORTED_PROVIDERS.includes(normalizedProvider)) {
1186
- logger5.error(
1187
- { provider: normalizedProvider, modelName: modelParts.join("/") },
1188
- "Unsupported provider detected, falling back to anthropic"
1189
- );
1200
+ if (!_ModelFactory.BUILT_IN_PROVIDERS.includes(normalizedProvider)) {
1190
1201
  throw new Error(
1191
- `Unsupported provider: ${normalizedProvider}. Please provide a model in the format of provider/model-name.`
1202
+ `Unsupported provider: ${normalizedProvider}. Supported providers are: ${_ModelFactory.BUILT_IN_PROVIDERS.join(", ")}. To access other models, use OpenRouter (openrouter/model-id) or Vercel AI Gateway (gateway/model-id).`
1192
1203
  );
1193
1204
  }
1194
1205
  return {
@@ -1197,9 +1208,7 @@ var _ModelFactory = class _ModelFactory {
1197
1208
  // In case model name has slashes
1198
1209
  };
1199
1210
  }
1200
- throw new Error(
1201
- `Invalid model provided: ${modelString}. Please provide a model in the format of provider/model-name.`
1202
- );
1211
+ throw new Error(`No provider specified in model string: ${modelString}`);
1203
1212
  }
1204
1213
  /**
1205
1214
  * Get generation parameters from provider options
@@ -1263,11 +1272,16 @@ var _ModelFactory = class _ModelFactory {
1263
1272
  }
1264
1273
  };
1265
1274
  /**
1266
- * Supported providers for security validation
1275
+ * Built-in providers that have special handling
1267
1276
  */
1268
- __publicField(_ModelFactory, "SUPPORTED_PROVIDERS", ["anthropic", "openai", "google"]);
1277
+ __publicField(_ModelFactory, "BUILT_IN_PROVIDERS", [
1278
+ "anthropic",
1279
+ "openai",
1280
+ "google",
1281
+ "openrouter",
1282
+ "gateway"
1283
+ ]);
1269
1284
  var ModelFactory = _ModelFactory;
1270
- var tracer = getTracer("agents-run-api");
1271
1285
 
1272
1286
  // src/utils/stream-registry.ts
1273
1287
  var streamHelperRegistry = /* @__PURE__ */ new Map();
@@ -1283,6 +1297,7 @@ function getStreamHelper(requestId2) {
1283
1297
  function unregisterStreamHelper(requestId2) {
1284
1298
  streamHelperRegistry.delete(requestId2);
1285
1299
  }
1300
+ var tracer = getTracer("agents-run-api");
1286
1301
 
1287
1302
  // src/utils/graph-session.ts
1288
1303
  var logger6 = getLogger("GraphSession");
@@ -1591,7 +1606,6 @@ var GraphSession = class {
1591
1606
  }
1592
1607
  this.isGeneratingUpdate = true;
1593
1608
  const statusUpdateState = this.statusUpdateState;
1594
- const graphId = this.graphId;
1595
1609
  try {
1596
1610
  const streamHelper = getStreamHelper(this.sessionId);
1597
1611
  if (!streamHelper) {
@@ -1604,81 +1618,49 @@ var GraphSession = class {
1604
1618
  }
1605
1619
  const now = Date.now();
1606
1620
  const elapsedTime = now - statusUpdateState.startTime;
1607
- let operation;
1608
- if (statusUpdateState.config.statusComponents && statusUpdateState.config.statusComponents.length > 0) {
1609
- const result = await this.generateStructuredStatusUpdate(
1610
- this.events.slice(statusUpdateState.lastEventCount),
1611
- elapsedTime,
1612
- statusUpdateState.config.statusComponents,
1613
- statusUpdateState.summarizerModel,
1614
- this.previousSummaries
1615
- );
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) {
1619
- logger6.warn(
1620
- {
1621
- sessionId: this.sessionId,
1622
- operation: op
1623
- },
1624
- "Skipping empty or invalid structured operation"
1625
- );
1626
- continue;
1627
- }
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
- }
1637
- };
1638
- await streamHelper.writeOperation(operationToSend);
1639
- }
1640
- const summaryTexts = result.operations.map(
1641
- (op) => JSON.stringify({ type: op.type, data: op.data })
1642
- );
1643
- this.previousSummaries.push(...summaryTexts);
1644
- if (this.statusUpdateState) {
1645
- this.statusUpdateState.lastUpdateTime = now;
1646
- this.statusUpdateState.lastEventCount = this.events.length;
1621
+ const statusComponents = statusUpdateState.config.statusComponents && statusUpdateState.config.statusComponents.length > 0 ? statusUpdateState.config.statusComponents : defaultStatusSchemas;
1622
+ const result = await this.generateStructuredStatusUpdate(
1623
+ this.events.slice(statusUpdateState.lastEventCount),
1624
+ elapsedTime,
1625
+ statusComponents,
1626
+ statusUpdateState.summarizerModel,
1627
+ this.previousSummaries
1628
+ );
1629
+ if (result.summaries && result.summaries.length > 0) {
1630
+ for (const summary of result.summaries) {
1631
+ if (!summary || !summary.type || !summary.data || !summary.data.label || Object.keys(summary.data).length === 0) {
1632
+ logger6.warn(
1633
+ {
1634
+ sessionId: this.sessionId,
1635
+ summary
1636
+ },
1637
+ "Skipping empty or invalid structured operation"
1638
+ );
1639
+ continue;
1647
1640
  }
1648
- return;
1641
+ const summaryToSend = {
1642
+ type: summary.data.type || summary.type,
1643
+ // Preserve the actual custom type from LLM
1644
+ label: summary.data.label,
1645
+ details: Object.fromEntries(
1646
+ Object.entries(summary.data).filter(([key]) => !["label", "type"].includes(key))
1647
+ )
1648
+ };
1649
+ await streamHelper.writeSummary(summaryToSend);
1649
1650
  }
1650
- } else {
1651
- const summary = await this.generateProgressSummary(
1652
- this.events.slice(statusUpdateState.lastEventCount),
1653
- elapsedTime,
1654
- statusUpdateState.summarizerModel,
1655
- this.previousSummaries
1651
+ const summaryTexts = result.summaries.map(
1652
+ (summary) => JSON.stringify({ type: summary.type, data: summary.data })
1656
1653
  );
1657
- 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
- });
1654
+ this.previousSummaries.push(...summaryTexts);
1655
+ if (this.statusUpdateState) {
1656
+ this.statusUpdateState.lastUpdateTime = now;
1657
+ this.statusUpdateState.lastEventCount = this.events.length;
1658
+ }
1659
+ return;
1667
1660
  }
1668
1661
  if (this.previousSummaries.length > 3) {
1669
1662
  this.previousSummaries.shift();
1670
1663
  }
1671
- if (!operation || !operation.type || !operation.ctx) {
1672
- logger6.warn(
1673
- {
1674
- sessionId: this.sessionId,
1675
- operation
1676
- },
1677
- "Skipping empty or invalid status update operation"
1678
- );
1679
- return;
1680
- }
1681
- await streamHelper.writeOperation(operation);
1682
1664
  if (this.statusUpdateState) {
1683
1665
  this.statusUpdateState.lastUpdateTime = now;
1684
1666
  this.statusUpdateState.lastEventCount = this.events.length;
@@ -1762,103 +1744,6 @@ var GraphSession = class {
1762
1744
  this.statusUpdateState.updateLock = false;
1763
1745
  }
1764
1746
  }
1765
- /**
1766
- * Generate user-focused progress summary hiding internal operations
1767
- */
1768
- async generateProgressSummary(newEvents, elapsedTime, summarizerModel, previousSummaries = []) {
1769
- return tracer.startActiveSpan(
1770
- "graph_session.generate_progress_summary",
1771
- {
1772
- attributes: {
1773
- "graph_session.id": this.sessionId,
1774
- "events.count": newEvents.length,
1775
- "elapsed_time.seconds": Math.round(elapsedTime / 1e3),
1776
- "llm.model": summarizerModel?.model,
1777
- "previous_summaries.count": previousSummaries.length
1778
- }
1779
- },
1780
- async (span) => {
1781
- try {
1782
- const userVisibleActivities = this.extractUserVisibleActivities(newEvents);
1783
- let conversationContext = "";
1784
- if (this.tenantId && this.projectId) {
1785
- try {
1786
- const conversationHistory = await getFormattedConversationHistory({
1787
- tenantId: this.tenantId,
1788
- projectId: this.projectId,
1789
- conversationId: this.sessionId,
1790
- options: {
1791
- limit: 10,
1792
- // Get recent conversation context
1793
- maxOutputTokens: 2e3
1794
- },
1795
- filters: {}
1796
- });
1797
- conversationContext = conversationHistory.trim() ? `
1798
- User's Question/Context:
1799
- ${conversationHistory}
1800
- ` : "";
1801
- } catch (error) {
1802
- logger6.warn(
1803
- { sessionId: this.sessionId, error },
1804
- "Failed to fetch conversation history for status update"
1805
- );
1806
- }
1807
- }
1808
- const previousSummaryContext = previousSummaries.length > 0 ? `
1809
- Previous updates provided to user:
1810
- ${previousSummaries.map((s, i) => `${i + 1}. ${s}`).join("\n")}
1811
- ` : "";
1812
- const basePrompt = `Generate a meaningful status update that tells the user what specific information or result was just found/achieved.${conversationContext}${previousSummaries.length > 0 ? `
1813
- ${previousSummaryContext}` : ""}
1814
-
1815
- Activities:
1816
- ${userVisibleActivities.join("\n") || "No New Activities"}
1817
-
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").
1819
-
1820
- ${this.statusUpdateState?.config.prompt?.trim() || ""}`;
1821
- const prompt = basePrompt;
1822
- let modelToUse = summarizerModel;
1823
- if (!summarizerModel?.model?.trim()) {
1824
- if (!this.statusUpdateState?.baseModel?.model?.trim()) {
1825
- throw new Error(
1826
- "Either summarizer or base model is required for progress summary generation. Please configure models at the project level."
1827
- );
1828
- }
1829
- modelToUse = this.statusUpdateState.baseModel;
1830
- }
1831
- const model = ModelFactory.createModel(modelToUse);
1832
- const { text } = await generateText({
1833
- model,
1834
- prompt,
1835
- experimental_telemetry: {
1836
- isEnabled: true,
1837
- functionId: `status_update_${this.sessionId}`,
1838
- recordInputs: true,
1839
- recordOutputs: true,
1840
- metadata: {
1841
- operation: "progress_summary_generation",
1842
- sessionId: this.sessionId
1843
- }
1844
- }
1845
- });
1846
- span.setAttributes({
1847
- "summary.length": text.trim().length,
1848
- "user_activities.count": userVisibleActivities.length
1849
- });
1850
- span.setStatus({ code: SpanStatusCode.OK });
1851
- return text.trim();
1852
- } catch (error) {
1853
- setSpanWithError(span, error);
1854
- logger6.error({ error }, "Failed to generate summary, using fallback");
1855
- return this.generateFallbackSummary(newEvents, elapsedTime);
1856
- } finally {
1857
- span.end();
1858
- }
1859
- }
1860
- );
1861
- }
1862
1747
  /**
1863
1748
  * Generate structured status update using configured data components
1864
1749
  */
@@ -1937,15 +1822,45 @@ Rules:
1937
1822
  - Fill in data for relevant components only
1938
1823
  - Use 'no_relevant_updates' if nothing substantially new to report. DO NOT WRITE LABELS OR USE OTHER COMPONENTS IF YOU USE THIS COMPONENT.
1939
1824
  - 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")
1825
+ - Labels MUST be short 3-7 word phrases with ACTUAL information discovered. NEVER MAKE UP SOMETHING WITHOUT BACKING IT UP WITH ACTUAL INFORMATION.
1826
+ - 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
1827
  - DO NOT use action words like "Searching", "Processing", "Analyzing" - state what was FOUND
1942
1828
  - Include specific details, numbers, requirements, or insights discovered
1943
- - 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
1945
- - Present all operations as seamless actions by a single system
1946
- - 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
1948
- - 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.
1829
+ - Examples: "Admin permissions required", "Three OAuth steps found", "Token expires daily"
1830
+
1831
+ CRITICAL - HIDE ALL INTERNAL SYSTEM OPERATIONS:
1832
+ - You are ONE unified AI system presenting results to the user
1833
+ - ABSOLUTELY FORBIDDEN WORDS/PHRASES: "transfer", "transferring", "delegation", "delegating", "delegate", "agent", "routing", "route", "artifact", "saving artifact", "stored artifact", "artifact saved", "continuing", "passing to", "handing off", "switching to"
1834
+ - NEVER reveal internal architecture: No mentions of different agents, components, systems, or modules working together
1835
+ - NEVER mention artifact operations: Users don't need to know about data being saved, stored, or organized internally
1836
+ - NEVER describe handoffs or transitions: Present everything as one seamless operation
1837
+ - If you see "transfer", "delegation_sent", "delegation_returned", or "artifact_saved" events - IGNORE THEM or translate to user-facing information only
1838
+ - Focus ONLY on actual discoveries, findings, and results that matter to the user
1839
+
1840
+ - Bad examples:
1841
+ * "Transferring to search agent"
1842
+ * "Delegating research task"
1843
+ * "Routing to QA specialist"
1844
+ * "Artifact saved successfully"
1845
+ * "Storing results for later"
1846
+ * "Passing request to tool handler"
1847
+ * "Continuing with analysis"
1848
+ * "Handing off to processor"
1849
+ - Good examples:
1850
+ * "Slack bot needs admin privileges"
1851
+ * "Found 3-step OAuth flow required"
1852
+ * "Channel limit is 500 per workspace"
1853
+ * Use no_relevant_updates if nothing new to report
1854
+
1855
+ CRITICAL ANTI-HALLUCINATION RULES:
1856
+ - NEVER MAKE UP SOMETHING WITHOUT BACKING IT UP WITH ACTUAL INFORMATION. EVERY SINGLE UPDATE MUST BE BACKED UP WITH ACTUAL INFORMATION.
1857
+ - DO NOT MAKE UP PEOPLE, NAMES, PLACES, THINGS, ORGANIZATIONS, OR INFORMATION. IT IS OBVIOUS WHEN A PERSON/ENTITY DOES NOT EXIST.
1858
+ - Only report facts that are EXPLICITLY mentioned in the activities or tool results
1859
+ - If you don't have concrete information about something, DO NOT mention it
1860
+ - Never invent names like "John Doe", "Alice", "Bob", or any other placeholder names
1861
+ - Never create fictional companies, products, or services
1862
+ - If a tool returned no results or an error, DO NOT pretend it found something
1863
+ - Every detail in your status update must be traceable back to the actual activities provided
1949
1864
 
1950
1865
  REMEMBER YOU CAN ONLY USE 'no_relevant_updates' ALONE! IT CANNOT BE CONCATENATED WITH OTHER STATUS UPDATES!
1951
1866
 
@@ -1960,6 +1875,9 @@ ${this.statusUpdateState?.config.prompt?.trim() || ""}`;
1960
1875
  }
1961
1876
  modelToUse = this.statusUpdateState.baseModel;
1962
1877
  }
1878
+ if (!modelToUse) {
1879
+ throw new Error("No model configuration available");
1880
+ }
1963
1881
  const model = ModelFactory.createModel(modelToUse);
1964
1882
  const { object } = await generateObject({
1965
1883
  model,
@@ -1977,29 +1895,29 @@ ${this.statusUpdateState?.config.prompt?.trim() || ""}`;
1977
1895
  }
1978
1896
  });
1979
1897
  const result = object;
1980
- const operations = [];
1898
+ const summaries = [];
1981
1899
  for (const [componentId, data] of Object.entries(result)) {
1982
1900
  if (componentId === "no_relevant_updates") {
1983
1901
  continue;
1984
1902
  }
1985
1903
  if (data && typeof data === "object" && Object.keys(data).length > 0) {
1986
- operations.push({
1904
+ summaries.push({
1987
1905
  type: componentId,
1988
1906
  data
1989
1907
  });
1990
1908
  }
1991
1909
  }
1992
1910
  span.setAttributes({
1993
- "operations.count": operations.length,
1911
+ "summaries.count": summaries.length,
1994
1912
  "user_activities.count": userVisibleActivities.length,
1995
1913
  "result_keys.count": Object.keys(result).length
1996
1914
  });
1997
1915
  span.setStatus({ code: SpanStatusCode.OK });
1998
- return { operations };
1916
+ return { summaries };
1999
1917
  } catch (error) {
2000
1918
  setSpanWithError(span, error);
2001
1919
  logger6.error({ error }, "Failed to generate structured update, using fallback");
2002
- return { operations: [] };
1920
+ return { summaries: [] };
2003
1921
  } finally {
2004
1922
  span.end();
2005
1923
  }
@@ -2015,7 +1933,7 @@ ${this.statusUpdateState?.config.prompt?.trim() || ""}`;
2015
1933
  }
2016
1934
  return z.object({
2017
1935
  label: z.string().describe(
2018
- 'A short 3-5 word phrase, that is a descriptive label for the update component. This Label must be EXTREMELY unique to represent the UNIQUE update we are providing. The ACTUAL finding or result, not the action. What specific information was discovered? (e.g., "Slack requires OAuth 2.0 setup", "Found 5 integration methods", "API rate limit is 100/minute"). Include the actual detail or insight, not just that you searched or processed.'
1936
+ 'A short 3-5 word phrase, that is a descriptive label for the update component. This Label must be EXTREMELY unique to represent the UNIQUE update we are providing. The ACTUAL finding or result, not the action. What specific information was discovered? (e.g., "Slack requires OAuth 2.0 setup", "Found 5 integration methods", "API rate limit is 100/minute"). Include the actual detail or insight, not just that you searched or processed. CRITICAL: Only use facts explicitly found in the activities - NEVER invent names, people, organizations, or details that are not present in the actual tool results.'
2019
1937
  )
2020
1938
  });
2021
1939
  }
@@ -2025,7 +1943,7 @@ ${this.statusUpdateState?.config.prompt?.trim() || ""}`;
2025
1943
  buildZodSchemaFromJson(jsonSchema) {
2026
1944
  const properties = {};
2027
1945
  properties["label"] = z.string().describe(
2028
- 'A short 3-5 word phrase, that is a descriptive label for the update component. This Label must be EXTREMELY unique to represent the UNIQUE update we are providing. The SPECIFIC finding, result, or insight discovered (e.g., "Slack bot needs workspace admin role", "Found ingestion requires 3 steps", "Channel history limited to 10k messages"). State the ACTUAL information found, not that you searched. What did you LEARN or DISCOVER? What specific detail is now known?'
1946
+ 'A short 3-5 word phrase, that is a descriptive label for the update component. This Label must be EXTREMELY unique to represent the UNIQUE update we are providing. The SPECIFIC finding, result, or insight discovered (e.g., "Slack bot needs workspace admin role", "Found ingestion requires 3 steps", "Channel history limited to 10k messages"). State the ACTUAL information found, not that you searched. What did you LEARN or DISCOVER? What specific detail is now known? CRITICAL: Only use facts explicitly found in the activities - NEVER invent names, people, organizations, or details that are not present in the actual tool results.'
2029
1947
  );
2030
1948
  for (const [key, value] of Object.entries(jsonSchema.properties)) {
2031
1949
  let zodType;
@@ -2102,41 +2020,12 @@ ${this.statusUpdateState?.config.prompt?.trim() || ""}`;
2102
2020
  );
2103
2021
  break;
2104
2022
  }
2105
- case "transfer": {
2106
- const data = event.data;
2107
- activities.push(
2108
- `\u{1F504} **Continuing**: ${data.reason || "Processing request"}
2109
- ${data.context ? `Context: ${JSON.stringify(data.context, null, 2)}` : ""}`
2110
- );
2111
- break;
2112
- }
2113
- case "delegation_sent": {
2114
- const data = event.data;
2115
- activities.push(
2116
- `\u{1F4E4} **Processing**: ${data.taskDescription}
2117
- ${data.context ? `Context: ${JSON.stringify(data.context, null, 2)}` : ""}`
2118
- );
2119
- break;
2120
- }
2121
- case "delegation_returned": {
2122
- const data = event.data;
2123
- activities.push(
2124
- `\u{1F4E5} **Completed subtask**
2125
- Result: ${JSON.stringify(data.result, null, 2)}`
2126
- );
2127
- break;
2128
- }
2129
- case "artifact_saved": {
2130
- const data = event.data;
2131
- activities.push(
2132
- `\u{1F4BE} **Artifact Saved**: ${data.artifactType}
2133
- ID: ${data.artifactId}
2134
- Task: ${data.taskId}
2135
- ${data.summaryData ? `Summary: ${data.summaryData}` : ""}
2136
- ${data.fullData ? `Full Data: ${data.fullData}` : ""}`
2137
- );
2023
+ // INTERNAL OPERATIONS - DO NOT EXPOSE TO STATUS UPDATES
2024
+ case "transfer":
2025
+ case "delegation_sent":
2026
+ case "delegation_returned":
2027
+ case "artifact_saved":
2138
2028
  break;
2139
- }
2140
2029
  case "agent_reasoning": {
2141
2030
  const data = event.data;
2142
2031
  activities.push(
@@ -2161,21 +2050,6 @@ ${this.statusUpdateState?.config.prompt?.trim() || ""}`;
2161
2050
  }
2162
2051
  return activities;
2163
2052
  }
2164
- /**
2165
- * Generate fallback summary when LLM fails
2166
- */
2167
- generateFallbackSummary(events, elapsedTime) {
2168
- const timeStr = Math.round(elapsedTime / 1e3);
2169
- const toolCalls = events.filter((e) => e.eventType === "tool_execution").length;
2170
- const artifacts = events.filter((e) => e.eventType === "artifact_saved").length;
2171
- if (artifacts > 0) {
2172
- return `Generated ${artifacts} result${artifacts > 1 ? "s" : ""} so far (${timeStr}s elapsed)`;
2173
- } else if (toolCalls > 0) {
2174
- return `Used ${toolCalls} tool${toolCalls > 1 ? "s" : ""} to gather information (${timeStr}s elapsed)`;
2175
- } else {
2176
- return `Processing your request... (${timeStr}s elapsed)`;
2177
- }
2178
- }
2179
2053
  /**
2180
2054
  * Process a single artifact to generate name and description using conversation context
2181
2055
  */
@@ -2212,7 +2086,7 @@ ${this.statusUpdateState?.config.prompt?.trim() || ""}`;
2212
2086
  );
2213
2087
  }
2214
2088
  span.setAttributes({ "validation.passed": true });
2215
- const { getFormattedConversationHistory: getFormattedConversationHistory2 } = await import('./conversations-WDOIWO7W.js');
2089
+ const { getFormattedConversationHistory: getFormattedConversationHistory2 } = await import('./conversations-OVETKXSP.js');
2216
2090
  const conversationHistory = await getFormattedConversationHistory2({
2217
2091
  tenantId: artifactData.tenantId,
2218
2092
  projectId: artifactData.projectId,
@@ -2250,6 +2124,9 @@ Make it specific and relevant.`;
2250
2124
  }
2251
2125
  modelToUse = this.statusUpdateState.baseModel;
2252
2126
  }
2127
+ if (!modelToUse) {
2128
+ throw new Error("No model configuration available");
2129
+ }
2253
2130
  const model = ModelFactory.createModel(modelToUse);
2254
2131
  const schema = z.object({
2255
2132
  name: z.string().max(50).describe("Concise, descriptive name for the artifact"),
@@ -2528,6 +2405,7 @@ var _ArtifactParser = class _ArtifactParser {
2528
2405
  }
2529
2406
  for (let i = matches.length - 1; i >= 0; i--) {
2530
2407
  const match = matches[i];
2408
+ if (match.index === void 0) continue;
2531
2409
  const startIdx = match.index;
2532
2410
  const textAfterMatch = text.slice(startIdx);
2533
2411
  if (!textAfterMatch.includes("/>")) {
@@ -2577,7 +2455,8 @@ var _ArtifactParser = class _ArtifactParser {
2577
2455
  taskId,
2578
2456
  name: artifact.name || "Processing...",
2579
2457
  description: artifact.description || "Name and description being generated...",
2580
- artifactType: artifact.metadata?.artifactType,
2458
+ type: artifact.metadata?.artifactType || artifact.artifactType,
2459
+ // Map artifactType to type for consistency
2581
2460
  artifactSummary: artifact.parts?.[0]?.data?.summary || {}
2582
2461
  };
2583
2462
  }
@@ -2594,10 +2473,11 @@ var _ArtifactParser = class _ArtifactParser {
2594
2473
  let lastIndex = 0;
2595
2474
  for (const match of matches) {
2596
2475
  const [fullMatch, artifactId, taskId] = match;
2476
+ if (match.index === void 0) continue;
2597
2477
  const matchStart = match.index;
2598
2478
  if (matchStart > lastIndex) {
2599
2479
  const textBefore = text.slice(lastIndex, matchStart);
2600
- if (textBefore.trim()) {
2480
+ if (textBefore) {
2601
2481
  parts.push({ kind: "text", text: textBefore });
2602
2482
  }
2603
2483
  }
@@ -2609,7 +2489,7 @@ var _ArtifactParser = class _ArtifactParser {
2609
2489
  }
2610
2490
  if (lastIndex < text.length) {
2611
2491
  const remainingText = text.slice(lastIndex);
2612
- if (remainingText.trim()) {
2492
+ if (remainingText) {
2613
2493
  parts.push({ kind: "text", text: remainingText });
2614
2494
  }
2615
2495
  }
@@ -2719,8 +2599,9 @@ __publicField(_ArtifactParser, "INCOMPLETE_ARTIFACT_REGEX", /<(a(r(t(i(f(a(c(t(:
2719
2599
  var ArtifactParser = _ArtifactParser;
2720
2600
 
2721
2601
  // src/utils/incremental-stream-parser.ts
2722
- var logger8 = getLogger("IncrementalStreamParser");
2723
- var IncrementalStreamParser = class {
2602
+ getLogger("IncrementalStreamParser");
2603
+ var _IncrementalStreamParser = class _IncrementalStreamParser {
2604
+ // Max number of streamed component IDs to track
2724
2605
  constructor(streamHelper, tenantId, contextId) {
2725
2606
  __publicField(this, "buffer", "");
2726
2607
  __publicField(this, "pendingTextBuffer", "");
@@ -2730,6 +2611,9 @@ var IncrementalStreamParser = class {
2730
2611
  __publicField(this, "collectedParts", []);
2731
2612
  __publicField(this, "contextId");
2732
2613
  __publicField(this, "lastChunkWasToolResult", false);
2614
+ __publicField(this, "componentAccumulator", {});
2615
+ __publicField(this, "lastStreamedComponents", /* @__PURE__ */ new Map());
2616
+ __publicField(this, "componentSnapshots", /* @__PURE__ */ new Map());
2733
2617
  this.streamHelper = streamHelper;
2734
2618
  this.contextId = contextId;
2735
2619
  this.artifactParser = new ArtifactParser(tenantId);
@@ -2744,7 +2628,7 @@ var IncrementalStreamParser = class {
2744
2628
  * Process a new text chunk for text streaming (handles artifact markers)
2745
2629
  */
2746
2630
  async processTextChunk(chunk) {
2747
- if (this.lastChunkWasToolResult && this.buffer === "" && chunk.trim()) {
2631
+ if (this.lastChunkWasToolResult && this.buffer === "" && chunk) {
2748
2632
  chunk = "\n\n" + chunk;
2749
2633
  this.lastChunkWasToolResult = false;
2750
2634
  }
@@ -2756,129 +2640,179 @@ var IncrementalStreamParser = class {
2756
2640
  this.buffer = parseResult.remainingBuffer;
2757
2641
  }
2758
2642
  /**
2759
- * Process a new object chunk for object streaming (handles JSON objects with artifact references)
2643
+ * Process object deltas directly from Vercel AI SDK's fullStream
2644
+ * Accumulates components and streams them when they're stable (unchanged between deltas)
2760
2645
  */
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);
2646
+ async processObjectDelta(delta) {
2647
+ if (!delta || typeof delta !== "object") {
2648
+ return;
2766
2649
  }
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);
2650
+ this.componentAccumulator = this.deepMerge(this.componentAccumulator, delta);
2651
+ if (this.componentAccumulator.dataComponents && Array.isArray(this.componentAccumulator.dataComponents)) {
2652
+ const components = this.componentAccumulator.dataComponents;
2653
+ const currentComponentIds = new Set(components.filter((c) => c?.id).map((c) => c.id));
2654
+ for (const [componentId, snapshot] of this.componentSnapshots.entries()) {
2655
+ if (!currentComponentIds.has(componentId) && !this.lastStreamedComponents.has(componentId)) {
2656
+ try {
2657
+ const component = JSON.parse(snapshot);
2658
+ if (this.isComponentComplete(component)) {
2659
+ await this.streamComponent(component);
2660
+ }
2661
+ } catch (e) {
2662
+ }
2787
2663
  }
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;
2664
+ }
2665
+ for (let i = 0; i < components.length; i++) {
2666
+ const component = components[i];
2667
+ if (!component?.id) continue;
2668
+ const componentKey = component.id;
2669
+ const hasBeenStreamed = this.lastStreamedComponents.has(componentKey);
2670
+ if (hasBeenStreamed) continue;
2671
+ const currentSnapshot = JSON.stringify(component);
2672
+ const previousSnapshot = this.componentSnapshots.get(componentKey);
2673
+ this.componentSnapshots.set(componentKey, currentSnapshot);
2674
+ if (this.componentSnapshots.size > _IncrementalStreamParser.MAX_SNAPSHOT_SIZE) {
2675
+ const firstKey = this.componentSnapshots.keys().next().value;
2676
+ if (firstKey) {
2677
+ this.componentSnapshots.delete(firstKey);
2798
2678
  }
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
- }
2679
+ }
2680
+ if (component.name === "Text" && component.props?.text) {
2681
+ const previousTextContent = previousSnapshot ? JSON.parse(previousSnapshot).props?.text || "" : "";
2682
+ const currentTextContent = component.props.text || "";
2683
+ if (currentTextContent.length > previousTextContent.length) {
2684
+ const newText = currentTextContent.slice(previousTextContent.length);
2685
+ if (!this.hasStartedRole) {
2686
+ await this.streamHelper.writeRole("assistant");
2687
+ this.hasStartedRole = true;
2838
2688
  }
2689
+ await this.streamHelper.streamText(newText, 50);
2690
+ this.collectedParts.push({
2691
+ kind: "text",
2692
+ text: newText
2693
+ });
2839
2694
  }
2840
- if (componentBuffer.includes('"dataComponents"') && componentBuffer.includes("[")) ;
2695
+ continue;
2841
2696
  }
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);
2697
+ if (this.isComponentComplete(component)) {
2698
+ const currentPropsSnapshot = JSON.stringify(component.props);
2699
+ const previousPropsSnapshot = previousSnapshot ? JSON.stringify(JSON.parse(previousSnapshot).props) : null;
2700
+ if (previousPropsSnapshot === currentPropsSnapshot) {
2701
+ await this.streamComponent(component);
2847
2702
  }
2848
2703
  }
2849
- break;
2850
2704
  }
2851
2705
  }
2852
- logger8.debug({ componentsStreamed }, "Finished streaming components");
2853
2706
  }
2854
2707
  /**
2855
- * Legacy method for backward compatibility - defaults to text processing
2708
+ * Stream a component and mark it as streamed
2709
+ * Note: Text components are handled separately with incremental streaming
2856
2710
  */
2857
- async processChunk(chunk) {
2858
- await this.processTextChunk(chunk);
2711
+ async streamComponent(component) {
2712
+ const parts = await this.artifactParser.parseObject({
2713
+ dataComponents: [component]
2714
+ });
2715
+ for (const part of parts) {
2716
+ await this.streamPart(part);
2717
+ }
2718
+ this.lastStreamedComponents.set(component.id, true);
2719
+ if (this.lastStreamedComponents.size > _IncrementalStreamParser.MAX_STREAMED_SIZE) {
2720
+ const firstKey = this.lastStreamedComponents.keys().next().value;
2721
+ if (firstKey) {
2722
+ this.lastStreamedComponents.delete(firstKey);
2723
+ }
2724
+ }
2725
+ this.componentSnapshots.delete(component.id);
2859
2726
  }
2860
2727
  /**
2861
- * Process any remaining buffer content at the end of stream
2728
+ * Check if a component has the basic structure required for streaming
2729
+ * Requires id, name, and props object with content
2862
2730
  */
2863
- async finalize() {
2864
- if (this.buffer.trim()) {
2865
- const part = {
2866
- kind: "text",
2867
- text: this.buffer.trim()
2868
- };
2869
- await this.streamPart(part);
2731
+ isComponentComplete(component) {
2732
+ if (!component || !component.id || !component.name) {
2733
+ return false;
2870
2734
  }
2871
- if (this.pendingTextBuffer.trim()) {
2872
- const cleanedText = this.pendingTextBuffer.replace(/<\/?artifact:ref(?:\s[^>]*)?>\/?>/g, "").replace(/<\/?artifact(?:\s[^>]*)?>\/?>/g, "").replace(/<\/(?:\w+:)?artifact>/g, "").trim();
2873
- if (cleanedText) {
2874
- this.collectedParts.push({
2875
- kind: "text",
2735
+ if (!component.props || typeof component.props !== "object") {
2736
+ return false;
2737
+ }
2738
+ const isArtifact = component.name === "Artifact" || component.props.artifact_id && component.props.task_id;
2739
+ if (isArtifact) {
2740
+ return Boolean(component.props.artifact_id && component.props.task_id);
2741
+ }
2742
+ return true;
2743
+ }
2744
+ /**
2745
+ * Deep merge helper for object deltas
2746
+ */
2747
+ deepMerge(target, source) {
2748
+ if (!source) return target;
2749
+ if (!target) return source;
2750
+ const result = { ...target };
2751
+ for (const key in source) {
2752
+ if (source[key] && typeof source[key] === "object" && !Array.isArray(source[key])) {
2753
+ result[key] = this.deepMerge(target[key], source[key]);
2754
+ } else {
2755
+ result[key] = source[key];
2756
+ }
2757
+ }
2758
+ return result;
2759
+ }
2760
+ /**
2761
+ * Legacy method for backward compatibility - defaults to text processing
2762
+ */
2763
+ async processChunk(chunk) {
2764
+ await this.processTextChunk(chunk);
2765
+ }
2766
+ /**
2767
+ * Process any remaining buffer content at the end of stream
2768
+ */
2769
+ async finalize() {
2770
+ if (this.componentAccumulator.dataComponents && Array.isArray(this.componentAccumulator.dataComponents)) {
2771
+ const components = this.componentAccumulator.dataComponents;
2772
+ for (let i = 0; i < components.length; i++) {
2773
+ const component = components[i];
2774
+ if (!component?.id) continue;
2775
+ const componentKey = component.id;
2776
+ const hasBeenStreamed = this.lastStreamedComponents.has(componentKey);
2777
+ if (!hasBeenStreamed && this.isComponentComplete(component) && component.name !== "Text") {
2778
+ const parts = await this.artifactParser.parseObject({
2779
+ dataComponents: [component]
2780
+ });
2781
+ for (const part of parts) {
2782
+ await this.streamPart(part);
2783
+ }
2784
+ this.lastStreamedComponents.set(componentKey, true);
2785
+ if (this.lastStreamedComponents.size > _IncrementalStreamParser.MAX_STREAMED_SIZE) {
2786
+ const firstKey = this.lastStreamedComponents.keys().next().value;
2787
+ if (firstKey) {
2788
+ this.lastStreamedComponents.delete(firstKey);
2789
+ }
2790
+ }
2791
+ this.componentSnapshots.delete(componentKey);
2792
+ }
2793
+ }
2794
+ }
2795
+ if (this.buffer) {
2796
+ const part = {
2797
+ kind: "text",
2798
+ text: this.buffer
2799
+ };
2800
+ await this.streamPart(part);
2801
+ }
2802
+ if (this.pendingTextBuffer) {
2803
+ const cleanedText = this.pendingTextBuffer.replace(/<\/?artifact:ref(?:\s[^>]*)?>\/?>/g, "").replace(/<\/?artifact(?:\s[^>]*)?>\/?>/g, "").replace(/<\/artifact:ref>/g, "").replace(/<\/(?:\w+:)?artifact>/g, "");
2804
+ if (cleanedText) {
2805
+ this.collectedParts.push({
2806
+ kind: "text",
2876
2807
  text: cleanedText
2877
2808
  });
2878
2809
  await this.streamHelper.streamText(cleanedText, 50);
2879
2810
  }
2880
2811
  this.pendingTextBuffer = "";
2881
2812
  }
2813
+ this.componentSnapshots.clear();
2814
+ this.lastStreamedComponents.clear();
2815
+ this.componentAccumulator = {};
2882
2816
  }
2883
2817
  /**
2884
2818
  * Get all collected parts for building the final response
@@ -2925,30 +2859,6 @@ var IncrementalStreamParser = class {
2925
2859
  remainingBuffer: ""
2926
2860
  };
2927
2861
  }
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
2862
  /**
2953
2863
  * Check if text might be the start of an artifact marker
2954
2864
  */
@@ -2968,16 +2878,16 @@ var IncrementalStreamParser = class {
2968
2878
  if (part.kind === "text" && part.text) {
2969
2879
  this.pendingTextBuffer += part.text;
2970
2880
  if (!this.artifactParser.hasIncompleteArtifact(this.pendingTextBuffer)) {
2971
- const cleanedText = this.pendingTextBuffer.replace(/<\/?artifact:ref(?:\s[^>]*)?>\/?>/g, "").replace(/<\/?artifact(?:\s[^>]*)?>\/?>/g, "").replace(/<\/(?:\w+:)?artifact>/g, "");
2972
- if (cleanedText.trim()) {
2881
+ const cleanedText = this.pendingTextBuffer.replace(/<\/?artifact:ref(?:\s[^>]*)?>\/?>/g, "").replace(/<\/?artifact(?:\s[^>]*)?>\/?>/g, "").replace(/<\/artifact:ref>/g, "").replace(/<\/(?:\w+:)?artifact>/g, "");
2882
+ if (cleanedText) {
2973
2883
  await this.streamHelper.streamText(cleanedText, 50);
2974
2884
  }
2975
2885
  this.pendingTextBuffer = "";
2976
2886
  }
2977
2887
  } else if (part.kind === "data" && part.data) {
2978
2888
  if (this.pendingTextBuffer) {
2979
- const cleanedText = this.pendingTextBuffer.replace(/<\/?artifact:ref(?:\s[^>]*)?>\/?>/g, "").replace(/<\/?artifact(?:\s[^>]*)?>\/?>/g, "").replace(/<\/(?:\w+:)?artifact>/g, "");
2980
- if (cleanedText.trim()) {
2889
+ const cleanedText = this.pendingTextBuffer.replace(/<\/?artifact:ref(?:\s[^>]*)?>\/?>/g, "").replace(/<\/?artifact(?:\s[^>]*)?>\/?>/g, "").replace(/<\/artifact:ref>/g, "").replace(/<\/(?:\w+:)?artifact>/g, "");
2890
+ if (cleanedText) {
2981
2891
  await this.streamHelper.streamText(cleanedText, 50);
2982
2892
  }
2983
2893
  this.pendingTextBuffer = "";
@@ -2991,6 +2901,11 @@ var IncrementalStreamParser = class {
2991
2901
  }
2992
2902
  }
2993
2903
  };
2904
+ // Memory management constants
2905
+ __publicField(_IncrementalStreamParser, "MAX_SNAPSHOT_SIZE", 100);
2906
+ // Max number of snapshots to keep
2907
+ __publicField(_IncrementalStreamParser, "MAX_STREAMED_SIZE", 1e3);
2908
+ var IncrementalStreamParser = _IncrementalStreamParser;
2994
2909
 
2995
2910
  // src/utils/response-formatter.ts
2996
2911
  var logger9 = getLogger("ResponseFormatter");
@@ -4377,7 +4292,8 @@ function createDelegateToAgentTool({
4377
4292
  const externalAgent = await getExternalAgent(dbClient_default)({
4378
4293
  scopes: {
4379
4294
  tenantId,
4380
- projectId
4295
+ projectId,
4296
+ graphId
4381
4297
  },
4382
4298
  agentId: delegateConfig.config.id
4383
4299
  });
@@ -4979,6 +4895,23 @@ var Agent = class {
4979
4895
  __publicField(this, "credentialStoreRegistry");
4980
4896
  this.artifactComponents = config.artifactComponents || [];
4981
4897
  let processedDataComponents = config.dataComponents || [];
4898
+ if (processedDataComponents.length > 0) {
4899
+ processedDataComponents.push({
4900
+ id: "text-content",
4901
+ name: "Text",
4902
+ description: "Natural conversational text for the user - write naturally without mentioning technical details. Avoid redundancy and repetition with data components.",
4903
+ props: {
4904
+ type: "object",
4905
+ properties: {
4906
+ text: {
4907
+ type: "string",
4908
+ 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."
4909
+ }
4910
+ },
4911
+ required: ["text"]
4912
+ }
4913
+ });
4914
+ }
4982
4915
  if (this.artifactComponents.length > 0 && config.dataComponents && config.dataComponents.length > 0) {
4983
4916
  processedDataComponents = [
4984
4917
  ArtifactReferenceSchema.getDataComponent(config.tenantId, config.projectId),
@@ -5249,8 +5182,12 @@ var Agent = class {
5249
5182
  async getMcpTool(tool4) {
5250
5183
  const credentialReferenceId = tool4.credentialReferenceId;
5251
5184
  const toolsForAgent = await getToolsForAgent(dbClient_default)({
5252
- scopes: { tenantId: this.config.tenantId, projectId: this.config.projectId },
5253
- agentId: this.config.id
5185
+ scopes: {
5186
+ tenantId: this.config.tenantId,
5187
+ projectId: this.config.projectId,
5188
+ graphId: this.config.graphId,
5189
+ agentId: this.config.id
5190
+ }
5254
5191
  });
5255
5192
  const selectedTools = toolsForAgent.data.find((t) => t.toolId === tool4.id)?.selectedTools || void 0;
5256
5193
  let serverConfig;
@@ -5397,9 +5334,9 @@ var Agent = class {
5397
5334
  const graphDefinition = await getFullGraphDefinition(dbClient_default)({
5398
5335
  scopes: {
5399
5336
  tenantId: this.config.tenantId,
5400
- projectId: this.config.projectId
5401
- },
5402
- graphId: this.config.graphId
5337
+ projectId: this.config.projectId,
5338
+ graphId: this.config.graphId
5339
+ }
5403
5340
  });
5404
5341
  return graphDefinition?.graphPrompt || void 0;
5405
5342
  } catch (error) {
@@ -5421,14 +5358,16 @@ var Agent = class {
5421
5358
  const graphDefinition = await getFullGraphDefinition(dbClient_default)({
5422
5359
  scopes: {
5423
5360
  tenantId: this.config.tenantId,
5424
- projectId: this.config.projectId
5425
- },
5426
- graphId: this.config.graphId
5361
+ projectId: this.config.projectId,
5362
+ graphId: this.config.graphId
5363
+ }
5427
5364
  });
5428
5365
  if (!graphDefinition) {
5429
5366
  return false;
5430
5367
  }
5431
- return !!(graphDefinition.artifactComponents && Object.keys(graphDefinition.artifactComponents).length > 0);
5368
+ return Object.values(graphDefinition.agents).some(
5369
+ (agent) => "artifactComponents" in agent && agent.artifactComponents && agent.artifactComponents.length > 0
5370
+ );
5432
5371
  } catch (error) {
5433
5372
  logger15.warn(
5434
5373
  {
@@ -5456,7 +5395,8 @@ Key requirements:
5456
5395
  - Mix artifact references throughout your dataComponents array
5457
5396
  - Each artifact reference must use EXACT IDs from tool outputs
5458
5397
  - Reference artifacts that directly support the adjacent information
5459
- - Follow the pattern: Data \u2192 Supporting Artifact \u2192 Next Data \u2192 Next Artifact`;
5398
+ - Follow the pattern: Data \u2192 Supporting Artifact \u2192 Next Data \u2192 Next Artifact
5399
+ - 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
5400
  }
5461
5401
  if (hasDataComponents && !hasArtifactComponents) {
5462
5402
  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 +5404,8 @@ Key requirements:
5464
5404
  Key requirements:
5465
5405
  - Use the exact component structure and property names
5466
5406
  - Fill in all relevant data from the research
5467
- - Ensure data is organized logically and completely`;
5407
+ - Ensure data is organized logically and completely
5408
+ - 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
5409
  }
5469
5410
  if (!hasDataComponents && hasArtifactComponents) {
5470
5411
  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 +5415,7 @@ Key requirements:
5474
5415
  - Reference artifacts that support your response
5475
5416
  - Never make up or modify artifact IDs`;
5476
5417
  }
5477
- return `Generate the final response based on the research above.`;
5418
+ return `Generate the final response based on the research above. Write naturally as if having a conversation.`;
5478
5419
  }
5479
5420
  async buildSystemPrompt(runtimeContext, excludeDataComponents = false) {
5480
5421
  const conversationId = runtimeContext?.metadata?.conversationId || runtimeContext?.contextId;
@@ -5625,9 +5566,9 @@ Key requirements:
5625
5566
  return await graphHasArtifactComponents(dbClient_default)({
5626
5567
  scopes: {
5627
5568
  tenantId: this.config.tenantId,
5628
- projectId: this.config.projectId
5629
- },
5630
- graphId: this.config.graphId
5569
+ projectId: this.config.projectId,
5570
+ graphId: this.config.graphId
5571
+ }
5631
5572
  });
5632
5573
  } catch (error) {
5633
5574
  logger15.error(
@@ -5973,35 +5914,94 @@ ${output}`;
5973
5914
  this.getStructuredOutputModel()
5974
5915
  );
5975
5916
  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"
5917
+ const shouldStreamPhase2 = this.getStreamingHelper();
5918
+ if (shouldStreamPhase2) {
5919
+ const streamResult = streamObject({
5920
+ ...structuredModelSettings,
5921
+ messages: [
5922
+ { role: "user", content: userMessage },
5923
+ ...reasoningFlow,
5924
+ {
5925
+ role: "user",
5926
+ content: await this.buildPhase2SystemPrompt()
5927
+ }
5928
+ ],
5929
+ schema: z.object({
5930
+ dataComponents: z.array(dataComponentsSchema)
5931
+ }),
5932
+ experimental_telemetry: {
5933
+ isEnabled: true,
5934
+ functionId: this.config.id,
5935
+ recordInputs: true,
5936
+ recordOutputs: true,
5937
+ metadata: {
5938
+ phase: "structured_generation"
5939
+ }
5940
+ },
5941
+ abortSignal: AbortSignal.timeout(phase2TimeoutMs)
5942
+ });
5943
+ const streamHelper = this.getStreamingHelper();
5944
+ if (!streamHelper) {
5945
+ throw new Error("Stream helper is unexpectedly undefined in streaming context");
5946
+ }
5947
+ const parser = new IncrementalStreamParser(
5948
+ streamHelper,
5949
+ this.config.tenantId,
5950
+ contextId
5951
+ );
5952
+ for await (const delta of streamResult.partialObjectStream) {
5953
+ if (delta) {
5954
+ await parser.processObjectDelta(delta);
5996
5955
  }
5997
- },
5998
- abortSignal: AbortSignal.timeout(phase2TimeoutMs)
5999
- });
6000
- response = {
6001
- ...response,
6002
- object: structuredResponse.object
6003
- };
6004
- textResponse = JSON.stringify(structuredResponse.object, null, 2);
5956
+ }
5957
+ await parser.finalize();
5958
+ const structuredResponse = await streamResult;
5959
+ const collectedParts = parser.getCollectedParts();
5960
+ if (collectedParts.length > 0) {
5961
+ response.formattedContent = {
5962
+ parts: collectedParts.map((part) => ({
5963
+ kind: part.kind,
5964
+ ...part.kind === "text" && { text: part.text },
5965
+ ...part.kind === "data" && { data: part.data }
5966
+ }))
5967
+ };
5968
+ }
5969
+ response = {
5970
+ ...response,
5971
+ object: structuredResponse.object
5972
+ };
5973
+ textResponse = JSON.stringify(structuredResponse.object, null, 2);
5974
+ } else {
5975
+ const structuredResponse = await generateObject({
5976
+ ...structuredModelSettings,
5977
+ messages: [
5978
+ { role: "user", content: userMessage },
5979
+ ...reasoningFlow,
5980
+ {
5981
+ role: "user",
5982
+ content: await this.buildPhase2SystemPrompt()
5983
+ }
5984
+ ],
5985
+ schema: z.object({
5986
+ dataComponents: z.array(dataComponentsSchema)
5987
+ }),
5988
+ experimental_telemetry: {
5989
+ isEnabled: true,
5990
+ functionId: this.config.id,
5991
+ recordInputs: true,
5992
+ recordOutputs: true,
5993
+ metadata: {
5994
+ phase: "structured_generation"
5995
+ }
5996
+ },
5997
+ abortSignal: AbortSignal.timeout(phase2TimeoutMs)
5998
+ });
5999
+ response = {
6000
+ ...response,
6001
+ object: structuredResponse.object
6002
+ };
6003
+ textResponse = JSON.stringify(structuredResponse.object, null, 2);
6004
+ }
6005
6005
  } else {
6006
6006
  textResponse = response.text || "";
6007
6007
  }
@@ -6046,39 +6046,6 @@ ${output}`;
6046
6046
  });
6047
6047
  }
6048
6048
  };
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
6049
 
6083
6050
  // src/agents/generateTaskHandler.ts
6084
6051
  function parseEmbeddedJson(data) {
@@ -6114,31 +6081,34 @@ var createTaskHandler = (config, credentialStoreRegistry) => {
6114
6081
  getRelatedAgentsForGraph(dbClient_default)({
6115
6082
  scopes: {
6116
6083
  tenantId: config.tenantId,
6117
- projectId: config.projectId
6084
+ projectId: config.projectId,
6085
+ graphId: config.graphId
6118
6086
  },
6119
- graphId: config.graphId,
6120
6087
  agentId: config.agentId
6121
6088
  }),
6122
6089
  getToolsForAgent(dbClient_default)({
6123
6090
  scopes: {
6124
6091
  tenantId: config.tenantId,
6125
- projectId: config.projectId
6126
- },
6127
- agentId: config.agentId
6092
+ projectId: config.projectId,
6093
+ graphId: config.graphId,
6094
+ agentId: config.agentId
6095
+ }
6128
6096
  }),
6129
6097
  getDataComponentsForAgent(dbClient_default)({
6130
6098
  scopes: {
6131
6099
  tenantId: config.tenantId,
6132
- projectId: config.projectId
6133
- },
6134
- agentId: config.agentId
6100
+ projectId: config.projectId,
6101
+ graphId: config.graphId,
6102
+ agentId: config.agentId
6103
+ }
6135
6104
  }),
6136
6105
  getArtifactComponentsForAgent(dbClient_default)({
6137
6106
  scopes: {
6138
6107
  tenantId: config.tenantId,
6139
- projectId: config.projectId
6140
- },
6141
- agentId: config.agentId
6108
+ projectId: config.projectId,
6109
+ graphId: config.graphId,
6110
+ agentId: config.agentId
6111
+ }
6142
6112
  })
6143
6113
  ]);
6144
6114
  logger16.info({ toolsForAgent, internalRelations, externalRelations }, "agent stuff");
@@ -6146,13 +6116,16 @@ var createTaskHandler = (config, credentialStoreRegistry) => {
6146
6116
  internalRelations.map(async (relation) => {
6147
6117
  try {
6148
6118
  const relatedAgent = await getAgentById(dbClient_default)({
6149
- scopes: { tenantId: config.tenantId, projectId: config.projectId },
6119
+ scopes: {
6120
+ tenantId: config.tenantId,
6121
+ projectId: config.projectId,
6122
+ graphId: config.graphId
6123
+ },
6150
6124
  agentId: relation.id
6151
6125
  });
6152
6126
  if (relatedAgent) {
6153
6127
  const relatedAgentRelations = await getRelatedAgentsForGraph(dbClient_default)({
6154
- scopes: { tenantId: config.tenantId, projectId: config.projectId },
6155
- graphId: config.graphId,
6128
+ scopes: { tenantId: config.tenantId, projectId: config.projectId, graphId: config.graphId },
6156
6129
  agentId: relation.id
6157
6130
  });
6158
6131
  const enhancedDescription = generateDescriptionWithTransfers(
@@ -6375,16 +6348,17 @@ var createTaskHandlerConfig = async (params) => {
6375
6348
  const agent = await getAgentById(dbClient_default)({
6376
6349
  scopes: {
6377
6350
  tenantId: params.tenantId,
6378
- projectId: params.projectId
6351
+ projectId: params.projectId,
6352
+ graphId: params.graphId
6379
6353
  },
6380
6354
  agentId: params.agentId
6381
6355
  });
6382
- const agentGraph = await getAgentGraph(dbClient_default)({
6356
+ const agentGraph = await getAgentGraphById(dbClient_default)({
6383
6357
  scopes: {
6384
6358
  tenantId: params.tenantId,
6385
- projectId: params.projectId
6386
- },
6387
- graphId: params.graphId
6359
+ projectId: params.projectId,
6360
+ graphId: params.graphId
6361
+ }
6388
6362
  });
6389
6363
  if (!agent) {
6390
6364
  throw new Error(`Agent not found: ${params.agentId}`);
@@ -6423,10 +6397,14 @@ async function hydrateGraph({
6423
6397
  apiKey
6424
6398
  }) {
6425
6399
  try {
6400
+ if (!dbGraph.defaultAgentId) {
6401
+ throw new Error(`Graph ${dbGraph.id} does not have a default agent configured`);
6402
+ }
6426
6403
  const defaultAgent = await getAgentById(dbClient_default)({
6427
6404
  scopes: {
6428
6405
  tenantId: dbGraph.tenantId,
6429
- projectId: dbGraph.projectId
6406
+ projectId: dbGraph.projectId,
6407
+ graphId: dbGraph.id
6430
6408
  },
6431
6409
  agentId: dbGraph.defaultAgentId
6432
6410
  });
@@ -6481,7 +6459,7 @@ async function hydrateGraph({
6481
6459
  }
6482
6460
  async function getRegisteredGraph(executionContext) {
6483
6461
  const { tenantId, projectId, graphId, baseUrl, apiKey } = executionContext;
6484
- const dbGraph = await getAgentGraph(dbClient_default)({ scopes: { tenantId, projectId }, graphId });
6462
+ const dbGraph = await getAgentGraphById(dbClient_default)({ scopes: { tenantId, projectId, graphId } });
6485
6463
  if (!dbGraph) {
6486
6464
  return null;
6487
6465
  }
@@ -6539,6 +6517,7 @@ app.openapi(
6539
6517
  );
6540
6518
  const executionContext = getRequestExecutionContext(c);
6541
6519
  const { tenantId, projectId, graphId, agentId } = executionContext;
6520
+ console.dir("executionContext", executionContext);
6542
6521
  if (agentId) {
6543
6522
  logger17.info(
6544
6523
  {
@@ -6554,7 +6533,10 @@ app.openapi(
6554
6533
  const agent = await getRegisteredAgent(executionContext, credentialStores);
6555
6534
  logger17.info({ agent }, "agent registered: well-known agent.json");
6556
6535
  if (!agent) {
6557
- return c.json({ error: "Agent not found" }, 404);
6536
+ throw createApiError({
6537
+ code: "not_found",
6538
+ message: "Agent not found"
6539
+ });
6558
6540
  }
6559
6541
  return c.json(agent.agentCard);
6560
6542
  } else {
@@ -6569,7 +6551,10 @@ app.openapi(
6569
6551
  );
6570
6552
  const graph = await getRegisteredGraph(executionContext);
6571
6553
  if (!graph) {
6572
- return c.json({ error: "Graph not found" }, 404);
6554
+ throw createApiError({
6555
+ code: "not_found",
6556
+ message: "Graph not found"
6557
+ });
6573
6558
  }
6574
6559
  return c.json(graph.agentCard);
6575
6560
  }
@@ -6626,8 +6611,7 @@ app.post("/a2a", async (c) => {
6626
6611
  "graph-level a2a endpoint"
6627
6612
  );
6628
6613
  const graph = await getAgentGraphWithDefaultAgent(dbClient_default)({
6629
- scopes: { tenantId, projectId },
6630
- graphId
6614
+ scopes: { tenantId, projectId, graphId }
6631
6615
  });
6632
6616
  if (!graph) {
6633
6617
  return c.json(
@@ -6639,6 +6623,16 @@ app.post("/a2a", async (c) => {
6639
6623
  404
6640
6624
  );
6641
6625
  }
6626
+ if (!graph.defaultAgentId) {
6627
+ return c.json(
6628
+ {
6629
+ jsonrpc: "2.0",
6630
+ error: { code: -32004, message: "Graph does not have a default agent configured" },
6631
+ id: null
6632
+ },
6633
+ 400
6634
+ );
6635
+ }
6642
6636
  executionContext.agentId = graph.defaultAgentId;
6643
6637
  const credentialStores = c.get("credentialStores");
6644
6638
  const defaultAgent = await getRegisteredAgent(executionContext, credentialStores);
@@ -6683,7 +6677,7 @@ var SSEStreamHelper = class {
6683
6677
  this.timestamp = timestamp;
6684
6678
  // Stream queuing for proper event ordering
6685
6679
  __publicField(this, "isTextStreaming", false);
6686
- __publicField(this, "queuedOperations", []);
6680
+ __publicField(this, "queuedEvents", []);
6687
6681
  }
6688
6682
  /**
6689
6683
  * Write the initial role message
@@ -6748,9 +6742,10 @@ var SSEStreamHelper = class {
6748
6742
  await this.writeContent(JSON.stringify(data));
6749
6743
  }
6750
6744
  /**
6751
- * Write error message
6745
+ * Write error message or error event
6752
6746
  */
6753
- async writeError(errorMessage) {
6747
+ async writeError(error) {
6748
+ const errorMessage = typeof error === "string" ? error : error.message;
6754
6749
  await this.writeContent(`
6755
6750
 
6756
6751
  ${errorMessage}`);
@@ -6774,22 +6769,6 @@ ${errorMessage}`);
6774
6769
  })
6775
6770
  });
6776
6771
  }
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
6772
  async writeData(type, data) {
6794
6773
  await this.stream.writeSSE({
6795
6774
  data: JSON.stringify({
@@ -6808,16 +6787,23 @@ ${errorMessage}`);
6808
6787
  })
6809
6788
  });
6810
6789
  }
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
- };
6790
+ async writeSummary(summary) {
6791
+ if (this.isTextStreaming) {
6792
+ this.queuedEvents.push({
6793
+ type: "data-summary",
6794
+ event: summary
6795
+ });
6796
+ return;
6818
6797
  }
6798
+ await this.flushQueuedOperations();
6799
+ await this.writeData("data-summary", summary);
6800
+ }
6801
+ async writeOperation(operation) {
6819
6802
  if (this.isTextStreaming) {
6820
- this.queuedOperations.push(operation);
6803
+ this.queuedEvents.push({
6804
+ type: "data-operation",
6805
+ event: operation
6806
+ });
6821
6807
  return;
6822
6808
  }
6823
6809
  await this.flushQueuedOperations();
@@ -6827,15 +6813,31 @@ ${errorMessage}`);
6827
6813
  * Flush all queued operations in order after text streaming completes
6828
6814
  */
6829
6815
  async flushQueuedOperations() {
6830
- if (this.queuedOperations.length === 0) {
6816
+ if (this.queuedEvents.length === 0) {
6831
6817
  return;
6832
6818
  }
6833
- const operationsToFlush = [...this.queuedOperations];
6834
- this.queuedOperations = [];
6835
- for (const operation of operationsToFlush) {
6836
- await this.writeData("data-operation", operation);
6819
+ const eventsToFlush = [...this.queuedEvents];
6820
+ this.queuedEvents = [];
6821
+ for (const event of eventsToFlush) {
6822
+ await this.writeData(event.type, event.event);
6837
6823
  }
6838
6824
  }
6825
+ /**
6826
+ * Write the final [DONE] message
6827
+ */
6828
+ async writeDone() {
6829
+ await this.stream.writeSSE({
6830
+ data: "[DONE]"
6831
+ });
6832
+ }
6833
+ /**
6834
+ * Complete the stream with finish reason and done message
6835
+ */
6836
+ async complete(finishReason = "stop") {
6837
+ await this.flushQueuedOperations();
6838
+ await this.writeCompletion(finishReason);
6839
+ await this.writeDone();
6840
+ }
6839
6841
  };
6840
6842
  function createSSEStreamHelper(stream2, requestId2, timestamp) {
6841
6843
  return new SSEStreamHelper(stream2, requestId2, timestamp);
@@ -6855,10 +6857,10 @@ var _VercelDataStreamHelper = class _VercelDataStreamHelper {
6855
6857
  __publicField(this, "isCompleted", false);
6856
6858
  // Stream queuing for proper event ordering
6857
6859
  __publicField(this, "isTextStreaming", false);
6858
- __publicField(this, "queuedOperations", []);
6860
+ __publicField(this, "queuedEvents", []);
6859
6861
  // Timing tracking for text sequences (text-end to text-start gap)
6860
6862
  __publicField(this, "lastTextEndTimestamp", 0);
6861
- __publicField(this, "TEXT_GAP_THRESHOLD", 50);
6863
+ __publicField(this, "TEXT_GAP_THRESHOLD", 2e3);
6862
6864
  // milliseconds - if gap between text sequences is less than this, queue operations
6863
6865
  // Connection management and forced cleanup
6864
6866
  __publicField(this, "connectionDropTimer");
@@ -6967,15 +6969,24 @@ var _VercelDataStreamHelper = class _VercelDataStreamHelper {
6967
6969
  data
6968
6970
  });
6969
6971
  }
6970
- async writeError(errorMessage) {
6972
+ async writeError(error) {
6971
6973
  if (this.isCompleted) {
6972
6974
  console.warn("Attempted to write error to completed stream");
6973
6975
  return;
6974
6976
  }
6975
- this.writer.write({
6976
- type: "error",
6977
- errorText: errorMessage
6978
- });
6977
+ if (typeof error === "string") {
6978
+ this.writer.write({
6979
+ type: "error",
6980
+ message: error,
6981
+ severity: "error",
6982
+ timestamp: Date.now()
6983
+ });
6984
+ } else {
6985
+ this.writer.write({
6986
+ ...error,
6987
+ type: "error"
6988
+ });
6989
+ }
6979
6990
  }
6980
6991
  async streamData(data) {
6981
6992
  await this.writeContent(JSON.stringify(data));
@@ -6987,20 +6998,6 @@ var _VercelDataStreamHelper = class _VercelDataStreamHelper {
6987
6998
  }
6988
6999
  this.writer.merge(stream2);
6989
7000
  }
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
7001
  /**
7005
7002
  * Clean up all memory allocations
7006
7003
  * Should be called when the stream helper is no longer needed
@@ -7014,7 +7011,7 @@ var _VercelDataStreamHelper = class _VercelDataStreamHelper {
7014
7011
  this.sentItems.clear();
7015
7012
  this.completedItems.clear();
7016
7013
  this.textId = null;
7017
- this.queuedOperations = [];
7014
+ this.queuedEvents = [];
7018
7015
  this.isTextStreaming = false;
7019
7016
  }
7020
7017
  /**
@@ -7080,7 +7077,9 @@ var _VercelDataStreamHelper = class _VercelDataStreamHelper {
7080
7077
  if (this.writer && !this.isCompleted) {
7081
7078
  this.writer.write({
7082
7079
  type: "error",
7083
- errorText: `Stream terminated: ${reason}`
7080
+ message: `Stream terminated: ${reason}`,
7081
+ severity: "error",
7082
+ timestamp: Date.now()
7084
7083
  });
7085
7084
  }
7086
7085
  } catch (e) {
@@ -7103,23 +7102,33 @@ var _VercelDataStreamHelper = class _VercelDataStreamHelper {
7103
7102
  isCompleted: this.isCompleted
7104
7103
  };
7105
7104
  }
7105
+ async writeSummary(summary) {
7106
+ if (this.isCompleted) {
7107
+ console.warn("Attempted to write summary to completed stream");
7108
+ return;
7109
+ }
7110
+ const now = Date.now();
7111
+ const gapFromLastTextEnd = this.lastTextEndTimestamp > 0 ? now - this.lastTextEndTimestamp : Number.MAX_SAFE_INTEGER;
7112
+ if (this.isTextStreaming || gapFromLastTextEnd < this.TEXT_GAP_THRESHOLD) {
7113
+ this.queuedEvents.push({ type: "data-summary", event: summary });
7114
+ return;
7115
+ }
7116
+ await this.flushQueuedOperations();
7117
+ await this.writer.write({
7118
+ id: "id" in summary ? summary.id : void 0,
7119
+ type: "data-summary",
7120
+ data: summary
7121
+ });
7122
+ }
7106
7123
  async writeOperation(operation) {
7107
7124
  if (this.isCompleted) {
7108
7125
  console.warn("Attempted to write operation to completed stream");
7109
7126
  return;
7110
7127
  }
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
7128
  const now = Date.now();
7120
7129
  const gapFromLastTextEnd = this.lastTextEndTimestamp > 0 ? now - this.lastTextEndTimestamp : Number.MAX_SAFE_INTEGER;
7121
7130
  if (this.isTextStreaming || gapFromLastTextEnd < this.TEXT_GAP_THRESHOLD) {
7122
- this.queuedOperations.push(operation);
7131
+ this.queuedEvents.push({ type: "data-operation", event: operation });
7123
7132
  return;
7124
7133
  }
7125
7134
  await this.flushQueuedOperations();
@@ -7133,19 +7142,33 @@ var _VercelDataStreamHelper = class _VercelDataStreamHelper {
7133
7142
  * Flush all queued operations in order after text streaming completes
7134
7143
  */
7135
7144
  async flushQueuedOperations() {
7136
- if (this.queuedOperations.length === 0) {
7145
+ if (this.queuedEvents.length === 0) {
7137
7146
  return;
7138
7147
  }
7139
- const operationsToFlush = [...this.queuedOperations];
7140
- this.queuedOperations = [];
7141
- for (const operation of operationsToFlush) {
7148
+ const eventsToFlush = [...this.queuedEvents];
7149
+ this.queuedEvents = [];
7150
+ for (const event of eventsToFlush) {
7142
7151
  this.writer.write({
7143
- id: "id" in operation ? operation.id : void 0,
7144
- type: "data-operation",
7145
- data: operation
7152
+ id: "id" in event.event ? event.event.id : void 0,
7153
+ type: event.type,
7154
+ data: event.event
7146
7155
  });
7147
7156
  }
7148
7157
  }
7158
+ async writeCompletion(_finishReason = "stop") {
7159
+ }
7160
+ async writeDone() {
7161
+ }
7162
+ /**
7163
+ * Complete the stream and clean up all memory
7164
+ * This is the primary cleanup point to prevent memory leaks between requests
7165
+ */
7166
+ async complete() {
7167
+ if (this.isCompleted) return;
7168
+ await this.flushQueuedOperations();
7169
+ this.isCompleted = true;
7170
+ this.cleanup();
7171
+ }
7149
7172
  };
7150
7173
  // Memory management - focused on connection completion cleanup
7151
7174
  __publicField(_VercelDataStreamHelper, "MAX_BUFFER_SIZE", 5 * 1024 * 1024);
@@ -7158,6 +7181,7 @@ var MCPStreamHelper = class {
7158
7181
  __publicField(this, "capturedText", "");
7159
7182
  __publicField(this, "capturedData", []);
7160
7183
  __publicField(this, "capturedOperations", []);
7184
+ __publicField(this, "capturedSummaries", []);
7161
7185
  __publicField(this, "hasError", false);
7162
7186
  __publicField(this, "errorMessage", "");
7163
7187
  __publicField(this, "sessionId");
@@ -7176,18 +7200,27 @@ var MCPStreamHelper = class {
7176
7200
  async streamData(data) {
7177
7201
  this.capturedData.push(data);
7178
7202
  }
7203
+ async streamSummary(summary) {
7204
+ this.capturedSummaries.push(summary);
7205
+ }
7206
+ async streamOperation(operation) {
7207
+ this.capturedOperations.push(operation);
7208
+ }
7179
7209
  async writeData(_type, data) {
7180
7210
  this.capturedData.push(data);
7181
7211
  }
7182
- async writeError(errorMessage) {
7183
- this.hasError = true;
7184
- this.errorMessage = errorMessage;
7185
- }
7186
- async complete() {
7212
+ async writeSummary(summary) {
7213
+ this.capturedSummaries.push(summary);
7187
7214
  }
7188
7215
  async writeOperation(operation) {
7189
7216
  this.capturedOperations.push(operation);
7190
7217
  }
7218
+ async writeError(error) {
7219
+ this.hasError = true;
7220
+ this.errorMessage = typeof error === "string" ? error : error.message;
7221
+ }
7222
+ async complete() {
7223
+ }
7191
7224
  /**
7192
7225
  * Get the captured response for MCP tool result
7193
7226
  */
@@ -7204,6 +7237,8 @@ var MCPStreamHelper = class {
7204
7237
  function createMCPStreamHelper() {
7205
7238
  return new MCPStreamHelper();
7206
7239
  }
7240
+
7241
+ // src/handlers/executionHandler.ts
7207
7242
  var logger19 = getLogger("ExecutionHandler");
7208
7243
  var ExecutionHandler = class {
7209
7244
  constructor() {
@@ -7232,7 +7267,7 @@ var ExecutionHandler = class {
7232
7267
  logger19.info({ sessionId: requestId2, graphId }, "Created GraphSession for message execution");
7233
7268
  let graphConfig = null;
7234
7269
  try {
7235
- graphConfig = await getFullGraph(dbClient_default)({ scopes: { tenantId, projectId }, graphId });
7270
+ graphConfig = await getFullGraph(dbClient_default)({ scopes: { tenantId, projectId, graphId } });
7236
7271
  if (graphConfig?.statusUpdates && graphConfig.statusUpdates.enabled !== false) {
7237
7272
  graphSessionManager.initializeStatusUpdates(
7238
7273
  requestId2,
@@ -7386,7 +7421,6 @@ var ExecutionHandler = class {
7386
7421
  if (errorCount >= this.MAX_ERRORS) {
7387
7422
  const errorMessage2 = `Maximum error limit (${this.MAX_ERRORS}) reached`;
7388
7423
  logger19.error({ maxErrors: this.MAX_ERRORS, errorCount }, errorMessage2);
7389
- await sseHelper.writeError(errorMessage2);
7390
7424
  await sseHelper.writeOperation(errorOp(errorMessage2, currentAgentId || "system"));
7391
7425
  if (task) {
7392
7426
  await updateTask(dbClient_default)({
@@ -7527,7 +7561,6 @@ var ExecutionHandler = class {
7527
7561
  if (errorCount >= this.MAX_ERRORS) {
7528
7562
  const errorMessage2 = `Maximum error limit (${this.MAX_ERRORS}) reached`;
7529
7563
  logger19.error({ maxErrors: this.MAX_ERRORS, errorCount }, errorMessage2);
7530
- await sseHelper.writeError(errorMessage2);
7531
7564
  await sseHelper.writeOperation(errorOp(errorMessage2, currentAgentId || "system"));
7532
7565
  if (task) {
7533
7566
  await updateTask(dbClient_default)({
@@ -7549,7 +7582,6 @@ var ExecutionHandler = class {
7549
7582
  }
7550
7583
  const errorMessage = `Maximum transfer limit (${maxTransfers}) reached without completion`;
7551
7584
  logger19.error({ maxTransfers, iterations }, errorMessage);
7552
- await sseHelper.writeError(errorMessage);
7553
7585
  await sseHelper.writeOperation(errorOp(errorMessage, currentAgentId || "system"));
7554
7586
  if (task) {
7555
7587
  await updateTask(dbClient_default)({
@@ -7570,8 +7602,7 @@ var ExecutionHandler = class {
7570
7602
  } catch (error) {
7571
7603
  logger19.error({ error }, "Error in execution handler");
7572
7604
  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"));
7605
+ await sseHelper.writeOperation(errorOp(`Execution error: ${errorMessage}`, currentAgentId || "system"));
7575
7606
  if (task) {
7576
7607
  await updateTask(dbClient_default)({
7577
7608
  taskId: task.id,
@@ -7733,8 +7764,7 @@ app2.openapi(chatCompletionsRoute, async (c) => {
7733
7764
  const body = c.get("requestBody") || {};
7734
7765
  const conversationId = body.conversationId || nanoid();
7735
7766
  const fullGraph = await getFullGraph(dbClient_default)({
7736
- scopes: { tenantId, projectId },
7737
- graphId
7767
+ scopes: { tenantId, projectId, graphId }
7738
7768
  });
7739
7769
  let agentGraph;
7740
7770
  let defaultAgentId;
@@ -7751,16 +7781,21 @@ app2.openapi(chatCompletionsRoute, async (c) => {
7751
7781
  defaultAgentId = fullGraph.defaultAgentId || firstAgentId;
7752
7782
  } else {
7753
7783
  agentGraph = await getAgentGraphWithDefaultAgent(dbClient_default)({
7754
- scopes: { tenantId, projectId },
7755
- graphId
7784
+ scopes: { tenantId, projectId, graphId }
7756
7785
  });
7757
7786
  if (!agentGraph) {
7758
- return c.json({ error: "Agent graph not found" }, 404);
7787
+ throw createApiError({
7788
+ code: "not_found",
7789
+ message: "Agent graph not found"
7790
+ });
7759
7791
  }
7760
7792
  defaultAgentId = agentGraph.defaultAgentId || "";
7761
7793
  }
7762
7794
  if (!defaultAgentId) {
7763
- return c.json({ error: "No default agent found in graph" }, 404);
7795
+ throw createApiError({
7796
+ code: "not_found",
7797
+ message: "No default agent found in graph"
7798
+ });
7764
7799
  }
7765
7800
  await createOrGetConversation(dbClient_default)({
7766
7801
  tenantId,
@@ -7781,26 +7816,30 @@ app2.openapi(chatCompletionsRoute, async (c) => {
7781
7816
  }
7782
7817
  const agentId = activeAgent?.activeAgentId || defaultAgentId;
7783
7818
  const agentInfo = await getAgentById(dbClient_default)({
7784
- scopes: { tenantId, projectId },
7819
+ scopes: { tenantId, projectId, graphId },
7785
7820
  agentId
7786
7821
  });
7787
7822
  if (!agentInfo) {
7788
- return c.json({ error: "Agent not found" }, 404);
7823
+ throw createApiError({
7824
+ code: "not_found",
7825
+ message: "Agent not found"
7826
+ });
7789
7827
  }
7790
7828
  const validatedContext = c.get("validatedContext") || body.requestContext || {};
7791
7829
  const credentialStores = c.get("credentialStores");
7792
- await handleContextResolution(
7830
+ await handleContextResolution({
7793
7831
  tenantId,
7794
7832
  projectId,
7795
- conversationId,
7796
7833
  graphId,
7797
- validatedContext,
7798
- dbClient_default,
7834
+ conversationId,
7835
+ requestContext: validatedContext,
7836
+ dbClient: dbClient_default,
7799
7837
  credentialStores
7800
- );
7838
+ });
7801
7839
  logger20.info(
7802
7840
  {
7803
7841
  tenantId,
7842
+ projectId,
7804
7843
  graphId,
7805
7844
  conversationId,
7806
7845
  defaultAgentId,
@@ -7842,41 +7881,69 @@ app2.openapi(chatCompletionsRoute, async (c) => {
7842
7881
  });
7843
7882
  }
7844
7883
  return streamSSE(c, async (stream2) => {
7845
- const sseHelper = createSSEStreamHelper(stream2, requestId2, timestamp);
7846
- await sseHelper.writeRole();
7847
- logger20.info({ agentId }, "Starting execution");
7848
- const executionHandler = new ExecutionHandler();
7849
- const result = await executionHandler.execute({
7850
- executionContext,
7851
- conversationId,
7852
- userMessage,
7853
- initialAgentId: agentId,
7854
- requestId: requestId2,
7855
- sseHelper
7856
- });
7857
- logger20.info(
7858
- { result },
7859
- `Execution completed: ${result.success ? "success" : "failed"} after ${result.iterations} iterations`
7860
- );
7861
- if (!result.success) {
7862
- await sseHelper.writeError(
7863
- "Sorry, I was unable to process your request at this time. Please try again."
7884
+ try {
7885
+ const sseHelper = createSSEStreamHelper(stream2, requestId2, timestamp);
7886
+ await sseHelper.writeRole();
7887
+ logger20.info({ agentId }, "Starting execution");
7888
+ const executionHandler = new ExecutionHandler();
7889
+ const result = await executionHandler.execute({
7890
+ executionContext,
7891
+ conversationId,
7892
+ userMessage,
7893
+ initialAgentId: agentId,
7894
+ requestId: requestId2,
7895
+ sseHelper
7896
+ });
7897
+ logger20.info(
7898
+ { result },
7899
+ `Execution completed: ${result.success ? "success" : "failed"} after ${result.iterations} iterations`
7864
7900
  );
7901
+ if (!result.success) {
7902
+ await sseHelper.writeOperation(
7903
+ errorOp(
7904
+ "Sorry, I was unable to process your request at this time. Please try again.",
7905
+ "system"
7906
+ )
7907
+ );
7908
+ }
7909
+ await sseHelper.complete();
7910
+ } catch (error) {
7911
+ logger20.error(
7912
+ {
7913
+ error: error instanceof Error ? error.message : error,
7914
+ stack: error instanceof Error ? error.stack : void 0
7915
+ },
7916
+ "Error during streaming execution"
7917
+ );
7918
+ try {
7919
+ const sseHelper = createSSEStreamHelper(stream2, requestId2, timestamp);
7920
+ await sseHelper.writeOperation(
7921
+ errorOp(
7922
+ "Sorry, I was unable to process your request at this time. Please try again.",
7923
+ "system"
7924
+ )
7925
+ );
7926
+ await sseHelper.complete();
7927
+ } catch (streamError) {
7928
+ logger20.error({ streamError }, "Failed to write error to stream");
7929
+ }
7865
7930
  }
7866
- await sseHelper.complete();
7867
7931
  });
7868
7932
  } catch (error) {
7869
- console.error("\u274C Error in chat completions endpoint:", {
7870
- error: error instanceof Error ? error.message : error,
7871
- stack: error instanceof Error ? error.stack : void 0
7872
- });
7873
- return c.json(
7933
+ logger20.error(
7874
7934
  {
7875
- error: "Failed to process chat completion",
7876
- message: error instanceof Error ? error.message : "Unknown error"
7935
+ error: error instanceof Error ? error.message : error,
7936
+ stack: error instanceof Error ? error.stack : void 0
7877
7937
  },
7878
- 500
7938
+ "Error in chat completions endpoint before streaming"
7879
7939
  );
7940
+ if (error && typeof error === "object" && "status" in error) {
7941
+ throw error;
7942
+ }
7943
+ throw createApiError({
7944
+ code: "internal_server_error",
7945
+ message: error instanceof Error ? error.message : "Failed to process chat completion"
7946
+ });
7880
7947
  }
7881
7948
  });
7882
7949
  var getMessageText = (content) => {
@@ -7940,6 +8007,7 @@ app3.openapi(chatDataStreamRoute, async (c) => {
7940
8007
  try {
7941
8008
  const executionContext = getRequestExecutionContext(c);
7942
8009
  const { tenantId, projectId, graphId } = executionContext;
8010
+ loggerFactory.getLogger("chatDataStream").debug({ tenantId, projectId, graphId }, "Extracted chatDataStream parameters");
7943
8011
  const body = c.get("requestBody") || {};
7944
8012
  const conversationId = body.conversationId || nanoid();
7945
8013
  const activeSpan = trace.getActiveSpan();
@@ -7952,14 +8020,22 @@ app3.openapi(chatDataStreamRoute, async (c) => {
7952
8020
  });
7953
8021
  }
7954
8022
  const agentGraph = await getAgentGraphWithDefaultAgent(dbClient_default)({
7955
- scopes: { tenantId, projectId },
7956
- graphId
8023
+ scopes: { tenantId, projectId, graphId }
7957
8024
  });
7958
8025
  if (!agentGraph) {
7959
- return c.json({ error: "Agent graph not found" }, 404);
8026
+ throw createApiError({
8027
+ code: "not_found",
8028
+ message: "Agent graph not found"
8029
+ });
7960
8030
  }
7961
8031
  const defaultAgentId = agentGraph.defaultAgentId;
7962
8032
  const graphName = agentGraph.name;
8033
+ if (!defaultAgentId) {
8034
+ throw createApiError({
8035
+ code: "bad_request",
8036
+ message: "Graph does not have a default agent configured"
8037
+ });
8038
+ }
7963
8039
  const activeAgent = await getActiveAgentForConversation(dbClient_default)({
7964
8040
  scopes: { tenantId, projectId },
7965
8041
  conversationId
@@ -7973,23 +8049,26 @@ app3.openapi(chatDataStreamRoute, async (c) => {
7973
8049
  }
7974
8050
  const agentId = activeAgent?.activeAgentId || defaultAgentId;
7975
8051
  const agentInfo = await getAgentById(dbClient_default)({
7976
- scopes: { tenantId, projectId },
8052
+ scopes: { tenantId, projectId, graphId },
7977
8053
  agentId
7978
8054
  });
7979
8055
  if (!agentInfo) {
7980
- return c.json({ error: "Agent not found" }, 404);
8056
+ throw createApiError({
8057
+ code: "not_found",
8058
+ message: "Agent not found"
8059
+ });
7981
8060
  }
7982
8061
  const validatedContext = c.get("validatedContext") || body.requestContext || {};
7983
8062
  const credentialStores = c.get("credentialStores");
7984
- await handleContextResolution(
8063
+ await handleContextResolution({
7985
8064
  tenantId,
7986
8065
  projectId,
7987
- conversationId,
7988
8066
  graphId,
7989
- validatedContext,
7990
- dbClient_default,
8067
+ conversationId,
8068
+ requestContext: validatedContext,
8069
+ dbClient: dbClient_default,
7991
8070
  credentialStores
7992
- );
8071
+ });
7993
8072
  const lastUserMessage = body.messages.filter((m) => m.role === "user").slice(-1)[0];
7994
8073
  const userText = typeof lastUserMessage?.content === "string" ? lastUserMessage.content : lastUserMessage?.parts?.map((p) => p.text).join("") || "";
7995
8074
  logger21.info({ userText, lastUserMessage }, "userText");
@@ -8031,11 +8110,11 @@ app3.openapi(chatDataStreamRoute, async (c) => {
8031
8110
  sseHelper: streamHelper
8032
8111
  });
8033
8112
  if (!result.success) {
8034
- await streamHelper.writeError("Unable to process request");
8113
+ await streamHelper.writeOperation(errorOp("Unable to process request", "system"));
8035
8114
  }
8036
8115
  } catch (err) {
8037
8116
  logger21.error({ err }, "Streaming error");
8038
- await streamHelper.writeError("Internal server error");
8117
+ await streamHelper.writeOperation(errorOp("Internal server error", "system"));
8039
8118
  } finally {
8040
8119
  if ("cleanup" in streamHelper && typeof streamHelper.cleanup === "function") {
8041
8120
  streamHelper.cleanup();
@@ -8056,7 +8135,10 @@ app3.openapi(chatDataStreamRoute, async (c) => {
8056
8135
  );
8057
8136
  } catch (error) {
8058
8137
  logger21.error({ error }, "chatDataStream error");
8059
- return c.json({ error: "Failed to process chat completion" }, 500);
8138
+ throw createApiError({
8139
+ code: "internal_server_error",
8140
+ message: "Failed to process chat completion"
8141
+ });
8060
8142
  }
8061
8143
  });
8062
8144
  var chatDataStream_default = app3;
@@ -8258,8 +8340,7 @@ var getServer = async (requestContext, executionContext, conversationId, credent
8258
8340
  const { tenantId, projectId, graphId } = executionContext;
8259
8341
  setupTracing(conversationId, tenantId, graphId);
8260
8342
  const agentGraph = await getAgentGraphWithDefaultAgent(dbClient_default)({
8261
- scopes: { tenantId, projectId },
8262
- graphId
8343
+ scopes: { tenantId, projectId, graphId }
8263
8344
  });
8264
8345
  if (!agentGraph) {
8265
8346
  throw new Error("Agent graph not found");
@@ -8279,9 +8360,20 @@ var getServer = async (requestContext, executionContext, conversationId, credent
8279
8360
  },
8280
8361
  async ({ query }) => {
8281
8362
  try {
8363
+ if (!agentGraph.defaultAgentId) {
8364
+ return {
8365
+ content: [
8366
+ {
8367
+ type: "text",
8368
+ text: `Graph does not have a default agent configured`
8369
+ }
8370
+ ],
8371
+ isError: true
8372
+ };
8373
+ }
8282
8374
  const defaultAgentId = agentGraph.defaultAgentId;
8283
8375
  const agentInfo = await getAgentById(dbClient_default)({
8284
- scopes: { tenantId, projectId },
8376
+ scopes: { tenantId, projectId, graphId },
8285
8377
  agentId: defaultAgentId
8286
8378
  });
8287
8379
  if (!agentInfo) {
@@ -8295,18 +8387,19 @@ var getServer = async (requestContext, executionContext, conversationId, credent
8295
8387
  isError: true
8296
8388
  };
8297
8389
  }
8298
- const resolvedContext = await handleContextResolution(
8390
+ const resolvedContext = await handleContextResolution({
8299
8391
  tenantId,
8300
8392
  projectId,
8301
- conversationId,
8302
8393
  graphId,
8394
+ conversationId,
8303
8395
  requestContext,
8304
- dbClient_default,
8396
+ dbClient: dbClient_default,
8305
8397
  credentialStores
8306
- );
8398
+ });
8307
8399
  logger22.info(
8308
8400
  {
8309
8401
  tenantId,
8402
+ projectId,
8310
8403
  graphId,
8311
8404
  conversationId,
8312
8405
  hasContextConfig: !!agentGraph.contextConfigId,
@@ -8368,8 +8461,7 @@ var handleInitializationRequest = async (body, executionContext, validatedContex
8368
8461
  logger22.info({ body }, "Received initialization request");
8369
8462
  const sessionId = nanoid();
8370
8463
  const agentGraph = await getAgentGraphWithDefaultAgent(dbClient_default)({
8371
- scopes: { tenantId, projectId },
8372
- graphId
8464
+ scopes: { tenantId, projectId, graphId }
8373
8465
  });
8374
8466
  if (!agentGraph) {
8375
8467
  return c.json(
@@ -8381,6 +8473,16 @@ var handleInitializationRequest = async (body, executionContext, validatedContex
8381
8473
  { status: 404 }
8382
8474
  );
8383
8475
  }
8476
+ if (!agentGraph.defaultAgentId) {
8477
+ return c.json(
8478
+ {
8479
+ jsonrpc: "2.0",
8480
+ error: { code: -32001, message: "Graph does not have a default agent configured" },
8481
+ id: body.id || null
8482
+ },
8483
+ { status: 400 }
8484
+ );
8485
+ }
8384
8486
  const conversation = await createOrGetConversation(dbClient_default)({
8385
8487
  id: sessionId,
8386
8488
  tenantId,
@@ -8577,6 +8679,8 @@ app4.delete("/", async (c) => {
8577
8679
  );
8578
8680
  });
8579
8681
  var mcp_default = app4;
8682
+
8683
+ // src/app.ts
8580
8684
  var logger23 = getLogger("agents-run-api");
8581
8685
  function createExecutionHono(serverConfig, credentialStores) {
8582
8686
  const app6 = new OpenAPIHono();
@@ -8766,21 +8870,21 @@ function createExecutionHono(serverConfig, credentialStores) {
8766
8870
  app6.route("/v1/mcp", mcp_default);
8767
8871
  app6.route("/agents", agents_default);
8768
8872
  setupOpenAPIRoutes(app6);
8769
- app6.use("/tenants/*", async (c, next) => {
8873
+ app6.use("/tenants/*", async (_c, next) => {
8770
8874
  await next();
8771
- await batchProcessor.forceFlush();
8875
+ await defaultBatchProcessor.forceFlush();
8772
8876
  });
8773
- app6.use("/agents/*", async (c, next) => {
8877
+ app6.use("/agents/*", async (_c, next) => {
8774
8878
  await next();
8775
- await batchProcessor.forceFlush();
8879
+ await defaultBatchProcessor.forceFlush();
8776
8880
  });
8777
- app6.use("/v1/*", async (c, next) => {
8881
+ app6.use("/v1/*", async (_c, next) => {
8778
8882
  await next();
8779
- await batchProcessor.forceFlush();
8883
+ await defaultBatchProcessor.forceFlush();
8780
8884
  });
8781
- app6.use("/api/*", async (c, next) => {
8885
+ app6.use("/api/*", async (_c, next) => {
8782
8886
  await next();
8783
- await batchProcessor.forceFlush();
8887
+ await defaultBatchProcessor.forceFlush();
8784
8888
  });
8785
8889
  const baseApp = new Hono();
8786
8890
  baseApp.route("/", app6);