@copilotkit/channels 0.1.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 (156) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +204 -0
  3. package/dist/action-registry.d.ts +59 -0
  4. package/dist/action-registry.d.ts.map +1 -0
  5. package/dist/action-registry.js +217 -0
  6. package/dist/action-registry.test.d.ts +2 -0
  7. package/dist/action-registry.test.d.ts.map +1 -0
  8. package/dist/action-registry.test.js +115 -0
  9. package/dist/action-store.d.ts +21 -0
  10. package/dist/action-store.d.ts.map +1 -0
  11. package/dist/action-store.js +23 -0
  12. package/dist/action-store.test.d.ts +2 -0
  13. package/dist/action-store.test.d.ts.map +1 -0
  14. package/dist/action-store.test.js +27 -0
  15. package/dist/codec.d.ts +25 -0
  16. package/dist/codec.d.ts.map +1 -0
  17. package/dist/codec.js +1 -0
  18. package/dist/commands.d.ts +73 -0
  19. package/dist/commands.d.ts.map +1 -0
  20. package/dist/commands.js +38 -0
  21. package/dist/commands.test.d.ts +2 -0
  22. package/dist/commands.test.d.ts.map +1 -0
  23. package/dist/commands.test.js +23 -0
  24. package/dist/create-bot.d.ts +171 -0
  25. package/dist/create-bot.d.ts.map +1 -0
  26. package/dist/create-bot.foundations.test.d.ts +2 -0
  27. package/dist/create-bot.foundations.test.d.ts.map +1 -0
  28. package/dist/create-bot.foundations.test.js +147 -0
  29. package/dist/create-bot.js +576 -0
  30. package/dist/create-bot.test.d.ts +2 -0
  31. package/dist/create-bot.test.d.ts.map +1 -0
  32. package/dist/create-bot.test.js +936 -0
  33. package/dist/index.d.ts +26 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/index.js +32 -0
  36. package/dist/mint-id.d.ts +3 -0
  37. package/dist/mint-id.d.ts.map +1 -0
  38. package/dist/mint-id.js +20 -0
  39. package/dist/mint-id.test.d.ts +2 -0
  40. package/dist/mint-id.test.d.ts.map +1 -0
  41. package/dist/mint-id.test.js +16 -0
  42. package/dist/modal-submit.test.d.ts +2 -0
  43. package/dist/modal-submit.test.d.ts.map +1 -0
  44. package/dist/modal-submit.test.js +68 -0
  45. package/dist/platform-adapter.d.ts +312 -0
  46. package/dist/platform-adapter.d.ts.map +1 -0
  47. package/dist/platform-adapter.js +1 -0
  48. package/dist/platform-adapter.test.d.ts +2 -0
  49. package/dist/platform-adapter.test.d.ts.map +1 -0
  50. package/dist/platform-adapter.test.js +40 -0
  51. package/dist/reactions.test.d.ts +2 -0
  52. package/dist/reactions.test.d.ts.map +1 -0
  53. package/dist/reactions.test.js +197 -0
  54. package/dist/run-loop.d.ts +41 -0
  55. package/dist/run-loop.d.ts.map +1 -0
  56. package/dist/run-loop.js +102 -0
  57. package/dist/run-loop.test.d.ts +2 -0
  58. package/dist/run-loop.test.d.ts.map +1 -0
  59. package/dist/run-loop.test.js +125 -0
  60. package/dist/standard-schema.d.ts +52 -0
  61. package/dist/standard-schema.d.ts.map +1 -0
  62. package/dist/standard-schema.js +66 -0
  63. package/dist/state/duration.d.ts +3 -0
  64. package/dist/state/duration.d.ts.map +1 -0
  65. package/dist/state/duration.js +16 -0
  66. package/dist/state/duration.test.d.ts +2 -0
  67. package/dist/state/duration.test.d.ts.map +1 -0
  68. package/dist/state/duration.test.js +13 -0
  69. package/dist/state/kv-action-store.d.ts +7 -0
  70. package/dist/state/kv-action-store.d.ts.map +1 -0
  71. package/dist/state/kv-action-store.js +9 -0
  72. package/dist/state/kv-action-store.test.d.ts +2 -0
  73. package/dist/state/kv-action-store.test.d.ts.map +1 -0
  74. package/dist/state/kv-action-store.test.js +21 -0
  75. package/dist/state/memory-store.d.ts +41 -0
  76. package/dist/state/memory-store.d.ts.map +1 -0
  77. package/dist/state/memory-store.js +110 -0
  78. package/dist/state/memory-store.test.d.ts +2 -0
  79. package/dist/state/memory-store.test.d.ts.map +1 -0
  80. package/dist/state/memory-store.test.js +22 -0
  81. package/dist/state/state-conversation-store.d.ts +14 -0
  82. package/dist/state/state-conversation-store.d.ts.map +1 -0
  83. package/dist/state/state-conversation-store.js +22 -0
  84. package/dist/state/state-conversation-store.test.d.ts +2 -0
  85. package/dist/state/state-conversation-store.test.d.ts.map +1 -0
  86. package/dist/state/state-conversation-store.test.js +58 -0
  87. package/dist/state/state-store.d.ts +63 -0
  88. package/dist/state/state-store.d.ts.map +1 -0
  89. package/dist/state/state-store.js +1 -0
  90. package/dist/telemetry/bot-telemetry.d.ts +31 -0
  91. package/dist/telemetry/bot-telemetry.d.ts.map +1 -0
  92. package/dist/telemetry/bot-telemetry.js +70 -0
  93. package/dist/telemetry/bot-telemetry.test.d.ts +2 -0
  94. package/dist/telemetry/bot-telemetry.test.d.ts.map +1 -0
  95. package/dist/telemetry/bot-telemetry.test.js +56 -0
  96. package/dist/telemetry/create-bot-telemetry.test.d.ts +2 -0
  97. package/dist/telemetry/create-bot-telemetry.test.d.ts.map +1 -0
  98. package/dist/telemetry/create-bot-telemetry.test.js +71 -0
  99. package/dist/telemetry/e2e-telemetry.test.d.ts +2 -0
  100. package/dist/telemetry/e2e-telemetry.test.d.ts.map +1 -0
  101. package/dist/telemetry/e2e-telemetry.test.js +56 -0
  102. package/dist/telemetry/events-catalog.test.d.ts +2 -0
  103. package/dist/telemetry/events-catalog.test.d.ts.map +1 -0
  104. package/dist/telemetry/events-catalog.test.js +8 -0
  105. package/dist/telemetry/install-id.d.ts +8 -0
  106. package/dist/telemetry/install-id.d.ts.map +1 -0
  107. package/dist/telemetry/install-id.js +43 -0
  108. package/dist/telemetry/install-id.test.d.ts +2 -0
  109. package/dist/telemetry/install-id.test.d.ts.map +1 -0
  110. package/dist/telemetry/install-id.test.js +43 -0
  111. package/dist/telemetry/platform-allowlist-coverage.test.d.ts +2 -0
  112. package/dist/telemetry/platform-allowlist-coverage.test.d.ts.map +1 -0
  113. package/dist/telemetry/platform-allowlist-coverage.test.js +45 -0
  114. package/dist/telemetry/sanitize-error.d.ts +3 -0
  115. package/dist/telemetry/sanitize-error.d.ts.map +1 -0
  116. package/dist/telemetry/sanitize-error.js +31 -0
  117. package/dist/telemetry/sanitize-error.test.d.ts +2 -0
  118. package/dist/telemetry/sanitize-error.test.d.ts.map +1 -0
  119. package/dist/telemetry/sanitize-error.test.js +33 -0
  120. package/dist/testing/fake-adapter.d.ts +137 -0
  121. package/dist/testing/fake-adapter.d.ts.map +1 -0
  122. package/dist/testing/fake-adapter.js +273 -0
  123. package/dist/testing/fake-agent.d.ts +28 -0
  124. package/dist/testing/fake-agent.d.ts.map +1 -0
  125. package/dist/testing/fake-agent.js +36 -0
  126. package/dist/testing/state-store-conformance.d.ts +4 -0
  127. package/dist/testing/state-store-conformance.d.ts.map +1 -0
  128. package/dist/testing/state-store-conformance.js +117 -0
  129. package/dist/thread-capabilities.test.d.ts +2 -0
  130. package/dist/thread-capabilities.test.d.ts.map +1 -0
  131. package/dist/thread-capabilities.test.js +77 -0
  132. package/dist/thread-ephemeral.test.d.ts +2 -0
  133. package/dist/thread-ephemeral.test.d.ts.map +1 -0
  134. package/dist/thread-ephemeral.test.js +45 -0
  135. package/dist/thread-reactions.test.d.ts +2 -0
  136. package/dist/thread-reactions.test.d.ts.map +1 -0
  137. package/dist/thread-reactions.test.js +38 -0
  138. package/dist/thread.d.ts +152 -0
  139. package/dist/thread.d.ts.map +1 -0
  140. package/dist/thread.js +329 -0
  141. package/dist/thread.test.d.ts +2 -0
  142. package/dist/thread.test.d.ts.map +1 -0
  143. package/dist/thread.test.js +83 -0
  144. package/dist/tools.d.ts +67 -0
  145. package/dist/tools.d.ts.map +1 -0
  146. package/dist/tools.js +38 -0
  147. package/dist/tools.test.d.ts +2 -0
  148. package/dist/tools.test.d.ts.map +1 -0
  149. package/dist/tools.test.js +31 -0
  150. package/dist/transcripts.d.ts +52 -0
  151. package/dist/transcripts.d.ts.map +1 -0
  152. package/dist/transcripts.js +67 -0
  153. package/dist/transcripts.test.d.ts +2 -0
  154. package/dist/transcripts.test.d.ts.map +1 -0
  155. package/dist/transcripts.test.js +108 -0
  156. package/package.json +72 -0
