MCPcopy
hub / github.com/CopilotKit/CopilotKit / Thread

Class Thread

packages/bot/src/thread.ts:69–480  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

67
68/** A concrete conversation thread: posts UI, runs the agent loop, and resolves HITL waiters. */
69export class Thread implements ThreadInterface {
70 readonly platform: string;
71 /** Stable key identifying this conversation (used by transcript bridging). */
72 readonly conversationKey: string;
73 private readonly store: StateStore;
74
75 constructor(private deps: ThreadDeps) {
76 this.platform = deps.adapter.platform;
77 this.conversationKey = deps.conversationKey;
78 this.store = deps.state;
79 }
80
81 private async bindForPost(ui: Renderable) {
82 return this.deps.registry.bindRenderable(ui, this.deps.conversationKey);
83 }
84
85 /**
86 * Wire a posted message's `onReaction` to its returned id: cache it for this
87 * process and, when it came from a component, persist a durable snapshot so a
88 * reaction after a restart re-derives it (parity with a component `onClick`).
89 */
90 private async bindReaction(
91 messageId: string,
92 bound: Awaited<ReturnType<Thread["bindForPost"]>>,
93 ): Promise<void> {
94 if (bound.onReaction) {
95 this.deps.registry.registerMessageReaction(messageId, bound.onReaction);
96 }
97 if (bound.reactionComponent) {
98 await this.deps.registry.persistMessageReaction(messageId, {
99 ...bound.reactionComponent,
100 conversationKey: this.deps.conversationKey,
101 });
102 }
103 }
104
105 async post(ui: Renderable): Promise<MessageRef> {
106 const bound = await this.bindForPost(ui);
107 const ref = await this.deps.adapter.post(this.deps.replyTarget, bound.root);
108 await this.bindReaction(ref.id, bound);
109 return ref;
110 }
111
112 async update(ref: MessageRef, ui: Renderable): Promise<MessageRef> {
113 const bound = await this.bindForPost(ui);
114 await this.deps.adapter.update(ref, bound.root);
115 await this.bindReaction(ref.id, bound);
116 return ref;
117 }
118
119 async delete(ref: MessageRef): Promise<void> {
120 await this.deps.adapter.delete(ref);
121 }
122
123 async stream(src: string | AsyncIterable<string>): Promise<MessageRef> {
124 const iter =
125 typeof src === "string"
126 ? (async function* () {

Callers

nothing calls this directly

Calls

no outgoing calls

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…