@inkeep/agents-api 0.42.0 → 0.44.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 (138) hide show
  1. package/dist/.well-known/workflow/v1/manifest.debug.json +6 -6
  2. package/dist/.well-known/workflow/v1/step.cjs +220467 -203416
  3. package/dist/_virtual/rolldown_runtime.js +7 -0
  4. package/dist/createApp.js +47 -17
  5. package/dist/domains/evals/api/.well-known/workflow/v1/flow.d.ts +4 -0
  6. package/dist/domains/evals/api/.well-known/workflow/v1/flow.js +12 -0
  7. package/dist/domains/evals/api/.well-known/workflow/v1/step.d.ts +4 -0
  8. package/dist/domains/evals/api/.well-known/workflow/v1/step.js +12 -0
  9. package/dist/domains/evals/routes/datasetTriggers.d.ts +2 -2
  10. package/dist/domains/evals/routes/index.d.ts +2 -2
  11. package/dist/domains/evals/scripts/build-workflow.js +2 -2
  12. package/dist/domains/evals/workflow/world.js +3 -2
  13. package/dist/domains/manage/index.js +6 -2
  14. package/dist/domains/manage/routes/agent.js +7 -4
  15. package/dist/domains/manage/routes/agentFull.js +9 -6
  16. package/dist/domains/manage/routes/apiKeys.js +1 -2
  17. package/dist/domains/manage/routes/artifactComponents.js +5 -5
  18. package/dist/domains/manage/routes/cliAuth.js +3 -3
  19. package/dist/domains/manage/routes/contextConfigs.js +5 -5
  20. package/dist/domains/manage/routes/conversations.d.ts +2 -2
  21. package/dist/domains/manage/routes/credentialStores.js +2 -2
  22. package/dist/domains/manage/routes/credentials.js +6 -7
  23. package/dist/domains/manage/routes/dataComponents.js +6 -7
  24. package/dist/domains/manage/routes/externalAgents.js +1 -2
  25. package/dist/domains/manage/routes/github.d.ts +16 -0
  26. package/dist/domains/manage/routes/github.js +511 -0
  27. package/dist/domains/manage/routes/index.d.ts +2 -2
  28. package/dist/domains/manage/routes/index.js +4 -0
  29. package/dist/domains/manage/routes/invitations.js +1 -1
  30. package/dist/domains/manage/routes/mcp.d.ts +2 -2
  31. package/dist/domains/manage/routes/{agentToolRelations.d.ts → mcpToolGithubAccess.d.ts} +1 -1
  32. package/dist/domains/manage/routes/mcpToolGithubAccess.js +205 -0
  33. package/dist/domains/manage/routes/playgroundToken.js +1 -2
  34. package/dist/domains/manage/routes/projectFull.js +33 -11
  35. package/dist/domains/manage/routes/projectGithubAccess.d.ts +9 -0
  36. package/dist/domains/manage/routes/projectGithubAccess.js +167 -0
  37. package/dist/domains/manage/routes/projectMembers.js +12 -44
  38. package/dist/domains/manage/routes/projectPermissions.js +11 -11
  39. package/dist/domains/manage/routes/projects.js +15 -18
  40. package/dist/domains/manage/routes/signoz.d.ts +2 -2
  41. package/dist/domains/manage/routes/signoz.js +7 -4
  42. package/dist/domains/manage/routes/subAgentArtifactComponents.js +5 -5
  43. package/dist/domains/manage/routes/subAgentDataComponents.js +5 -5
  44. package/dist/domains/manage/routes/subAgentExternalAgentRelations.js +5 -5
  45. package/dist/domains/manage/routes/subAgentFunctionTools.js +5 -5
  46. package/dist/domains/manage/routes/subAgentRelations.js +6 -6
  47. package/dist/domains/manage/routes/subAgentTeamAgentRelations.js +6 -6
  48. package/dist/domains/manage/routes/subAgentToolRelations.js +6 -6
  49. package/dist/domains/manage/routes/subAgents.js +5 -5
  50. package/dist/domains/manage/routes/tools.js +28 -5
  51. package/dist/domains/manage/routes/triggers.js +49 -24
  52. package/dist/domains/manage/routes/userOrganizations.js +4 -4
  53. package/dist/domains/manage/routes/userProjectMemberships.d.ts +9 -0
  54. package/dist/domains/manage/routes/userProjectMemberships.js +44 -0
  55. package/dist/domains/mcp/routes/mcp.d.ts +7 -0
  56. package/dist/domains/mcp/routes/mcp.js +45 -0
  57. package/dist/domains/run/agents/Agent.d.ts +1 -0
  58. package/dist/domains/run/agents/Agent.js +235 -45
  59. package/dist/domains/run/agents/relationTools.d.ts +2 -2
  60. package/dist/domains/run/constants/execution-limits/defaults.d.ts +1 -1
  61. package/dist/domains/run/constants/execution-limits/defaults.js +1 -1
  62. package/dist/domains/run/constants/execution-limits/index.d.ts +1 -1
  63. package/dist/domains/run/context/ContextFetcher.js +8 -7
  64. package/dist/domains/run/context/validation.d.ts +1 -1
  65. package/dist/domains/run/handlers/executionHandler.js +143 -79
  66. package/dist/domains/run/routes/agents.js +1 -1
  67. package/dist/domains/run/routes/chat.js +47 -1
  68. package/dist/domains/run/routes/chatDataStream.js +107 -14
  69. package/dist/domains/run/routes/webhooks.js +40 -348
  70. package/dist/domains/run/services/AgentSession.d.ts +3 -0
  71. package/dist/domains/run/services/AgentSession.js +14 -1
  72. package/dist/domains/run/services/ToolApprovalUiBus.d.ts +28 -0
  73. package/dist/domains/run/services/ToolApprovalUiBus.js +44 -0
  74. package/dist/domains/run/services/TriggerService.d.ts +31 -0
  75. package/dist/domains/run/services/TriggerService.js +545 -0
  76. package/dist/domains/run/tools/NativeSandboxExecutor.d.ts +3 -2
  77. package/dist/domains/run/tools/NativeSandboxExecutor.js +76 -48
  78. package/dist/domains/run/tools/SandboxExecutorFactory.d.ts +11 -1
  79. package/dist/domains/run/tools/SandboxExecutorFactory.js +27 -3
  80. package/dist/domains/run/tools/VercelSandboxExecutor.d.ts +3 -11
  81. package/dist/domains/run/tools/VercelSandboxExecutor.js +137 -127
  82. package/dist/domains/run/tools/sandbox-utils.js +1 -1
  83. package/dist/domains/run/types/executionContext.js +3 -1
  84. package/dist/domains/run/utils/stream-helpers.d.ts +134 -0
  85. package/dist/domains/run/utils/stream-helpers.js +182 -0
  86. package/dist/domains/run/utils/token-estimator.d.ts +2 -2
  87. package/dist/env.d.ts +12 -2
  88. package/dist/env.js +37 -32
  89. package/dist/factory.d.ts +31 -31
  90. package/dist/factory.js +4 -10
  91. package/dist/index.d.ts +30 -29
  92. package/dist/index.js +3 -5
  93. package/dist/middleware/branchScopedDb.d.ts +1 -1
  94. package/dist/middleware/cors.js +1 -1
  95. package/dist/middleware/evalsAuth.d.ts +2 -2
  96. package/dist/middleware/manageAuth.d.ts +2 -2
  97. package/dist/middleware/projectAccess.d.ts +4 -20
  98. package/dist/middleware/projectAccess.js +7 -49
  99. package/dist/middleware/projectConfig.d.ts +3 -3
  100. package/dist/middleware/ref.d.ts +1 -1
  101. package/dist/middleware/requirePermission.d.ts +2 -2
  102. package/dist/middleware/requirePermission.js +1 -2
  103. package/dist/middleware/runAuth.d.ts +4 -4
  104. package/dist/middleware/sessionAuth.d.ts +3 -3
  105. package/dist/middleware/sessionAuth.js +1 -2
  106. package/dist/middleware/tenantAccess.d.ts +2 -2
  107. package/dist/middleware/tenantAccess.js +4 -4
  108. package/dist/middleware/tracing.d.ts +3 -3
  109. package/dist/openapi.d.ts +36 -1
  110. package/dist/openapi.js +40 -95
  111. package/dist/routes/healthChecks.d.ts +10 -0
  112. package/dist/routes/healthChecks.js +75 -0
  113. package/dist/types/app.d.ts +2 -0
  114. package/dist/types/runExecutionContext.js +3 -1
  115. package/dist/utils/healthChecks.d.ts +8 -0
  116. package/dist/utils/healthChecks.js +38 -0
  117. package/dist/utils/signozHelpers.d.ts +2 -2
  118. package/dist/utils/signozHelpers.js +15 -3
  119. package/package.json +8 -9
  120. package/dist/domains/evals/services/startEvaluation.d.ts +0 -19
  121. package/dist/domains/evals/services/startEvaluation.js +0 -18
  122. package/dist/domains/index.d.ts +0 -4
  123. package/dist/domains/index.js +0 -5
  124. package/dist/domains/manage/routes/agentToolRelations.js +0 -289
  125. package/dist/domains/run/agents/ModelFactory.d.ts +0 -63
  126. package/dist/domains/run/agents/ModelFactory.js +0 -194
  127. package/dist/domains/run/data/agent.d.ts +0 -7
  128. package/dist/domains/run/data/agent.js +0 -67
  129. package/dist/domains/run/services/evaluationRunConfigMatcher.d.ts +0 -4
  130. package/dist/domains/run/services/evaluationRunConfigMatcher.js +0 -7
  131. package/dist/domains/run/utils/cleanup.d.ts +0 -21
  132. package/dist/domains/run/utils/cleanup.js +0 -59
  133. package/dist/initialization.d.ts +0 -6
  134. package/dist/initialization.js +0 -65
  135. package/dist/utils/tempApiKeys.d.ts +0 -17
  136. package/dist/utils/tempApiKeys.js +0 -26
  137. package/dist/utils/workflowApiHelpers.d.ts +0 -1
  138. package/dist/utils/workflowApiHelpers.js +0 -1