@@ -0,0 +1,152 @@
1
+ import type { PlatformAdapter, ReplyTarget } from "./platform-adapter.js";
2
+ import type { ActionRegistry } from "./action-registry.js";
3
+ import type { AgentContentPart, Renderable, MessageRef, PlatformUser, ThreadMessage, IncomingMessage, Thread as ThreadInterface, EmojiValue, EphemeralResult } from "@copilotkit/channels-ui";
4
+ import type { Transcripts } from "./transcripts.js";
5
+ import type { BotTool, ContextEntry, AgentToolDescriptor } from "./tools.js";
6
+ import type { AbstractAgent } from "@ag-ui/client";
7
+ import type { StateStore } from "./state/state-store.js";
8
+ import type { StandardSchemaV1 } from "./standard-schema.js";
9
+ export interface ThreadDeps {
10
+ adapter: PlatformAdapter;
11
+ replyTarget: ReplyTarget;
12
+ conversationKey: string;
13
+ registry: ActionRegistry;
14
+ agentFactory: (threadId: string) => AbstractAgent;
15
+ tools: Map<string, BotTool>;
16
+ toolDescriptors: AgentToolDescriptor[];
17
+ context: ContextEntry[];
18
+ registerWaiter: (conversationKey: string, resolve: (value: unknown) => void) => void;
19
+ interruptHandlers: Map<string, (args: {
20
+ payload: unknown;
21
+ thread: Thread;
22
+ }) => void | Promise<void>>;
23
+ /** Pluggable persistence. Injected by createBot; always required. */
24
+ state: StateStore;
25
+ /**
26
+ * Optional Standard Schema for per-thread state. When set, `setState`
27
+ * validates its argument before persisting and throws on a schema mismatch.
28
+ */
29
+ stateSchema?: StandardSchemaV1;
30
+ /** Cross-platform transcript store. Present only when `store.transcripts` is configured. */
31
+ transcripts?: Transcripts;
32
+ /** Resolved cross-platform identity key for this turn (if any). */
33
+ userKey?: string;
34
+ /** The inbound message that triggered this turn (for transcript bridging). */
35
+ message?: IncomingMessage;
36
+ /**
37
+ * Optional anonymous telemetry sink. Structural type (not the concrete
38
+ * BotTelemetry) avoids an import cycle; the real BotTelemetry satisfies it.
39
+ */
40
+ telemetry?: {
41
+ capture(event: string, properties: Record<string, unknown>): void;
42
+ };
43
+ }
44
+ /** A concrete conversation thread: posts UI, runs the agent loop, and resolves HITL waiters. */
45
+ export declare class Thread implements ThreadInterface {
46
+ private deps;
47
+ readonly platform: string;
48
+ /** Stable key identifying this conversation (used by transcript bridging). */
49
+ readonly conversationKey: string;
50
+ private readonly store;
51
+ constructor(deps: ThreadDeps);
52
+ private bindForPost;
53
+ /**
54
+ * Wire a posted message's `onReaction` to its returned id: cache it for this
55
+ * process and, when it came from a component, persist a durable snapshot so a
56
+ * reaction after a restart re-derives it (parity with a component `onClick`).
57
+ */
58
+ private bindReaction;
59
+ post(ui: Renderable): Promise<MessageRef>;
60
+ update(ref: MessageRef, ui: Renderable): Promise<MessageRef>;
61
+ delete(ref: MessageRef): Promise<void>;
62
+ stream(src: string | AsyncIterable<string>): Promise<MessageRef>;
63
+ postFile(args: {
64
+ bytes: Uint8Array;
65
+ filename: string;
66
+ title?: string;
67
+ altText?: string;
68
+ }): Promise<{
69
+ ok: boolean;
70
+ fileId?: string;
71
+ error?: string;
72
+ }>;
73
+ /** Pin suggested prompts (returns `{ ok: false }` on surfaces without support). */
74
+ setSuggestedPrompts(prompts: ReadonlyArray<{
75
+ title: string;
76
+ message: string;
77
+ }>, opts?: {
78
+ title?: string;
79
+ }): Promise<{
80
+ ok: boolean;
81
+ error?: string;
82
+ }>;
83
+ /** Name this conversation (returns `{ ok: false }` on surfaces without support). */
84
+ setTitle(title: string): Promise<{
85
+ ok: boolean;
86
+ error?: string;
87
+ }>;
88
+ /** Add an emoji reaction to a message (capability-gated; `{ ok: false }` on surfaces without support). */
89
+ react(messageRef: MessageRef, emoji: EmojiValue): Promise<{
90
+ ok: boolean;
91
+ error?: string;
92
+ }>;
93
+ /** Remove the bot's emoji reaction from a message (capability-gated). */
94
+ unreact(messageRef: MessageRef, emoji: EmojiValue): Promise<{
95
+ ok: boolean;
96
+ error?: string;
97
+ }>;
98
+ /**
99
+ * Post a message only `user` can see. `fallbackToDM` is required:
100
+ * `true` → DM the user when native ephemeral is unsupported; `false` →
101
+ * resolve to `null` when native ephemeral is unsupported.
102
+ */
103
+ postEphemeral(user: PlatformUser | string, ui: Renderable, opts: {
104
+ fallbackToDM: boolean;
105
+ }): Promise<EphemeralResult | null>;
106
+ /** Record this conversation as subscribed (persisted in state). Proactive delivery to subscribed conversations is not yet wired. */
107
+ subscribe(): Promise<void>;
108
+ /** Remove the subscription for this conversation. */
109
+ unsubscribe(): Promise<void>;
110
+ /** Returns true if this conversation is currently subscribed. */
111
+ isSubscribed(): Promise<boolean>;
112
+ /** Persist arbitrary per-thread state (e.g. workflow step). */
113
+ setState<T>(v: T): Promise<void>;
114
+ /** Read back per-thread state previously written with `setState`. */
115
+ state<T>(): Promise<T | undefined>;
116
+ /** Read the conversation's messages (returns `[]` when the adapter can't read history). */
117
+ getMessages(): Promise<ThreadMessage[]>;
118
+ /** Resolve a platform user by free-form query (returns `undefined` when unsupported). */
119
+ lookupUser(query: string): Promise<PlatformUser | undefined>;
120
+ /** Post a picker and wait until an interaction in this conversation resolves it. */
121
+ awaitChoice<T = unknown>(ui: Renderable): Promise<T>;
122
+ runAgent(input?: {
123
+ context?: ContextEntry[];
124
+ tools?: BotTool[];
125
+ /**
126
+ * A user message to inject before running. Needed when the input isn't
127
+ * already in the conversation history the adapter reconstructs — e.g. a
128
+ * slash command, whose args are never posted to the channel. A
129
+ * `AgentContentPart[]` carries multimodal content (e.g. inbound image/file
130
+ * attachments) the model can read.
131
+ */
132
+ prompt?: string | AgentContentPart[];
133
+ /**
134
+ * Auto-bridge cross-platform transcripts for this run. When truthy AND the
135
+ * thread has a resolved `userKey` AND a `Transcripts` instance, this:
136
+ * 1. injects prior history (`transcripts.list`, default limit 20) as a
137
+ * context entry,
138
+ * 2. appends the current user turn,
139
+ * 3. runs the agent,
140
+ * 4. captures the assistant reply and appends it.
141
+ * This flag OWNS the bridge — callers using it should NOT also manually
142
+ * append the same user/assistant turn via `bot.transcripts.append`.
143
+ * No-ops with a one-time warning when identity/transcripts aren't configured.
144
+ */
145
+ transcript?: boolean | {
146
+ limit?: number;
147
+ };
148
+ }): Promise<MessageRef | undefined>;
149
+ resume(value: unknown): Promise<MessageRef | undefined>;
150
+ private run;
151
+ }
152
+ //# sourceMappingURL=thread.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thread.d.ts","sourceRoot":"","sources":["../src/thread.ts"],"names":[],"mappings":"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"}
package/dist/thread.js ADDED
@@ -0,0 +1,329 @@
1
+ import { runAgentLoop } from "./run-loop.js";
2
+ import { errorClass, normalizePlatform } from "./telemetry/sanitize-error.js";
3
+ import { toAgentToolDescriptors } from "./tools.js";
4
+ import { validateSchema } from "./standard-schema.js";
5
+ /** A concrete conversation thread: posts UI, runs the agent loop, and resolves HITL waiters. */
6
+ export class Thread {
7
+ deps;
8
+ platform;
9
+ /** Stable key identifying this conversation (used by transcript bridging). */
10
+ conversationKey;
11
+ store;
12
+ constructor(deps) {
13
+ this.deps = deps;
14
+ this.platform = deps.adapter.platform;
15
+ this.conversationKey = deps.conversationKey;
16
+ this.store = deps.state;
17
+ }
18
+ async bindForPost(ui) {
19
+ return this.deps.registry.bindRenderable(ui, this.deps.conversationKey);
20
+ }
21
+ /**
22
+ * Wire a posted message's `onReaction` to its returned id: cache it for this
23
+ * process and, when it came from a component, persist a durable snapshot so a
24
+ * reaction after a restart re-derives it (parity with a component `onClick`).
25
+ */
26
+ async bindReaction(messageId, bound) {
27
+ if (bound.onReaction) {
28
+ this.deps.registry.registerMessageReaction(messageId, bound.onReaction);
29
+ }
30
+ if (bound.reactionComponent) {
31
+ await this.deps.registry.persistMessageReaction(messageId, {
32
+ ...bound.reactionComponent,
33
+ conversationKey: this.deps.conversationKey,
34
+ });
35
+ }
36
+ }
37
+ async post(ui) {
38
+ const bound = await this.bindForPost(ui);
39
+ const ref = await this.deps.adapter.post(this.deps.replyTarget, bound.root);
40
+ await this.bindReaction(ref.id, bound);
41
+ return ref;
42
+ }
43
+ async update(ref, ui) {
44
+ const bound = await this.bindForPost(ui);
45
+ await this.deps.adapter.update(ref, bound.root);
46
+ await this.bindReaction(ref.id, bound);
47
+ return ref;
48
+ }
49
+ async delete(ref) {
50
+ await this.deps.adapter.delete(ref);
51
+ }
52
+ async stream(src) {
53
+ const iter = typeof src === "string"
54
+ ? (async function* () {
55
+ yield src;
56
+ })()
57
+ : src;
58
+ return this.deps.adapter.stream(this.deps.replyTarget, iter);
59
+ }
60
+ async postFile(args) {
61
+ const adapter = this.deps.adapter;
62
+ if (!adapter.postFile) {
63
+ return {
64
+ ok: false,
65
+ error: `${this.platform} does not support file upload`,
66
+ };
67
+ }
68
+ return adapter.postFile(this.deps.replyTarget, args);
69
+ }
70
+ /** Pin suggested prompts (returns `{ ok: false }` on surfaces without support). */
71
+ async setSuggestedPrompts(prompts, opts) {
72
+ const adapter = this.deps.adapter;
73
+ if (!adapter.setSuggestedPrompts) {
74
+ return {
75
+ ok: false,
76
+ error: `${this.platform} does not support suggested prompts`,
77
+ };
78
+ }
79
+ return adapter.setSuggestedPrompts(this.deps.replyTarget, prompts, opts);
80
+ }
81
+ /** Name this conversation (returns `{ ok: false }` on surfaces without support). */
82
+ async setTitle(title) {
83
+ const adapter = this.deps.adapter;
84
+ if (!adapter.setThreadTitle) {
85
+ return {
86
+ ok: false,
87
+ error: `${this.platform} does not support thread titles`,
88
+ };
89
+ }
90
+ return adapter.setThreadTitle(this.deps.replyTarget, title);
91
+ }
92
+ /** Add an emoji reaction to a message (capability-gated; `{ ok: false }` on surfaces without support). */
93
+ async react(messageRef, emoji) {
94
+ const adapter = this.deps.adapter;
95
+ if (!adapter.addReaction) {
96
+ return {
97
+ ok: false,
98
+ error: `${this.platform} does not support reactions`,
99
+ };
100
+ }
101
+ return adapter.addReaction(this.deps.replyTarget, messageRef, emoji);
102
+ }
103
+ /** Remove the bot's emoji reaction from a message (capability-gated). */
104
+ async unreact(messageRef, emoji) {
105
+ const adapter = this.deps.adapter;
106
+ if (!adapter.removeReaction) {
107
+ return {
108
+ ok: false,
109
+ error: `${this.platform} does not support reactions`,
110
+ };
111
+ }
112
+ return adapter.removeReaction(this.deps.replyTarget, messageRef, emoji);
113
+ }
114
+ /**
115
+ * Post a message only `user` can see. `fallbackToDM` is required:
116
+ * `true` → DM the user when native ephemeral is unsupported; `false` →
117
+ * resolve to `null` when native ephemeral is unsupported.
118
+ */
119
+ async postEphemeral(user, ui, opts) {
120
+ const adapter = this.deps.adapter;
121
+ if (!adapter.postEphemeral) {
122
+ return {
123
+ ok: false,
124
+ error: `${this.platform} does not support ephemeral messages`,
125
+ };
126
+ }
127
+ // Ephemeral messages can't be reacted to, so any `onReaction` is dropped
128
+ // (stripped by bindForPost) rather than registered.
129
+ const { root } = await this.bindForPost(ui);
130
+ return adapter.postEphemeral(this.deps.replyTarget, user, root, opts);
131
+ }
132
+ // Subscription STORAGE lands here; subscription ROUTING (onSubscribedMessage) is deferred.
133
+ /** Record this conversation as subscribed (persisted in state). Proactive delivery to subscribed conversations is not yet wired. */
134
+ async subscribe() {
135
+ await this.store.kv.set(`sub:${this.deps.conversationKey}`, true);
136
+ }
137
+ /** Remove the subscription for this conversation. */
138
+ async unsubscribe() {
139
+ await this.store.kv.delete(`sub:${this.deps.conversationKey}`);
140
+ }
141
+ /** Returns true if this conversation is currently subscribed. */
142
+ async isSubscribed() {
143
+ return ((await this.store.kv.get(`sub:${this.deps.conversationKey}`)) ===
144
+ true);
145
+ }
146
+ /** Persist arbitrary per-thread state (e.g. workflow step). */
147
+ async setState(v) {
148
+ let value = v;
149
+ if (this.deps.stateSchema) {
150
+ const r = await validateSchema(this.deps.stateSchema, v);
151
+ if (!r.ok)
152
+ throw new Error(`thread.setState: invalid state — ${r.error}`);
153
+ value = r.value;
154
+ }
155
+ await this.store.kv.set(`threadstate:${this.deps.conversationKey}`, value);
156
+ }
157
+ /** Read back per-thread state previously written with `setState`. */
158
+ async state() {
159
+ return this.store.kv.get(`threadstate:${this.deps.conversationKey}`);
160
+ }
161
+ /** Read the conversation's messages (returns `[]` when the adapter can't read history). */
162
+ async getMessages() {
163
+ return (await this.deps.adapter.getMessages?.(this.deps.replyTarget)) ?? [];
164
+ }
165
+ /** Resolve a platform user by free-form query (returns `undefined` when unsupported). */
166
+ async lookupUser(query) {
167
+ return this.deps.adapter.lookupUser?.({ query });
168
+ }
169
+ /** Post a picker and wait until an interaction in this conversation resolves it. */
170
+ async awaitChoice(ui) {
171
+ const p = new Promise((resolve) => this.deps.registerWaiter(this.deps.conversationKey, resolve));
172
+ await this.post(ui);
173
+ return p;
174
+ }
175
+ async runAgent(input) {
176
+ return this.run(undefined, input);
177
+ }
178
+ async resume(value) {
179
+ return this.run({ resume: value });
180
+ }
181
+ async run(initialResume, extra) {
182
+ const session = await this.deps.adapter.conversationStore.getOrCreate(this.deps.conversationKey, this.deps.replyTarget, this.deps.agentFactory);
183
+ // Inject an explicit user message when the input isn't in the adapter's
184
+ // reconstructed history (e.g. a slash command's args, or inbound image/file
185
+ // attachments built into multimodal content parts). A non-empty array is
186
+ // truthy, so this guard also admits multimodal prompts.
187
+ if (extra?.prompt) {
188
+ session.agent.addMessage({
189
+ id: globalThis.crypto.randomUUID(),
190
+ role: "user",
191
+ // AG-UI types `content` as `string`, but multimodal works at runtime by
192
+ // setting it to an `AgentContentPart[]` — the runtime's LLM adapter
193
+ // converts the parts to the provider's multimodal format. We cast to
194
+ // satisfy the string-typed field (bot-slack parity — it does the same
195
+ // when assigning multimodal `content` to its reconstructed messages).
196
+ content: extra.prompt,
197
+ });
198
+ }
199
+ const renderer = this.deps.adapter.createRunRenderer(this.deps.replyTarget);
200
+ // Transcript auto-bridge (step 1 + 2): inject prior cross-platform history
201
+ // as a context entry, then append the current user turn. This flag owns the
202
+ // bridge — see `runAgent`'s `transcript` doc. No-ops with one warning when
203
+ // identity/transcripts aren't configured.
204
+ const transcripts = this.deps.transcripts;
205
+ const userKey = this.deps.userKey;
206
+ let transcriptContext;
207
+ if (extra?.transcript) {
208
+ if (transcripts && userKey) {
209
+ const limit = typeof extra.transcript === "object"
210
+ ? (extra.transcript.limit ?? 20)
211
+ : 20;
212
+ // List BEFORE appending the current user turn so the current message
213
+ // isn't counted as its own "prior history".
214
+ const prior = await transcripts.list({ userKey, limit });
215
+ if (prior.length > 0) {
216
+ transcriptContext = {
217
+ description: `Prior cross-platform conversation history with this user. Current channel: ${this.platform}.`,
218
+ value: prior
219
+ .map((e) => `[${e.platform}] ${e.role}: ${e.text}`)
220
+ .join("\n"),
221
+ };
222
+ }
223
+ if (this.deps.message) {
224
+ await transcripts.append(this, this.deps.message, { userKey });
225
+ }
226
+ }
227
+ else {
228
+ warnTranscriptIgnored();
229
+ }
230
+ }
231
+ // Merge per-run context/tools (this run only) on top of the bot-level deps.
232
+ const extraTools = extra?.tools ?? [];
233
+ let tools = this.deps.tools;
234
+ let toolDescriptors = this.deps.toolDescriptors;
235
+ if (extraTools.length > 0) {
236
+ tools = new Map(this.deps.tools);
237
+ for (const t of extraTools)
238
+ tools.set(t.name, t);
239
+ toolDescriptors = [
240
+ ...this.deps.toolDescriptors,
241
+ ...toAgentToolDescriptors(extraTools),
242
+ ];
243
+ }
244
+ const context = [
245
+ ...this.deps.context,
246
+ ...(transcriptContext ? [transcriptContext] : []),
247
+ ...(extra?.context ?? []),
248
+ ];
249
+ // Snapshot the message count BEFORE the loop so we can isolate the
250
+ // assistant messages this run produced (step 4).
251
+ const messagesBefore = session.agent.messages.length;
252
+ const startedAt = Date.now();
253
+ let loopResult;
254
+ // Telemetry stage: "agent" while the run loop runs, "finalize" for the
255
+ // transcript-append + renderer.finish() steps below. A throw in either is
256
+ // reported as agent_run_failed (with the right stage) instead of being
257
+ // hidden behind an already-sent success event.
258
+ let stage = "agent";
259
+ try {
260
+ loopResult = await runAgentLoop({
261
+ agent: session.agent,
262
+ renderer,
263
+ tools,
264
+ toolDescriptors,
265
+ context,
266
+ makeToolCtx: () => ({
267
+ thread: this,
268
+ platform: this.platform,
269
+ }),
270
+ handleInterrupt: async (interrupt) => {
271
+ const h = this.deps.interruptHandlers.get(interrupt.eventName);
272
+ if (h)
273
+ await h({ payload: interrupt.value, thread: this });
274
+ },
275
+ initialResume,
276
+ });
277
+ stage = "finalize";
278
+ // Transcript auto-bridge (step 4): capture the assistant text this run
279
+ // produced and append it. Only when the bridge actually applied (transcripts
280
+ // + userKey both present and `transcript` was requested).
281
+ if (extra?.transcript && transcripts && userKey) {
282
+ const produced = session.agent.messages.slice(messagesBefore);
283
+ const text = produced
284
+ .filter((m) => m.role === "assistant" &&
285
+ typeof m.content === "string" &&
286
+ m.content.trim().length > 0)
287
+ .map((m) => m.content)
288
+ .join("\n\n");
289
+ if (text.length > 0) {
290
+ await transcripts.append(this, { role: "assistant", text }, { userKey });
291
+ }
292
+ }
293
+ // Turn-end hook: lets a renderer finalize any turn-scoped resource it kept
294
+ // open across runAgent iterations (e.g. a native streaming message). A
295
+ // no-op for renderers whose per-message streams already self-terminate, and
296
+ // for runs that were interrupted (the renderer guards that internally).
297
+ await renderer.finish?.();
298
+ }
299
+ catch (err) {
300
+ // A throw is a run failure — in the agent loop (tool-handler errors are
301
+ // swallowed inside the loop, so a throw is agent-level) or in finalization.
302
+ // `stage` distinguishes the two.
303
+ this.deps.telemetry?.capture("oss.bot.agent_run_failed", {
304
+ platform: normalizePlatform(this.platform),
305
+ errorClass: errorClass(err),
306
+ stage,
307
+ });
308
+ throw err;
309
+ }
310
+ // Emit success ONLY after the loop AND finalization both completed, so a
311
+ // late transcript/finish rejection can never follow a success event.
312
+ this.deps.telemetry?.capture("oss.bot.agent_run", {
313
+ platform: normalizePlatform(this.platform),
314
+ durationMs: Date.now() - startedAt,
315
+ toolCallCount: renderer.getCapturedToolCalls().length,
316
+ iterations: loopResult.iterations,
317
+ interrupted: loopResult.interrupted,
318
+ });
319
+ return undefined;
320
+ }
321
+ }
322
+ let transcriptWarned = false;
323
+ /** Warn once when `runAgent({ transcript })` is used without identity/transcripts configured. */
324
+ function warnTranscriptIgnored() {
325
+ if (transcriptWarned)
326
+ return;
327
+ transcriptWarned = true;
328
+ console.warn("[bot] runAgent({ transcript }) ignored — configure store.identity + store.transcripts so a userKey resolves");
329
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=thread.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thread.test.d.ts","sourceRoot":"","sources":["../src/thread.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,83 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { Thread } from "./thread.js";
3
+ import { MemoryStore } from "./state/memory-store.js";
4
+ import { FakeAdapter } from "./testing/fake-adapter.js";
5
+ import { ActionRegistry } from "./action-registry.js";
6
+ import { InMemoryActionStore } from "./action-store.js";
7
+ function makeTestThread(overrides) {
8
+ const adapter = new FakeAdapter();
9
+ const registry = new ActionRegistry({ store: new InMemoryActionStore() });
10
+ const deps = {
11
+ adapter,
12
+ replyTarget: {},
13
+ conversationKey: overrides.conversationKey ?? "c1",
14
+ registry,
15
+ agentFactory: (id) => {
16
+ throw new Error(`agentFactory not needed in this test: ${id}`);
17
+ },
18
+ tools: new Map(),
19
+ toolDescriptors: [],
20
+ context: [],
21
+ registerWaiter: () => { },
22
+ interruptHandlers: new Map(),
23
+ state: overrides.state,
24
+ };
25
+ return new Thread(deps);
26
+ }
27
+ describe("Thread.subscribe / unsubscribe / isSubscribed", () => {
28
+ it("subscribe marks the conversation as subscribed", async () => {
29
+ const state = new MemoryStore();
30
+ const thread = makeTestThread({ state, conversationKey: "c1" });
31
+ await thread.subscribe();
32
+ expect(await thread.isSubscribed()).toBe(true);
33
+ });
34
+ it("unsubscribe removes the subscription", async () => {
35
+ const state = new MemoryStore();
36
+ const thread = makeTestThread({ state, conversationKey: "c1" });
37
+ await thread.subscribe();
38
+ await thread.unsubscribe();
39
+ expect(await thread.isSubscribed()).toBe(false);
40
+ });
41
+ it("isSubscribed returns false before any subscribe call", async () => {
42
+ const state = new MemoryStore();
43
+ const thread = makeTestThread({ state, conversationKey: "c1" });
44
+ expect(await thread.isSubscribed()).toBe(false);
45
+ });
46
+ it("subscription state is keyed per conversationKey", async () => {
47
+ const state = new MemoryStore();
48
+ const t1 = makeTestThread({ state, conversationKey: "c1" });
49
+ const t2 = makeTestThread({ state, conversationKey: "c2" });
50
+ await t1.subscribe();
51
+ expect(await t1.isSubscribed()).toBe(true);
52
+ expect(await t2.isSubscribed()).toBe(false);
53
+ });
54
+ });
55
+ describe("Thread.setState / state", () => {
56
+ it("round-trips an arbitrary object", async () => {
57
+ const state = new MemoryStore();
58
+ const thread = makeTestThread({ state, conversationKey: "c1" });
59
+ await thread.setState({ step: "ask_name" });
60
+ expect(await thread.state()).toEqual({
61
+ step: "ask_name",
62
+ });
63
+ });
64
+ it("returns undefined before any setState call", async () => {
65
+ const state = new MemoryStore();
66
+ const thread = makeTestThread({ state, conversationKey: "c1" });
67
+ expect(await thread.state()).toBeUndefined();
68
+ });
69
+ it("overwrites a previous value", async () => {
70
+ const state = new MemoryStore();
71
+ const thread = makeTestThread({ state, conversationKey: "c1" });
72
+ await thread.setState({ step: "ask_name" });
73
+ await thread.setState({ step: "confirm" });
74
+ expect(await thread.state()).toEqual({ step: "confirm" });
75
+ });
76
+ it("state is keyed per conversationKey", async () => {
77
+ const state = new MemoryStore();
78
+ const t1 = makeTestThread({ state, conversationKey: "c1" });
79
+ const t2 = makeTestThread({ state, conversationKey: "c2" });
80
+ await t1.setState({ v: 1 });
81
+ expect(await t2.state()).toBeUndefined();
82
+ });
83
+ });
@@ -0,0 +1,67 @@
1
+ import type { InferSchemaOutput, ObjectSchema } from "./standard-schema.js";
2
+ import { validateSchema } from "./standard-schema.js";
3
+ import type { Thread, IncomingMessage, PlatformUser } from "@copilotkit/channels-ui";
4
+ export type { ObjectSchema } from "./standard-schema.js";
5
+ export interface BotToolContext {
6
+ thread: Thread;
7
+ message?: IncomingMessage;
8
+ user?: PlatformUser;
9
+ signal?: AbortSignal;
10
+ platform: string;
11
+ }
12
+ export type BotTool<Schema extends ObjectSchema = ObjectSchema> = {
13
+ name: string;
14
+ description: string;
15
+ parameters: Schema;
16
+ /**
17
+ * Run the tool. The returned value is what the **agent (LLM)** reads back as
18
+ * the tool result — not the end user.
19
+ *
20
+ * Return any value: a `string` is sent to the agent as-is; `null`/`undefined`
21
+ * becomes an empty string; any other value is JSON-stringified automatically
22
+ * (see {@link stringifyHandlerResult}). Do NOT hand-stringify and do NOT
23
+ * return boilerplate like `{ ok: true }`.
24
+ *
25
+ * Return something MEANINGFUL to the model:
26
+ * - a render tool (one that posts a card via `thread.post`) → a short
27
+ * natural-language confirmation (e.g. `"Displayed the issue card to the
28
+ * user."`) so the model gives a brief ack and doesn't restate the card;
29
+ * - a failure → the actual error text so the model can repair and retry;
30
+ * - a data tool → the data itself (return the raw object/array — the SDK
31
+ * serializes it for you).
32
+ */
33
+ handler(args: InferSchemaOutput<Schema>, ctx: BotToolContext): Promise<unknown> | unknown;
34
+ };
35
+ /**
36
+ * Define a {@link BotTool} with full type inference. The handler's `args` are
37
+ * inferred from `parameters`, and `ctx` is the generic {@link BotToolContext}
38
+ * ({@link Thread} + optional message/user/signal + platform). Reach for
39
+ * platform power via capability-gated `thread` methods (e.g.
40
+ * `thread.getMessages()`, `thread.lookupUser(query)`).
41
+ *
42
+ * ```ts
43
+ * const tool = defineBotTool({
44
+ * name: "show_thing",
45
+ * description: "...",
46
+ * parameters: z.object({ id: z.string() }),
47
+ * async handler({ id }, { thread }) { // `id` and `ctx` fully typed
48
+ * await thread.post(<Thing id={id} />);
49
+ * return "Displayed the thing.";
50
+ * },
51
+ * });
52
+ * ```
53
+ */
54
+ export declare function defineBotTool<Schema extends ObjectSchema>(tool: BotTool<Schema>): BotTool<Schema>;
55
+ export interface ContextEntry {
56
+ description: string;
57
+ value: string;
58
+ }
59
+ export interface AgentToolDescriptor {
60
+ name: string;
61
+ description: string;
62
+ parameters: Record<string, unknown>;
63
+ }
64
+ export declare function toAgentToolDescriptors(tools: ReadonlyArray<BotTool>): AgentToolDescriptor[];
65
+ export declare const parseToolArgs: typeof validateSchema;
66
+ export declare function stringifyHandlerResult(value: unknown): string;
67
+ //# sourceMappingURL=tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAC5E,OAAO,EAAgB,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,KAAK,EACV,MAAM,EACN,eAAe,EACf,YAAY,EACb,MAAM,yBAAyB,CAAC;AAEjC,YAAY,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;CAClB;AACD,MAAM,MAAM,OAAO,CAAC,MAAM,SAAS,YAAY,GAAG,YAAY,IAAI;IAChE,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB;;;;;;;;;;;;;;;;OAgBG;IACH,OAAO,CACL,IAAI,EAAE,iBAAiB,CAAC,MAAM,CAAC,EAC/B,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;CAC/B,CAAC;AAEF;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,aAAa,CAAC,MAAM,SAAS,YAAY,EACvD,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,GACpB,OAAO,CAAC,MAAM,CAAC,CAEjB;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;CACf;AACD,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAED,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,GAC5B,mBAAmB,EAAE,CAMvB;AACD,eAAO,MAAM,aAAa,uBAAiB,CAAC;AAC5C,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAI7D"}