@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/chunk-5RGAMXUL.js +55 -0
- package/dist/{chunk-7PHUFKNP.js → chunk-HIGMADTA.js} +3 -6
- package/dist/chunk-PKBMQBKP.js +5 -0
- package/dist/{conversations-WDOIWO7W.js → conversations-OVETKXSP.js} +1 -1
- package/dist/index.cjs +833 -683
- package/dist/index.js +800 -696
- package/dist/instrumentation.cjs +63 -0
- package/dist/instrumentation.d.cts +15 -0
- package/dist/instrumentation.d.ts +15 -0
- package/dist/instrumentation.js +1 -0
- package/package.json +10 -3
package/dist/index.js
CHANGED
|
@@ -1,14 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
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,
|
|
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,
|
|
988
|
+
function errorOp(message, agentId, severity = "error", code) {
|
|
1002
989
|
return {
|
|
1003
990
|
type: "error",
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
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(
|
|
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.
|
|
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}.
|
|
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
|
-
*
|
|
1275
|
+
* Built-in providers that have special handling
|
|
1267
1276
|
*/
|
|
1268
|
-
__publicField(_ModelFactory, "
|
|
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
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1651
|
-
|
|
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(
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
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
|
|
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
|
-
-
|
|
1944
|
-
|
|
1945
|
-
-
|
|
1946
|
-
-
|
|
1947
|
-
-
|
|
1948
|
-
-
|
|
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
|
|
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
|
-
|
|
1904
|
+
summaries.push({
|
|
1987
1905
|
type: componentId,
|
|
1988
1906
|
data
|
|
1989
1907
|
});
|
|
1990
1908
|
}
|
|
1991
1909
|
}
|
|
1992
1910
|
span.setAttributes({
|
|
1993
|
-
"
|
|
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 {
|
|
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 {
|
|
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
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
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-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
2723
|
-
var
|
|
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
|
|
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
|
|
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
|
|
2762
|
-
|
|
2763
|
-
|
|
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.
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
const delta = part.argsTextDelta || "";
|
|
2781
|
-
if (jsonBuffer.length + delta.length > MAX_BUFFER_SIZE) {
|
|
2782
|
-
logger8.warn(
|
|
2783
|
-
{ bufferSize: jsonBuffer.length + delta.length, maxSize: MAX_BUFFER_SIZE },
|
|
2784
|
-
"JSON buffer exceeded maximum size, truncating"
|
|
2785
|
-
);
|
|
2786
|
-
jsonBuffer = jsonBuffer.slice(-MAX_BUFFER_SIZE / 2);
|
|
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
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
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
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
if (componentMatch[0].length > MAX_COMPONENT_SIZE) {
|
|
2809
|
-
logger8.warn(
|
|
2810
|
-
{
|
|
2811
|
-
size: componentMatch[0].length,
|
|
2812
|
-
maxSize: MAX_COMPONENT_SIZE
|
|
2813
|
-
},
|
|
2814
|
-
"Component exceeds size limit, skipping"
|
|
2815
|
-
);
|
|
2816
|
-
componentBuffer = "";
|
|
2817
|
-
continue;
|
|
2818
|
-
}
|
|
2819
|
-
try {
|
|
2820
|
-
const component = JSON.parse(componentMatch[0]);
|
|
2821
|
-
if (typeof component !== "object" || !component.id) {
|
|
2822
|
-
logger8.warn({ component }, "Invalid component structure, skipping");
|
|
2823
|
-
componentBuffer = "";
|
|
2824
|
-
continue;
|
|
2825
|
-
}
|
|
2826
|
-
const parts = await this.artifactParser.parseObject({
|
|
2827
|
-
dataComponents: [component]
|
|
2828
|
-
});
|
|
2829
|
-
for (const part2 of parts) {
|
|
2830
|
-
await this.streamPart(part2);
|
|
2831
|
-
}
|
|
2832
|
-
componentsStreamed++;
|
|
2833
|
-
componentBuffer = "";
|
|
2834
|
-
} catch (e) {
|
|
2835
|
-
logger8.debug({ error: e }, "Failed to parse component, continuing to accumulate");
|
|
2836
|
-
}
|
|
2837
|
-
}
|
|
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
|
-
|
|
2695
|
+
continue;
|
|
2841
2696
|
}
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
const
|
|
2845
|
-
|
|
2846
|
-
await this.
|
|
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
|
-
*
|
|
2708
|
+
* Stream a component and mark it as streamed
|
|
2709
|
+
* Note: Text components are handled separately with incremental streaming
|
|
2856
2710
|
*/
|
|
2857
|
-
async
|
|
2858
|
-
await this.
|
|
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
|
-
*
|
|
2728
|
+
* Check if a component has the basic structure required for streaming
|
|
2729
|
+
* Requires id, name, and props object with content
|
|
2862
2730
|
*/
|
|
2863
|
-
|
|
2864
|
-
if (
|
|
2865
|
-
|
|
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 (
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
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
|
|
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
|
|
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: {
|
|
5253
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
5977
|
-
|
|
5978
|
-
|
|
5979
|
-
|
|
5980
|
-
|
|
5981
|
-
|
|
5982
|
-
|
|
5983
|
-
|
|
5984
|
-
|
|
5985
|
-
|
|
5986
|
-
|
|
5987
|
-
|
|
5988
|
-
|
|
5989
|
-
|
|
5990
|
-
|
|
5991
|
-
|
|
5992
|
-
|
|
5993
|
-
|
|
5994
|
-
|
|
5995
|
-
|
|
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
|
-
|
|
5999
|
-
|
|
6000
|
-
|
|
6001
|
-
|
|
6002
|
-
|
|
6003
|
-
|
|
6004
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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: {
|
|
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
|
|
6356
|
+
const agentGraph = await getAgentGraphById(dbClient_default)({
|
|
6383
6357
|
scopes: {
|
|
6384
6358
|
tenantId: params.tenantId,
|
|
6385
|
-
projectId: params.projectId
|
|
6386
|
-
|
|
6387
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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, "
|
|
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(
|
|
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
|
|
6812
|
-
if (
|
|
6813
|
-
|
|
6814
|
-
type:
|
|
6815
|
-
|
|
6816
|
-
|
|
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.
|
|
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.
|
|
6816
|
+
if (this.queuedEvents.length === 0) {
|
|
6831
6817
|
return;
|
|
6832
6818
|
}
|
|
6833
|
-
const
|
|
6834
|
-
this.
|
|
6835
|
-
for (const
|
|
6836
|
-
await this.writeData(
|
|
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, "
|
|
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",
|
|
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(
|
|
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
|
-
|
|
6976
|
-
|
|
6977
|
-
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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.
|
|
7145
|
+
if (this.queuedEvents.length === 0) {
|
|
7137
7146
|
return;
|
|
7138
7147
|
}
|
|
7139
|
-
const
|
|
7140
|
-
this.
|
|
7141
|
-
for (const
|
|
7148
|
+
const eventsToFlush = [...this.queuedEvents];
|
|
7149
|
+
this.queuedEvents = [];
|
|
7150
|
+
for (const event of eventsToFlush) {
|
|
7142
7151
|
this.writer.write({
|
|
7143
|
-
id: "id" in
|
|
7144
|
-
type:
|
|
7145
|
-
data:
|
|
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
|
|
7183
|
-
this.
|
|
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
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
7798
|
-
|
|
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
|
-
|
|
7846
|
-
|
|
7847
|
-
|
|
7848
|
-
|
|
7849
|
-
|
|
7850
|
-
|
|
7851
|
-
|
|
7852
|
-
|
|
7853
|
-
|
|
7854
|
-
|
|
7855
|
-
|
|
7856
|
-
|
|
7857
|
-
|
|
7858
|
-
|
|
7859
|
-
|
|
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
|
-
|
|
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:
|
|
7876
|
-
|
|
7935
|
+
error: error instanceof Error ? error.message : error,
|
|
7936
|
+
stack: error instanceof Error ? error.stack : void 0
|
|
7877
7937
|
},
|
|
7878
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
7990
|
-
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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 (
|
|
8873
|
+
app6.use("/tenants/*", async (_c, next) => {
|
|
8770
8874
|
await next();
|
|
8771
|
-
await
|
|
8875
|
+
await defaultBatchProcessor.forceFlush();
|
|
8772
8876
|
});
|
|
8773
|
-
app6.use("/agents/*", async (
|
|
8877
|
+
app6.use("/agents/*", async (_c, next) => {
|
|
8774
8878
|
await next();
|
|
8775
|
-
await
|
|
8879
|
+
await defaultBatchProcessor.forceFlush();
|
|
8776
8880
|
});
|
|
8777
|
-
app6.use("/v1/*", async (
|
|
8881
|
+
app6.use("/v1/*", async (_c, next) => {
|
|
8778
8882
|
await next();
|
|
8779
|
-
await
|
|
8883
|
+
await defaultBatchProcessor.forceFlush();
|
|
8780
8884
|
});
|
|
8781
|
-
app6.use("/api/*", async (
|
|
8885
|
+
app6.use("/api/*", async (_c, next) => {
|
|
8782
8886
|
await next();
|
|
8783
|
-
await
|
|
8887
|
+
await defaultBatchProcessor.forceFlush();
|
|
8784
8888
|
});
|
|
8785
8889
|
const baseApp = new Hono();
|
|
8786
8890
|
baseApp.route("/", app6);
|