@@ -207,30 +207,45 @@ var ExecutionHandler = class {
207
207
  fullResponse: messageResponse
208
208
  }, `No response from agent ${currentAgentId} on iteration ${iterations} (error ${errorCount}/${this.MAX_ERRORS})`);
209
209
  if (errorCount >= this.MAX_ERRORS) {
210
- const errorMessage$1 = `Maximum error limit (${this.MAX_ERRORS}) reached`;
210
+ const errorMessage = `Maximum error limit (${this.MAX_ERRORS}) reached`;
211
211
  logger.error({
212
212
  maxErrors: this.MAX_ERRORS,
213
213
  errorCount
214
- }, errorMessage$1);
215
- await sseHelper.writeOperation(errorOp(errorMessage$1, currentAgentId || "system"));
216
- if (task) await updateTask(runDbClient_default)({
217
- taskId: task.id,
218
- data: {
219
- status: "failed",
220
- metadata: {
221
- ...task.metadata,
222
- failed_at: (/* @__PURE__ */ new Date()).toISOString(),
223
- error: errorMessage$1
224
- }
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();
225
247
  }
226
248
  });
227
- await agentSessionManager.endSession(requestId);
228
- unregisterStreamHelper(requestId);
229
- return {
230
- success: false,
231
- error: errorMessage$1,
232
- iterations
233
- };
234
249
  }
