@inkeep/agents-api 0.0.1 → 0.43.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.
Files changed (150) hide show
  1. package/dist/.well-known/workflow/v1/flow.cjs +43 -106
  2. package/dist/.well-known/workflow/v1/flow.cjs.debug.json +2 -4
  3. package/dist/.well-known/workflow/v1/manifest.debug.json +17 -55
  4. package/dist/.well-known/workflow/v1/step.cjs +45938 -45976
  5. package/dist/.well-known/workflow/v1/step.cjs.debug.json +2 -4
  6. package/dist/_virtual/rolldown_runtime.js +7 -0
  7. package/dist/createApp.js +40 -12
  8. package/dist/domains/evals/api/.well-known/workflow/v1/flow.d.ts +4 -0
  9. package/dist/domains/evals/api/.well-known/workflow/v1/flow.js +12 -0
  10. package/dist/domains/evals/api/.well-known/workflow/v1/step.d.ts +4 -0
  11. package/dist/domains/evals/api/.well-known/workflow/v1/step.js +12 -0
  12. package/dist/domains/evals/routes/datasetTriggers.d.ts +2 -2
  13. package/dist/domains/evals/routes/index.d.ts +2 -2
  14. package/dist/domains/evals/scripts/build-workflow.js +2 -2
  15. package/dist/domains/evals/workflow/functions/evaluateConversation.d.ts +4 -1
  16. package/dist/domains/evals/workflow/functions/evaluateConversation.js +2 -1
  17. package/dist/domains/evals/workflow/functions/runDatasetItem.d.ts +4 -1
  18. package/dist/domains/evals/workflow/functions/runDatasetItem.js +2 -1
  19. package/dist/domains/evals/workflow/routes.d.ts +2 -2
  20. package/dist/domains/evals/workflow/world.js +3 -2
  21. package/dist/domains/github/config.d.ts +14 -0
  22. package/dist/domains/github/config.js +47 -0
  23. package/dist/domains/github/index.d.ts +12 -0
  24. package/dist/domains/github/index.js +18 -0
  25. package/dist/domains/github/installation.d.ts +34 -0
  26. package/dist/domains/github/installation.js +172 -0
  27. package/dist/domains/github/jwks.d.ts +20 -0
  28. package/dist/domains/github/jwks.js +85 -0
  29. package/dist/domains/github/oidcToken.d.ts +22 -0
  30. package/dist/domains/github/oidcToken.js +140 -0
  31. package/dist/domains/github/routes/tokenExchange.d.ts +7 -0
  32. package/dist/domains/github/routes/tokenExchange.js +130 -0
  33. package/dist/domains/manage/index.js +0 -2
  34. package/dist/domains/manage/routes/agent.js +9 -4
  35. package/dist/domains/manage/routes/agentFull.js +9 -6
  36. package/dist/domains/manage/routes/apiKeys.js +1 -2
  37. package/dist/domains/manage/routes/artifactComponents.js +5 -5
  38. package/dist/domains/manage/routes/cliAuth.js +3 -3
  39. package/dist/domains/manage/routes/contextConfigs.js +5 -5
  40. package/dist/domains/manage/routes/conversations.d.ts +2 -2
  41. package/dist/domains/manage/routes/credentialStores.js +2 -2
  42. package/dist/domains/manage/routes/credentials.js +6 -7
  43. package/dist/domains/manage/routes/dataComponents.js +6 -7
  44. package/dist/domains/manage/routes/externalAgents.js +1 -2
  45. package/dist/domains/manage/routes/index.d.ts +2 -2
  46. package/dist/domains/manage/routes/index.js +4 -0
  47. package/dist/domains/manage/routes/invitations.js +1 -1
  48. package/dist/domains/manage/routes/mcp.d.ts +2 -2
  49. package/dist/domains/manage/routes/playgroundToken.js +1 -2
  50. package/dist/domains/manage/routes/projectFull.js +33 -11
  51. package/dist/domains/manage/routes/projectMembers.js +16 -35
  52. package/dist/domains/manage/routes/projectPermissions.js +17 -10
  53. package/dist/domains/manage/routes/projects.js +4 -5
  54. package/dist/domains/manage/routes/signoz.d.ts +2 -2
  55. package/dist/domains/manage/routes/signoz.js +6 -3
  56. package/dist/domains/manage/routes/subAgentArtifactComponents.js +5 -5
  57. package/dist/domains/manage/routes/subAgentDataComponents.js +5 -5
  58. package/dist/domains/manage/routes/subAgentExternalAgentRelations.js +5 -5
  59. package/dist/domains/manage/routes/subAgentFunctionTools.js +5 -5
  60. package/dist/domains/manage/routes/subAgentRelations.js +6 -6
  61. package/dist/domains/manage/routes/subAgentTeamAgentRelations.js +6 -6
  62. package/dist/domains/manage/routes/subAgentToolRelations.js +6 -6
  63. package/dist/domains/manage/routes/subAgents.js +5 -5
  64. package/dist/domains/manage/routes/tools.js +24 -3
  65. package/dist/domains/manage/routes/triggers.js +82 -25
  66. package/dist/domains/manage/routes/userOrganizations.js +4 -4
  67. package/dist/domains/manage/routes/{agentToolRelations.d.ts → userProjectMemberships.d.ts} +1 -1
  68. package/dist/domains/manage/routes/userProjectMemberships.js +45 -0
  69. package/dist/domains/mcp/routes/mcp.d.ts +7 -0
  70. package/dist/domains/mcp/routes/mcp.js +45 -0
  71. package/dist/domains/run/a2a/handlers.js +2 -10
  72. package/dist/domains/run/a2a/types.d.ts +2 -6
  73. package/dist/domains/run/agents/Agent.d.ts +1 -0
  74. package/dist/domains/run/agents/Agent.js +207 -44
  75. package/dist/domains/run/agents/generateTaskHandler.js +14 -2
  76. package/dist/domains/run/context/ContextFetcher.js +8 -7
  77. package/dist/domains/run/context/ContextResolver.js +1 -1
  78. package/dist/domains/run/handlers/executionHandler.d.ts +3 -1
  79. package/dist/domains/run/handlers/executionHandler.js +149 -84
  80. package/dist/domains/run/routes/agents.js +1 -1
  81. package/dist/domains/run/routes/chat.js +47 -1
  82. package/dist/domains/run/routes/chatDataStream.js +107 -14
  83. package/dist/domains/run/routes/webhooks.js +40 -329
  84. package/dist/domains/run/services/AgentSession.d.ts +3 -0
  85. package/dist/domains/run/services/AgentSession.js +9 -0
  86. package/dist/domains/run/services/BaseCompressor.js +1 -1
  87. package/dist/domains/run/services/ToolApprovalUiBus.d.ts +28 -0
  88. package/dist/domains/run/services/ToolApprovalUiBus.js +44 -0
  89. package/dist/domains/run/services/TriggerService.d.ts +31 -0
  90. package/dist/domains/run/services/TriggerService.js +543 -0
  91. package/dist/domains/run/tools/NativeSandboxExecutor.d.ts +3 -2
  92. package/dist/domains/run/tools/NativeSandboxExecutor.js +76 -48
  93. package/dist/domains/run/tools/SandboxExecutorFactory.d.ts +11 -1
  94. package/dist/domains/run/tools/SandboxExecutorFactory.js +27 -3
  95. package/dist/domains/run/tools/VercelSandboxExecutor.d.ts +3 -11
  96. package/dist/domains/run/tools/VercelSandboxExecutor.js +137 -127
  97. package/dist/domains/run/types/xml.d.ts +1 -5
  98. package/dist/domains/run/utils/stream-helpers.d.ts +134 -0
  99. package/dist/domains/run/utils/stream-helpers.js +182 -0
  100. package/dist/factory.d.ts +278 -272
  101. package/dist/index.d.ts +275 -269
  102. package/dist/index.js +16 -1
  103. package/dist/initialization.js +9 -2
  104. package/dist/middleware/cors.js +1 -1
  105. package/dist/middleware/evalsAuth.d.ts +2 -2
  106. package/dist/middleware/manageAuth.d.ts +2 -2
  107. package/dist/middleware/projectAccess.d.ts +4 -11
  108. package/dist/middleware/projectAccess.js +1 -17
  109. package/dist/middleware/projectConfig.d.ts +3 -3
  110. package/dist/middleware/requirePermission.d.ts +2 -2
  111. package/dist/middleware/runAuth.d.ts +4 -4
  112. package/dist/middleware/sessionAuth.d.ts +3 -3
  113. package/dist/middleware/tenantAccess.d.ts +2 -2
  114. package/dist/middleware/tenantAccess.js +4 -4
  115. package/dist/middleware/tracing.d.ts +3 -3
  116. package/dist/openapi.d.ts +35 -1
  117. package/dist/openapi.js +39 -95
  118. package/dist/routes/healthChecks.d.ts +10 -0
  119. package/dist/routes/healthChecks.js +75 -0
  120. package/dist/templates/v1/phase1/system-prompt.js +1 -1
  121. package/dist/templates/v1/phase1/thinking-preparation.js +1 -1
  122. package/dist/templates/v1/phase1/tool.js +1 -1
  123. package/dist/templates/v1/phase2/data-component.js +1 -1
  124. package/dist/templates/v1/phase2/data-components.js +1 -1
  125. package/dist/templates/v1/phase2/system-prompt.js +1 -1
  126. package/dist/templates/v1/shared/artifact-retrieval-guidance.js +1 -1
  127. package/dist/templates/v1/shared/artifact.js +1 -1
  128. package/dist/types/app.d.ts +2 -0
  129. package/dist/utils/healthChecks.d.ts +8 -0
  130. package/dist/utils/healthChecks.js +38 -0
  131. package/dist/utils/signozHelpers.d.ts +2 -2
  132. package/dist/utils/signozHelpers.js +15 -3
  133. package/package.json +25 -28
  134. package/dist/domains/evals/services/startEvaluation.d.ts +0 -19
  135. package/dist/domains/evals/services/startEvaluation.js +0 -18
  136. package/dist/domains/index.d.ts +0 -4
  137. package/dist/domains/index.js +0 -5
  138. package/dist/domains/manage/routes/agentToolRelations.js +0 -289
  139. package/dist/domains/run/agents/ModelFactory.d.ts +0 -63
  140. package/dist/domains/run/agents/ModelFactory.js +0 -194
  141. package/dist/domains/run/data/agent.d.ts +0 -7
  142. package/dist/domains/run/data/agent.js +0 -67
  143. package/dist/domains/run/services/evaluationRunConfigMatcher.d.ts +0 -4
  144. package/dist/domains/run/services/evaluationRunConfigMatcher.js +0 -7
  145. package/dist/domains/run/utils/cleanup.d.ts +0 -21
  146. package/dist/domains/run/utils/cleanup.js +0 -59
  147. package/dist/utils/tempApiKeys.d.ts +0 -17
  148. package/dist/utils/tempApiKeys.js +0 -26
  149. package/dist/utils/workflowApiHelpers.d.ts +0 -1
  150. package/dist/utils/workflowApiHelpers.js +0 -1
