@inkeep/agents-core 0.41.2 → 0.42.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 (228) hide show
  1. package/dist/api-client/base-client.d.ts +87 -8
  2. package/dist/api-client/base-client.js +174 -1
  3. package/dist/api-client/eval-api-client.d.ts +47 -0
  4. package/dist/api-client/eval-api-client.js +65 -0
  5. package/dist/api-client/index.d.ts +4 -0
  6. package/dist/api-client/index.js +5 -0
  7. package/dist/api-client/manage-api-client.d.ts +34 -0
  8. package/dist/api-client/manage-api-client.js +104 -0
  9. package/dist/auth/auth.d.ts +86 -20
  10. package/dist/auth/auth.js +55 -1
  11. package/dist/auth/authz/client.d.ts +81 -0
  12. package/dist/auth/authz/client.js +189 -0
  13. package/dist/auth/authz/config.d.ts +76 -0
  14. package/dist/auth/authz/config.js +76 -0
  15. package/dist/auth/authz/index.d.ts +5 -0
  16. package/dist/auth/authz/index.js +6 -0
  17. package/dist/auth/authz/permissions.d.ts +57 -0
  18. package/dist/auth/authz/permissions.js +83 -0
  19. package/dist/auth/authz/sync.d.ts +85 -0
  20. package/dist/auth/authz/sync.js +237 -0
  21. package/dist/auth/permissions.d.ts +13 -13
  22. package/dist/auth/permissions.js +2 -181
  23. package/dist/client-exports.d.ts +8 -3
  24. package/dist/client-exports.js +3 -2
  25. package/dist/constants/context-breakdown.d.ts +61 -0
  26. package/dist/constants/context-breakdown.js +124 -0
  27. package/dist/constants/otel-attributes.d.ts +4 -0
  28. package/dist/constants/otel-attributes.js +4 -0
  29. package/dist/context/ContextConfig.d.ts +2 -2
  30. package/dist/context/ContextConfig.js +3 -3
  31. package/dist/context/TemplateEngine.js +0 -1
  32. package/dist/context/index.d.ts +1 -5
  33. package/dist/context/index.js +1 -5
  34. package/dist/credential-stuffer/CredentialStuffer.d.ts +1 -1
  35. package/dist/data-access/index.d.ts +34 -26
  36. package/dist/data-access/index.js +34 -26
  37. package/dist/data-access/manage/agentFull.d.ts +36 -0
  38. package/dist/data-access/{agentFull.js → manage/agentFull.js} +205 -7
  39. package/dist/data-access/{agents.d.ts → manage/agents.d.ts} +23 -22
  40. package/dist/data-access/{agents.js → manage/agents.js} +52 -7
  41. package/dist/data-access/{artifactComponents.d.ts → manage/artifactComponents.d.ts} +21 -21
  42. package/dist/data-access/{artifactComponents.js → manage/artifactComponents.js} +5 -5
  43. package/dist/data-access/{contextConfigs.d.ts → manage/contextConfigs.d.ts} +14 -14
  44. package/dist/data-access/{contextConfigs.js → manage/contextConfigs.js} +3 -3
  45. package/dist/data-access/{credentialReferences.d.ts → manage/credentialReferences.d.ts} +17 -17
  46. package/dist/data-access/{credentialReferences.js → manage/credentialReferences.js} +2 -2
  47. package/dist/data-access/{dataComponents.d.ts → manage/dataComponents.d.ts} +20 -20
  48. package/dist/data-access/{dataComponents.js → manage/dataComponents.js} +7 -7
  49. package/dist/data-access/manage/evalConfig.d.ts +221 -0
  50. package/dist/data-access/manage/evalConfig.js +275 -0
  51. package/dist/data-access/{externalAgents.d.ts → manage/externalAgents.d.ts} +16 -16
  52. package/dist/data-access/{externalAgents.js → manage/externalAgents.js} +2 -2
  53. package/dist/data-access/{functionTools.d.ts → manage/functionTools.d.ts} +65 -15
  54. package/dist/data-access/{functionTools.js → manage/functionTools.js} +90 -8
  55. package/dist/data-access/{functions.d.ts → manage/functions.d.ts} +9 -9
  56. package/dist/data-access/{functions.js → manage/functions.js} +3 -3
  57. package/dist/data-access/manage/projectFull.d.ts +38 -0
  58. package/dist/data-access/{projectFull.js → manage/projectFull.js} +64 -65
  59. package/dist/data-access/manage/projectLifecycle.d.ts +119 -0
  60. package/dist/data-access/manage/projectLifecycle.js +234 -0
  61. package/dist/data-access/manage/projects.d.ts +75 -0
  62. package/dist/data-access/{projects.js → manage/projects.js} +15 -16
  63. package/dist/data-access/{subAgentExternalAgentRelations.d.ts → manage/subAgentExternalAgentRelations.d.ts} +19 -19
  64. package/dist/data-access/{subAgentExternalAgentRelations.js → manage/subAgentExternalAgentRelations.js} +2 -2
  65. package/dist/data-access/{subAgentRelations.d.ts → manage/subAgentRelations.d.ts} +29 -29
  66. package/dist/data-access/{subAgentRelations.js → manage/subAgentRelations.js} +3 -3
  67. package/dist/data-access/{subAgentTeamAgentRelations.d.ts → manage/subAgentTeamAgentRelations.d.ts} +19 -19
  68. package/dist/data-access/{subAgentTeamAgentRelations.js → manage/subAgentTeamAgentRelations.js} +2 -2
  69. package/dist/data-access/{subAgents.d.ts → manage/subAgents.d.ts} +13 -13
  70. package/dist/data-access/{subAgents.js → manage/subAgents.js} +4 -4
  71. package/dist/data-access/{tools.d.ts → manage/tools.d.ts} +26 -19
  72. package/dist/data-access/{tools.js → manage/tools.js} +57 -35
  73. package/dist/data-access/manage/triggers.d.ts +80 -0
  74. package/dist/data-access/manage/triggers.js +81 -0
  75. package/dist/data-access/{apiKeys.d.ts → runtime/apiKeys.d.ts} +17 -17
  76. package/dist/data-access/{apiKeys.js → runtime/apiKeys.js} +3 -3
  77. package/dist/data-access/runtime/cascade-delete.d.ts +77 -0
  78. package/dist/data-access/runtime/cascade-delete.js +111 -0
  79. package/dist/data-access/{contextCache.d.ts → runtime/contextCache.d.ts} +13 -13
  80. package/dist/data-access/{contextCache.js → runtime/contextCache.js} +5 -5
  81. package/dist/data-access/{conversations.d.ts → runtime/conversations.d.ts} +68 -19
  82. package/dist/data-access/{conversations.js → runtime/conversations.js} +13 -7
  83. package/dist/data-access/runtime/evalRuns.d.ts +120 -0
  84. package/dist/data-access/runtime/evalRuns.js +168 -0
  85. package/dist/data-access/{ledgerArtifacts.d.ts → runtime/ledgerArtifacts.d.ts} +13 -13
  86. package/dist/data-access/{ledgerArtifacts.js → runtime/ledgerArtifacts.js} +3 -3
  87. package/dist/data-access/{messages.d.ts → runtime/messages.d.ts} +15 -15
  88. package/dist/data-access/{messages.js → runtime/messages.js} +2 -2
  89. package/dist/data-access/{organizations.d.ts → runtime/organizations.d.ts} +16 -7
  90. package/dist/data-access/{organizations.js → runtime/organizations.js} +15 -3
  91. package/dist/data-access/runtime/projects.d.ts +62 -0
  92. package/dist/data-access/runtime/projects.js +90 -0
  93. package/dist/data-access/runtime/tasks.d.ts +55 -0
  94. package/dist/data-access/{tasks.js → runtime/tasks.js} +2 -2
  95. package/dist/data-access/runtime/triggerInvocations.d.ts +62 -0
  96. package/dist/data-access/runtime/triggerInvocations.js +54 -0
  97. package/dist/data-access/runtime/users.d.ts +19 -0
  98. package/dist/data-access/{users.js → runtime/users.js} +2 -2
  99. package/dist/data-access/validation.d.ts +4 -4
  100. package/dist/data-access/validation.js +1 -1
  101. package/dist/db/clean.d.ts +8 -4
  102. package/dist/db/clean.js +14 -105
  103. package/dist/db/delete.d.ts +1 -1
  104. package/dist/db/delete.js +7 -10
  105. package/dist/db/manage/dolt-cleanup.d.ts +51 -0
  106. package/dist/db/manage/dolt-cleanup.js +132 -0
  107. package/dist/db/manage/manage-client.d.ts +26 -0
  108. package/dist/db/manage/manage-client.js +68 -0
  109. package/dist/db/{schema.d.ts → manage/manage-schema.d.ts} +1459 -1285
  110. package/dist/db/{schema.js → manage/manage-schema.js} +433 -341
  111. package/dist/db/manage/test-manage-client.d.ts +27 -0
  112. package/dist/db/manage/test-manage-client.js +68 -0
  113. package/dist/db/runtime/runtime-client.d.ts +20 -0
  114. package/dist/db/runtime/runtime-client.js +30 -0
  115. package/dist/db/runtime/runtime-schema.d.ts +2834 -0
  116. package/dist/db/runtime/runtime-schema.js +483 -0
  117. package/dist/db/runtime/test-runtime-client.d.ts +27 -0
  118. package/dist/db/{test-client.js → runtime/test-runtime-client.js} +11 -25
  119. package/dist/dolt/branch.d.ts +62 -0
  120. package/dist/dolt/branch.js +82 -0
  121. package/dist/dolt/branches-api.d.ts +108 -0
  122. package/dist/dolt/branches-api.js +162 -0
  123. package/dist/dolt/commit.d.ts +94 -0
  124. package/dist/dolt/commit.js +103 -0
  125. package/dist/dolt/diff.d.ts +27 -0
  126. package/dist/dolt/diff.js +21 -0
  127. package/dist/dolt/index.d.ts +10 -0
  128. package/dist/dolt/index.js +11 -0
  129. package/dist/dolt/merge.d.ts +63 -0
  130. package/dist/dolt/merge.js +81 -0
  131. package/dist/dolt/migrate-all-branches.d.ts +4 -0
  132. package/dist/dolt/migrate-all-branches.js +78 -0
  133. package/dist/dolt/migrate-dolt.d.ts +1 -0
  134. package/dist/dolt/migrate-dolt.js +22 -0
  135. package/dist/dolt/ref-helpers.d.ts +19 -0
  136. package/dist/dolt/ref-helpers.js +65 -0
  137. package/dist/dolt/ref-middleware.d.ts +82 -0
  138. package/dist/dolt/ref-middleware.js +217 -0
  139. package/dist/dolt/ref-scope.d.ts +101 -0
  140. package/dist/dolt/ref-scope.js +231 -0
  141. package/dist/dolt/schema-sync.d.ts +134 -0
  142. package/dist/dolt/schema-sync.js +246 -0
  143. package/dist/env.d.ts +6 -4
  144. package/dist/env.js +3 -2
  145. package/dist/index.d.ts +71 -44
  146. package/dist/index.js +74 -47
  147. package/dist/types/entities.d.ts +81 -2
  148. package/dist/types/index.d.ts +3 -3
  149. package/dist/types/utility.d.ts +45 -4
  150. package/dist/utils/JsonTransformer.d.ts +44 -0
  151. package/dist/utils/JsonTransformer.js +112 -0
  152. package/dist/utils/apiKeys.d.ts +5 -1
  153. package/dist/utils/apiKeys.js +11 -1
  154. package/dist/utils/colors.d.ts +34 -0
  155. package/dist/utils/colors.js +49 -0
  156. package/dist/utils/credential-store-utils.d.ts +1 -1
  157. package/dist/utils/format-messages.d.ts +1 -1
  158. package/dist/utils/index.d.ts +7 -3
  159. package/dist/utils/index.js +7 -3
  160. package/dist/utils/internal-service-auth.d.ts +79 -0
  161. package/dist/utils/internal-service-auth.js +140 -0
  162. package/dist/utils/jwt-helpers.d.ts +56 -0
  163. package/dist/utils/jwt-helpers.js +90 -0
  164. package/dist/utils/service-token-auth.d.ts +9 -27
  165. package/dist/utils/service-token-auth.js +48 -96
  166. package/dist/utils/template-interpolation.d.ts +22 -0
  167. package/dist/utils/template-interpolation.js +62 -0
  168. package/dist/utils/third-party-mcp-servers/composio-client.js +23 -23
  169. package/dist/utils/trigger-auth.d.ts +62 -0
  170. package/dist/utils/trigger-auth.js +125 -0
  171. package/dist/validation/agentFull.js +2 -4
  172. package/dist/validation/dolt-schemas.d.ts +49 -0
  173. package/dist/validation/dolt-schemas.js +44 -0
  174. package/dist/validation/drizzle-schema-helpers.d.ts +4 -26
  175. package/dist/validation/drizzle-schema-helpers.js +5 -151
  176. package/dist/validation/index.d.ts +4 -3
  177. package/dist/validation/index.js +3 -2
  178. package/dist/validation/schemas.d.ts +17647 -4789
  179. package/dist/validation/schemas.js +328 -11
  180. package/drizzle/manage/0000_tearful_rhodey.sql +414 -0
  181. package/drizzle/manage/0001_broken_wendell_vaughn.sql +19 -0
  182. package/drizzle/manage/0002_bent_sunfire.sql +1 -0
  183. package/drizzle/manage/meta/0000_snapshot.json +2987 -0
  184. package/drizzle/manage/meta/0001_snapshot.json +3115 -0
  185. package/drizzle/manage/meta/0002_snapshot.json +3115 -0
  186. package/drizzle/manage/meta/_journal.json +27 -0
  187. package/drizzle/runtime/0008_silly_preak.sql +127 -0
  188. package/drizzle/runtime/0009_freezing_leo.sql +17 -0
  189. package/drizzle/runtime/meta/0008_snapshot.json +2263 -0
  190. package/drizzle/runtime/meta/0009_snapshot.json +2397 -0
  191. package/drizzle/{meta → runtime/meta}/_journal.json +14 -0
  192. package/package.json +48 -15
  193. package/dist/context/ContextFetcher.d.ts +0 -73
  194. package/dist/context/ContextFetcher.js +0 -291
  195. package/dist/context/ContextResolver.d.ts +0 -60
  196. package/dist/context/ContextResolver.js +0 -278
  197. package/dist/context/context.d.ts +0 -27
  198. package/dist/context/context.js +0 -128
  199. package/dist/context/contextCache.d.ts +0 -58
  200. package/dist/context/contextCache.js +0 -177
  201. package/dist/data-access/agentFull.d.ts +0 -33
  202. package/dist/data-access/projectFull.d.ts +0 -32
  203. package/dist/data-access/projects.d.ts +0 -71
  204. package/dist/data-access/tasks.d.ts +0 -45
  205. package/dist/data-access/users.d.ts +0 -19
  206. package/dist/db/client.d.ts +0 -20
  207. package/dist/db/client.js +0 -28
  208. package/dist/db/test-client.d.ts +0 -31
  209. package/dist/middleware/contextValidation.d.ts +0 -46
  210. package/dist/middleware/contextValidation.js +0 -280
  211. package/dist/middleware/index.d.ts +0 -2
  212. package/dist/middleware/index.js +0 -3
  213. package/dist/utils/execution.d.ts +0 -22
  214. package/dist/utils/execution.js +0 -25
  215. /package/drizzle/{0000_exotic_mysterio.sql → runtime/0000_exotic_mysterio.sql} +0 -0
  216. /package/drizzle/{0001_calm_sheva_callister.sql → runtime/0001_calm_sheva_callister.sql} +0 -0
  217. /package/drizzle/{0002_puzzling_goblin_queen.sql → runtime/0002_puzzling_goblin_queen.sql} +0 -0
  218. /package/drizzle/{0003_sweet_human_robot.sql → runtime/0003_sweet_human_robot.sql} +0 -0
  219. /package/drizzle/{0004_cuddly_shooting_star.sql → runtime/0004_cuddly_shooting_star.sql} +0 -0
  220. /package/drizzle/{0005_reflective_starfox.sql → runtime/0005_reflective_starfox.sql} +0 -0
  221. /package/drizzle/{0006_stale_thaddeus_ross.sql → runtime/0006_stale_thaddeus_ross.sql} +0 -0
  222. /package/drizzle/{0007_slim_karma.sql → runtime/0007_slim_karma.sql} +0 -0
  223. /package/drizzle/{meta → runtime/meta}/0000_snapshot.json +0 -0
  224. /package/drizzle/{meta → runtime/meta}/0001_snapshot.json +0 -0
  225. /package/drizzle/{meta → runtime/meta}/0003_snapshot.json +0 -0
  226. /package/drizzle/{meta → runtime/meta}/0005_snapshot.json +0 -0
  227. /package/drizzle/{meta → runtime/meta}/0006_snapshot.json +0 -0
  228. /package/drizzle/{meta → runtime/meta}/0007_snapshot.json +0 -0
