@copilotkit/channels-core 0.4.1-canary.parallel1 → 0.5.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 (47) hide show
  1. package/README.md +7 -8
  2. package/dist/canonical-run-loop.test.d.ts +2 -0
  3. package/dist/canonical-run-loop.test.d.ts.map +1 -0
  4. package/dist/canonical-run-loop.test.js +453 -0
  5. package/dist/codec.d.ts +2 -3
  6. package/dist/codec.d.ts.map +1 -1
  7. package/dist/create-channel.d.ts +110 -4
  8. package/dist/create-channel.d.ts.map +1 -1
  9. package/dist/create-channel.js +258 -92
  10. package/dist/create-channel.test.js +552 -29
  11. package/dist/delivery-error.d.ts +17 -0
  12. package/dist/delivery-error.d.ts.map +1 -0
  13. package/dist/delivery-error.js +22 -0
  14. package/dist/index.d.ts +6 -2
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +8 -0
  17. package/dist/managed-v1-await-choice-guard.test.d.ts +2 -0
  18. package/dist/managed-v1-await-choice-guard.test.d.ts.map +1 -0
  19. package/dist/managed-v1-await-choice-guard.test.js +52 -0
  20. package/dist/platform-adapter.d.ts +74 -11
  21. package/dist/platform-adapter.d.ts.map +1 -1
  22. package/dist/run-loop.d.ts +25 -6
  23. package/dist/run-loop.d.ts.map +1 -1
  24. package/dist/run-loop.js +289 -39
  25. package/dist/run-loop.test.js +37 -0
  26. package/dist/sanitize-agent-events.d.ts +24 -0
  27. package/dist/sanitize-agent-events.d.ts.map +1 -0
  28. package/dist/sanitize-agent-events.js +88 -0
  29. package/dist/sanitize-agent-events.test.d.ts +2 -0
  30. package/dist/sanitize-agent-events.test.d.ts.map +1 -0
  31. package/dist/sanitize-agent-events.test.js +194 -0
  32. package/dist/source-platform.test.d.ts +2 -0
  33. package/dist/source-platform.test.d.ts.map +1 -0
  34. package/dist/source-platform.test.js +149 -0
  35. package/dist/testing/fake-adapter.d.ts +8 -1
  36. package/dist/testing/fake-adapter.d.ts.map +1 -1
  37. package/dist/testing/fake-adapter.js +30 -1
  38. package/dist/testing/fake-agent.d.ts +5 -0
  39. package/dist/testing/fake-agent.d.ts.map +1 -1
  40. package/dist/testing/fake-agent.js +12 -0
  41. package/dist/thread-promise-contract.test.d.ts +2 -0
  42. package/dist/thread-promise-contract.test.d.ts.map +1 -0
  43. package/dist/thread-promise-contract.test.js +37 -0
  44. package/dist/thread.d.ts +5 -0
  45. package/dist/thread.d.ts.map +1 -1
  46. package/dist/thread.js +338 -243
  47. package/package.json +4 -4
