@copilotkit/channels-core 0.2.1 → 0.3.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.
package/README.md CHANGED
@@ -4,6 +4,11 @@ The supported platform-neutral foundation behind `@copilotkit/channels`.
4
4
  Most applications should use the batteries-included `@copilotkit/channels` package;
5
5
  install core directly when building an adapter or intentionally selecting one platform.
6
6
 
7
+ **Every Channel requires a CopilotKit Intelligence connection** (an API key — a
8
+ free tier is available). There is no standalone / DIY run path: a Channel is
9
+ started and owned by the `CopilotRuntime` once Intelligence is configured, not
10
+ by calling a method on the Channel itself. See "Running a Channel" below.
11
+
7
12
  ## Selective install
8
13
 
9
14
  ```sh
@@ -45,12 +50,50 @@ import { slack } from "@copilotkit/channels-slack";
45
50
  (e.g. Discord). Forwarded to adapters that support commands and ignored
46
51
  elsewhere — also pass them up front via `commands` in `CreateChannelOptions`.
47
52
  - `tool(t)` — register a `ChannelTool` (alternative to `opts.tools`); must be
48
- added before `start()`.
49
- - `start()` / `stop()` — bring adapters up / down.
53
+ added before the runtime activates the channel.
50
54
 
51
55
  `agent` is optional. If omitted, calling `thread.runAgent()` throws; supply
52
56
  an `AbstractAgent` or a `(threadId) => AbstractAgent` factory.
53
57
 
58
+ A `Channel` has no public `start()` / `stop()` — lifecycle is runtime-owned
59
+ (see below).
60
+
61
+ ## Running a Channel
62
+
63
+ A Channel only runs when it's declared on an Intelligence-configured
64
+ `CopilotRuntime`; there is no `channel.start()` and no standalone/DIY runner.
65
+ Pass the `Channel` in `channels`, then drive activation through the returned
66
+ handler:
67
+
68
+ ```ts
69
+ import { createChannel } from "@copilotkit/channels-core";
70
+ import { slack } from "@copilotkit/channels-slack";
71
+ import {
72
+ CopilotRuntime,
73
+ CopilotKitIntelligence,
74
+ createCopilotRuntimeHandler,
75
+ } from "@copilotkit/runtime/v2";
76
+
77
+ const channel = createChannel({
78
+ name: "support-bot", // project-unique Intelligence Channel name
79
+ adapters: [slack({ botToken, appToken })],
80
+ });
81
+
82
+ const runtime = new CopilotRuntime({
83
+ intelligence: new CopilotKitIntelligence({
84
+ apiUrl: "https://api.copilotkit.ai",
85
+ wsUrl: "wss://api.copilotkit.ai",
86
+ apiKey: process.env.COPILOTKIT_INTELLIGENCE_API_KEY!, // free tier available
87
+ }),
88
+ identifyUser: async () => ({ id: "support-bot", name: "Support Bot" }),
89
+ channels: [channel],
90
+ });
91
+
92
+ const handler = createCopilotRuntimeHandler({ runtime });
93
+ await handler.channels.ready(); // starts every declared channel
94
+ // await handler.channels.stop(); // tears them down
95
+ ```
96
+
54
97
  ## `Thread`
55
98
 
56
99
  A `Thread` is the per-conversation handle handed to your handlers and tool
@@ -26,9 +26,10 @@ export type LockConflictDecision = "drop" | "force";
26
26
  * (Intelligence OSS-450 / #511).
27
27
  *
28
28
  * Distinct from a {@link PlatformAdapter} attached via
29
- * `createChannel({ adapters })` / {@link Channel.addAdapter}: an adapter is a
30
- * *direct*, developer-owned connection this handler does not manage, whereas
31
- * `provider` selects the *managed* platform for a Channel with no adapters.
29
+ * `createChannel({ adapters })` / `channel.ɵruntime.addAdapter`: an adapter is
30
+ * a *direct*, developer-owned connection this handler does not manage,
31
+ * whereas `provider` selects the *managed* platform for a Channel with no
32
+ * adapters.
32
33
  */
33
34
  export type ManagedChannelProvider = "slack" | "teams";
34
35
  /**
@@ -124,7 +125,8 @@ export interface CreateChannelOptions<TStateSchema extends StandardSchemaV1 | un
124
125
  name?: string;
125
126
  /**
126
127
  * Adapters supplied at construction. Optional — adapters can also be attached
127
- * before `start()` via {@link Channel.addAdapter} (the Channel runtime uses this).
128
+ * before the runner starts the channel, via `channel.ɵruntime.addAdapter`
129
+ * (the Channel runtime uses this).
128
130
  */
129
131
  adapters?: PlatformAdapter[];
130
132
  /**
@@ -139,8 +141,8 @@ export interface CreateChannelOptions<TStateSchema extends StandardSchemaV1 | un
139
141
  * {@link ManagedChannelProvider}.
140
142
  *
141
143
  * Ignored for direct-adapter Channels (those created with `adapters` /
142
- * {@link Channel.addAdapter}) — a direct Channel is owned by the developer's
143
- * own adapter, not by managed activation.
144
+ * `channel.ɵruntime.addAdapter`) — a direct Channel is owned by the
145
+ * developer's own adapter, not by managed activation.
144
146
  */
145
147
  provider?: ManagedChannelProvider;
146
148
  agent?: AbstractAgent | ((threadId: string) => AbstractAgent);
@@ -205,12 +207,20 @@ export interface Channel<TState = unknown> {
205
207
  /** Handle a modal dismissal for `callbackId` (Slack `view_closed`). */
206
208
  onModalClose(callbackId: string, handler: ModalCloseHandler): void;
207
209
  tool(t: ChannelTool): void;
208
- /** Attach an adapter before `start()`. Throws if called after the channel has started. */
209
- addAdapter(adapter: PlatformAdapter): void;
210
- start(): Promise<void>;
211
- stop(): Promise<void>;
212
210
  /** Cross-platform transcript store. Append, list, and delete entries per user. */
213
211
  transcripts: Transcripts;
212
+ /**
213
+ * Internal lifecycle seam. Holds the `start`/`stop`/`addAdapter`
214
+ * implementations that the runtime uses to drive the lifecycle directly —
215
+ * there is no public equivalent; channels are runtime-driven only. (Read the
216
+ * managed provider off the top-level `channel.provider`, not here.)
217
+ * @internal
218
+ */
219
+ ɵruntime: {
220
+ start(): Promise<void>;
221
+ stop(): Promise<void>;
222
+ addAdapter(adapter: PlatformAdapter): void;
223
+ };
214
224
  }
215
225
  export declare function createChannel<TStateSchema extends StandardSchemaV1 | undefined = undefined>(opts: CreateChannelOptions<TStateSchema>): Channel<ThreadStateOf<TStateSchema>>;
216
226
  export {};
@@ -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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"}
@@ -8,8 +8,8 @@ describe("createChannel — optional adapters + addAdapter", () => {
8
8
  it("starts with no adapters and runs one added before start()", async () => {
9
9
  const fake = new FakeAdapter();
10
10
  const channel = createChannel({ agent: () => new FakeAgent() });
11
- channel.addAdapter(fake);
12
- await channel.start();
11
+ channel.ɵruntime.addAdapter(fake);
12
+ await channel.ɵruntime.start();
13
13
  expect(fake.started).toBe(true);
14
14
  });
15
15
  it("throws when addAdapter is called after start()", async () => {
@@ -17,8 +17,8 @@ describe("createChannel — optional adapters + addAdapter", () => {
17
17
  adapters: [new FakeAdapter()],
18
18
  agent: () => new FakeAgent(),
19
19
  });
20
- await channel.start();
21
- expect(() => channel.addAdapter(new FakeAdapter())).toThrow(/start/i);
20
+ await channel.ɵruntime.start();
21
+ expect(() => channel.ɵruntime.addAdapter(new FakeAdapter())).toThrow(/start/i);
22
22
  });
23
23
  it("is idempotent: a second start() does not re-start adapters or rebuild state", async () => {
24
24
  const fake = new FakeAdapter();
@@ -27,9 +27,9 @@ describe("createChannel — optional adapters + addAdapter", () => {
27
27
  agent: () => new FakeAgent(),
28
28
  });
29
29
  const startSpy = vi.spyOn(fake, "start");
30
- await channel.start();
30
+ await channel.ɵruntime.start();
31
31
  const transcriptsAfterFirst = channel.transcripts;
32
- await channel.start(); // second call must be a no-op
32
+ await channel.ɵruntime.start(); // second call must be a no-op
33
33
  expect(startSpy).toHaveBeenCalledTimes(1);
34
34
  // Same transcript-store instance → state (locks/dedup/actions) not wiped.
35
35
  expect(channel.transcripts).toBe(transcriptsAfterFirst);
@@ -41,9 +41,9 @@ describe("createChannel — optional adapters + addAdapter", () => {
41
41
  agent: () => new FakeAgent(),
42
42
  });
43
43
  const startSpy = vi.spyOn(fake, "start");
44
- await channel.start();
45
- await channel.stop();
46
- await channel.start(); // stop() cleared `started`, so this is a real restart
44
+ await channel.ɵruntime.start();
45
+ await channel.ɵruntime.stop();
46
+ await channel.ɵruntime.start(); // stop() cleared `started`, so this is a real restart
47
47
  expect(startSpy).toHaveBeenCalledTimes(2);
48
48
  });
49
49
  });
@@ -75,7 +75,7 @@ describe("createChannel — store resolution", () => {
75
75
  transcripts: {},
76
76
  },
77
77
  });
78
- await seeder.start();
78
+ await seeder.ɵruntime.start();
79
79
  await seeder.transcripts.append({ platform: "fake", conversationKey: "c" }, { role: "user", text: "seeded" }, { userKey: "u@x.com" });
80
80
  const fake = new FakeAdapter();
81
81
  fake.stateStore = adapterStore;
@@ -84,7 +84,7 @@ describe("createChannel — store resolution", () => {
84
84
  agent: () => new FakeAgent(),
85
85
  store: { identity: () => "u@x.com", transcripts: {} },
86
86
  });
87
- await channel.start();
87
+ await channel.ɵruntime.start();
88
88
  const entries = await channel.transcripts.list({ userKey: "u@x.com" });
89
89
  expect(entries.map((e) => e.text)).toContain("seeded");
90
90
  });
@@ -102,7 +102,7 @@ describe("createChannel — store resolution", () => {
102
102
  transcripts: {},
103
103
  },
104
104
  });
105
- await channel.start();
105
+ await channel.ɵruntime.start();
106
106
  expect(warn).not.toHaveBeenCalled();
107
107
  warn.mockRestore();
108
108
  });
@@ -116,7 +116,7 @@ describe("createChannel — store resolution", () => {
116
116
  adapters: [a, b],
117
117
  agent: () => new FakeAgent(),
118
118
  });
119
- await channel.start();
119
+ await channel.ɵruntime.start();
120
120
  expect(warn).toHaveBeenCalledWith(expect.stringContaining("state store"));
121
121
  warn.mockRestore();
122
122
  });
@@ -136,7 +136,7 @@ describe("createChannel — id propagation to handler context", () => {
136
136
  eventId: message.eventId,
137
137
  };
138
138
  });
139
- await channel.start();
139
+ await channel.ɵruntime.start();
140
140
  fake.emitTurn({
141
141
  userText: "hi",
142
142
  conversationKey: "c1",
@@ -79,16 +79,18 @@ export function createChannel(opts) {
79
79
  (!cfg.identity && cfg.transcripts)) {
80
80
  throw new Error("createChannel: `identity` and `transcripts` must be configured together.");
81
81
  }
82
- // Adapters can be supplied up front or added later via `channel.addAdapter`
83
- // (before `start()`). The runtime uses the latter to attach Channel delivery.
82
+ // Adapters can be supplied up front or added later via
83
+ // `channel.ɵruntime.addAdapter` (before `channel.ɵruntime.start()`). The
84
+ // runtime uses the latter to attach Channel delivery.
84
85
  const adapters = [...(opts.adapters ?? [])];
85
86
  assertExclusive(adapters);
86
87
  let started = false;
87
88
  // Backend, transcripts, telemetry, the action registry, and component
88
- // registration are resolved in `start()` — not at construction — so an
89
- // adapter added via `addAdapter` after `createChannel` can still supply the
90
- // persistence backend (see `resolveBackend`). Nothing reads these before the
91
- // first event, which can only arrive after `start()`.
89
+ // registration are resolved in `ɵruntime.start()` — not at construction —
90
+ // so an adapter added via `ɵruntime.addAdapter` after `createChannel` can
91
+ // still supply the persistence backend (see `resolveBackend`). Nothing
92
+ // reads these before the first event, which can only arrive after
93
+ // `ɵruntime.start()`.
92
94
  let backend;
93
95
  let transcripts;
94
96
  let registry;
@@ -123,7 +125,7 @@ export function createChannel(opts) {
123
125
  let toolDescriptors = toAgentToolDescriptors([...toolMap.values()]);
124
126
  function makeThread(adapter, replyTarget, conversationKey, extras) {
125
127
  if (!backend || !registry || !telemetry) {
126
- throw new Error("channel not started: call channel.start() before handling events");
128
+ throw new Error("channel not started: the runner must start the channel (channel.ɵruntime.start()) before handling events");
127
129
  }
128
130
  const deps = {
129
131
  adapter,
@@ -419,16 +421,133 @@ export function createChannel(opts) {
419
421
  },
420
422
  get transcripts() {
421
423
  if (!transcripts) {
422
- throw new Error("channel.transcripts is available after channel.start()");
424
+ throw new Error("channel.transcripts is available after the runner starts the channel (channel.ɵruntime.start())");
423
425
  }
424
426
  return transcripts;
425
427
  },
426
- addAdapter(adapter) {
427
- if (started) {
428
- throw new Error("channel.addAdapter must be called before channel.start()");
429
- }
430
- assertExclusive([...adapters, adapter]);
431
- adapters.push(adapter);
428
+ ɵruntime: {
429
+ addAdapter(adapter) {
430
+ if (started) {
431
+ throw new Error("channel.ɵruntime.addAdapter must be called before channel.ɵruntime.start()");
432
+ }
433
+ assertExclusive([...adapters, adapter]);
434
+ adapters.push(adapter);
435
+ },
436
+ async start() {
437
+ // Idempotent: a second start() must not re-resolve the backend and
438
+ // rebuild Transcripts/Telemetry/ActionRegistry or re-call adapter.start()
439
+ // — with a MemoryStore that wipes all lock/dedup/transcript/action state,
440
+ // and real adapters would connect/port-bind twice.
441
+ if (started)
442
+ return;
443
+ started = true;
444
+ assertExclusive(adapters);
445
+ // Resolve persistence now that all adapters (including any attached via
446
+ // addAdapter) are known, then build the transcript store, action
447
+ // registry, and register components against it.
448
+ backend = resolveBackend(cfg.adapter, adapters);
449
+ transcripts = new Transcripts(backend, cfg.transcripts ?? {});
450
+ const tel = new ChannelTelemetry({
451
+ backend,
452
+ packageName: pkg.name,
453
+ packageVersion: pkg.version,
454
+ });
455
+ telemetry = tel;
456
+ const registryInstance = new ActionRegistry({
457
+ store: opts.actionStore ?? kvActionStore(backend),
458
+ });
459
+ registry = registryInstance;
460
+ for (const c of opts.components ?? []) {
461
+ if (!c.name) {
462
+ console.warn("[channel] createChannel: skipping anonymous component — give it a name to enable durable actions after restart.");
463
+ continue;
464
+ }
465
+ registryInstance.registerComponent(c.name, c);
466
+ }
467
+ toolDescriptors = toAgentToolDescriptors([...toolMap.values()]);
468
+ tel.capture("oss.channel.configured", {
469
+ platforms: adapters.map((a) => normalizePlatform(a.platform)),
470
+ adapterCount: adapters.length,
471
+ store: storeKind(backend),
472
+ hasComponents: (opts.components?.length ?? 0) > 0,
473
+ componentsCount: opts.components?.length ?? 0,
474
+ toolsCount: toolMap.size,
475
+ commandsCount: commandHandlers.size,
476
+ contextCount: context.length,
477
+ transcripts: !!cfg.transcripts,
478
+ identity: !!cfg.identity,
479
+ });
480
+ // Isolate per-adapter startup failures: one adapter rejecting (e.g.
481
+ // Telegram's setMyCommands rejecting a hyphenated command name, a revoked
482
+ // token, a port already in use) must NOT crash the channel or prevent the
483
+ // other adapters from starting. Log + degrade, never throw.
484
+ const startResults = await Promise.allSettled(adapters.map((a) => a.start(makeSink(a), { channelName: opts.name })));
485
+ const startedPlatforms = [];
486
+ const failedPlatforms = [];
487
+ startResults.forEach((r, i) => {
488
+ const rawPlatform = adapters[i].platform;
489
+ // Raw label for the human-facing log; normalized label for telemetry.
490
+ const platform = normalizePlatform(rawPlatform);
491
+ if (r.status === "rejected") {
492
+ failedPlatforms.push(platform);
493
+ console.error(`[channel] adapter "${rawPlatform}" failed to start:`, r.reason);
494
+ tel.capture("oss.channel.start_failed", {
495
+ platform,
496
+ errorClass: errorClass(r.reason),
497
+ });
498
+ }
499
+ else {
500
+ startedPlatforms.push(platform);
501
+ }
502
+ });
503
+ if (startedPlatforms.length > 0) {
504
+ tel.capture("oss.channel.started", {
505
+ platforms: startedPlatforms,
506
+ startedCount: startedPlatforms.length,
507
+ failedCount: failedPlatforms.length,
508
+ hasMentionHandler: mentionHandlers.length > 0,
509
+ hasMessageHandler: messageHandlers.length > 0,
510
+ interruptHandlers: interruptHandlers.size,
511
+ commandsCount: commandHandlers.size,
512
+ toolsCount: toolMap.size,
513
+ });
514
+ }
515
+ // A channel that has adapters but where NONE started is dead — surface an
516
+ // error so the runtime reports status "error", not a false "online". A
517
+ // PARTIAL start (>=1 adapter live) still counts as started. Reset the
518
+ // `started` guard so a caller can retry after fixing the misconfiguration.
519
+ if (adapters.length > 0 && startedPlatforms.length === 0) {
520
+ started = false;
521
+ throw new Error(`channel "${opts.name ?? "(unnamed)"}" failed to start: all ${failedPlatforms.length} adapter(s) failed to connect (${failedPlatforms.join(", ")}) — see the logged errors above`);
522
+ }
523
+ // Hand declared commands to adapters that register them up front (e.g.
524
+ // Discord); adapters without `registerCommands` are skipped. Per-adapter
525
+ // failures are isolated the same way as start().
526
+ const commandSpecs = [...commandHandlers.values()].map(toCommandSpec);
527
+ if (commandSpecs.length > 0) {
528
+ const registerResults = await Promise.allSettled(adapters.map((a) => a.registerCommands?.(commandSpecs)));
529
+ registerResults.forEach((r, i) => {
530
+ if (r.status === "rejected") {
531
+ console.error(`[channel] adapter "${adapters[i].platform}" failed to register commands:`, r.reason);
532
+ }
533
+ });
534
+ }
535
+ },
536
+ async stop() {
537
+ // Clear the started flag so a later start() is a real restart (re-resolve
538
+ // backend, rebuild components, reconnect adapters) rather than a silent
539
+ // no-op. The idempotency guard in start() only exists to block a DOUBLE
540
+ // start() while running — not a legitimate start→stop→start cycle.
541
+ started = false;
542
+ // Isolate per-adapter shutdown failures: one adapter's stop() rejecting
543
+ // must not prevent the others from being stopped.
544
+ const stopResults = await Promise.allSettled(adapters.map((a) => a.stop()));
545
+ stopResults.forEach((r, i) => {
546
+ if (r.status === "rejected") {
547
+ console.error(`[channel] adapter "${adapters[i].platform}" failed to stop:`, r.reason);
548
+ }
549
+ });
550
+ },
432
551
  },
433
552
  onMention(h) {
434
553
  // The public surface narrows `thread` to StatefulThread<TState>; the
@@ -483,113 +602,6 @@ export function createChannel(opts) {
483
602
  tool(t) {
484
603
  toolMap.set(t.name, t);
485
604
  },
486
- async start() {
487
- // Idempotent: a second start() must not re-resolve the backend and
488
- // rebuild Transcripts/Telemetry/ActionRegistry or re-call adapter.start()
489
- // — with a MemoryStore that wipes all lock/dedup/transcript/action state,
490
- // and real adapters would connect/port-bind twice.
491
- if (started)
492
- return;
493
- started = true;
494
- assertExclusive(adapters);
495
- // Resolve persistence now that all adapters (including any attached via
496
- // addAdapter) are known, then build the transcript store, action
497
- // registry, and register components against it.
498
- backend = resolveBackend(cfg.adapter, adapters);
499
- transcripts = new Transcripts(backend, cfg.transcripts ?? {});
500
- const tel = new ChannelTelemetry({
501
- backend,
502
- packageName: pkg.name,
503
- packageVersion: pkg.version,
504
- });
505
- telemetry = tel;
506
- const registryInstance = new ActionRegistry({
507
- store: opts.actionStore ?? kvActionStore(backend),
508
- });
509
- registry = registryInstance;
510
- for (const c of opts.components ?? []) {
511
- if (!c.name) {
512
- console.warn("[channel] createChannel: skipping anonymous component — give it a name to enable durable actions after restart.");
513
- continue;
514
- }
515
- registryInstance.registerComponent(c.name, c);
516
- }
517
- toolDescriptors = toAgentToolDescriptors([...toolMap.values()]);
518
- tel.capture("oss.channel.configured", {
519
- platforms: adapters.map((a) => normalizePlatform(a.platform)),
520
- adapterCount: adapters.length,
521
- store: storeKind(backend),
522
- hasComponents: (opts.components?.length ?? 0) > 0,
523
- componentsCount: opts.components?.length ?? 0,
524
- toolsCount: toolMap.size,
525
- commandsCount: commandHandlers.size,
526
- contextCount: context.length,
527
- transcripts: !!cfg.transcripts,
528
- identity: !!cfg.identity,
529
- });
530
- // Isolate per-adapter startup failures: one adapter rejecting (e.g.
531
- // Telegram's setMyCommands rejecting a hyphenated command name, a revoked
532
- // token, a port already in use) must NOT crash the channel or prevent the
533
- // other adapters from starting. Log + degrade, never throw.
534
- const startResults = await Promise.allSettled(adapters.map((a) => a.start(makeSink(a), { channelName: opts.name })));
535
- const startedPlatforms = [];
536
- const failedPlatforms = [];
537
- startResults.forEach((r, i) => {
538
- const rawPlatform = adapters[i].platform;
539
- // Raw label for the human-facing log; normalized label for telemetry.
540
- const platform = normalizePlatform(rawPlatform);
541
- if (r.status === "rejected") {
542
- failedPlatforms.push(platform);
543
- console.error(`[channel] adapter "${rawPlatform}" failed to start:`, r.reason);
544
- tel.capture("oss.channel.start_failed", {
545
- platform,
546
- errorClass: errorClass(r.reason),
547
- });
548
- }
549
- else {
550
- startedPlatforms.push(platform);
551
- }
552
- });
553
- if (startedPlatforms.length > 0) {
554
- tel.capture("oss.channel.started", {
555
- platforms: startedPlatforms,
556
- startedCount: startedPlatforms.length,
557
- failedCount: failedPlatforms.length,
558
- hasMentionHandler: mentionHandlers.length > 0,
559
- hasMessageHandler: messageHandlers.length > 0,
560
- interruptHandlers: interruptHandlers.size,
561
- commandsCount: commandHandlers.size,
562
- toolsCount: toolMap.size,
563
- });
564
- }
565
- // Hand declared commands to adapters that register them up front (e.g.
566
- // Discord); adapters without `registerCommands` are skipped. Per-adapter
567
- // failures are isolated the same way as start().
568
- const commandSpecs = [...commandHandlers.values()].map(toCommandSpec);
569
- if (commandSpecs.length > 0) {
570
- const registerResults = await Promise.allSettled(adapters.map((a) => a.registerCommands?.(commandSpecs)));
571
- registerResults.forEach((r, i) => {
572
- if (r.status === "rejected") {
573
- console.error(`[channel] adapter "${adapters[i].platform}" failed to register commands:`, r.reason);
574
- }
575
- });
576
- }
577
- },
578
- async stop() {
579
- // Clear the started flag so a later start() is a real restart (re-resolve
580
- // backend, rebuild components, reconnect adapters) rather than a silent
581
- // no-op. The idempotency guard in start() only exists to block a DOUBLE
582
- // start() while running — not a legitimate start→stop→start cycle.
583
- started = false;
584
- // Isolate per-adapter shutdown failures: one adapter's stop() rejecting
585
- // must not prevent the others from being stopped.
586
- const stopResults = await Promise.allSettled(adapters.map((a) => a.stop()));
587
- stopResults.forEach((r, i) => {
588
- if (r.status === "rejected") {
589
- console.error(`[channel] adapter "${adapters[i].platform}" failed to stop:`, r.reason);
590
- }
591
- });
592
- },
593
605
  };
594
606
  return channel;
595
607
  }
@@ -60,7 +60,7 @@ describe("createChannel", () => {
60
60
  channel.onMention(async ({ thread }) => {
61
61
  await thread.post(Section({ children: "hi" }));
62
62
  });
63
- await channel.start();
63
+ await channel.ɵruntime.start();
64
64
  fake.emitTurn({ userText: "yo", conversationKey: "c1" });
65
65
  await tick();
66
66
  expect(fake.posted.length).toBe(1);
@@ -75,7 +75,7 @@ describe("createChannel", () => {
75
75
  channel.onMention(async ({ thread }) => {
76
76
  await thread.runAgent();
77
77
  });
78
- await channel.start();
78
+ await channel.ɵruntime.start();
79
79
  fake.emitTurn({ userText: "yo", conversationKey: "c1" });
80
80
  await tick();
81
81
  const renderer = fake.lastRunRenderer;
@@ -107,7 +107,7 @@ describe("createChannel", () => {
107
107
  : message.text,
108
108
  });
109
109
  });
110
- await channel.start();
110
+ await channel.ɵruntime.start();
111
111
  fake.emitTurn({
112
112
  userText: "look",
113
113
  conversationKey: "c1",
@@ -138,7 +138,7 @@ describe("createChannel", () => {
138
138
  ],
139
139
  }));
140
140
  });
141
- await channel.start();
141
+ await channel.ɵruntime.start();
142
142
  fake.emitTurn({ userText: "yo", conversationKey: "c1" });
143
143
  await tick();
144
144
  const button = findNode(fake.posted[0], "button");
@@ -164,7 +164,7 @@ describe("createChannel", () => {
164
164
  ],
165
165
  }));
166
166
  });
167
- await channel.start();
167
+ await channel.ɵruntime.start();
168
168
  fake.emitTurn({ userText: "create a thing", conversationKey: "c1" });
169
169
  await tick();
170
170
  const button = findNode(fake.posted[0], "button");
@@ -201,7 +201,7 @@ describe("createChannel", () => {
201
201
  context: [{ description: "who", value: "user U1" }],
202
202
  });
203
203
  });
204
- await channel.start();
204
+ await channel.ɵruntime.start();
205
205
  fake.emitTurn({ userText: "go", conversationKey: "c1" });
206
206
  await tick();
207
207
  expect(seenContext).toEqual([
@@ -221,7 +221,7 @@ describe("createChannel", () => {
221
221
  filename: "x.png",
222
222
  });
223
223
  });
224
- await channel.start();
224
+ await channel.ɵruntime.start();
225
225
  fake.emitTurn({ userText: "hi", conversationKey: "c1" });
226
226
  await tick();
227
227
  expect(result).toEqual({
@@ -243,7 +243,7 @@ describe("createChannel", () => {
243
243
  history = await thread.getMessages();
244
244
  resolved = await thread.lookupUser("Ada");
245
245
  });
246
- await channel.start();
246
+ await channel.ɵruntime.start();
247
247
  fake.emitTurn({ userText: "hi", conversationKey: "c1" });
248
248
  await tick();
249
249
  expect(history).toEqual([
@@ -267,7 +267,7 @@ describe("createChannel", () => {
267
267
  ],
268
268
  }));
269
269
  });
270
- await channel.start();
270
+ await channel.ɵruntime.start();
271
271
  fake.emitTurn({ userText: "decide", conversationKey: "c1" });
272
272
  await tick();
273
273
  const button = findNode(fake.posted[0], "button");
@@ -297,7 +297,7 @@ describe("createChannel", () => {
297
297
  runs++;
298
298
  await gate;
299
299
  });
300
- await channel.start();
300
+ await channel.ɵruntime.start();
301
301
  const sink = fake.getSink();
302
302
  const turn = {
303
303
  conversationKey: "c1",
@@ -329,7 +329,7 @@ describe("createChannel", () => {
329
329
  runs++;
330
330
  await gate;
331
331
  });
332
- await channel.start();
332
+ await channel.ɵruntime.start();
333
333
  const sink = fake.getSink();
334
334
  const turn = {
335
335
  conversationKey: "c1",
@@ -358,7 +358,7 @@ describe("createChannel", () => {
358
358
  channel.onMention(async () => {
359
359
  runs++;
360
360
  });
361
- await channel.start();
361
+ await channel.ɵruntime.start();
362
362
  const sink = fake.getSink();
363
363
  const base = {
364
364
  conversationKey: "c",
@@ -406,7 +406,7 @@ describe("createChannel", () => {
406
406
  channel.onMention(async ({ message }) => {
407
407
  capturedKey = message.userKey;
408
408
  });
409
- await channel.start();
409
+ await channel.ɵruntime.start();
410
410
  const sink = fake.getSink();
411
411
  await sink.onTurn({
412
412
  conversationKey: "c1",
@@ -430,7 +430,7 @@ describe("createChannel", () => {
430
430
  transcripts: { maxPerUser: 50 },
431
431
  },
432
432
  });
433
- await channel.start();
433
+ await channel.ɵruntime.start();
434
434
  const sink = fake.getSink();
435
435
  // Drive a turn so identity is resolved and we can verify transcripts exist
436
436
  const thread = { platform: "fake", conversationKey: "c1" };
@@ -481,7 +481,7 @@ describe("createChannel", () => {
481
481
  channel.onMention(async ({ thread }) => {
482
482
  await thread.runAgent({ transcript: true });
483
483
  });
484
- await channel.start();
484
+ await channel.ɵruntime.start();
485
485
  // Seed one prior cross-platform entry (different platform label) so we can
486
486
  // assert it shows up in the injected context. Seeded post-start: transcripts
487
487
  // are only available once the backend is resolved in start().
@@ -535,7 +535,7 @@ describe("createChannel", () => {
535
535
  rejected = true;
536
536
  }
537
537
  });
538
- await channel.start();
538
+ await channel.ɵruntime.start();
539
539
  fake.emitTurn({ userText: "go", conversationKey: "c1" });
540
540
  await tick();
541
541
  expect(roundTripped).toEqual({ step: "x" });
@@ -559,7 +559,7 @@ describe("createChannel lock and dedup edge cases", () => {
559
559
  await gate;
560
560
  throw new Error("boom");
561
561
  });
562
- await bot1.start();
562
+ await bot1.ɵruntime.start();
563
563
  const sink = fake.getSink();
564
564
  const turn = {
565
565
  conversationKey: "c1",
@@ -601,7 +601,7 @@ describe("createChannel lock and dedup edge cases", () => {
601
601
  runs++;
602
602
  await gate;
603
603
  });
604
- await channel.start();
604
+ await channel.ɵruntime.start();
605
605
  const sink = fake.getSink();
606
606
  const turn = {
607
607
  conversationKey: "c1",
@@ -634,7 +634,7 @@ describe("createChannel lock and dedup edge cases", () => {
634
634
  runs++;
635
635
  await gate;
636
636
  });
637
- await channel.start();
637
+ await channel.ɵruntime.start();
638
638
  const sink = fake.getSink();
639
639
  const turn = {
640
640
  conversationKey: "c1",
@@ -665,7 +665,7 @@ describe("createChannel lock and dedup edge cases", () => {
665
665
  channel.onMention(async ({ message }) => {
666
666
  capturedUserKey = message.userKey;
667
667
  });
668
- await channel.start();
668
+ await channel.ɵruntime.start();
669
669
  const sink = fake.getSink();
670
670
  await sink.onTurn({
671
671
  conversationKey: "c1",
@@ -686,7 +686,7 @@ describe("createChannel lock and dedup edge cases", () => {
686
686
  channel.onMention(async ({ message }) => {
687
687
  capturedUserKey = message.userKey;
688
688
  });
689
- await channel.start();
689
+ await channel.ɵruntime.start();
690
690
  const sink = fake.getSink();
691
691
  await sink.onTurn({
692
692
  conversationKey: "c1",
@@ -707,7 +707,7 @@ describe("createChannel lock and dedup edge cases", () => {
707
707
  channel.onMention(async () => {
708
708
  runs++;
709
709
  });
710
- await channel.start();
710
+ await channel.ɵruntime.start();
711
711
  const sink = fake.getSink();
712
712
  const base = {
713
713
  conversationKey: "c1",
@@ -746,7 +746,7 @@ describe("createChannel lock and dedup edge cases", () => {
746
746
  channel.onMention(async () => {
747
747
  runs++;
748
748
  });
749
- await channel.start();
749
+ await channel.ɵruntime.start();
750
750
  const sink = fake.getSink();
751
751
  await sink.onTurn({
752
752
  conversationKey: "c1",
@@ -772,7 +772,7 @@ describe("createChannel lock and dedup edge cases", () => {
772
772
  runs++;
773
773
  await gate;
774
774
  });
775
- await channel.start();
775
+ await channel.ɵruntime.start();
776
776
  const sink = fake.getSink();
777
777
  const turnA = {
778
778
  conversationKey: "c1",
@@ -813,7 +813,7 @@ describe("createChannel lock and dedup edge cases", () => {
813
813
  channel.onMention(async () => {
814
814
  runs++;
815
815
  });
816
- await channel.start();
816
+ await channel.ɵruntime.start();
817
817
  const sink = fake.getSink();
818
818
  const turn = {
819
819
  conversationKey: "c2",
@@ -838,7 +838,7 @@ describe("createChannel slash commands", () => {
838
838
  channel.onCommand("triage", ({ command, text }) => {
839
839
  seen = { command, text };
840
840
  });
841
- await channel.start();
841
+ await channel.ɵruntime.start();
842
842
  await fake.emitCommand({ command: "/Triage", text: "db is down" });
843
843
  expect(seen).toEqual({ command: "triage", text: "db is down" });
844
844
  });
@@ -849,7 +849,7 @@ describe("createChannel slash commands", () => {
849
849
  channel.onCommand("triage", () => {
850
850
  fired = true;
851
851
  });
852
- await channel.start();
852
+ await channel.ɵruntime.start();
853
853
  await fake.emitCommand({ command: "unknown", text: "x" });
854
854
  expect(fired).toBe(false);
855
855
  });
@@ -868,7 +868,7 @@ describe("createChannel slash commands", () => {
868
868
  }),
869
869
  ],
870
870
  });
871
- await channel.start();
871
+ await channel.ɵruntime.start();
872
872
  await fake.emitCommand({
873
873
  command: "book",
874
874
  text: "raw",
@@ -881,7 +881,7 @@ describe("createChannel slash commands", () => {
881
881
  const channel = createChannel({ adapters: [fake] });
882
882
  channel.onCommand("triage", () => { });
883
883
  channel.onCommand("status", () => { });
884
- await channel.start();
884
+ await channel.ɵruntime.start();
885
885
  expect(fake.registeredCommands?.map((c) => c.name).sort()).toEqual([
886
886
  "status",
887
887
  "triage",
@@ -893,7 +893,7 @@ describe("createChannel slash commands", () => {
893
893
  const bad = new FakeAdapter({ platform: "telegram", failStart: true });
894
894
  const good = new FakeAdapter({ platform: "slack" });
895
895
  const channel = createChannel({ adapters: [bad, good] });
896
- await expect(channel.start()).resolves.toBeUndefined();
896
+ await expect(channel.ɵruntime.start()).resolves.toBeUndefined();
897
897
  expect(good.started).toBe(true);
898
898
  expect(errSpy.mock.calls.some((c) => String(c[0]).includes("telegram"))).toBe(true);
899
899
  }
@@ -911,7 +911,7 @@ describe("createChannel slash commands", () => {
911
911
  const good = new FakeAdapter({ platform: "slack" });
912
912
  const channel = createChannel({ adapters: [bad, good] });
913
913
  channel.onCommand("triage", () => { });
914
- await expect(channel.start()).resolves.toBeUndefined();
914
+ await expect(channel.ɵruntime.start()).resolves.toBeUndefined();
915
915
  expect(good.started).toBe(true);
916
916
  expect(good.registeredCommands?.map((c) => c.name)).toEqual(["triage"]);
917
917
  expect(errSpy.mock.calls.some((c) => String(c[0]).includes("telegram"))).toBe(true);
@@ -927,8 +927,8 @@ describe("createChannel slash commands", () => {
927
927
  const good = new FakeAdapter({ platform: "slack" });
928
928
  const stopSpy = vi.spyOn(good, "stop");
929
929
  const channel = createChannel({ adapters: [bad, good] });
930
- await channel.start();
931
- await expect(channel.stop()).resolves.toBeUndefined();
930
+ await channel.ɵruntime.start();
931
+ await expect(channel.ɵruntime.stop()).resolves.toBeUndefined();
932
932
  expect(stopSpy).toHaveBeenCalled();
933
933
  expect(errSpy.mock.calls.some((c) => String(c[0]).includes("telegram"))).toBe(true);
934
934
  }
@@ -949,7 +949,7 @@ describe("createChannel slash commands", () => {
949
949
  const channel = createChannel({});
950
950
  expect(channel.adapters).toHaveLength(0);
951
951
  const fake = new FakeAdapter();
952
- channel.addAdapter(fake);
952
+ channel.ɵruntime.addAdapter(fake);
953
953
  expect(channel.adapters).toEqual([fake]);
954
954
  });
955
955
  });
@@ -15,7 +15,7 @@ describe("channel.onModalSubmit / onModalClose", () => {
15
15
  hasThread: !!evt.thread,
16
16
  });
17
17
  });
18
- await channel.start();
18
+ await channel.ɵruntime.start();
19
19
  const res = await fake.emitModalSubmit({
20
20
  callbackId: "triage",
21
21
  values: { summary: "boom", prio: "high" },
@@ -37,7 +37,7 @@ describe("channel.onModalSubmit / onModalClose", () => {
37
37
  const fake = new FakeAdapter();
38
38
  const channel = createChannel({ adapters: [fake] });
39
39
  channel.onModalSubmit("triage", (evt) => evt.values.summary ? undefined : { errors: { summary: "Required" } });
40
- await channel.start();
40
+ await channel.ɵruntime.start();
41
41
  const res = await fake.emitModalSubmit({
42
42
  callbackId: "triage",
43
43
  values: {},
@@ -47,7 +47,7 @@ describe("channel.onModalSubmit / onModalClose", () => {
47
47
  it("ignores submissions with no registered handler", async () => {
48
48
  const fake = new FakeAdapter();
49
49
  const channel = createChannel({ adapters: [fake] });
50
- await channel.start();
50
+ await channel.ɵruntime.start();
51
51
  const res = await fake.emitModalSubmit({
52
52
  callbackId: "unknown",
53
53
  values: {},
@@ -61,7 +61,7 @@ describe("channel.onModalSubmit / onModalClose", () => {
61
61
  channel.onModalClose("triage", (evt) => {
62
62
  closed.push(evt.callbackId);
63
63
  });
64
- await channel.start();
64
+ await channel.ɵruntime.start();
65
65
  await fake.emitModalClose({ callbackId: "triage", user: { id: "U2" } });
66
66
  expect(closed).toEqual(["triage"]);
67
67
  });
@@ -18,7 +18,7 @@ describe("ctx.openModal", () => {
18
18
  channel.onInteraction("ck:open", async (ctx) => {
19
19
  res = await ctx.openModal(view);
20
20
  });
21
- await channel.start();
21
+ await channel.ɵruntime.start();
22
22
  fake.emitInteraction({ id: "ck:open", triggerId: "T123" });
23
23
  await tick();
24
24
  expect(res).toEqual({ ok: true });
@@ -33,7 +33,7 @@ describe("ctx.openModal", () => {
33
33
  channel.onCommand("triage", async (ctx) => {
34
34
  res = await ctx.openModal(view);
35
35
  });
36
- await channel.start();
36
+ await channel.ɵruntime.start();
37
37
  await fake.emitCommand({ command: "triage", triggerId: "T999" });
38
38
  expect(res).toEqual({ ok: true });
39
39
  expect(fake.openedModals[0].triggerId).toBe("T999");
@@ -45,7 +45,7 @@ describe("ctx.openModal", () => {
45
45
  channel.onInteraction("ck:noop", (ctx) => {
46
46
  hasOpen = typeof ctx.openModal === "function";
47
47
  });
48
- await channel.start();
48
+ await channel.ɵruntime.start();
49
49
  fake.emitInteraction({ id: "ck:noop" });
50
50
  await tick();
51
51
  expect(hasOpen).toBe(false);
@@ -57,7 +57,7 @@ describe("ctx.openModal", () => {
57
57
  channel.onInteraction("ck:x", (ctx) => {
58
58
  hasOpen = typeof ctx.openModal === "function";
59
59
  });
60
- await channel.start();
60
+ await channel.ɵruntime.start();
61
61
  fake.emitInteraction({ id: "ck:x", triggerId: "T1" });
62
62
  await tick();
63
63
  expect(hasOpen).toBe(false);
@@ -13,7 +13,7 @@ describe("channel.onReaction", () => {
13
13
  channel.onReaction([emoji.thumbs_up], (evt) => {
14
14
  seen.push({ emoji: evt.emoji, raw: evt.rawEmoji, added: evt.added });
15
15
  });
16
- await channel.start();
16
+ await channel.ɵruntime.start();
17
17
  // FakeAdapter.platform === "fake": normalizeEmoji falls through, but engine
18
18
  // normalizes by adapter.platform. Use a Slack-style token via a fake whose
19
19
  // platform normalizes — here we assert passthrough + catch-all instead.
@@ -35,7 +35,7 @@ describe("channel.onReaction", () => {
35
35
  platform: evt.thread.platform,
36
36
  });
37
37
  });
38
- await channel.start();
38
+ await channel.ɵruntime.start();
39
39
  fake.emitReaction({
40
40
  rawEmoji: "🎉",
41
41
  added: true,
@@ -64,7 +64,7 @@ describe("channel.onReaction", () => {
64
64
  channel.onReaction(["thumbs_up"], (evt) => {
65
65
  hits.push(evt.emoji);
66
66
  });
67
- await channel.start();
67
+ await channel.ɵruntime.start();
68
68
  fake.emitReaction({ rawEmoji: "thumbsup", added: true }); // Slack alias
69
69
  await tick();
70
70
  expect(hits).toEqual(["thumbs_up"]);
@@ -80,7 +80,7 @@ describe("channel.onReaction", () => {
80
80
  channel.onReaction(["refresh"], (evt) => {
81
81
  hits.push(evt.emoji);
82
82
  });
83
- await channel.start();
83
+ await channel.ɵruntime.start();
84
84
  fake.emitReaction({
85
85
  rawEmoji: "1f504_refresh",
86
86
  added: true,
@@ -101,7 +101,7 @@ describe("channel.onReaction", () => {
101
101
  children: "hi",
102
102
  }));
103
103
  });
104
- await channel.start();
104
+ await channel.ɵruntime.start();
105
105
  fake.emitTurn({});
106
106
  await tick();
107
107
  // The handler is a closure, never serialized into the native payload.
@@ -128,7 +128,7 @@ describe("channel.onReaction", () => {
128
128
  children: "hi",
129
129
  }));
130
130
  });
131
- await channel.start();
131
+ await channel.ɵruntime.start();
132
132
  fake.emitTurn({});
133
133
  await tick();
134
134
  // Channel delivery: the reaction arrives keyed by the provider ts (NOT the
@@ -165,7 +165,7 @@ describe("channel.onReaction", () => {
165
165
  // pre-rendered Message() node.
166
166
  await thread.post({ type: Card, props: {} });
167
167
  });
168
- await bot1.start();
168
+ await bot1.ɵruntime.start();
169
169
  fake1.emitTurn({});
170
170
  await tick();
171
171
  // "Restart": a fresh channel + registry sharing the same store, Card re-registered.
@@ -176,7 +176,7 @@ describe("channel.onReaction", () => {
176
176
  store: { adapter: backend },
177
177
  components: [Card],
178
178
  });
179
- await bot2.start();
179
+ await bot2.ɵruntime.start();
180
180
  fake2.emitReaction({ rawEmoji: "🎉", added: true, messageId: "msg-1" });
181
181
  await tick();
182
182
  expect(seen).toEqual(["🎉"]);
@@ -194,7 +194,7 @@ describe("channel.onReaction", () => {
194
194
  children: "hi",
195
195
  }));
196
196
  });
197
- await channel.start();
197
+ await channel.ɵruntime.start();
198
198
  fake.emitTurn({});
199
199
  await tick();
200
200
  const before = fake.posted.length;
@@ -217,7 +217,7 @@ describe("channel.onReaction", () => {
217
217
  children: "hi",
218
218
  }));
219
219
  });
220
- await channel.start();
220
+ await channel.ɵruntime.start();
221
221
  fake.emitTurn({});
222
222
  await tick();
223
223
  fake.emitReaction({ rawEmoji: "🎉", added: true, messageId: "other" });
@@ -237,7 +237,7 @@ describe("channel.onReaction", () => {
237
237
  channel.onReaction(["thumbsup"], (evt) => {
238
238
  hits.push(`alias:${evt.emoji}`);
239
239
  });
240
- await channel.start();
240
+ await channel.ɵruntime.start();
241
241
  fake.emitReaction({ rawEmoji: "thumbsup", added: true }); // Slack alias
242
242
  await tick();
243
243
  expect(hits).toEqual(["thumbs_up", "alias:thumbs_up"]);
@@ -28,7 +28,7 @@ describe("createChannel telemetry wiring", () => {
28
28
  },
29
29
  ],
30
30
  });
31
- await channel.start();
31
+ await channel.ɵruntime.start();
32
32
  const call = capture.mock.calls.find((c) => c[0] === "oss.channel.configured");
33
33
  expect(call).toBeDefined();
34
34
  expect(call[1].platforms).toEqual(["custom"]); // FakeAdapter.platform "fake" → normalized
@@ -38,14 +38,17 @@ describe("createChannel telemetry wiring", () => {
38
38
  it("emits oss.channel.started on start, start_failed (category only) on a throwing adapter", async () => {
39
39
  const ok = new FakeAdapter();
40
40
  const channel = createChannel({ adapters: [ok] });
41
- await channel.start();
41
+ await channel.ɵruntime.start();
42
42
  expect(capture.mock.calls.find((c) => c[0] === "oss.channel.started")?.[1]
43
43
  .startedCount).toBe(1);
44
44
  capture.mockClear();
45
45
  const bad = new FakeAdapter();
46
46
  bad.start = () => Promise.reject(Object.assign(new Error("xoxb-SECRET token bad"), { code: "EAUTH" }));
47
47
  const bot2 = createChannel({ adapters: [bad] });
48
- await bot2.start();
48
+ // All adapters failed → start() rejects (the channel is dead; the runtime
49
+ // reports status "error"). The start_failed telemetry is still captured
50
+ // before the throw.
51
+ await expect(bot2.ɵruntime.start()).rejects.toThrow(/failed to start/i);
49
52
  const f = capture.mock.calls.find((c) => c[0] === "oss.channel.start_failed");
50
53
  expect(f).toBeDefined();
51
54
  expect(f[1].errorClass).toBe("auth");
@@ -60,7 +63,7 @@ describe("createChannel telemetry wiring", () => {
60
63
  channel.onMention(async ({ thread }) => {
61
64
  await thread.runAgent();
62
65
  });
63
- await channel.start();
66
+ await channel.ɵruntime.start();
64
67
  capture.mockClear();
65
68
  fake.emitTurn({ userText: "hi", conversationKey: "c1" });
66
69
  await tick();
@@ -40,7 +40,7 @@ describe("oss.channel.* end-to-end (real ChannelTelemetry, only network boundary
40
40
  channel.onMention(async ({ thread }) => {
41
41
  await thread.runAgent();
42
42
  });
43
- await channel.start();
43
+ await channel.ɵruntime.start();
44
44
  fake.emitTurn({ userText: "hi", conversationKey: "c1" });
45
45
  await waitFor(() => sendSpy.mock.calls.some((c) => c[0].event === "oss.channel.agent_run"));
46
46
  const events = sendSpy.mock.calls.map((c) => c[0].event);
@@ -1 +1 @@
1
- {"version":3,"file":"fake-adapter.d.ts","sourceRoot":"","sources":["../../src/testing/fake-adapter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"fake-adapter.d.ts","sourceRoot":"","sources":["../../src/testing/fake-adapter.ts"],"names":[],"mappings":"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"}
@@ -142,7 +142,7 @@ export class FakeAdapter {
142
142
  /** Expose the registered sink so tests can invoke onTurn() directly for overlap/lock tests. */
143
143
  getSink() {
144
144
  if (!this.sink)
145
- throw new Error("FakeAdapter: sink not set — call channel.start() first");
145
+ throw new Error("FakeAdapter: sink not set — start the channel (channel.ɵruntime.start()) first");
146
146
  return this.sink;
147
147
  }
148
148
  async start(sink) {
@@ -9,7 +9,7 @@ describe("onThreadStarted routing", () => {
9
9
  channel.onThreadStarted(({ thread, user }) => {
10
10
  seen.push({ user: user?.id, platform: thread.platform });
11
11
  });
12
- await channel.start();
12
+ await channel.ɵruntime.start();
13
13
  await fake.emitThreadStarted({ user: { id: "U1", name: "Ada" } });
14
14
  expect(seen).toEqual([{ user: "U1", platform: "fake" }]);
15
15
  });
@@ -23,14 +23,14 @@ describe("onThreadStarted routing", () => {
23
23
  channel.onThreadStarted(() => {
24
24
  order.push(2);
25
25
  });
26
- await channel.start();
26
+ await channel.ɵruntime.start();
27
27
  await fake.emitThreadStarted();
28
28
  expect(order).toEqual([1, 2]);
29
29
  });
30
30
  it("is a no-op when no handler is registered", async () => {
31
31
  const fake = new FakeAdapter();
32
32
  const channel = createChannel({ adapters: [fake] });
33
- await channel.start();
33
+ await channel.ɵruntime.start();
34
34
  // Should not throw.
35
35
  await expect(Promise.resolve(fake.emitThreadStarted())).resolves.toBeUndefined();
36
36
  });
@@ -44,7 +44,7 @@ describe("Thread.setSuggestedPrompts / setTitle capability gating", () => {
44
44
  results.push(await thread.setSuggestedPrompts([{ title: "Triage", message: "Triage my issues" }], { title: "Try" }));
45
45
  results.push(await thread.setTitle("My conversation"));
46
46
  });
47
- await channel.start();
47
+ await channel.ɵruntime.start();
48
48
  await fake.emitThreadStarted({ replyTarget: { channel: "D1" } });
49
49
  expect(results).toEqual([{ ok: true }, { ok: true }]);
50
50
  expect(fake.suggestedPromptsCalls).toHaveLength(1);
@@ -65,7 +65,7 @@ describe("Thread.setSuggestedPrompts / setTitle capability gating", () => {
65
65
  results.push(await thread.setSuggestedPrompts([]));
66
66
  results.push(await thread.setTitle("nope"));
67
67
  });
68
- await channel.start();
68
+ await channel.ɵruntime.start();
69
69
  await fake.emitThreadStarted();
70
70
  expect(results[0].ok).toBe(false);
71
71
  expect(results[0].error).toMatch(/does not support suggested prompts/);
@@ -4,7 +4,7 @@ import { FakeAdapter } from "./testing/fake-adapter.js";
4
4
  async function runOnMessage(fake, fn) {
5
5
  const channel = createChannel({ adapters: [fake] });
6
6
  channel.onMessage(fn);
7
- await channel.start();
7
+ await channel.ɵruntime.start();
8
8
  fake.emitTurn({ userText: "hi", user: { id: "U1" } });
9
9
  await new Promise((r) => setTimeout(r, 0));
10
10
  }
@@ -11,7 +11,7 @@ describe("Thread.react / unreact", () => {
11
11
  results.push(await thread.react(message.ref, emoji.thumbs_up));
12
12
  results.push(await thread.unreact(message.ref, emoji.thumbs_up));
13
13
  });
14
- await channel.start();
14
+ await channel.ɵruntime.start();
15
15
  fake.emitTurn({ userText: "hi" });
16
16
  await new Promise((r) => setTimeout(r, 0));
17
17
  expect(results).toEqual([{ ok: true }, { ok: true }]);
@@ -29,7 +29,7 @@ describe("Thread.react / unreact", () => {
29
29
  channel.onMessage(async ({ thread, message }) => {
30
30
  res = await thread.react(message.ref, emoji.heart);
31
31
  });
32
- await channel.start();
32
+ await channel.ɵruntime.start();
33
33
  fake.emitTurn({ userText: "hi" });
34
34
  await new Promise((r) => setTimeout(r, 0));
35
35
  expect(res.ok).toBe(false);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@copilotkit/channels-core",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "Platform-agnostic JSX channel engine for CopilotKit (createChannel, Thread, PlatformAdapter, ActionStore).",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -51,9 +51,9 @@
51
51
  "@ag-ui/client": "0.0.57",
52
52
  "@ag-ui/core": "0.0.57",
53
53
  "zod-to-json-schema": "^3.24.1",
54
- "@copilotkit/channels-ui": "~0.2.1",
55
- "@copilotkit/core": "^1.63.1",
56
- "@copilotkit/shared": "^1.63.1"
54
+ "@copilotkit/channels-ui": "~0.3.0",
55
+ "@copilotkit/shared": "^1.63.2",
56
+ "@copilotkit/core": "^1.63.2"
57
57
  },
58
58
  "devDependencies": {
59
59
  "@types/node": "^22.10.0",