@inkeep/agents-run-api 0.0.0-dev-20260113172432 → 0.0.0-dev-20260115183047
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/README.md +2 -1
- package/dist/a2a/client.d.ts +3 -1
- package/dist/a2a/client.js +23 -9
- package/dist/a2a/handlers.js +11 -5
- package/dist/a2a/transfer.d.ts +6 -1
- package/dist/a2a/transfer.js +10 -6
- package/dist/agents/Agent.d.ts +8 -4
- package/dist/agents/Agent.js +226 -92
- package/dist/agents/ToolSessionManager.js +2 -2
- package/dist/agents/generateTaskHandler.d.ts +4 -9
- package/dist/agents/generateTaskHandler.js +107 -246
- package/dist/agents/relationTools.d.ts +19 -8
- package/dist/agents/relationTools.js +105 -14
- package/dist/agents/types.d.ts +4 -2
- package/dist/agents/versions/v1/Phase1Config.d.ts +4 -3
- package/dist/agents/versions/v1/Phase1Config.js +33 -20
- package/dist/constants/execution-limits/index.js +1 -1
- package/dist/context/ContextFetcher.d.ts +68 -0
- package/dist/context/ContextFetcher.js +276 -0
- package/dist/context/ContextResolver.d.ts +56 -0
- package/dist/context/ContextResolver.js +273 -0
- package/dist/context/context.d.ts +19 -0
- package/dist/context/context.js +108 -0
- package/dist/context/contextCache.d.ts +56 -0
- package/dist/context/contextCache.js +175 -0
- package/dist/context/index.d.ts +6 -0
- package/dist/context/index.js +7 -0
- package/dist/context/validation.d.ts +39 -0
- package/dist/context/validation.js +255 -0
- package/dist/create-app.d.ts +2 -2
- package/dist/create-app.js +7 -2
- package/dist/data/agent.d.ts +2 -2
- package/dist/data/agent.js +17 -22
- package/dist/data/agents.d.ts +2 -2
- package/dist/data/agents.js +34 -42
- package/dist/data/conversations.d.ts +2 -1
- package/dist/data/conversations.js +7 -8
- package/dist/data/db/dbClient.d.ts +2 -2
- package/dist/data/db/dbClient.js +2 -10
- package/dist/env.d.ts +6 -2
- package/dist/env.js +3 -1
- package/dist/handlers/executionHandler.d.ts +3 -2
- package/dist/handlers/executionHandler.js +46 -22
- package/dist/index.d.ts +3 -3
- package/dist/middleware/api-key-auth.d.ts +4 -10
- package/dist/middleware/api-key-auth.js +164 -163
- package/dist/middleware/index.d.ts +3 -2
- package/dist/middleware/index.js +3 -2
- package/dist/middleware/projectConfig.d.ts +19 -0
- package/dist/middleware/projectConfig.js +80 -0
- package/dist/routes/agents.d.ts +2 -1
- package/dist/routes/agents.js +7 -13
- package/dist/routes/chat.d.ts +2 -1
- package/dist/routes/chat.js +29 -52
- package/dist/routes/chatDataStream.d.ts +2 -1
- package/dist/routes/chatDataStream.js +28 -30
- package/dist/routes/mcp.d.ts +2 -1
- package/dist/routes/mcp.js +25 -37
- package/dist/services/AgentSession.d.ts +5 -7
- package/dist/services/AgentSession.js +25 -34
- package/dist/services/ArtifactParser.d.ts +2 -2
- package/dist/services/ArtifactParser.js +2 -2
- package/dist/services/ArtifactService.d.ts +2 -3
- package/dist/services/ArtifactService.js +23 -20
- package/dist/services/BaseCompressor.js +2 -2
- package/dist/services/IncrementalStreamParser.d.ts +2 -2
- package/dist/services/IncrementalStreamParser.js +2 -2
- package/dist/services/ResponseFormatter.d.ts +2 -2
- package/dist/services/ResponseFormatter.js +2 -2
- package/dist/services/evaluationHttpClient.d.ts +21 -0
- package/dist/services/evaluationHttpClient.js +48 -0
- package/dist/services/evaluationRunConfigMatcher.d.ts +6 -0
- package/dist/services/evaluationRunConfigMatcher.js +7 -0
- package/dist/tools/NativeSandboxExecutor.js +1 -1
- package/dist/tools/distill-conversation-history-tool.js +2 -2
- package/dist/tools/distill-conversation-tool.js +2 -2
- package/dist/types/execution-context.d.ts +8 -14
- package/dist/types/execution-context.js +3 -2
- package/dist/utils/model-resolver.d.ts +2 -2
- package/dist/utils/model-resolver.js +3 -13
- package/dist/utils/project.d.ts +207 -0
- package/dist/utils/project.js +315 -0
- package/dist/utils/token-estimator.d.ts +6 -52
- package/dist/utils/token-estimator.js +2 -38
- package/package.json +2 -2
package/dist/env.d.ts
CHANGED
|
@@ -13,8 +13,10 @@ declare const envSchema: z.ZodObject<{
|
|
|
13
13
|
test: "test";
|
|
14
14
|
pentest: "pentest";
|
|
15
15
|
}>>>;
|
|
16
|
-
DATABASE_URL: z.ZodOptional<z.ZodString>;
|
|
17
16
|
INKEEP_AGENTS_RUN_API_URL: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
17
|
+
INKEEP_AGENTS_MANAGE_API_URL: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
18
|
+
INKEEP_AGENTS_EVAL_API_URL: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
19
|
+
INKEEP_AGENTS_RUN_DATABASE_URL: z.ZodOptional<z.ZodString>;
|
|
18
20
|
AGENTS_MANAGE_UI_URL: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
19
21
|
LOG_LEVEL: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
|
|
20
22
|
trace: "trace";
|
|
@@ -37,6 +39,8 @@ declare const envSchema: z.ZodObject<{
|
|
|
37
39
|
declare const env: {
|
|
38
40
|
ENVIRONMENT: "development" | "production" | "test" | "pentest";
|
|
39
41
|
INKEEP_AGENTS_RUN_API_URL: string;
|
|
42
|
+
INKEEP_AGENTS_MANAGE_API_URL: string;
|
|
43
|
+
INKEEP_AGENTS_EVAL_API_URL: string;
|
|
40
44
|
AGENTS_MANAGE_UI_URL: string;
|
|
41
45
|
LOG_LEVEL: "trace" | "debug" | "info" | "warn" | "error";
|
|
42
46
|
NANGO_SERVER_URL: string;
|
|
@@ -44,7 +48,7 @@ declare const env: {
|
|
|
44
48
|
OTEL_BSP_SCHEDULE_DELAY: number;
|
|
45
49
|
OTEL_BSP_MAX_EXPORT_BATCH_SIZE: number;
|
|
46
50
|
NODE_ENV?: "development" | "production" | "test" | undefined;
|
|
47
|
-
|
|
51
|
+
INKEEP_AGENTS_RUN_DATABASE_URL?: string | undefined;
|
|
48
52
|
NANGO_SECRET_KEY?: string | undefined;
|
|
49
53
|
OPENAI_API_KEY?: string | undefined;
|
|
50
54
|
GOOGLE_GENERATIVE_AI_API_KEY?: string | undefined;
|
package/dist/env.js
CHANGED
|
@@ -15,8 +15,10 @@ const envSchema = z.object({
|
|
|
15
15
|
"pentest",
|
|
16
16
|
"test"
|
|
17
17
|
]).optional().default("development"),
|
|
18
|
-
DATABASE_URL: z.string().optional(),
|
|
19
18
|
INKEEP_AGENTS_RUN_API_URL: z.string().optional().default("http://localhost:3003"),
|
|
19
|
+
INKEEP_AGENTS_MANAGE_API_URL: z.string().optional().default("http://localhost:3002"),
|
|
20
|
+
INKEEP_AGENTS_EVAL_API_URL: z.string().optional().default("http://localhost:3005"),
|
|
21
|
+
INKEEP_AGENTS_RUN_DATABASE_URL: z.string().optional(),
|
|
20
22
|
AGENTS_MANAGE_UI_URL: z.string().optional().default("http://localhost:3000"),
|
|
21
23
|
LOG_LEVEL: z.enum([
|
|
22
24
|
"trace",
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { StreamHelper } from "../utils/stream-helpers.js";
|
|
2
|
-
import {
|
|
2
|
+
import { FullExecutionContext } from "@inkeep/agents-core";
|
|
3
3
|
|
|
4
4
|
//#region src/handlers/executionHandler.d.ts
|
|
5
5
|
interface ExecutionHandlerParams {
|
|
6
|
-
executionContext:
|
|
6
|
+
executionContext: FullExecutionContext;
|
|
7
7
|
conversationId: string;
|
|
8
8
|
userMessage: string;
|
|
9
9
|
initialAgentId: string;
|
|
10
10
|
requestId: string;
|
|
11
11
|
sseHelper: StreamHelper;
|
|
12
12
|
emitOperations?: boolean;
|
|
13
|
+
datasetRunId?: string;
|
|
13
14
|
/** Headers to forward to MCP servers (e.g., x-forwarded-cookie for auth) */
|
|
14
15
|
forwardedHeaders?: Record<string, string>;
|
|
15
16
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { getLogger } from "../logger.js";
|
|
1
|
+
import { getLogger as getLogger$1 } from "../logger.js";
|
|
2
2
|
import { flushBatchProcessor } from "../instrumentation.js";
|
|
3
3
|
import dbClient_default from "../data/db/dbClient.js";
|
|
4
|
+
import { getUserIdFromContext } from "../types/execution-context.js";
|
|
4
5
|
import { AGENT_EXECUTION_MAX_CONSECUTIVE_ERRORS } from "../constants/execution-limits/index.js";
|
|
5
6
|
import { tracer } from "../utils/tracer.js";
|
|
6
7
|
import { registerStreamHelper, unregisterStreamHelper } from "../utils/stream-registry.js";
|
|
@@ -10,11 +11,12 @@ import { agentInitializingOp, completionOp, errorOp } from "../utils/agent-opera
|
|
|
10
11
|
import { A2AClient } from "../a2a/client.js";
|
|
11
12
|
import { extractTransferData, isTransferTask } from "../a2a/types.js";
|
|
12
13
|
import { executeTransfer } from "../a2a/transfer.js";
|
|
14
|
+
import { triggerConversationEvaluationHttp } from "../services/evaluationHttpClient.js";
|
|
13
15
|
import { BufferingStreamHelper } from "../utils/stream-helpers.js";
|
|
14
|
-
import { AGENT_EXECUTION_TRANSFER_COUNT_DEFAULT, createMessage, createTask, generateId, getActiveAgentForConversation,
|
|
16
|
+
import { AGENT_EXECUTION_TRANSFER_COUNT_DEFAULT, createMessage, createTask, generateId, getActiveAgentForConversation, getTask, setSpanWithError, updateTask } from "@inkeep/agents-core";
|
|
15
17
|
|
|
16
18
|
//#region src/handlers/executionHandler.ts
|
|
17
|
-
const logger = getLogger("ExecutionHandler");
|
|
19
|
+
const logger = getLogger$1("ExecutionHandler");
|
|
18
20
|
var ExecutionHandler = class {
|
|
19
21
|
MAX_ERRORS = AGENT_EXECUTION_MAX_CONSECUTIVE_ERRORS;
|
|
20
22
|
/**
|
|
@@ -33,9 +35,9 @@ var ExecutionHandler = class {
|
|
|
33
35
|
*/
|
|
34
36
|
async execute(params) {
|
|
35
37
|
const { executionContext, conversationId, userMessage, initialAgentId, requestId, sseHelper, emitOperations, forwardedHeaders } = params;
|
|
36
|
-
const { tenantId, projectId, agentId, apiKey, baseUrl } = executionContext;
|
|
38
|
+
const { tenantId, projectId, project, agentId, apiKey, baseUrl, resolvedRef } = executionContext;
|
|
37
39
|
registerStreamHelper(requestId, sseHelper);
|
|
38
|
-
agentSessionManager.createSession(requestId,
|
|
40
|
+
agentSessionManager.createSession(requestId, executionContext, conversationId);
|
|
39
41
|
if (emitOperations) agentSessionManager.enableEmitOperations(requestId);
|
|
40
42
|
logger.info({
|
|
41
43
|
sessionId: requestId,
|
|
@@ -43,21 +45,12 @@ var ExecutionHandler = class {
|
|
|
43
45
|
conversationId,
|
|
44
46
|
emitOperations
|
|
45
47
|
}, "Created AgentSession for message execution");
|
|
46
|
-
|
|
48
|
+
const agentConfig = null;
|
|
47
49
|
try {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
} });
|
|
53
|
-
if (agentConfig?.statusUpdates && agentConfig.statusUpdates.enabled !== false) try {
|
|
54
|
-
const agentWithDefault = await getAgentWithDefaultSubAgent(dbClient_default)({ scopes: {
|
|
55
|
-
tenantId,
|
|
56
|
-
projectId,
|
|
57
|
-
agentId
|
|
58
|
-
} });
|
|
59
|
-
if (agentWithDefault?.defaultSubAgent) {
|
|
60
|
-
const resolvedModels = await resolveModelConfig(agentId, agentWithDefault.defaultSubAgent);
|
|
50
|
+
const agent = project.agents[agentId];
|
|
51
|
+
if (agent?.statusUpdates && agent.statusUpdates.enabled !== false) try {
|
|
52
|
+
if (agent?.defaultSubAgentId) {
|
|
53
|
+
const resolvedModels = await resolveModelConfig(executionContext, agent.subAgents[agent.defaultSubAgentId]);
|
|
61
54
|
agentSessionManager.initializeStatusUpdates(requestId, agentConfig.statusUpdates, resolvedModels.summarizer, resolvedModels.base);
|
|
62
55
|
} else agentSessionManager.initializeStatusUpdates(requestId, agentConfig.statusUpdates, agentConfig.models?.summarizer);
|
|
63
56
|
} catch (modelError) {
|
|
@@ -96,6 +89,7 @@ var ExecutionHandler = class {
|
|
|
96
89
|
subAgentId: currentAgentId,
|
|
97
90
|
contextId: conversationId,
|
|
98
91
|
status: "pending",
|
|
92
|
+
ref: resolvedRef,
|
|
99
93
|
metadata: {
|
|
100
94
|
conversation_id: conversationId,
|
|
101
95
|
message_id: requestId,
|
|
@@ -205,7 +199,10 @@ var ExecutionHandler = class {
|
|
|
205
199
|
logger.error({
|
|
206
200
|
currentAgentId,
|
|
207
201
|
iterations,
|
|
208
|
-
errorCount
|
|
202
|
+
errorCount,
|
|
203
|
+
hasError: !!messageResponse?.error,
|
|
204
|
+
errorDetails: messageResponse?.error,
|
|
205
|
+
fullResponse: messageResponse
|
|
209
206
|
}, `No response from agent ${currentAgentId} on iteration ${iterations} (error ${errorCount}/${this.MAX_ERRORS})`);
|
|
210
207
|
if (errorCount >= this.MAX_ERRORS) {
|
|
211
208
|
const errorMessage$1 = `Maximum error limit (${this.MAX_ERRORS}) reached`;
|
|
@@ -272,7 +269,9 @@ var ExecutionHandler = class {
|
|
|
272
269
|
projectId,
|
|
273
270
|
tenantId,
|
|
274
271
|
threadId: conversationId,
|
|
275
|
-
|
|
272
|
+
agentId,
|
|
273
|
+
targetSubAgentId,
|
|
274
|
+
ref: resolvedRef
|
|
276
275
|
});
|
|
277
276
|
if (success) {
|
|
278
277
|
fromSubAgentId = currentAgentId;
|
|
@@ -306,7 +305,7 @@ var ExecutionHandler = class {
|
|
|
306
305
|
span.setAttributes({
|
|
307
306
|
"ai.response.content": textContent || "No response content",
|
|
308
307
|
"ai.response.timestamp": (/* @__PURE__ */ new Date()).toISOString(),
|
|
309
|
-
"subAgent.name":
|
|
308
|
+
"subAgent.name": project.agents[agentId]?.subAgents[currentAgentId]?.name,
|
|
310
309
|
"subAgent.id": currentAgentId
|
|
311
310
|
});
|
|
312
311
|
await createMessage(dbClient_default)({
|
|
@@ -356,6 +355,18 @@ var ExecutionHandler = class {
|
|
|
356
355
|
let response;
|
|
357
356
|
if (sseHelper instanceof BufferingStreamHelper) response = sseHelper.getCapturedResponse().text || "No response content";
|
|
358
357
|
logger.info({}, "ExecutionHandler returning success");
|
|
358
|
+
if (!params.datasetRunId) triggerConversationEvaluationHttp({
|
|
359
|
+
tenantId,
|
|
360
|
+
projectId,
|
|
361
|
+
conversationId
|
|
362
|
+
}).catch((error) => {
|
|
363
|
+
logger.error({
|
|
364
|
+
error,
|
|
365
|
+
conversationId,
|
|
366
|
+
tenantId,
|
|
367
|
+
projectId
|
|
368
|
+
}, "Failed to trigger conversation evaluation (non-blocking)");
|
|
369
|
+
});
|
|
359
370
|
return {
|
|
360
371
|
success: true,
|
|
361
372
|
iterations,
|
|
@@ -396,6 +407,19 @@ var ExecutionHandler = class {
|
|
|
396
407
|
});
|
|
397
408
|
await agentSessionManager.endSession(requestId);
|
|
398
409
|
unregisterStreamHelper(requestId);
|
|
410
|
+
if (!params.datasetRunId) triggerConversationEvaluationHttp({
|
|
411
|
+
tenantId,
|
|
412
|
+
projectId,
|
|
413
|
+
conversationId,
|
|
414
|
+
userId: getUserIdFromContext(executionContext)
|
|
415
|
+
}).catch((error) => {
|
|
416
|
+
logger.error({
|
|
417
|
+
error,
|
|
418
|
+
conversationId,
|
|
419
|
+
tenantId,
|
|
420
|
+
projectId
|
|
421
|
+
}, "Failed to trigger conversation evaluation (non-blocking)");
|
|
422
|
+
});
|
|
399
423
|
return {
|
|
400
424
|
success: false,
|
|
401
425
|
error: errorMessage$1,
|
package/dist/index.d.ts
CHANGED
|
@@ -3,14 +3,14 @@ import { createExecutionHono } from "./create-app.js";
|
|
|
3
3
|
import "./env.js";
|
|
4
4
|
import { CredentialStore, ServerConfig } from "@inkeep/agents-core";
|
|
5
5
|
import { Hono } from "hono";
|
|
6
|
-
import * as
|
|
6
|
+
import * as hono_types1 from "hono/types";
|
|
7
7
|
|
|
8
8
|
//#region src/index.d.ts
|
|
9
|
-
declare const app: Hono<
|
|
9
|
+
declare const app: Hono<hono_types1.BlankEnv, hono_types1.BlankSchema, "/">;
|
|
10
10
|
declare function createExecutionApp(config?: {
|
|
11
11
|
serverConfig?: ServerConfig;
|
|
12
12
|
credentialStores?: CredentialStore[];
|
|
13
13
|
sandboxConfig?: SandboxConfig;
|
|
14
|
-
}): Hono<
|
|
14
|
+
}): Hono<hono_types1.BlankEnv, hono_types1.BlankSchema, "/">;
|
|
15
15
|
//#endregion
|
|
16
16
|
export { Hono, type NativeSandboxConfig, type SandboxConfig, type VercelSandboxConfig, createExecutionApp, createExecutionHono, app as default };
|
|
@@ -1,26 +1,20 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BaseExecutionContext } from "@inkeep/agents-core";
|
|
2
2
|
import * as hono0 from "hono";
|
|
3
3
|
|
|
4
4
|
//#region src/middleware/api-key-auth.d.ts
|
|
5
5
|
declare const apiKeyAuth: () => hono0.MiddlewareHandler<{
|
|
6
6
|
Variables: {
|
|
7
|
-
executionContext:
|
|
7
|
+
executionContext: BaseExecutionContext;
|
|
8
8
|
};
|
|
9
9
|
}, string, {}, Response>;
|
|
10
|
-
declare const extractContextFromApiKey: (apiKey: string, baseUrl?: string) => Promise<ExecutionContext>;
|
|
11
|
-
/**
|
|
12
|
-
* Extract execution context from a team agent JWT token
|
|
13
|
-
* Team agent tokens are used for intra-tenant agent delegation
|
|
14
|
-
*/
|
|
15
|
-
declare const extractContextFromTeamAgentToken: (token: string, baseUrl?: string, expectedSubAgentId?: string) => Promise<ExecutionContext>;
|
|
16
10
|
/**
|
|
17
11
|
* Helper middleware for endpoints that optionally support API key authentication
|
|
18
12
|
* If no auth header is present, it continues without setting the executionContext
|
|
19
13
|
*/
|
|
20
14
|
declare const optionalAuth: () => hono0.MiddlewareHandler<{
|
|
21
15
|
Variables: {
|
|
22
|
-
executionContext?:
|
|
16
|
+
executionContext?: BaseExecutionContext;
|
|
23
17
|
};
|
|
24
18
|
}, string, {}, Response>;
|
|
25
19
|
//#endregion
|
|
26
|
-
export { apiKeyAuth,
|
|
20
|
+
export { apiKeyAuth, optionalAuth };
|
|
@@ -1,198 +1,105 @@
|
|
|
1
1
|
import { env } from "../env.js";
|
|
2
|
-
import { getLogger } from "../logger.js";
|
|
2
|
+
import { getLogger as getLogger$1 } from "../logger.js";
|
|
3
3
|
import dbClient_default from "../data/db/dbClient.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { createBaseExecutionContext } from "../types/execution-context.js";
|
|
5
|
+
import { validateAndGetApiKey, validateTargetAgent, verifyServiceToken, verifyTempToken } from "@inkeep/agents-core";
|
|
6
6
|
import { HTTPException } from "hono/http-exception";
|
|
7
7
|
import { createMiddleware } from "hono/factory";
|
|
8
8
|
|
|
9
9
|
//#region src/middleware/api-key-auth.ts
|
|
10
|
-
const logger = getLogger("env-key-auth");
|
|
10
|
+
const logger = getLogger$1("env-key-auth");
|
|
11
|
+
/**
|
|
12
|
+
* Extract common request data from the Hono context
|
|
13
|
+
*/
|
|
14
|
+
function extractRequestData(c) {
|
|
15
|
+
const authHeader = c.req.header("Authorization");
|
|
16
|
+
const tenantId = c.req.header("x-inkeep-tenant-id");
|
|
17
|
+
const projectId = c.req.header("x-inkeep-project-id");
|
|
18
|
+
const agentId = c.req.header("x-inkeep-agent-id");
|
|
19
|
+
const subAgentId = c.req.header("x-inkeep-sub-agent-id");
|
|
20
|
+
const proto = c.req.header("x-forwarded-proto")?.split(",")[0].trim();
|
|
21
|
+
const host = c.req.header("x-forwarded-host")?.split(",")[0].trim() ?? c.req.header("host");
|
|
22
|
+
const reqUrl = new URL(c.req.url);
|
|
23
|
+
const ref = c.req.query("ref");
|
|
24
|
+
const baseUrl = proto && host ? `${proto}://${host}` : host ? `${reqUrl.protocol}//${host}` : `${reqUrl.origin}`;
|
|
25
|
+
return {
|
|
26
|
+
authHeader,
|
|
27
|
+
apiKey: authHeader?.startsWith("Bearer ") ? authHeader.substring(7) : void 0,
|
|
28
|
+
tenantId,
|
|
29
|
+
projectId,
|
|
30
|
+
agentId,
|
|
31
|
+
subAgentId,
|
|
32
|
+
ref,
|
|
33
|
+
baseUrl
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Build the final execution context from auth result and request data
|
|
38
|
+
*/
|
|
39
|
+
function buildExecutionContext(authResult, reqData) {
|
|
40
|
+
return createBaseExecutionContext({
|
|
41
|
+
apiKey: authResult.apiKey,
|
|
42
|
+
tenantId: authResult.tenantId,
|
|
43
|
+
projectId: authResult.projectId,
|
|
44
|
+
agentId: authResult.agentId,
|
|
45
|
+
apiKeyId: authResult.apiKeyId,
|
|
46
|
+
baseUrl: reqData.baseUrl,
|
|
47
|
+
subAgentId: reqData.subAgentId,
|
|
48
|
+
ref: reqData.ref,
|
|
49
|
+
metadata: authResult.metadata
|
|
50
|
+
});
|
|
51
|
+
}
|
|
11
52
|
/**
|
|
12
53
|
* Attempts to authenticate using a JWT temporary token
|
|
13
|
-
* Returns execution context if successful, null if token is invalid or not a JWT
|
|
14
54
|
*/
|
|
15
|
-
async function
|
|
55
|
+
async function tryTempJwtAuth(apiKey) {
|
|
16
56
|
if (!apiKey.startsWith("eyJ") || !env.INKEEP_AGENTS_TEMP_JWT_PUBLIC_KEY) return null;
|
|
17
57
|
try {
|
|
18
58
|
const payload = await verifyTempToken(Buffer.from(env.INKEEP_AGENTS_TEMP_JWT_PUBLIC_KEY, "base64").toString("utf-8"), apiKey);
|
|
19
59
|
logger.info({}, "JWT temp token authenticated successfully");
|
|
20
|
-
return
|
|
60
|
+
return {
|
|
21
61
|
apiKey,
|
|
22
62
|
tenantId: payload.tenantId,
|
|
23
63
|
projectId: payload.projectId,
|
|
24
64
|
agentId: payload.agentId,
|
|
25
65
|
apiKeyId: "temp-jwt",
|
|
26
|
-
baseUrl,
|
|
27
|
-
subAgentId,
|
|
28
66
|
metadata: { initiatedBy: payload.initiatedBy }
|
|
29
|
-
}
|
|
67
|
+
};
|
|
30
68
|
} catch (error) {
|
|
31
69
|
logger.debug({ error }, "JWT verification failed");
|
|
32
70
|
return null;
|
|
33
71
|
}
|
|
34
72
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
const authHeader = c.req.header("Authorization");
|
|
41
|
-
const tenantId = c.req.header("x-inkeep-tenant-id");
|
|
42
|
-
const projectId = c.req.header("x-inkeep-project-id");
|
|
43
|
-
const agentId = c.req.header("x-inkeep-agent-id");
|
|
44
|
-
const subAgentId = c.req.header("x-inkeep-sub-agent-id");
|
|
45
|
-
const proto = c.req.header("x-forwarded-proto")?.split(",")[0].trim();
|
|
46
|
-
const host = c.req.header("x-forwarded-host")?.split(",")[0].trim() ?? c.req.header("host");
|
|
47
|
-
const reqUrl = new URL(c.req.url);
|
|
48
|
-
const baseUrl = proto && host ? `${proto}://${host}` : host ? `${reqUrl.protocol}//${host}` : `${reqUrl.origin}`;
|
|
49
|
-
if (process.env.ENVIRONMENT === "development" || process.env.ENVIRONMENT === "test") {
|
|
50
|
-
logger.info({}, "development environment");
|
|
51
|
-
let executionContext;
|
|
52
|
-
if (authHeader?.startsWith("Bearer ")) {
|
|
53
|
-
const apiKey$1 = authHeader.substring(7);
|
|
54
|
-
const jwtContext$1 = await tryAuthenticateWithTempJwt(apiKey$1, baseUrl, subAgentId);
|
|
55
|
-
if (jwtContext$1) {
|
|
56
|
-
c.set("executionContext", jwtContext$1);
|
|
57
|
-
await next();
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
try {
|
|
61
|
-
executionContext = await extractContextFromApiKey(apiKey$1, baseUrl);
|
|
62
|
-
if (subAgentId) executionContext.subAgentId = subAgentId;
|
|
63
|
-
c.set("executionContext", executionContext);
|
|
64
|
-
} catch {
|
|
65
|
-
try {
|
|
66
|
-
executionContext = await extractContextFromTeamAgentToken(apiKey$1, baseUrl, subAgentId);
|
|
67
|
-
c.set("executionContext", executionContext);
|
|
68
|
-
} catch {
|
|
69
|
-
executionContext = createExecutionContext({
|
|
70
|
-
apiKey: "development",
|
|
71
|
-
tenantId: tenantId || "test-tenant",
|
|
72
|
-
projectId: projectId || "test-project",
|
|
73
|
-
agentId: agentId || "test-agent",
|
|
74
|
-
apiKeyId: "test-key",
|
|
75
|
-
baseUrl,
|
|
76
|
-
subAgentId
|
|
77
|
-
});
|
|
78
|
-
c.set("executionContext", executionContext);
|
|
79
|
-
logger.info({}, "Development/test environment - fallback to default context due to invalid API key");
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
} else {
|
|
83
|
-
executionContext = createExecutionContext({
|
|
84
|
-
apiKey: "development",
|
|
85
|
-
tenantId: tenantId || "test-tenant",
|
|
86
|
-
projectId: projectId || "test-project",
|
|
87
|
-
agentId: agentId || "test-agent",
|
|
88
|
-
apiKeyId: "test-key",
|
|
89
|
-
baseUrl,
|
|
90
|
-
subAgentId
|
|
91
|
-
});
|
|
92
|
-
c.set("executionContext", executionContext);
|
|
93
|
-
logger.info({}, "Development/test environment - no API key provided, using default context");
|
|
94
|
-
}
|
|
95
|
-
await next();
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
if (!authHeader || !authHeader.startsWith("Bearer ")) throw new HTTPException(401, { message: "Missing or invalid authorization header. Expected: Bearer <api_key>" });
|
|
99
|
-
const apiKey = authHeader.substring(7);
|
|
100
|
-
const jwtContext = await tryAuthenticateWithTempJwt(apiKey, baseUrl, subAgentId);
|
|
101
|
-
if (jwtContext) {
|
|
102
|
-
c.set("executionContext", jwtContext);
|
|
103
|
-
await next();
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
if (env.INKEEP_AGENTS_RUN_API_BYPASS_SECRET) {
|
|
107
|
-
if (apiKey === env.INKEEP_AGENTS_RUN_API_BYPASS_SECRET) {
|
|
108
|
-
if (!tenantId || !projectId || !agentId) throw new HTTPException(401, { message: "Missing or invalid tenant, project, or agent ID" });
|
|
109
|
-
const executionContext = createExecutionContext({
|
|
110
|
-
apiKey,
|
|
111
|
-
tenantId,
|
|
112
|
-
projectId,
|
|
113
|
-
agentId,
|
|
114
|
-
apiKeyId: "bypass",
|
|
115
|
-
baseUrl,
|
|
116
|
-
subAgentId
|
|
117
|
-
});
|
|
118
|
-
c.set("executionContext", executionContext);
|
|
119
|
-
logger.info({}, "Bypass secret authenticated successfully");
|
|
120
|
-
await next();
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
if (apiKey) {
|
|
124
|
-
try {
|
|
125
|
-
const executionContext = await extractContextFromApiKey(apiKey, baseUrl);
|
|
126
|
-
if (subAgentId) executionContext.subAgentId = subAgentId;
|
|
127
|
-
c.set("executionContext", executionContext);
|
|
128
|
-
logger.info({}, "API key authenticated successfully");
|
|
129
|
-
} catch {
|
|
130
|
-
const executionContext = await extractContextFromTeamAgentToken(apiKey, baseUrl, subAgentId);
|
|
131
|
-
c.set("executionContext", executionContext);
|
|
132
|
-
}
|
|
133
|
-
await next();
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
throw new HTTPException(401, { message: "Invalid Token" });
|
|
137
|
-
}
|
|
138
|
-
if (!apiKey || apiKey.length < 16) throw new HTTPException(401, { message: "Invalid API key format" });
|
|
139
|
-
try {
|
|
140
|
-
const executionContext = await extractContextFromApiKey(apiKey, baseUrl);
|
|
141
|
-
if (subAgentId) executionContext.subAgentId = subAgentId;
|
|
142
|
-
c.set("executionContext", executionContext);
|
|
143
|
-
logger.debug({
|
|
144
|
-
tenantId: executionContext.tenantId,
|
|
145
|
-
projectId: executionContext.projectId,
|
|
146
|
-
agentId: executionContext.agentId,
|
|
147
|
-
subAgentId: executionContext.subAgentId
|
|
148
|
-
}, "API key authenticated successfully");
|
|
149
|
-
await next();
|
|
150
|
-
} catch {
|
|
151
|
-
try {
|
|
152
|
-
const executionContext = await extractContextFromTeamAgentToken(apiKey, baseUrl, subAgentId);
|
|
153
|
-
c.set("executionContext", executionContext);
|
|
154
|
-
await next();
|
|
155
|
-
} catch (error) {
|
|
156
|
-
if (error instanceof HTTPException) throw error;
|
|
157
|
-
logger.error({ error }, "API key authentication error");
|
|
158
|
-
throw new HTTPException(500, { message: "Authentication failed" });
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
});
|
|
162
|
-
const extractContextFromApiKey = async (apiKey, baseUrl) => {
|
|
73
|
+
/**
|
|
74
|
+
* Authenticate using a regular API key
|
|
75
|
+
*/
|
|
76
|
+
async function tryApiKeyAuth(apiKey) {
|
|
163
77
|
const apiKeyRecord = await validateAndGetApiKey(apiKey, dbClient_default);
|
|
164
|
-
if (!apiKeyRecord)
|
|
165
|
-
const agent = await getAgentById(dbClient_default)({ scopes: {
|
|
166
|
-
tenantId: apiKeyRecord.tenantId,
|
|
167
|
-
projectId: apiKeyRecord.projectId,
|
|
168
|
-
agentId: apiKeyRecord.agentId
|
|
169
|
-
} });
|
|
170
|
-
if (!agent) throw new HTTPException(401, { message: "Invalid or expired API key" });
|
|
78
|
+
if (!apiKeyRecord) return null;
|
|
171
79
|
logger.debug({
|
|
172
80
|
tenantId: apiKeyRecord.tenantId,
|
|
173
81
|
projectId: apiKeyRecord.projectId,
|
|
174
|
-
agentId: apiKeyRecord.agentId
|
|
175
|
-
subAgentId: agent.defaultSubAgentId || void 0
|
|
82
|
+
agentId: apiKeyRecord.agentId
|
|
176
83
|
}, "API key authenticated successfully");
|
|
177
|
-
return
|
|
84
|
+
return {
|
|
178
85
|
apiKey,
|
|
179
86
|
tenantId: apiKeyRecord.tenantId,
|
|
180
87
|
projectId: apiKeyRecord.projectId,
|
|
181
88
|
agentId: apiKeyRecord.agentId,
|
|
182
|
-
apiKeyId: apiKeyRecord.id
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
});
|
|
186
|
-
};
|
|
89
|
+
apiKeyId: apiKeyRecord.id
|
|
90
|
+
};
|
|
91
|
+
}
|
|
187
92
|
/**
|
|
188
|
-
*
|
|
189
|
-
* Team agent tokens are used for intra-tenant agent delegation
|
|
93
|
+
* Authenticate using a team agent JWT token (for intra-tenant delegation)
|
|
190
94
|
*/
|
|
191
|
-
|
|
95
|
+
async function tryTeamAgentAuth(token, expectedSubAgentId) {
|
|
192
96
|
const result = await verifyServiceToken(token);
|
|
193
97
|
if (!result.valid || !result.payload) {
|
|
194
98
|
logger.warn({ error: result.error }, "Invalid team agent JWT token");
|
|
195
|
-
|
|
99
|
+
return {
|
|
100
|
+
authResult: null,
|
|
101
|
+
failureMessage: `Invalid team agent token: ${result.error || "Invalid token"}`
|
|
102
|
+
};
|
|
196
103
|
}
|
|
197
104
|
const payload = result.payload;
|
|
198
105
|
if (expectedSubAgentId && !validateTargetAgent(payload, expectedSubAgentId)) {
|
|
@@ -209,20 +116,114 @@ const extractContextFromTeamAgentToken = async (token, baseUrl, expectedSubAgent
|
|
|
209
116
|
tenantId: payload.tenantId,
|
|
210
117
|
projectId: payload.projectId
|
|
211
118
|
}, "Team agent JWT token authenticated successfully");
|
|
212
|
-
return
|
|
119
|
+
return { authResult: {
|
|
213
120
|
apiKey: "team-agent-jwt",
|
|
214
121
|
tenantId: payload.tenantId,
|
|
215
122
|
projectId: payload.projectId,
|
|
216
123
|
agentId: payload.aud,
|
|
217
124
|
apiKeyId: "team-agent-token",
|
|
218
|
-
baseUrl,
|
|
219
|
-
subAgentId: void 0,
|
|
220
125
|
metadata: {
|
|
221
126
|
teamDelegation: true,
|
|
222
127
|
originAgentId: payload.sub
|
|
223
128
|
}
|
|
224
|
-
}
|
|
225
|
-
}
|
|
129
|
+
} };
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Authenticate using bypass secret (production mode bypass)
|
|
133
|
+
*/
|
|
134
|
+
function tryBypassAuth(apiKey, reqData) {
|
|
135
|
+
if (!env.INKEEP_AGENTS_RUN_API_BYPASS_SECRET) return null;
|
|
136
|
+
if (apiKey !== env.INKEEP_AGENTS_RUN_API_BYPASS_SECRET) return null;
|
|
137
|
+
if (!reqData.tenantId || !reqData.projectId || !reqData.agentId) throw new HTTPException(401, { message: "Missing or invalid tenant, project, or agent ID" });
|
|
138
|
+
logger.info({}, "Bypass secret authenticated successfully");
|
|
139
|
+
return {
|
|
140
|
+
apiKey,
|
|
141
|
+
tenantId: reqData.tenantId,
|
|
142
|
+
projectId: reqData.projectId,
|
|
143
|
+
agentId: reqData.agentId,
|
|
144
|
+
apiKeyId: "bypass"
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Create default development context
|
|
149
|
+
*/
|
|
150
|
+
function createDevContext(reqData) {
|
|
151
|
+
const result = {
|
|
152
|
+
apiKey: "development",
|
|
153
|
+
tenantId: reqData.tenantId || "test-tenant",
|
|
154
|
+
projectId: reqData.projectId || "test-project",
|
|
155
|
+
agentId: reqData.agentId || "test-agent",
|
|
156
|
+
apiKeyId: "test-key"
|
|
157
|
+
};
|
|
158
|
+
if (!reqData.tenantId || !reqData.projectId) logger.warn({
|
|
159
|
+
hasTenantId: !!reqData.tenantId,
|
|
160
|
+
hasProjectId: !!reqData.projectId,
|
|
161
|
+
hasApiKey: !!reqData.apiKey,
|
|
162
|
+
apiKeyPrefix: reqData.apiKey?.substring(0, 10),
|
|
163
|
+
resultTenantId: result.tenantId,
|
|
164
|
+
resultProjectId: result.projectId
|
|
165
|
+
}, "createDevContext: Using fallback test values due to missing tenant/project in request");
|
|
166
|
+
return result;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Try all auth strategies in order, returning the first successful result
|
|
170
|
+
*/
|
|
171
|
+
async function authenticateRequest(reqData) {
|
|
172
|
+
const { apiKey, subAgentId } = reqData;
|
|
173
|
+
if (!apiKey) return { authResult: null };
|
|
174
|
+
const jwtResult = await tryTempJwtAuth(apiKey);
|
|
175
|
+
if (jwtResult) return { authResult: jwtResult };
|
|
176
|
+
const bypassResult = tryBypassAuth(apiKey, reqData);
|
|
177
|
+
if (bypassResult) return { authResult: bypassResult };
|
|
178
|
+
const apiKeyResult = await tryApiKeyAuth(apiKey);
|
|
179
|
+
if (apiKeyResult) return { authResult: apiKeyResult };
|
|
180
|
+
const teamAttempt = await tryTeamAgentAuth(apiKey, subAgentId);
|
|
181
|
+
if (teamAttempt.authResult) return { authResult: teamAttempt.authResult };
|
|
182
|
+
return {
|
|
183
|
+
authResult: null,
|
|
184
|
+
failureMessage: teamAttempt.failureMessage
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
const apiKeyAuth = () => createMiddleware(async (c, next) => {
|
|
188
|
+
if (c.req.method === "OPTIONS") {
|
|
189
|
+
await next();
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
const reqData = extractRequestData(c);
|
|
193
|
+
if (process.env.ENVIRONMENT === "development" || process.env.ENVIRONMENT === "test") {
|
|
194
|
+
logger.info({}, "development environment");
|
|
195
|
+
const attempt$1 = await authenticateRequest(reqData);
|
|
196
|
+
if (attempt$1.authResult) c.set("executionContext", buildExecutionContext(attempt$1.authResult, reqData));
|
|
197
|
+
else {
|
|
198
|
+
logger.info({}, reqData.apiKey ? "Development/test environment - fallback to default context due to invalid API key" : "Development/test environment - no API key provided, using default context");
|
|
199
|
+
c.set("executionContext", buildExecutionContext(createDevContext(reqData), reqData));
|
|
200
|
+
}
|
|
201
|
+
await next();
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
if (!reqData.authHeader || !reqData.authHeader.startsWith("Bearer ")) throw new HTTPException(401, { message: "Missing or invalid authorization header. Expected: Bearer <api_key>" });
|
|
205
|
+
if (!reqData.apiKey || reqData.apiKey.length < 16) throw new HTTPException(401, { message: "Invalid API key format" });
|
|
206
|
+
let attempt = { authResult: null };
|
|
207
|
+
try {
|
|
208
|
+
attempt = await authenticateRequest(reqData);
|
|
209
|
+
} catch (error) {
|
|
210
|
+
if (error instanceof HTTPException) throw error;
|
|
211
|
+
logger.error({ error }, "Authentication failed");
|
|
212
|
+
throw new HTTPException(500, { message: "Authentication failed" });
|
|
213
|
+
}
|
|
214
|
+
if (!attempt.authResult) {
|
|
215
|
+
logger.error({}, "API key authentication error - no valid auth method found");
|
|
216
|
+
throw new HTTPException(401, { message: attempt.failureMessage || "Invalid Token" });
|
|
217
|
+
}
|
|
218
|
+
logger.debug({
|
|
219
|
+
tenantId: attempt.authResult.tenantId,
|
|
220
|
+
projectId: attempt.authResult.projectId,
|
|
221
|
+
agentId: attempt.authResult.agentId,
|
|
222
|
+
subAgentId: reqData.subAgentId
|
|
223
|
+
}, "API key authenticated successfully");
|
|
224
|
+
c.set("executionContext", buildExecutionContext(attempt.authResult, reqData));
|
|
225
|
+
await next();
|
|
226
|
+
});
|
|
226
227
|
/**
|
|
227
228
|
* Helper middleware for endpoints that optionally support API key authentication
|
|
228
229
|
* If no auth header is present, it continues without setting the executionContext
|
|
@@ -237,4 +238,4 @@ const optionalAuth = () => createMiddleware(async (c, next) => {
|
|
|
237
238
|
});
|
|
238
239
|
|
|
239
240
|
//#endregion
|
|
240
|
-
export { apiKeyAuth,
|
|
241
|
+
export { apiKeyAuth, optionalAuth };
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import { apiKeyAuth,
|
|
2
|
-
|
|
1
|
+
import { apiKeyAuth, optionalAuth } from "./api-key-auth.js";
|
|
2
|
+
import { projectConfigMiddleware } from "./projectConfig.js";
|
|
3
|
+
export { apiKeyAuth, optionalAuth, projectConfigMiddleware };
|
package/dist/middleware/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import { apiKeyAuth,
|
|
1
|
+
import { apiKeyAuth, optionalAuth } from "./api-key-auth.js";
|
|
2
|
+
import { projectConfigMiddleware } from "./projectConfig.js";
|
|
2
3
|
|
|
3
|
-
export { apiKeyAuth,
|
|
4
|
+
export { apiKeyAuth, optionalAuth, projectConfigMiddleware };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { FullExecutionContext } from "@inkeep/agents-core";
|
|
2
|
+
import * as hono0 from "hono";
|
|
3
|
+
|
|
4
|
+
//#region src/middleware/projectConfig.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Middleware that fetches the full project definition from the Management API
|
|
8
|
+
* and adds it to the Hono context for use in route handlers.
|
|
9
|
+
*
|
|
10
|
+
* This middleware should be applied after authentication middleware since it
|
|
11
|
+
* requires the execution context to be set.
|
|
12
|
+
*/
|
|
13
|
+
declare const projectConfigMiddleware: hono0.MiddlewareHandler<{
|
|
14
|
+
Variables: {
|
|
15
|
+
executionContext: FullExecutionContext;
|
|
16
|
+
};
|
|
17
|
+
}, string, {}, Response>;
|
|
18
|
+
//#endregion
|
|
19
|
+
export { projectConfigMiddleware };
|