@copilotkit/bot 0.0.2 → 0.0.3
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/dist/action-registry.d.ts +6 -0
- package/dist/action-registry.d.ts.map +1 -1
- package/dist/action-registry.js +38 -4
- package/dist/action-registry.test.js +20 -8
- package/dist/create-bot.d.ts.map +1 -1
- package/dist/create-bot.js +11 -3
- package/dist/create-bot.test.js +80 -0
- package/dist/platform-adapter.d.ts +16 -1
- package/dist/platform-adapter.d.ts.map +1 -1
- package/dist/testing/fake-adapter.d.ts.map +1 -1
- package/dist/testing/fake-adapter.js +7 -0
- package/dist/thread.d.ts +5 -3
- package/dist/thread.d.ts.map +1 -1
- package/dist/thread.js +13 -1
- package/package.json +4 -4
|
@@ -15,6 +15,12 @@ export declare class ActionRegistry {
|
|
|
15
15
|
bindTree(componentName: string, props: Record<string, unknown>, conversationKey: string): Promise<BotNode[]>;
|
|
16
16
|
bindRenderable(ui: Renderable, conversationKey: string): Promise<BotNode[]>;
|
|
17
17
|
private walk;
|
|
18
|
+
/**
|
|
19
|
+
* Run the click handler for `id` and return the clicked element's `value`
|
|
20
|
+
* (so callers can resolve a HITL `awaitChoice` waiter even when the platform
|
|
21
|
+
* couldn't carry the value in its callback payload). Returns `undefined` when
|
|
22
|
+
* the element has no `value`.
|
|
23
|
+
*/
|
|
18
24
|
dispatch(id: string, ctx: InteractionContext): Promise<unknown>;
|
|
19
25
|
}
|
|
20
26
|
//# sourceMappingURL=action-registry.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action-registry.d.ts","sourceRoot":"","sources":["../src/action-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EAEP,kBAAkB,EAClB,WAAW,EACX,UAAU,EACX,MAAM,oBAAoB,CAAC;AAG5B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,EAAE,EAAE,MAAM;CAIvB;AAcD,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAAc;IAC3B,OAAO,CAAC,UAAU,CAAkC;
|
|
1
|
+
{"version":3,"file":"action-registry.d.ts","sourceRoot":"","sources":["../src/action-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EAEP,kBAAkB,EAClB,WAAW,EACX,UAAU,EACX,MAAM,oBAAoB,CAAC;AAG5B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,EAAE,EAAE,MAAM;CAIvB;AAcD,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAAc;IAC3B,OAAO,CAAC,UAAU,CAAkC;IAKpD,OAAO,CAAC,GAAG,CAAgE;gBAE/D,IAAI,EAAE;QAAE,KAAK,EAAE,WAAW,CAAA;KAAE;IAIxC,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,WAAW,GAAG,IAAI;IAItD,aAAa,IAAI,IAAI;IAMf,QAAQ,CACZ,aAAa,EAAE,MAAM,EACrB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,OAAO,EAAE,CAAC;IAYf,cAAc,CAClB,EAAE,EAAE,UAAU,EACd,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,OAAO,EAAE,CAAC;YAgBP,IAAI;IA0ClB;;;;;OAKG;IACG,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,kBAAkB,GAAG,OAAO,CAAC,OAAO,CAAC;CAsBtE"}
|
package/dist/action-registry.js
CHANGED
|
@@ -15,6 +15,10 @@ function isComponentElement(ui) {
|
|
|
15
15
|
export class ActionRegistry {
|
|
16
16
|
store;
|
|
17
17
|
components = new Map();
|
|
18
|
+
// Cache the handler AND the element's `value` per minted id. The value is
|
|
19
|
+
// needed to resolve HITL `awaitChoice` waiters on platforms whose callback
|
|
20
|
+
// payload can't carry it (e.g. Telegram's 64-byte callback_data only holds
|
|
21
|
+
// the action id), where `evt.value` arrives undefined.
|
|
18
22
|
hot = new Map();
|
|
19
23
|
constructor(opts) {
|
|
20
24
|
this.store = opts.store;
|
|
@@ -58,7 +62,10 @@ export class ActionRegistry {
|
|
|
58
62
|
if (typeof handler === "function") {
|
|
59
63
|
const fullPath = [...path, ep];
|
|
60
64
|
const id = mintId(comp, fullPath, props);
|
|
61
|
-
this.hot.set(id,
|
|
65
|
+
this.hot.set(id, {
|
|
66
|
+
handler: handler,
|
|
67
|
+
value: node.props.value,
|
|
68
|
+
});
|
|
62
69
|
await this.store.put(id, {
|
|
63
70
|
component: comp,
|
|
64
71
|
props,
|
|
@@ -75,9 +82,21 @@ export class ActionRegistry {
|
|
|
75
82
|
}
|
|
76
83
|
}
|
|
77
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* Run the click handler for `id` and return the clicked element's `value`
|
|
87
|
+
* (so callers can resolve a HITL `awaitChoice` waiter even when the platform
|
|
88
|
+
* couldn't carry the value in its callback payload). Returns `undefined` when
|
|
89
|
+
* the element has no `value`.
|
|
90
|
+
*/
|
|
78
91
|
async dispatch(id, ctx) {
|
|
79
|
-
let handler
|
|
80
|
-
|
|
92
|
+
let handler;
|
|
93
|
+
let value;
|
|
94
|
+
const hot = this.hot.get(id);
|
|
95
|
+
if (hot) {
|
|
96
|
+
handler = hot.handler;
|
|
97
|
+
value = hot.value;
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
81
100
|
const snap = await this.store.get(id);
|
|
82
101
|
if (!snap || !snap.component)
|
|
83
102
|
throw new ActionExpiredError(id);
|
|
@@ -86,11 +105,26 @@ export class ActionRegistry {
|
|
|
86
105
|
throw new ActionExpiredError(id);
|
|
87
106
|
const tree = renderToIR(fn(snap.props));
|
|
88
107
|
handler = pluck(tree, snap.path);
|
|
108
|
+
value = pluckValue(tree, snap.path);
|
|
89
109
|
if (!handler)
|
|
90
110
|
throw new ActionExpiredError(id);
|
|
91
111
|
}
|
|
92
|
-
|
|
112
|
+
await handler({ ...ctx, action: { ...ctx.action, id } });
|
|
113
|
+
return value;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/** Navigate to the node owning the event-prop at `path` and read its `value`. */
|
|
117
|
+
function pluckValue(tree, path) {
|
|
118
|
+
let cur = tree;
|
|
119
|
+
for (const seg of path.slice(0, -1)) {
|
|
120
|
+
if (Array.isArray(cur))
|
|
121
|
+
cur = cur[seg];
|
|
122
|
+
else if (cur && typeof cur === "object")
|
|
123
|
+
cur = cur.props?.[seg];
|
|
124
|
+
else
|
|
125
|
+
return undefined;
|
|
93
126
|
}
|
|
127
|
+
return cur?.props?.value;
|
|
94
128
|
}
|
|
95
129
|
function pluck(tree, path) {
|
|
96
130
|
let cur = tree;
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
1
|
+
import { describe, it, expect, beforeEach } from "vitest";
|
|
2
2
|
import { ActionRegistry, ActionExpiredError } from "./action-registry.js";
|
|
3
3
|
import { InMemoryActionStore } from "./action-store.js";
|
|
4
|
+
// Records each click so a test can assert the handler ran — dispatch() now
|
|
5
|
+
// returns the clicked element's `value` (needed to resolve HITL waiters on
|
|
6
|
+
// platforms whose callback payload can't carry it), not the handler's return.
|
|
7
|
+
const clicks = [];
|
|
4
8
|
function Confirm(props) {
|
|
5
9
|
return {
|
|
6
10
|
type: "actions",
|
|
@@ -9,7 +13,10 @@ function Confirm(props) {
|
|
|
9
13
|
{
|
|
10
14
|
type: "button",
|
|
11
15
|
props: {
|
|
12
|
-
|
|
16
|
+
value: { ok: props.action },
|
|
17
|
+
onClick: ({ action }) => {
|
|
18
|
+
clicks.push(`ok:${props.action}:${action.id}`);
|
|
19
|
+
},
|
|
13
20
|
children: "Yes",
|
|
14
21
|
},
|
|
15
22
|
},
|
|
@@ -19,24 +26,29 @@ function Confirm(props) {
|
|
|
19
26
|
}
|
|
20
27
|
const ctx = {};
|
|
21
28
|
describe("ActionRegistry", () => {
|
|
22
|
-
|
|
29
|
+
beforeEach(() => {
|
|
30
|
+
clicks.length = 0;
|
|
31
|
+
});
|
|
32
|
+
it("dispatches via hot cache, runs the handler, and returns the element value", async () => {
|
|
23
33
|
const reg = new ActionRegistry({ store: new InMemoryActionStore() });
|
|
24
34
|
reg.registerComponent("Confirm", Confirm);
|
|
25
35
|
const ir = await reg.bindTree("Confirm", { action: "write" }, "conv1");
|
|
26
36
|
const button = ir[0].props.children[0];
|
|
27
37
|
const id = button.props.onClick.id;
|
|
28
38
|
expect(typeof id).toBe("string");
|
|
29
|
-
const
|
|
30
|
-
expect(
|
|
39
|
+
const value = await reg.dispatch(id, ctx);
|
|
40
|
+
expect(value).toEqual({ ok: "write" });
|
|
41
|
+
expect(clicks[0]).toContain("ok:write:");
|
|
31
42
|
});
|
|
32
|
-
it("cold path re-renders from snapshot when hot cache is cleared", async () => {
|
|
43
|
+
it("cold path re-renders from snapshot when hot cache is cleared, still returning the value", async () => {
|
|
33
44
|
const reg = new ActionRegistry({ store: new InMemoryActionStore() });
|
|
34
45
|
reg.registerComponent("Confirm", Confirm);
|
|
35
46
|
const ir = await reg.bindTree("Confirm", { action: "write" }, "conv1");
|
|
36
47
|
const id = ir[0].props.children[0].props.onClick.id;
|
|
37
48
|
reg.clearHotCache();
|
|
38
|
-
const
|
|
39
|
-
expect(
|
|
49
|
+
const value = await reg.dispatch(id, ctx);
|
|
50
|
+
expect(value).toEqual({ ok: "write" });
|
|
51
|
+
expect(clicks[0]).toContain("ok:write:");
|
|
40
52
|
});
|
|
41
53
|
it("throws ActionExpiredError on full miss", async () => {
|
|
42
54
|
const reg = new ActionRegistry({ store: new InMemoryActionStore() });
|
package/dist/create-bot.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-bot.d.ts","sourceRoot":"","sources":["../src/create-bot.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EAMhB,MAAM,uBAAuB,CAAC;AAG/B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAExD,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAChE,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,KAAK,EACV,kBAAkB,EAClB,eAAe,EACf,YAAY,EACb,MAAM,oBAAoB,CAAC;AAE5B,MAAM,MAAM,UAAU,GAAG,CAAC,GAAG,EAAE;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,eAAe,CAAC;CAC1B,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE3B,2FAA2F;AAC3F,MAAM,MAAM,kBAAkB,GAAG,CAAC,GAAG,EAAE;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,YAAY,CAAC;CACrB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE3B,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,KAAK,CAAC,EAAE,aAAa,GAAG,CAAC,CAAC,QAAQ,EAAE,MAAM,KAAK,aAAa,CAAC,CAAC;IAC9D,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC;IAClB,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;IACzB,kFAAkF;IAClF,QAAQ,CAAC,EAAE,UAAU,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,GAAG;IAClB,SAAS,CAAC,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IAC/B,SAAS,CAAC,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IAC/B;;;;OAIG;IACH,eAAe,CAAC,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAC7C,wFAAwF;IACxF,aAAa,CAAC,MAAM,GAAG,OAAO,EAC5B,EAAE,EAAE,MAAM,EACV,CAAC,EAAE,CAAC,GAAG,EAAE,kBAAkB,CAAC,MAAM,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAC3D,IAAI,CAAC;IACR;;;;OAIG;IACH,WAAW,CAAC,QAAQ,GAAG,OAAO,EAC5B,SAAS,EAAE,MAAM,EACjB,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,QAAQ,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GACvE,IAAI,CAAC;IACR,8DAA8D;IAC9D,SAAS,CAAC,OAAO,EAAE,UAAU,GAAG,IAAI,CAAC;IACrC,kDAAkD;IAClD,SAAS,CACP,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GACrD,IAAI,CAAC;IACR,IAAI,CAAC,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACvB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,gBAAgB,GAAG,GAAG,
|
|
1
|
+
{"version":3,"file":"create-bot.d.ts","sourceRoot":"","sources":["../src/create-bot.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EAMhB,MAAM,uBAAuB,CAAC;AAG/B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAExD,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAChE,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,KAAK,EACV,kBAAkB,EAClB,eAAe,EACf,YAAY,EACb,MAAM,oBAAoB,CAAC;AAE5B,MAAM,MAAM,UAAU,GAAG,CAAC,GAAG,EAAE;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,eAAe,CAAC;CAC1B,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE3B,2FAA2F;AAC3F,MAAM,MAAM,kBAAkB,GAAG,CAAC,GAAG,EAAE;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,YAAY,CAAC;CACrB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE3B,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,KAAK,CAAC,EAAE,aAAa,GAAG,CAAC,CAAC,QAAQ,EAAE,MAAM,KAAK,aAAa,CAAC,CAAC;IAC9D,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC;IAClB,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;IACzB,kFAAkF;IAClF,QAAQ,CAAC,EAAE,UAAU,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,GAAG;IAClB,SAAS,CAAC,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IAC/B,SAAS,CAAC,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IAC/B;;;;OAIG;IACH,eAAe,CAAC,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAC7C,wFAAwF;IACxF,aAAa,CAAC,MAAM,GAAG,OAAO,EAC5B,EAAE,EAAE,MAAM,EACV,CAAC,EAAE,CAAC,GAAG,EAAE,kBAAkB,CAAC,MAAM,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAC3D,IAAI,CAAC;IACR;;;;OAIG;IACH,WAAW,CAAC,QAAQ,GAAG,OAAO,EAC5B,SAAS,EAAE,MAAM,EACjB,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,QAAQ,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GACvE,IAAI,CAAC;IACR,8DAA8D;IAC9D,SAAS,CAAC,OAAO,EAAE,UAAU,GAAG,IAAI,CAAC;IACrC,kDAAkD;IAClD,SAAS,CACP,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GACrD,IAAI,CAAC;IACR,IAAI,CAAC,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACvB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,gBAAgB,GAAG,GAAG,CAqOrD"}
|
package/dist/create-bot.js
CHANGED
|
@@ -53,6 +53,7 @@ export function createBot(opts) {
|
|
|
53
53
|
const thread = makeThread(adapter, turn.replyTarget, turn.conversationKey);
|
|
54
54
|
const message = {
|
|
55
55
|
text: turn.userText,
|
|
56
|
+
contentParts: turn.contentParts,
|
|
56
57
|
user: turn.user ?? { id: "" },
|
|
57
58
|
ref: { id: "" },
|
|
58
59
|
platform: turn.platform,
|
|
@@ -81,13 +82,18 @@ export function createBot(opts) {
|
|
|
81
82
|
user,
|
|
82
83
|
platform: adapter.platform,
|
|
83
84
|
};
|
|
85
|
+
// The clicked element's `value`, recovered by the registry when it
|
|
86
|
+
// re-renders to find the handler. Used to resolve a HITL waiter on
|
|
87
|
+
// platforms whose callback payload can't carry the value (Telegram),
|
|
88
|
+
// where `evt.value` is undefined.
|
|
89
|
+
let dispatchedValue;
|
|
84
90
|
try {
|
|
85
91
|
const explicit = interactionHandlers.get(evt.id);
|
|
86
92
|
if (explicit) {
|
|
87
93
|
await explicit(ctx);
|
|
88
94
|
}
|
|
89
95
|
else {
|
|
90
|
-
await registry.dispatch(evt.id, ctx);
|
|
96
|
+
dispatchedValue = await registry.dispatch(evt.id, ctx);
|
|
91
97
|
}
|
|
92
98
|
}
|
|
93
99
|
catch (err) {
|
|
@@ -95,11 +101,13 @@ export function createBot(opts) {
|
|
|
95
101
|
if (!(err instanceof ActionExpiredError))
|
|
96
102
|
throw err;
|
|
97
103
|
}
|
|
98
|
-
// Resolve any HITL waiter awaiting a choice in this conversation.
|
|
104
|
+
// Resolve any HITL waiter awaiting a choice in this conversation. Prefer
|
|
105
|
+
// the value carried in the event (Slack), falling back to the value the
|
|
106
|
+
// registry recovered from the rendered element (Telegram).
|
|
99
107
|
const w = waiters.get(evt.conversationKey);
|
|
100
108
|
if (w) {
|
|
101
109
|
waiters.delete(evt.conversationKey);
|
|
102
|
-
w(evt.value);
|
|
110
|
+
w(evt.value !== undefined ? evt.value : dispatchedValue);
|
|
103
111
|
}
|
|
104
112
|
},
|
|
105
113
|
async onCommand(cmd) {
|
package/dist/create-bot.test.js
CHANGED
|
@@ -67,6 +67,58 @@ describe("createBot", () => {
|
|
|
67
67
|
expect(findNode(ir, "section")).toBeDefined();
|
|
68
68
|
expect(collectText(ir)).toBe("hi");
|
|
69
69
|
});
|
|
70
|
+
it("calls renderer.finish() once after a turn's run-loop resolves", async () => {
|
|
71
|
+
const fake = new FakeAdapter();
|
|
72
|
+
const agent = new FakeAgent();
|
|
73
|
+
const bot = createBot({ adapters: [fake], agent: () => agent });
|
|
74
|
+
bot.onMention(async ({ thread }) => {
|
|
75
|
+
await thread.runAgent();
|
|
76
|
+
});
|
|
77
|
+
await bot.start();
|
|
78
|
+
fake.emitTurn({ userText: "yo", conversationKey: "c1" });
|
|
79
|
+
await tick();
|
|
80
|
+
const renderer = fake.lastRunRenderer;
|
|
81
|
+
expect(renderer.finishCalls).toBe(1);
|
|
82
|
+
});
|
|
83
|
+
it("delivers a turn's contentParts as the runAgent prompt to agent.addMessage", async () => {
|
|
84
|
+
const fake = new FakeAdapter();
|
|
85
|
+
const agent = new FakeAgent();
|
|
86
|
+
// Capture what the framework injects as the user message.
|
|
87
|
+
const added = [];
|
|
88
|
+
const origAddMessage = agent.addMessage.bind(agent);
|
|
89
|
+
agent.addMessage = (m) => {
|
|
90
|
+
added.push(m);
|
|
91
|
+
return origAddMessage(m);
|
|
92
|
+
};
|
|
93
|
+
const bot = createBot({ adapters: [fake], agent: () => agent });
|
|
94
|
+
const parts = [
|
|
95
|
+
{ type: "text", text: "look" },
|
|
96
|
+
{
|
|
97
|
+
type: "image",
|
|
98
|
+
source: { type: "data", value: "QUJD", mimeType: "image/png" },
|
|
99
|
+
},
|
|
100
|
+
];
|
|
101
|
+
bot.onMention(async ({ thread, message }) => {
|
|
102
|
+
// The example mirrors this: prefer multimodal parts over plain text.
|
|
103
|
+
await thread.runAgent({
|
|
104
|
+
prompt: message.contentParts && message.contentParts.length > 0
|
|
105
|
+
? message.contentParts
|
|
106
|
+
: message.text,
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
await bot.start();
|
|
110
|
+
fake.emitTurn({
|
|
111
|
+
userText: "look",
|
|
112
|
+
conversationKey: "c1",
|
|
113
|
+
contentParts: parts,
|
|
114
|
+
});
|
|
115
|
+
await tick();
|
|
116
|
+
expect(added).toHaveLength(1);
|
|
117
|
+
const msg = added[0];
|
|
118
|
+
expect(msg.role).toBe("user");
|
|
119
|
+
// The multimodal parts array survives the string-typed `content` cast.
|
|
120
|
+
expect(msg.content).toEqual(parts);
|
|
121
|
+
});
|
|
70
122
|
it("dispatches a bound onClick handler on interaction", async () => {
|
|
71
123
|
const fake = new FakeAdapter();
|
|
72
124
|
const agent = new FakeAgent();
|
|
@@ -95,6 +147,34 @@ describe("createBot", () => {
|
|
|
95
147
|
await tick();
|
|
96
148
|
expect(clicked).toBe(true);
|
|
97
149
|
});
|
|
150
|
+
it("resolves a HITL awaitChoice with the element value when the event carries none (Telegram)", async () => {
|
|
151
|
+
const fake = new FakeAdapter();
|
|
152
|
+
const agent = new FakeAgent();
|
|
153
|
+
const bot = createBot({ adapters: [fake], agent: () => agent });
|
|
154
|
+
let chosen;
|
|
155
|
+
bot.onMention(async ({ thread }) => {
|
|
156
|
+
chosen = await thread.awaitChoice(Actions({
|
|
157
|
+
children: [
|
|
158
|
+
Button({
|
|
159
|
+
value: { confirmed: true },
|
|
160
|
+
onClick: () => { },
|
|
161
|
+
children: "Create",
|
|
162
|
+
}),
|
|
163
|
+
],
|
|
164
|
+
}));
|
|
165
|
+
});
|
|
166
|
+
await bot.start();
|
|
167
|
+
fake.emitTurn({ userText: "create a thing", conversationKey: "c1" });
|
|
168
|
+
await tick();
|
|
169
|
+
const button = findNode(fake.posted[0], "button");
|
|
170
|
+
const id = button.props.onClick.id;
|
|
171
|
+
// Telegram can't carry the button value in callback_data, so the event has
|
|
172
|
+
// no `value`. The waiter must still resolve with the button's value, which
|
|
173
|
+
// the registry recovers from the rendered element.
|
|
174
|
+
fake.emitInteraction({ id, conversationKey: "c1" });
|
|
175
|
+
await tick();
|
|
176
|
+
expect(chosen).toEqual({ confirmed: true });
|
|
177
|
+
});
|
|
98
178
|
it("merges per-turn runAgent context with the bot-level context", async () => {
|
|
99
179
|
const fake = new FakeAdapter();
|
|
100
180
|
const agent = new FakeAgent();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AgentSubscriber, AbstractAgent } from "@ag-ui/client";
|
|
2
|
-
import type { BotNode, MessageRef, PlatformUser, ThreadMessage } from "@copilotkit/bot-ui";
|
|
2
|
+
import type { AgentContentPart, BotNode, MessageRef, PlatformUser, ThreadMessage } from "@copilotkit/bot-ui";
|
|
3
3
|
import type { CommandSpec } from "./commands.js";
|
|
4
4
|
/** Opaque to the bot core — created by an adapter during ingress and passed back to post/createRunRenderer. */
|
|
5
5
|
export type ReplyTarget = unknown;
|
|
@@ -33,11 +33,26 @@ export interface RunRenderer {
|
|
|
33
33
|
getCapturedToolCalls(): readonly CapturedToolCall[];
|
|
34
34
|
getPendingInterrupt(): CapturedInterrupt | undefined;
|
|
35
35
|
clearPendingInterrupt(): void;
|
|
36
|
+
/**
|
|
37
|
+
* Optional turn-end hook. Called once after the run-loop resolves normally
|
|
38
|
+
* (no more tool calls, or an interrupt was acked), so a renderer that keeps a
|
|
39
|
+
* turn-scoped resource open across `runAgent` iterations — e.g. a single
|
|
40
|
+
* native streaming message that interleaves text and tool-progress — can
|
|
41
|
+
* finalize it. Symmetric with {@link markInterrupted}; renderers whose
|
|
42
|
+
* streams self-terminate per message simply omit it. Must be a no-op if the
|
|
43
|
+
* run was already interrupted.
|
|
44
|
+
*/
|
|
45
|
+
finish?(): Promise<void>;
|
|
36
46
|
}
|
|
37
47
|
export interface IncomingTurn {
|
|
38
48
|
conversationKey: string;
|
|
39
49
|
replyTarget: ReplyTarget;
|
|
40
50
|
userText: string;
|
|
51
|
+
/**
|
|
52
|
+
* Optional multimodal content parts built by the adapter (e.g. inbound
|
|
53
|
+
* image/file attachments). Carried through to `IncomingMessage.contentParts`.
|
|
54
|
+
*/
|
|
55
|
+
contentParts?: AgentContentPart[];
|
|
41
56
|
user?: PlatformUser;
|
|
42
57
|
platform: string;
|
|
43
58
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"platform-adapter.d.ts","sourceRoot":"","sources":["../src/platform-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACpE,OAAO,KAAK,EACV,OAAO,EACP,UAAU,EACV,YAAY,EACZ,aAAa,EACd,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD,+GAA+G;AAC/G,MAAM,MAAM,WAAW,GAAG,OAAO,CAAC;AAClC,+DAA+D;AAC/D,MAAM,MAAM,aAAa,GAAG,OAAO,CAAC;AAEpC,MAAM,WAAW,mBAAmB;IAClC,cAAc,EAAE,OAAO,CAAC;IACxB,cAAc,EAAE,OAAO,CAAC;IACxB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,4EAA4E;IAC5E,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,8DAA8D;IAC9D,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACvC;AACD,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,4HAA4H;AAC5H,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,eAAe,CAAC;IAC5B,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,oBAAoB,IAAI,SAAS,gBAAgB,EAAE,CAAC;IACpD,mBAAmB,IAAI,iBAAiB,GAAG,SAAS,CAAC;IACrD,qBAAqB,IAAI,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"platform-adapter.d.ts","sourceRoot":"","sources":["../src/platform-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fake-adapter.d.ts","sourceRoot":"","sources":["../../src/testing/fake-adapter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,OAAO,EACP,UAAU,EACV,YAAY,EACZ,aAAa,EACd,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EACV,eAAe,EACf,mBAAmB,EACnB,WAAW,EACX,YAAY,EACZ,mBAAmB,EACnB,gBAAgB,EAChB,eAAe,EACf,WAAW,EAGX,WAAW,EACX,aAAa,EACb,SAAS,EACT,iBAAiB,EAClB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD,oHAAoH;AACpH,wBAAgB,mBAAmB,IAAI,WAAW,
|
|
1
|
+
{"version":3,"file":"fake-adapter.d.ts","sourceRoot":"","sources":["../../src/testing/fake-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -16,6 +16,7 @@ export function makeFakeRunRenderer() {
|
|
|
16
16
|
pending = { eventName: e.name, value: e.value };
|
|
17
17
|
},
|
|
18
18
|
};
|
|
19
|
+
let finishCalls = 0;
|
|
19
20
|
return {
|
|
20
21
|
subscriber,
|
|
21
22
|
async markInterrupted() { },
|
|
@@ -24,6 +25,12 @@ export function makeFakeRunRenderer() {
|
|
|
24
25
|
clearPendingInterrupt: () => {
|
|
25
26
|
pending = undefined;
|
|
26
27
|
},
|
|
28
|
+
async finish() {
|
|
29
|
+
finishCalls++;
|
|
30
|
+
},
|
|
31
|
+
get finishCalls() {
|
|
32
|
+
return finishCalls;
|
|
33
|
+
},
|
|
27
34
|
};
|
|
28
35
|
}
|
|
29
36
|
export class FakeAdapter {
|
package/dist/thread.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { PlatformAdapter, ReplyTarget } from "./platform-adapter.js";
|
|
2
2
|
import type { ActionRegistry } from "./action-registry.js";
|
|
3
|
-
import type { Renderable, MessageRef, PlatformUser, ThreadMessage, Thread as ThreadInterface } from "@copilotkit/bot-ui";
|
|
3
|
+
import type { AgentContentPart, Renderable, MessageRef, PlatformUser, ThreadMessage, Thread as ThreadInterface } from "@copilotkit/bot-ui";
|
|
4
4
|
import type { BotTool, ContextEntry, AgentToolDescriptor } from "./tools.js";
|
|
5
5
|
import type { AbstractAgent } from "@ag-ui/client";
|
|
6
6
|
export interface ThreadDeps {
|
|
@@ -65,9 +65,11 @@ export declare class Thread implements ThreadInterface {
|
|
|
65
65
|
/**
|
|
66
66
|
* A user message to inject before running. Needed when the input isn't
|
|
67
67
|
* already in the conversation history the adapter reconstructs — e.g. a
|
|
68
|
-
* slash command, whose args are never posted to the channel.
|
|
68
|
+
* slash command, whose args are never posted to the channel. A
|
|
69
|
+
* `AgentContentPart[]` carries multimodal content (e.g. inbound image/file
|
|
70
|
+
* attachments) the model can read.
|
|
69
71
|
*/
|
|
70
|
-
prompt?: string;
|
|
72
|
+
prompt?: string | AgentContentPart[];
|
|
71
73
|
}): Promise<MessageRef | undefined>;
|
|
72
74
|
resume(value: unknown): Promise<MessageRef | undefined>;
|
|
73
75
|
private run;
|
package/dist/thread.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"thread.d.ts","sourceRoot":"","sources":["../src/thread.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"thread.d.ts","sourceRoot":"","sources":["../src/thread.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAC1E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EACV,gBAAgB,EAChB,UAAU,EACV,UAAU,EACV,YAAY,EACZ,aAAa,EACb,MAAM,IAAI,eAAe,EAC1B,MAAM,oBAAoB,CAAC;AAG5B,OAAO,KAAK,EACV,OAAO,EAEP,YAAY,EACZ,mBAAmB,EACpB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,eAAe,CAAC;IACzB,WAAW,EAAE,WAAW,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,cAAc,CAAC;IACzB,YAAY,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,aAAa,CAAC;IAClD,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC5B,eAAe,EAAE,mBAAmB,EAAE,CAAC;IACvC,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,cAAc,EAAE,CACd,eAAe,EAAE,MAAM,EACvB,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,KAC9B,IAAI,CAAC;IACV,iBAAiB,EAAE,GAAG,CACpB,MAAM,EACN,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CACrE,CAAC;CACH;AAED,gGAAgG;AAChG,qBAAa,MAAO,YAAW,eAAe;IAGhC,OAAO,CAAC,IAAI;IAFxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;gBAEN,IAAI,EAAE,UAAU;YAItB,WAAW;IAInB,IAAI,CAAC,EAAE,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IAOzC,MAAM,CAAC,GAAG,EAAE,UAAU,EAAE,EAAE,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IAK5D,MAAM,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAItC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC;IAUhE,QAAQ,CAAC,IAAI,EAAE;QACnB,KAAK,EAAE,UAAU,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAW7D,mFAAmF;IAC7E,mBAAmB,CACvB,OAAO,EAAE,aAAa,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,EAC1D,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GACxB,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAW3C,oFAAoF;IAC9E,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAWvE,2FAA2F;IACrF,WAAW,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;IAI7C,yFAAyF;IACnF,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC;IAIlE,oFAAoF;IAC9E,WAAW,CAAC,CAAC,GAAG,OAAO,EAAE,EAAE,EAAE,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC;IAWpD,QAAQ,CAAC,KAAK,CAAC,EAAE;QACrB,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;QACzB,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC;QAClB;;;;;;WAMG;QACH,MAAM,CAAC,EAAE,MAAM,GAAG,gBAAgB,EAAE,CAAC;KACtC,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAI7B,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;YAI/C,GAAG;CAsElB"}
|
package/dist/thread.js
CHANGED
|
@@ -84,11 +84,18 @@ export class Thread {
|
|
|
84
84
|
async run(initialResume, extra) {
|
|
85
85
|
const session = await this.deps.adapter.conversationStore.getOrCreate(this.deps.conversationKey, this.deps.replyTarget, this.deps.agentFactory);
|
|
86
86
|
// Inject an explicit user message when the input isn't in the adapter's
|
|
87
|
-
// reconstructed history (e.g. a slash command's args
|
|
87
|
+
// reconstructed history (e.g. a slash command's args, or inbound image/file
|
|
88
|
+
// attachments built into multimodal content parts). A non-empty array is
|
|
89
|
+
// truthy, so this guard also admits multimodal prompts.
|
|
88
90
|
if (extra?.prompt) {
|
|
89
91
|
session.agent.addMessage({
|
|
90
92
|
id: globalThis.crypto.randomUUID(),
|
|
91
93
|
role: "user",
|
|
94
|
+
// AG-UI types `content` as `string`, but multimodal works at runtime by
|
|
95
|
+
// setting it to an `AgentContentPart[]` — the runtime's LLM adapter
|
|
96
|
+
// converts the parts to the provider's multimodal format. We cast to
|
|
97
|
+
// satisfy the string-typed field (bot-slack parity — it does the same
|
|
98
|
+
// when assigning multimodal `content` to its reconstructed messages).
|
|
92
99
|
content: extra.prompt,
|
|
93
100
|
});
|
|
94
101
|
}
|
|
@@ -126,6 +133,11 @@ export class Thread {
|
|
|
126
133
|
},
|
|
127
134
|
initialResume,
|
|
128
135
|
});
|
|
136
|
+
// Turn-end hook: lets a renderer finalize any turn-scoped resource it kept
|
|
137
|
+
// open across runAgent iterations (e.g. a native streaming message). A
|
|
138
|
+
// no-op for renderers whose per-message streams already self-terminate, and
|
|
139
|
+
// for runs that were interrupted (the renderer guards that internally).
|
|
140
|
+
await renderer.finish?.();
|
|
129
141
|
return undefined;
|
|
130
142
|
}
|
|
131
143
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@copilotkit/bot",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "Platform-agnostic JSX bot engine for CopilotKit (createBot, Thread, PlatformAdapter, ActionStore).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -38,9 +38,9 @@
|
|
|
38
38
|
"@ag-ui/client": "0.0.57",
|
|
39
39
|
"@ag-ui/core": "0.0.57",
|
|
40
40
|
"zod-to-json-schema": "^3.24.1",
|
|
41
|
-
"@copilotkit/bot-ui": "~0.0.
|
|
42
|
-
"@copilotkit/
|
|
43
|
-
"@copilotkit/
|
|
41
|
+
"@copilotkit/bot-ui": "~0.0.3",
|
|
42
|
+
"@copilotkit/core": "^1.61.0",
|
|
43
|
+
"@copilotkit/shared": "^1.61.0"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@types/node": "^22.10.0",
|