@kilnai/runtime 0.1.1

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 (205) hide show
  1. package/dist/a2a/a2a-client.d.ts +6 -0
  2. package/dist/a2a/a2a-client.d.ts.map +1 -0
  3. package/dist/a2a/a2a-client.js +112 -0
  4. package/dist/a2a/a2a-client.js.map +1 -0
  5. package/dist/a2a/index.d.ts +2 -0
  6. package/dist/a2a/index.d.ts.map +1 -0
  7. package/dist/a2a/index.js +3 -0
  8. package/dist/a2a/index.js.map +1 -0
  9. package/dist/channels/api-channel.d.ts +43 -0
  10. package/dist/channels/api-channel.d.ts.map +1 -0
  11. package/dist/channels/api-channel.js +95 -0
  12. package/dist/channels/api-channel.js.map +1 -0
  13. package/dist/channels/channel-registry.d.ts +25 -0
  14. package/dist/channels/channel-registry.d.ts.map +1 -0
  15. package/dist/channels/channel-registry.js +49 -0
  16. package/dist/channels/channel-registry.js.map +1 -0
  17. package/dist/channels/channel-router.d.ts +43 -0
  18. package/dist/channels/channel-router.d.ts.map +1 -0
  19. package/dist/channels/channel-router.js +72 -0
  20. package/dist/channels/channel-router.js.map +1 -0
  21. package/dist/channels/cli-channel.d.ts +19 -0
  22. package/dist/channels/cli-channel.d.ts.map +1 -0
  23. package/dist/channels/cli-channel.js +37 -0
  24. package/dist/channels/cli-channel.js.map +1 -0
  25. package/dist/channels/event-bridge.d.ts +27 -0
  26. package/dist/channels/event-bridge.d.ts.map +1 -0
  27. package/dist/channels/event-bridge.js +83 -0
  28. package/dist/channels/event-bridge.js.map +1 -0
  29. package/dist/channels/index.d.ts +17 -0
  30. package/dist/channels/index.d.ts.map +1 -0
  31. package/dist/channels/index.js +12 -0
  32. package/dist/channels/index.js.map +1 -0
  33. package/dist/channels/message-formatter.d.ts +4 -0
  34. package/dist/channels/message-formatter.d.ts.map +1 -0
  35. package/dist/channels/message-formatter.js +32 -0
  36. package/dist/channels/message-formatter.js.map +1 -0
  37. package/dist/channels/slack-channel.d.ts +32 -0
  38. package/dist/channels/slack-channel.d.ts.map +1 -0
  39. package/dist/channels/slack-channel.js +71 -0
  40. package/dist/channels/slack-channel.js.map +1 -0
  41. package/dist/channels/types.d.ts +27 -0
  42. package/dist/channels/types.d.ts.map +1 -0
  43. package/dist/channels/types.js +12 -0
  44. package/dist/channels/types.js.map +1 -0
  45. package/dist/channels/web-channel.d.ts +37 -0
  46. package/dist/channels/web-channel.d.ts.map +1 -0
  47. package/dist/channels/web-channel.js +112 -0
  48. package/dist/channels/web-channel.js.map +1 -0
  49. package/dist/channels/whatsapp-api.d.ts +20 -0
  50. package/dist/channels/whatsapp-api.d.ts.map +1 -0
  51. package/dist/channels/whatsapp-api.js +44 -0
  52. package/dist/channels/whatsapp-api.js.map +1 -0
  53. package/dist/channels/whatsapp-channel.d.ts +32 -0
  54. package/dist/channels/whatsapp-channel.d.ts.map +1 -0
  55. package/dist/channels/whatsapp-channel.js +85 -0
  56. package/dist/channels/whatsapp-channel.js.map +1 -0
  57. package/dist/gateway/app-resolver.d.ts +11 -0
  58. package/dist/gateway/app-resolver.d.ts.map +1 -0
  59. package/dist/gateway/app-resolver.js +36 -0
  60. package/dist/gateway/app-resolver.js.map +1 -0
  61. package/dist/gateway/approval-registry.d.ts +19 -0
  62. package/dist/gateway/approval-registry.d.ts.map +1 -0
  63. package/dist/gateway/approval-registry.js +49 -0
  64. package/dist/gateway/approval-registry.js.map +1 -0
  65. package/dist/gateway/budget-middleware.d.ts +47 -0
  66. package/dist/gateway/budget-middleware.d.ts.map +1 -0
  67. package/dist/gateway/budget-middleware.js +88 -0
  68. package/dist/gateway/budget-middleware.js.map +1 -0
  69. package/dist/gateway/config-validator.d.ts +31 -0
  70. package/dist/gateway/config-validator.d.ts.map +1 -0
  71. package/dist/gateway/config-validator.js +68 -0
  72. package/dist/gateway/config-validator.js.map +1 -0
  73. package/dist/gateway/delegation-handler.d.ts +53 -0
  74. package/dist/gateway/delegation-handler.d.ts.map +1 -0
  75. package/dist/gateway/delegation-handler.js +257 -0
  76. package/dist/gateway/delegation-handler.js.map +1 -0
  77. package/dist/gateway/delegation-routes.d.ts +7 -0
  78. package/dist/gateway/delegation-routes.d.ts.map +1 -0
  79. package/dist/gateway/delegation-routes.js +48 -0
  80. package/dist/gateway/delegation-routes.js.map +1 -0
  81. package/dist/gateway/dev-inspector.d.ts +2 -0
  82. package/dist/gateway/dev-inspector.d.ts.map +1 -0
  83. package/dist/gateway/dev-inspector.js +355 -0
  84. package/dist/gateway/dev-inspector.js.map +1 -0
  85. package/dist/gateway/dev-orchestrator.d.ts +24 -0
  86. package/dist/gateway/dev-orchestrator.d.ts.map +1 -0
  87. package/dist/gateway/dev-orchestrator.js +71 -0
  88. package/dist/gateway/dev-orchestrator.js.map +1 -0
  89. package/dist/gateway/dev-routes-types.d.ts +39 -0
  90. package/dist/gateway/dev-routes-types.d.ts.map +1 -0
  91. package/dist/gateway/dev-routes-types.js +3 -0
  92. package/dist/gateway/dev-routes-types.js.map +1 -0
  93. package/dist/gateway/dev-routes.d.ts +53 -0
  94. package/dist/gateway/dev-routes.d.ts.map +1 -0
  95. package/dist/gateway/dev-routes.js +217 -0
  96. package/dist/gateway/dev-routes.js.map +1 -0
  97. package/dist/gateway/dev-token-store.d.ts +19 -0
  98. package/dist/gateway/dev-token-store.d.ts.map +1 -0
  99. package/dist/gateway/dev-token-store.js +40 -0
  100. package/dist/gateway/dev-token-store.js.map +1 -0
  101. package/dist/gateway/gateway-routes.d.ts +46 -0
  102. package/dist/gateway/gateway-routes.d.ts.map +1 -0
  103. package/dist/gateway/gateway-routes.js +143 -0
  104. package/dist/gateway/gateway-routes.js.map +1 -0
  105. package/dist/gateway/gateway-server.d.ts +25 -0
  106. package/dist/gateway/gateway-server.d.ts.map +1 -0
  107. package/dist/gateway/gateway-server.js +736 -0
  108. package/dist/gateway/gateway-server.js.map +1 -0
  109. package/dist/gateway/health-registry.d.ts +18 -0
  110. package/dist/gateway/health-registry.d.ts.map +1 -0
  111. package/dist/gateway/health-registry.js +40 -0
  112. package/dist/gateway/health-registry.js.map +1 -0
  113. package/dist/gateway/memory-routes.d.ts +12 -0
  114. package/dist/gateway/memory-routes.d.ts.map +1 -0
  115. package/dist/gateway/memory-routes.js +32 -0
  116. package/dist/gateway/memory-routes.js.map +1 -0
  117. package/dist/gateway/mode-b-routes.d.ts +14 -0
  118. package/dist/gateway/mode-b-routes.d.ts.map +1 -0
  119. package/dist/gateway/mode-b-routes.js +96 -0
  120. package/dist/gateway/mode-b-routes.js.map +1 -0
  121. package/dist/gateway/safety-middleware.d.ts +21 -0
  122. package/dist/gateway/safety-middleware.d.ts.map +1 -0
  123. package/dist/gateway/safety-middleware.js +175 -0
  124. package/dist/gateway/safety-middleware.js.map +1 -0
  125. package/dist/gateway/security-middleware.d.ts +12 -0
  126. package/dist/gateway/security-middleware.d.ts.map +1 -0
  127. package/dist/gateway/security-middleware.js +62 -0
  128. package/dist/gateway/security-middleware.js.map +1 -0
  129. package/dist/gateway/tenant-admin-routes.d.ts +15 -0
  130. package/dist/gateway/tenant-admin-routes.d.ts.map +1 -0
  131. package/dist/gateway/tenant-admin-routes.js +148 -0
  132. package/dist/gateway/tenant-admin-routes.js.map +1 -0
  133. package/dist/gateway/tenant-routes.d.ts +15 -0
  134. package/dist/gateway/tenant-routes.d.ts.map +1 -0
  135. package/dist/gateway/tenant-routes.js +107 -0
  136. package/dist/gateway/tenant-routes.js.map +1 -0
  137. package/dist/gateway/whatsapp-webhook-routes.d.ts +15 -0
  138. package/dist/gateway/whatsapp-webhook-routes.d.ts.map +1 -0
  139. package/dist/gateway/whatsapp-webhook-routes.js +217 -0
  140. package/dist/gateway/whatsapp-webhook-routes.js.map +1 -0
  141. package/dist/gateway/ws-routes.d.ts +19 -0
  142. package/dist/gateway/ws-routes.d.ts.map +1 -0
  143. package/dist/gateway/ws-routes.js +79 -0
  144. package/dist/gateway/ws-routes.js.map +1 -0
  145. package/dist/index.d.ts +64 -0
  146. package/dist/index.d.ts.map +1 -0
  147. package/dist/index.js +44 -0
  148. package/dist/index.js.map +1 -0
  149. package/dist/session/index.d.ts +6 -0
  150. package/dist/session/index.d.ts.map +1 -0
  151. package/dist/session/index.js +4 -0
  152. package/dist/session/index.js.map +1 -0
  153. package/dist/session/mode-b-orchestrator.d.ts +43 -0
  154. package/dist/session/mode-b-orchestrator.d.ts.map +1 -0
  155. package/dist/session/mode-b-orchestrator.js +224 -0
  156. package/dist/session/mode-b-orchestrator.js.map +1 -0
  157. package/dist/session/mode-b-session.d.ts +29 -0
  158. package/dist/session/mode-b-session.d.ts.map +1 -0
  159. package/dist/session/mode-b-session.js +50 -0
  160. package/dist/session/mode-b-session.js.map +1 -0
  161. package/dist/session/session-registry.d.ts +15 -0
  162. package/dist/session/session-registry.d.ts.map +1 -0
  163. package/dist/session/session-registry.js +60 -0
  164. package/dist/session/session-registry.js.map +1 -0
  165. package/dist/tenant/index.d.ts +3 -0
  166. package/dist/tenant/index.d.ts.map +1 -0
  167. package/dist/tenant/index.js +3 -0
  168. package/dist/tenant/index.js.map +1 -0
  169. package/dist/tenant/system-prompt-builder.d.ts +3 -0
  170. package/dist/tenant/system-prompt-builder.d.ts.map +1 -0
  171. package/dist/tenant/system-prompt-builder.js +76 -0
  172. package/dist/tenant/system-prompt-builder.js.map +1 -0
  173. package/dist/tenant/tenant-registry.d.ts +33 -0
  174. package/dist/tenant/tenant-registry.d.ts.map +1 -0
  175. package/dist/tenant/tenant-registry.js +156 -0
  176. package/dist/tenant/tenant-registry.js.map +1 -0
  177. package/dist/trigger/event-listener.d.ts +22 -0
  178. package/dist/trigger/event-listener.d.ts.map +1 -0
  179. package/dist/trigger/event-listener.js +64 -0
  180. package/dist/trigger/event-listener.js.map +1 -0
  181. package/dist/trigger/index.d.ts +10 -0
  182. package/dist/trigger/index.d.ts.map +1 -0
  183. package/dist/trigger/index.js +7 -0
  184. package/dist/trigger/index.js.map +1 -0
  185. package/dist/trigger/scheduler.d.ts +22 -0
  186. package/dist/trigger/scheduler.d.ts.map +1 -0
  187. package/dist/trigger/scheduler.js +77 -0
  188. package/dist/trigger/scheduler.js.map +1 -0
  189. package/dist/trigger/trigger-executor.d.ts +14 -0
  190. package/dist/trigger/trigger-executor.d.ts.map +1 -0
  191. package/dist/trigger/trigger-executor.js +47 -0
  192. package/dist/trigger/trigger-executor.js.map +1 -0
  193. package/dist/trigger/trigger-registry.d.ts +28 -0
  194. package/dist/trigger/trigger-registry.d.ts.map +1 -0
  195. package/dist/trigger/trigger-registry.js +118 -0
  196. package/dist/trigger/trigger-registry.js.map +1 -0
  197. package/dist/trigger/webhook-handler.d.ts +11 -0
  198. package/dist/trigger/webhook-handler.d.ts.map +1 -0
  199. package/dist/trigger/webhook-handler.js +71 -0
  200. package/dist/trigger/webhook-handler.js.map +1 -0
  201. package/dist/utils/hmac.d.ts +15 -0
  202. package/dist/utils/hmac.d.ts.map +1 -0
  203. package/dist/utils/hmac.js +27 -0
  204. package/dist/utils/hmac.js.map +1 -0
  205. package/package.json +53 -0
