@framers/agentos-ext-topicality 0.1.0 → 0.2.1
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/CHANGELOG.md +18 -0
- package/dist/TopicalityGuardrail.d.ts +69 -154
- package/dist/TopicalityGuardrail.d.ts.map +1 -1
- package/dist/TopicalityGuardrail.js +229 -336
- package/dist/TopicalityGuardrail.js.map +1 -1
- package/dist/embeddings.d.ts +58 -0
- package/dist/embeddings.d.ts.map +1 -0
- package/dist/embeddings.js +79 -0
- package/dist/embeddings.js.map +1 -0
- package/dist/index.d.ts +42 -42
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +65 -160
- package/dist/index.js.map +1 -1
- package/dist/tools/CheckTopicTool.d.ts +39 -125
- package/dist/tools/CheckTopicTool.d.ts.map +1 -1
- package/dist/tools/CheckTopicTool.js +61 -168
- package/dist/tools/CheckTopicTool.js.map +1 -1
- package/dist/types.d.ts +85 -315
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +13 -202
- package/dist/types.js.map +1 -1
- package/package.json +12 -15
- package/src/TopicalityGuardrail.ts +265 -402
- package/src/embeddings.ts +84 -0
- package/src/index.ts +66 -188
- package/src/tools/CheckTopicTool.ts +73 -237
- package/src/types.ts +90 -505
- package/test/CheckTopicTool.spec.ts +271 -0
- package/test/TopicDriftTracker.spec.ts +422 -0
- package/test/TopicEmbeddingIndex.spec.ts +310 -0
- package/test/TopicalityGuardrail.spec.ts +610 -0
- package/test/index.spec.ts +312 -0
- package/tsconfig.json +18 -0
- package/vitest.config.ts +24 -0
package/src/types.ts
CHANGED
|
@@ -1,565 +1,150 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @
|
|
2
|
+
* @file types.ts
|
|
3
|
+
* @description Core type definitions for the Topicality guardrail extension pack.
|
|
3
4
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
5
|
+
* Defines the configuration interface that controls which topics are allowed
|
|
6
|
+
* or blocked, similarity thresholds, and optional LLM fallback for ambiguous
|
|
7
|
+
* cases.
|
|
6
8
|
*
|
|
7
|
-
*
|
|
8
|
-
* - {@link TopicMatch} — a similarity score between text and a topic
|
|
9
|
-
* - {@link DriftConfig} — tuning knobs for the EMA-based drift tracker
|
|
10
|
-
* - {@link DEFAULT_DRIFT_CONFIG} — out-of-the-box sensible defaults
|
|
11
|
-
* - {@link DriftResult} — output of a single drift-tracking update
|
|
12
|
-
* - {@link TopicState} — per-session mutable state kept by the tracker
|
|
13
|
-
* - {@link TopicalityPackOptions} — top-level options passed to the pack factory
|
|
14
|
-
* - {@link TOPIC_PRESETS} — ready-made topic sets for common agent profiles
|
|
15
|
-
*
|
|
16
|
-
* All types are pure data shapes (no class logic) so they can be freely
|
|
17
|
-
* serialised, logged, and passed across async boundaries.
|
|
18
|
-
*
|
|
19
|
-
* @module topicality/types
|
|
9
|
+
* @module agentos/extensions/packs/topicality/types
|
|
20
10
|
*/
|
|
21
11
|
|
|
22
12
|
// ---------------------------------------------------------------------------
|
|
23
|
-
//
|
|
13
|
+
// TopicalityOptions
|
|
24
14
|
// ---------------------------------------------------------------------------
|
|
25
15
|
|
|
26
16
|
/**
|
|
27
|
-
*
|
|
17
|
+
* Configuration object passed to `createTopicalityGuardrail()`.
|
|
28
18
|
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* robust centroid.
|
|
19
|
+
* Controls the list of allowed and blocked topics, similarity thresholds for
|
|
20
|
+
* embedding-based matching, and an optional LLM invoker for fallback
|
|
21
|
+
* classification when embeddings are unavailable or inconclusive.
|
|
33
22
|
*
|
|
34
23
|
* @example
|
|
35
|
-
* ```
|
|
36
|
-
* const
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
* 'Why was I charged twice?',
|
|
42
|
-
* 'How do I cancel my subscription?',
|
|
43
|
-
* 'Can I get a refund for last month?',
|
|
44
|
-
* ],
|
|
24
|
+
* ```typescript
|
|
25
|
+
* const opts: TopicalityOptions = {
|
|
26
|
+
* allowedTopics: ['customer support', 'billing', 'product features'],
|
|
27
|
+
* blockedTopics: ['politics', 'violence', 'gambling'],
|
|
28
|
+
* minSimilarity: 0.35,
|
|
29
|
+
* maxBlockedSimilarity: 0.55,
|
|
45
30
|
* };
|
|
46
31
|
* ```
|
|
47
32
|
*/
|
|
48
|
-
export interface
|
|
49
|
-
/**
|
|
50
|
-
* Stable machine-readable identifier for this topic.
|
|
51
|
-
* Must be unique within a given {@link TopicalityPackOptions.allowedTopics} or
|
|
52
|
-
* {@link TopicalityPackOptions.forbiddenTopics} array.
|
|
53
|
-
* @example `'billing'`, `'technical-support'`, `'violence'`
|
|
54
|
-
*/
|
|
55
|
-
id: string;
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Human-readable display name for logging, dashboards, and error messages.
|
|
59
|
-
* @example `'Billing & Payments'`, `'Technical Support'`
|
|
60
|
-
*/
|
|
61
|
-
name: string;
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Free-text description of what this topic covers. This text is embedded
|
|
65
|
-
* alongside the `examples` to anchor the centroid in semantic space.
|
|
66
|
-
*/
|
|
67
|
-
description: string;
|
|
68
|
-
|
|
33
|
+
export interface TopicalityOptions {
|
|
69
34
|
/**
|
|
70
|
-
*
|
|
71
|
-
* Each string is embedded separately; the centroid is the component-wise
|
|
72
|
-
* average of all embeddings (description + examples).
|
|
35
|
+
* Topics that the agent is permitted to discuss.
|
|
73
36
|
*
|
|
74
|
-
*
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// ---------------------------------------------------------------------------
|
|
80
|
-
// TopicMatch
|
|
81
|
-
// ---------------------------------------------------------------------------
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Describes how closely a piece of text matches a single {@link TopicDescriptor}.
|
|
85
|
-
*
|
|
86
|
-
* Returned by {@link TopicEmbeddingIndex.match} and
|
|
87
|
-
* {@link TopicEmbeddingIndex.matchByVector}, sorted descending by `similarity`.
|
|
88
|
-
*/
|
|
89
|
-
export interface TopicMatch {
|
|
90
|
-
/** The `id` field of the matched {@link TopicDescriptor}. */
|
|
91
|
-
topicId: string;
|
|
92
|
-
|
|
93
|
-
/** The `name` field of the matched {@link TopicDescriptor}. */
|
|
94
|
-
topicName: string;
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Cosine similarity between the query embedding and the topic centroid,
|
|
98
|
-
* clamped to the range **[0, 1]**.
|
|
37
|
+
* Each entry is a short natural-language description (e.g. "customer support",
|
|
38
|
+
* "product pricing"). The guardrail computes cosine similarity between the
|
|
39
|
+
* user input embedding and each allowed topic embedding. If no allowed topic
|
|
40
|
+
* exceeds {@link minSimilarity}, the input is flagged as off-topic.
|
|
99
41
|
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
* A score of `1.0` means the query is identical in direction to the
|
|
103
|
-
* topic centroid; `0` means orthogonal or opposite.
|
|
42
|
+
* An empty array means "no topic restriction" (all inputs are on-topic by
|
|
43
|
+
* default unless they match a blocked topic).
|
|
104
44
|
*/
|
|
105
|
-
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// ---------------------------------------------------------------------------
|
|
109
|
-
// DriftConfig
|
|
110
|
-
// ---------------------------------------------------------------------------
|
|
45
|
+
allowedTopics: string[];
|
|
111
46
|
|
|
112
|
-
/**
|
|
113
|
-
* Configuration knobs for the EMA (Exponential Moving Average) drift tracker.
|
|
114
|
-
*
|
|
115
|
-
* The tracker maintains a running embedding per session by blending each
|
|
116
|
-
* new message into the running vector:
|
|
117
|
-
* ```
|
|
118
|
-
* running[i] = alpha * message[i] + (1 - alpha) * running[i]
|
|
119
|
-
* ```
|
|
120
|
-
* A low `alpha` means the running embedding changes slowly (long memory);
|
|
121
|
-
* a high `alpha` means it reacts quickly to the latest message.
|
|
122
|
-
*
|
|
123
|
-
* Drift is declared when `isOnTopicByVector(running, driftThreshold)` returns
|
|
124
|
-
* `false` for `driftStreakLimit` consecutive messages.
|
|
125
|
-
*/
|
|
126
|
-
export interface DriftConfig {
|
|
127
47
|
/**
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
* @
|
|
48
|
+
* Topics that the agent must refuse to discuss.
|
|
49
|
+
*
|
|
50
|
+
* Each entry is a short natural-language description (e.g. "politics",
|
|
51
|
+
* "violence"). If the cosine similarity between the user input and any
|
|
52
|
+
* blocked topic exceeds {@link maxBlockedSimilarity}, the input is blocked
|
|
53
|
+
* outright.
|
|
54
|
+
*
|
|
55
|
+
* Blocked-topic checks run before allowed-topic checks, so a message that
|
|
56
|
+
* matches both a blocked and an allowed topic will be blocked.
|
|
133
57
|
*/
|
|
134
|
-
|
|
58
|
+
blockedTopics: string[];
|
|
135
59
|
|
|
136
60
|
/**
|
|
137
|
-
* Minimum cosine similarity (
|
|
138
|
-
* for the
|
|
139
|
-
*
|
|
61
|
+
* Minimum cosine similarity (inclusive) between the input embedding and the
|
|
62
|
+
* best-matching allowed topic for the input to be considered on-topic.
|
|
63
|
+
*
|
|
64
|
+
* Values closer to 0 are more permissive; values closer to 1 are stricter.
|
|
65
|
+
* Must be in the range [0, 1].
|
|
66
|
+
*
|
|
140
67
|
* @default 0.3
|
|
141
68
|
*/
|
|
142
|
-
|
|
69
|
+
minSimilarity?: number;
|
|
143
70
|
|
|
144
71
|
/**
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Session inactivity timeout in milliseconds. Sessions that have not
|
|
154
|
-
* received a message within this window are pruned during the next
|
|
155
|
-
* `update()` call (lazy pruning).
|
|
156
|
-
* @default 3_600_000 (1 hour)
|
|
72
|
+
* Maximum cosine similarity (inclusive) between the input embedding and any
|
|
73
|
+
* blocked topic before the input is blocked outright.
|
|
74
|
+
*
|
|
75
|
+
* Values closer to 0 are stricter (blocks more); values closer to 1 are
|
|
76
|
+
* more permissive (blocks less). Must be in the range [0, 1].
|
|
77
|
+
*
|
|
78
|
+
* @default 0.5
|
|
157
79
|
*/
|
|
158
|
-
|
|
80
|
+
maxBlockedSimilarity?: number;
|
|
159
81
|
|
|
160
82
|
/**
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
83
|
+
* Optional LLM callable used as a fallback when local embeddings are
|
|
84
|
+
* unavailable (e.g. `@huggingface/transformers` not installed) or when
|
|
85
|
+
* the embedding similarity scores are ambiguous (near the threshold).
|
|
86
|
+
*
|
|
87
|
+
* The function receives a fully-formed classification prompt and must
|
|
88
|
+
* return the raw LLM response text, which the guardrail parses as JSON.
|
|
89
|
+
*
|
|
90
|
+
* @param prompt - The classification prompt to send to the LLM.
|
|
91
|
+
* @returns A promise resolving to the raw LLM response text.
|
|
165
92
|
*/
|
|
166
|
-
|
|
93
|
+
llmInvoker?: (prompt: string) => Promise<string>;
|
|
167
94
|
}
|
|
168
95
|
|
|
169
96
|
// ---------------------------------------------------------------------------
|
|
170
|
-
//
|
|
97
|
+
// TopicMatchResult
|
|
171
98
|
// ---------------------------------------------------------------------------
|
|
172
99
|
|
|
173
100
|
/**
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
* These values are designed for a production customer-support agent:
|
|
177
|
-
* - `alpha = 0.3` — moderate memory; 3–4 messages to fully shift
|
|
178
|
-
* - `driftThreshold = 0.3` — wide enough to allow tangential questions
|
|
179
|
-
* - `driftStreakLimit = 3` — flag after 3 consecutive off-topic messages
|
|
180
|
-
* - `sessionTimeoutMs = 3_600_000` — 1 hour idle timeout
|
|
181
|
-
* - `maxSessions = 100` — suitable for low-to-medium concurrency agents
|
|
101
|
+
* Result of a single topic-matching evaluation.
|
|
182
102
|
*
|
|
183
|
-
*
|
|
103
|
+
* Returned by {@link CheckTopicTool} and used internally by the guardrail
|
|
104
|
+
* to communicate classification outcomes.
|
|
184
105
|
*/
|
|
185
|
-
export
|
|
186
|
-
|
|
187
|
-
driftThreshold: 0.3,
|
|
188
|
-
driftStreakLimit: 3,
|
|
189
|
-
sessionTimeoutMs: 3_600_000,
|
|
190
|
-
maxSessions: 100,
|
|
191
|
-
} as const;
|
|
192
|
-
|
|
193
|
-
// ---------------------------------------------------------------------------
|
|
194
|
-
// DriftResult
|
|
195
|
-
// ---------------------------------------------------------------------------
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* The output of a single {@link TopicDriftTracker.update} call.
|
|
199
|
-
*
|
|
200
|
-
* Consumers should inspect `onTopic` first; when `false` they should check
|
|
201
|
-
* `driftLimitExceeded` to decide whether to warn or hard-block the session.
|
|
202
|
-
*/
|
|
203
|
-
export interface DriftResult {
|
|
204
|
-
/**
|
|
205
|
-
* Whether the session's current running embedding is considered on-topic
|
|
206
|
-
* according to `driftThreshold`. `true` = acceptable; `false` = drifting.
|
|
207
|
-
*/
|
|
106
|
+
export interface TopicMatchResult {
|
|
107
|
+
/** Whether the input text is considered on-topic. */
|
|
208
108
|
onTopic: boolean;
|
|
209
109
|
|
|
210
110
|
/**
|
|
211
|
-
*
|
|
212
|
-
* embedding after applying the EMA update. In the range [0, 1].
|
|
213
|
-
*/
|
|
214
|
-
currentSimilarity: number;
|
|
215
|
-
|
|
216
|
-
/**
|
|
217
|
-
* The {@link TopicMatch} with the highest similarity among all allowed topics,
|
|
218
|
-
* or `null` if the allowed-topic index is empty.
|
|
219
|
-
*/
|
|
220
|
-
nearestTopic: TopicMatch | null;
|
|
221
|
-
|
|
222
|
-
/**
|
|
223
|
-
* Number of consecutive messages (including the current one) that scored
|
|
224
|
-
* below `driftThreshold`. Resets to 0 when an on-topic message is received.
|
|
225
|
-
*/
|
|
226
|
-
driftStreak: number;
|
|
227
|
-
|
|
228
|
-
/**
|
|
229
|
-
* `true` when `driftStreak >= driftStreakLimit`, indicating that the
|
|
230
|
-
* guardrail should take the configured action (warn, redirect, or block).
|
|
231
|
-
*/
|
|
232
|
-
driftLimitExceeded: boolean;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
// ---------------------------------------------------------------------------
|
|
236
|
-
// TopicState
|
|
237
|
-
// ---------------------------------------------------------------------------
|
|
238
|
-
|
|
239
|
-
/**
|
|
240
|
-
* Per-session mutable state maintained by {@link TopicDriftTracker}.
|
|
241
|
-
*
|
|
242
|
-
* This type is an internal implementation detail of the tracker; it is
|
|
243
|
-
* exported primarily to make unit-testing state inspection straightforward.
|
|
244
|
-
*/
|
|
245
|
-
export interface TopicState {
|
|
246
|
-
/**
|
|
247
|
-
* The EMA-blended running embedding for this session.
|
|
248
|
-
* Initialised to a copy of the first message embedding; subsequently
|
|
249
|
-
* updated in-place via the EMA formula on every `update()` call.
|
|
250
|
-
*/
|
|
251
|
-
runningEmbedding: number[];
|
|
252
|
-
|
|
253
|
-
/**
|
|
254
|
-
* Total number of messages processed in this session (including the current
|
|
255
|
-
* one). Used internally; exposed for observability.
|
|
256
|
-
*/
|
|
257
|
-
messageCount: number;
|
|
258
|
-
|
|
259
|
-
/**
|
|
260
|
-
* The `currentSimilarity` value from the most recent {@link DriftResult}.
|
|
261
|
-
*/
|
|
262
|
-
lastTopicScore: number;
|
|
263
|
-
|
|
264
|
-
/**
|
|
265
|
-
* Current consecutive off-topic streak count. Mirrors
|
|
266
|
-
* {@link DriftResult.driftStreak} and is stored so subsequent calls can
|
|
267
|
-
* accumulate it correctly.
|
|
268
|
-
*/
|
|
269
|
-
driftStreak: number;
|
|
270
|
-
|
|
271
|
-
/**
|
|
272
|
-
* Unix timestamp (milliseconds) of the last `update()` call for this
|
|
273
|
-
* session. Used for stale-session pruning.
|
|
274
|
-
*/
|
|
275
|
-
lastSeenAt: number;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
// ---------------------------------------------------------------------------
|
|
279
|
-
// TopicalityPackOptions
|
|
280
|
-
// ---------------------------------------------------------------------------
|
|
281
|
-
|
|
282
|
-
/**
|
|
283
|
-
* Top-level configuration object passed to the `createTopicalityPack()` factory.
|
|
284
|
-
*
|
|
285
|
-
* Every property is optional; applying zero-config produces a permissive pack
|
|
286
|
-
* with no topic filtering and no drift detection.
|
|
287
|
-
*/
|
|
288
|
-
export interface TopicalityPackOptions {
|
|
289
|
-
/**
|
|
290
|
-
* Topics that the agent is expected (or allowed) to discuss.
|
|
291
|
-
* Messages that score below `allowedThreshold` against **all** topics in
|
|
292
|
-
* this list are considered off-topic.
|
|
293
|
-
*
|
|
294
|
-
* Leave empty to disable the allowed-topic guardrail.
|
|
295
|
-
*/
|
|
296
|
-
allowedTopics?: TopicDescriptor[];
|
|
297
|
-
|
|
298
|
-
/**
|
|
299
|
-
* Topics that the agent must never engage with.
|
|
300
|
-
* Messages that score above `forbiddenThreshold` against **any** topic in
|
|
301
|
-
* this list trigger `forbiddenAction`.
|
|
302
|
-
*
|
|
303
|
-
* Leave empty to disable the forbidden-topic guardrail.
|
|
304
|
-
*/
|
|
305
|
-
forbiddenTopics?: TopicDescriptor[];
|
|
306
|
-
|
|
307
|
-
/**
|
|
308
|
-
* Minimum similarity score (against any allowed topic) for a message to be
|
|
309
|
-
* considered on-topic. Below this value the `offTopicAction` fires.
|
|
111
|
+
* Confidence score in the range [0, 1].
|
|
310
112
|
*
|
|
311
|
-
*
|
|
312
|
-
*
|
|
113
|
+
* For embedding-based evaluation this is the cosine similarity to the
|
|
114
|
+
* best-matching allowed topic. For LLM-based evaluation this is the
|
|
115
|
+
* confidence value returned by the LLM. For keyword matching this is
|
|
116
|
+
* a fixed heuristic value.
|
|
313
117
|
*/
|
|
314
|
-
|
|
118
|
+
confidence: number;
|
|
315
119
|
|
|
316
120
|
/**
|
|
317
|
-
*
|
|
318
|
-
* topic. Above this value the `forbiddenAction` fires.
|
|
121
|
+
* The detected topic string that best matches the input.
|
|
319
122
|
*
|
|
320
|
-
*
|
|
321
|
-
*
|
|
322
|
-
*/
|
|
323
|
-
forbiddenThreshold?: number;
|
|
324
|
-
|
|
325
|
-
/**
|
|
326
|
-
* Action taken when a message does not meet the allowed-topic threshold.
|
|
327
|
-
* - `'flag'` — annotate the message with metadata; do not block
|
|
328
|
-
* - `'redirect'` — inject a canned response redirecting the user
|
|
329
|
-
* - `'block'` — prevent the message from reaching the agent
|
|
330
|
-
* @default 'flag'
|
|
331
|
-
*/
|
|
332
|
-
offTopicAction?: 'flag' | 'redirect' | 'block';
|
|
333
|
-
|
|
334
|
-
/**
|
|
335
|
-
* Action taken when a message matches a forbidden topic.
|
|
336
|
-
* - `'flag'` — annotate but allow
|
|
337
|
-
* - `'block'` — prevent the message from reaching the agent
|
|
338
|
-
* @default 'block'
|
|
123
|
+
* May be one of the allowed topics, one of the blocked topics, or
|
|
124
|
+
* `'unknown'` when no topic could be identified.
|
|
339
125
|
*/
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
/**
|
|
343
|
-
* Whether to activate the EMA-based session drift tracker.
|
|
344
|
-
* When `true`, each session's running embedding is tracked and compared
|
|
345
|
-
* against the allowed topics; sustained drift triggers `driftLimitExceeded`.
|
|
346
|
-
* @default true
|
|
347
|
-
*/
|
|
348
|
-
enableDriftDetection?: boolean;
|
|
349
|
-
|
|
350
|
-
/**
|
|
351
|
-
* Fine-grained tuning for the drift tracker.
|
|
352
|
-
* When omitted, {@link DEFAULT_DRIFT_CONFIG} is used.
|
|
353
|
-
*/
|
|
354
|
-
drift?: Partial<DriftConfig>;
|
|
355
|
-
|
|
356
|
-
/**
|
|
357
|
-
* Async function that converts an array of text strings into a corresponding
|
|
358
|
-
* array of embedding vectors (one per string, same order).
|
|
359
|
-
*
|
|
360
|
-
* The pack does **not** bundle an embedding model; the caller must provide
|
|
361
|
-
* one — e.g. wrapping `openai.embeddings.create()` or a local model.
|
|
362
|
-
*
|
|
363
|
-
* @param texts - One or more strings to embed.
|
|
364
|
-
* @returns A promise resolving to one numeric vector per input string.
|
|
365
|
-
* All vectors must have the same dimensionality.
|
|
366
|
-
*/
|
|
367
|
-
embeddingFn?: (texts: string[]) => Promise<number[][]>;
|
|
368
|
-
|
|
369
|
-
/**
|
|
370
|
-
* Which agent messages the guardrail evaluates.
|
|
371
|
-
* - `'input'` — only inbound user messages (default; lowest latency)
|
|
372
|
-
* - `'output'` — only outbound assistant messages
|
|
373
|
-
* - `'both'` — both directions
|
|
374
|
-
* @default 'input'
|
|
375
|
-
*/
|
|
376
|
-
guardrailScope?: 'input' | 'output' | 'both';
|
|
126
|
+
detectedTopic: string;
|
|
377
127
|
}
|
|
378
128
|
|
|
379
129
|
// ---------------------------------------------------------------------------
|
|
380
|
-
//
|
|
130
|
+
// Service identity constants
|
|
381
131
|
// ---------------------------------------------------------------------------
|
|
382
132
|
|
|
383
133
|
/**
|
|
384
|
-
*
|
|
134
|
+
* Stable string identifiers for services provided by the topicality pack.
|
|
385
135
|
*
|
|
386
|
-
*
|
|
387
|
-
* domain-specific examples to improve precision for production deployments.
|
|
388
|
-
*
|
|
389
|
-
* @example
|
|
390
|
-
* ```ts
|
|
391
|
-
* const pack = createTopicalityPack({
|
|
392
|
-
* allowedTopics: TOPIC_PRESETS.customerSupport,
|
|
393
|
-
* forbiddenTopics: TOPIC_PRESETS.commonUnsafe,
|
|
394
|
-
* });
|
|
395
|
-
* ```
|
|
136
|
+
* Values follow the AgentOS convention: `agentos:<domain>:<service-name>`.
|
|
396
137
|
*/
|
|
397
|
-
export const
|
|
138
|
+
export const TOPICALITY_SERVICE_IDS = {
|
|
398
139
|
/**
|
|
399
|
-
*
|
|
400
|
-
*
|
|
140
|
+
* The feature-extraction pipeline instance used to compute text embeddings
|
|
141
|
+
* for cosine-similarity topic matching.
|
|
401
142
|
*/
|
|
402
|
-
|
|
403
|
-
{
|
|
404
|
-
id: 'billing',
|
|
405
|
-
name: 'Billing & Payments',
|
|
406
|
-
description:
|
|
407
|
-
'Questions about invoices, charges, refunds, payment methods, and subscription management.',
|
|
408
|
-
examples: [
|
|
409
|
-
'Why was I charged twice this month?',
|
|
410
|
-
'How do I update my credit card?',
|
|
411
|
-
'Can I get a refund for my last invoice?',
|
|
412
|
-
'When does my subscription renew?',
|
|
413
|
-
'How do I cancel my plan?',
|
|
414
|
-
],
|
|
415
|
-
},
|
|
416
|
-
{
|
|
417
|
-
id: 'technical-support',
|
|
418
|
-
name: 'Technical Support',
|
|
419
|
-
description:
|
|
420
|
-
'Troubleshooting software bugs, login issues, performance problems, and integration errors.',
|
|
421
|
-
examples: [
|
|
422
|
-
"I can't log in to my account.",
|
|
423
|
-
'The app keeps crashing when I open it.',
|
|
424
|
-
'My API key is returning a 401 error.',
|
|
425
|
-
'How do I reset my password?',
|
|
426
|
-
'The dashboard is loading very slowly.',
|
|
427
|
-
],
|
|
428
|
-
},
|
|
429
|
-
{
|
|
430
|
-
id: 'account-management',
|
|
431
|
-
name: 'Account Management',
|
|
432
|
-
description:
|
|
433
|
-
'Managing user profiles, team members, permissions, and organisation settings.',
|
|
434
|
-
examples: [
|
|
435
|
-
'How do I add a new team member?',
|
|
436
|
-
'Can I change my account email address?',
|
|
437
|
-
'How do I remove a user from my organisation?',
|
|
438
|
-
'Where do I find my usage limits?',
|
|
439
|
-
'How do I enable two-factor authentication?',
|
|
440
|
-
],
|
|
441
|
-
},
|
|
442
|
-
{
|
|
443
|
-
id: 'product-features',
|
|
444
|
-
name: 'Product Features & Usage',
|
|
445
|
-
description:
|
|
446
|
-
'How to use specific product features, best practices, and general how-to questions.',
|
|
447
|
-
examples: [
|
|
448
|
-
'How do I export my data as CSV?',
|
|
449
|
-
'What integrations do you support?',
|
|
450
|
-
'Is there a mobile app available?',
|
|
451
|
-
'How does the search feature work?',
|
|
452
|
-
'Can I automate this with your API?',
|
|
453
|
-
],
|
|
454
|
-
},
|
|
455
|
-
{
|
|
456
|
-
id: 'onboarding',
|
|
457
|
-
name: 'Onboarding & Getting Started',
|
|
458
|
-
description:
|
|
459
|
-
'Help for new users setting up their account, completing first-time setup, and understanding basics.',
|
|
460
|
-
examples: [
|
|
461
|
-
"I just signed up — where do I start?",
|
|
462
|
-
'How do I connect my data source?',
|
|
463
|
-
'Can you walk me through the initial setup?',
|
|
464
|
-
'What is the quickest way to get value from the product?',
|
|
465
|
-
'Is there a tutorial or quickstart guide?',
|
|
466
|
-
],
|
|
467
|
-
},
|
|
468
|
-
] satisfies TopicDescriptor[],
|
|
469
|
-
|
|
470
|
-
/**
|
|
471
|
-
* Four topics covering the typical scope of a coding-assistant agent.
|
|
472
|
-
* Use as `allowedTopics` to keep conversations focused on software development.
|
|
473
|
-
*/
|
|
474
|
-
codingAssistant: [
|
|
475
|
-
{
|
|
476
|
-
id: 'code-review',
|
|
477
|
-
name: 'Code Review',
|
|
478
|
-
description:
|
|
479
|
-
'Reviewing pull requests, spotting bugs, suggesting improvements, and discussing best practices.',
|
|
480
|
-
examples: [
|
|
481
|
-
'Can you review this function for edge cases?',
|
|
482
|
-
'Is this implementation thread-safe?',
|
|
483
|
-
'How would you improve the readability of this code?',
|
|
484
|
-
'Does this code follow the SOLID principles?',
|
|
485
|
-
],
|
|
486
|
-
},
|
|
487
|
-
{
|
|
488
|
-
id: 'debugging',
|
|
489
|
-
name: 'Debugging & Error Resolution',
|
|
490
|
-
description:
|
|
491
|
-
'Diagnosing runtime errors, stack traces, unexpected behaviour, and test failures.',
|
|
492
|
-
examples: [
|
|
493
|
-
"I'm getting a TypeError on line 42 — what's wrong?",
|
|
494
|
-
'My unit test is failing but the code looks correct.',
|
|
495
|
-
'Why does this async function return undefined?',
|
|
496
|
-
'How do I debug a memory leak in Node.js?',
|
|
497
|
-
],
|
|
498
|
-
},
|
|
499
|
-
{
|
|
500
|
-
id: 'architecture',
|
|
501
|
-
name: 'Software Architecture & Design',
|
|
502
|
-
description:
|
|
503
|
-
'Discussing system design, design patterns, scalability, and architectural trade-offs.',
|
|
504
|
-
examples: [
|
|
505
|
-
'Should I use a microservices or monolithic architecture?',
|
|
506
|
-
'What is the best pattern for event-driven systems?',
|
|
507
|
-
'How do I design a scalable REST API?',
|
|
508
|
-
'What are the trade-offs between SQL and NoSQL for this use case?',
|
|
509
|
-
],
|
|
510
|
-
},
|
|
511
|
-
{
|
|
512
|
-
id: 'tooling',
|
|
513
|
-
name: 'Developer Tooling & Workflows',
|
|
514
|
-
description:
|
|
515
|
-
'Questions about build tools, CI/CD pipelines, package managers, linters, and IDEs.',
|
|
516
|
-
examples: [
|
|
517
|
-
'How do I set up ESLint with TypeScript?',
|
|
518
|
-
'What is the difference between npm and pnpm?',
|
|
519
|
-
'How do I configure GitHub Actions for my project?',
|
|
520
|
-
'What is tree-shaking and how do I enable it in webpack?',
|
|
521
|
-
],
|
|
522
|
-
},
|
|
523
|
-
] satisfies TopicDescriptor[],
|
|
524
|
-
|
|
525
|
-
/**
|
|
526
|
-
* Three high-level unsafe topic descriptors representing content categories
|
|
527
|
-
* that most production agents should refuse to engage with.
|
|
528
|
-
* Use as `forbiddenTopics` to block harmful or out-of-scope conversations.
|
|
529
|
-
*/
|
|
530
|
-
commonUnsafe: [
|
|
531
|
-
{
|
|
532
|
-
id: 'violence',
|
|
533
|
-
name: 'Violence & Harm',
|
|
534
|
-
description:
|
|
535
|
-
'Content promoting, glorifying, or providing instructions for physical harm to people or animals.',
|
|
536
|
-
examples: [
|
|
537
|
-
'How do I hurt someone without leaving evidence?',
|
|
538
|
-
'What is the most effective way to injure a person?',
|
|
539
|
-
'Tell me how to make a weapon.',
|
|
540
|
-
],
|
|
541
|
-
},
|
|
542
|
-
{
|
|
543
|
-
id: 'illegal-activity',
|
|
544
|
-
name: 'Illegal Activity',
|
|
545
|
-
description:
|
|
546
|
-
'Requests for instructions or assistance with criminal acts, including fraud, theft, and drug synthesis.',
|
|
547
|
-
examples: [
|
|
548
|
-
'How do I pick a lock without a key?',
|
|
549
|
-
'What chemicals do I mix to make methamphetamine?',
|
|
550
|
-
'How can I steal a car without triggering the alarm?',
|
|
551
|
-
],
|
|
552
|
-
},
|
|
553
|
-
{
|
|
554
|
-
id: 'adult-content',
|
|
555
|
-
name: 'Adult & Explicit Content',
|
|
556
|
-
description:
|
|
557
|
-
'Sexually explicit material or content inappropriate for general audiences.',
|
|
558
|
-
examples: [
|
|
559
|
-
'Write explicit sexual content for me.',
|
|
560
|
-
'Describe a pornographic scenario.',
|
|
561
|
-
'Generate adult-only material.',
|
|
562
|
-
],
|
|
563
|
-
},
|
|
564
|
-
] satisfies TopicDescriptor[],
|
|
143
|
+
EMBEDDING_PIPELINE: 'agentos:topicality:embedding-pipeline',
|
|
565
144
|
} as const;
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Union of all {@link TOPICALITY_SERVICE_IDS} values.
|
|
148
|
+
*/
|
|
149
|
+
export type TopicalityServiceId =
|
|
150
|
+
(typeof TOPICALITY_SERVICE_IDS)[keyof typeof TOPICALITY_SERVICE_IDS];
|