@kilnai/runtime 0.1.15 → 0.9.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 (249) hide show
  1. package/README.md +7 -3
  2. package/dist/channels/email-api.d.ts +29 -0
  3. package/dist/channels/email-api.d.ts.map +1 -0
  4. package/dist/channels/email-api.js +133 -0
  5. package/dist/channels/email-api.js.map +1 -0
  6. package/dist/channels/email-channel.d.ts +26 -0
  7. package/dist/channels/email-channel.d.ts.map +1 -0
  8. package/dist/channels/email-channel.js +59 -0
  9. package/dist/channels/email-channel.js.map +1 -0
  10. package/dist/channels/email-template.d.ts +10 -0
  11. package/dist/channels/email-template.d.ts.map +1 -0
  12. package/dist/channels/email-template.js +63 -0
  13. package/dist/channels/email-template.js.map +1 -0
  14. package/dist/channels/instagram-api.d.ts +29 -0
  15. package/dist/channels/instagram-api.d.ts.map +1 -0
  16. package/dist/channels/instagram-api.js +75 -0
  17. package/dist/channels/instagram-api.js.map +1 -0
  18. package/dist/channels/instagram-channel.d.ts +24 -0
  19. package/dist/channels/instagram-channel.d.ts.map +1 -0
  20. package/dist/channels/instagram-channel.js +55 -0
  21. package/dist/channels/instagram-channel.js.map +1 -0
  22. package/dist/channels/message-formatter.d.ts +17 -0
  23. package/dist/channels/message-formatter.d.ts.map +1 -1
  24. package/dist/channels/message-formatter.js +27 -0
  25. package/dist/channels/message-formatter.js.map +1 -1
  26. package/dist/channels/messenger-api.d.ts +27 -0
  27. package/dist/channels/messenger-api.d.ts.map +1 -0
  28. package/dist/channels/messenger-api.js +75 -0
  29. package/dist/channels/messenger-api.js.map +1 -0
  30. package/dist/channels/messenger-channel.d.ts +23 -0
  31. package/dist/channels/messenger-channel.d.ts.map +1 -0
  32. package/dist/channels/messenger-channel.js +55 -0
  33. package/dist/channels/messenger-channel.js.map +1 -0
  34. package/dist/channels/web-channel.d.ts +2 -0
  35. package/dist/channels/web-channel.d.ts.map +1 -1
  36. package/dist/channels/web-channel.js +9 -0
  37. package/dist/channels/web-channel.js.map +1 -1
  38. package/dist/enrichment/enrichment-runner.d.ts +17 -0
  39. package/dist/enrichment/enrichment-runner.d.ts.map +1 -0
  40. package/dist/enrichment/enrichment-runner.js +45 -0
  41. package/dist/enrichment/enrichment-runner.js.map +1 -0
  42. package/dist/enrichment/sqlite-enrichment-store.d.ts +14 -0
  43. package/dist/enrichment/sqlite-enrichment-store.d.ts.map +1 -0
  44. package/dist/enrichment/sqlite-enrichment-store.js +69 -0
  45. package/dist/enrichment/sqlite-enrichment-store.js.map +1 -0
  46. package/dist/gateway/audio-preprocessor.d.ts +11 -0
  47. package/dist/gateway/audio-preprocessor.d.ts.map +1 -0
  48. package/dist/gateway/audio-preprocessor.js +76 -0
  49. package/dist/gateway/audio-preprocessor.js.map +1 -0
  50. package/dist/gateway/auth-middleware.d.ts.map +1 -1
  51. package/dist/gateway/auth-middleware.js +10 -2
  52. package/dist/gateway/auth-middleware.js.map +1 -1
  53. package/dist/gateway/contact-memory-admin-routes.d.ts +9 -0
  54. package/dist/gateway/contact-memory-admin-routes.d.ts.map +1 -0
  55. package/dist/gateway/contact-memory-admin-routes.js +42 -0
  56. package/dist/gateway/contact-memory-admin-routes.js.map +1 -0
  57. package/dist/gateway/context-formatter.d.ts +5 -0
  58. package/dist/gateway/context-formatter.d.ts.map +1 -0
  59. package/dist/gateway/context-formatter.js +16 -0
  60. package/dist/gateway/context-formatter.js.map +1 -0
  61. package/dist/gateway/conversation-event-emitter.d.ts +4 -1
  62. package/dist/gateway/conversation-event-emitter.d.ts.map +1 -1
  63. package/dist/gateway/conversation-event-emitter.js +44 -13
  64. package/dist/gateway/conversation-event-emitter.js.map +1 -1
  65. package/dist/gateway/dev-routes.d.ts +1 -1
  66. package/dist/gateway/dev-routes.d.ts.map +1 -1
  67. package/dist/gateway/dev-routes.js +2 -2
  68. package/dist/gateway/dev-routes.js.map +1 -1
  69. package/dist/gateway/email-loop-guard.d.ts +10 -0
  70. package/dist/gateway/email-loop-guard.d.ts.map +1 -0
  71. package/dist/gateway/email-loop-guard.js +39 -0
  72. package/dist/gateway/email-loop-guard.js.map +1 -0
  73. package/dist/gateway/email-thread-store.d.ts +24 -0
  74. package/dist/gateway/email-thread-store.d.ts.map +1 -0
  75. package/dist/gateway/email-thread-store.js +34 -0
  76. package/dist/gateway/email-thread-store.js.map +1 -0
  77. package/dist/gateway/email-webhook-routes.d.ts +32 -0
  78. package/dist/gateway/email-webhook-routes.d.ts.map +1 -0
  79. package/dist/gateway/email-webhook-routes.js +411 -0
  80. package/dist/gateway/email-webhook-routes.js.map +1 -0
  81. package/dist/gateway/enrichment-admin-routes.d.ts +9 -0
  82. package/dist/gateway/enrichment-admin-routes.d.ts.map +1 -0
  83. package/dist/gateway/enrichment-admin-routes.js +41 -0
  84. package/dist/gateway/enrichment-admin-routes.js.map +1 -0
  85. package/dist/gateway/gateway-routes.d.ts +17 -1
  86. package/dist/gateway/gateway-routes.d.ts.map +1 -1
  87. package/dist/gateway/gateway-routes.js +55 -1
  88. package/dist/gateway/gateway-routes.js.map +1 -1
  89. package/dist/gateway/gateway-server.d.ts.map +1 -1
  90. package/dist/gateway/gateway-server.js +250 -14
  91. package/dist/gateway/gateway-server.js.map +1 -1
  92. package/dist/gateway/handoff-routes.d.ts +15 -0
  93. package/dist/gateway/handoff-routes.d.ts.map +1 -0
  94. package/dist/gateway/handoff-routes.js +253 -0
  95. package/dist/gateway/handoff-routes.js.map +1 -0
  96. package/dist/gateway/instagram-webhook-routes.d.ts +30 -0
  97. package/dist/gateway/instagram-webhook-routes.d.ts.map +1 -0
  98. package/dist/gateway/instagram-webhook-routes.js +394 -0
  99. package/dist/gateway/instagram-webhook-routes.js.map +1 -0
  100. package/dist/gateway/knowledge-admin-routes.d.ts +9 -0
  101. package/dist/gateway/knowledge-admin-routes.d.ts.map +1 -0
  102. package/dist/gateway/knowledge-admin-routes.js +84 -0
  103. package/dist/gateway/knowledge-admin-routes.js.map +1 -0
  104. package/dist/gateway/knowledge-factory.d.ts +19 -0
  105. package/dist/gateway/knowledge-factory.d.ts.map +1 -0
  106. package/dist/gateway/knowledge-factory.js +122 -0
  107. package/dist/gateway/knowledge-factory.js.map +1 -0
  108. package/dist/gateway/message-pipeline.d.ts +69 -0
  109. package/dist/gateway/message-pipeline.d.ts.map +1 -0
  110. package/dist/gateway/message-pipeline.js +185 -0
  111. package/dist/gateway/message-pipeline.js.map +1 -0
  112. package/dist/gateway/messenger-webhook-routes.d.ts +30 -0
  113. package/dist/gateway/messenger-webhook-routes.d.ts.map +1 -0
  114. package/dist/gateway/messenger-webhook-routes.js +394 -0
  115. package/dist/gateway/messenger-webhook-routes.js.map +1 -0
  116. package/dist/gateway/meta-webhook-foundation.d.ts +12 -0
  117. package/dist/gateway/meta-webhook-foundation.d.ts.map +1 -0
  118. package/dist/gateway/meta-webhook-foundation.js +25 -0
  119. package/dist/gateway/meta-webhook-foundation.js.map +1 -0
  120. package/dist/gateway/mode-b-routes.d.ts +8 -0
  121. package/dist/gateway/mode-b-routes.d.ts.map +1 -1
  122. package/dist/gateway/mode-b-routes.js +74 -36
  123. package/dist/gateway/mode-b-routes.js.map +1 -1
  124. package/dist/gateway/outbound-routes.d.ts.map +1 -1
  125. package/dist/gateway/outbound-routes.js +49 -21
  126. package/dist/gateway/outbound-routes.js.map +1 -1
  127. package/dist/gateway/routing-test-routes.d.ts +10 -0
  128. package/dist/gateway/routing-test-routes.d.ts.map +1 -0
  129. package/dist/gateway/routing-test-routes.js +76 -0
  130. package/dist/gateway/routing-test-routes.js.map +1 -0
  131. package/dist/gateway/sqlite-email-thread-store.d.ts +13 -0
  132. package/dist/gateway/sqlite-email-thread-store.d.ts.map +1 -0
  133. package/dist/gateway/sqlite-email-thread-store.js +66 -0
  134. package/dist/gateway/sqlite-email-thread-store.js.map +1 -0
  135. package/dist/gateway/stt-factory.d.ts +3 -0
  136. package/dist/gateway/stt-factory.d.ts.map +1 -0
  137. package/dist/gateway/stt-factory.js +21 -0
  138. package/dist/gateway/stt-factory.js.map +1 -0
  139. package/dist/gateway/tenant-admin-routes.d.ts.map +1 -1
  140. package/dist/gateway/tenant-admin-routes.js +17 -3
  141. package/dist/gateway/tenant-admin-routes.js.map +1 -1
  142. package/dist/gateway/tenant-routes.d.ts.map +1 -1
  143. package/dist/gateway/tenant-routes.js +18 -27
  144. package/dist/gateway/tenant-routes.js.map +1 -1
  145. package/dist/gateway/tenant-tool-factory.d.ts +10 -0
  146. package/dist/gateway/tenant-tool-factory.d.ts.map +1 -0
  147. package/dist/gateway/tenant-tool-factory.js +55 -0
  148. package/dist/gateway/tenant-tool-factory.js.map +1 -0
  149. package/dist/gateway/trace-context.d.ts +8 -0
  150. package/dist/gateway/trace-context.d.ts.map +1 -0
  151. package/dist/gateway/trace-context.js +17 -0
  152. package/dist/gateway/trace-context.js.map +1 -0
  153. package/dist/gateway/webhook-dedup.d.ts +13 -0
  154. package/dist/gateway/webhook-dedup.d.ts.map +1 -0
  155. package/dist/gateway/webhook-dedup.js +37 -0
  156. package/dist/gateway/webhook-dedup.js.map +1 -0
  157. package/dist/gateway/webhook-tool-executor.d.ts +17 -0
  158. package/dist/gateway/webhook-tool-executor.d.ts.map +1 -0
  159. package/dist/gateway/webhook-tool-executor.js +69 -0
  160. package/dist/gateway/webhook-tool-executor.js.map +1 -0
  161. package/dist/gateway/whatsapp-webhook-routes.d.ts +11 -0
  162. package/dist/gateway/whatsapp-webhook-routes.d.ts.map +1 -1
  163. package/dist/gateway/whatsapp-webhook-routes.js +205 -33
  164. package/dist/gateway/whatsapp-webhook-routes.js.map +1 -1
  165. package/dist/gateway/ws-tenant-routes.d.ts +9 -0
  166. package/dist/gateway/ws-tenant-routes.d.ts.map +1 -1
  167. package/dist/gateway/ws-tenant-routes.js +184 -7
  168. package/dist/gateway/ws-tenant-routes.js.map +1 -1
  169. package/dist/index.d.ts +63 -3
  170. package/dist/index.d.ts.map +1 -1
  171. package/dist/index.js +39 -1
  172. package/dist/index.js.map +1 -1
  173. package/dist/observability/composite-event-store.d.ts +13 -0
  174. package/dist/observability/composite-event-store.d.ts.map +1 -0
  175. package/dist/observability/composite-event-store.js +37 -0
  176. package/dist/observability/composite-event-store.js.map +1 -0
  177. package/dist/observability/prometheus-collector.d.ts +33 -0
  178. package/dist/observability/prometheus-collector.d.ts.map +1 -0
  179. package/dist/observability/prometheus-collector.js +170 -0
  180. package/dist/observability/prometheus-collector.js.map +1 -0
  181. package/dist/session/agent-handoff-summarizer.d.ts +11 -0
  182. package/dist/session/agent-handoff-summarizer.d.ts.map +1 -0
  183. package/dist/session/agent-handoff-summarizer.js +26 -0
  184. package/dist/session/agent-handoff-summarizer.js.map +1 -0
  185. package/dist/session/context-summarizer.d.ts +11 -0
  186. package/dist/session/context-summarizer.d.ts.map +1 -0
  187. package/dist/session/context-summarizer.js +23 -0
  188. package/dist/session/context-summarizer.js.map +1 -0
  189. package/dist/session/escalation-detector.d.ts +27 -0
  190. package/dist/session/escalation-detector.d.ts.map +1 -0
  191. package/dist/session/escalation-detector.js +75 -0
  192. package/dist/session/escalation-detector.js.map +1 -0
  193. package/dist/session/in-memory-session-store.d.ts +11 -0
  194. package/dist/session/in-memory-session-store.d.ts.map +1 -0
  195. package/dist/session/in-memory-session-store.js +26 -0
  196. package/dist/session/in-memory-session-store.js.map +1 -0
  197. package/dist/session/mode-b-orchestrator.d.ts +54 -1
  198. package/dist/session/mode-b-orchestrator.d.ts.map +1 -1
  199. package/dist/session/mode-b-orchestrator.js +349 -17
  200. package/dist/session/mode-b-orchestrator.js.map +1 -1
  201. package/dist/session/mode-b-session.d.ts +48 -1
  202. package/dist/session/mode-b-session.d.ts.map +1 -1
  203. package/dist/session/mode-b-session.js +105 -0
  204. package/dist/session/mode-b-session.js.map +1 -1
  205. package/dist/session/redis-session-store.d.ts +22 -0
  206. package/dist/session/redis-session-store.d.ts.map +1 -0
  207. package/dist/session/redis-session-store.js +44 -0
  208. package/dist/session/redis-session-store.js.map +1 -0
  209. package/dist/session/session-mode.d.ts +4 -0
  210. package/dist/session/session-mode.d.ts.map +1 -0
  211. package/dist/session/session-mode.js +20 -0
  212. package/dist/session/session-mode.js.map +1 -0
  213. package/dist/session/session-registry.d.ts +17 -9
  214. package/dist/session/session-registry.d.ts.map +1 -1
  215. package/dist/session/session-registry.js +80 -29
  216. package/dist/session/session-registry.js.map +1 -1
  217. package/dist/session/session-serializer.d.ts +4 -0
  218. package/dist/session/session-serializer.d.ts.map +1 -0
  219. package/dist/session/session-serializer.js +26 -0
  220. package/dist/session/session-serializer.js.map +1 -0
  221. package/dist/session/session-store.d.ts +9 -0
  222. package/dist/session/session-store.d.ts.map +1 -0
  223. package/dist/session/session-store.js +2 -0
  224. package/dist/session/session-store.js.map +1 -0
  225. package/dist/tenant/agent-resolver.d.ts +26 -0
  226. package/dist/tenant/agent-resolver.d.ts.map +1 -0
  227. package/dist/tenant/agent-resolver.js +232 -0
  228. package/dist/tenant/agent-resolver.js.map +1 -0
  229. package/dist/tenant/ping-pong-guard.d.ts +9 -0
  230. package/dist/tenant/ping-pong-guard.d.ts.map +1 -0
  231. package/dist/tenant/ping-pong-guard.js +30 -0
  232. package/dist/tenant/ping-pong-guard.js.map +1 -0
  233. package/dist/tenant/system-prompt-builder.d.ts +1 -1
  234. package/dist/tenant/system-prompt-builder.d.ts.map +1 -1
  235. package/dist/tenant/system-prompt-builder.js +13 -1
  236. package/dist/tenant/system-prompt-builder.js.map +1 -1
  237. package/dist/tenant/tenant-registry.d.ts +3 -0
  238. package/dist/tenant/tenant-registry.d.ts.map +1 -1
  239. package/dist/tenant/tenant-registry.js +83 -4
  240. package/dist/tenant/tenant-registry.js.map +1 -1
  241. package/dist/tenant/tenant-router.d.ts +27 -0
  242. package/dist/tenant/tenant-router.d.ts.map +1 -0
  243. package/dist/tenant/tenant-router.js +72 -0
  244. package/dist/tenant/tenant-router.js.map +1 -0
  245. package/dist/utils/hmac.d.ts +1 -0
  246. package/dist/utils/hmac.d.ts.map +1 -1
  247. package/dist/utils/hmac.js +3 -0
  248. package/dist/utils/hmac.js.map +1 -1
  249. package/package.json +7 -3