@@ -0,0 +1,140 @@
1
+ import { getLogger } from "./logger.js";
2
+ import { extractBearerToken, hasIssuer, signJwt, verifyJwt } from "./jwt-helpers.js";
3
+
4
+ //#region src/utils/internal-service-auth.ts
5
+ const logger = getLogger("internal-service-auth");
6
+ const ISSUER = "inkeep-agents-internal";
7
+ /**
8
+ * Known internal services that can authenticate
9
+ */
10
+ const InternalServices = {
11
+ INKEEP_AGENTS_RUN_API: "inkeep-agents-run-api",
12
+ INKEEP_AGENTS_MANAGE_API: "inkeep-agents-manage-api",
13
+ INKEEP_AGENTS_EVAL_API: "inkeep-agents-eval-api"
14
+ };
15
+ /**
16
+ * Generate an internal service token for service-to-service authentication
17
+ */
18
+ async function generateInternalServiceToken(params) {
19
+ try {
20
+ const claims = {};
21
+ if (params.tenantId) claims.tenantId = params.tenantId;
22
+ if (params.projectId) claims.projectId = params.projectId;
23
+ if (params.userId) claims.userId = params.userId;
24
+ const token = await signJwt({
25
+ issuer: ISSUER,
26
+ subject: params.serviceId,
27
+ expiresIn: params.expiresIn || "5m",
28
+ claims
29
+ });
30
+ logger.debug({
31
+ serviceId: params.serviceId,
32
+ tenantId: params.tenantId,
33
+ projectId: params.projectId
34
+ }, "Generated internal service token");
35
+ return token;
36
+ } catch (error) {
37
+ logger.error({ error }, "Failed to generate internal service token");
38
+ throw new Error("Failed to generate internal service token");
39
+ }
40
+ }
41
+ /**
42
+ * Verify and decode an internal service token
43
+ */
44
+ async function verifyInternalServiceToken(token) {
45
+ const result = await verifyJwt(token, { issuer: ISSUER });
46
+ if (!result.valid || !result.payload) {
47
+ logger.warn({ error: result.error }, "Internal service token verification failed");
48
+ return {
49
+ valid: false,
50
+ error: result.error
51
+ };
52
+ }
53
+ const payload = result.payload;
54
+ if (typeof payload.sub !== "string") {
55
+ logger.warn({ payload }, "Invalid internal service token: missing subject");
56
+ return {
57
+ valid: false,
58
+ error: "Invalid token: missing service identifier"
59
+ };
60
+ }
61
+ if (!Object.values(InternalServices).includes(payload.sub)) {
62
+ logger.warn({ serviceId: payload.sub }, "Unknown service identifier in token");
63
+ return {
64
+ valid: false,
65
+ error: `Unknown service identifier: ${payload.sub}`
66
+ };
67
+ }
68
+ const validPayload = {
69
+ iss: payload.iss,
70
+ sub: payload.sub,
71
+ tenantId: payload.tenantId,
72
+ projectId: payload.projectId,
73
+ userId: payload.userId,
74
+ iat: payload.iat,
75
+ exp: payload.exp
76
+ };
77
+ logger.debug({
78
+ serviceId: validPayload.sub,
79
+ tenantId: validPayload.tenantId,
80
+ projectId: validPayload.projectId,
81
+ userId: validPayload.userId
82
+ }, "Successfully verified internal service token");
83
+ return {
84
+ valid: true,
85
+ payload: validPayload
86
+ };
87
+ }
88
+ /**
89
+ * Extract and verify an internal service token from Authorization header
90
+ */
91
+ async function verifyInternalServiceAuthHeader(authHeader) {
92
+ const extracted = extractBearerToken(authHeader);
93
+ if (!extracted.token) return {
94
+ valid: false,
95
+ error: extracted.error
96
+ };
97
+ return verifyInternalServiceToken(extracted.token);
98
+ }
99
+ /**
100
+ * Check if a token is an internal service token (vs user/agent token)
101
+ * by checking the issuer claim without full verification
102
+ */
103
+ function isInternalServiceToken(token) {
104
+ return hasIssuer(token, ISSUER);
105
+ }
106
+ /**
107
+ * Validate that the token has access to the specified tenant.
108
+ * If token has no tenantId claim, it has access to all tenants (superuser service).
109
+ */
110
+ function validateInternalServiceTenantAccess(payload, tenantId) {
111
+ if (!payload.tenantId) return true;
112
+ if (payload.tenantId !== tenantId) {
113
+ logger.warn({
114
+ tokenTenantId: payload.tenantId,
115
+ requestedTenantId: tenantId,
116
+ serviceId: payload.sub
117
+ }, "Internal service token tenant mismatch");
118
+ return false;
119
+ }
120
+ return true;
121
+ }
122
+ /**
123
+ * Validate that the token has access to the specified project.
124
+ * If token has no projectId claim, it has access to all projects in the allowed tenant(s).
125
+ */
126
+ function validateInternalServiceProjectAccess(payload, projectId) {
127
+ if (!payload.projectId) return true;
128
+ if (payload.projectId !== projectId) {
129
+ logger.warn({
130
+ tokenProjectId: payload.projectId,
131
+ requestedProjectId: projectId,
132
+ serviceId: payload.sub
133
+ }, "Internal service token project mismatch");
134
+ return false;
135
+ }
136
+ return true;
137
+ }
138
+
139
+ //#endregion
140
+ export { InternalServices, generateInternalServiceToken, isInternalServiceToken, validateInternalServiceProjectAccess, validateInternalServiceTenantAccess, verifyInternalServiceAuthHeader, verifyInternalServiceToken };
@@ -0,0 +1,56 @@
1
+ //#region src/utils/jwt-helpers.d.ts
2
+ /**
3
+ * Get the JWT signing secret from environment variables.
4
+ * Falls back to an insecure default in non-production environments.
5
+ */
6
+ declare function getJwtSecret(): Uint8Array;
7
+ /**
8
+ * Common verification result structure
9
+ */
10
+ interface JwtVerifyResult<T> {
11
+ valid: boolean;
12
+ payload?: T;
13
+ error?: string;
14
+ }
15
+ /**
16
+ * Options for signing a JWT
17
+ */
18
+ interface SignJwtOptions {
19
+ issuer: string;
20
+ subject: string;
21
+ audience?: string;
22
+ expiresIn?: string;
23
+ claims?: Record<string, unknown>;
24
+ }
25
+ /**
26
+ * Sign a JWT with the shared secret
27
+ */
28
+ declare function signJwt(options: SignJwtOptions): Promise<string>;
29
+ /**
30
+ * Options for verifying a JWT
31
+ */
32
+ interface VerifyJwtOptions {
33
+ issuer: string;
34
+ audience?: string;
35
+ }
36
+ /**
37
+ * Verify a JWT and return the raw payload
38
+ */
39
+ declare function verifyJwt(token: string, options: VerifyJwtOptions): Promise<JwtVerifyResult<Record<string, unknown>>>;
40
+ /**
41
+ * Extract bearer token from Authorization header
42
+ */
43
+ declare function extractBearerToken(authHeader: string | undefined): {
44
+ token?: string;
45
+ error?: string;
46
+ };
47
+ /**
48
+ * Decode JWT payload without verification (for checking issuer before full verify)
49
+ */
50
+ declare function decodeJwtPayload(token: string): Record<string, unknown> | null;
51
+ /**
52
+ * Check if a token has a specific issuer (without full verification)
53
+ */
54
+ declare function hasIssuer(token: string, issuer: string): boolean;
55
+ //#endregion
56
+ export { JwtVerifyResult, SignJwtOptions, VerifyJwtOptions, decodeJwtPayload, extractBearerToken, getJwtSecret, hasIssuer, signJwt, verifyJwt };
@@ -0,0 +1,90 @@
1
+ import { env } from "../env.js";
2
+ import { getLogger } from "./logger.js";
3
+ import { SignJWT, jwtVerify } from "jose";
4
+
5
+ //#region src/utils/jwt-helpers.ts
6
+ const logger = getLogger("jwt-helpers");
7
+ const DEV_SECRET = "insecure-dev-secret-change-in-production-min-32-chars";
8
+ /**
9
+ * Get the JWT signing secret from environment variables.
10
+ * Falls back to an insecure default in non-production environments.
11
+ */
12
+ function getJwtSecret() {
13
+ const secret = env.INKEEP_AGENTS_JWT_SIGNING_SECRET;
14
+ if (!secret) {
15
+ if (env.ENVIRONMENT === "production") throw new Error("INKEEP_AGENTS_JWT_SIGNING_SECRET environment variable is required in production");
16
+ logger.warn({}, "INKEEP_AGENTS_JWT_SIGNING_SECRET not set, using insecure default. DO NOT USE IN PRODUCTION!");
17
+ return new TextEncoder().encode(DEV_SECRET);
18
+ }
19
+ return new TextEncoder().encode(secret);
20
+ }
21
+ /**
22
+ * Sign a JWT with the shared secret
23
+ */
24
+ async function signJwt(options) {
25
+ const secret = getJwtSecret();
26
+ const builder = new SignJWT(options.claims || {}).setProtectedHeader({
27
+ alg: "HS256",
28
+ typ: "JWT"
29
+ }).setIssuer(options.issuer).setSubject(options.subject).setIssuedAt().setExpirationTime(options.expiresIn || "5m");
30
+ if (options.audience) builder.setAudience(options.audience);
31
+ return builder.sign(secret);
32
+ }
33
+ /**
34
+ * Verify a JWT and return the raw payload
35
+ */
36
+ async function verifyJwt(token, options) {
37
+ const secret = getJwtSecret();
38
+ try {
39
+ const verifyOptions = {
40
+ issuer: options.issuer,
41
+ algorithms: ["HS256"]
42
+ };
43
+ if (options.audience) verifyOptions.audience = options.audience;
44
+ const { payload } = await jwtVerify(token, secret, verifyOptions);
45
+ return {
46
+ valid: true,
47
+ payload
48
+ };
49
+ } catch (error) {
50
+ if (error instanceof Error) return {
51
+ valid: false,
52
+ error: error.message
53
+ };
54
+ return {
55
+ valid: false,
56
+ error: "Token verification failed"
57
+ };
58
+ }
59
+ }
60
+ /**
61
+ * Extract bearer token from Authorization header
62
+ */
63
+ function extractBearerToken(authHeader) {
64
+ if (!authHeader) return { error: "Missing Authorization header" };
65
+ if (!authHeader.startsWith("Bearer ")) return { error: "Invalid Authorization header format. Expected: Bearer <token>" };
66
+ const token = authHeader.substring(7);
67
+ if (!token) return { error: "Empty token in Authorization header" };
68
+ return { token };
69
+ }
70
+ /**
71
+ * Decode JWT payload without verification (for checking issuer before full verify)
72
+ */
73
+ function decodeJwtPayload(token) {
74
+ try {
75
+ const parts = token.split(".");
76
+ if (parts.length !== 3) return null;
77
+ return JSON.parse(Buffer.from(parts[1], "base64url").toString());
78
+ } catch {
79
+ return null;
80
+ }
81
+ }
82
+ /**
83
+ * Check if a token has a specific issuer (without full verification)
84
+ */
85
+ function hasIssuer(token, issuer) {
86
+ return decodeJwtPayload(token)?.iss === issuer;
87
+ }
88
+
89
+ //#endregion
90
+ export { decodeJwtPayload, extractBearerToken, getJwtSecret, hasIssuer, signJwt, verifyJwt };
@@ -1,6 +1,9 @@
1
+ import { JwtVerifyResult } from "./jwt-helpers.js";
2
+
1
3
  //#region src/utils/service-token-auth.d.ts