@@ -1 +1 @@
1
- {"version":3,"file":"create-channel.d.ts","sourceRoot":"","sources":["../src/create-channel.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"create-channel.d.ts","sourceRoot":"","sources":["../src/create-channel.ts"],"names":[],"mappings":"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"}
@@ -4,6 +4,7 @@ import { kvActionStore } from "./state/kv-action-store.js";
4
4
  import { toAgentToolDescriptors, parseToolArgs } from "./tools.js";
5
5
  import { normalizeCommandName, toCommandSpec } from "./commands.js";
6
6
  import { Thread } from "./thread.js";
7
+ import { sanitizeAgentEventStream } from "./sanitize-agent-events.js";
7
8
  import { normalizeEmoji, toCanonicalEmoji, renderToIR, } from "@copilotkit/channels-ui";
8
9
  import { Transcripts } from "./transcripts.js";
9
10
  import { ChannelTelemetry } from "./telemetry/channel-telemetry.js";
@@ -31,6 +32,107 @@ const EMOJI_PLATFORMS = new Set([
31
32
  function isEmojiPlatform(platform) {
32
33
  return EMOJI_PLATFORMS.has(platform);
33
34
  }
35
+ /**
36
+ * Isolate an agent for one turn via `clone()`.
37
+ *
38
+ * Applied to every configured shape, so the object a turn runs on is never one
39
+ * the caller still holds a reference to:
40
+ * - `createChannel({ agent: shared })` — singleton config
41
+ * - `agent: (id) => new Agent()` — fresh factory, cloning an unused agent
42
+ * - `agent: (id) => shared` — factory returning the same object every call
43
+ *
44
+ * The last shape is the one that needs this, and it is easy to write by accident
45
+ * (it is also what a singleton becomes when someone refactors to get at the
46
+ * `threadId`). Sharing one `AbstractAgent` across turns is not safe, because
47
+ * turn concurrency defaults to `"parallel"` — see {@link ChannelConcurrency} —
48
+ * and only the managed adapter serializes same-thread deliveries. On a directly
49
+ * connected adapter two turns in one conversation can run at the same time, and
50
+ * on the same instance they corrupt each other: `messages` is a single array
51
+ * both runs append into, so each run's new-message diff picks up the other's,
52
+ * and `isRunning` / `activeRunDetach$` / `activeRunCompletionPromise` are
53
+ * single-slot fields the second run overwrites while the first is still
54
+ * streaming. Managed delivery serializes them instead, on object identity, which
55
+ * head-of-line blocks two *different* conversations that share one instance.
56
+ *
57
+ * Fails loud on all three ways cloning can fail to isolate: a missing `clone()`,
58
+ * a `clone()` that hands back the same object, and a `clone()` that silently
59
+ * drops subclass state (see {@link assertCloneKeptOwnFields}).
60
+ */
61
+ export function isolateAgentInstance(prototype, threadId) {
62
+ if (typeof prototype.clone !== "function") {
63
+ throw new Error("createChannel: agent must implement clone() that returns a new instance " +
64
+ "(HttpAgent, BuiltInAgent, etc.). Every turn is isolated via clone(), " +
65
+ "including agents returned from an agent: (threadId) => ... factory.");
66
+ }
67
+ const cloned = prototype.clone();
68
+ if (cloned == null || cloned === prototype) {
69
+ throw new Error("createChannel: agent.clone() must return a distinct instance for concurrent turns");
70
+ }
71
+ assertCloneKeptOwnFields(prototype, cloned);
72
+ cloned.threadId = threadId;
73
+ // `clone()` copies `isRunning` from the source, and a source that has already
74
+ // run can be mid-run at the moment it is cloned. A fresh turn is not.
75
+ //
76
+ // Hygiene, not a fix for a dead turn: `runAgent` assigns
77
+ // `abortController = params?.abortController ?? new AbortController()` before
78
+ // each run and the run loop passes no controller, so an inherited aborted
79
+ // controller cannot reach the next request on its own. Reset it anyway so
80
+ // anything reading the signal between isolation and the run sees a live one.
81
+ // Note this deliberately discards `HttpAgent.clone()`'s propagation of the
82
+ // source's aborted state, which exists for callers that clone mid-run.
83
+ cloned.isRunning = false;
84
+ const withAbort = cloned;
85
+ if ("abortController" in withAbort) {
86
+ withAbort.abortController = new AbortController();
87
+ }
88
+ return cloned;
89
+ }
90
+ /**
91
+ * Fail loud when `clone()` silently drops subclass state.
92
+ *
93
+ * `AbstractAgent.prototype.clone()` copies a fixed field list, so a subclass
94
+ * that declares its own fields (an auth client, config, a cache) gets them back
95
+ * as `undefined` on the clone — and because the base implementation always
96
+ * exists and returns a correctly-typed instance, nothing else surfaces it. The
97
+ * agent just runs gutted.
98
+ *
99
+ * Comparing own enumerable keys catches exactly that and stays quiet for the
100
+ * agents that do override `clone()` (`HttpAgent`, `LangGraphAgent`,
101
+ * `BuiltInAgent`, `IntelligenceAgent`). Symbol-keyed and non-enumerable fields
102
+ * are not covered.
103
+ *
104
+ * Own *functions* are deliberately exempt. Assigning a method on the instance is
105
+ * how spies and instrumentation wrap an agent, and losing that wrapper leaves
106
+ * the class's prototype method intact — the clone still behaves correctly, it
107
+ * just isn't wrapped. Only dropped state leaves an agent genuinely gutted.
108
+ */
109
+ function assertCloneKeptOwnFields(prototype, cloned) {
110
+ const source = prototype;
111
+ const dropped = Object.keys(prototype).filter((key) => typeof source[key] !== "function" &&
112
+ !Object.prototype.hasOwnProperty.call(cloned, key));
113
+ if (dropped.length === 0)
114
+ return;
115
+ const name = prototype.constructor?.name ?? "the configured agent";
116
+ throw new Error(`createChannel: ${name}.clone() dropped ${dropped.join(", ")}. ` +
117
+ "Every turn runs on a clone, and AbstractAgent's clone() only copies its " +
118
+ `own fixed field list, so those fields would read as undefined. Override ` +
119
+ `clone() on ${name} to copy them (HttpAgent.clone() is the reference).`);
120
+ }
121
+ /**
122
+ * Resolve effective turn concurrency from `store.concurrency` and legacy
123
+ * `store.onLockConflict`. Prefer `concurrency` when both are set.
124
+ */
125
+ export function resolveChannelConcurrency(cfg) {
126
+ if (cfg.concurrency)
127
+ return cfg.concurrency;
128
+ if (typeof cfg.onLockConflict === "function")
129
+ return "legacy-callback";
130
+ if (cfg.onLockConflict === "drop")
131
+ return "drop";
132
+ if (cfg.onLockConflict === "force")
133
+ return "parallel";
134
+ return "parallel";
135
+ }
34
136
  /** Build the IncomingMessage object from an IncomingTurn (shared by lock-conflict callback and handler path). */
35
137
  function msgFromTurn(turn) {
36
138
  return {
@@ -39,22 +141,25 @@ function msgFromTurn(turn) {
39
141
  user: turn.user ?? { id: "" },
40
142
  ref: { id: "" },
41
143
  platform: turn.platform,
144
+ operation: turn.operation,
42
145
  eventId: turn.eventId,
43
146
  turnId: turn.turnId,
44
147
  deliveryId: turn.deliveryId,
45
148
  };
46
149
  }
150
+ /** Resolve the provider that produced an event without changing adapter identity. */
151
+ function ingressPlatform(adapter, event) {
152
+ return event.platform ?? adapter.platform;
153
+ }
47
154
  /**
48
- * Enforce V1 Intelligence Channel exclusivity: an Intelligence Channel adapter
49
- * (`intelligenceAdapter`) must be the only adapter on a Channel. Channel and direct delivery are
50
- * alternative modes on a Channel — Intelligence holds the platform creds, or
51
- * the runtime does, never both.
155
+ * Enforce managed Intelligence Channel exclusivity. Managed and direct
156
+ * delivery are alternative modes on a Channel: Intelligence holds provider
157
+ * credentials, or the runtime does, never both.
52
158
  */
53
159
  function assertExclusive(adapters) {
54
160
  if (adapters.some((a) => a.__intelligenceChannel) && adapters.length > 1) {
55
- throw new Error("intelligenceAdapter() must be the only adapter on a Channel — Channel and " +
56
- "direct delivery are alternative modes. Use intelligenceAdapter() OR " +
57
- "direct adapters (slack/discord/...), not both.");
161
+ throw new Error("The managed Intelligence adapter must be the only adapter on a Channel — " +
162
+ "managed and direct delivery are alternative modes.");
58
163
  }
59
164
  }
60
165
  /**
@@ -96,15 +201,37 @@ export function createChannel(opts) {
96
201
  let registry;
97
202
  let telemetry;
98
203
  const agentFactory = (() => {
204
+ // Applied here rather than at each call site so a developer never has to
205
+ // know the workaround exists. Idempotent, so reusing one agent instance
206
+ // across threads (or being handed an already-sanitized one) is fine.
207
+ const sanitize = opts.sanitizeAgentEvents === false
208
+ ? (agent) => agent
209
+ : sanitizeAgentEventStream;
99
210
  const a = opts.agent;
100
- if (typeof a === "function")
101
- return a;
102
- if (a)
103
- return () => a;
104
- return () => {
105
- throw new Error("createChannel: no agent configured (pass `agent` to use runAgent)");
106
- };
211
+ if (!a) {
212
+ return () => {
213
+ throw new Error("createChannel: no agent configured (pass `agent` to use runAgent)");
214
+ };
215
+ }
216
+ // Clone per turn for both shapes, so concurrent turns never share one
217
+ // mutable agent. Isolating only the singleton config is not enough: a
218
+ // factory is free to return the same object on every call. Cloning a fresh
219
+ // factory's result costs an unused instance and closes the shared case —
220
+ // see `isolateAgentInstance`.
221
+ if (typeof a === "function") {
222
+ return (threadId) => sanitize(isolateAgentInstance(a(threadId), threadId));
223
+ }
224
+ return (threadId) => sanitize(isolateAgentInstance(a, threadId));
107
225
  })();
226
+ /** Per-conversation serial turn queue (error-boundaried so one failure cannot poison the chain). */
227
+ const conversationTurnQueues = new Map();
228
+ function enqueueConversationTurn(conversationKey, work) {
229
+ const previous = conversationTurnQueues.get(conversationKey) ?? Promise.resolve();
230
+ const run = previous.then(work, work);
231
+ // Keep the map tail settled so a rejected turn does not block later ones forever.
232
+ conversationTurnQueues.set(conversationKey, run.then(() => undefined, () => undefined));
233
+ return run;
234
+ }
108
235
  const toolMap = new Map();
109
236
  for (const t of opts.tools ?? [])
110
237
  toolMap.set(t.name, t);
@@ -129,6 +256,7 @@ export function createChannel(opts) {
129
256
  }
130
257
  const deps = {
131
258
  adapter,
259
+ platform: extras?.platform,
132
260
  replyTarget,
133
261
  conversationKey,
134
262
  registry,
@@ -161,83 +289,114 @@ export function createChannel(opts) {
161
289
  // backend/registry are resolved in start() before any adapter.start() runs,
162
290
  // so they are always set by the time the sink receives an event.
163
291
  const store = backend;
164
- return {
165
- async onTurn(turn) {
166
- const lockKey = `turn:${turn.conversationKey}`;
167
- const acquired = await store.lock.acquire(lockKey, {
168
- ttlMs: cfg.lockTtl ?? 60_000,
169
- });
170
- if (!acquired) {
171
- const decision = typeof cfg.onLockConflict === "function"
172
- ? await cfg.onLockConflict(turn.conversationKey, msgFromTurn(turn))
173
- : (cfg.onLockConflict ?? "drop");
174
- if (decision === "drop")
175
- return; // discard overlapping turn
176
- // "force": proceed WITHOUT a lock token. Does NOT cancel the
177
- // in-flight handler — cooperative cancellation is a future extension.
292
+ /**
293
+ * Core turn body (dedup → identity → handlers). Used by all concurrency modes.
294
+ * Dedup marks the event seen at the start so a Slack redelivery of an
295
+ * in-flight event does not double-run under parallel mode either.
296
+ */
297
+ async function processTurn(turn) {
298
+ const platform = ingressPlatform(adapter, turn);
299
+ if (!adapter.skipIngressDedup) {
300
+ const dupKey = [
301
+ "message",
302
+ platform,
303
+ turn.operation.kind,
304
+ turn.operation.logicalMessageId,
305
+ turn.operation.revisionId,
306
+ ].join(":");
307
+ try {
308
+ if (await store.dedup.seen(dupKey, cfg.dedupTtl ?? 300_000))
309
+ return;
310
+ }
311
+ catch (err) {
312
+ console.warn(`[channel] dedup check failed for ${platform}; processing without dedup`, err);
178
313
  }
314
+ }
315
+ // Resolve cross-platform identity key (if configured) and stamp it on
316
+ // the message so handlers and transcript storage can use it. Done
317
+ // BEFORE makeThread so the thread carries the userKey + message for
318
+ // the transcript auto-bridge (runAgent({ transcript: true })).
319
+ let userKey;
320
+ if (cfg.identity) {
179
321
  try {
180
- // Dedup AFTER acquiring the lock: a turn dropped on lock-conflict must NOT burn its
181
- // eventId, so Slack's retry can still be processed once the lock frees. (A handler
182
- // that throws still leaves its event marked seen — dedup drops duplicate DELIVERIES,
183
- // it is not retry-of-failed-turns.)
184
- if (turn.eventId && !adapter.skipIngressDedup) {
185
- const dupKey = `evt:${adapter.platform}:${turn.eventId}`;
186
- try {
187
- if (await store.dedup.seen(dupKey, cfg.dedupTtl ?? 300_000))
188
- return;
189
- }
190
- catch (err) {
191
- console.warn(`[channel] dedup check failed for ${adapter.platform}; processing without dedup`, err);
192
- }
193
- }
194
- // Resolve cross-platform identity key (if configured) and stamp it on
195
- // the message so handlers and transcript storage can use it. Done
196
- // BEFORE makeThread so the thread carries the userKey + message for
197
- // the transcript auto-bridge (runAgent({ transcript: true })).
198
- let userKey;
199
- if (cfg.identity) {
200
- try {
201
- const resolved = await cfg.identity({
202
- adapter: adapter.platform,
203
- author: turn.user ?? { id: "" },
204
- message: msgFromTurn(turn),
205
- });
206
- userKey = resolved ?? undefined;
207
- }
208
- catch (err) {
209
- console.warn(`[channel] identity resolution failed for ${adapter.platform}; continuing without userKey`, err);
210
- }
211
- }
212
- const message = { ...msgFromTurn(turn), userKey };
213
- const thread = makeThread(adapter, turn.replyTarget, turn.conversationKey, { userKey, message });
214
- // v1 routing: there is no turn `kind`, so prefer mention handlers; if
215
- // none are registered, fall back to message handlers. (The reference
216
- // example registers identical handlers on both, so this avoids
217
- // double-firing while still invoking whatever is registered.)
218
- const handlers = mentionHandlers.length > 0 ? mentionHandlers : messageHandlers;
219
- for (const h of handlers)
220
- await h({ thread, message });
322
+ const resolved = await cfg.identity({
323
+ adapter: platform,
324
+ author: turn.user ?? { id: "" },
325
+ message: msgFromTurn(turn),
326
+ });
327
+ userKey = resolved ?? undefined;
221
328
  }
222
- finally {
223
- // acquired is null on "force" naturally skips release.
224
- if (acquired)
225
- await store.lock.release(lockKey, acquired.token);
329
+ catch (err) {
330
+ console.warn(`[channel] identity resolution failed for ${platform}; continuing without userKey`, err);
226
331
  }
332
+ }
333
+ const message = { ...msgFromTurn(turn), userKey };
334
+ const thread = makeThread(adapter, turn.replyTarget, turn.conversationKey, { platform, userKey, message });
335
+ const handlers = turn.operation.mentioned
336
+ ? mentionHandlers.length > 0
337
+ ? mentionHandlers
338
+ : messageHandlers
339
+ : messageHandlers;
340
+ for (const h of handlers)
341
+ await h({ thread, message });
342
+ }
343
+ /**
344
+ * Exclusive-lock path for `drop` and legacy `onLockConflict` callback.
345
+ * A turn dropped on lock-conflict must NOT burn its eventId, so Slack's
346
+ * retry can still be processed once the lock frees — hence dedup lives
347
+ * inside `processTurn` only after we hold the lock (or force through).
348
+ */
349
+ async function processTurnWithLock(turn) {
350
+ const lockKey = `turn:${turn.conversationKey}`;
351
+ const acquired = await store.lock.acquire(lockKey, {
352
+ ttlMs: cfg.lockTtl ?? 60_000,
353
+ });
354
+ if (!acquired) {
355
+ const decision = typeof cfg.onLockConflict === "function"
356
+ ? await cfg.onLockConflict(turn.conversationKey, msgFromTurn(turn))
357
+ : (cfg.onLockConflict ?? "drop");
358
+ if (decision === "drop")
359
+ return; // discard overlapping turn
360
+ // "force": proceed WITHOUT a lock token. Does NOT cancel the
361
+ // in-flight handler — cooperative cancellation is a future extension.
362
+ }
363
+ try {
364
+ await processTurn(turn);
365
+ }
366
+ finally {
367
+ // acquired is null on "force" — naturally skips release.
368
+ if (acquired)
369
+ await store.lock.release(lockKey, acquired.token);
370
+ }
371
+ }
372
+ return {
373
+ async onTurn(turn) {
374
+ const mode = resolveChannelConcurrency(cfg);
375
+ if (mode === "parallel") {
376
+ await processTurn(turn);
377
+ return;
378
+ }
379
+ if (mode === "serial") {
380
+ await enqueueConversationTurn(turn.conversationKey, () => processTurn(turn));
381
+ return;
382
+ }
383
+ // "drop" or legacy callback — exclusive lock + drop/force.
384
+ await processTurnWithLock(turn);
227
385
  },
228
386
  async onInteraction(evt) {
387
+ const platform = ingressPlatform(adapter, evt);
229
388
  // Dedup guard: drop duplicate deliveries of the same event within the TTL window.
230
389
  if (evt.eventId && !adapter.skipIngressDedup) {
231
- const dupKey = `evt:${adapter.platform}:${evt.eventId}`;
390
+ const dupKey = `evt:${platform}:${evt.eventId}`;
232
391
  try {
233
392
  if (await store.dedup.seen(dupKey, cfg.dedupTtl ?? 300_000))
234
393
  return;
235
394
  }
236
395
  catch (err) {
237
- console.warn(`[channel] dedup check failed for ${adapter.platform}; processing without dedup`, err);
396
+ console.warn(`[channel] dedup check failed for ${platform}; processing without dedup`, err);
238
397
  }
239
398
  }
240
- const thread = makeThread(adapter, evt.replyTarget, evt.conversationKey);
399
+ const thread = makeThread(adapter, evt.replyTarget, evt.conversationKey, { platform });
241
400
  const user = evt.user ?? { id: "" };
242
401
  const ctx = {
243
402
  thread,
@@ -245,12 +404,12 @@ export function createChannel(opts) {
245
404
  text: "",
246
405
  user,
247
406
  ref: evt.messageRef ?? { id: "" },
248
- platform: adapter.platform,
407
+ platform,
249
408
  },
250
409
  action: { id: evt.id, value: evt.value },
251
410
  values: {},
252
411
  user,
253
- platform: adapter.platform,
412
+ platform,
254
413
  };
255
414
  const openModal = makeOpenModal(adapter, evt.replyTarget, evt.triggerId);
256
415
  if (openModal)
@@ -284,21 +443,22 @@ export function createChannel(opts) {
284
443
  }
285
444
  },
286
445
  async onCommand(cmd) {
446
+ const platform = ingressPlatform(adapter, cmd);
287
447
  // Dedup guard: drop duplicate deliveries of the same event within the TTL window.
288
448
  if (cmd.eventId && !adapter.skipIngressDedup) {
289
- const dupKey = `evt:${adapter.platform}:${cmd.eventId}`;
449
+ const dupKey = `evt:${platform}:${cmd.eventId}`;
290
450
  try {
291
451
  if (await store.dedup.seen(dupKey, cfg.dedupTtl ?? 300_000))
292
452
  return;
293
453
  }
294
454
  catch (err) {
295
- console.warn(`[channel] dedup check failed for ${adapter.platform}; processing without dedup`, err);
455
+ console.warn(`[channel] dedup check failed for ${platform}; processing without dedup`, err);
296
456
  }
297
457
  }
298
458
  const command = commandHandlers.get(normalizeCommandName(cmd.command));
299
459
  if (!command)
300
460
  return; // unregistered command → skip
301
- const thread = makeThread(adapter, cmd.replyTarget, cmd.conversationKey);
461
+ const thread = makeThread(adapter, cmd.replyTarget, cmd.conversationKey, { platform });
302
462
  // Resolve typed options from any structured args the surface supplied
303
463
  // (e.g. Discord); text-only surfaces (Slack) leave `options` empty and
304
464
  // the handler reads `text`.
@@ -314,7 +474,7 @@ export function createChannel(opts) {
314
474
  text: cmd.text,
315
475
  options,
316
476
  user: cmd.user,
317
- platform: cmd.platform,
477
+ platform,
318
478
  };
319
479
  const openModal = makeOpenModal(adapter, cmd.replyTarget, cmd.triggerId);
320
480
  if (openModal)
@@ -325,23 +485,19 @@ export function createChannel(opts) {
325
485
  // The adapter has already applied its static defaults (greeting /
326
486
  // prompts) before emitting this, so handlers layer on top and never
327
487
  // race. Zero handlers → no-op.
328
- const thread = makeThread(adapter, evt.replyTarget, evt.conversationKey);
488
+ const thread = makeThread(adapter, evt.replyTarget, evt.conversationKey, { platform: ingressPlatform(adapter, evt) });
329
489
  for (const h of threadStartedHandlers)
330
490
  await h({ thread, user: evt.user });
331
491
  },
332
492
  async onReaction(evt) {
333
- // Normalize by the reaction's SOURCE platform: direct adapters omit
334
- // `evt.platform`, so it falls back to `adapter.platform`; the managed
335
- // path (adapter.platform === "intelligence") sets `evt.platform` to the
336
- // originating provider (e.g. "teams"/"slack") so central normalization
337
- // still runs. Only normalize when that platform is one the emoji table
338
- // knows; otherwise the raw token passes through unchanged.
339
- const sourcePlatform = evt.platform ?? adapter.platform;
493
+ // Normalize by source platform, falling back to adapter identity for
494
+ // direct adapters that do not need per-event provider routing.
495
+ const sourcePlatform = ingressPlatform(adapter, evt);
340
496
  const normalized = isEmojiPlatform(sourcePlatform)
341
497
  ? normalizeEmoji(evt.rawEmoji, sourcePlatform)
342
498
  : undefined;
343
499
  const value = normalized ?? evt.rawEmoji;
344
- const thread = makeThread(adapter, evt.replyTarget, evt.conversationKey);
500
+ const thread = makeThread(adapter, evt.replyTarget, evt.conversationKey, { platform: sourcePlatform });
345
501
  // Prefer the adapter's update-capable ref; fall back to the bare id.
346
502
  const messageRef = evt.messageRef ?? { id: evt.messageId };
347
503
  const reactionEvt = {
@@ -383,7 +539,9 @@ export function createChannel(opts) {
383
539
  if (!handler)
384
540
  return; // unregistered → closes
385
541
  const thread = evt.conversationKey !== undefined && evt.replyTarget !== undefined
386
- ? makeThread(adapter, evt.replyTarget, evt.conversationKey)
542
+ ? makeThread(adapter, evt.replyTarget, evt.conversationKey, {
543
+ platform: evt.platform,
544
+ })
387
545
  : undefined;
388
546
  const result = await handler({
389
547
  callbackId: evt.callbackId,
@@ -414,6 +572,9 @@ export function createChannel(opts) {
414
572
  ...(opts.showToolStatus !== undefined
415
573
  ? { showToolStatus: opts.showToolStatus }
416
574
  : {}),
575
+ ...(opts.replyContinuation !== undefined
576
+ ? { replyContinuation: opts.replyContinuation }
577
+ : {}),
417
578
  get adapters() {
418
579
  // Defensive read-only copy: mutating the returned array must not affect
419
580
  // the Channel's private adapter list.
@@ -443,6 +604,11 @@ export function createChannel(opts) {
443
604
  // and real adapters would connect/port-bind twice.
444
605
  if (started)
445
606
  return;
607
+ if (adapters.some((adapter) => adapter.capabilities.supportsMessageEvents) &&
608
+ mentionHandlers.length === 0 &&
609
+ messageHandlers.length === 0) {
610
+ throw new Error(`channel "${opts.name ?? "(unnamed)"}" must register onMention or onMessage before activation`);
611
+ }
446
612
  started = true;
447
613
  assertExclusive(adapters);
448
614
  // Resolve persistence now that all adapters (including any attached via