@@ -0,0 +1,394 @@
1
+ // Gateway: Messenger webhook routes -- Hono sub-app for Facebook Messenger Platform
2
+ // Resolves tenant by Messenger Page ID, processes messages via Mode B orchestrator, replies via Messenger Send API
3
+ import { Hono } from "hono";
4
+ import { join } from "node:path";
5
+ import { mkdirSync } from "node:fs";
6
+ import { extractText, SqliteMemoryStore } from "@kilnai/core";
7
+ import { toMessengerFormat } from "../channels/message-formatter.js";
8
+ import { resolveAgentContextAsync } from "../tenant/agent-resolver.js";
9
+ import { sendMessengerMessage } from "../channels/messenger-api.js";
10
+ import { checkBudget, reportUsage } from "./budget-middleware.js";
11
+ import { requireWebhookSignature } from "./auth-middleware.js";
12
+ import { verifyMetaWebhook } from "./meta-webhook-foundation.js";
13
+ import { TraceContext } from "./trace-context.js";
14
+ import { preprocessAudio, createGenericMediaDownloader } from "./audio-preprocessor.js";
15
+ import { formatKnowledgeContext, formatContactContext, mergeContextSources } from "./context-formatter.js";
16
+ /** Lazily-opened per-tenant memory stores. Keyed by tenantId. */
17
+ const memoryStores = new Map();
18
+ function getMemoryStore(memoryBasePath, tenantId) {
19
+ let store = memoryStores.get(tenantId);
20
+ if (store)
21
+ return store;
22
+ const dir = join(memoryBasePath, "memory");
23
+ mkdirSync(dir, { recursive: true });
24
+ store = new SqliteMemoryStore({
25
+ dbPath: join(dir, `${tenantId}.db`),
26
+ layer: "user",
27
+ tenantId,
28
+ });
29
+ memoryStores.set(tenantId, store);
30
+ return store;
31
+ }
32
+ /** Tool definition for knowledge_search -- injected when knowledge mode is "tool" */
33
+ const KNOWLEDGE_SEARCH_TOOL = {
34
+ name: "knowledge_search",
35
+ description: "Search the knowledge base for relevant information. Use this when the user asks a question that may be answered by stored documents or knowledge.",
36
+ inputSchema: {
37
+ type: "object",
38
+ properties: {
39
+ query: {
40
+ type: "string",
41
+ description: "The search query to find relevant knowledge.",
42
+ },
43
+ },
44
+ required: ["query"],
45
+ },
46
+ tags: new Set(["builtin"]),
47
+ };
48
+ /** Parse a Messenger messaging entry into ContentPart[] */
49
+ function parseMessengerMessageParts(entry) {
50
+ const msg = entry.message;
51
+ if (!msg)
52
+ return null;
53
+ const parts = [];
54
+ if (msg.text) {
55
+ parts.push({ type: "text", text: msg.text });
56
+ }
57
+ if (msg.attachments) {
58
+ for (const att of msg.attachments) {
59
+ if (att.type === "image" && att.payload.url) {
60
+ parts.push({ type: "image", mimeType: "image/jpeg", url: att.payload.url });
61
+ }
62
+ else if (att.type === "audio" && att.payload.url) {
63
+ parts.push({ type: "audio", mimeType: "audio/mp4", url: att.payload.url });
64
+ }
65
+ }
66
+ }
67
+ return parts.length > 0 ? parts : null;
68
+ }
69
+ export function createMessengerWebhookRoutes(config) {
70
+ const app = new Hono();
71
+ // GET /webhook -- Meta verification handshake
72
+ app.get("/webhook", (c) => verifyMetaWebhook(c, config.verifyToken));
73
+ // HMAC-SHA256 signature validation for POST webhooks
74
+ if (config.appSecret) {
75
+ app.use("/webhook", requireWebhookSignature(config.appSecret, "x-hub-signature-256"));
76
+ }
77
+ // POST /webhook -- Incoming messages from Messenger
78
+ app.post("/webhook", async (c) => {
79
+ let payload;
80
+ try {
81
+ payload = await c.req.json();
82
+ }
83
+ catch {
84
+ return c.text("OK", 200);
85
+ }
86
+ if (payload.object !== "page" || !payload.entry) {
87
+ return c.text("OK", 200);
88
+ }
89
+ const processPromises = [];
90
+ for (const entry of payload.entry) {
91
+ for (const messaging of entry.messaging) {
92
+ // Filter echo messages (business-sent messages echoed back)
93
+ if (messaging.message?.is_echo)
94
+ continue;
95
+ // Deduplicate -- Meta uses at-least-once delivery
96
+ if (messaging.message?.mid && config.dedup?.isDuplicate(messaging.message.mid)) {
97
+ console.debug(`[messenger] Skipping duplicate message ${messaging.message.mid}`);
98
+ continue;
99
+ }
100
+ const senderId = messaging.sender.id;
101
+ const recipientPageId = messaging.recipient.id;
102
+ // Resolve tenant by Messenger Page ID
103
+ const tenant = config.tenantRegistry.resolveByMessengerPageId(recipientPageId, config.appName);
104
+ if (!tenant) {
105
+ const trace = new TraceContext();
106
+ trace.warn("messenger", "No tenant found", { recipientPageId, appName: config.appName });
107
+ continue;
108
+ }
109
+ const msgParts = parseMessengerMessageParts(messaging);
110
+ if (!msgParts)
111
+ continue;
112
+ const promise = processMessengerMessage(config, tenant.tenantId, senderId, msgParts, tenant.messengerAccessToken);
113
+ processPromises.push(promise);
114
+ }
115
+ }
116
+ // Fire and forget -- log any failures from settled promises
117
+ Promise.allSettled(processPromises).then((results) => {
118
+ for (const result of results) {
119
+ if (result.status === "rejected") {
120
+ const failTrace = new TraceContext();
121
+ failTrace.warn("messenger", "Message processing failed", { error: String(result.reason) });
122
+ }
123
+ }
124
+ });
125
+ return c.text("OK", 200);
126
+ });
127
+ return app;
128
+ }
129
+ async function processMessengerMessage(config, tenantId, senderId, messageParts, accessToken) {
130
+ const trace = new TraceContext();
131
+ trace.log("messenger", "Processing message", { tenantId, from: senderId });
132
+ const tenant = config.tenantRegistry.get(tenantId);
133
+ if (!tenant)
134
+ return;
135
+ const resolvedAccessToken = accessToken
136
+ ? (process.env[accessToken] ?? accessToken)
137
+ : "";
138
+ // Preprocess audio parts via STT (fail-open) -- Messenger CDN URLs don't need auth
139
+ let processedParts = messageParts;
140
+ if (config.sttAdapter) {
141
+ try {
142
+ const downloader = createGenericMediaDownloader();
143
+ processedParts = await preprocessAudio(messageParts, config.sttAdapter, downloader);
144
+ }
145
+ catch (err) {
146
+ trace.warn("messenger", "Audio preprocessing failed", { error: err instanceof Error ? err.message : String(err) });
147
+ }
148
+ }
149
+ const messageText = extractText(processedParts);
150
+ // --- Memory: recall past context about this user ---
151
+ let recalledMemory;
152
+ if (config.memoryBasePath) {
153
+ try {
154
+ const store = getMemoryStore(config.memoryBasePath, tenantId);
155
+ const query = `${senderId} ${messageText}`;
156
+ recalledMemory = await store.recall(query, 500) || undefined;
157
+ }
158
+ catch (err) {
159
+ trace.warn("messenger", "Memory recall failed", { tenantId, error: err instanceof Error ? err.message : String(err) });
160
+ }
161
+ }
162
+ // --- Knowledge: retrieve relevant context ---
163
+ let knowledgeContext;
164
+ if (config.knowledgePipeline && messageText.length > 0) {
165
+ const knowledgeMode = config.knowledgeMode ?? "auto";
166
+ if (knowledgeMode === "auto") {
167
+ try {
168
+ const results = await config.knowledgePipeline.retrieve(messageText, { topK: 5 });
169
+ knowledgeContext = formatKnowledgeContext(results);
170
+ }
171
+ catch (err) {
172
+ trace.warn("messenger", "Knowledge retrieval failed", { error: err instanceof Error ? err.message : String(err) });
173
+ }
174
+ }
175
+ }
176
+ // --- Contact memory: recall persistent facts about this user ---
177
+ let contactContext;
178
+ if (config.contactMemoryService) {
179
+ try {
180
+ const facts = await config.contactMemoryService.recall(senderId, tenantId);
181
+ contactContext = formatContactContext(facts);
182
+ }
183
+ catch (err) {
184
+ trace.warn("messenger", "Contact memory recall failed", { tenantId, error: err instanceof Error ? err.message : String(err) });
185
+ }
186
+ }
187
+ const combinedMemory = mergeContextSources(recalledMemory, knowledgeContext, contactContext);
188
+ // --- Tools: build per-call builtin tools ---
189
+ const callTools = new Map();
190
+ // Register knowledge_search tool for "tool" mode
191
+ if (config.knowledgePipeline && (config.knowledgeMode ?? "auto") === "tool") {
192
+ callTools.set("knowledge_search", async (input) => {
193
+ const query = String(input.query ?? "");
194
+ const results = await config.knowledgePipeline.retrieve(query, { topK: 5 });
195
+ return results.map((r) => ({ content: r.content, score: r.score }));
196
+ });
197
+ const hasKnowledgeTool = config.orchestrator.tools?.some((t) => t.name === "knowledge_search");
198
+ if (!hasKnowledgeTool) {
199
+ config.orchestrator.registerTools([KNOWLEDGE_SEARCH_TOOL]);
200
+ }
201
+ }
202
+ // Get or create session first (needed for ping-pong guard)
203
+ const session = await config.sessionRegistry.getOrCreate({
204
+ appName: config.appName,
205
+ tenantId,
206
+ userId: senderId,
207
+ systemPrompt: "",
208
+ idleTimeoutMs: tenant.idleTimeoutMs,
209
+ });
210
+ // Resolve agent context (multi-agent routing with ping-pong guard)
211
+ const agentCtx = await resolveAgentContextAsync(tenant, processedParts, session, { handoffSummarizer: config.handoffSummarizer, eventBus: config.eventBus }, "messenger", callTools);
212
+ // Update session with resolved prompt and agent
213
+ session.setSystemPrompt(agentCtx.systemPrompt);
214
+ if (agentCtx.activeAgentId) {
215
+ session.setActiveAgent(agentCtx.activeAgentId, agentCtx.handoffBrief);
216
+ }
217
+ const tenantToolCtx = agentCtx.tenantToolContext;
218
+ // Register webhook tool definitions on the orchestrator
219
+ if (tenantToolCtx.toolDefinitions.length > 0) {
220
+ config.orchestrator.registerTools(tenantToolCtx.toolDefinitions);
221
+ }
222
+ const perCallConfig = {
223
+ toolAllowlist: tenantToolCtx.toolAllowlist,
224
+ rateLimiter: tenantToolCtx.rateLimiter,
225
+ tenantId: tenant.tenantId,
226
+ additionalTools: tenantToolCtx.toolDefinitions.length > 0 ? tenantToolCtx.toolDefinitions : undefined,
227
+ };
228
+ // --- Budget check ---
229
+ const activeBilling = tenant.billing?.budgetEndpoint
230
+ ? tenant.billing
231
+ : config.billing;
232
+ if (activeBilling) {
233
+ const budgetResult = await checkBudget(activeBilling, tenantId);
234
+ if (!budgetResult.allowed) {
235
+ const overBudgetMsg = tenant.billing?.overBudgetMessage
236
+ ?? activeBilling.overBudgetMessage ?? "Budget exhausted.";
237
+ trace.log("messenger", "Budget exhausted", { tenantId, sender: senderId });
238
+ try {
239
+ await sendMessengerMessage(resolvedAccessToken, senderId, overBudgetMsg);
240
+ }
241
+ catch (err) {
242
+ trace.warn("messenger", "Failed to send over-budget reply", { error: err instanceof Error ? err.message : String(err) });
243
+ }
244
+ return;
245
+ }
246
+ }
247
+ // Emit MESSAGE_RECEIVED event (fire-and-forget)
248
+ if (config.eventEmitter) {
249
+ config.eventEmitter.emit({
250
+ eventType: "MESSAGE_RECEIVED",
251
+ tenantId,
252
+ channel: "messenger",
253
+ externalUserId: senderId,
254
+ messageContent: messageText,
255
+ messageRole: "USER",
256
+ traceId: trace.traceId,
257
+ timestamp: new Date().toISOString(),
258
+ });
259
+ }
260
+ let replyText;
261
+ try {
262
+ const result = await config.orchestrator.processMessage(session, processedParts, combinedMemory, tenantToolCtx.callBuiltinTools.size > 0 ? tenantToolCtx.callBuiltinTools : undefined, perCallConfig);
263
+ // Persist mutated session
264
+ await config.sessionRegistry.save(session);
265
+ // Emit handoff events when message was queued
266
+ if (result.queued && config.eventEmitter) {
267
+ config.eventEmitter.emit({
268
+ eventType: "HANDOFF_MESSAGE_QUEUED",
269
+ tenantId,
270
+ channel: "messenger",
271
+ externalUserId: senderId,
272
+ sessionMode: session.sessionMode,
273
+ traceId: trace.traceId,
274
+ timestamp: new Date().toISOString(),
275
+ });
276
+ }
277
+ // Emit escalation event when detected
278
+ if (result.escalation && config.eventEmitter) {
279
+ config.eventEmitter.emit({
280
+ eventType: "ESCALATION_DETECTED",
281
+ tenantId,
282
+ channel: "messenger",
283
+ externalUserId: senderId,
284
+ escalationReason: result.escalation.reason,
285
+ escalationDetail: result.escalation.detail,
286
+ summary: result.contextSummary,
287
+ sessionMode: session.sessionMode,
288
+ traceId: trace.traceId,
289
+ timestamp: new Date().toISOString(),
290
+ });
291
+ }
292
+ // Emit TOOL_EXECUTED events
293
+ if (result.toolExecutions && config.eventEmitter) {
294
+ for (const exec of result.toolExecutions) {
295
+ config.eventEmitter.emit({
296
+ eventType: "TOOL_EXECUTED",
297
+ tenantId,
298
+ channel: "messenger",
299
+ externalUserId: senderId,
300
+ toolName: exec.toolName,
301
+ durationMs: exec.durationMs,
302
+ success: exec.success,
303
+ resultSummary: exec.resultSummary,
304
+ traceId: trace.traceId,
305
+ timestamp: new Date().toISOString(),
306
+ });
307
+ }
308
+ }
309
+ // Emit AGENT_ROUTED when multi-agent routing is active
310
+ if (agentCtx.activeAgentId && config.eventEmitter) {
311
+ config.eventEmitter.emit({
312
+ eventType: "AGENT_ROUTED",
313
+ tenantId,
314
+ channel: "messenger",
315
+ externalUserId: senderId,
316
+ activeAgentId: agentCtx.activeAgentId,
317
+ activeAgentName: agentCtx.activeAgentName,
318
+ routingTier: agentCtx.routingResult?.tier,
319
+ routingConfidence: agentCtx.routingResult?.confidence,
320
+ traceId: trace.traceId,
321
+ timestamp: new Date().toISOString(),
322
+ });
323
+ }
324
+ // Emit AGENT_HANDOFF when an agent switch occurred (or was blocked)
325
+ if ((agentCtx.isHandoff || agentCtx.pingPongBlocked) && config.eventEmitter) {
326
+ const fromAgent = tenant.agents?.find((a) => a.id === agentCtx.previousAgentId);
327
+ const toAgent = tenant.agents?.find((a) => a.id === agentCtx.activeAgentId);
328
+ config.eventEmitter.emit({
329
+ eventType: "AGENT_HANDOFF",
330
+ tenantId,
331
+ channel: "messenger",
332
+ externalUserId: senderId,
333
+ fromAgentId: agentCtx.previousAgentId,
334
+ fromAgentName: fromAgent?.name,
335
+ toAgentId: agentCtx.activeAgentId,
336
+ toAgentName: toAgent?.name,
337
+ handoffBrief: agentCtx.handoffBrief,
338
+ handoffBlocked: agentCtx.pingPongBlocked,
339
+ handoffBlockReason: agentCtx.pingPongReason,
340
+ traceId: trace.traceId,
341
+ timestamp: new Date().toISOString(),
342
+ });
343
+ }
344
+ replyText = toMessengerFormat(extractText(result.parts));
345
+ // Report usage (fire-and-forget)
346
+ if (activeBilling) {
347
+ reportUsage(activeBilling, {
348
+ tenantId,
349
+ messages: 1,
350
+ tokens: result.inputTokens + result.outputTokens,
351
+ model: config.orchestrator.model ?? "unknown",
352
+ });
353
+ }
354
+ // Emit MESSAGE_SENT event (fire-and-forget)
355
+ if (config.eventEmitter) {
356
+ config.eventEmitter.emit({
357
+ eventType: "MESSAGE_SENT",
358
+ tenantId,
359
+ channel: "messenger",
360
+ externalUserId: senderId,
361
+ messageContent: replyText,
362
+ messageRole: "ASSISTANT",
363
+ traceId: trace.traceId,
364
+ timestamp: new Date().toISOString(),
365
+ });
366
+ }
367
+ }
368
+ catch (err) {
369
+ trace.error("messenger", "Orchestrator error", { tenantId, error: err instanceof Error ? err.message : String(err) });
370
+ replyText = "Something went wrong. Please try again.";
371
+ }
372
+ // Reply via Messenger Send API
373
+ try {
374
+ await sendMessengerMessage(resolvedAccessToken, senderId, replyText);
375
+ }
376
+ catch (err) {
377
+ trace.warn("messenger", "Failed to send reply", { recipient: senderId, error: err instanceof Error ? err.message : String(err) });
378
+ }
379
+ // --- Memory: save what was learned from this exchange ---
380
+ if (config.memoryBasePath && messageText.length > 5) {
381
+ try {
382
+ const store = getMemoryStore(config.memoryBasePath, tenantId);
383
+ await store.save({
384
+ layer: "user",
385
+ content: `[${senderId}] User: ${messageText}\nAssistant: ${replyText}`,
386
+ tags: [senderId],
387
+ });
388
+ }
389
+ catch (err) {
390
+ trace.warn("messenger", "Memory save failed", { tenantId, error: err instanceof Error ? err.message : String(err) });
391
+ }
392
+ }
393
+ }
394
+ //# sourceMappingURL=messenger-webhook-routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messenger-webhook-routes.js","sourceRoot":"","sources":["../../src/gateway/messenger-webhook-routes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { Context } from "hono";
2
+ /**
3
+ * Handle Meta's GET verification handshake.
4
+ * Returns hub.challenge on valid subscribe requests; 403 otherwise.
5
+ */
6
+ export declare function verifyMetaWebhook(c: Context, verifyToken: string): Response;
7
+ /**
8
+ * Validate Meta's HMAC-SHA256 signature from `X-Hub-Signature-256` header.
9
+ * Strips the `sha256=` prefix before comparison.
10
+ */
11
+ export declare function validateMetaSignature(body: string, signature: string, appSecret: string): boolean;
12
+ //# sourceMappingURL=meta-webhook-foundation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meta-webhook-foundation.d.ts","sourceRoot":"","sources":["../../src/gateway/meta-webhook-foundation.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAGpC;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,GAAG,QAAQ,CAS3E;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAGjG"}
@@ -0,0 +1,25 @@
1
+ // Meta Webhook Foundation -- shared verification, HMAC validation, and entry dispatch
2
+ // Used by WhatsApp, Instagram, and Messenger webhook handlers
3
+ import { verifyHmacSha256 } from "../utils/hmac.js";
4
+ /**
5
+ * Handle Meta's GET verification handshake.
6
+ * Returns hub.challenge on valid subscribe requests; 403 otherwise.
7
+ */
8
+ export function verifyMetaWebhook(c, verifyToken) {
9
+ const mode = c.req.query("hub.mode");
10
+ const token = c.req.query("hub.verify_token");
11
+ const challenge = c.req.query("hub.challenge");
12
+ if (mode === "subscribe" && token === verifyToken) {
13
+ return c.text(challenge ?? "", 200);
14
+ }
15
+ return c.text("Forbidden", 403);
16
+ }
17
+ /**
18
+ * Validate Meta's HMAC-SHA256 signature from `X-Hub-Signature-256` header.
19
+ * Strips the `sha256=` prefix before comparison.
20
+ */
21
+ export function validateMetaSignature(body, signature, appSecret) {
22
+ const sig = signature.startsWith("sha256=") ? signature.slice(7) : signature;
23
+ return verifyHmacSha256(appSecret, body, sig);
24
+ }
25
+ //# sourceMappingURL=meta-webhook-foundation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meta-webhook-foundation.js","sourceRoot":"","sources":["../../src/gateway/meta-webhook-foundation.ts"],"names":[],"mappings":"AAAA,sFAAsF;AACtF,8DAA8D;AAG9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEpD;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,CAAU,EAAE,WAAmB;IAC/D,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACrC,MAAM,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;IAC9C,MAAM,SAAS,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;IAE/C,IAAI,IAAI,KAAK,WAAW,IAAI,KAAK,KAAK,WAAW,EAAE,CAAC;QAClD,OAAO,CAAC,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC;IACtC,CAAC;IACD,OAAO,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;AAClC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAY,EAAE,SAAiB,EAAE,SAAiB;IACtF,MAAM,GAAG,GAAG,SAAS,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC7E,OAAO,gBAAgB,CAAC,SAAS,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;AAChD,CAAC"}
@@ -1,7 +1,10 @@
1
1
  import { Hono } from "hono";
