@operor/copilot 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/dist/index.d.ts +282 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +708 -0
- package/dist/index.js.map +1 -0
- package/package.json +32 -0
- package/src/CopilotCommandHandler.ts +263 -0
- package/src/DigestScheduler.ts +76 -0
- package/src/InMemoryCopilotStore.ts +90 -0
- package/src/QueryClusterer.ts +84 -0
- package/src/SQLiteCopilotStore.ts +300 -0
- package/src/SuggestionEngine.ts +44 -0
- package/src/UnansweredQueryTracker.ts +83 -0
- package/src/__tests__/copilot.test.ts +1007 -0
- package/src/index.ts +8 -0
- package/src/types.ts +131 -0
- package/tsconfig.json +9 -0
- package/tsdown.config.ts +10 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import { KnowledgeBaseRuntime } from "@operor/core";
|
|
2
|
+
|
|
3
|
+
//#region src/types.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Training Copilot types
|
|
6
|
+
*/
|
|
7
|
+
/** Status of an unanswered query through the review lifecycle */
|
|
8
|
+
type QueryStatus = 'pending' | 'taught' | 'dismissed';
|
|
9
|
+
/** A customer query that the KB couldn't confidently answer */
|
|
10
|
+
interface UnansweredQuery {
|
|
11
|
+
id: string;
|
|
12
|
+
query: string;
|
|
13
|
+
normalizedQuery: string;
|
|
14
|
+
channel: string;
|
|
15
|
+
customerPhone: string;
|
|
16
|
+
kbTopScore: number;
|
|
17
|
+
kbIsFaqMatch: boolean;
|
|
18
|
+
kbTopChunkContent?: string;
|
|
19
|
+
kbResultCount: number;
|
|
20
|
+
status: QueryStatus;
|
|
21
|
+
clusterId?: string;
|
|
22
|
+
timesAsked: number;
|
|
23
|
+
uniqueCustomers: string[];
|
|
24
|
+
embedding?: number[];
|
|
25
|
+
suggestedAnswer?: string;
|
|
26
|
+
taughtAnswer?: string;
|
|
27
|
+
createdAt: number;
|
|
28
|
+
updatedAt: number;
|
|
29
|
+
}
|
|
30
|
+
/** A cluster of semantically similar unanswered queries */
|
|
31
|
+
interface QueryCluster {
|
|
32
|
+
id: string;
|
|
33
|
+
label?: string;
|
|
34
|
+
representativeQuery: string;
|
|
35
|
+
centroid?: number[];
|
|
36
|
+
queryCount: number;
|
|
37
|
+
uniqueCustomers: string[];
|
|
38
|
+
status: QueryStatus;
|
|
39
|
+
createdAt: number;
|
|
40
|
+
updatedAt: number;
|
|
41
|
+
}
|
|
42
|
+
/** Aggregate metrics for the copilot dashboard / digest */
|
|
43
|
+
interface ImpactMetrics {
|
|
44
|
+
pendingCount: number;
|
|
45
|
+
taughtCount: number;
|
|
46
|
+
dismissedCount: number;
|
|
47
|
+
totalCustomersAffected: number;
|
|
48
|
+
totalTimesAsked: number;
|
|
49
|
+
topPendingQueries: UnansweredQuery[];
|
|
50
|
+
}
|
|
51
|
+
/** Configuration for the copilot subsystem */
|
|
52
|
+
interface CopilotConfig {
|
|
53
|
+
enabled: boolean;
|
|
54
|
+
trackingThreshold: number;
|
|
55
|
+
clusterThreshold: number;
|
|
56
|
+
digestIntervalMs: number;
|
|
57
|
+
digestMaxItems: number;
|
|
58
|
+
autoSuggest: boolean;
|
|
59
|
+
}
|
|
60
|
+
/** Default copilot configuration values */
|
|
61
|
+
declare const DEFAULT_COPILOT_CONFIG: CopilotConfig;
|
|
62
|
+
/** Embedding service interface — decouples copilot from specific embedding providers */
|
|
63
|
+
interface EmbeddingService {
|
|
64
|
+
embed(text: string): Promise<number[]>;
|
|
65
|
+
dimensions: number;
|
|
66
|
+
}
|
|
67
|
+
/** AI provider interface for suggestion generation */
|
|
68
|
+
interface AIProviderLike {
|
|
69
|
+
generateText(options: {
|
|
70
|
+
model?: string;
|
|
71
|
+
system?: string;
|
|
72
|
+
prompt: string;
|
|
73
|
+
maxTokens?: number;
|
|
74
|
+
temperature?: number;
|
|
75
|
+
}): Promise<{
|
|
76
|
+
text: string;
|
|
77
|
+
}>;
|
|
78
|
+
}
|
|
79
|
+
/** Store interface for copilot persistence */
|
|
80
|
+
interface CopilotStore {
|
|
81
|
+
initialize(): Promise<void>;
|
|
82
|
+
close(): Promise<void>;
|
|
83
|
+
addQuery(query: UnansweredQuery): Promise<void>;
|
|
84
|
+
getQuery(id: string): Promise<UnansweredQuery | null>;
|
|
85
|
+
updateQuery(id: string, updates: Partial<UnansweredQuery>): Promise<void>;
|
|
86
|
+
getPendingQueries(limit?: number): Promise<UnansweredQuery[]>;
|
|
87
|
+
findSimilarQuery(normalizedQuery: string): Promise<UnansweredQuery | null>;
|
|
88
|
+
getQueriesByCluster(clusterId: string): Promise<UnansweredQuery[]>;
|
|
89
|
+
addCluster(cluster: QueryCluster): Promise<void>;
|
|
90
|
+
getCluster(id: string): Promise<QueryCluster | null>;
|
|
91
|
+
updateCluster(id: string, updates: Partial<QueryCluster>): Promise<void>;
|
|
92
|
+
getOpenClusters(): Promise<QueryCluster[]>;
|
|
93
|
+
getImpactMetrics(topN?: number): Promise<ImpactMetrics>;
|
|
94
|
+
getLastDigestTime(): Promise<number>;
|
|
95
|
+
setLastDigestTime(time: number): Promise<void>;
|
|
96
|
+
}
|
|
97
|
+
/** Event emitted after a message is processed by the agent pipeline */
|
|
98
|
+
interface MessageProcessedEvent {
|
|
99
|
+
query: string;
|
|
100
|
+
channel: string;
|
|
101
|
+
customerPhone: string;
|
|
102
|
+
response: {
|
|
103
|
+
text: string;
|
|
104
|
+
metadata?: {
|
|
105
|
+
kbTopScore?: number;
|
|
106
|
+
kbIsFaqMatch?: boolean;
|
|
107
|
+
kbTopChunkContent?: string;
|
|
108
|
+
kbResultCount?: number;
|
|
109
|
+
};
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
//#endregion
|
|
113
|
+
//#region src/SQLiteCopilotStore.d.ts
|
|
114
|
+
/**
|
|
115
|
+
* SQLite-backed copilot store with sqlite-vec for vector search on cluster centroids.
|
|
116
|
+
*/
|
|
117
|
+
declare class SQLiteCopilotStore implements CopilotStore {
|
|
118
|
+
private dbPath;
|
|
119
|
+
private dimensions;
|
|
120
|
+
private db;
|
|
121
|
+
constructor(dbPath: string, dimensions: number);
|
|
122
|
+
initialize(): Promise<void>;
|
|
123
|
+
close(): Promise<void>;
|
|
124
|
+
addQuery(query: UnansweredQuery): Promise<void>;
|
|
125
|
+
getQuery(id: string): Promise<UnansweredQuery | null>;
|
|
126
|
+
updateQuery(id: string, updates: Partial<UnansweredQuery>): Promise<void>;
|
|
127
|
+
getPendingQueries(limit?: number): Promise<UnansweredQuery[]>;
|
|
128
|
+
findSimilarQuery(normalizedQuery: string): Promise<UnansweredQuery | null>;
|
|
129
|
+
getQueriesByCluster(clusterId: string): Promise<UnansweredQuery[]>;
|
|
130
|
+
addCluster(cluster: QueryCluster): Promise<void>;
|
|
131
|
+
getCluster(id: string): Promise<QueryCluster | null>;
|
|
132
|
+
updateCluster(id: string, updates: Partial<QueryCluster>): Promise<void>;
|
|
133
|
+
getOpenClusters(): Promise<QueryCluster[]>;
|
|
134
|
+
/** Vector search cluster centroids — returns closest clusters by cosine distance */
|
|
135
|
+
searchClusters(embedding: number[], limit: number): Promise<Array<{
|
|
136
|
+
clusterId: string;
|
|
137
|
+
distance: number;
|
|
138
|
+
}>>;
|
|
139
|
+
getImpactMetrics(topN?: number): Promise<ImpactMetrics>;
|
|
140
|
+
getLastDigestTime(): Promise<number>;
|
|
141
|
+
setLastDigestTime(time: number): Promise<void>;
|
|
142
|
+
private rowToQuery;
|
|
143
|
+
private rowToCluster;
|
|
144
|
+
}
|
|
145
|
+
//#endregion
|
|
146
|
+
//#region src/InMemoryCopilotStore.d.ts
|
|
147
|
+
/**
|
|
148
|
+
* In-memory copilot store for testing and development.
|
|
149
|
+
*/
|
|
150
|
+
declare class InMemoryCopilotStore implements CopilotStore {
|
|
151
|
+
private queries;
|
|
152
|
+
private clusters;
|
|
153
|
+
private lastDigestTime;
|
|
154
|
+
initialize(): Promise<void>;
|
|
155
|
+
close(): Promise<void>;
|
|
156
|
+
addQuery(query: UnansweredQuery): Promise<void>;
|
|
157
|
+
getQuery(id: string): Promise<UnansweredQuery | null>;
|
|
158
|
+
updateQuery(id: string, updates: Partial<UnansweredQuery>): Promise<void>;
|
|
159
|
+
getPendingQueries(limit?: number): Promise<UnansweredQuery[]>;
|
|
160
|
+
findSimilarQuery(normalizedQuery: string): Promise<UnansweredQuery | null>;
|
|
161
|
+
getQueriesByCluster(clusterId: string): Promise<UnansweredQuery[]>;
|
|
162
|
+
addCluster(cluster: QueryCluster): Promise<void>;
|
|
163
|
+
getCluster(id: string): Promise<QueryCluster | null>;
|
|
164
|
+
updateCluster(id: string, updates: Partial<QueryCluster>): Promise<void>;
|
|
165
|
+
getOpenClusters(): Promise<QueryCluster[]>;
|
|
166
|
+
getImpactMetrics(topN?: number): Promise<ImpactMetrics>;
|
|
167
|
+
getLastDigestTime(): Promise<number>;
|
|
168
|
+
setLastDigestTime(time: number): Promise<void>;
|
|
169
|
+
}
|
|
170
|
+
//#endregion
|
|
171
|
+
//#region src/QueryClusterer.d.ts
|
|
172
|
+
/**
|
|
173
|
+
* Groups semantically similar unanswered queries into clusters.
|
|
174
|
+
*/
|
|
175
|
+
declare class QueryClusterer {
|
|
176
|
+
private store;
|
|
177
|
+
private embedder;
|
|
178
|
+
private config;
|
|
179
|
+
constructor(store: CopilotStore, embedder: EmbeddingService, config?: {
|
|
180
|
+
clusterThreshold: number;
|
|
181
|
+
});
|
|
182
|
+
/**
|
|
183
|
+
* Assign a query to an existing cluster or create a new one.
|
|
184
|
+
* Returns the cluster ID.
|
|
185
|
+
*/
|
|
186
|
+
assignCluster(queryId: string, queryText: string, embedding: number[]): Promise<string>;
|
|
187
|
+
/** Cosine similarity between two vectors */
|
|
188
|
+
cosineSimilarity(a: number[], b: number[]): number;
|
|
189
|
+
/** Compute running average centroid */
|
|
190
|
+
updateCentroid(current: number[], newVec: number[], count: number): number[];
|
|
191
|
+
}
|
|
192
|
+
//#endregion
|
|
193
|
+
//#region src/UnansweredQueryTracker.d.ts
|
|
194
|
+
/**
|
|
195
|
+
* Tracks unanswered queries by listening to message:processed events.
|
|
196
|
+
* Runs non-blocking — errors are caught and logged, never thrown.
|
|
197
|
+
*/
|
|
198
|
+
declare class UnansweredQueryTracker {
|
|
199
|
+
private store;
|
|
200
|
+
private config;
|
|
201
|
+
private embedder;
|
|
202
|
+
private clusterer?;
|
|
203
|
+
constructor(store: CopilotStore, config: {
|
|
204
|
+
enabled: boolean;
|
|
205
|
+
trackingThreshold: number;
|
|
206
|
+
}, embedder: EmbeddingService, clusterer?: QueryClusterer | undefined);
|
|
207
|
+
/**
|
|
208
|
+
* Called after each message is processed. Decides whether to track the query.
|
|
209
|
+
* Non-blocking: catches all errors internally.
|
|
210
|
+
*/
|
|
211
|
+
maybeTrack(event: MessageProcessedEvent): Promise<void>;
|
|
212
|
+
/** Normalize query text for deduplication */
|
|
213
|
+
normalizeQuery(text: string): string;
|
|
214
|
+
}
|
|
215
|
+
//#endregion
|
|
216
|
+
//#region src/SuggestionEngine.d.ts
|
|
217
|
+
/**
|
|
218
|
+
* Generates suggested answers for unanswered queries using the LLM + KB context.
|
|
219
|
+
*/
|
|
220
|
+
declare class SuggestionEngine {
|
|
221
|
+
private aiProvider;
|
|
222
|
+
private kb;
|
|
223
|
+
constructor(aiProvider: AIProviderLike, kb: KnowledgeBaseRuntime);
|
|
224
|
+
/**
|
|
225
|
+
* Generate a suggested answer for a query, optionally including related queries from a cluster.
|
|
226
|
+
*/
|
|
227
|
+
suggest(query: string, relatedQueries?: string[]): Promise<string>;
|
|
228
|
+
}
|
|
229
|
+
//#endregion
|
|
230
|
+
//#region src/CopilotCommandHandler.d.ts
|
|
231
|
+
/**
|
|
232
|
+
* Handles /review commands from admin users in training mode.
|
|
233
|
+
*/
|
|
234
|
+
declare class CopilotCommandHandler {
|
|
235
|
+
private store;
|
|
236
|
+
private suggestionEngine;
|
|
237
|
+
private kb;
|
|
238
|
+
private clusterer?;
|
|
239
|
+
/** Per-admin session state: tracks which query they're currently reviewing */
|
|
240
|
+
private sessions;
|
|
241
|
+
constructor(store: CopilotStore, suggestionEngine: SuggestionEngine | undefined, kb: KnowledgeBaseRuntime, clusterer?: QueryClusterer | undefined);
|
|
242
|
+
/**
|
|
243
|
+
* Handle a /review subcommand.
|
|
244
|
+
* @param command The full command (always '/review')
|
|
245
|
+
* @param args Subcommand + arguments (e.g. 'accept This is the answer')
|
|
246
|
+
* @param adminPhone The admin's phone number
|
|
247
|
+
* @param reply Function to send a reply back to the admin
|
|
248
|
+
*/
|
|
249
|
+
handleCommand(command: string, args: string, adminPhone: string, reply: (text: string) => Promise<void>): Promise<void>;
|
|
250
|
+
private getSession;
|
|
251
|
+
private handleNext;
|
|
252
|
+
private handleAccept;
|
|
253
|
+
private handleEdit;
|
|
254
|
+
private handleSkip;
|
|
255
|
+
private handleStats;
|
|
256
|
+
private handleCluster;
|
|
257
|
+
private handleHelp;
|
|
258
|
+
}
|
|
259
|
+
//#endregion
|
|
260
|
+
//#region src/DigestScheduler.d.ts
|
|
261
|
+
/**
|
|
262
|
+
* Periodically sends digest summaries of unanswered queries to admin phones.
|
|
263
|
+
*/
|
|
264
|
+
declare class DigestScheduler {
|
|
265
|
+
private store;
|
|
266
|
+
private config;
|
|
267
|
+
private sendMessage;
|
|
268
|
+
private timer;
|
|
269
|
+
constructor(store: CopilotStore, config: {
|
|
270
|
+
digestIntervalMs: number;
|
|
271
|
+
digestMaxItems: number;
|
|
272
|
+
}, sendMessage: (phone: string, text: string) => Promise<void>);
|
|
273
|
+
/** Start the digest scheduler for the given admin phones */
|
|
274
|
+
start(adminPhones: string[]): void;
|
|
275
|
+
/** Stop the digest scheduler */
|
|
276
|
+
stop(): void;
|
|
277
|
+
/** Build the digest message text */
|
|
278
|
+
buildDigest(): Promise<string | null>;
|
|
279
|
+
}
|
|
280
|
+
//#endregion
|
|
281
|
+
export { AIProviderLike, CopilotCommandHandler, CopilotConfig, CopilotStore, DEFAULT_COPILOT_CONFIG, DigestScheduler, EmbeddingService, ImpactMetrics, InMemoryCopilotStore, MessageProcessedEvent, QueryCluster, QueryClusterer, QueryStatus, SQLiteCopilotStore, SuggestionEngine, UnansweredQuery, UnansweredQueryTracker };
|
|
282
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/SQLiteCopilotStore.ts","../src/InMemoryCopilotStore.ts","../src/QueryClusterer.ts","../src/UnansweredQueryTracker.ts","../src/SuggestionEngine.ts","../src/CopilotCommandHandler.ts","../src/DigestScheduler.ts"],"mappings":"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"}
|