@@ -33,7 +33,7 @@ var ExecutionHandler = class {
33
33
  * @returns
34
34
  */
35
35
  async execute(params) {
36
- const { executionContext, conversationId, userMessage, initialAgentId, requestId, sseHelper, emitOperations, forwardedHeaders } = params;
36
+ const { executionContext, conversationId, userMessage, messageParts, initialAgentId, requestId, sseHelper, emitOperations, forwardedHeaders } = params;
37
37
  const { tenantId, projectId, project, agentId, apiKey, baseUrl, resolvedRef } = executionContext;
38
38
  registerStreamHelper(requestId, sseHelper);
39
39
  agentSessionManager.createSession(requestId, executionContext, conversationId);
@@ -178,13 +178,14 @@ var ExecutionHandler = class {
178
178
  forwardedHeaders
179
179
  };
180
180
  if (fromSubAgentId) messageMetadata.fromSubAgentId = fromSubAgentId;
181
+ const partsToSend = iterations === 1 && messageParts && messageParts.length > 0 ? messageParts : [{
182
+ kind: "text",
183
+ text: currentMessage
184
+ }];
181
185
  messageResponse = await a2aClient.sendMessage({
182
186
  message: {
183
187
  role: "user",
184
- parts: [{
185
- kind: "text",
186
- text: currentMessage
187
- }],
188
+ parts: partsToSend,
188
189
  messageId: `${requestId}-iter-${iterations}`,
189
190
  kind: "message",
190
191
  contextId: conversationId,
@@ -206,30 +207,45 @@ var ExecutionHandler = class {
206
207
  fullResponse: messageResponse
207
208
  }, `No response from agent ${currentAgentId} on iteration ${iterations} (error ${errorCount}/${this.MAX_ERRORS})`);
208
209
  if (errorCount >= this.MAX_ERRORS) {
209
- const errorMessage$1 = `Maximum error limit (${this.MAX_ERRORS}) reached`;
210
+ const errorMessage = `Maximum error limit (${this.MAX_ERRORS}) reached`;
210
211
  logger.error({
211
212
  maxErrors: this.MAX_ERRORS,
212
213
  errorCount
213
- }, errorMessage$1);
214
- await sseHelper.writeOperation(errorOp(errorMessage$1, currentAgentId || "system"));
215
- if (task) await updateTask(runDbClient_default)({
216
- taskId: task.id,
217
- data: {
218
- status: "failed",
219
- metadata: {
220
- ...task.metadata,
221
- failed_at: (/* @__PURE__ */ new Date()).toISOString(),
222
- error: errorMessage$1
223
- }
214
+ }, errorMessage);
215
+ return tracer.startActiveSpan("execution_handler.execute", {}, async (span) => {
216
+ try {
217
+ span.setAttributes({
218
+ "ai.response.content": `Hmm.. It seems I might be having some issues right now. Please clear the chat and try again.`,
219
+ "ai.response.timestamp": (/* @__PURE__ */ new Date()).toISOString(),
220
+ "subAgent.name": agent?.subAgents[currentAgentId]?.name,
221
+ "subAgent.id": currentAgentId
222
+ });
223
+ setSpanWithError(span, new Error(errorMessage));
224
+ await sseHelper.writeOperation(errorOp(errorMessage, currentAgentId || "system"));
225
+ if (task) await updateTask(runDbClient_default)({
226
+ taskId: task.id,
227
+ data: {
228
+ status: "failed",
229
+ metadata: {
230
+ ...task.metadata,
231
+ failed_at: (/* @__PURE__ */ new Date()).toISOString(),
232
+ error: errorMessage
233
+ }
234
+ }
235
+ });
236
+ await agentSessionManager.endSession(requestId);
237
+ unregisterStreamHelper(requestId);
238
+ return {
239
+ success: false,
240
+ error: errorMessage,
241
+ iterations
242
+ };
243
+ } finally {
244
+ span.end();
245
+ await new Promise((resolve) => setImmediate(resolve));
246
+ await flushBatchProcessor();
224
247
  }
225
248
  });
226
- await agentSessionManager.endSession(requestId);
227
- unregisterStreamHelper(requestId);
228
- return {
229
- success: false,
230
- error: errorMessage$1,
231
- iterations
232
- };
233
249
  }
234
250
  continue;
235
251
  }
@@ -391,12 +407,75 @@ var ExecutionHandler = class {
391
407
  errorCount
392
408
  }, `No valid response or transfer on iteration ${iterations} (error ${errorCount}/${this.MAX_ERRORS})`);
393
409
  if (errorCount >= this.MAX_ERRORS) {
394
- const errorMessage$1 = `Maximum error limit (${this.MAX_ERRORS}) reached`;
410
+ const errorMessage = `Maximum error limit (${this.MAX_ERRORS}) reached`;
395
411
  logger.error({
396
412
  maxErrors: this.MAX_ERRORS,
397
413
  errorCount
398
- }, errorMessage$1);
399
- await sseHelper.writeOperation(errorOp(errorMessage$1, currentAgentId || "system"));
414
+ }, errorMessage);
415
+ return tracer.startActiveSpan("execution_handler.execute", {}, async (span) => {
416
+ try {
417
+ span.setAttributes({
418
+ "ai.response.content": "Hmm.. It seems I might be having some issues right now. Please clear the chat and try again.",
419
+ "ai.response.timestamp": (/* @__PURE__ */ new Date()).toISOString(),
420
+ "subAgent.name": agent?.subAgents[currentAgentId]?.name,
421
+ "subAgent.id": currentAgentId
422
+ });
423
+ setSpanWithError(span, new Error(errorMessage));
424
+ await sseHelper.writeOperation(errorOp(errorMessage, currentAgentId || "system"));
425
+ if (task) await updateTask(runDbClient_default)({
426
+ taskId: task.id,
427
+ data: {
428
+ status: "failed",
429
+ metadata: {
430
+ ...task.metadata,
431
+ failed_at: /* @__PURE__ */ new Date(),
432
+ error: errorMessage
433
+ }
434
+ }
435
+ });
436
+ await agentSessionManager.endSession(requestId);
437
+ unregisterStreamHelper(requestId);
438
+ if (!params.datasetRunId) triggerConversationEvaluation({
439
+ tenantId,
440
+ projectId,
441
+ conversationId,
442
+ resolvedRef
443
+ }).catch((evalError) => {
444
+ logger.error({
445
+ error: evalError,
446
+ conversationId,
447
+ tenantId,
448
+ projectId
449
+ }, "Failed to trigger conversation evaluation (non-blocking)");
450
+ });
451
+ return {
452
+ success: false,
453
+ error: errorMessage,
454
+ iterations
455
+ };
456
+ } finally {
457
+ span.end();
458
+ await new Promise((resolve) => setImmediate(resolve));
459
+ await flushBatchProcessor();
460
+ }
461
+ });
462
+ }
463
+ }
464
+ const maxTransfersErrorMessage = `Maximum transfer limit (${maxTransfers}) reached without completion`;
465
+ logger.error({
466
+ maxTransfers,
467
+ iterations
468
+ }, maxTransfersErrorMessage);
469
+ return tracer.startActiveSpan("execution_handler.execute", {}, async (span) => {
470
+ try {
471
+ span.setAttributes({
472
+ "ai.response.content": "Hmm.. It seems I might be having some issues right now. Please clear the chat and try again.",
473
+ "ai.response.timestamp": (/* @__PURE__ */ new Date()).toISOString(),
474
+ "subAgent.name": agent?.subAgents[currentAgentId]?.name,
475
+ "subAgent.id": currentAgentId
476
+ });
477
+ setSpanWithError(span, new Error(maxTransfersErrorMessage));
478
+ await sseHelper.writeOperation(errorOp(maxTransfersErrorMessage, currentAgentId || "system"));
400
479
  if (task) await updateTask(runDbClient_default)({
401
480
  taskId: task.id,
402
481
  data: {
@@ -404,78 +483,64 @@ var ExecutionHandler = class {
404
483
  metadata: {
405
484
  ...task.metadata,
406
485
  failed_at: /* @__PURE__ */ new Date(),
407
- error: errorMessage$1
486
+ error: maxTransfersErrorMessage
408
487
  }
409
488
  }
410
489
  });
411
490
  await agentSessionManager.endSession(requestId);
412
491
  unregisterStreamHelper(requestId);
413
- if (!params.datasetRunId) triggerConversationEvaluation({
414
- tenantId,
415
- projectId,
416
- conversationId,
417
- resolvedRef
418
- }).catch((error) => {
419
- logger.error({
420
- error,
421
- conversationId,
422
- tenantId,
423
- projectId
424
- }, "Failed to trigger conversation evaluation (non-blocking)");
425
- });
426
492
  return {
427
493
  success: false,
428
- error: errorMessage$1,
494
+ error: maxTransfersErrorMessage,
429
495
  iterations
430
496
  };
431
- }
432
- }
433
- const errorMessage = `Maximum transfer limit (${maxTransfers}) reached without completion`;
434
- logger.error({
435
- maxTransfers,
436
- iterations
437
- }, errorMessage);
438
- await sseHelper.writeOperation(errorOp(errorMessage, currentAgentId || "system"));
439
- if (task) await updateTask(runDbClient_default)({
440
- taskId: task.id,
441
- data: {
442
- status: "failed",
443
- metadata: {
444
- ...task.metadata,
445
- failed_at: /* @__PURE__ */ new Date(),
446
- error: errorMessage
447
- }
497
+ } finally {
498
+ span.end();
499
+ await new Promise((resolve) => setImmediate(resolve));
500
+ await flushBatchProcessor();
448
501
  }
449
502
  });
450
- await agentSessionManager.endSession(requestId);
451
- unregisterStreamHelper(requestId);
452
- return {
453
- success: false,
454
- error: errorMessage,
455
- iterations
456
- };
457
503
  } catch (error) {
458
- logger.error({ error }, "Error in execution handler");
459
504
  const errorMessage = error instanceof Error ? error.message : "Unknown execution error";
460
- await sseHelper.writeOperation(errorOp(`Execution error: ${errorMessage}`, currentAgentId || "system"));
461
- if (task) await updateTask(runDbClient_default)({
462
- taskId: task.id,
463
- data: {
464
- status: "failed",
465
- metadata: {
466
- ...task.metadata,
467
- failed_at: /* @__PURE__ */ new Date(),
468
- error: errorMessage
469
- }
505
+ const errorStack = error instanceof Error ? error.stack : void 0;
506
+ logger.error({
507
+ errorMessage,
508
+ errorStack
509
+ }, "Error in execution handler");
510
+ return tracer.startActiveSpan("execution_handler.execute", {}, async (span) => {
511
+ try {
512
+ span.setAttributes({
513
+ "ai.response.content": "Hmm.. It seems I might be having some issues right now. Please clear the chat and try again.",
514
+ "ai.response.timestamp": (/* @__PURE__ */ new Date()).toISOString(),
515
+ "subAgent.name": agent?.subAgents[currentAgentId]?.name,
516
+ "subAgent.id": currentAgentId
517
+ });
518
+ setSpanWithError(span, error instanceof Error ? error : new Error(errorMessage));
519
+ await sseHelper.writeOperation(errorOp(`Execution error: ${errorMessage}`, currentAgentId || "system"));
520
+ if (task) await updateTask(runDbClient_default)({
521
+ taskId: task.id,
522
+ data: {
523
+ status: "failed",
524
+ metadata: {
525
+ ...task.metadata,
526
+ failed_at: /* @__PURE__ */ new Date(),
527
+ error: errorMessage
528
+ }
529
+ }
530
+ });
531
+ await agentSessionManager.endSession(requestId);
532
+ unregisterStreamHelper(requestId);
533
+ return {
534
+ success: false,
535
+ error: errorMessage,
536
+ iterations
537
+ };
538
+ } finally {
539
+ span.end();
540
+ await new Promise((resolve) => setImmediate(resolve));
541
+ await flushBatchProcessor();
470
542
  }
471
543
  });
472
- await agentSessionManager.endSession(requestId);
473
- unregisterStreamHelper(requestId);
474
- return {
475
- success: false,
476
- error: errorMessage,
477
- iterations
478
- };
479
544
  }
480
545
  }
481
546
  };
@@ -11,7 +11,7 @@ app.openapi(createRoute({
11
11
  method: "get",
12
12
  path: "/.well-known/agent.json",
13
13
  request: { headers: HeadersScopeSchema },
14
- tags: ["a2a"],
14
+ tags: ["A2A"],
15
15
  security: [{ bearerAuth: [] }],
16
16
  responses: {
17
17
  200: {
@@ -3,6 +3,7 @@ import runDbClient_default from "../../../data/db/runDbClient.js";
3
3
  import { contextValidationMiddleware } from "../context/validation.js";
4
4
  import { handleContextResolution } from "../context/context.js";
5
5
  import "../context/index.js";
6
+ import { toolApprovalUiBus } from "../services/ToolApprovalUiBus.js";
6
7
  import { errorOp } from "../utils/agent-operations.js";
7
8
  import { createSSEStreamHelper } from "../utils/stream-helpers.js";
8
9
  import { ExecutionHandler } from "../handlers/executionHandler.js";
@@ -17,7 +18,7 @@ const logger = getLogger$1("completionsHandler");
17
18
  const chatCompletionsRoute = createRoute({
18
19
  method: "post",
19
20
  path: "/completions",
20
- tags: ["chat"],
21
+ tags: ["Chat"],
21
22
  summary: "Create chat completion",
22
23
  description: "Creates a new chat completion with streaming SSE response using the configured agent",
23
24
  security: [{ bearerAuth: [] }],
@@ -222,9 +223,50 @@ app.openapi(chatCompletionsRoute, async (c) => {
222
223
  "database.operation": "insert"
223
224
  });
224
225
  return streamSSE(c, async (stream$1) => {
226
+ const chunkString = (s, size = 16) => {
227
+ const out = [];
228
+ for (let i = 0; i < s.length; i += size) out.push(s.slice(i, i + size));
229
+ return out;
230
+ };
231
+ let unsubscribe;
225
232
  try {
226
233
  const sseHelper = createSSEStreamHelper(stream$1, requestId, timestamp);
227
234
  await sseHelper.writeRole();
235
+ const seenToolCalls = /* @__PURE__ */ new Set();
236
+ const seenOutputs = /* @__PURE__ */ new Set();
237
+ unsubscribe = toolApprovalUiBus.subscribe(requestId, async (event) => {
238
+ if (event.type === "approval-needed") {
239
+ if (seenToolCalls.has(event.toolCallId)) return;
240
+ seenToolCalls.add(event.toolCallId);
241
+ await sseHelper.writeToolInputStart({
242
+ toolCallId: event.toolCallId,
243
+ toolName: event.toolName
244
+ });
245
+ const inputText = JSON.stringify(event.input ?? {});
246
+ for (const part of chunkString(inputText, 16)) await sseHelper.writeToolInputDelta({
247
+ toolCallId: event.toolCallId,
248
+ inputTextDelta: part
249
+ });
250
+ await sseHelper.writeToolInputAvailable({
251
+ toolCallId: event.toolCallId,
252
+ toolName: event.toolName,
253
+ input: event.input ?? {},
254
+ providerMetadata: event.providerMetadata
255
+ });
256
+ await sseHelper.writeToolApprovalRequest({
257
+ approvalId: event.approvalId,
258
+ toolCallId: event.toolCallId
259
+ });
260
+ } else if (event.type === "approval-resolved") {
261
+ if (seenOutputs.has(event.toolCallId)) return;
262
+ seenOutputs.add(event.toolCallId);
263
+ if (event.approved) await sseHelper.writeToolOutputAvailable({
264
+ toolCallId: event.toolCallId,
265
+ output: { status: "approved" }
266
+ });
267
+ else await sseHelper.writeToolOutputDenied({ toolCallId: event.toolCallId });
268
+ }
269
+ });
228
270
  logger.info({ subAgentId }, "Starting execution");
229
271
  const emitOperations = c.req.header("x-emit-operations") === "true";
230
272
  const forwardedHeaders = {};
@@ -275,6 +317,10 @@ app.openapi(chatCompletionsRoute, async (c) => {
275
317
  } catch (streamError) {
276
318
  logger.error({ streamError }, "Failed to write error to stream");
277
319
  }
320
+ } finally {
321
+ try {
322
+ unsubscribe?.();
323
+ } catch (_e) {}
278
324
  }
279
325
  });
280
326
  });
@@ -4,6 +4,7 @@ import { contextValidationMiddleware } from "../context/validation.js";
4
4
  import { handleContextResolution } from "../context/context.js";
5
5
  import "../context/index.js";
6
6
  import { pendingToolApprovalManager } from "../services/PendingToolApprovalManager.js";
7
+ import { toolApprovalUiBus } from "../services/ToolApprovalUiBus.js";
7
8
  import { errorOp } from "../utils/agent-operations.js";
8
9
  import { createBufferingStreamHelper, createVercelStreamHelper } from "../utils/stream-helpers.js";
9
10
  import { ExecutionHandler } from "../handlers/executionHandler.js";
@@ -19,7 +20,7 @@ const logger = getLogger$1("chatDataStream");
19
20
  const chatDataStreamRoute = createRoute({
20
21
  method: "post",
21
22
  path: "/chat",
22
- tags: ["chat"],
23
+ tags: ["Chat"],
23
24
  summary: "Chat (Vercel Streaming Protocol)",
24
25
  description: "Chat completion endpoint streaming with Vercel data stream protocol.",
25
26
  security: [{ bearerAuth: [] }],
@@ -34,16 +35,31 @@ const chatDataStreamRoute = createRoute({
34
35
  "tool"
35
36
  ]),
36
37
  content: z.any(),
37
- parts: z.array(z.object({
38
- type: z.union([z.enum([
39
- "text",
40
- "image",
41
- "audio",
42
- "video",
43
- "file"
44
- ]), z.string().regex(/^data-/, "Type must start with \"data-\"")]),
45
- text: z.string().optional()
46
- })).optional()
38
+ parts: z.array(z.union([
39
+ z.object({
40
+ type: z.union([z.enum([
41
+ "text",
42
+ "image",
43
+ "audio",
44
+ "video",
45
+ "file"
46
+ ]), z.string().regex(/^data-/, "Type must start with \"data-\"")]),
47
+ text: z.string().optional()
48
+ }),
49
+ z.object({
50
+ type: z.string().regex(/^tool-/, "Type must start with \"tool-\""),
51
+ toolCallId: z.string(),
52
+ state: z.any(),
53
+ approval: z.object({
54
+ id: z.string(),
55
+ approved: z.boolean().optional(),
56
+ reason: z.string().optional()
57
+ }).optional(),
58
+ input: z.any().optional(),
59
+ callProviderMetadata: z.any().optional()
60
+ }),
61
+ z.object({ type: z.literal("step-start") })
62
+ ])).optional()
47
63
  })),
48
64
  id: z.string().optional(),
49
65
  conversationId: z.string().optional(),
@@ -74,7 +90,39 @@ app.openapi(chatDataStreamRoute, async (c) => {
74
90
  agentId
75
91
  }, "Extracted chatDataStream parameters");
76
92
  const body = c.get("requestBody") || {};
77
- const conversationId = body.conversationId || getConversationId();
93
+ const approvalPart = (body.messages || []).flatMap((m) => m?.parts || []).find((p) => p?.state === "approval-responded" && typeof p?.toolCallId === "string");
94
+ const isApprovalResponse = !!approvalPart;
95
+ const conversationId = isApprovalResponse ? body.conversationId : body.conversationId || getConversationId();
96
+ if (isApprovalResponse) {
97
+ if (!conversationId) return c.json({
98
+ success: false,
99
+ error: "conversationId is required for approval response"
100
+ }, 400);
101
+ const toolCallId = approvalPart.toolCallId;
102
+ const approved = !!approvalPart.approval?.approved;
103
+ const reason = approvalPart.approval?.reason;
104
+ if (!await getConversation(runDbClient_default)({
105
+ scopes: {
106
+ tenantId,
107
+ projectId
108
+ },
109
+ conversationId
110
+ })) return c.json({
111
+ success: false,
112
+ error: "Conversation not found"
113
+ }, 404);
114
+ if (!(approved ? pendingToolApprovalManager.approveToolCall(toolCallId) : pendingToolApprovalManager.denyToolCall(toolCallId, reason))) return c.json({
115
+ success: true,
116
+ toolCallId,
117
+ approved,
118
+ alreadyProcessed: true
119
+ });
120
+ return c.json({
121
+ success: true,
122
+ toolCallId,
123
+ approved
124
+ });
125
+ }
78
126
  const targetTenantId = c.req.header("x-target-tenant-id");
79
127
  const targetProjectId = c.req.header("x-target-project-id");
80
128
  const targetAgentId = c.req.header("x-target-agent-id");
@@ -227,16 +275,58 @@ app.openapi(chatDataStreamRoute, async (c) => {
227
275
  }
228
276
  const dataStream = createUIMessageStream({ execute: async ({ writer }) => {
229
277
  const streamHelper = createVercelStreamHelper(writer);
278
+ let unsubscribe;
230
279
  try {
231
280
  const emitOperations = c.req.header("x-emit-operations") === "true";
232
281
  const executionHandler = new ExecutionHandler();
233
282
  const datasetRunId = c.req.header("x-inkeep-dataset-run-id");
283
+ const requestId = `chatds-${Date.now()}`;
284
+ const chunkString = (s, size = 16) => {
285
+ const out = [];
286
+ for (let i = 0; i < s.length; i += size) out.push(s.slice(i, i + size));
287
+ return out;
288
+ };
289
+ const seenToolCalls = /* @__PURE__ */ new Set();
290
+ const seenOutputs = /* @__PURE__ */ new Set();
291
+ unsubscribe = toolApprovalUiBus.subscribe(requestId, async (event) => {
292
+ if (event.type === "approval-needed") {
293
+ if (seenToolCalls.has(event.toolCallId)) return;
294
+ seenToolCalls.add(event.toolCallId);
295
+ await streamHelper.writeToolInputStart({
296
+ toolCallId: event.toolCallId,
297
+ toolName: event.toolName
298
+ });
299
+ const inputText = JSON.stringify(event.input ?? {});
300
+ for (const part of chunkString(inputText, 16)) await streamHelper.writeToolInputDelta({
301
+ toolCallId: event.toolCallId,
302
+ inputTextDelta: part
303
+ });
304
+ await streamHelper.writeToolInputAvailable({
305
+ toolCallId: event.toolCallId,
306
+ toolName: event.toolName,
307
+ input: event.input ?? {},
308
+ providerMetadata: event.providerMetadata
309
+ });
310
+ await streamHelper.writeToolApprovalRequest({
311
+ approvalId: event.approvalId,
312
+ toolCallId: event.toolCallId
313
+ });
314
+ } else if (event.type === "approval-resolved") {
315
+ if (seenOutputs.has(event.toolCallId)) return;
316
+ seenOutputs.add(event.toolCallId);
317
+ if (event.approved) await streamHelper.writeToolOutputAvailable({
318
+ toolCallId: event.toolCallId,
319
+ output: { status: "approved" }
320
+ });
321
+ else await streamHelper.writeToolOutputDenied({ toolCallId: event.toolCallId });
322
+ }
323
+ });
234
324
  if (!(await executionHandler.execute({
235
325
  executionContext,
236
326
  conversationId,
237
327
  userMessage: userText,
238
328
  initialAgentId: subAgentId,
239
- requestId: `chatds-${Date.now()}`,
329
+ requestId,
240
330
  sseHelper: streamHelper,
241
331
  emitOperations,
242
332
  datasetRunId: datasetRunId || void 0,
@@ -246,6 +336,9 @@ app.openapi(chatDataStreamRoute, async (c) => {
246
336
  logger.error({ err }, "Streaming error");
247
337
  await streamHelper.writeOperation(errorOp("Internal server error", "system"));
248
338
  } finally {
339
+ try {
340
+ unsubscribe?.();
341
+ } catch (_e) {}
249
342
  if ("cleanup" in streamHelper && typeof streamHelper.cleanup === "function") streamHelper.cleanup();
250
343
  }
251
344
  } });
@@ -272,7 +365,7 @@ app.openapi(chatDataStreamRoute, async (c) => {
272
365
  const toolApprovalRoute = createRoute({
273
366
  method: "post",
274
367
  path: "/tool-approvals",
275
- tags: ["chat"],
368
+ tags: ["Chat"],
276
369
  summary: "Approve or deny tool execution",
277
370
  description: "Handle user approval/denial of tool execution requests during conversations",
278
371
  security: [{ bearerAuth: [] }],