@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
package/README.md CHANGED
@@ -18,7 +18,7 @@
18
18
  `@kilnai/runtime` is the production runtime for [Kiln](https://github.com/sequelcore/kiln). It turns your YAML-configured AI apps into a running server with:
19
19
 
20
20
  - **Multi-app gateway** -- host multiple Kiln apps in one Bun/Hono process
21
- - **5 channel adapters** -- Web (WebSocket), WhatsApp, Slack, REST API, CLI
21
+ - **8 channel adapters** -- CLI, Web (WebSocket), WhatsApp, Instagram, Messenger, Slack, Email, REST API
22
22
  - **Multi-tenant isolation** -- per-tenant memory, system prompts, billing, and channel credentials
23
23
  - **Budget middleware** -- per-tenant token budgets with fail-open enforcement
24
24
  - **Trigger runtime** -- webhooks (HMAC-SHA256), event listeners, cron scheduler
@@ -86,10 +86,10 @@ await startDevServer("app.yaml", { port: 3000 });
86
86
  | Module | Exports |
87
87
  |--------|---------|
88
88
  | Gateway | `startGateway()`, `startDevServer()`, `createGatewayApp()`, `resolveApps()` |
89
- | Session | `ModeBOrchestrator`, `ModeBSession`, `SessionRegistry` |
89
+ | Session | `ModeBOrchestrator`, `ModeBSession`, `SessionRegistry`, `SessionMode`, `SessionStore`, `InMemorySessionStore`, `RedisSessionStore`, `serializeSession`, `deserializeSession` |
90
90
  | Tenant | `TenantRegistry`, `buildTenantSystemPrompt()`, `extractSuggestions()` |
91
91
  | Triggers | `TriggerRegistry`, `createWebhookHandler()`, `EventListener`, `Scheduler` |
92
- | Channels | `WebChannel`, `WhatsAppChannel`, `SlackChannel`, `CliChannel`, `ApiChannel` |
92
+ | Channels | `WebChannel`, `WhatsAppChannel`, `InstagramChannel`, `MessengerChannel`, `SlackChannel`, `EmailChannel`, `CliChannel`, `ApiChannel` |
93
93
  | Budget | `checkBudget()`, `reportUsage()` |
94
94
 
95
95
  ## Endpoints
@@ -105,6 +105,10 @@ When the gateway starts, it automatically mounts:
105
105
  | `POST /whatsapp/{name}/webhook` | WhatsApp webhook |
106
106
  | `POST /webhooks/{name}/{path}` | Webhook triggers |
107
107
  | `POST /admin/{name}/tenants` | Tenant CRUD (admin API) |
108
+ | `POST /{path}/handoff` | Initiate handoff (transition to queued/human_active) |
109
+ | `POST /{path}/release` | Release session back to ai_active |
110
+ | `POST /{path}/operator-message` | Send operator message to end user |
111
+ | `GET /{path}/session-history` | Retrieve full conversation history |
108
112
  | `GET /api/memory` | Memory read API |
109
113
 
110
114
  ## Documentation
@@ -0,0 +1,29 @@
1
+ /** Outbound email envelope */
2
+ export interface OutboundEmail {
3
+ readonly from: string;
4
+ readonly fromName?: string;
5
+ readonly to: string;
6
+ readonly subject: string;
7
+ readonly htmlBody: string;
8
+ readonly textBody: string;
9
+ readonly inReplyTo?: string;
10
+ readonly references?: string;
11
+ readonly headers?: Record<string, string>;
12
+ }
13
+ /** Result of sending an email */
14
+ export interface EmailSendResult {
15
+ readonly messageId: string;
16
+ }
17
+ /** Transport interface for sending emails */
18
+ export interface EmailTransport {
19
+ send(email: OutboundEmail): Promise<EmailSendResult>;
20
+ }
21
+ /** Configuration for creating an email transport */
22
+ export interface EmailTransportConfig {
23
+ readonly provider: "postmark" | "resend" | "sendgrid" | "generic";
24
+ readonly apiKey: string;
25
+ readonly endpoint?: string;
26
+ }
27
+ /** Create an email transport from configuration */
28
+ export declare function createEmailTransport(config: EmailTransportConfig): EmailTransport;
29
+ //# sourceMappingURL=email-api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email-api.d.ts","sourceRoot":"","sources":["../../src/channels/email-api.ts"],"names":[],"mappings":"AAGA,8BAA8B;AAC9B,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC3C;AAED,iCAAiC;AACjC,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,6CAA6C;AAC7C,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;CACtD;AAED,oDAAoD;AACpD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,QAAQ,EAAE,UAAU,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;IAClE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAuHD,mDAAmD;AACnD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,oBAAoB,GAAG,cAAc,CAYjF"}
@@ -0,0 +1,133 @@
1
+ // Email transport abstraction with pluggable providers
2
+ // Raw fetch only, no SDK dependencies
3
+ /** Postmark transactional email transport */
4
+ class PostmarkTransport {
5
+ apiKey;
6
+ constructor(apiKey) {
7
+ this.apiKey = apiKey;
8
+ }
9
+ async send(email) {
10
+ const from = email.fromName ? `${email.fromName} <${email.from}>` : email.from;
11
+ const headers = [
12
+ { Name: "Auto-Submitted", Value: "auto-generated" },
13
+ { Name: "X-Auto-Response-Suppress", Value: "OOF, AutoReply" },
14
+ ];
15
+ if (email.inReplyTo)
16
+ headers.push({ Name: "In-Reply-To", Value: email.inReplyTo });
17
+ if (email.references)
18
+ headers.push({ Name: "References", Value: email.references });
19
+ const res = await fetch("https://api.postmarkapp.com/email", {
20
+ method: "POST",
21
+ headers: {
22
+ "Content-Type": "application/json",
23
+ Accept: "application/json",
24
+ "X-Postmark-Server-Token": this.apiKey,
25
+ },
26
+ body: JSON.stringify({
27
+ From: from,
28
+ To: email.to,
29
+ Subject: email.subject,
30
+ HtmlBody: email.htmlBody,
31
+ TextBody: email.textBody,
32
+ Headers: headers,
33
+ }),
34
+ });
35
+ if (!res.ok) {
36
+ const body = await res.text().catch(() => "(unreadable)");
37
+ throw new Error(`Postmark API error ${res.status}: ${body}`);
38
+ }
39
+ const json = (await res.json());
40
+ return { messageId: json.MessageID ?? "" };
41
+ }
42
+ }
43
+ /** Resend email transport */
44
+ class ResendTransport {
45
+ apiKey;
46
+ constructor(apiKey) {
47
+ this.apiKey = apiKey;
48
+ }
49
+ async send(email) {
50
+ const from = email.fromName ? `${email.fromName} <${email.from}>` : email.from;
51
+ const headers = {
52
+ "Auto-Submitted": "auto-generated",
53
+ "X-Auto-Response-Suppress": "OOF, AutoReply",
54
+ ...email.headers,
55
+ };
56
+ if (email.inReplyTo)
57
+ headers["In-Reply-To"] = email.inReplyTo;
58
+ if (email.references)
59
+ headers["References"] = email.references;
60
+ const res = await fetch("https://api.resend.com/emails", {
61
+ method: "POST",
62
+ headers: {
63
+ "Content-Type": "application/json",
64
+ Authorization: `Bearer ${this.apiKey}`,
65
+ },
66
+ body: JSON.stringify({
67
+ from,
68
+ to: email.to,
69
+ subject: email.subject,
70
+ html: email.htmlBody,
71
+ text: email.textBody,
72
+ headers,
73
+ }),
74
+ });
75
+ if (!res.ok) {
76
+ const body = await res.text().catch(() => "(unreadable)");
77
+ throw new Error(`Resend API error ${res.status}: ${body}`);
78
+ }
79
+ const json = (await res.json());
80
+ return { messageId: json.id ?? "" };
81
+ }
82
+ }
83
+ /** Generic API email transport with configurable endpoint */
84
+ class GenericApiTransport {
85
+ apiKey;
86
+ endpoint;
87
+ constructor(apiKey, endpoint) {
88
+ this.apiKey = apiKey;
89
+ this.endpoint = endpoint;
90
+ }
91
+ async send(email) {
92
+ const res = await fetch(this.endpoint, {
93
+ method: "POST",
94
+ headers: {
95
+ "Content-Type": "application/json",
96
+ Authorization: `Bearer ${this.apiKey}`,
97
+ },
98
+ body: JSON.stringify({
99
+ from: email.from,
100
+ fromName: email.fromName,
101
+ to: email.to,
102
+ subject: email.subject,
103
+ htmlBody: email.htmlBody,
104
+ textBody: email.textBody,
105
+ inReplyTo: email.inReplyTo,
106
+ references: email.references,
107
+ headers: email.headers,
108
+ }),
109
+ });
110
+ if (!res.ok) {
111
+ const body = await res.text().catch(() => "(unreadable)");
112
+ throw new Error(`Email API error ${res.status}: ${body}`);
113
+ }
114
+ const json = (await res.json());
115
+ return { messageId: json.messageId ?? "" };
116
+ }
117
+ }
118
+ /** Create an email transport from configuration */
119
+ export function createEmailTransport(config) {
120
+ switch (config.provider) {
121
+ case "postmark":
122
+ return new PostmarkTransport(config.apiKey);
123
+ case "resend":
124
+ return new ResendTransport(config.apiKey);
125
+ case "sendgrid":
126
+ return new ResendTransport(config.apiKey); // SendGrid uses same Bearer auth pattern
127
+ case "generic":
128
+ if (!config.endpoint)
129
+ throw new Error("Generic email transport requires an endpoint");
130
+ return new GenericApiTransport(config.apiKey, config.endpoint);
131
+ }
132
+ }
133
+ //# sourceMappingURL=email-api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email-api.js","sourceRoot":"","sources":["../../src/channels/email-api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type { Channel, IncomingMessage, OutgoingMessage, EngineEvent, MessageFormat, Modality } from "@kilnai/core";
2
+ import type { EmailTransport } from "./email-api.js";
3
+ export interface EmailChannelConfig {
4
+ readonly transport: EmailTransport;
5
+ readonly fromAddress: string;
6
+ readonly fromName?: string;
7
+ }
8
+ /**
9
+ * Channel adapter for email.
10
+ * receive() accepts parsed inbound emails (from webhook providers).
11
+ * send() renders HTML + plain text and delivers via the configured transport.
12
+ * stream() buffers events and sends as a single email (email is non-streaming).
13
+ */
14
+ export declare class EmailChannel implements Channel {
15
+ readonly name = "email";
16
+ readonly defaultFormat: MessageFormat;
17
+ readonly supportedModalities: readonly Modality[];
18
+ private readonly config;
19
+ private messageHandler;
20
+ constructor(config: EmailChannelConfig);
21
+ onMessage(handler: (message: IncomingMessage) => void): void;
22
+ receive(message: IncomingMessage): Promise<void>;
23
+ send(response: OutgoingMessage): Promise<void>;
24
+ stream(events: AsyncIterable<EngineEvent>): Promise<void>;
25
+ }
26
+ //# sourceMappingURL=email-channel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email-channel.d.ts","sourceRoot":"","sources":["../../src/channels/email-channel.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,WAAW,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAEpH,OAAO,KAAK,EAAE,cAAc,EAAiB,MAAM,gBAAgB,CAAC;AAGpE,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAC;IACnC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;GAKG;AACH,qBAAa,YAAa,YAAW,OAAO;IAC1C,QAAQ,CAAC,IAAI,WAAW;IACxB,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAU;IAC/C,QAAQ,CAAC,mBAAmB,EAAE,SAAS,QAAQ,EAAE,CAAoB;IAErE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C,OAAO,CAAC,cAAc,CAAqD;gBAE/D,MAAM,EAAE,kBAAkB;IAItC,SAAS,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,GAAG,IAAI;IAItD,OAAO,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAMhD,IAAI,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAwB9C,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;CAShE"}
@@ -0,0 +1,59 @@
1
+ // EmailChannel: Email adapter for AI-powered email replies
2
+ // Uses pluggable EmailTransport for outbound delivery
3
+ import { extractText, textParts } from "@kilnai/core";
4
+ import { renderEmailHtml, renderEmailPlainText } from "./email-template.js";
5
+ /**
6
+ * Channel adapter for email.
7
+ * receive() accepts parsed inbound emails (from webhook providers).
8
+ * send() renders HTML + plain text and delivers via the configured transport.
9
+ * stream() buffers events and sends as a single email (email is non-streaming).
10
+ */
11
+ export class EmailChannel {
12
+ name = "email";
13
+ defaultFormat = "full";
14
+ supportedModalities = ["text", "file"];
15
+ config;
16
+ messageHandler = null;
17
+ constructor(config) {
18
+ this.config = config;
19
+ }
20
+ onMessage(handler) {
21
+ this.messageHandler = handler;
22
+ }
23
+ async receive(message) {
24
+ if (this.messageHandler) {
25
+ this.messageHandler(message);
26
+ }
27
+ }
28
+ async send(response) {
29
+ const text = extractText(response.parts);
30
+ if (!text)
31
+ return;
32
+ const to = response.metadata?.to;
33
+ const subject = response.metadata?.subject ?? "Re: Your message";
34
+ const inReplyTo = response.metadata?.inReplyTo;
35
+ const references = response.metadata?.references;
36
+ const branding = response.metadata?.branding;
37
+ const email = {
38
+ from: this.config.fromAddress,
39
+ fromName: this.config.fromName,
40
+ to: to ?? response.target,
41
+ subject,
42
+ htmlBody: renderEmailHtml(text, branding),
43
+ textBody: renderEmailPlainText(text),
44
+ inReplyTo,
45
+ references,
46
+ };
47
+ await this.config.transport.send(email);
48
+ }
49
+ async stream(events) {
50
+ for await (const event of events) {
51
+ await this.send({
52
+ parts: textParts(`[${event.type}] ${JSON.stringify(event.payload)}`),
53
+ target: "stream",
54
+ format: this.defaultFormat,
55
+ });
56
+ }
57
+ }
58
+ }
59
+ //# sourceMappingURL=email-channel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email-channel.js","sourceRoot":"","sources":["../../src/channels/email-channel.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,sDAAsD;AAGtD,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEtD,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAQ5E;;;;;GAKG;AACH,MAAM,OAAO,YAAY;IACd,IAAI,GAAG,OAAO,CAAC;IACf,aAAa,GAAkB,MAAM,CAAC;IACtC,mBAAmB,GAAwB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEpD,MAAM,CAAqB;IACpC,cAAc,GAAgD,IAAI,CAAC;IAE3E,YAAY,MAA0B;QACpC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED,SAAS,CAAC,OAA2C;QACnD,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC;IAChC,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,OAAwB;QACpC,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACxB,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,QAAyB;QAClC,MAAM,IAAI,GAAG,WAAW,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACzC,IAAI,CAAC,IAAI;YAAE,OAAO;QAElB,MAAM,EAAE,GAAG,QAAQ,CAAC,QAAQ,EAAE,EAAwB,CAAC;QACvD,MAAM,OAAO,GAAI,QAAQ,CAAC,QAAQ,EAAE,OAA8B,IAAI,kBAAkB,CAAC;QACzF,MAAM,SAAS,GAAG,QAAQ,CAAC,QAAQ,EAAE,SAA+B,CAAC;QACrE,MAAM,UAAU,GAAG,QAAQ,CAAC,QAAQ,EAAE,UAAgC,CAAC;QACvE,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,EAAE,QAA8C,CAAC;QAEnF,MAAM,KAAK,GAAkB;YAC3B,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW;YAC7B,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ;YAC9B,EAAE,EAAE,EAAE,IAAI,QAAQ,CAAC,MAAM;YACzB,OAAO;YACP,QAAQ,EAAE,eAAe,CAAC,IAAI,EAAE,QAAQ,CAAC;YACzC,QAAQ,EAAE,oBAAoB,CAAC,IAAI,CAAC;YACpC,SAAS;YACT,UAAU;SACX,CAAC;QAEF,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1C,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,MAAkC;QAC7C,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YACjC,MAAM,IAAI,CAAC,IAAI,CAAC;gBACd,KAAK,EAAE,SAAS,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;gBACpE,MAAM,EAAE,QAAQ;gBAChB,MAAM,EAAE,IAAI,CAAC,aAAa;aAC3B,CAAC,CAAC;QACL,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,10 @@
1
+ export interface EmailBranding {
2
+ readonly businessName?: string;
3
+ readonly primaryColor?: string;
4
+ readonly unsubscribeUrl?: string;
5
+ }
6
+ /** Render text content into a responsive HTML email template */
7
+ export declare function renderEmailHtml(text: string, branding?: EmailBranding): string;
8
+ /** Render text as a plain text email body, stripping markdown */
9
+ export declare function renderEmailPlainText(text: string): string;
10
+ //# sourceMappingURL=email-template.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email-template.d.ts","sourceRoot":"","sources":["../../src/channels/email-template.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CAClC;AAED,gEAAgE;AAChE,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,aAAa,GAAG,MAAM,CA6B9E;AAED,iEAAiE;AACjE,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzD"}
@@ -0,0 +1,63 @@
1
+ // Email HTML template rendering with inline CSS
2
+ // Produces responsive, client-safe HTML for email delivery
3
+ /** Render text content into a responsive HTML email template */
4
+ export function renderEmailHtml(text, branding) {
5
+ const primaryColor = branding?.primaryColor ?? "#333333";
6
+ const fontStack = "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif";
7
+ const header = branding?.businessName
8
+ ? `<tr><td style="padding:24px 32px 16px;background:${primaryColor};color:#ffffff;font-family:${fontStack};font-size:18px;font-weight:600;border-radius:8px 8px 0 0;">${escapeHtml(branding.businessName)}</td></tr>`
9
+ : "";
10
+ const topRadius = branding?.businessName ? "0" : "8px";
11
+ const footer = branding?.unsubscribeUrl
12
+ ? `<tr><td style="padding:16px 32px;text-align:center;font-family:${fontStack};font-size:12px;color:#999999;"><a href="${escapeHtml(branding.unsubscribeUrl)}" style="color:#999999;text-decoration:underline;">Unsubscribe</a></td></tr>`
13
+ : "";
14
+ const bodyHtml = textToHtml(text);
15
+ return `<!DOCTYPE html>
16
+ <html lang="en">
17
+ <head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1.0"></head>
18
+ <body style="margin:0;padding:0;background:#f4f4f7;">
19
+ <table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="background:#f4f4f7;padding:32px 16px;">
20
+ <tr><td align="center">
21
+ <table role="presentation" width="600" cellpadding="0" cellspacing="0" style="max-width:600px;width:100%;background:#ffffff;border-radius:8px;box-shadow:0 1px 3px rgba(0,0,0,0.08);">
22
+ ${header}<tr><td style="padding:24px 32px;font-family:${fontStack};font-size:15px;line-height:1.6;color:#333333;border-radius:${topRadius} ${topRadius} 0 0;">${bodyHtml}</td></tr>
23
+ ${footer}</table>
24
+ </td></tr>
25
+ </table>
26
+ </body>
27
+ </html>`;
28
+ }
29
+ /** Render text as a plain text email body, stripping markdown */
30
+ export function renderEmailPlainText(text) {
31
+ return stripMarkdown(text);
32
+ }
33
+ /** Convert newlines to HTML, wrapping in paragraphs */
34
+ function textToHtml(text) {
35
+ const paragraphs = text.split(/\n{2,}/);
36
+ return paragraphs
37
+ .map((p) => {
38
+ const inner = escapeHtml(p.trim()).replace(/\n/g, "<br>");
39
+ return `<p style="margin:0 0 16px 0;">${inner}</p>`;
40
+ })
41
+ .filter((p) => p !== '<p style="margin:0 0 16px 0;"></p>')
42
+ .join("\n");
43
+ }
44
+ /** Escape HTML special characters */
45
+ function escapeHtml(text) {
46
+ return text
47
+ .replace(/&/g, "&amp;")
48
+ .replace(/</g, "&lt;")
49
+ .replace(/>/g, "&gt;")
50
+ .replace(/"/g, "&quot;");
51
+ }
52
+ /** Strip basic markdown formatting for plain text */
53
+ function stripMarkdown(text) {
54
+ return text
55
+ .replace(/```[\s\S]*?```/g, "[code block]")
56
+ .replace(/`([^`]+)`/g, "$1")
57
+ .replace(/\*\*([^*]+)\*\*/g, "$1")
58
+ .replace(/\*([^*]+)\*/g, "$1")
59
+ .replace(/#+\s/g, "")
60
+ .replace(/\[([^\]]+)\]\([^)]+\)/g, "$1")
61
+ .replace(/^[-*]\s/gm, "- ");
62
+ }
63
+ //# sourceMappingURL=email-template.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email-template.js","sourceRoot":"","sources":["../../src/channels/email-template.ts"],"names":[],"mappings":"AAAA,gDAAgD;AAChD,2DAA2D;AAQ3D,gEAAgE;AAChE,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,QAAwB;IACpE,MAAM,YAAY,GAAG,QAAQ,EAAE,YAAY,IAAI,SAAS,CAAC;IACzD,MAAM,SAAS,GAAG,qFAAqF,CAAC;IAExG,MAAM,MAAM,GAAG,QAAQ,EAAE,YAAY;QACnC,CAAC,CAAC,oDAAoD,YAAY,8BAA8B,SAAS,+DAA+D,UAAU,CAAC,QAAQ,CAAC,YAAY,CAAC,YAAY;QACrN,CAAC,CAAC,EAAE,CAAC;IAEP,MAAM,SAAS,GAAG,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC;IAEvD,MAAM,MAAM,GAAG,QAAQ,EAAE,cAAc;QACrC,CAAC,CAAC,kEAAkE,SAAS,4CAA4C,UAAU,CAAC,QAAQ,CAAC,cAAc,CAAC,8EAA8E;QAC1O,CAAC,CAAC,EAAE,CAAC;IAEP,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAElC,OAAO;;;;;;;EAOP,MAAM,gDAAgD,SAAS,+DAA+D,SAAS,IAAI,SAAS,UAAU,QAAQ;EACtK,MAAM;;;;QAIA,CAAC;AACT,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC/C,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC;AAC7B,CAAC;AAED,uDAAuD;AACvD,SAAS,UAAU,CAAC,IAAY;IAC9B,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IACxC,OAAO,UAAU;SACd,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACT,MAAM,KAAK,GAAG,UAAU,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC1D,OAAO,iCAAiC,KAAK,MAAM,CAAC;IACtD,CAAC,CAAC;SACD,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,oCAAoC,CAAC;SACzD,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED,qCAAqC;AACrC,SAAS,UAAU,CAAC,IAAY;IAC9B,OAAO,IAAI;SACR,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AAC7B,CAAC;AAED,qDAAqD;AACrD,SAAS,aAAa,CAAC,IAAY;IACjC,OAAO,IAAI;SACR,OAAO,CAAC,iBAAiB,EAAE,cAAc,CAAC;SAC1C,OAAO,CAAC,YAAY,EAAE,IAAI,CAAC;SAC3B,OAAO,CAAC,kBAAkB,EAAE,IAAI,CAAC;SACjC,OAAO,CAAC,cAAc,EAAE,IAAI,CAAC;SAC7B,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;SACpB,OAAO,CAAC,wBAAwB,EAAE,IAAI,CAAC;SACvC,OAAO,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;AAChC,CAAC"}
@@ -0,0 +1,29 @@
1
+ /** Instagram/Meta Graph API version */
2
+ export declare const INSTAGRAM_GRAPH_API_VERSION = "v21.0";
3
+ /** Build the Instagram Graph API messages endpoint URL */
4
+ export declare function instagramMessagesUrl(pageId: string): string;
5
+ /** Response from Instagram messaging API */
6
+ export interface InstagramSendResult {
7
+ readonly recipientId: string;
8
+ readonly messageId: string;
9
+ }
10
+ /**
11
+ * Send a text message via Instagram Messaging API.
12
+ *
13
+ * @param pageId - The Instagram-connected Page ID
14
+ * @param accessToken - Page access token
15
+ * @param recipientId - Instagram-scoped user ID (IGSID)
16
+ * @param text - Message text (max 1000 chars)
17
+ */
18
+ export declare function sendInstagramMessage(pageId: string, accessToken: string, recipientId: string, text: string): Promise<InstagramSendResult>;
19
+ /**
20
+ * Send a media message (image) via Instagram Messaging API.
21
+ *
22
+ * @param pageId - The Instagram-connected Page ID
23
+ * @param accessToken - Page access token
24
+ * @param recipientId - Instagram-scoped user ID (IGSID)
25
+ * @param mediaUrl - Public URL of the media
26
+ * @param mediaType - Type of media ("image")
27
+ */
28
+ export declare function sendInstagramMediaMessage(pageId: string, accessToken: string, recipientId: string, mediaUrl: string, mediaType: "image"): Promise<InstagramSendResult>;
29
+ //# sourceMappingURL=instagram-api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instagram-api.d.ts","sourceRoot":"","sources":["../../src/channels/instagram-api.ts"],"names":[],"mappings":"AAGA,uCAAuC;AACvC,eAAO,MAAM,2BAA2B,UAAU,CAAC;AAEnD,0DAA0D;AAC1D,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED,4CAA4C;AAC5C,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,mBAAmB,CAAC,CAuB9B;AAED;;;;;;;;GAQG;AACH,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,OAAO,GACjB,OAAO,CAAC,mBAAmB,CAAC,CA4B9B"}
@@ -0,0 +1,75 @@
1
+ // Instagram Messaging API client
2
+ // Uses the Instagram Graph API (same version as WhatsApp) for DM replies
3
+ /** Instagram/Meta Graph API version */
4
+ export const INSTAGRAM_GRAPH_API_VERSION = "v21.0";
5
+ /** Build the Instagram Graph API messages endpoint URL */
6
+ export function instagramMessagesUrl(pageId) {
7
+ return `https://graph.facebook.com/${INSTAGRAM_GRAPH_API_VERSION}/${pageId}/messages`;
8
+ }
9
+ /**
10
+ * Send a text message via Instagram Messaging API.
11
+ *
12
+ * @param pageId - The Instagram-connected Page ID
13
+ * @param accessToken - Page access token
14
+ * @param recipientId - Instagram-scoped user ID (IGSID)
15
+ * @param text - Message text (max 1000 chars)
16
+ */
17
+ export async function sendInstagramMessage(pageId, accessToken, recipientId, text) {
18
+ const res = await fetch(instagramMessagesUrl(pageId), {
19
+ method: "POST",
20
+ headers: {
21
+ "Content-Type": "application/json",
22
+ Authorization: `Bearer ${accessToken}`,
23
+ },
24
+ body: JSON.stringify({
25
+ recipient: { id: recipientId },
26
+ message: { text },
27
+ }),
28
+ });
29
+ if (!res.ok) {
30
+ const body = await res.text().catch(() => "(unreadable)");
31
+ throw new Error(`Instagram API error ${res.status}: ${body}`);
32
+ }
33
+ const json = (await res.json());
34
+ return {
35
+ recipientId: json.recipient_id ?? recipientId,
36
+ messageId: json.message_id ?? "",
37
+ };
38
+ }
39
+ /**
40
+ * Send a media message (image) via Instagram Messaging API.
41
+ *
42
+ * @param pageId - The Instagram-connected Page ID
43
+ * @param accessToken - Page access token
44
+ * @param recipientId - Instagram-scoped user ID (IGSID)
45
+ * @param mediaUrl - Public URL of the media
46
+ * @param mediaType - Type of media ("image")
47
+ */
48
+ export async function sendInstagramMediaMessage(pageId, accessToken, recipientId, mediaUrl, mediaType) {
49
+ const res = await fetch(instagramMessagesUrl(pageId), {
50
+ method: "POST",
51
+ headers: {
52
+ "Content-Type": "application/json",
53
+ Authorization: `Bearer ${accessToken}`,
54
+ },
55
+ body: JSON.stringify({
56
+ recipient: { id: recipientId },
57
+ message: {
58
+ attachment: {
59
+ type: mediaType,
60
+ payload: { url: mediaUrl },
61
+ },
62
+ },
63
+ }),
64
+ });
65
+ if (!res.ok) {
66
+ const body = await res.text().catch(() => "(unreadable)");
67
+ throw new Error(`Instagram API error ${res.status}: ${body}`);
68
+ }
69
+ const json = (await res.json());
70
+ return {
71
+ recipientId: json.recipient_id ?? recipientId,
72
+ messageId: json.message_id ?? "",
73
+ };
74
+ }
75
+ //# sourceMappingURL=instagram-api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instagram-api.js","sourceRoot":"","sources":["../../src/channels/instagram-api.ts"],"names":[],"mappings":"AAAA,iCAAiC;AACjC,yEAAyE;AAEzE,uCAAuC;AACvC,MAAM,CAAC,MAAM,2BAA2B,GAAG,OAAO,CAAC;AAEnD,0DAA0D;AAC1D,MAAM,UAAU,oBAAoB,CAAC,MAAc;IACjD,OAAO,8BAA8B,2BAA2B,IAAI,MAAM,WAAW,CAAC;AACxF,CAAC;AAQD;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,MAAc,EACd,WAAmB,EACnB,WAAmB,EACnB,IAAY;IAEZ,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,oBAAoB,CAAC,MAAM,CAAC,EAAE;QACpD,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,aAAa,EAAE,UAAU,WAAW,EAAE;SACvC;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;YACnB,SAAS,EAAE,EAAE,EAAE,EAAE,WAAW,EAAE;YAC9B,OAAO,EAAE,EAAE,IAAI,EAAE;SAClB,CAAC;KACH,CAAC,CAAC;IAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,cAAc,CAAC,CAAC;QAC1D,MAAM,IAAI,KAAK,CAAC,uBAAuB,GAAG,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC,CAAC;IAChE,CAAC;IAED,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAmD,CAAC;IAClF,OAAO;QACL,WAAW,EAAE,IAAI,CAAC,YAAY,IAAI,WAAW;QAC7C,SAAS,EAAE,IAAI,CAAC,UAAU,IAAI,EAAE;KACjC,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,MAAc,EACd,WAAmB,EACnB,WAAmB,EACnB,QAAgB,EAChB,SAAkB;IAElB,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,oBAAoB,CAAC,MAAM,CAAC,EAAE;QACpD,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,aAAa,EAAE,UAAU,WAAW,EAAE;SACvC;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;YACnB,SAAS,EAAE,EAAE,EAAE,EAAE,WAAW,EAAE;YAC9B,OAAO,EAAE;gBACP,UAAU,EAAE;oBACV,IAAI,EAAE,SAAS;oBACf,OAAO,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE;iBAC3B;aACF;SACF,CAAC;KACH,CAAC,CAAC;IAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,cAAc,CAAC,CAAC;QAC1D,MAAM,IAAI,KAAK,CAAC,uBAAuB,GAAG,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC,CAAC;IAChE,CAAC;IAED,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAmD,CAAC;IAClF,OAAO;QACL,WAAW,EAAE,IAAI,CAAC,YAAY,IAAI,WAAW;QAC7C,SAAS,EAAE,IAAI,CAAC,UAAU,IAAI,EAAE;KACjC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,24 @@
1
+ import type { Channel, IncomingMessage, OutgoingMessage, EngineEvent, MessageFormat, Modality } from "@kilnai/core";
2
+ export interface InstagramConfig {
3
+ readonly pageId: string;
4
+ readonly accessToken: string;
5
+ }
6
+ /**
7
+ * Channel adapter for Instagram DM API.
8
+ * receive() accepts parsed webhook messages from Instagram.
9
+ * send() posts text/image messages via graph.facebook.com.
10
+ * stream() sends each engine event as a summarized text message.
11
+ */
12
+ export declare class InstagramChannel implements Channel {
13
+ readonly name = "instagram";
14
+ readonly defaultFormat: MessageFormat;
15
+ readonly supportedModalities: readonly Modality[];
16
+ private readonly config;
17
+ private messageHandler;
18
+ constructor(config: InstagramConfig);
19
+ onMessage(handler: (message: IncomingMessage) => void): void;
20
+ receive(message: IncomingMessage): Promise<void>;
21
+ send(response: OutgoingMessage): Promise<void>;
22
+ stream(events: AsyncIterable<EngineEvent>): Promise<void>;
23
+ }
24
+ //# sourceMappingURL=instagram-channel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instagram-channel.d.ts","sourceRoot":"","sources":["../../src/channels/instagram-channel.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,WAAW,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAKpH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;GAKG;AACH,qBAAa,gBAAiB,YAAW,OAAO;IAC9C,QAAQ,CAAC,IAAI,eAAe;IAC5B,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAW;IAChD,QAAQ,CAAC,mBAAmB,EAAE,SAAS,QAAQ,EAAE,CAAqB;IAEtE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IACzC,OAAO,CAAC,cAAc,CAAqD;gBAE/D,MAAM,EAAE,eAAe;IAInC,SAAS,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,GAAG,IAAI;IAItD,OAAO,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAMhD,IAAI,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAmB9C,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;CAShE"}
@@ -0,0 +1,55 @@
1
+ // InstagramChannel: Instagram DM API adapter
2
+ // Uses Instagram Graph API via shared API client
3
+ import { extractText, textParts } from "@kilnai/core";
4
+ import { toInstagramFormat } from "./message-formatter.js";
5
+ import { sendInstagramMessage, sendInstagramMediaMessage } from "./instagram-api.js";
6
+ /**
7
+ * Channel adapter for Instagram DM API.
8
+ * receive() accepts parsed webhook messages from Instagram.
9
+ * send() posts text/image messages via graph.facebook.com.
10
+ * stream() sends each engine event as a summarized text message.
11
+ */
12
+ export class InstagramChannel {
13
+ name = "instagram";
14
+ defaultFormat = "short";
15
+ supportedModalities = ["text", "image"];
16
+ config;
17
+ messageHandler = null;
18
+ constructor(config) {
19
+ this.config = config;
20
+ }
21
+ onMessage(handler) {
22
+ this.messageHandler = handler;
23
+ }
24
+ async receive(message) {
25
+ if (this.messageHandler) {
26
+ this.messageHandler(message);
27
+ }
28
+ }
29
+ async send(response) {
30
+ const { pageId, accessToken } = this.config;
31
+ const to = response.target;
32
+ // Send image parts first
33
+ for (const part of response.parts) {
34
+ if (part.type === "image" && part.url) {
35
+ await sendInstagramMediaMessage(pageId, accessToken, to, part.url, "image");
36
+ }
37
+ }
38
+ // Send text content
39
+ const text = extractText(response.parts);
40
+ if (text) {
41
+ const formatted = toInstagramFormat(text);
42
+ await sendInstagramMessage(pageId, accessToken, to, formatted);
43
+ }
44
+ }
45
+ async stream(events) {
46
+ for await (const event of events) {
47
+ await this.send({
48
+ parts: textParts(`[${event.type}] ${JSON.stringify(event.payload)}`),
49
+ target: "stream",
50
+ format: this.defaultFormat,
51
+ });
52
+ }
53
+ }
54
+ }
55
+ //# sourceMappingURL=instagram-channel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instagram-channel.js","sourceRoot":"","sources":["../../src/channels/instagram-channel.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,iDAAiD;AAGjD,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAOrF;;;;;GAKG;AACH,MAAM,OAAO,gBAAgB;IAClB,IAAI,GAAG,WAAW,CAAC;IACnB,aAAa,GAAkB,OAAO,CAAC;IACvC,mBAAmB,GAAwB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAErD,MAAM,CAAkB;IACjC,cAAc,GAAgD,IAAI,CAAC;IAE3E,YAAY,MAAuB;QACjC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED,SAAS,CAAC,OAA2C;QACnD,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC;IAChC,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,OAAwB;QACpC,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACxB,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,QAAyB;QAClC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC;QAC5C,MAAM,EAAE,GAAG,QAAQ,CAAC,MAAM,CAAC;QAE3B,yBAAyB;QACzB,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;YAClC,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;gBACtC,MAAM,yBAAyB,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;YAC9E,CAAC;QACH,CAAC;QAED,oBAAoB;QACpB,MAAM,IAAI,GAAG,WAAW,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACzC,IAAI,IAAI,EAAE,CAAC;YACT,MAAM,SAAS,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;YAC1C,MAAM,oBAAoB,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE,EAAE,SAAS,CAAC,CAAC;QACjE,CAAC;IACH,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,MAAkC;QAC7C,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YACjC,MAAM,IAAI,CAAC,IAAI,CAAC;gBACd,KAAK,EAAE,SAAS,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;gBACpE,MAAM,EAAE,QAAQ;gBAChB,MAAM,EAAE,IAAI,CAAC,aAAa;aAC3B,CAAC,CAAC;QACL,CAAC;IACH,CAAC;CACF"}
@@ -14,4 +14,21 @@ export declare function formatForChannel(content: string, format: MessageFormat)
14
14
  * truncates to the 4096-char Cloud API limit.
15
15
  */
16
16
  export declare function toWhatsAppFormat(text: string): string;
17
+ /**
18
+ * Convert content to Instagram-compatible plain text.
19
+ * Instagram DM API supports plain text only (no markdown, no formatting).
20
+ * Truncates to 1000-char API limit.
21
+ */
22
+ export declare function toInstagramFormat(text: string): string;
23
+ /**
24
+ * Convert content to Messenger-compatible plain text.
25
+ * Messenger supports plain text only (no markdown).
26
+ * Truncates to 2000-char API limit.
27
+ */
28
+ export declare function toMessengerFormat(text: string): string;
29
+ /**
30
+ * Format content for email -- keep full markdown (email supports rich formatting).
31
+ * No character truncation (email has no message length limit).
32
+ */
33
+ export declare function toEmailFormat(text: string): string;
17
34
  //# sourceMappingURL=message-formatter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"message-formatter.d.ts","sourceRoot":"","sources":["../../src/channels/message-formatter.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAKlD,kDAAkD;AAClD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,MAAM,CAc/E;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAErD"}
1
+ {"version":3,"file":"message-formatter.d.ts","sourceRoot":"","sources":["../../src/channels/message-formatter.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAWlD,kDAAkD;AAClD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,MAAM,CAc/E;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAErD;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD"}