@inkeep/agents-api 0.0.0-dev-20260122001454 → 0.0.0-dev-20260122004923
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/.well-known/workflow/v1/manifest.debug.json +14 -14
- package/dist/.well-known/workflow/v1/step.cjs +3 -1
- package/dist/createApp.d.ts +2 -2
- package/dist/domains/evals/routes/datasetTriggers.d.ts +2 -2
- package/dist/domains/evals/routes/index.d.ts +2 -2
- package/dist/domains/evals/workflow/routes.d.ts +2 -2
- package/dist/domains/manage/routes/conversations.d.ts +2 -2
- package/dist/domains/manage/routes/index.d.ts +2 -2
- package/dist/domains/manage/routes/mcp.d.ts +2 -2
- package/dist/domains/run/agents/Agent.d.ts +1 -0
- package/dist/domains/run/agents/Agent.js +100 -29
- package/dist/domains/run/routes/chat.js +46 -0
- package/dist/domains/run/routes/chatDataStream.js +105 -12
- package/dist/domains/run/services/ToolApprovalUiBus.d.ts +28 -0
- package/dist/domains/run/services/ToolApprovalUiBus.js +44 -0
- package/dist/domains/run/utils/stream-helpers.d.ts +134 -0
- package/dist/domains/run/utils/stream-helpers.js +182 -0
- package/dist/factory.d.ts +261 -261
- package/dist/index.d.ts +261 -261
- package/dist/middleware/evalsAuth.d.ts +2 -2
- package/dist/middleware/manageAuth.d.ts +2 -2
- package/dist/middleware/projectAccess.d.ts +2 -2
- package/dist/middleware/projectConfig.d.ts +3 -3
- package/dist/middleware/requirePermission.d.ts +2 -2
- package/dist/middleware/runAuth.d.ts +4 -4
- package/dist/middleware/sessionAuth.d.ts +3 -3
- package/dist/middleware/tenantAccess.d.ts +2 -2
- package/dist/middleware/tracing.d.ts +3 -3
- package/package.json +3 -3
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"steps": {
|
|
3
|
+
"src/domains/evals/workflow/functions/runDatasetItem.ts": {
|
|
4
|
+
"callChatApiStep": {
|
|
5
|
+
"stepId": "step//src/domains/evals/workflow/functions/runDatasetItem.ts//callChatApiStep"
|
|
6
|
+
},
|
|
7
|
+
"createRelationStep": {
|
|
8
|
+
"stepId": "step//src/domains/evals/workflow/functions/runDatasetItem.ts//createRelationStep"
|
|
9
|
+
},
|
|
10
|
+
"executeEvaluatorStep": {
|
|
11
|
+
"stepId": "step//src/domains/evals/workflow/functions/runDatasetItem.ts//executeEvaluatorStep"
|
|
12
|
+
},
|
|
13
|
+
"logStep": {
|
|
14
|
+
"stepId": "step//src/domains/evals/workflow/functions/runDatasetItem.ts//logStep"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
3
17
|
"node_modules/.pnpm/workflow@4.0.1-beta.33_@aws-sdk+client-sts@3.970.0_@opentelemetry+api@1.9.0_@types+reac_5c488396978166b4f12e99cb3aa4a769/node_modules/workflow/dist/internal/builtins.js": {
|
|
4
18
|
"__builtin_response_array_buffer": {
|
|
5
19
|
"stepId": "__builtin_response_array_buffer"
|
|
@@ -24,20 +38,6 @@
|
|
|
24
38
|
"logStep": {
|
|
25
39
|
"stepId": "step//src/domains/evals/workflow/functions/evaluateConversation.ts//logStep"
|
|
26
40
|
}
|
|
27
|
-
},
|
|
28
|
-
"src/domains/evals/workflow/functions/runDatasetItem.ts": {
|
|
29
|
-
"callChatApiStep": {
|
|
30
|
-
"stepId": "step//src/domains/evals/workflow/functions/runDatasetItem.ts//callChatApiStep"
|
|
31
|
-
},
|
|
32
|
-
"createRelationStep": {
|
|
33
|
-
"stepId": "step//src/domains/evals/workflow/functions/runDatasetItem.ts//createRelationStep"
|
|
34
|
-
},
|
|
35
|
-
"executeEvaluatorStep": {
|
|
36
|
-
"stepId": "step//src/domains/evals/workflow/functions/runDatasetItem.ts//executeEvaluatorStep"
|
|
37
|
-
},
|
|
38
|
-
"logStep": {
|
|
39
|
-
"stepId": "step//src/domains/evals/workflow/functions/runDatasetItem.ts//logStep"
|
|
40
|
-
}
|
|
41
41
|
}
|
|
42
42
|
},
|
|
43
43
|
"workflows": {
|
|
@@ -127829,7 +127829,9 @@ var FunctionToolInsertSchema = createInsertSchema2(functionTools).extend({
|
|
|
127829
127829
|
id: resourceIdSchema
|
|
127830
127830
|
});
|
|
127831
127831
|
var FunctionToolUpdateSchema = FunctionToolInsertSchema.partial();
|
|
127832
|
-
var FunctionToolApiSelectSchema = createApiSchema(FunctionToolSelectSchema).
|
|
127832
|
+
var FunctionToolApiSelectSchema = createApiSchema(FunctionToolSelectSchema).extend({
|
|
127833
|
+
relationshipId: external_exports.string().optional()
|
|
127834
|
+
}).openapi("FunctionTool");
|
|
127833
127835
|
var FunctionToolApiInsertSchema = createAgentScopedApiInsertSchema(FunctionToolInsertSchema).openapi("FunctionToolCreate");
|
|
127834
127836
|
var FunctionToolApiUpdateSchema = createApiUpdateSchema(FunctionToolUpdateSchema).openapi("FunctionToolUpdate");
|
|
127835
127837
|
var SubAgentFunctionToolRelationSelectSchema = createSelectSchema2(subAgentFunctionToolRelations);
|
package/dist/createApp.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { AppConfig } from "./types/app.js";
|
|
2
2
|
import "./types/index.js";
|
|
3
3
|
import { Hono } from "hono";
|
|
4
|
-
import * as
|
|
4
|
+
import * as hono_types1 from "hono/types";
|
|
5
5
|
|
|
6
6
|
//#region src/createApp.d.ts
|
|
7
7
|
declare const isWebhookRoute: (path: string) => boolean;
|
|
8
|
-
declare function createAgentsHono(config: AppConfig): Hono<
|
|
8
|
+
declare function createAgentsHono(config: AppConfig): Hono<hono_types1.BlankEnv, hono_types1.BlankSchema, "/">;
|
|
9
9
|
//#endregion
|
|
10
10
|
export { createAgentsHono, isWebhookRoute };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { OpenAPIHono } from "@hono/zod-openapi";
|
|
2
|
-
import * as
|
|
2
|
+
import * as hono14 from "hono";
|
|
3
3
|
|
|
4
4
|
//#region src/domains/evals/routes/datasetTriggers.d.ts
|
|
5
|
-
declare const app: OpenAPIHono<
|
|
5
|
+
declare const app: OpenAPIHono<hono14.Env, {}, "/">;
|
|
6
6
|
//#endregion
|
|
7
7
|
export { app as default };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { OpenAPIHono } from "@hono/zod-openapi";
|
|
2
|
-
import * as
|
|
2
|
+
import * as hono15 from "hono";
|
|
3
3
|
|
|
4
4
|
//#region src/domains/evals/routes/index.d.ts
|
|
5
|
-
declare const app: OpenAPIHono<
|
|
5
|
+
declare const app: OpenAPIHono<hono15.Env, {}, "/">;
|
|
6
6
|
//#endregion
|
|
7
7
|
export { app as default };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Hono } from "hono";
|
|
2
|
-
import * as
|
|
2
|
+
import * as hono_types5 from "hono/types";
|
|
3
3
|
|
|
4
4
|
//#region src/domains/evals/workflow/routes.d.ts
|
|
5
|
-
declare const workflowRoutes: Hono<
|
|
5
|
+
declare const workflowRoutes: Hono<hono_types5.BlankEnv, hono_types5.BlankSchema, "/">;
|
|
6
6
|
//#endregion
|
|
7
7
|
export { workflowRoutes };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { OpenAPIHono } from "@hono/zod-openapi";
|
|
2
|
-
import * as
|
|
2
|
+
import * as hono16 from "hono";
|
|
3
3
|
|
|
4
4
|
//#region src/domains/manage/routes/conversations.d.ts
|
|
5
|
-
declare const app: OpenAPIHono<
|
|
5
|
+
declare const app: OpenAPIHono<hono16.Env, {}, "/">;
|
|
6
6
|
//#endregion
|
|
7
7
|
export { app as default };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { OpenAPIHono } from "@hono/zod-openapi";
|
|
2
|
-
import * as
|
|
2
|
+
import * as hono17 from "hono";
|
|
3
3
|
|
|
4
4
|
//#region src/domains/manage/routes/index.d.ts
|
|
5
|
-
declare const app: OpenAPIHono<
|
|
5
|
+
declare const app: OpenAPIHono<hono17.Env, {}, "/">;
|
|
6
6
|
//#endregion
|
|
7
7
|
export { app as default };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Hono } from "hono";
|
|
2
|
-
import * as
|
|
2
|
+
import * as hono_types8 from "hono/types";
|
|
3
3
|
|
|
4
4
|
//#region src/domains/manage/routes/mcp.d.ts
|
|
5
|
-
declare const app: Hono<
|
|
5
|
+
declare const app: Hono<hono_types8.BlankEnv, hono_types8.BlankSchema, "/">;
|
|
6
6
|
//#endregion
|
|
7
7
|
export { app as default };
|
|
@@ -99,6 +99,7 @@ declare class Agent {
|
|
|
99
99
|
private mcpConnectionLocks;
|
|
100
100
|
private currentCompressor;
|
|
101
101
|
private executionContext;
|
|
102
|
+
private functionToolRelationshipIdByName;
|
|
102
103
|
constructor(config: AgentConfig, executionContext: FullExecutionContext, credentialStoreRegistry?: CredentialStoreRegistry);
|
|
103
104
|
/**
|
|
104
105
|
* Get the maximum number of generation steps for this agent
|
|
@@ -15,6 +15,7 @@ import { IncrementalStreamParser } from "../services/IncrementalStreamParser.js"
|
|
|
15
15
|
import { MidGenerationCompressor } from "../services/MidGenerationCompressor.js";
|
|
16
16
|
import { pendingToolApprovalManager } from "../services/PendingToolApprovalManager.js";
|
|
17
17
|
import { ResponseFormatter } from "../services/ResponseFormatter.js";
|
|
18
|
+
import { toolApprovalUiBus } from "../services/ToolApprovalUiBus.js";
|
|
18
19
|
import { generateToolId } from "../utils/agent-operations.js";
|
|
19
20
|
import { jsonSchemaToZod } from "../utils/data-component-schema.js";
|
|
20
21
|
import { ArtifactCreateSchema, ArtifactReferenceSchema } from "../utils/artifact-component-schema.js";
|
|
@@ -66,6 +67,7 @@ var Agent = class {
|
|
|
66
67
|
mcpConnectionLocks = /* @__PURE__ */ new Map();
|
|
67
68
|
currentCompressor = null;
|
|
68
69
|
executionContext;
|
|
70
|
+
functionToolRelationshipIdByName = /* @__PURE__ */ new Map();
|
|
69
71
|
constructor(config, executionContext, credentialStoreRegistry) {
|
|
70
72
|
this.artifactComponents = config.artifactComponents || [];
|
|
71
73
|
this.executionContext = executionContext;
|
|
@@ -135,6 +137,7 @@ var Agent = class {
|
|
|
135
137
|
if (tool$1.config.mcp.activeTools?.includes(toolName)) return true;
|
|
136
138
|
return tool$1.name === toolName;
|
|
137
139
|
}))?.relationshipId;
|
|
140
|
+
if (toolType === "tool") return this.functionToolRelationshipIdByName.get(toolName);
|
|
138
141
|
if (toolType === "delegation") return this.config.delegateRelations.find((relation) => this.#createRelationToolName("delegate", relation.config.id) === toolName)?.config.relationId;
|
|
139
142
|
}
|
|
140
143
|
/**
|
|
@@ -221,6 +224,12 @@ var Agent = class {
|
|
|
221
224
|
execute: async (args, context$1) => {
|
|
222
225
|
const startTime = Date.now();
|
|
223
226
|
const toolCallId = context$1?.toolCallId || generateToolId();
|
|
227
|
+
const streamHelper = this.getStreamingHelper();
|
|
228
|
+
const chunkString = (s, size = 16) => {
|
|
229
|
+
const out = [];
|
|
230
|
+
for (let i = 0; i < s.length; i += size) out.push(s.slice(i, i + size));
|
|
231
|
+
return out;
|
|
232
|
+
};
|
|
224
233
|
const activeSpan = trace.getActiveSpan();
|
|
225
234
|
if (activeSpan) {
|
|
226
235
|
const attributes = {
|
|
@@ -235,9 +244,26 @@ var Agent = class {
|
|
|
235
244
|
if (options?.mcpServerName) attributes["ai.toolCall.mcpServerName"] = options.mcpServerName;
|
|
236
245
|
activeSpan.setAttributes(attributes);
|
|
237
246
|
}
|
|
238
|
-
const
|
|
247
|
+
const isInternalToolForUi = toolName.includes("save_tool_result") || toolName.includes("thinking_complete") || toolName.startsWith("transfer_to_") || toolName.startsWith("delegate_to_");
|
|
239
248
|
const needsApproval = options?.needsApproval || false;
|
|
240
|
-
if (streamRequestId && !
|
|
249
|
+
if (streamRequestId && streamHelper && !isInternalToolForUi) {
|
|
250
|
+
const inputText = JSON.stringify(args ?? {});
|
|
251
|
+
await streamHelper.writeToolInputStart({
|
|
252
|
+
toolCallId,
|
|
253
|
+
toolName
|
|
254
|
+
});
|
|
255
|
+
for (const part of chunkString(inputText, 16)) await streamHelper.writeToolInputDelta({
|
|
256
|
+
toolCallId,
|
|
257
|
+
inputTextDelta: part
|
|
258
|
+
});
|
|
259
|
+
await streamHelper.writeToolInputAvailable({
|
|
260
|
+
toolCallId,
|
|
261
|
+
toolName,
|
|
262
|
+
input: args ?? {},
|
|
263
|
+
providerMetadata: context$1?.providerMetadata
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
if (streamRequestId && !isInternalToolForUi) {
|
|
241
267
|
const toolCallData = {
|
|
242
268
|
toolName,
|
|
243
269
|
input: args,
|
|
@@ -254,7 +280,7 @@ var Agent = class {
|
|
|
254
280
|
const result = await originalExecute(args, context$1);
|
|
255
281
|
const duration = Date.now() - startTime;
|
|
256
282
|
const toolResultConversationId = this.getToolResultConversationId();
|
|
257
|
-
if (streamRequestId && !
|
|
283
|
+
if (streamRequestId && !isInternalToolForUi && toolResultConversationId) try {
|
|
258
284
|
const messagePayload = {
|
|
259
285
|
id: generateId(),
|
|
260
286
|
tenantId: this.config.tenantId,
|
|
@@ -282,7 +308,7 @@ var Agent = class {
|
|
|
282
308
|
conversationId: toolResultConversationId
|
|
283
309
|
}, "Failed to store tool result in conversation history");
|
|
284
310
|
}
|
|
285
|
-
if (streamRequestId && !
|
|
311
|
+
if (streamRequestId && !isInternalToolForUi) agentSessionManager.recordEvent(streamRequestId, "tool_result", this.config.id, {
|
|
286
312
|
toolName,
|
|
287
313
|
output: result,
|
|
288
314
|
toolCallId,
|
|
@@ -290,11 +316,17 @@ var Agent = class {
|
|
|
290
316
|
relationshipId,
|
|
291
317
|
needsApproval
|
|
292
318
|
});
|
|
319
|
+
const isDeniedResult = !!result && typeof result === "object" && "__inkeepToolDenied" in result && result.__inkeepToolDenied === true;
|
|
320
|
+
if (streamRequestId && streamHelper && !isInternalToolForUi) if (isDeniedResult) await streamHelper.writeToolOutputDenied({ toolCallId });
|
|
321
|
+
else await streamHelper.writeToolOutputAvailable({
|
|
322
|
+
toolCallId,
|
|
323
|
+
output: result
|
|
324
|
+
});
|
|
293
325
|
return result;
|
|
294
326
|
} catch (error) {
|
|
295
327
|
const duration = Date.now() - startTime;
|
|
296
328
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
297
|
-
if (streamRequestId && !
|
|
329
|
+
if (streamRequestId && !isInternalToolForUi) agentSessionManager.recordEvent(streamRequestId, "tool_result", this.config.id, {
|
|
298
330
|
toolName,
|
|
299
331
|
output: null,
|
|
300
332
|
toolCallId,
|
|
@@ -303,6 +335,10 @@ var Agent = class {
|
|
|
303
335
|
relationshipId,
|
|
304
336
|
needsApproval
|
|
305
337
|
});
|
|
338
|
+
if (streamRequestId && streamHelper && !isInternalToolForUi) await streamHelper.writeToolOutputError({
|
|
339
|
+
toolCallId,
|
|
340
|
+
error: errorMessage
|
|
341
|
+
});
|
|
306
342
|
throw error;
|
|
307
343
|
}
|
|
308
344
|
}
|
|
@@ -372,7 +408,7 @@ var Agent = class {
|
|
|
372
408
|
const sessionWrappedTool = tool({
|
|
373
409
|
description: originalTool.description,
|
|
374
410
|
inputSchema: originalTool.inputSchema,
|
|
375
|
-
execute: async (args, { toolCallId }) => {
|
|
411
|
+
execute: async (args, { toolCallId, providerMetadata }) => {
|
|
376
412
|
let processedArgs;
|
|
377
413
|
try {
|
|
378
414
|
processedArgs = parseEmbeddedJson(args);
|
|
@@ -410,22 +446,52 @@ var Agent = class {
|
|
|
410
446
|
requestSpan.setStatus({ code: SpanStatusCode.OK });
|
|
411
447
|
requestSpan.end();
|
|
412
448
|
});
|
|
413
|
-
const
|
|
414
|
-
if (
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
"subAgent.id": this.config.id,
|
|
418
|
-
"subAgent.name": this.config.name
|
|
419
|
-
} }, (denialSpan) => {
|
|
420
|
-
logger.info({
|
|
421
|
-
toolName,
|
|
422
|
-
toolCallId,
|
|
423
|
-
reason: approvalResult.reason
|
|
424
|
-
}, "Tool execution denied by user");
|
|
425
|
-
denialSpan.setStatus({ code: SpanStatusCode.OK });
|
|
426
|
-
denialSpan.end();
|
|
427
|
-
return `User denied approval to run this tool: ${approvalResult.reason}`;
|
|
449
|
+
const streamHelper = this.getStreamingHelper();
|
|
450
|
+
if (streamHelper) await streamHelper.writeToolApprovalRequest({
|
|
451
|
+
approvalId: `aitxt-${toolCallId}`,
|
|
452
|
+
toolCallId
|
|
428
453
|
});
|
|
454
|
+
else if (this.isDelegatedAgent) {
|
|
455
|
+
const streamRequestId$1 = this.getStreamRequestId();
|
|
456
|
+
if (streamRequestId$1) await toolApprovalUiBus.publish(streamRequestId$1, {
|
|
457
|
+
type: "approval-needed",
|
|
458
|
+
toolCallId,
|
|
459
|
+
toolName,
|
|
460
|
+
input: finalArgs,
|
|
461
|
+
providerMetadata,
|
|
462
|
+
approvalId: `aitxt-${toolCallId}`
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
const approvalResult = await pendingToolApprovalManager.waitForApproval(toolCallId, toolName, args, this.conversationId || "unknown", this.config.id);
|
|
466
|
+
if (!approvalResult.approved) {
|
|
467
|
+
if (!streamHelper && this.isDelegatedAgent) {
|
|
468
|
+
const streamRequestId$1 = this.getStreamRequestId();
|
|
469
|
+
if (streamRequestId$1) await toolApprovalUiBus.publish(streamRequestId$1, {
|
|
470
|
+
type: "approval-resolved",
|
|
471
|
+
toolCallId,
|
|
472
|
+
approved: false
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
return tracer.startActiveSpan("tool.approval_denied", { attributes: {
|
|
476
|
+
"tool.name": toolName,
|
|
477
|
+
"tool.callId": toolCallId,
|
|
478
|
+
"subAgent.id": this.config.id,
|
|
479
|
+
"subAgent.name": this.config.name
|
|
480
|
+
} }, (denialSpan) => {
|
|
481
|
+
logger.info({
|
|
482
|
+
toolName,
|
|
483
|
+
toolCallId,
|
|
484
|
+
reason: approvalResult.reason
|
|
485
|
+
}, "Tool execution denied by user");
|
|
486
|
+
denialSpan.setStatus({ code: SpanStatusCode.OK });
|
|
487
|
+
denialSpan.end();
|
|
488
|
+
return {
|
|
489
|
+
__inkeepToolDenied: true,
|
|
490
|
+
toolCallId,
|
|
491
|
+
reason: approvalResult.reason
|
|
492
|
+
};
|
|
493
|
+
});
|
|
494
|
+
}
|
|
429
495
|
tracer.startActiveSpan("tool.approval_approved", { attributes: {
|
|
430
496
|
"tool.name": toolName,
|
|
431
497
|
"tool.callId": toolCallId,
|
|
@@ -439,6 +505,14 @@ var Agent = class {
|
|
|
439
505
|
approvedSpan.setStatus({ code: SpanStatusCode.OK });
|
|
440
506
|
approvedSpan.end();
|
|
441
507
|
});
|
|
508
|
+
if (!streamHelper && this.isDelegatedAgent) {
|
|
509
|
+
const streamRequestId$1 = this.getStreamRequestId();
|
|
510
|
+
if (streamRequestId$1) await toolApprovalUiBus.publish(streamRequestId$1, {
|
|
511
|
+
type: "approval-resolved",
|
|
512
|
+
toolCallId,
|
|
513
|
+
approved: true
|
|
514
|
+
});
|
|
515
|
+
}
|
|
442
516
|
}
|
|
443
517
|
logger.debug({
|
|
444
518
|
toolName,
|
|
@@ -498,10 +572,7 @@ var Agent = class {
|
|
|
498
572
|
result: enhancedResult,
|
|
499
573
|
timestamp: Date.now()
|
|
500
574
|
});
|
|
501
|
-
return
|
|
502
|
-
result: enhancedResult,
|
|
503
|
-
toolCallId
|
|
504
|
-
};
|
|
575
|
+
return enhancedResult;
|
|
505
576
|
} catch (error) {
|
|
506
577
|
logger.error({
|
|
507
578
|
toolName,
|
|
@@ -727,6 +798,9 @@ var Agent = class {
|
|
|
727
798
|
});
|
|
728
799
|
})).data ?? [];
|
|
729
800
|
if (functionToolsData.length === 0) return functionTools;
|
|
801
|
+
this.functionToolRelationshipIdByName = new Map(functionToolsData.flatMap((t) => {
|
|
802
|
+
return t.relationshipId ? [[t.name, t.relationshipId]] : [];
|
|
803
|
+
}));
|
|
730
804
|
const { SandboxExecutorFactory } = await import("../tools/SandboxExecutorFactory.js");
|
|
731
805
|
const sandboxExecutor = sessionId ? SandboxExecutorFactory.getForSession(sessionId) : new SandboxExecutorFactory();
|
|
732
806
|
for (const functionToolDef of functionToolsData) {
|
|
@@ -790,10 +864,7 @@ var Agent = class {
|
|
|
790
864
|
result,
|
|
791
865
|
timestamp: Date.now()
|
|
792
866
|
});
|
|
793
|
-
return
|
|
794
|
-
result,
|
|
795
|
-
toolCallId
|
|
796
|
-
};
|
|
867
|
+
return result;
|
|
797
868
|
} catch (error) {
|
|
798
869
|
logger.error({
|
|
799
870
|
toolName: functionToolDef.name,
|
|
@@ -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";
|
|
@@ -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";
|
|
@@ -34,16 +35,31 @@ const chatDataStreamRoute = createRoute({
|
|
|
34
35
|
"tool"
|
|
35
36
|
]),
|
|
36
37
|
content: z.any(),
|
|
37
|
-
parts: z.array(z.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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.literal("approval-responded"),
|
|
53
|
+
approval: z.object({
|
|
54
|
+
id: z.string(),
|
|
55
|
+
approved: z.boolean(),
|
|
56
|
+
reason: z.string().optional()
|
|
57
|
+
}),
|
|
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
|
|
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
|
|
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
|
} });
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
//#region src/domains/run/services/ToolApprovalUiBus.d.ts
|
|
2
|
+
type ToolApprovalUiEvent = {
|
|
3
|
+
type: 'approval-needed';
|
|
4
|
+
toolCallId: string;
|
|
5
|
+
toolName: string;
|
|
6
|
+
input: any;
|
|
7
|
+
providerMetadata?: any;
|
|
8
|
+
approvalId: string;
|
|
9
|
+
} | {
|
|
10
|
+
type: 'approval-resolved';
|
|
11
|
+
toolCallId: string;
|
|
12
|
+
approved: boolean;
|
|
13
|
+
};
|
|
14
|
+
type Listener = (event: ToolApprovalUiEvent) => void | Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* In-process event bus keyed by streamRequestId.
|
|
17
|
+
*
|
|
18
|
+
* Used to propagate approval UI events from delegated agents (who must not write to stream)
|
|
19
|
+
* up to the user-facing request handler, which can stream tool UI parts to the client.
|
|
20
|
+
*/
|
|
21
|
+
declare class ToolApprovalUiBus {
|
|
22
|
+
private listeners;
|
|
23
|
+
subscribe(streamRequestId: string, listener: Listener): () => void;
|
|
24
|
+
publish(streamRequestId: string, event: ToolApprovalUiEvent): Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
declare const toolApprovalUiBus: ToolApprovalUiBus;
|
|
27
|
+
//#endregion
|
|
28
|
+
export { ToolApprovalUiBus, ToolApprovalUiEvent, toolApprovalUiBus };
|