235
250
  continue;
236
251
  }
@@ -392,12 +407,75 @@ var ExecutionHandler = class {
392
407
  errorCount
393
408
  }, `No valid response or transfer on iteration ${iterations} (error ${errorCount}/${this.MAX_ERRORS})`);
394
409
  if (errorCount >= this.MAX_ERRORS) {
395
- const errorMessage$1 = `Maximum error limit (${this.MAX_ERRORS}) reached`;
410
+ const errorMessage = `Maximum error limit (${this.MAX_ERRORS}) reached`;
396
411
  logger.error({
397
412
  maxErrors: this.MAX_ERRORS,
398
413
  errorCount
399
- }, errorMessage$1);
400
- 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"));
401
479
  if (task) await updateTask(runDbClient_default)({
402
480
  taskId: task.id,
403
481
  data: {
@@ -405,78 +483,64 @@ var ExecutionHandler = class {
405
483
  metadata: {
406
484
  ...task.metadata,
407
485
  failed_at: /* @__PURE__ */ new Date(),
408
- error: errorMessage$1
486
+ error: maxTransfersErrorMessage
409
487
  }
410
488
  }
411
489
  });
412
490
  await agentSessionManager.endSession(requestId);
413
491
  unregisterStreamHelper(requestId);
414
- if (!params.datasetRunId) triggerConversationEvaluation({
415
- tenantId,
416
- projectId,
417
- conversationId,
418
- resolvedRef
419
- }).catch((error) => {
420
- logger.error({
421
- error,
422
- conversationId,
423
- tenantId,
424
- projectId
425
- }, "Failed to trigger conversation evaluation (non-blocking)");
426
- });
427
492
  return {
428
493
  success: false,
429
- error: errorMessage$1,
494
+ error: maxTransfersErrorMessage,
430
495
  iterations
431
496
  };
432
- }
433
- }
434
- const errorMessage = `Maximum transfer limit (${maxTransfers}) reached without completion`;
435
- logger.error({
436
- maxTransfers,
437
- iterations
438
- }, errorMessage);
439
- await sseHelper.writeOperation(errorOp(errorMessage, currentAgentId || "system"));
440
- if (task) await updateTask(runDbClient_default)({
441
- taskId: task.id,
442
- data: {
443
- status: "failed",
444
- metadata: {
445
- ...task.metadata,
446
- failed_at: /* @__PURE__ */ new Date(),
447
- error: errorMessage
448
- }
497
+ } finally {
498
+ span.end();
499
+ await new Promise((resolve) => setImmediate(resolve));
500
+ await flushBatchProcessor();
449
501
  }
450
502
  });
451
- await agentSessionManager.endSession(requestId);
452
- unregisterStreamHelper(requestId);
453
- return {
454
- success: false,
455
- error: errorMessage,
456
- iterations
457
- };
458
503
  } catch (error) {
459
- logger.error({ error }, "Error in execution handler");
460
504
  const errorMessage = error instanceof Error ? error.message : "Unknown execution error";
461
- await sseHelper.writeOperation(errorOp(`Execution error: ${errorMessage}`, currentAgentId || "system"));
462
- if (task) await updateTask(runDbClient_default)({
463
- taskId: task.id,
464
- data: {
465
- status: "failed",
466
- metadata: {
467
- ...task.metadata,
468
- failed_at: /* @__PURE__ */ new Date(),
469
- error: errorMessage
470
- }
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();
471
542
  }
472
543
  });
473
- await agentSessionManager.endSession(requestId);
474
- unregisterStreamHelper(requestId);
475
- return {
476
- success: false,
477
- error: errorMessage,
478
- iterations
479
- };
480
544
  }
481
545
  }
482
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: [] }],