@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.
- package/LICENSE +21 -0
- package/README.md +204 -0
- package/dist/action-registry.d.ts +59 -0
- package/dist/action-registry.d.ts.map +1 -0
- package/dist/action-registry.js +217 -0
- package/dist/action-registry.test.d.ts +2 -0
- package/dist/action-registry.test.d.ts.map +1 -0
- package/dist/action-registry.test.js +115 -0
- package/dist/action-store.d.ts +21 -0
- package/dist/action-store.d.ts.map +1 -0
- package/dist/action-store.js +23 -0
- package/dist/action-store.test.d.ts +2 -0
- package/dist/action-store.test.d.ts.map +1 -0
- package/dist/action-store.test.js +27 -0
- package/dist/codec.d.ts +25 -0
- package/dist/codec.d.ts.map +1 -0
- package/dist/codec.js +1 -0
- package/dist/commands.d.ts +73 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +38 -0
- package/dist/commands.test.d.ts +2 -0
- package/dist/commands.test.d.ts.map +1 -0
- package/dist/commands.test.js +23 -0
- package/dist/create-bot.d.ts +171 -0
- package/dist/create-bot.d.ts.map +1 -0
- package/dist/create-bot.foundations.test.d.ts +2 -0
- package/dist/create-bot.foundations.test.d.ts.map +1 -0
- package/dist/create-bot.foundations.test.js +147 -0
- package/dist/create-bot.js +576 -0
- package/dist/create-bot.test.d.ts +2 -0
- package/dist/create-bot.test.d.ts.map +1 -0
- package/dist/create-bot.test.js +936 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/mint-id.d.ts +3 -0
- package/dist/mint-id.d.ts.map +1 -0
- package/dist/mint-id.js +20 -0
- package/dist/mint-id.test.d.ts +2 -0
- package/dist/mint-id.test.d.ts.map +1 -0
- package/dist/mint-id.test.js +16 -0
- package/dist/modal-submit.test.d.ts +2 -0
- package/dist/modal-submit.test.d.ts.map +1 -0
- package/dist/modal-submit.test.js +68 -0
- package/dist/platform-adapter.d.ts +312 -0
- package/dist/platform-adapter.d.ts.map +1 -0
- package/dist/platform-adapter.js +1 -0
- package/dist/platform-adapter.test.d.ts +2 -0
- package/dist/platform-adapter.test.d.ts.map +1 -0
- package/dist/platform-adapter.test.js +40 -0
- package/dist/reactions.test.d.ts +2 -0
- package/dist/reactions.test.d.ts.map +1 -0
- package/dist/reactions.test.js +197 -0
- package/dist/run-loop.d.ts +41 -0
- package/dist/run-loop.d.ts.map +1 -0
- package/dist/run-loop.js +102 -0
- package/dist/run-loop.test.d.ts +2 -0
- package/dist/run-loop.test.d.ts.map +1 -0
- package/dist/run-loop.test.js +125 -0
- package/dist/standard-schema.d.ts +52 -0
- package/dist/standard-schema.d.ts.map +1 -0
- package/dist/standard-schema.js +66 -0
- package/dist/state/duration.d.ts +3 -0
- package/dist/state/duration.d.ts.map +1 -0
- package/dist/state/duration.js +16 -0
- package/dist/state/duration.test.d.ts +2 -0
- package/dist/state/duration.test.d.ts.map +1 -0
- package/dist/state/duration.test.js +13 -0
- package/dist/state/kv-action-store.d.ts +7 -0
- package/dist/state/kv-action-store.d.ts.map +1 -0
- package/dist/state/kv-action-store.js +9 -0
- package/dist/state/kv-action-store.test.d.ts +2 -0
- package/dist/state/kv-action-store.test.d.ts.map +1 -0
- package/dist/state/kv-action-store.test.js +21 -0
- package/dist/state/memory-store.d.ts +41 -0
- package/dist/state/memory-store.d.ts.map +1 -0
- package/dist/state/memory-store.js +110 -0
- package/dist/state/memory-store.test.d.ts +2 -0
- package/dist/state/memory-store.test.d.ts.map +1 -0
- package/dist/state/memory-store.test.js +22 -0
- package/dist/state/state-conversation-store.d.ts +14 -0
- package/dist/state/state-conversation-store.d.ts.map +1 -0
- package/dist/state/state-conversation-store.js +22 -0
- package/dist/state/state-conversation-store.test.d.ts +2 -0
- package/dist/state/state-conversation-store.test.d.ts.map +1 -0
- package/dist/state/state-conversation-store.test.js +58 -0
- package/dist/state/state-store.d.ts +63 -0
- package/dist/state/state-store.d.ts.map +1 -0
- package/dist/state/state-store.js +1 -0
- package/dist/telemetry/bot-telemetry.d.ts +31 -0
- package/dist/telemetry/bot-telemetry.d.ts.map +1 -0
- package/dist/telemetry/bot-telemetry.js +70 -0
- package/dist/telemetry/bot-telemetry.test.d.ts +2 -0
- package/dist/telemetry/bot-telemetry.test.d.ts.map +1 -0
- package/dist/telemetry/bot-telemetry.test.js +56 -0
- package/dist/telemetry/create-bot-telemetry.test.d.ts +2 -0
- package/dist/telemetry/create-bot-telemetry.test.d.ts.map +1 -0
- package/dist/telemetry/create-bot-telemetry.test.js +71 -0
- package/dist/telemetry/e2e-telemetry.test.d.ts +2 -0
- package/dist/telemetry/e2e-telemetry.test.d.ts.map +1 -0
- package/dist/telemetry/e2e-telemetry.test.js +56 -0
- package/dist/telemetry/events-catalog.test.d.ts +2 -0
- package/dist/telemetry/events-catalog.test.d.ts.map +1 -0
- package/dist/telemetry/events-catalog.test.js +8 -0
- package/dist/telemetry/install-id.d.ts +8 -0
- package/dist/telemetry/install-id.d.ts.map +1 -0
- package/dist/telemetry/install-id.js +43 -0
- package/dist/telemetry/install-id.test.d.ts +2 -0
- package/dist/telemetry/install-id.test.d.ts.map +1 -0
- package/dist/telemetry/install-id.test.js +43 -0
- package/dist/telemetry/platform-allowlist-coverage.test.d.ts +2 -0
- package/dist/telemetry/platform-allowlist-coverage.test.d.ts.map +1 -0
- package/dist/telemetry/platform-allowlist-coverage.test.js +45 -0
- package/dist/telemetry/sanitize-error.d.ts +3 -0
- package/dist/telemetry/sanitize-error.d.ts.map +1 -0
- package/dist/telemetry/sanitize-error.js +31 -0
- package/dist/telemetry/sanitize-error.test.d.ts +2 -0
- package/dist/telemetry/sanitize-error.test.d.ts.map +1 -0
- package/dist/telemetry/sanitize-error.test.js +33 -0
- package/dist/testing/fake-adapter.d.ts +137 -0
- package/dist/testing/fake-adapter.d.ts.map +1 -0
- package/dist/testing/fake-adapter.js +273 -0
- package/dist/testing/fake-agent.d.ts +28 -0
- package/dist/testing/fake-agent.d.ts.map +1 -0
- package/dist/testing/fake-agent.js +36 -0
- package/dist/testing/state-store-conformance.d.ts +4 -0
- package/dist/testing/state-store-conformance.d.ts.map +1 -0
- package/dist/testing/state-store-conformance.js +117 -0
- package/dist/thread-capabilities.test.d.ts +2 -0
- package/dist/thread-capabilities.test.d.ts.map +1 -0
- package/dist/thread-capabilities.test.js +77 -0
- package/dist/thread-ephemeral.test.d.ts +2 -0
- package/dist/thread-ephemeral.test.d.ts.map +1 -0
- package/dist/thread-ephemeral.test.js +45 -0
- package/dist/thread-reactions.test.d.ts +2 -0
- package/dist/thread-reactions.test.d.ts.map +1 -0
- package/dist/thread-reactions.test.js +38 -0
- package/dist/thread.d.ts +152 -0
- package/dist/thread.d.ts.map +1 -0
- package/dist/thread.js +329 -0
- package/dist/thread.test.d.ts +2 -0
- package/dist/thread.test.d.ts.map +1 -0
- package/dist/thread.test.js +83 -0
- package/dist/tools.d.ts +67 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +38 -0
- package/dist/tools.test.d.ts +2 -0
- package/dist/tools.test.d.ts.map +1 -0
- package/dist/tools.test.js +31 -0
- package/dist/transcripts.d.ts +52 -0
- package/dist/transcripts.d.ts.map +1 -0
- package/dist/transcripts.js +67 -0
- package/dist/transcripts.test.d.ts +2 -0
- package/dist/transcripts.test.d.ts.map +1 -0
- package/dist/transcripts.test.js +108 -0
- package/package.json +72 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const key = (id) => `action:${id}`;
|
|
2
|
+
/** Back the legacy ActionStore shape with state.kv. Durable iff `state` is durable. */
|
|
3
|
+
export function kvActionStore(state, opts) {
|
|
4
|
+
return {
|
|
5
|
+
put: (id, snap, ttlMs) => state.kv.set(key(id), snap, ttlMs ?? opts?.defaultTtlMs),
|
|
6
|
+
get: (id) => state.kv.get(key(id)),
|
|
7
|
+
delete: (id) => state.kv.delete(key(id)),
|
|
8
|
+
};
|
|
9
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kv-action-store.test.d.ts","sourceRoot":"","sources":["../../src/state/kv-action-store.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { MemoryStore } from "./memory-store.js";
|
|
3
|
+
import { kvActionStore } from "./kv-action-store.js";
|
|
4
|
+
describe("kvActionStore", () => {
|
|
5
|
+
it("put/get/delete a snapshot via state.kv", async () => {
|
|
6
|
+
const state = new MemoryStore();
|
|
7
|
+
const store = kvActionStore(state);
|
|
8
|
+
const snap = {
|
|
9
|
+
component: "Card",
|
|
10
|
+
props: { x: 1 },
|
|
11
|
+
path: [0, "onClick"],
|
|
12
|
+
conversationKey: "c",
|
|
13
|
+
};
|
|
14
|
+
await store.put("ck:abc", snap);
|
|
15
|
+
expect(await store.get("ck:abc")).toEqual(snap);
|
|
16
|
+
// It is actually stored under the action: namespace in kv.
|
|
17
|
+
expect(await state.kv.get("action:ck:abc")).toEqual(snap);
|
|
18
|
+
await store.delete("ck:abc");
|
|
19
|
+
expect(await store.get("ck:abc")).toBeUndefined();
|
|
20
|
+
});
|
|
21
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { StateStore } from "./state-store.js";
|
|
2
|
+
export declare class MemoryStore implements StateStore {
|
|
3
|
+
private kvMap;
|
|
4
|
+
private lists;
|
|
5
|
+
private locks;
|
|
6
|
+
private queues;
|
|
7
|
+
kv: {
|
|
8
|
+
get: <T>(key: string) => Promise<T | undefined>;
|
|
9
|
+
set: <T>(key: string, value: T, ttlMs?: number) => Promise<void>;
|
|
10
|
+
delete: (key: string) => Promise<void>;
|
|
11
|
+
};
|
|
12
|
+
list: {
|
|
13
|
+
append: <T>(key: string, value: T, opts?: {
|
|
14
|
+
maxLen?: number;
|
|
15
|
+
ttlMs?: number;
|
|
16
|
+
}) => Promise<number>;
|
|
17
|
+
range: <T>(key: string, start?: number, stop?: number) => Promise<T[]>;
|
|
18
|
+
trim: (key: string, maxLen: number) => Promise<void>;
|
|
19
|
+
delete: (key: string) => Promise<void>;
|
|
20
|
+
};
|
|
21
|
+
lock: {
|
|
22
|
+
acquire: (key: string, opts?: {
|
|
23
|
+
ttlMs?: number;
|
|
24
|
+
}) => Promise<{
|
|
25
|
+
token: string;
|
|
26
|
+
} | null>;
|
|
27
|
+
release: (key: string, token: string) => Promise<void>;
|
|
28
|
+
};
|
|
29
|
+
dedup: {
|
|
30
|
+
seen: (key: string, ttlMs: number) => Promise<boolean>;
|
|
31
|
+
};
|
|
32
|
+
queue: {
|
|
33
|
+
enqueue: <T>(key: string, value: T, opts?: {
|
|
34
|
+
maxSize?: number;
|
|
35
|
+
onFull?: "drop-oldest" | "drop-newest";
|
|
36
|
+
}) => Promise<number>;
|
|
37
|
+
dequeue: <T>(key: string) => Promise<T | undefined>;
|
|
38
|
+
depth: (key: string) => Promise<number>;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=memory-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-store.d.ts","sourceRoot":"","sources":["../../src/state/memory-store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAQnD,qBAAa,WAAY,YAAW,UAAU;IAC5C,OAAO,CAAC,KAAK,CAAwC;IACrD,OAAO,CAAC,KAAK,CAA0C;IACvD,OAAO,CAAC,KAAK,CAA4D;IACzE,OAAO,CAAC,MAAM,CAAgC;IAE9C,EAAE;cACY,CAAC,OAAO,MAAM,KAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;cAQvC,CAAC,OAAO,MAAM,SAAS,CAAC,UAAU,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;sBAMhD,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;MAG1C;IAEF,IAAI;iBACa,CAAC,OACT,MAAM,SACJ,CAAC,SACD;YAAE,MAAM,CAAC,EAAE,MAAM,CAAC;YAAC,KAAK,CAAC,EAAE,MAAM,CAAA;SAAE,KACzC,OAAO,CAAC,MAAM,CAAC;gBAYJ,CAAC,OAAO,MAAM,yBAAoB,MAAM,KAAG,OAAO,CAAC,CAAC,EAAE,CAAC;oBASnD,MAAM,UAAU,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;sBAMpC,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;MAG1C;IAEF,IAAI;uBAEK,MAAM,SACJ;YAAE,KAAK,CAAC,EAAE,MAAM,CAAA;SAAE,KACxB,OAAO,CAAC;YAAE,KAAK,EAAE,MAAM,CAAA;SAAE,GAAG,IAAI,CAAC;uBAWf,MAAM,SAAS,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;MAI1D;IAEF,KAAK;oBACe,MAAM,SAAS,MAAM,KAAG,OAAO,CAAC,OAAO,CAAC;MAO1D;IAEF,KAAK;kBACa,CAAC,OACV,MAAM,SACJ,CAAC,SACD;YAAE,OAAO,CAAC,EAAE,MAAM,CAAC;YAAC,MAAM,CAAC,EAAE,aAAa,GAAG,aAAa,CAAA;SAAE,KAClE,OAAO,CAAC,MAAM,CAAC;kBAaF,CAAC,OAAO,MAAM,KAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;qBAIpC,MAAM,KAAG,OAAO,CAAC,MAAM,CAAC;MAE3C;CACH"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
const DEFAULT_LOCK_TTL_MS = 30_000;
|
|
3
|
+
const live = (e) => !!e && (e.expiresAt === undefined || Date.now() <= e.expiresAt);
|
|
4
|
+
export class MemoryStore {
|
|
5
|
+
kvMap = new Map();
|
|
6
|
+
lists = new Map();
|
|
7
|
+
locks = new Map();
|
|
8
|
+
queues = new Map();
|
|
9
|
+
kv = {
|
|
10
|
+
get: async (key) => {
|
|
11
|
+
const e = this.kvMap.get(key);
|
|
12
|
+
if (!live(e)) {
|
|
13
|
+
this.kvMap.delete(key);
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
return e.value;
|
|
17
|
+
},
|
|
18
|
+
set: async (key, value, ttlMs) => {
|
|
19
|
+
this.kvMap.set(key, {
|
|
20
|
+
value,
|
|
21
|
+
expiresAt: ttlMs ? Date.now() + ttlMs : undefined,
|
|
22
|
+
});
|
|
23
|
+
},
|
|
24
|
+
delete: async (key) => {
|
|
25
|
+
this.kvMap.delete(key);
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
list = {
|
|
29
|
+
append: async (key, value, opts) => {
|
|
30
|
+
const e = this.lists.get(key);
|
|
31
|
+
const arr = live(e) ? e.value : [];
|
|
32
|
+
arr.push(value);
|
|
33
|
+
if (opts?.maxLen && arr.length > opts.maxLen)
|
|
34
|
+
arr.splice(0, arr.length - opts.maxLen);
|
|
35
|
+
this.lists.set(key, {
|
|
36
|
+
value: arr,
|
|
37
|
+
expiresAt: opts?.ttlMs ? Date.now() + opts.ttlMs : e?.expiresAt,
|
|
38
|
+
});
|
|
39
|
+
return arr.length;
|
|
40
|
+
},
|
|
41
|
+
range: async (key, start = 0, stop) => {
|
|
42
|
+
const e = this.lists.get(key);
|
|
43
|
+
if (!live(e)) {
|
|
44
|
+
this.lists.delete(key);
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
47
|
+
const arr = e.value;
|
|
48
|
+
return arr.slice(start, stop === undefined ? undefined : stop + 1);
|
|
49
|
+
},
|
|
50
|
+
trim: async (key, maxLen) => {
|
|
51
|
+
const e = this.lists.get(key);
|
|
52
|
+
if (!live(e))
|
|
53
|
+
return;
|
|
54
|
+
const arr = e.value;
|
|
55
|
+
if (arr.length > maxLen)
|
|
56
|
+
arr.splice(0, arr.length - maxLen);
|
|
57
|
+
},
|
|
58
|
+
delete: async (key) => {
|
|
59
|
+
this.lists.delete(key);
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
lock = {
|
|
63
|
+
acquire: async (key, opts) => {
|
|
64
|
+
const cur = this.locks.get(key);
|
|
65
|
+
if (cur && (cur.expiresAt === undefined || Date.now() <= cur.expiresAt))
|
|
66
|
+
return null;
|
|
67
|
+
const token = randomUUID();
|
|
68
|
+
this.locks.set(key, {
|
|
69
|
+
token,
|
|
70
|
+
expiresAt: Date.now() + (opts?.ttlMs ?? DEFAULT_LOCK_TTL_MS),
|
|
71
|
+
});
|
|
72
|
+
return { token };
|
|
73
|
+
},
|
|
74
|
+
release: async (key, token) => {
|
|
75
|
+
const cur = this.locks.get(key);
|
|
76
|
+
if (cur?.token === token)
|
|
77
|
+
this.locks.delete(key);
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
dedup = {
|
|
81
|
+
seen: async (key, ttlMs) => {
|
|
82
|
+
const k = `dedup:${key}`;
|
|
83
|
+
const e = this.kvMap.get(k);
|
|
84
|
+
if (live(e))
|
|
85
|
+
return true;
|
|
86
|
+
this.kvMap.set(k, { value: 1, expiresAt: Date.now() + ttlMs });
|
|
87
|
+
return false;
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
queue = {
|
|
91
|
+
enqueue: async (key, value, opts) => {
|
|
92
|
+
const arr = this.queues.get(key) ?? [];
|
|
93
|
+
if (opts?.maxSize && arr.length >= opts.maxSize) {
|
|
94
|
+
if ((opts.onFull ?? "drop-oldest") === "drop-newest") {
|
|
95
|
+
this.queues.set(key, arr);
|
|
96
|
+
return arr.length;
|
|
97
|
+
}
|
|
98
|
+
arr.shift();
|
|
99
|
+
}
|
|
100
|
+
arr.push(value);
|
|
101
|
+
this.queues.set(key, arr);
|
|
102
|
+
return arr.length;
|
|
103
|
+
},
|
|
104
|
+
dequeue: async (key) => {
|
|
105
|
+
const arr = this.queues.get(key);
|
|
106
|
+
return arr && arr.length ? arr.shift() : undefined;
|
|
107
|
+
},
|
|
108
|
+
depth: async (key) => this.queues.get(key)?.length ?? 0,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-store.test.d.ts","sourceRoot":"","sources":["../../src/state/memory-store.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from "vitest";
|
|
2
|
+
import { runStateStoreConformance } from "../testing/state-store-conformance.js";
|
|
3
|
+
import { MemoryStore } from "./memory-store.js";
|
|
4
|
+
runStateStoreConformance("MemoryStore", () => new MemoryStore());
|
|
5
|
+
describe("MemoryStore lock default TTL", () => {
|
|
6
|
+
it("auto-expires a no-ttl lock after the 30s default (not immortal)", async () => {
|
|
7
|
+
vi.useFakeTimers();
|
|
8
|
+
try {
|
|
9
|
+
const s = new MemoryStore();
|
|
10
|
+
const a = await s.lock.acquire("k"); // no ttlMs
|
|
11
|
+
expect(a).not.toBeNull();
|
|
12
|
+
vi.advanceTimersByTime(29_000);
|
|
13
|
+
expect(await s.lock.acquire("k")).toBeNull(); // still held before 30s
|
|
14
|
+
vi.advanceTimersByTime(2_000); // now past 30s
|
|
15
|
+
const b = await s.lock.acquire("k");
|
|
16
|
+
expect(b).not.toBeNull(); // expired -> re-acquirable
|
|
17
|
+
}
|
|
18
|
+
finally {
|
|
19
|
+
vi.useRealTimers();
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ConversationStore } from "../platform-adapter.js";
|
|
2
|
+
import type { StateStore } from "./state-store.js";
|
|
3
|
+
/**
|
|
4
|
+
* A {@link ConversationStore} backed by `StateStore.kv`.
|
|
5
|
+
*
|
|
6
|
+
* Persists the `conversationKey → threadId` mapping under the key
|
|
7
|
+
* `conv:<conversationKey>`, so the same stable agent thread is reused across
|
|
8
|
+
* process restarts and multiple instances sharing the same store backend.
|
|
9
|
+
* Agent instances are still created per-process via `makeAgent`.
|
|
10
|
+
*/
|
|
11
|
+
export declare function createStateBackedConversationStore(state: StateStore, opts?: {
|
|
12
|
+
idTtlMs?: number;
|
|
13
|
+
}): ConversationStore;
|
|
14
|
+
//# sourceMappingURL=state-conversation-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state-conversation-store.d.ts","sourceRoot":"","sources":["../../src/state/state-conversation-store.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,iBAAiB,EAGlB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD;;;;;;;GAOG;AACH,wBAAgB,kCAAkC,CAChD,KAAK,EAAE,UAAU,EACjB,IAAI,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAC1B,iBAAiB,CAgBnB"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
/**
|
|
3
|
+
* A {@link ConversationStore} backed by `StateStore.kv`.
|
|
4
|
+
*
|
|
5
|
+
* Persists the `conversationKey → threadId` mapping under the key
|
|
6
|
+
* `conv:<conversationKey>`, so the same stable agent thread is reused across
|
|
7
|
+
* process restarts and multiple instances sharing the same store backend.
|
|
8
|
+
* Agent instances are still created per-process via `makeAgent`.
|
|
9
|
+
*/
|
|
10
|
+
export function createStateBackedConversationStore(state, opts) {
|
|
11
|
+
return {
|
|
12
|
+
async getOrCreate(conversationKey, _replyTarget, makeAgent) {
|
|
13
|
+
const k = `conv:${conversationKey}`;
|
|
14
|
+
let threadId = await state.kv.get(k);
|
|
15
|
+
if (!threadId) {
|
|
16
|
+
threadId = randomUUID();
|
|
17
|
+
await state.kv.set(k, threadId, opts?.idTtlMs);
|
|
18
|
+
}
|
|
19
|
+
return { agent: makeAgent(threadId) };
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state-conversation-store.test.d.ts","sourceRoot":"","sources":["../../src/state/state-conversation-store.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { MemoryStore } from "./memory-store.js";
|
|
3
|
+
import { createStateBackedConversationStore } from "./state-conversation-store.js";
|
|
4
|
+
describe("createStateBackedConversationStore", () => {
|
|
5
|
+
it("two stores sharing one MemoryStore yield the same persisted threadId", async () => {
|
|
6
|
+
const mem = new MemoryStore();
|
|
7
|
+
// Minimal stub — makeAgent only needs to accept a threadId; the test captures it.
|
|
8
|
+
const capturedIds = [];
|
|
9
|
+
const makeAgent = (threadId) => {
|
|
10
|
+
capturedIds.push(threadId);
|
|
11
|
+
// Return a minimal object that satisfies AbstractAgent structurally.
|
|
12
|
+
return {};
|
|
13
|
+
};
|
|
14
|
+
const store1 = createStateBackedConversationStore(mem);
|
|
15
|
+
const store2 = createStateBackedConversationStore(mem);
|
|
16
|
+
const target = {};
|
|
17
|
+
const session1 = await store1.getOrCreate("c1", target, makeAgent);
|
|
18
|
+
const session2 = await store2.getOrCreate("c1", target, makeAgent);
|
|
19
|
+
// Both calls should have reached makeAgent with the SAME threadId.
|
|
20
|
+
expect(capturedIds).toHaveLength(2);
|
|
21
|
+
expect(capturedIds[0]).toBe(capturedIds[1]);
|
|
22
|
+
// The threadId must be a valid UUID (minted on first call).
|
|
23
|
+
expect(capturedIds[0]).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/);
|
|
24
|
+
// Both sessions carry the agent returned by makeAgent.
|
|
25
|
+
expect(session1.agent).toBeDefined();
|
|
26
|
+
expect(session2.agent).toBeDefined();
|
|
27
|
+
});
|
|
28
|
+
it("different conversationKeys get distinct threadIds", async () => {
|
|
29
|
+
const mem = new MemoryStore();
|
|
30
|
+
const store = createStateBackedConversationStore(mem);
|
|
31
|
+
const target = {};
|
|
32
|
+
const ids = [];
|
|
33
|
+
const makeAgent = (threadId) => {
|
|
34
|
+
ids.push(threadId);
|
|
35
|
+
return {};
|
|
36
|
+
};
|
|
37
|
+
await store.getOrCreate("c1", target, makeAgent);
|
|
38
|
+
await store.getOrCreate("c2", target, makeAgent);
|
|
39
|
+
expect(ids).toHaveLength(2);
|
|
40
|
+
expect(ids[0]).not.toBe(ids[1]);
|
|
41
|
+
});
|
|
42
|
+
it("respects idTtlMs — expired mapping mints a new threadId", async () => {
|
|
43
|
+
const mem = new MemoryStore();
|
|
44
|
+
const store = createStateBackedConversationStore(mem, { idTtlMs: 30 });
|
|
45
|
+
const target = {};
|
|
46
|
+
const ids = [];
|
|
47
|
+
const makeAgent = (threadId) => {
|
|
48
|
+
ids.push(threadId);
|
|
49
|
+
return {};
|
|
50
|
+
};
|
|
51
|
+
await store.getOrCreate("c1", target, makeAgent);
|
|
52
|
+
// Wait for the TTL to expire.
|
|
53
|
+
await new Promise((r) => setTimeout(r, 60));
|
|
54
|
+
await store.getOrCreate("c1", target, makeAgent);
|
|
55
|
+
expect(ids).toHaveLength(2);
|
|
56
|
+
expect(ids[0]).not.toBe(ids[1]);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pluggable persistence interface for the bot runtime.
|
|
3
|
+
*
|
|
4
|
+
* **JSON-serialization contract**: all values round-trip through
|
|
5
|
+
* `JSON.stringify` / `JSON.parse` on remote backends (Redis, Postgres), so `T`
|
|
6
|
+
* must be JSON-serializable. Non-JSON values (Date, Map, class instances) will
|
|
7
|
+
* not survive on those backends. MemoryStore preserves them by reference — a
|
|
8
|
+
* backend divergence to be aware of when writing tests that run against both.
|
|
9
|
+
*/
|
|
10
|
+
export interface StateStore {
|
|
11
|
+
kv: {
|
|
12
|
+
get<T>(key: string): Promise<T | undefined>;
|
|
13
|
+
set<T>(key: string, value: T, ttlMs?: number): Promise<void>;
|
|
14
|
+
delete(key: string): Promise<void>;
|
|
15
|
+
};
|
|
16
|
+
list: {
|
|
17
|
+
/**
|
|
18
|
+
* Append to a capped list; returns new length.
|
|
19
|
+
* When `ttlMs` is given, (re)sets the whole list's expiry; otherwise the
|
|
20
|
+
* existing expiry is preserved.
|
|
21
|
+
*/
|
|
22
|
+
append<T>(key: string, value: T, opts?: {
|
|
23
|
+
maxLen?: number;
|
|
24
|
+
ttlMs?: number;
|
|
25
|
+
}): Promise<number>;
|
|
26
|
+
/**
|
|
27
|
+
* Oldest-first range; defaults to the whole list.
|
|
28
|
+
* Indices are non-negative only; negative indices are not supported
|
|
29
|
+
* (behavior is backend-specific).
|
|
30
|
+
*/
|
|
31
|
+
range<T>(key: string, start?: number, stop?: number): Promise<T[]>;
|
|
32
|
+
trim(key: string, maxLen: number): Promise<void>;
|
|
33
|
+
delete(key: string): Promise<void>;
|
|
34
|
+
};
|
|
35
|
+
lock: {
|
|
36
|
+
/**
|
|
37
|
+
* Returns a release token, or null if already held.
|
|
38
|
+
* When `ttlMs` is omitted, the lock auto-expires after a default window
|
|
39
|
+
* (30_000 ms) so a crashed holder can't deadlock the key. All backends
|
|
40
|
+
* apply the same default.
|
|
41
|
+
*/
|
|
42
|
+
acquire(key: string, opts?: {
|
|
43
|
+
ttlMs?: number;
|
|
44
|
+
}): Promise<{
|
|
45
|
+
token: string;
|
|
46
|
+
} | null>;
|
|
47
|
+
/** No-op if the token no longer owns the lock. */
|
|
48
|
+
release(key: string, token: string): Promise<void>;
|
|
49
|
+
};
|
|
50
|
+
dedup: {
|
|
51
|
+
/** Atomically record `key`; returns true if it was ALREADY seen within ttl. */
|
|
52
|
+
seen(key: string, ttlMs: number): Promise<boolean>;
|
|
53
|
+
};
|
|
54
|
+
queue: {
|
|
55
|
+
enqueue<T>(key: string, value: T, opts?: {
|
|
56
|
+
maxSize?: number;
|
|
57
|
+
onFull?: "drop-oldest" | "drop-newest";
|
|
58
|
+
}): Promise<number>;
|
|
59
|
+
dequeue<T>(key: string): Promise<T | undefined>;
|
|
60
|
+
depth(key: string): Promise<number>;
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=state-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state-store.d.ts","sourceRoot":"","sources":["../../src/state/state-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE;QACF,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;QAC5C,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAC7D,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;KACpC,CAAC;IACF,IAAI,EAAE;QACJ;;;;WAIG;QACH,MAAM,CAAC,CAAC,EACN,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,CAAC,EACR,IAAI,CAAC,EAAE;YAAE,MAAM,CAAC,EAAE,MAAM,CAAC;YAAC,KAAK,CAAC,EAAE,MAAM,CAAA;SAAE,GACzC,OAAO,CAAC,MAAM,CAAC,CAAC;QACnB;;;;WAIG;QACH,KAAK,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;QACnE,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QACjD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;KACpC,CAAC;IACF,IAAI,EAAE;QACJ;;;;;WAKG;QACH,OAAO,CACL,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE;YAAE,KAAK,CAAC,EAAE,MAAM,CAAA;SAAE,GACxB,OAAO,CAAC;YAAE,KAAK,EAAE,MAAM,CAAA;SAAE,GAAG,IAAI,CAAC,CAAC;QACrC,kDAAkD;QAClD,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;KACpD,CAAC;IACF,KAAK,EAAE;QACL,+EAA+E;QAC/E,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;KACpD,CAAC;IACF,KAAK,EAAE;QACL,OAAO,CAAC,CAAC,EACP,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,CAAC,EACR,IAAI,CAAC,EAAE;YAAE,OAAO,CAAC,EAAE,MAAM,CAAC;YAAC,MAAM,CAAC,EAAE,aAAa,GAAG,aAAa,CAAA;SAAE,GAClE,OAAO,CAAC,MAAM,CAAC,CAAC;QACnB,OAAO,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;QAChD,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;KACrC,CAAC;CACH"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { LambdaSendOptions } from "@copilotkit/shared";
|
|
2
|
+
import type { StateStore } from "../state/state-store.js";
|
|
3
|
+
export declare const BOT_TELEMETRY_EVENTS: readonly ["oss.bot.configured", "oss.bot.started", "oss.bot.start_failed", "oss.bot.agent_run", "oss.bot.agent_run_failed"];
|
|
4
|
+
export type BotTelemetryEvent = (typeof BOT_TELEMETRY_EVENTS)[number];
|
|
5
|
+
export declare function isTestEnv(): boolean;
|
|
6
|
+
export declare function resolveEnvironment(): string;
|
|
7
|
+
export interface BotTelemetryOptions {
|
|
8
|
+
backend: StateStore;
|
|
9
|
+
packageName: string;
|
|
10
|
+
packageVersion: string;
|
|
11
|
+
environment?: string;
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
sessionId?: string;
|
|
14
|
+
send?: (o: LambdaSendOptions) => Promise<void>;
|
|
15
|
+
resolveId?: () => Promise<string>;
|
|
16
|
+
}
|
|
17
|
+
export declare class BotTelemetry {
|
|
18
|
+
private readonly opts;
|
|
19
|
+
private readonly disabled;
|
|
20
|
+
private readonly sendFn;
|
|
21
|
+
private readonly sessionId;
|
|
22
|
+
private readonly environment;
|
|
23
|
+
private readonly resolveId;
|
|
24
|
+
private idPromise?;
|
|
25
|
+
private static disclosed;
|
|
26
|
+
constructor(opts: BotTelemetryOptions);
|
|
27
|
+
capture(event: BotTelemetryEvent, properties: Record<string, unknown>): void;
|
|
28
|
+
private disclose;
|
|
29
|
+
private dispatch;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=bot-telemetry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bot-telemetry.d.ts","sourceRoot":"","sources":["../../src/telemetry/bot-telemetry.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAG1D,eAAO,MAAM,oBAAoB,6HAMvB,CAAC;AACX,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEtE,wBAAgB,SAAS,IAAI,OAAO,CAGnC;AAED,wBAAgB,kBAAkB,IAAI,MAAM,CAI3C;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,UAAU,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,iBAAiB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;CACnC;AAED,qBAAa,YAAY;IASX,OAAO,CAAC,QAAQ,CAAC,IAAI;IARjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAU;IACnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0C;IACjE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAwB;IAClD,OAAO,CAAC,SAAS,CAAC,CAAkB;IACpC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAS;gBAEJ,IAAI,EAAE,mBAAmB;IAStD,OAAO,CAAC,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAM5E,OAAO,CAAC,QAAQ;YAQF,QAAQ;CAsBvB"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { lambdaClient, isTelemetryDisabled } from "@copilotkit/shared";
|
|
2
|
+
import { resolveInstallId } from "./install-id.js";
|
|
3
|
+
export const BOT_TELEMETRY_EVENTS = [
|
|
4
|
+
"oss.bot.configured",
|
|
5
|
+
"oss.bot.started",
|
|
6
|
+
"oss.bot.start_failed",
|
|
7
|
+
"oss.bot.agent_run",
|
|
8
|
+
"oss.bot.agent_run_failed",
|
|
9
|
+
];
|
|
10
|
+
export function isTestEnv() {
|
|
11
|
+
const env = process.env;
|
|
12
|
+
return env.NODE_ENV === "test" || !!env.VITEST || !!env.JEST_WORKER_ID;
|
|
13
|
+
}
|
|
14
|
+
export function resolveEnvironment() {
|
|
15
|
+
const e = (process.env.NODE_ENV ?? "").toLowerCase();
|
|
16
|
+
if (e === "production" || e === "development" || e === "test")
|
|
17
|
+
return e;
|
|
18
|
+
return "unknown";
|
|
19
|
+
}
|
|
20
|
+
export class BotTelemetry {
|
|
21
|
+
opts;
|
|
22
|
+
disabled;
|
|
23
|
+
sendFn;
|
|
24
|
+
sessionId;
|
|
25
|
+
environment;
|
|
26
|
+
resolveId;
|
|
27
|
+
idPromise;
|
|
28
|
+
static disclosed = false;
|
|
29
|
+
constructor(opts) {
|
|
30
|
+
this.opts = opts;
|
|
31
|
+
this.disabled = opts.disabled ?? (isTelemetryDisabled() || isTestEnv());
|
|
32
|
+
this.sendFn = opts.send ?? lambdaClient.send;
|
|
33
|
+
this.sessionId = opts.sessionId ?? globalThis.crypto.randomUUID();
|
|
34
|
+
this.environment = opts.environment ?? resolveEnvironment();
|
|
35
|
+
this.resolveId =
|
|
36
|
+
opts.resolveId ?? (() => resolveInstallId({ backend: opts.backend }));
|
|
37
|
+
}
|
|
38
|
+
capture(event, properties) {
|
|
39
|
+
if (this.disabled)
|
|
40
|
+
return;
|
|
41
|
+
this.disclose();
|
|
42
|
+
void this.dispatch(event, properties);
|
|
43
|
+
}
|
|
44
|
+
disclose() {
|
|
45
|
+
if (BotTelemetry.disclosed)
|
|
46
|
+
return;
|
|
47
|
+
BotTelemetry.disclosed = true;
|
|
48
|
+
console.info("[CopilotKit Bot] anonymous telemetry enabled — see https://docs.copilotkit.ai/telemetry to opt out (set COPILOTKIT_TELEMETRY_DISABLED=true).");
|
|
49
|
+
}
|
|
50
|
+
async dispatch(event, properties) {
|
|
51
|
+
try {
|
|
52
|
+
this.idPromise ??= this.resolveId();
|
|
53
|
+
const anonymous_id = await this.idPromise;
|
|
54
|
+
await this.sendFn({
|
|
55
|
+
event,
|
|
56
|
+
properties,
|
|
57
|
+
globalProperties: {
|
|
58
|
+
anonymous_id,
|
|
59
|
+
bot_session_id: this.sessionId,
|
|
60
|
+
environment: this.environment,
|
|
61
|
+
},
|
|
62
|
+
packageName: this.opts.packageName,
|
|
63
|
+
packageVersion: this.opts.packageVersion,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
/* best-effort: telemetry must not break the host app */
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bot-telemetry.test.d.ts","sourceRoot":"","sources":["../../src/telemetry/bot-telemetry.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from "vitest";
|
|
2
|
+
import { BotTelemetry, BOT_TELEMETRY_EVENTS } from "./bot-telemetry.js";
|
|
3
|
+
import { MemoryStore } from "../state/memory-store.js";
|
|
4
|
+
const tick = () => new Promise((r) => setTimeout(r, 0));
|
|
5
|
+
const base = {
|
|
6
|
+
backend: new MemoryStore(),
|
|
7
|
+
packageName: "@copilotkit/channels",
|
|
8
|
+
packageVersion: "0.0.3",
|
|
9
|
+
};
|
|
10
|
+
describe("BotTelemetry", () => {
|
|
11
|
+
it("sends event with anonymous_id + bot_session_id in global_properties", async () => {
|
|
12
|
+
const send = vi.fn().mockResolvedValue(undefined);
|
|
13
|
+
const t = new BotTelemetry({
|
|
14
|
+
...base,
|
|
15
|
+
disabled: false,
|
|
16
|
+
send,
|
|
17
|
+
sessionId: "S1",
|
|
18
|
+
resolveId: async () => "ANON",
|
|
19
|
+
});
|
|
20
|
+
t.capture("oss.bot.configured", { platforms: ["slack"] });
|
|
21
|
+
await tick();
|
|
22
|
+
expect(send).toHaveBeenCalledTimes(1);
|
|
23
|
+
const arg = send.mock.calls[0][0];
|
|
24
|
+
expect(arg.event).toBe("oss.bot.configured");
|
|
25
|
+
expect(arg.properties).toEqual({ platforms: ["slack"] });
|
|
26
|
+
expect(arg.globalProperties.anonymous_id).toBe("ANON");
|
|
27
|
+
expect(arg.globalProperties.bot_session_id).toBe("S1");
|
|
28
|
+
});
|
|
29
|
+
it("is a no-op when disabled", async () => {
|
|
30
|
+
const send = vi.fn();
|
|
31
|
+
const t = new BotTelemetry({ ...base, disabled: true, send });
|
|
32
|
+
t.capture("oss.bot.started", {});
|
|
33
|
+
await tick();
|
|
34
|
+
expect(send).not.toHaveBeenCalled();
|
|
35
|
+
});
|
|
36
|
+
it("never throws when send rejects", async () => {
|
|
37
|
+
const send = vi.fn().mockRejectedValue(new Error("boom"));
|
|
38
|
+
const t = new BotTelemetry({
|
|
39
|
+
...base,
|
|
40
|
+
disabled: false,
|
|
41
|
+
send,
|
|
42
|
+
resolveId: async () => "X",
|
|
43
|
+
});
|
|
44
|
+
expect(() => t.capture("oss.bot.agent_run", {})).not.toThrow();
|
|
45
|
+
await tick();
|
|
46
|
+
});
|
|
47
|
+
it("exposes the five event names", () => {
|
|
48
|
+
expect([...BOT_TELEMETRY_EVENTS].sort()).toEqual([
|
|
49
|
+
"oss.bot.agent_run",
|
|
50
|
+
"oss.bot.agent_run_failed",
|
|
51
|
+
"oss.bot.configured",
|
|
52
|
+
"oss.bot.start_failed",
|
|
53
|
+
"oss.bot.started",
|
|
54
|
+
]);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-bot-telemetry.test.d.ts","sourceRoot":"","sources":["../../src/telemetry/create-bot-telemetry.test.ts"],"names":[],"mappings":""}
|