4
+
2
5
  /**
3
- * Service Token JWT Claims
6
+ * Service Token JWT Claims (for agent-to-agent communication)
4
7
  */
5
8
  interface ServiceTokenPayload {
6
9
  /** Issuer - always 'inkeep-agents' */
@@ -30,48 +33,27 @@ interface GenerateServiceTokenParams {
30
33
  /**
31
34
  * Result of verifying a service token
32
35
  */
33
- interface VerifyServiceTokenResult {
34
- valid: boolean;
35
- payload?: ServiceTokenPayload;
36
- error?: string;
37
- }
36
+ type VerifyServiceTokenResult = JwtVerifyResult<ServiceTokenPayload>;
38
37
  /**
39
- * Generate a JWT token for team agent authentication
40
- * Token expires in 5 minutes
41
- *
42
- * @param params - Token generation parameters
43
- * @returns Signed JWT token string
38
+ * Generate a JWT token for agent-to-agent authentication.
39
+ * Token expires in 5 minutes.
44
40
  */
45
41
  declare function generateServiceToken(params: GenerateServiceTokenParams): Promise<string>;
46
42
  /**
47
43
  * Verify and decode a service JWT token
48
- *
49
- * @param token - JWT token string to verify
50
- * @returns Verification result with payload if valid
51
44
  */
52
45
  declare function verifyServiceToken(token: string): Promise<VerifyServiceTokenResult>;
53
46
  /**
54
- * Validate that the token's tenant ID matches the expected tenant
55
- * This prevents cross-tenant delegation attempts
56
- *
57
- * @param payload - Decoded token payload
58
- * @param expectedTenantId - The tenant ID to validate against
59
- * @returns true if tenant IDs match, false otherwise
47
+ * Validate that the token's tenant ID matches the expected tenant.
48
+ * This prevents cross-tenant delegation attempts.
60
49
  */
61
50
  declare function validateTenantId(payload: ServiceTokenPayload, expectedTenantId: string): boolean;
62
51
  /**
63
52
  * Validate that the token's target agent ID matches the expected agent
64
- *
65
- * @param payload - Decoded token payload
66
- * @param expectedTargetAgentId - The agent ID to validate against
67
- * @returns true if agent IDs match, false otherwise
68
53
  */
69
54
  declare function validateTargetAgent(payload: ServiceTokenPayload, expectedTargetAgentId: string): boolean;
70
55
  /**
71
56
  * Extract the Authorization header and verify the bearer token
72
- *
73
- * @param authHeader - The Authorization header value (e.g., "Bearer <token>")
74
- * @returns Verification result with payload if valid
75
57
  */
76
58
  declare function verifyAuthorizationHeader(authHeader: string | undefined): Promise<VerifyServiceTokenResult>;
77
59
  //#endregion
@@ -1,40 +1,25 @@
1
- import { env } from "../env.js";
2
1
  import { getLogger } from "./logger.js";
3
- import { SignJWT, jwtVerify } from "jose";
2
+ import { extractBearerToken, signJwt, verifyJwt } from "./jwt-helpers.js";
4
3
 
5
4
  //#region src/utils/service-token-auth.ts
6
5
  const logger = getLogger("service-token-auth");
6
+ const ISSUER = "inkeep-agents";
7
7
  /**
8
- * Get the JWT secret from environment variables
9
- * Falls back to a default secret in non-production environments (with warning)
10
- */
11
- function getJwtSecret() {
12
- const secret = env.INKEEP_AGENTS_JWT_SIGNING_SECRET;
13
- const dev_secret = "insecure-dev-secret-change-in-production-min-32-chars";
14
- if (!secret) {
15
- if (env.ENVIRONMENT === "production") throw new Error("INKEEP_AGENTS_JWT_SIGNING_SECRET environment variable is required in production");
16
- logger.warn({}, "INKEEP_AGENTS_JWT_SIGNING_SECRET not set, using insecure default. DO NOT USE IN PRODUCTION!");
17
- return new TextEncoder().encode(dev_secret);
18
- }
19
- return new TextEncoder().encode(secret);
20
- }
21
- /**
22
- * Generate a JWT token for team agent authentication
23
- * Token expires in 5 minutes
24
- *
25
- * @param params - Token generation parameters
26
- * @returns Signed JWT token string
8
+ * Generate a JWT token for agent-to-agent authentication.
9
+ * Token expires in 5 minutes.
27
10
  */
28
11
  async function generateServiceToken(params) {
29
- const secret = getJwtSecret();
30
12
  try {
31
- const token = await new SignJWT({
32
- tenantId: params.tenantId,
33
- projectId: params.projectId
34
- }).setProtectedHeader({
35
- alg: "HS256",
36
- typ: "JWT"
37
- }).setIssuer("inkeep-agents").setSubject(params.originAgentId).setAudience(params.targetAgentId).setIssuedAt().setExpirationTime("5m").sign(secret);
13
+ const token = await signJwt({
14
+ issuer: ISSUER,
15
+ subject: params.originAgentId,
16
+ audience: params.targetAgentId,
17
+ expiresIn: "5m",
18
+ claims: {
19
+ tenantId: params.tenantId,
20
+ projectId: params.projectId
21
+ }
22
+ });
38
23
  logger.debug({
39
24
  originAgentId: params.originAgentId,
40
25
  targetAgentId: params.targetAgentId,
@@ -48,64 +33,46 @@ async function generateServiceToken(params) {
48
33
  }
49
34
  /**
50
35
  * Verify and decode a service JWT token
51
- *
52
- * @param token - JWT token string to verify
53
- * @returns Verification result with payload if valid
54
36
  */
55
37
  async function verifyServiceToken(token) {
56
- const secret = getJwtSecret();
57
- try {
58
- const { payload } = await jwtVerify(token, secret, {
59
- issuer: "inkeep-agents",
60
- algorithms: ["HS256"]
61
- });
62
- if (typeof payload.sub !== "string" || typeof payload.aud !== "string" || typeof payload.tenantId !== "string" || typeof payload.projectId !== "string") {
63
- logger.warn({ payload }, "Invalid service token: missing required claims");
64
- return {
65
- valid: false,
66
- error: "Invalid token: missing required claims"
67
- };
68
- }
69
- const validPayload = {
70
- iss: payload.iss,
71
- aud: payload.aud,
72
- sub: payload.sub,
73
- tenantId: payload.tenantId,
74
- projectId: payload.projectId,
75
- iat: payload.iat,
76
- exp: payload.exp
77
- };
78
- logger.debug({
79
- originAgentId: validPayload.sub,
80
- targetAgentId: validPayload.aud,
81
- tenantId: validPayload.tenantId
82
- }, "Successfully verified team agent token");
38
+ const result = await verifyJwt(token, { issuer: ISSUER });
39
+ if (!result.valid || !result.payload) {
40
+ logger.warn({ error: result.error }, "Team agent token verification failed");
83
41
  return {
84
- valid: true,
85
- payload: validPayload
42
+ valid: false,
43
+ error: result.error
86
44
  };
87
- } catch (error) {
88
- if (error instanceof Error) {
89
- logger.warn({ error: error.message }, "Team agent token verification failed");
90
- return {
91
- valid: false,
92
- error: error.message
93
- };
94
- }
95
- logger.warn({ error }, "Team agent token verification failed with unknown error");
45
+ }
46
+ const payload = result.payload;
47
+ if (typeof payload.sub !== "string" || typeof payload.aud !== "string" || typeof payload.tenantId !== "string" || typeof payload.projectId !== "string") {
48
+ logger.warn({ payload }, "Invalid service token: missing required claims");
96
49
  return {
97
50
  valid: false,
98
- error: "Token verification failed"
51
+ error: "Invalid token: missing required claims"
99
52
  };
100
53
  }
54
+ const validPayload = {
55
+ iss: payload.iss,
56
+ aud: payload.aud,
57
+ sub: payload.sub,
58
+ tenantId: payload.tenantId,
59
+ projectId: payload.projectId,
60
+ iat: payload.iat,
61
+ exp: payload.exp
62
+ };
63
+ logger.debug({
64
+ originAgentId: validPayload.sub,
65
+ targetAgentId: validPayload.aud,
66
+ tenantId: validPayload.tenantId
67
+ }, "Successfully verified team agent token");
68
+ return {
69
+ valid: true,
70
+ payload: validPayload
71
+ };
101
72
  }
102
73
  /**
103
- * Validate that the token's tenant ID matches the expected tenant
104
- * This prevents cross-tenant delegation attempts
105
- *
106
- * @param payload - Decoded token payload
107
- * @param expectedTenantId - The tenant ID to validate against
108
- * @returns true if tenant IDs match, false otherwise
74
+ * Validate that the token's tenant ID matches the expected tenant.
75
+ * This prevents cross-tenant delegation attempts.
109
76
  */
110
77
  function validateTenantId(payload, expectedTenantId) {
111
78
  if (payload.tenantId !== expectedTenantId) {
@@ -121,10 +88,6 @@ function validateTenantId(payload, expectedTenantId) {
121
88
  }
122
89
  /**
123
90
  * Validate that the token's target agent ID matches the expected agent
124
- *
125
- * @param payload - Decoded token payload
126
- * @param expectedTargetAgentId - The agent ID to validate against
127
- * @returns true if agent IDs match, false otherwise
128
91
  */
129
92
  function validateTargetAgent(payload, expectedTargetAgentId) {
130
93
  if (payload.aud !== expectedTargetAgentId) {
@@ -139,25 +102,14 @@ function validateTargetAgent(payload, expectedTargetAgentId) {
139
102
  }
140
103
  /**
141
104
  * Extract the Authorization header and verify the bearer token
142
- *
143
- * @param authHeader - The Authorization header value (e.g., "Bearer <token>")
144
- * @returns Verification result with payload if valid
145
105
  */
146
106
  async function verifyAuthorizationHeader(authHeader) {
147
- if (!authHeader) return {
148
- valid: false,
149
- error: "Missing Authorization header"
150
- };
151
- if (!authHeader.startsWith("Bearer ")) return {
152
- valid: false,
153
- error: "Invalid Authorization header format. Expected: Bearer <token>"
154
- };
155
- const token = authHeader.substring(7);
156
- if (!token) return {
107
+ const extracted = extractBearerToken(authHeader);
108
+ if (!extracted.token) return {
157
109
  valid: false,
158
- error: "Empty token in Authorization header"
110
+ error: extracted.error
159
111
  };
160
- return verifyServiceToken(token);
112
+ return verifyServiceToken(extracted.token);
161
113
  }
162
114
 
163
115
  //#endregion
@@ -0,0 +1,22 @@
1
+ //#region src/utils/template-interpolation.d.ts
2
+ /**
3
+ * Interpolates a message template with placeholders from a payload object.
4
+ * Supports {{path.to.value}} placeholder syntax with dot notation for nested paths.
5
+ * Missing values are replaced with empty strings.
6
+ *
7
+ * @param template - Message template with {{placeholder}} syntax
8
+ * @param payload - Object containing values to interpolate
9
+ * @returns Interpolated message with all placeholders resolved
10
+ *
11
+ * @example
12
+ * const template = "User {{user.name}} from {{user.profile.location}} submitted: {{message}}";
13
+ * const payload = {
14
+ * user: { name: "Alice", profile: { location: "NYC" } },
15
+ * message: "Hello World"
16
+ * };
17
+ * interpolateTemplate(template, payload);
18
+ * // => "User Alice from NYC submitted: Hello World"
19
+ */
20
+ declare function interpolateTemplate(template: string, payload: Record<string, unknown>): string;
21
+ //#endregion
22
+ export { interpolateTemplate };
@@ -0,0 +1,62 @@
1
+ //#region src/utils/template-interpolation.ts
2
+ /**
3
+ * Resolves a nested path from an object using dot notation.
4
+ * Example: getValue({ user: { profile: { name: 'John' } } }, 'user.profile.name') => 'John'
5
+ *
6
+ * @param obj - The object to traverse
7
+ * @param path - Dot-separated path (e.g., 'user.profile.name')
8
+ * @returns The value at the path, or undefined if not found
9
+ */
10
+ function getValue(obj, path) {
11
+ if (!obj || typeof obj !== "object") return;
12
+ const keys = path.split(".");
13
+ let current = obj;
14
+ for (const key of keys) {
15
+ if (current === null || current === void 0 || typeof current !== "object") return;
16
+ current = current[key];
17
+ }
18
+ return current;
19
+ }
20
+ /**
21
+ * Converts a value to string for template interpolation.
22
+ * Handles primitives, null, undefined gracefully.
23
+ *
24
+ * @param value - The value to convert
25
+ * @returns String representation or empty string if undefined/null
26
+ */
27
+ function valueToString(value) {
28
+ if (value === null || value === void 0) return "";
29
+ if (typeof value === "string") return value;
30
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
31
+ try {
32
+ return JSON.stringify(value);
33
+ } catch {
34
+ return "";
35
+ }
36
+ }
37
+ /**
38
+ * Interpolates a message template with placeholders from a payload object.
39
+ * Supports {{path.to.value}} placeholder syntax with dot notation for nested paths.
40
+ * Missing values are replaced with empty strings.
41
+ *
42
+ * @param template - Message template with {{placeholder}} syntax
43
+ * @param payload - Object containing values to interpolate
44
+ * @returns Interpolated message with all placeholders resolved
45
+ *
46
+ * @example
47
+ * const template = "User {{user.name}} from {{user.profile.location}} submitted: {{message}}";
48
+ * const payload = {
49
+ * user: { name: "Alice", profile: { location: "NYC" } },
50
+ * message: "Hello World"
51
+ * };
52
+ * interpolateTemplate(template, payload);
53
+ * // => "User Alice from NYC submitted: Hello World"
54
+ */
55
+ function interpolateTemplate(template, payload) {
56
+ return template.replace(/\{\{([^}]+)\}\}/g, (_match, path) => {
57
+ return valueToString(getValue(payload, path.trim()));
58
+ });
59
+ }
60
+
61
+ //#endregion
62
+ export { interpolateTemplate };