2
+ import type { TenantConfig, RetrievalPipeline } from "@kilnai/core";
2
3
  import type { ModeBOrchestrator } from "../session/mode-b-orchestrator.js";
3
4
  import type { SessionRegistry } from "../session/session-registry.js";
4
5
  import type { BillingConfig } from "./budget-middleware.js";
6
+ import type { AgentHandoffSummarizer } from "../session/agent-handoff-summarizer.js";
7
+ import type { EventBus } from "@kilnai/core";
5
8
  /** Runtime configuration for a Mode B App */
6
9
  export interface ModeBAppRuntime {
7
10
  readonly appName: string;
@@ -10,6 +13,11 @@ export interface ModeBAppRuntime {
10
13
  readonly billing?: BillingConfig;
11
14
  readonly systemPrompt: string;
12
15
  readonly apiKey?: string;
16
+ readonly knowledgePipeline?: RetrievalPipeline;
17
+ readonly knowledgeMode?: "auto" | "tool";
18
+ readonly tenant?: TenantConfig;
19
+ readonly handoffSummarizer?: AgentHandoffSummarizer;
20
+ readonly eventBus?: EventBus;
13
21
  }
14
22
  export declare function createModeBRoutes(runtime: ModeBAppRuntime): Hono;
15
23
  //# sourceMappingURL=mode-b-routes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"mode-b-routes.d.ts","sourceRoot":"","sources":["../../src/gateway/mode-b-routes.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAG5B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AAC3E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAEtE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAG5D,6CAA6C;AAC7C,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,YAAY,EAAE,iBAAiB,CAAC;IACzC,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;IAC1C,QAAQ,CAAC,OAAO,CAAC,EAAE,aAAa,CAAC;IACjC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAUD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI,CAuGhE"}
1
+ {"version":3,"file":"mode-b-routes.d.ts","sourceRoot":"","sources":["../../src/gateway/mode-b-routes.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,KAAK,EAAe,YAAY,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAGjF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AAC3E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAEtE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAI5D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AACrF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAE7C,6CAA6C;AAC7C,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,YAAY,EAAE,iBAAiB,CAAC;IACzC,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;IAC1C,QAAQ,CAAC,OAAO,CAAC,EAAE,aAAa,CAAC;IACjC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IAC/C,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzC,QAAQ,CAAC,MAAM,CAAC,EAAE,YAAY,CAAC;IAC/B,QAAQ,CAAC,iBAAiB,CAAC,EAAE,sBAAsB,CAAC;IACpD,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC;CAC9B;AAUD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI,CA6IhE"}
@@ -2,8 +2,11 @@
2
2
  // Handles message processing, session listing, and session removal
3
3
  import { Hono } from "hono";
4
4
  import { textParts, extractText } from "@kilnai/core";
5
- import { checkBudget, reportUsage, checkTier } from "./budget-middleware.js";
5
+ import { formatKnowledgeContext } from "./context-formatter.js";
6
+ import { checkTier } from "./budget-middleware.js";
6
7
  import { requireApiKey } from "./auth-middleware.js";
8
+ import { processInboundMessage } from "./message-pipeline.js";
9
+ import { resolveAgentContextAsync } from "../tenant/agent-resolver.js";
7
10
  export function createModeBRoutes(runtime) {
8
11
  const app = new Hono();
9
12
  if (runtime.apiKey) {
@@ -27,60 +30,95 @@ export function createModeBRoutes(runtime) {
27
30
  if (!body.userId || typeof body.userId !== "string") {
28
31
  return c.json({ error: "userId is required" }, 400);
29
32
  }
30
- // Budget check
31
- if (runtime.billing) {
32
- const budgetResult = await checkBudget(runtime.billing, body.userId);
33
- if (!budgetResult.allowed) {
33
+ // Tier enforcement (Mode B specific -- not in the pipeline)
34
+ if (runtime.billing?.tiers && body.plan) {
35
+ const tierResult = checkTier(runtime.billing, body.plan, "fast");
36
+ if (!tierResult.allowed) {
34
37
  return c.json({
35
- content: runtime.billing.overBudgetMessage,
36
- budgetExhausted: true,
38
+ content: `Tier "fast" is not available on your "${body.plan}" plan. Allowed tiers: ${tierResult.allowedTiers.join(", ")}`,
39
+ tierRestricted: true,
37
40
  });
38
41
  }
39
- // Tier enforcement
40
- if (runtime.billing.tiers && body.plan) {
41
- const tierResult = checkTier(runtime.billing, body.plan, "fast");
42
- if (!tierResult.allowed) {
43
- return c.json({
44
- content: `Tier "fast" is not available on your "${body.plan}" plan. Allowed tiers: ${tierResult.allowedTiers.join(", ")}`,
45
- tierRestricted: true,
46
- });
42
+ }
43
+ // Knowledge retrieval (auto mode)
44
+ let knowledgeContext;
45
+ if (runtime.knowledgePipeline && (runtime.knowledgeMode ?? "auto") === "auto") {
46
+ const queryText = extractText(userParts);
47
+ if (queryText.length > 0) {
48
+ try {
49
+ const results = await runtime.knowledgePipeline.retrieve(queryText, { topK: 5 });
50
+ knowledgeContext = formatKnowledgeContext(results);
51
+ }
52
+ catch {
53
+ // fail-open
47
54
  }
48
55
  }
49
56
  }
50
- // Get or create session
51
- const session = runtime.sessionRegistry.getOrCreate({
52
- appName: runtime.appName,
53
- userId: body.userId,
54
- systemPrompt: runtime.systemPrompt,
55
- });
56
- // Process message
57
- let result;
57
+ // Resolve agent context if tenant has multi-agent config
58
+ let systemPrompt = runtime.systemPrompt;
59
+ let activeAgentId;
60
+ let activeAgentName;
61
+ let routingTier;
62
+ let routingConfidence;
63
+ if (runtime.tenant) {
64
+ // Get or create session for ping-pong guard context
65
+ const session = await runtime.sessionRegistry.getOrCreate({
66
+ appName: runtime.appName,
67
+ userId: body.userId,
68
+ systemPrompt: "",
69
+ });
70
+ const agentCtx = await resolveAgentContextAsync(runtime.tenant, userParts, session, { handoffSummarizer: runtime.handoffSummarizer, eventBus: runtime.eventBus });
71
+ systemPrompt = agentCtx.systemPrompt;
72
+ activeAgentId = agentCtx.activeAgentId;
73
+ activeAgentName = agentCtx.activeAgentName;
74
+ routingTier = agentCtx.routingResult?.tier;
75
+ routingConfidence = agentCtx.routingResult?.confidence;
76
+ // Update session with resolved prompt and agent
77
+ session.setSystemPrompt(agentCtx.systemPrompt);
78
+ if (agentCtx.activeAgentId) {
79
+ session.setActiveAgent(agentCtx.activeAgentId, agentCtx.handoffBrief);
80
+ }
81
+ await runtime.sessionRegistry.save(session);
82
+ }
83
+ let processResult;
58
84
  try {
59
- result = await runtime.orchestrator.processMessage(session, userParts);
85
+ processResult = await processInboundMessage({
86
+ orchestrator: runtime.orchestrator,
87
+ sessionRegistry: runtime.sessionRegistry,
88
+ appName: runtime.appName,
89
+ userId: body.userId,
90
+ systemPrompt,
91
+ userParts,
92
+ billing: runtime.billing,
93
+ channel: "api",
94
+ knowledgeContext,
95
+ activeAgentId,
96
+ activeAgentName,
97
+ routingTier,
98
+ routingConfidence,
99
+ });
60
100
  }
61
101
  catch (err) {
62
102
  console.error(`[${runtime.appName}] processMessage error:`, err);
63
103
  return c.json({ error: String(err) }, 500);
64
104
  }
65
- // Report token usage to billing (fire-and-forget)
66
- if (runtime.billing) {
67
- reportUsage(runtime.billing, {
68
- tenantId: body.userId,
69
- messages: 1,
70
- tokens: result.inputTokens + result.outputTokens,
71
- model: runtime.orchestrator.model ?? "unknown",
105
+ if (!processResult.ok) {
106
+ return c.json({
107
+ content: processResult.budgetDenied.message,
108
+ budgetExhausted: true,
72
109
  });
73
110
  }
111
+ const result = processResult.result;
74
112
  return c.json({
75
113
  content: extractText(result.parts),
76
114
  parts: result.parts,
77
115
  inputTokens: result.inputTokens,
78
116
  outputTokens: result.outputTokens,
79
- sessionId: session.id,
117
+ sessionId: result.sessionId,
80
118
  });
81
119
  });
82
- app.get("/sessions", (c) => {
83
- const sessions = runtime.sessionRegistry.activeSessions();
120
+ app.get("/sessions", async (c) => {
121
+ const sessions = await runtime.sessionRegistry.activeSessions();
84
122
  return c.json({
85
123
  sessions: sessions.map((s) => ({
86
124
  id: s.id,
@@ -91,9 +129,9 @@ export function createModeBRoutes(runtime) {
91
129
  })),
92
130
  });
93
131
  });
94
- app.delete("/sessions/:userId", (c) => {
132
+ app.delete("/sessions/:userId", async (c) => {
95
133
  const userId = c.req.param("userId");
96
- const removed = runtime.sessionRegistry.remove(runtime.appName, userId);
134
+ const removed = await runtime.sessionRegistry.remove(runtime.appName, userId);
97
135
  return c.json({ removed });
98
136
  });
99
137
  return app;