@@ -0,0 +1,85 @@
1
+ // WhatsAppChannel: WhatsApp Business API adapter
2
+ // Uses WhatsApp Cloud API (graph.facebook.com) via shared API client
3
+ import { extractText, textParts } from "@kilnai/core";
4
+ import { formatForChannel } from "./message-formatter.js";
5
+ import { sendWhatsAppMessage } from "./whatsapp-api.js";
6
+ /**
7
+ * Channel adapter for WhatsApp Business API.
8
+ * receive() accepts parsed webhook messages from WhatsApp Cloud API.
9
+ * send() posts text messages via graph.facebook.com.
10
+ * stream() sends each engine event as a summarized text message.
11
+ * verifyWebhook() handles the one-time webhook verification handshake.
12
+ */
13
+ export class WhatsAppChannel {
14
+ name = "whatsapp";
15
+ defaultFormat = "short";
16
+ supportedModalities = ["text", "image", "audio", "file"];
17
+ config;
18
+ messageHandler = null;
19
+ constructor(config) {
20
+ this.config = config;
21
+ }
22
+ /** Register a handler for incoming messages (from parsed webhook payloads) */
23
+ onMessage(handler) {
24
+ this.messageHandler = handler;
25
+ }
26
+ async receive(message) {
27
+ if (this.messageHandler) {
28
+ this.messageHandler(message);
29
+ }
30
+ }
31
+ async send(response) {
32
+ const { phoneNumberId, accessToken } = this.config;
33
+ const to = response.target;
34
+ // Send media parts first, then text
35
+ for (const part of response.parts) {
36
+ if (part.type === "image" && part.url) {
37
+ await sendWhatsAppMessage(phoneNumberId, accessToken, to, {
38
+ type: "image",
39
+ image: { link: part.url },
40
+ });
41
+ }
42
+ else if (part.type === "audio" && part.url) {
43
+ await sendWhatsAppMessage(phoneNumberId, accessToken, to, {
44
+ type: "audio",
45
+ audio: { link: part.url },
46
+ });
47
+ }
48
+ else if (part.type === "file" && part.url) {
49
+ await sendWhatsAppMessage(phoneNumberId, accessToken, to, {
50
+ type: "document",
51
+ document: { link: part.url, filename: part.filename },
52
+ });
53
+ }
54
+ }
55
+ // Send text content
56
+ const text = extractText(response.parts);
57
+ if (text) {
58
+ const formatted = formatForChannel(text, response.format ?? this.defaultFormat);
59
+ await sendWhatsAppMessage(phoneNumberId, accessToken, to, {
60
+ type: "text",
61
+ text: { body: formatted },
62
+ });
63
+ }
64
+ }
65
+ async stream(events) {
66
+ for await (const event of events) {
67
+ await this.send({
68
+ parts: textParts(`[${event.type}] ${JSON.stringify(event.payload)}`),
69
+ target: "stream",
70
+ format: this.defaultFormat,
71
+ });
72
+ }
73
+ }
74
+ /**
75
+ * Verify a WhatsApp webhook subscription request.
76
+ * Returns the challenge string if mode is "subscribe" and token matches, else null.
77
+ */
78
+ verifyWebhook(mode, token, challenge) {
79
+ if (mode === "subscribe" && token === this.config.verifyToken) {
80
+ return challenge;
81
+ }
82
+ return null;
83
+ }
84
+ }
85
+ //# sourceMappingURL=whatsapp-channel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whatsapp-channel.js","sourceRoot":"","sources":["../../src/channels/whatsapp-channel.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { App, ModeBConfig } from "@kilnai/core";
2
+ import type { GatewayConfig, GatewayAppBinding } from "@kilnai/core";
3
+ export interface ResolvedApp {
4
+ readonly name: string;
5
+ readonly app: App;
6
+ readonly binding: GatewayAppBinding;
7
+ readonly memoryBasePath: string;
8
+ readonly modeBConfig?: ModeBConfig;
9
+ }
10
+ export declare function resolveApps(config: GatewayConfig, gatewayYamlDir: string): ResolvedApp[];
11
+ //# sourceMappingURL=app-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-resolver.d.ts","sourceRoot":"","sources":["../../src/gateway/app-resolver.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAErE,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC;IAClB,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;IACpC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,CAAC;CACpC;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,GAAG,WAAW,EAAE,CAmCxF"}
@@ -0,0 +1,36 @@
1
+ // Gateway: AppResolver -- resolves GatewayConfig app bindings to loaded App composites
2
+ import { readFileSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { homedir } from "node:os";
5
+ import { parseAppYaml, parseModeBConfig, KilnError } from "@kilnai/core";
6
+ export function resolveApps(config, gatewayYamlDir) {
7
+ return config.apps.map((binding) => {
8
+ const configPath = join(gatewayYamlDir, binding.config);
9
+ let content;
10
+ try {
11
+ content = readFileSync(configPath, "utf-8");
12
+ }
13
+ catch {
14
+ throw new KilnError("CONFIG_INVALID", `Failed to load App config at ${binding.config}: file not found`, {
15
+ context: { configPath: binding.config },
16
+ });
17
+ }
18
+ let app;
19
+ try {
20
+ app = parseAppYaml(content);
21
+ }
22
+ catch (err) {
23
+ throw new KilnError("CONFIG_INVALID", `Failed to parse App config at ${binding.config}: ${err instanceof Error ? err.message : String(err)}`, { context: { configPath: binding.config }, cause: err });
24
+ }
25
+ const memoryBasePath = join(homedir(), ".kiln", "gateway", binding.name);
26
+ let modeBConfig;
27
+ try {
28
+ modeBConfig = parseModeBConfig(content) ?? undefined;
29
+ }
30
+ catch {
31
+ // Mode B parse failure is non-fatal: app may be Mode A
32
+ }
33
+ return { name: binding.name, app, binding, memoryBasePath, modeBConfig };
34
+ });
35
+ }
36
+ //# sourceMappingURL=app-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-resolver.js","sourceRoot":"","sources":["../../src/gateway/app-resolver.ts"],"names":[],"mappings":"AAAA,uFAAuF;AAEvF,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAYzE,MAAM,UAAU,WAAW,CAAC,MAAqB,EAAE,cAAsB;IACvE,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;QACjC,MAAM,UAAU,GAAG,IAAI,CAAC,cAAc,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QAExD,IAAI,OAAe,CAAC;QACpB,IAAI,CAAC;YACH,OAAO,GAAG,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAC9C,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,SAAS,CAAC,gBAAgB,EAAE,gCAAgC,OAAO,CAAC,MAAM,kBAAkB,EAAE;gBACtG,OAAO,EAAE,EAAE,UAAU,EAAE,OAAO,CAAC,MAAM,EAAE;aACxC,CAAC,CAAC;QACL,CAAC;QAED,IAAI,GAAQ,CAAC;QACb,IAAI,CAAC;YACH,GAAG,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;QAC9B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,SAAS,CACjB,gBAAgB,EAChB,iCAAiC,OAAO,CAAC,MAAM,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EACtG,EAAE,OAAO,EAAE,EAAE,UAAU,EAAE,OAAO,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CACxD,CAAC;QACJ,CAAC;QAED,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;QAEzE,IAAI,WAAoC,CAAC;QACzC,IAAI,CAAC;YACH,WAAW,GAAG,gBAAgB,CAAC,OAAO,CAAC,IAAI,SAAS,CAAC;QACvD,CAAC;QAAC,MAAM,CAAC;YACP,uDAAuD;QACzD,CAAC;QAED,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC;IAC3E,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,19 @@
1
+ export interface ApprovalTarget {
2
+ readonly approve: () => void;
3
+ readonly reject: (reason: string) => void;
4
+ readonly status: () => string;
5
+ }
6
+ export declare class ApprovalGateRegistry {
7
+ private readonly targets;
8
+ register(sessionId: string, target: ApprovalTarget): void;
9
+ unregister(sessionId: string): void;
10
+ approve(sessionId?: string): {
11
+ ok: boolean;
12
+ error?: string;
13
+ };
14
+ reject(reason: string, sessionId?: string): {
15
+ ok: boolean;
16
+ error?: string;
17
+ };
18
+ }
19
+ //# sourceMappingURL=approval-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approval-registry.d.ts","sourceRoot":"","sources":["../../src/gateway/approval-registry.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,QAAQ,CAAC,MAAM,EAAE,MAAM,MAAM,CAAC;CAC/B;AAED,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqC;IAE7D,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,GAAG,IAAI;IAIzD,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAInC,OAAO,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;IAqB5D,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;CAoB5E"}
@@ -0,0 +1,49 @@
1
+ // ApprovalGateRegistry -- tracks approval targets (orchestrators) by session ID
2
+ export class ApprovalGateRegistry {
3
+ targets = new Map();
4
+ register(sessionId, target) {
5
+ this.targets.set(sessionId, target);
6
+ }
7
+ unregister(sessionId) {
8
+ this.targets.delete(sessionId);
9
+ }
10
+ approve(sessionId) {
11
+ if (sessionId !== undefined) {
12
+ const target = this.targets.get(sessionId);
13
+ if (!target)
14
+ return { ok: false, error: `Session not found: ${sessionId}` };
15
+ if (target.status() !== "awaiting_approval") {
16
+ return { ok: false, error: `Session ${sessionId} is not awaiting approval` };
17
+ }
18
+ target.approve();
19
+ return { ok: true };
20
+ }
21
+ for (const target of this.targets.values()) {
22
+ if (target.status() === "awaiting_approval") {
23
+ target.approve();
24
+ return { ok: true };
25
+ }
26
+ }
27
+ return { ok: false, error: "No approval pending" };
28
+ }
29
+ reject(reason, sessionId) {
30
+ if (sessionId !== undefined) {
31
+ const target = this.targets.get(sessionId);
32
+ if (!target)
33
+ return { ok: false, error: `Session not found: ${sessionId}` };
34
+ if (target.status() !== "awaiting_approval") {
35
+ return { ok: false, error: `Session ${sessionId} is not awaiting approval` };
36
+ }
37
+ target.reject(reason);
38
+ return { ok: true };
39
+ }
40
+ for (const target of this.targets.values()) {
41
+ if (target.status() === "awaiting_approval") {
42
+ target.reject(reason);
43
+ return { ok: true };
44
+ }
45
+ }
46
+ return { ok: false, error: "No approval pending" };
47
+ }
48
+ }
49
+ //# sourceMappingURL=approval-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approval-registry.js","sourceRoot":"","sources":["../../src/gateway/approval-registry.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAQhF,MAAM,OAAO,oBAAoB;IACd,OAAO,GAAG,IAAI,GAAG,EAA0B,CAAC;IAE7D,QAAQ,CAAC,SAAiB,EAAE,MAAsB;QAChD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IACtC,CAAC;IAED,UAAU,CAAC,SAAiB;QAC1B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACjC,CAAC;IAED,OAAO,CAAC,SAAkB;QACxB,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YAC5B,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YAC3C,IAAI,CAAC,MAAM;gBAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,sBAAsB,SAAS,EAAE,EAAE,CAAC;YAC5E,IAAI,MAAM,CAAC,MAAM,EAAE,KAAK,mBAAmB,EAAE,CAAC;gBAC5C,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,SAAS,2BAA2B,EAAE,CAAC;YAC/E,CAAC;YACD,MAAM,CAAC,OAAO,EAAE,CAAC;YACjB,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;QACtB,CAAC;QAED,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;YAC3C,IAAI,MAAM,CAAC,MAAM,EAAE,KAAK,mBAAmB,EAAE,CAAC;gBAC5C,MAAM,CAAC,OAAO,EAAE,CAAC;gBACjB,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;YACtB,CAAC;QACH,CAAC;QAED,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,qBAAqB,EAAE,CAAC;IACrD,CAAC;IAED,MAAM,CAAC,MAAc,EAAE,SAAkB;QACvC,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YAC5B,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YAC3C,IAAI,CAAC,MAAM;gBAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,sBAAsB,SAAS,EAAE,EAAE,CAAC;YAC5E,IAAI,MAAM,CAAC,MAAM,EAAE,KAAK,mBAAmB,EAAE,CAAC;gBAC5C,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,SAAS,2BAA2B,EAAE,CAAC;YAC/E,CAAC;YACD,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACtB,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;QACtB,CAAC;QAED,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;YAC3C,IAAI,MAAM,CAAC,MAAM,EAAE,KAAK,mBAAmB,EAAE,CAAC;gBAC5C,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBACtB,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;YACtB,CAAC;QACH,CAAC;QAED,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,qBAAqB,EAAE,CAAC;IACrD,CAAC;CACF"}
@@ -0,0 +1,47 @@
1
+ /** Budget check result */
2
+ export interface BudgetCheckResult {
3
+ readonly allowed: boolean;
4
+ readonly remaining: number;
5
+ readonly unit: string;
6
+ readonly overBudgetMessage?: string;
7
+ }
8
+ /** Tier enforcement check result */
9
+ export interface TierCheckResult {
10
+ readonly allowed: boolean;
11
+ readonly requestedTier: string;
12
+ readonly allowedTiers: readonly string[];
13
+ }
14
+ /** Billing configuration (matches ModeBConfig.billing from @kilnai/core) */
15
+ export interface BillingConfig {
16
+ readonly budgetEndpoint: string;
17
+ readonly usageEndpoint: string;
18
+ readonly overBudgetMessage: string;
19
+ readonly tiers?: Readonly<Record<string, {
20
+ readonly agents: readonly string[];
21
+ }>>;
22
+ }
23
+ /** Usage report sent to product API */
24
+ interface UsageReport {
25
+ readonly tokens: number;
26
+ readonly model: string;
27
+ readonly role: string;
28
+ }
29
+ /**
30
+ * Check if the user has remaining budget.
31
+ * Interpolates {userId} in the budget endpoint URL.
32
+ * Fail-open: returns allowed=true on any fetch error or when circuit is open.
33
+ */
34
+ export declare function checkBudget(billing: BillingConfig, userId: string): Promise<BudgetCheckResult>;
35
+ /**
36
+ * Report token usage to the product API.
37
+ * Interpolates {userId} in the usage endpoint URL.
38
+ * Fire-and-forget: errors are logged but not thrown.
39
+ */
40
+ export declare function reportUsage(billing: BillingConfig, userId: string, usage: UsageReport): Promise<void>;
41
+ /**
42
+ * Check if the requested agent tier is allowed for the user's plan.
43
+ * Fail-open: returns allowed=true if no tiers configured or plan not found.
44
+ */
45
+ export declare function checkTier(billing: BillingConfig, userPlan: string, requestedTier: string): TierCheckResult;
46
+ export {};
47
+ //# sourceMappingURL=budget-middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"budget-middleware.d.ts","sourceRoot":"","sources":["../../src/gateway/budget-middleware.ts"],"names":[],"mappings":"AAcA,0BAA0B;AAC1B,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CACrC;AAED,oCAAoC;AACpC,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1C;AAED,4EAA4E;AAC5E,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC,CAAC;CACnF;AAQD,uCAAuC;AACvC,UAAU,WAAW;IACnB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AASD;;;;GAIG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,iBAAiB,CAAC,CA6B5B;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,WAAW,GACjB,OAAO,CAAC,IAAI,CAAC,CAWf;AAED;;;GAGG;AACH,wBAAgB,SAAS,CACvB,OAAO,EAAE,aAAa,EACtB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,GACpB,eAAe,CAWjB"}
@@ -0,0 +1,88 @@
1
+ // Budget enforcement middleware for Mode B apps
2
+ // Checks remaining budget before LLM calls and reports usage after
3
+ //
4
+ // DESIGN RATIONALE (Fail-Open):
5
+ // This middleware intentionally fails OPEN (allows requests when budget API is unavailable).
6
+ // This prevents billing infrastructure issues from blocking user access to the service.
7
+ // If the budget API is down, users can continue using the service - revenue/budget
8
+ // tracking may be temporarily affected but service availability is preserved.
9
+ //
10
+ // Use case: Multi-tenant SaaS where service availability is prioritized over
11
+ // strict budget enforcement. For strict budget enforcement, use a different pattern.
12
+ import { CircuitBreaker } from "@kilnai/core";
13
+ /** Shared circuit breaker for budget API calls */
14
+ const budgetCircuitBreaker = new CircuitBreaker({
15
+ failureThreshold: 5,
16
+ resetTimeoutMs: 30000,
17
+ halfOpenMaxAttempts: 1,
18
+ });
19
+ /**
20
+ * Check if the user has remaining budget.
21
+ * Interpolates {userId} in the budget endpoint URL.
22
+ * Fail-open: returns allowed=true on any fetch error or when circuit is open.
23
+ */
24
+ export async function checkBudget(billing, userId) {
25
+ // If circuit is open, fail open immediately (consistent with current behavior)
26
+ if (budgetCircuitBreaker.currentState === "open") {
27
+ return { allowed: true, remaining: -1, unit: "unknown" };
28
+ }
29
+ try {
30
+ return await budgetCircuitBreaker.execute(async () => {
31
+ const url = billing.budgetEndpoint.replace("{userId}", userId);
32
+ const res = await fetch(url);
33
+ if (!res.ok) {
34
+ // Fail-open: billing failures should not block users
35
+ return { allowed: true, remaining: -1, unit: "unknown" };
36
+ }
37
+ const data = (await res.json());
38
+ if (data.remaining <= 0) {
39
+ return {
40
+ allowed: false,
41
+ remaining: data.remaining,
42
+ unit: data.unit,
43
+ overBudgetMessage: billing.overBudgetMessage,
44
+ };
45
+ }
46
+ return { allowed: true, remaining: data.remaining, unit: data.unit };
47
+ });
48
+ }
49
+ catch {
50
+ // Fail-open on network/fetch errors or circuit open
51
+ return { allowed: true, remaining: -1, unit: "unknown" };
52
+ }
53
+ }
54
+ /**
55
+ * Report token usage to the product API.
56
+ * Interpolates {userId} in the usage endpoint URL.
57
+ * Fire-and-forget: errors are logged but not thrown.
58
+ */
59
+ export async function reportUsage(billing, userId, usage) {
60
+ const url = billing.usageEndpoint.replace("{userId}", userId);
61
+ try {
62
+ await fetch(url, {
63
+ method: "POST",
64
+ headers: { "Content-Type": "application/json" },
65
+ body: JSON.stringify(usage),
66
+ });
67
+ }
68
+ catch {
69
+ // Fire-and-forget: errors logged but not thrown
70
+ }
71
+ }
72
+ /**
73
+ * Check if the requested agent tier is allowed for the user's plan.
74
+ * Fail-open: returns allowed=true if no tiers configured or plan not found.
75
+ */
76
+ export function checkTier(billing, userPlan, requestedTier) {
77
+ if (!billing.tiers) {
78
+ return { allowed: true, requestedTier, allowedTiers: [] };
79
+ }
80
+ const tier = billing.tiers[userPlan];
81
+ if (!tier) {
82
+ // Fail-open: unknown plan allows everything
83
+ return { allowed: true, requestedTier, allowedTiers: [] };
84
+ }
85
+ const allowed = tier.agents.includes(requestedTier);
86
+ return { allowed, requestedTier, allowedTiers: tier.agents };
87
+ }
88
+ //# sourceMappingURL=budget-middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"budget-middleware.js","sourceRoot":"","sources":["../../src/gateway/budget-middleware.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ export interface ConfigValidationResult {
2
+ readonly valid: boolean;
3
+ readonly errors: readonly {
4
+ field: string;
5
+ message: string;
6
+ }[];
7
+ }
8
+ /**
9
+ * Validate all required configuration at gateway startup.
10
+ * Checks environment variables, config values, and service URLs.
11
+ * Returns all errors at once -- does not fail on first error.
12
+ */
13
+ export declare function validateStartupConfig(config: {
14
+ modeBApps?: readonly {
15
+ provider: string;
16
+ apiKeyEnv: string;
17
+ }[];
18
+ whatsapp?: {
19
+ verifyTokenEnv: string;
20
+ accessTokenEnv: string;
21
+ };
22
+ tenantAdmin?: {
23
+ adminTokenEnv: string;
24
+ };
25
+ }): ConfigValidationResult;
26
+ /**
27
+ * Validate startup config and throw if invalid.
28
+ * Call this during gateway startup before creating providers.
29
+ */
30
+ export declare function assertValidStartupConfig(config: Parameters<typeof validateStartupConfig>[0]): void;
31
+ //# sourceMappingURL=config-validator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-validator.d.ts","sourceRoot":"","sources":["../../src/gateway/config-validator.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,SAAS;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAChE;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE;IAC5C,SAAS,CAAC,EAAE,SAAS;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC/D,QAAQ,CAAC,EAAE;QAAE,cAAc,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9D,WAAW,CAAC,EAAE;QAAE,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC;CACzC,GAAG,sBAAsB,CAoDzB;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAYlG"}
@@ -0,0 +1,68 @@
1
+ import { KilnError } from "@kilnai/core";
2
+ /**
3
+ * Validate all required configuration at gateway startup.
4
+ * Checks environment variables, config values, and service URLs.
5
+ * Returns all errors at once -- does not fail on first error.
6
+ */
7
+ export function validateStartupConfig(config) {
8
+ const errors = [];
9
+ // Validate app provider API keys for Mode B apps
10
+ if (config.modeBApps) {
11
+ for (const modeBApp of config.modeBApps) {
12
+ if (modeBApp.apiKeyEnv) {
13
+ const value = process.env[modeBApp.apiKeyEnv];
14
+ if (!value || value.trim() === "") {
15
+ errors.push({
16
+ field: `modeBApps.${modeBApp.provider}.apiKeyEnv`,
17
+ message: `Environment variable '${modeBApp.apiKeyEnv}' is required but not set`,
18
+ });
19
+ }
20
+ }
21
+ }
22
+ }
23
+ // Validate WhatsApp configuration if present
24
+ if (config.whatsapp) {
25
+ const verifyValue = process.env[config.whatsapp.verifyTokenEnv];
26
+ if (!verifyValue || verifyValue.trim() === "") {
27
+ errors.push({
28
+ field: "whatsapp.verifyTokenEnv",
29
+ message: `Environment variable '${config.whatsapp.verifyTokenEnv}' is required but not set`,
30
+ });
31
+ }
32
+ const accessValue = process.env[config.whatsapp.accessTokenEnv];
33
+ if (!accessValue || accessValue.trim() === "") {
34
+ errors.push({
35
+ field: "whatsapp.accessTokenEnv",
36
+ message: `Environment variable '${config.whatsapp.accessTokenEnv}' is required but not set`,
37
+ });
38
+ }
39
+ }
40
+ // Validate tenant admin configuration if present
41
+ if (config.tenantAdmin) {
42
+ const adminValue = process.env[config.tenantAdmin.adminTokenEnv];
43
+ if (!adminValue || adminValue.trim() === "") {
44
+ errors.push({
45
+ field: "tenantAdmin.adminTokenEnv",
46
+ message: `Environment variable '${config.tenantAdmin.adminTokenEnv}' is required but not set`,
47
+ });
48
+ }
49
+ }
50
+ return {
51
+ valid: errors.length === 0,
52
+ errors,
53
+ };
54
+ }
55
+ /**
56
+ * Validate startup config and throw if invalid.
57
+ * Call this during gateway startup before creating providers.
58
+ */
59
+ export function assertValidStartupConfig(config) {
60
+ const result = validateStartupConfig(config);
61
+ if (!result.valid) {
62
+ throw new KilnError("CONFIG_MISSING_ENV", `Startup configuration invalid:\n${result.errors.map((e) => ` ${e.field}: ${e.message}`).join("\n")}`, {
63
+ context: { errors: result.errors },
64
+ retryable: false,
65
+ });
66
+ }
67
+ }
68
+ //# sourceMappingURL=config-validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-validator.js","sourceRoot":"","sources":["../../src/gateway/config-validator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ import type { ProviderAdapter, A2AMessage } from "@kilnai/core";
2
+ import type { AppDelegation, AppDelegationResult, DelegationError } from "@kilnai/core";
3
+ import { A2AClient } from "../a2a/a2a-client.js";
4
+ /** Minimal info about a loaded app available as delegation target */
5
+ export interface DelegationTarget {
6
+ readonly appName: string;
7
+ readonly provider: ProviderAdapter;
8
+ readonly systemPrompt: string;
9
+ }
10
+ /** Registry of apps available for delegation */
11
+ export interface DelegationRegistry {
12
+ readonly targets: ReadonlyMap<string, DelegationTarget>;
13
+ }
14
+ /** Configuration for A2A delegation */
15
+ export interface A2ADelegationConfig {
16
+ readonly type: "a2a";
17
+ readonly agentUrl: string;
18
+ readonly message: A2AMessage;
19
+ readonly timeout?: number;
20
+ }
21
+ /** Extended delegation type for A2A routing */
22
+ export interface ExtendedDelegation extends AppDelegation {
23
+ readonly delegationType?: "a2a";
24
+ readonly agentUrl?: string;
25
+ readonly a2aMessage?: A2AMessage;
26
+ }
27
+ /** Result of lightweight JSON Schema validation */
28
+ export interface SchemaValidationResult {
29
+ readonly valid: boolean;
30
+ readonly errors: readonly string[];
31
+ }
32
+ /**
33
+ * Validate response data against a simplified JSON Schema subset.
34
+ * Checks type, required fields, and property types.
35
+ */
36
+ export declare function validateResponseSchema(data: unknown, schema: Record<string, unknown>): SchemaValidationResult;
37
+ /**
38
+ * Execute a delegation request.
39
+ * Routes to A2A or Kiln-native delegation based on delegationType field.
40
+ * Returns AppDelegationResult on success, DelegationError on failure.
41
+ */
42
+ export declare function executeDelegation(delegation: ExtendedDelegation, registry: DelegationRegistry, a2aClient?: A2AClient): Promise<AppDelegationResult | DelegationError>;
43
+ /**
44
+ * Execute a Kiln-native delegation request.
45
+ * Returns AppDelegationResult on success, DelegationError on failure.
46
+ */
47
+ export declare function executeKilnDelegation(delegation: AppDelegation, registry: DelegationRegistry): Promise<AppDelegationResult | DelegationError>;
48
+ /**
49
+ * Execute an A2A delegation request to a remote agent.
50
+ * Returns AppDelegationResult on success, DelegationError on failure.
51
+ */
52
+ export declare function executeA2ADelegation(a2aConfig: A2ADelegationConfig, fromApp: string, client?: A2AClient): Promise<AppDelegationResult | DelegationError>;
53
+ //# sourceMappingURL=delegation-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delegation-handler.d.ts","sourceRoot":"","sources":["../../src/gateway/delegation-handler.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,KAAK,EACV,aAAa,EACb,mBAAmB,EACnB,eAAe,EAChB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAMjD,qEAAqE;AACrE,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAED,gDAAgD;AAChD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;CACzD;AAED,uCAAuC;AACvC,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IACrB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAC7B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,+CAA+C;AAC/C,MAAM,WAAW,kBAAmB,SAAQ,aAAa;IACvD,QAAQ,CAAC,cAAc,CAAC,EAAE,KAAK,CAAC;IAChC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC;CAClC;AAED,mDAAmD;AACnD,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,OAAO,EACb,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,sBAAsB,CAmExB;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,UAAU,EAAE,kBAAkB,EAC9B,QAAQ,EAAE,kBAAkB,EAC5B,SAAS,CAAC,EAAE,SAAS,GACpB,OAAO,CAAC,mBAAmB,GAAG,eAAe,CAAC,CAwBhD;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,UAAU,EAAE,aAAa,EACzB,QAAQ,EAAE,kBAAkB,GAC3B,OAAO,CAAC,mBAAmB,GAAG,eAAe,CAAC,CAyGhD;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,mBAAmB,EAC9B,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,SAAS,GACjB,OAAO,CAAC,mBAAmB,GAAG,eAAe,CAAC,CA0EhD"}