llm-agent-runtime 0.1.2 → 0.1.6
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/README.md +2 -2
- package/USAGE.md +448 -0
- package/dist/create-runtime.d.ts.map +1 -1
- package/dist/create-runtime.js +14 -2
- package/dist/env-llm.d.ts +5 -5
- package/dist/env-llm.d.ts.map +1 -1
- package/dist/env-llm.js +25 -5
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/llm.d.ts.map +1 -1
- package/dist/llm.js +17 -0
- package/dist/services/conversation.d.ts.map +1 -1
- package/dist/services/conversation.js +20 -8
- package/dist/services/flow-router.d.ts +1 -0
- package/dist/services/flow-router.d.ts.map +1 -1
- package/dist/services/flow-router.js +24 -0
- package/dist/services/simple-config.d.ts +2 -19
- package/dist/services/simple-config.d.ts.map +1 -1
- package/dist/types.d.ts +21 -3
- package/dist/types.d.ts.map +1 -1
- package/package.json +5 -3
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# llm-agent-runtime
|
|
2
2
|
|
|
3
|
-
Reusable LangGraph agent runtime
|
|
3
|
+
Reusable LangGraph agent runtime: intent routing, sticky flows, checkpointer, tool outputs.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**Docs:** [USAGE.md](./USAGE.md)
|
package/USAGE.md
ADDED
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
# llm-agent-runtime
|
|
2
|
+
|
|
3
|
+
Reusable LangGraph agent engine. Your app supplies **intents, prompts, and tools**. The package runs:
|
|
4
|
+
|
|
5
|
+
`resolveFlow → runAgent → extract tool outputs → finalize`
|
|
6
|
+
|
|
7
|
+
Same shape as Xel-agent, but flexible for any product.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install llm-agent-runtime
|
|
15
|
+
# or
|
|
16
|
+
pnpm add llm-agent-runtime
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**Peer dependencies** (usually already in a LangChain app):
|
|
20
|
+
|
|
21
|
+
- `@langchain/core`
|
|
22
|
+
- `@langchain/langgraph`
|
|
23
|
+
- `@langchain/langgraph-checkpoint`
|
|
24
|
+
- `zod`
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Quick start
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
import { createAgentRuntime } from "llm-agent-runtime";
|
|
32
|
+
import { tool } from "@langchain/core/tools";
|
|
33
|
+
import { z } from "zod";
|
|
34
|
+
|
|
35
|
+
const greet = tool(async () => "ok", {
|
|
36
|
+
name: "noop",
|
|
37
|
+
description: "No-op",
|
|
38
|
+
schema: z.object({}),
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const runtime = await createAgentRuntime({
|
|
42
|
+
redisUrl: process.env.REDIS_URL, // omit → in-memory checkpointer
|
|
43
|
+
// llm omitted → reads process.env (see Env vars below)
|
|
44
|
+
|
|
45
|
+
intents: [
|
|
46
|
+
{
|
|
47
|
+
name: "greetings",
|
|
48
|
+
examples: ["hi", "hello", "good morning"],
|
|
49
|
+
description: "hello or small talk",
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: "create_campaign",
|
|
53
|
+
examples: ["create a campaign", "start fundraising"],
|
|
54
|
+
sticky: true,
|
|
55
|
+
description: "new campaign wizard",
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
|
|
59
|
+
intentRegistry: {
|
|
60
|
+
greetings: {
|
|
61
|
+
prompt: (ctx) =>
|
|
62
|
+
`Greet the user. Name: ${ctx.context?.contactName ?? "friend"}.`,
|
|
63
|
+
tools: () => [greet],
|
|
64
|
+
},
|
|
65
|
+
create_campaign: {
|
|
66
|
+
prompt: () => "Help create a campaign step by step. Call create_campaign when ready.",
|
|
67
|
+
tools: (phoneKey) => [/* your tools scoped by phoneKey */],
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
toolOutputMap: {
|
|
72
|
+
create_campaign: "campaign",
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
await runtime.connect();
|
|
77
|
+
|
|
78
|
+
const result = await runtime.invoke({
|
|
79
|
+
message: "hi",
|
|
80
|
+
threadId: "user-123",
|
|
81
|
+
context: { contactName: "Ada" },
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
console.log(result.answer, result.intent, result.flow, result.toolOutputs);
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## What you pass vs what the library does
|
|
90
|
+
|
|
91
|
+
| You configure | Library handles |
|
|
92
|
+
| --- | --- |
|
|
93
|
+
| `intents` (examples + `sticky` + `regex`) | Hybrid regex + LLM + embedding router |
|
|
94
|
+
| `intentRegistry` (prompt + tools) | LangGraph agent + Redis/memory checkpointer |
|
|
95
|
+
| `toolOutputMap` | Parse tool calls into structured outputs |
|
|
96
|
+
| `completeOn` | Sticky-flow completion + Redis flow state |
|
|
97
|
+
| `menuMap` (optional) | Digit → intent after a numbered menu |
|
|
98
|
+
| Prompts, API tools, webhooks | — stay in your app |
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Config reference
|
|
103
|
+
|
|
104
|
+
### `createAgentRuntime(config)`
|
|
105
|
+
|
|
106
|
+
#### Required
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
intents: IntentDefinition[]
|
|
110
|
+
intentRegistry: Record<string, { prompt: (ctx) => string; tools: (phoneKey) => Tool[] }>
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
#### Common optional
|
|
114
|
+
|
|
115
|
+
| Option | Default | Purpose |
|
|
116
|
+
| --- | --- | --- |
|
|
117
|
+
| `redisUrl` | none (MemorySaver) | Checkpointer + flow state + optional answer cache |
|
|
118
|
+
| `llm` | `llmConfigFromEnv()` | Provider / models |
|
|
119
|
+
| `cache.enabled` | `false` | Exact-match answer cache (needs Redis) |
|
|
120
|
+
| `toolOutputMap` | raw tool args | Map tool name → output key |
|
|
121
|
+
| `completeOn` | keys of `toolOutputMap` | Tool names that finish a sticky flow |
|
|
122
|
+
| `menuMap` | `{}` | `{ "1": "create_campaign" }` for digit menus |
|
|
123
|
+
| `intentAliases` | `{}` | Legacy name → catalog name |
|
|
124
|
+
| `defaultIntent` | first intent | Fallback intent |
|
|
125
|
+
| `buildSystemPrompt` | registry `prompt` | One builder for all intents |
|
|
126
|
+
| `resolvePhoneKey` | `phoneKey ?? threadId` | Key passed to `tools(phoneKey)` |
|
|
127
|
+
| `tracing` | auto-detect | LangSmith tracing config |
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Intents
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
intents: [
|
|
135
|
+
{
|
|
136
|
+
name: "greetings",
|
|
137
|
+
examples: ["hi", "hello"],
|
|
138
|
+
description: "Shown to the LLM router",
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
name: "create_campaign",
|
|
142
|
+
examples: ["create a campaign"],
|
|
143
|
+
sticky: true, // keep this flow across turns until completeOn fires
|
|
144
|
+
regex: /create.*(campaign|fundrais)/i, // fast-path: skip LLM if matched
|
|
145
|
+
},
|
|
146
|
+
]
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
- **examples** — embedding routing
|
|
150
|
+
- **sticky** — multi-step wizards
|
|
151
|
+
- **description** — LLM intent router
|
|
152
|
+
- **regex** — fast-path: if message matches, skip LLM/embeddings entirely (zero tokens)
|
|
153
|
+
|
|
154
|
+
### Intent detection flow
|
|
155
|
+
|
|
156
|
+
```
|
|
157
|
+
1. explicitIntent passed? → Use it directly (score 1.0)
|
|
158
|
+
2. Wizard input + sticky? → Reuse cached intent (skip LLM)
|
|
159
|
+
3. Menu digit match? → Use mapped intent (score 1.0)
|
|
160
|
+
4. Regex matches? → Use matched intent (score 1.0, 0 tokens)
|
|
161
|
+
5. Embeddings + LLM (hybrid) → Existing flow
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
The regex fast-path is a token-saving optimization. When a user message matches an intent's regex pattern, the library returns that intent immediately without calling the LLM or embeddings. Define regexes for high-confidence, pattern-based intents (e.g. "generate an image of...") and leave regex undefined for ambiguous intents that need LLM classification.
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Prompts & tools (`intentRegistry`)
|
|
169
|
+
|
|
170
|
+
```ts
|
|
171
|
+
intentRegistry: {
|
|
172
|
+
greetings: {
|
|
173
|
+
prompt: (ctx) => string,
|
|
174
|
+
tools: (phoneKey) => DynamicStructuredTool[],
|
|
175
|
+
},
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
`prompt` receives:
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
{
|
|
183
|
+
hasConversationHistory: boolean
|
|
184
|
+
intent: string
|
|
185
|
+
intentScore?: number
|
|
186
|
+
message?: string
|
|
187
|
+
context?: Record<string, unknown> // whatever you passed to invoke()
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Or use one builder for everything:
|
|
192
|
+
|
|
193
|
+
```ts
|
|
194
|
+
buildSystemPrompt: (ctx) => combineGeneralAndIntent(ctx)
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## Tool outputs (`toolOutputMap`)
|
|
200
|
+
|
|
201
|
+
Replaces hand-written extractors:
|
|
202
|
+
|
|
203
|
+
```ts
|
|
204
|
+
toolOutputMap: {
|
|
205
|
+
create_campaign: "campaign",
|
|
206
|
+
buy_airtime: "buyAirtime",
|
|
207
|
+
// Nested field on args + seed:
|
|
208
|
+
propose_tickets: { as: "tickets", from: "tickets", initial: [] },
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Result lands on `result.toolOutputs` and completed keys on `result.extras`.
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## Flow completion (`completeOn`)
|
|
217
|
+
|
|
218
|
+
Pass tool **names**. When any of them produces output, the sticky flow ends:
|
|
219
|
+
|
|
220
|
+
```ts
|
|
221
|
+
completeOn: ["create_campaign", "buy_airtime", "add_airtime"]
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
If you omit `completeOn`, the library defaults `completeOn` to the keys of `toolOutputMap`.
|
|
225
|
+
|
|
226
|
+
This is tuned to Xel-style wizards: when a sticky flow is already active and the user message looks like wizard input (digits / yes-no), the router LLM call is skipped for that turn to reduce tokens.
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## Menu digits (`menuMap`)
|
|
231
|
+
|
|
232
|
+
Optional. Needed only if users pick a numbered menu (`1`, `2`, …).
|
|
233
|
+
|
|
234
|
+
The **prompt** shows the menu text. **`menuMap`** tells the **router** that `"1"` means `create_campaign`. Without it, a bare `"1"` is not reliably routed.
|
|
235
|
+
|
|
236
|
+
```ts
|
|
237
|
+
menuMap: {
|
|
238
|
+
"1": "create_campaign",
|
|
239
|
+
"2": "support_campaign",
|
|
240
|
+
"3": "buy_airtime_and_data",
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## Invoke
|
|
247
|
+
|
|
248
|
+
```ts
|
|
249
|
+
const result = await runtime.invoke({
|
|
250
|
+
message: "hi",
|
|
251
|
+
threadId: "whatsapp:234...", // conversation / checkpoint id
|
|
252
|
+
phoneKey: "234...", // optional; passed to tools()
|
|
253
|
+
explicitIntent: "greetings", // optional; skips hybrid router
|
|
254
|
+
context: {
|
|
255
|
+
contactName: "Ada",
|
|
256
|
+
userInfo: { email: "ada@example.com" },
|
|
257
|
+
},
|
|
258
|
+
});
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
**Result**
|
|
262
|
+
|
|
263
|
+
```ts
|
|
264
|
+
{
|
|
265
|
+
messages: unknown[]
|
|
266
|
+
answer?: string
|
|
267
|
+
intent: { intent: string, score: number }
|
|
268
|
+
flow: { active: boolean, intent: string | null }
|
|
269
|
+
toolOutputs: Record<string, unknown>
|
|
270
|
+
flowCompleted: boolean
|
|
271
|
+
extras?: Record<string, unknown>
|
|
272
|
+
router?: { action: "continue" | "switch" | "cancel", reason?: string }
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
---
|
|
277
|
+
|
|
278
|
+
## Lifecycle
|
|
279
|
+
|
|
280
|
+
```ts
|
|
281
|
+
await runtime.connect() // Redis (if redisUrl set)
|
|
282
|
+
await runtime.invoke(...)
|
|
283
|
+
await runtime.clearFlow(id) // drop sticky flow state
|
|
284
|
+
await runtime.disconnect()
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## LLM Providers
|
|
290
|
+
|
|
291
|
+
### Supported providers
|
|
292
|
+
|
|
293
|
+
| Provider | `LLM_PROVIDER` | API Key Env Var | Default Model |
|
|
294
|
+
| --- | --- | --- | --- |
|
|
295
|
+
| Ollama | `ollama` (default) | — | `qwen2.5:7b` |
|
|
296
|
+
| OpenAI | `openai` | `OPENAI_API_KEY` | `gpt-4o-mini` |
|
|
297
|
+
| OpenRouter | `openrouter` | `OPENROUTER_API_KEY` | `meta-llama/llama-4-scout` |
|
|
298
|
+
|
|
299
|
+
### Env vars
|
|
300
|
+
|
|
301
|
+
| Variable | Notes |
|
|
302
|
+
| --- | --- |
|
|
303
|
+
| `LLM_PROVIDER` | `ollama` (default), `openai`, or `openrouter` |
|
|
304
|
+
| `EMBEDDINGS_PROVIDER` | defaults to `LLM_PROVIDER` |
|
|
305
|
+
| `OLLAMA_MODEL` | default `qwen2.5:7b` |
|
|
306
|
+
| `OLLAMA_BASE_URL` | e.g. `http://localhost:11434` |
|
|
307
|
+
| `OLLAMA_EMBEDDINGS_MODEL` | default `mxbai-embed-large:latest` |
|
|
308
|
+
| `INTENT_ROUTER_MODEL` | optional smaller router model (ollama) |
|
|
309
|
+
| `OPENAI_API_KEY` | required for openai |
|
|
310
|
+
| `OPENAI_MODEL` | default `gpt-4o-mini` |
|
|
311
|
+
| `OPENAI_EMBEDDINGS_MODEL` | default `text-embedding-3-small` |
|
|
312
|
+
| `OPENROUTER_API_KEY` | required for openrouter |
|
|
313
|
+
| `OPENROUTER_MODEL` | default `meta-llama/llama-4-scout` |
|
|
314
|
+
| `OPENROUTER_BASE_URL` | default `https://openrouter.ai/api/v1` |
|
|
315
|
+
| `OPENROUTER_INTENT_ROUTER_MODEL` | optional separate router model |
|
|
316
|
+
| `REDIS_URL` | your app usually passes this as `redisUrl` |
|
|
317
|
+
| `ANSWER_CACHE` | app convention: `"1"` to enable cache |
|
|
318
|
+
|
|
319
|
+
### OpenRouter example
|
|
320
|
+
|
|
321
|
+
```bash
|
|
322
|
+
LLM_PROVIDER=openrouter OPENROUTER_API_KEY=sk-or-... pnpm dev
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
Or pass explicitly:
|
|
326
|
+
|
|
327
|
+
```ts
|
|
328
|
+
createAgentRuntime({
|
|
329
|
+
llm: {
|
|
330
|
+
provider: "openrouter",
|
|
331
|
+
model: "meta-llama/llama-4-scout",
|
|
332
|
+
apiKey: "sk-or-...",
|
|
333
|
+
},
|
|
334
|
+
// ...
|
|
335
|
+
});
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
### LangSmith tracing
|
|
339
|
+
|
|
340
|
+
Tracing auto-enables when `LANGSMITH_API_KEY` is set in the environment. No code changes needed.
|
|
341
|
+
|
|
342
|
+
```bash
|
|
343
|
+
LANGSMITH_API_KEY=ls_... LLM_PROVIDER=openrouter OPENROUTER_API_KEY=sk-or-... pnpm dev
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
Or enable explicitly:
|
|
347
|
+
|
|
348
|
+
```ts
|
|
349
|
+
createAgentRuntime({
|
|
350
|
+
tracing: { enabled: true, projectName: "my-project" },
|
|
351
|
+
// ...
|
|
352
|
+
});
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
Tracing sets `LANGCHAIN_TRACING_V2`, `LANGCHAIN_API_KEY`, and `LANGCHAIN_PROJECT` env vars before model creation. The `langsmith` package must be installed (`pnpm add langsmith`).
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
359
|
+
## Minimal app shape (recommended)
|
|
360
|
+
|
|
361
|
+
```
|
|
362
|
+
your-app/
|
|
363
|
+
agent/
|
|
364
|
+
runtime.ts # createAgentRuntime({ ... })
|
|
365
|
+
intents.ts # intents + menuMap + aliases
|
|
366
|
+
prompts/ # prompt strings
|
|
367
|
+
tools/ # LangChain tools / API clients
|
|
368
|
+
controllers/ # HTTP / WhatsApp — call runtime.invoke()
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
Keep channel adapters and product APIs **out** of this package.
|
|
372
|
+
|
|
373
|
+
---
|
|
374
|
+
|
|
375
|
+
## Full example (Xel-like)
|
|
376
|
+
|
|
377
|
+
```ts
|
|
378
|
+
import { createAgentRuntime } from "llm-agent-runtime";
|
|
379
|
+
|
|
380
|
+
const runtime = await createAgentRuntime({
|
|
381
|
+
redisUrl: process.env.REDIS_URL ?? "redis://localhost:6379",
|
|
382
|
+
cache: { enabled: process.env.ANSWER_CACHE === "1" },
|
|
383
|
+
|
|
384
|
+
intents: [
|
|
385
|
+
{ name: "greetings", examples: ["hi", "hello"] },
|
|
386
|
+
{
|
|
387
|
+
name: "create_campaign",
|
|
388
|
+
examples: ["create a campaign"],
|
|
389
|
+
sticky: true,
|
|
390
|
+
regex: /create.*(campaign|fundrais)/i,
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
name: "buy_airtime_and_data",
|
|
394
|
+
examples: ["buy airtime", "vend airtime"],
|
|
395
|
+
sticky: true,
|
|
396
|
+
regex: /(buy|vend|purchase).*(airtime|data|credit)/i,
|
|
397
|
+
},
|
|
398
|
+
],
|
|
399
|
+
|
|
400
|
+
menuMap: {
|
|
401
|
+
"1": "create_campaign",
|
|
402
|
+
"4": "buy_airtime_and_data",
|
|
403
|
+
},
|
|
404
|
+
|
|
405
|
+
intentAliases: {
|
|
406
|
+
buy_airtime: "buy_airtime_and_data",
|
|
407
|
+
},
|
|
408
|
+
|
|
409
|
+
intentRegistry: {
|
|
410
|
+
greetings: {
|
|
411
|
+
prompt: (ctx) => `Greet ${ctx.context?.contactName ?? "there"}. Show menu 1–7.`,
|
|
412
|
+
tools: () => [],
|
|
413
|
+
},
|
|
414
|
+
create_campaign: {
|
|
415
|
+
prompt: () => "Walk through campaign creation.",
|
|
416
|
+
tools: (phoneKey) => createCampaignTools(phoneKey),
|
|
417
|
+
},
|
|
418
|
+
buy_airtime_and_data: {
|
|
419
|
+
prompt: () => "Help buy airtime/data.",
|
|
420
|
+
tools: (phoneKey) => airtimeTools(phoneKey),
|
|
421
|
+
},
|
|
422
|
+
},
|
|
423
|
+
|
|
424
|
+
toolOutputMap: {
|
|
425
|
+
create_campaign: "campaign",
|
|
426
|
+
buy_airtime: "buyAirtime",
|
|
427
|
+
add_airtime: "addAirtime",
|
|
428
|
+
},
|
|
429
|
+
completeOn: ["create_campaign", "buy_airtime", "add_airtime"],
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
await runtime.connect();
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
---
|
|
436
|
+
|
|
437
|
+
## Exports
|
|
438
|
+
|
|
439
|
+
```ts
|
|
440
|
+
import {
|
|
441
|
+
createAgentRuntime,
|
|
442
|
+
llmConfigFromEnv,
|
|
443
|
+
getLastMessageContent,
|
|
444
|
+
// advanced (usually not needed)
|
|
445
|
+
createToolOutputExtractor,
|
|
446
|
+
toolOutputMapToExtractors,
|
|
447
|
+
} from "llm-agent-runtime";
|
|
448
|
+
```
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-runtime.d.ts","sourceRoot":"","sources":["../src/create-runtime.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EACV,kBAAkB,EAClB,WAAW,EACX,YAAY,EAEb,MAAM,YAAY,CAAC;AAepB,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;IACtD,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,gEAAgE;IAChE,WAAW,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,eAAe,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAClE,eAAe,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpE,4EAA4E;IAC5E,0BAA0B,EAAE,MAAM,IAAI,CAAC;CACxC,CAAC;AAEF;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC,YAAY,CAAC,
|
|
1
|
+
{"version":3,"file":"create-runtime.d.ts","sourceRoot":"","sources":["../src/create-runtime.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EACV,kBAAkB,EAClB,WAAW,EACX,YAAY,EAEb,MAAM,YAAY,CAAC;AAepB,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;IACtD,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,gEAAgE;IAChE,WAAW,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,eAAe,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAClE,eAAe,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpE,4EAA4E;IAC5E,0BAA0B,EAAE,MAAM,IAAI,CAAC;CACxC,CAAC;AAEF;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC,YAAY,CAAC,CAoPvB"}
|
package/dist/create-runtime.js
CHANGED
|
@@ -28,6 +28,15 @@ const getTurnMessages = (allMessages, userMessage) => {
|
|
|
28
28
|
* Engine pipeline: resolveFlow → runAgent → getTurnMessages → extract → finalize
|
|
29
29
|
*/
|
|
30
30
|
export async function createAgentRuntime(config) {
|
|
31
|
+
// Wire LangSmith tracing: auto-detect from env or explicit config
|
|
32
|
+
const langsmithKey = process.env.LANGSMITH_API_KEY;
|
|
33
|
+
const tracingEnabled = config.tracing?.enabled ?? !!langsmithKey;
|
|
34
|
+
if (tracingEnabled) {
|
|
35
|
+
process.env.LANGCHAIN_TRACING_V2 = "true";
|
|
36
|
+
if (langsmithKey)
|
|
37
|
+
process.env.LANGCHAIN_API_KEY = langsmithKey;
|
|
38
|
+
process.env.LANGCHAIN_PROJECT = config.tracing?.projectName ?? "llm-agent-runtime";
|
|
39
|
+
}
|
|
31
40
|
const defaultIntent = config.defaultIntent ?? config.intents[0]?.name ?? "greetings";
|
|
32
41
|
const intentNames = new Set(config.intents.map((i) => i.name));
|
|
33
42
|
const aliases = config.intentAliases ?? {};
|
|
@@ -52,10 +61,12 @@ export async function createAgentRuntime(config) {
|
|
|
52
61
|
: null;
|
|
53
62
|
const toolExtractors = config.toolExtractors ?? fromMap?.toolExtractors;
|
|
54
63
|
const initialToolOutputs = config.initialToolOutputs ?? fromMap?.initialToolOutputs;
|
|
64
|
+
const completeOn = config.completeOn ??
|
|
65
|
+
(config.toolOutputMap ? Object.keys(config.toolOutputMap) : undefined);
|
|
55
66
|
const finalizeFlow = config.finalizeFlow ??
|
|
56
|
-
(
|
|
67
|
+
(completeOn?.length
|
|
57
68
|
? createCompleteOnFinalize({
|
|
58
|
-
completeOn
|
|
69
|
+
completeOn,
|
|
59
70
|
toolOutputMap: config.toolOutputMap,
|
|
60
71
|
})
|
|
61
72
|
: undefined);
|
|
@@ -101,6 +112,7 @@ export async function createAgentRuntime(config) {
|
|
|
101
112
|
stickyFlows,
|
|
102
113
|
menuMap,
|
|
103
114
|
normalizeIntent,
|
|
115
|
+
intents: config.intents,
|
|
104
116
|
getEmbeddedIntents: intentEmbeddings.getEmbeddedIntents,
|
|
105
117
|
scoreIntentsForMessage: intentEmbeddings.scoreIntentsForMessage,
|
|
106
118
|
classifyIntentWithLlm: intentRouter.classifyIntentWithLlm,
|
package/dist/env-llm.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import type { LlmConfig } from "./types.js";
|
|
2
2
|
/**
|
|
3
|
-
* Build LlmConfig from process.env
|
|
3
|
+
* Build LlmConfig from process.env.
|
|
4
4
|
*
|
|
5
5
|
* Env knobs:
|
|
6
|
-
* - LLM_PROVIDER / EMBEDDINGS_PROVIDER — ollama | openai
|
|
7
|
-
* - OLLAMA_MODEL / OPENAI_MODEL
|
|
8
|
-
* - INTENT_ROUTER_MODEL / OPENAI_INTENT_ROUTER_MODEL
|
|
6
|
+
* - LLM_PROVIDER / EMBEDDINGS_PROVIDER — ollama | openai | openrouter
|
|
7
|
+
* - OLLAMA_MODEL / OPENAI_MODEL / OPENROUTER_MODEL
|
|
8
|
+
* - INTENT_ROUTER_MODEL / OPENAI_INTENT_ROUTER_MODEL / OPENROUTER_INTENT_ROUTER_MODEL
|
|
9
9
|
* - OLLAMA_EMBEDDINGS_MODEL / OPENAI_EMBEDDINGS_MODEL
|
|
10
|
-
* - OLLAMA_BASE_URL / OPENAI_API_KEY
|
|
10
|
+
* - OLLAMA_BASE_URL / OPENAI_API_KEY / OPENROUTER_API_KEY / OPENROUTER_BASE_URL
|
|
11
11
|
*/
|
|
12
12
|
export declare function llmConfigFromEnv(env?: NodeJS.ProcessEnv): LlmConfig;
|
|
13
13
|
//# sourceMappingURL=env-llm.d.ts.map
|
package/dist/env-llm.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env-llm.d.ts","sourceRoot":"","sources":["../src/env-llm.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAe,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"env-llm.d.ts","sourceRoot":"","sources":["../src/env-llm.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAe,MAAM,YAAY,CAAC;AAqBzD;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,SAAS,CAiDX"}
|
package/dist/env-llm.js
CHANGED
|
@@ -5,23 +5,43 @@ const asProvider = (value, fallback) => {
|
|
|
5
5
|
normalized === "chatgpt") {
|
|
6
6
|
return "openai";
|
|
7
7
|
}
|
|
8
|
+
if (normalized === "openrouter" ||
|
|
9
|
+
normalized === "or") {
|
|
10
|
+
return "openrouter";
|
|
11
|
+
}
|
|
8
12
|
if (normalized === "ollama")
|
|
9
13
|
return "ollama";
|
|
10
14
|
return fallback;
|
|
11
15
|
};
|
|
12
16
|
/**
|
|
13
|
-
* Build LlmConfig from process.env
|
|
17
|
+
* Build LlmConfig from process.env.
|
|
14
18
|
*
|
|
15
19
|
* Env knobs:
|
|
16
|
-
* - LLM_PROVIDER / EMBEDDINGS_PROVIDER — ollama | openai
|
|
17
|
-
* - OLLAMA_MODEL / OPENAI_MODEL
|
|
18
|
-
* - INTENT_ROUTER_MODEL / OPENAI_INTENT_ROUTER_MODEL
|
|
20
|
+
* - LLM_PROVIDER / EMBEDDINGS_PROVIDER — ollama | openai | openrouter
|
|
21
|
+
* - OLLAMA_MODEL / OPENAI_MODEL / OPENROUTER_MODEL
|
|
22
|
+
* - INTENT_ROUTER_MODEL / OPENAI_INTENT_ROUTER_MODEL / OPENROUTER_INTENT_ROUTER_MODEL
|
|
19
23
|
* - OLLAMA_EMBEDDINGS_MODEL / OPENAI_EMBEDDINGS_MODEL
|
|
20
|
-
* - OLLAMA_BASE_URL / OPENAI_API_KEY
|
|
24
|
+
* - OLLAMA_BASE_URL / OPENAI_API_KEY / OPENROUTER_API_KEY / OPENROUTER_BASE_URL
|
|
21
25
|
*/
|
|
22
26
|
export function llmConfigFromEnv(env = process.env) {
|
|
23
27
|
const provider = asProvider(env.LLM_PROVIDER, "ollama");
|
|
24
28
|
const embeddingsProvider = asProvider(env.EMBEDDINGS_PROVIDER ?? env.LLM_PROVIDER, provider);
|
|
29
|
+
const openrouterBaseUrl = env.OPENROUTER_BASE_URL ?? "https://openrouter.ai/api/v1";
|
|
30
|
+
if (provider === "openrouter") {
|
|
31
|
+
return {
|
|
32
|
+
provider,
|
|
33
|
+
embeddingsProvider: embeddingsProvider === "openrouter" ? "ollama" : embeddingsProvider,
|
|
34
|
+
model: env.OPENROUTER_MODEL ?? "meta-llama/llama-4-scout",
|
|
35
|
+
intentRouterModel: env.OPENROUTER_INTENT_ROUTER_MODEL ??
|
|
36
|
+
env.OPENROUTER_MODEL ??
|
|
37
|
+
"meta-llama/llama-4-scout",
|
|
38
|
+
embeddingsModel: embeddingsProvider === "openai"
|
|
39
|
+
? (env.OPENAI_EMBEDDINGS_MODEL ?? "text-embedding-3-small")
|
|
40
|
+
: (env.OLLAMA_EMBEDDINGS_MODEL ?? "mxbai-embed-large:latest"),
|
|
41
|
+
baseUrl: openrouterBaseUrl,
|
|
42
|
+
apiKey: env.OPENROUTER_API_KEY,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
25
45
|
return {
|
|
26
46
|
provider,
|
|
27
47
|
embeddingsProvider,
|
package/dist/index.d.ts
CHANGED
|
@@ -3,9 +3,9 @@ export { createModels } from "./llm.js";
|
|
|
3
3
|
export { llmConfigFromEnv } from "./env-llm.js";
|
|
4
4
|
export { createRedis } from "./redis.js";
|
|
5
5
|
export { extractRawToolOutputs, extractToolCallArgs, getToolCallsFromMessages, createToolOutputExtractor, } from "./services/extract.js";
|
|
6
|
-
export { toolOutputMapToExtractors, createCompleteOnFinalize,
|
|
6
|
+
export { toolOutputMapToExtractors, createCompleteOnFinalize, } from "./services/simple-config.js";
|
|
7
7
|
export { isWizardInput } from "./services/flow-router.js";
|
|
8
8
|
export { getLastMessageContent } from "./utils/message.js";
|
|
9
9
|
export { normalize } from "./utils/normalize.js";
|
|
10
|
-
export type { AgentRuntimeConfig, CacheConfig, ChatFlowState, DetectedIntentResult, FinalizeFlowInput, FinalizeFlowResult, FlowResolution, FlowState, IntentBinding, IntentDefinition, IntentRegistry, InvokeInput, InvokeResult, LlmConfig, LlmIntentResult, LlmProvider, PromptContext, ToolCall, ToolExtractor, ToolExtractorMap, TracingConfig, } from "./types.js";
|
|
10
|
+
export type { AgentRuntimeConfig, CacheConfig, ChatFlowState, DetectedIntentResult, FinalizeFlowInput, FinalizeFlowResult, FlowResolution, FlowState, IntentBinding, IntentDefinition, IntentRegistry, InvokeInput, InvokeResult, LlmConfig, LlmIntentResult, LlmProvider, PromptContext, ToolCall, ToolExtractor, ToolExtractorMap, ToolOutputMap, TracingConfig, } from "./types.js";
|
|
11
11
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,KAAK,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,wBAAwB,EACxB,yBAAyB,GAC1B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,yBAAyB,EACzB,wBAAwB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,KAAK,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,wBAAwB,EACxB,yBAAyB,GAC1B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,yBAAyB,EACzB,wBAAwB,GACzB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD,YAAY,EACV,kBAAkB,EAClB,WAAW,EACX,aAAa,EACb,oBAAoB,EACpB,iBAAiB,EACjB,kBAAkB,EAClB,cAAc,EACd,SAAS,EACT,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,WAAW,EACX,YAAY,EACZ,SAAS,EACT,eAAe,EACf,WAAW,EACX,aAAa,EACb,QAAQ,EACR,aAAa,EACb,gBAAgB,EAChB,aAAa,EACb,aAAa,GACd,MAAM,YAAY,CAAC"}
|
package/dist/llm.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"llm.d.ts","sourceRoot":"","sources":["../src/llm.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6CAA6C,CAAC;AACjF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAG7D,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"llm.d.ts","sourceRoot":"","sources":["../src/llm.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6CAA6C,CAAC;AACjF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAG7D,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAoBzD,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,aAAa,CAAC;IACpB,YAAY,EAAE,aAAa,CAAC;IAC5B,UAAU,EAAE,UAAU,CAAC;IACvB,MAAM,EAAE;QACN,QAAQ,EAAE,WAAW,CAAC;QACtB,kBAAkB,EAAE,WAAW,CAAC;QAChC,KAAK,EAAE,MAAM,CAAC;QACd,iBAAiB,EAAE,MAAM,CAAC;QAC1B,eAAe,EAAE,MAAM,CAAC;KACzB,CAAC;CACH,CAAC;AAEF,wBAAgB,YAAY,CAAC,GAAG,EAAE,SAAS,GAAG,aAAa,CA8E1D"}
|
package/dist/llm.js
CHANGED
|
@@ -7,6 +7,10 @@ const normalizeProvider = (value) => {
|
|
|
7
7
|
normalized === "chatgpt") {
|
|
8
8
|
return "openai";
|
|
9
9
|
}
|
|
10
|
+
if (normalized === "openrouter" ||
|
|
11
|
+
normalized === "or") {
|
|
12
|
+
return "openrouter";
|
|
13
|
+
}
|
|
10
14
|
return "ollama";
|
|
11
15
|
};
|
|
12
16
|
export function createModels(llm) {
|
|
@@ -24,6 +28,19 @@ export function createModels(llm) {
|
|
|
24
28
|
apiKey: llm.apiKey,
|
|
25
29
|
});
|
|
26
30
|
}
|
|
31
|
+
if (provider === "openrouter") {
|
|
32
|
+
if (!llm.apiKey) {
|
|
33
|
+
throw new Error("llm.apiKey is required when provider is openrouter.");
|
|
34
|
+
}
|
|
35
|
+
return new ChatOpenAI({
|
|
36
|
+
model: modelName,
|
|
37
|
+
temperature,
|
|
38
|
+
apiKey: llm.apiKey,
|
|
39
|
+
configuration: {
|
|
40
|
+
baseURL: llm.baseUrl ?? "https://openrouter.ai/api/v1",
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
}
|
|
27
44
|
return new ChatOllama({
|
|
28
45
|
model: modelName,
|
|
29
46
|
temperature,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversation.d.ts","sourceRoot":"","sources":["../../src/services/conversation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,wBAAgB,yBAAyB,CAAC,YAAY,EAAE,YAAY;+
|
|
1
|
+
{"version":3,"file":"conversation.d.ts","sourceRoot":"","sources":["../../src/services/conversation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,wBAAgB,yBAAyB,CAAC,YAAY,EAAE,YAAY;+CAWV,MAAM;kDAwCT,OAAO,EAAE,KAAG,MAAM;gDAkB3D,MAAM,KACf,OAAO,CAAC,MAAM,CAAC;EAUnB"}
|
|
@@ -1,15 +1,26 @@
|
|
|
1
1
|
export function createConversationService(agentFactory) {
|
|
2
|
+
// Keep intent-router prompts small (matches Xel-agent defaults).
|
|
3
|
+
const AGENT_HISTORY_LIMIT = 4;
|
|
4
|
+
const INTENT_ROUTER_HISTORY_LIMIT = 3;
|
|
5
|
+
const INTENT_ROUTER_MESSAGE_CHAR_LIMIT = 200;
|
|
6
|
+
const isHumanOrAiMessage = (message) => {
|
|
7
|
+
const type = message._getType?.() ?? message.type ?? "";
|
|
8
|
+
return type === "human" || type === "ai";
|
|
9
|
+
};
|
|
2
10
|
const getManagedConversationMessages = async (threadId) => {
|
|
3
11
|
const state = await agentFactory.getAgentState(threadId);
|
|
4
12
|
const messages = state.values.messages ?? [];
|
|
5
13
|
return messages
|
|
6
14
|
.filter((message) => {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
15
|
+
if (!isHumanOrAiMessage(message))
|
|
16
|
+
return false;
|
|
17
|
+
const content = String(message?.content ?? "")
|
|
18
|
+
.toLowerCase();
|
|
19
|
+
return !(content.includes("tool failed") ||
|
|
20
|
+
content.includes("error") ||
|
|
21
|
+
content.includes("undefined"));
|
|
11
22
|
})
|
|
12
|
-
.slice(-
|
|
23
|
+
.slice(-AGENT_HISTORY_LIMIT);
|
|
13
24
|
};
|
|
14
25
|
const getMessageRole = (message) => {
|
|
15
26
|
const type = message._getType?.() ?? message.type ?? "";
|
|
@@ -17,7 +28,8 @@ export function createConversationService(agentFactory) {
|
|
|
17
28
|
return "User";
|
|
18
29
|
if (type === "ai")
|
|
19
30
|
return "Assistant";
|
|
20
|
-
|
|
31
|
+
// Should not happen due to isHumanOrAiMessage filter.
|
|
32
|
+
return "User";
|
|
21
33
|
};
|
|
22
34
|
const getMessageText = (message) => {
|
|
23
35
|
const content = message.content;
|
|
@@ -35,10 +47,10 @@ export function createConversationService(agentFactory) {
|
|
|
35
47
|
if (messages.length === 0)
|
|
36
48
|
return "(no prior messages)";
|
|
37
49
|
return messages
|
|
38
|
-
.slice(-
|
|
50
|
+
.slice(-INTENT_ROUTER_HISTORY_LIMIT)
|
|
39
51
|
.map((message) => {
|
|
40
52
|
const role = getMessageRole(message);
|
|
41
|
-
const text = getMessageText(message).slice(0,
|
|
53
|
+
const text = getMessageText(message).slice(0, INTENT_ROUTER_MESSAGE_CHAR_LIMIT);
|
|
42
54
|
return text ? `${role}: ${text}` : null;
|
|
43
55
|
})
|
|
44
56
|
.filter(Boolean)
|
|
@@ -5,6 +5,7 @@ export declare function createFlowRouter(options: {
|
|
|
5
5
|
stickyFlows: Set<string>;
|
|
6
6
|
menuMap: Record<string, string>;
|
|
7
7
|
normalizeIntent: (intent: string) => string;
|
|
8
|
+
intents: IntentDefinition[];
|
|
8
9
|
getEmbeddedIntents: () => Promise<{
|
|
9
10
|
name: string;
|
|
10
11
|
embedding: number[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flow-router.d.ts","sourceRoot":"","sources":["../../src/services/flow-router.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,oBAAoB,EACpB,iBAAiB,EACjB,kBAAkB,EAClB,cAAc,EACd,SAAS,EACT,gBAAgB,EAChB,eAAe,EAChB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAOjD,eAAO,MAAM,aAAa,GAAI,SAAS,MAAM,KAAG,OAI/C,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,OAAO,EAAE;IACxC,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,eAAe,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC;IAC5C,kBAAkB,EAAE,MAAM,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,CAAC,CAAC;IAC3E,sBAAsB,EAAE,CACtB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,KAC9C,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAAC;IACrC,qBAAqB,EAAE,CAAC,KAAK,EAAE;QAC7B,OAAO,EAAE,MAAM,CAAC;QAChB,mBAAmB,EAAE,MAAM,CAAC;QAC5B,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KAClC,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;IAC/B,kBAAkB,EAAE,CAClB,YAAY,EAAE,oBAAoB,EAClC,SAAS,EAAE,eAAe,KACvB,oBAAoB,GAAG;QAAE,MAAM,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAA;KAAE,CAAC;IAClE,SAAS,EAAE,SAAS,CAAC;IACrB,YAAY,CAAC,EAAE,CACb,KAAK,EAAE,iBAAiB,KACrB,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACtD,UAAU,CAAC,EAAE;QACX,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;CACH;sFAoBI;QACD,OAAO,EAAE,MAAM,CAAC;QAChB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,eAAe,EAAE,aAAa,GAAG,IAAI,CAAC;QACtC,mBAAmB,EAAE,MAAM,CAAC;KAC7B,KAAG,OAAO,CAAC,cAAc,CAAC;+
|
|
1
|
+
{"version":3,"file":"flow-router.d.ts","sourceRoot":"","sources":["../../src/services/flow-router.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,oBAAoB,EACpB,iBAAiB,EACjB,kBAAkB,EAClB,cAAc,EACd,SAAS,EACT,gBAAgB,EAChB,eAAe,EAChB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAOjD,eAAO,MAAM,aAAa,GAAI,SAAS,MAAM,KAAG,OAI/C,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,OAAO,EAAE;IACxC,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,eAAe,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC;IAC5C,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,kBAAkB,EAAE,MAAM,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,CAAC,CAAC;IAC3E,sBAAsB,EAAE,CACtB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,KAC9C,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAAC;IACrC,qBAAqB,EAAE,CAAC,KAAK,EAAE;QAC7B,OAAO,EAAE,MAAM,CAAC;QAChB,mBAAmB,EAAE,MAAM,CAAC;QAC5B,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KAClC,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;IAC/B,kBAAkB,EAAE,CAClB,YAAY,EAAE,oBAAoB,EAClC,SAAS,EAAE,eAAe,KACvB,oBAAoB,GAAG;QAAE,MAAM,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAA;KAAE,CAAC;IAClE,SAAS,EAAE,SAAS,CAAC;IACrB,YAAY,CAAC,EAAE,CACb,KAAK,EAAE,iBAAiB,KACrB,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACtD,UAAU,CAAC,EAAE;QACX,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;CACH;sFAoBI;QACD,OAAO,EAAE,MAAM,CAAC;QAChB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,eAAe,EAAE,aAAa,GAAG,IAAI,CAAC;QACtC,mBAAmB,EAAE,MAAM,CAAC;KAC7B,KAAG,OAAO,CAAC,cAAc,CAAC;+BAyLlB,iBAAiB,KACvB,OAAO,CAAC,kBAAkB,CAAC;EAkB/B;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,gBAAgB,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,CAE7E;AAED,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,CAAC"}
|
|
@@ -31,6 +31,18 @@ export function createFlowRouter(options) {
|
|
|
31
31
|
const cachedIntent = cachedFlowState?.intent
|
|
32
32
|
? options.normalizeIntent(cachedFlowState.intent)
|
|
33
33
|
: null;
|
|
34
|
+
// Token reduction: when we already know a sticky wizard intent,
|
|
35
|
+
// and the user replies with wizard-like input, skip router LLM.
|
|
36
|
+
// (Xel-agent equivalent: shouldSkipIntentClassification()).
|
|
37
|
+
if (cachedIntent !== null &&
|
|
38
|
+
options.stickyFlows.has(cachedIntent) &&
|
|
39
|
+
isWizardInput(message)) {
|
|
40
|
+
return {
|
|
41
|
+
messageIntent: { intent: cachedIntent, score: 1 },
|
|
42
|
+
flow: { active: true, intent: cachedIntent },
|
|
43
|
+
promptIntent: cachedIntent,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
34
46
|
const menuIntent = resolveGreetingMenuSelection(message, cachedIntent);
|
|
35
47
|
if (menuIntent) {
|
|
36
48
|
const sticky = options.stickyFlows.has(menuIntent);
|
|
@@ -40,6 +52,18 @@ export function createFlowRouter(options) {
|
|
|
40
52
|
promptIntent: menuIntent,
|
|
41
53
|
};
|
|
42
54
|
}
|
|
55
|
+
// Regex fast-path: skip LLM/embeddings if a pattern matches
|
|
56
|
+
const intentsWithRegex = options.intents.filter((i) => i.regex);
|
|
57
|
+
for (const intent of intentsWithRegex) {
|
|
58
|
+
if (intent.regex.test(message)) {
|
|
59
|
+
const sticky = options.stickyFlows.has(intent.name);
|
|
60
|
+
return {
|
|
61
|
+
messageIntent: { intent: intent.name, score: 1 },
|
|
62
|
+
flow: { active: sticky, intent: sticky ? intent.name : null },
|
|
63
|
+
promptIntent: intent.name,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
}
|
|
43
67
|
const embeddedIntents = await options.getEmbeddedIntents();
|
|
44
68
|
const [embeddingScores, llmResult] = await Promise.all([
|
|
45
69
|
options.scoreIntentsForMessage(message, embeddedIntents),
|
|
@@ -1,22 +1,5 @@
|
|
|
1
|
-
import type { ToolExtractorMap } from "../types.js";
|
|
2
|
-
|
|
3
|
-
* Simple tool → output key map.
|
|
4
|
-
*
|
|
5
|
-
* @example
|
|
6
|
-
* {
|
|
7
|
-
* create_campaign: "campaign",
|
|
8
|
-
* buy_airtime: "buyAirtime",
|
|
9
|
-
* propose_tickets: { as: "tickets", from: "tickets", initial: [] },
|
|
10
|
-
* }
|
|
11
|
-
*/
|
|
12
|
-
export type ToolOutputMap = Record<string, string | {
|
|
13
|
-
/** Key written onto toolOutputs / extras. */
|
|
14
|
-
as: string;
|
|
15
|
-
/** Nested field on tool args (e.g. args.tickets). */
|
|
16
|
-
from?: string;
|
|
17
|
-
/** Seed value when nothing extracted yet. */
|
|
18
|
-
initial?: unknown;
|
|
19
|
-
}>;
|
|
1
|
+
import type { ToolExtractorMap, ToolOutputMap } from "../types.js";
|
|
2
|
+
export type { ToolOutputMap };
|
|
20
3
|
export declare function resolveToolOutputKey(toolName: string, map: ToolOutputMap): string;
|
|
21
4
|
/** Build first-wins extractors + initial seed from a simple map. */
|
|
22
5
|
export declare function toolOutputMapToExtractors(map: ToolOutputMap): {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"simple-config.d.ts","sourceRoot":"","sources":["../../src/services/simple-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,
|
|
1
|
+
{"version":3,"file":"simple-config.d.ts","sourceRoot":"","sources":["../../src/services/simple-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEnE,YAAY,EAAE,aAAa,EAAE,CAAC;AAE9B,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,aAAa,GACjB,MAAM,CAIR;AAED,oEAAoE;AACpE,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,aAAa,GAAG;IAC7D,cAAc,EAAE,gBAAgB,CAAC;IACjC,kBAAkB,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnD,CAkCA;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE;IAChD,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B,IAGS,wBAGL;IACD,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE;QAAE,MAAM,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IACjD,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;;;;;;;EA0BF"}
|
package/dist/types.d.ts
CHANGED
|
@@ -2,8 +2,24 @@ import type { BaseChatModel } from "@langchain/core/language_models/chat_models"
|
|
|
2
2
|
import type { Embeddings } from "@langchain/core/embeddings";
|
|
3
3
|
import type { DynamicStructuredTool } from "@langchain/core/tools";
|
|
4
4
|
import type { BaseCheckpointSaver } from "@langchain/langgraph-checkpoint";
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Simple tool → output key map.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* {
|
|
10
|
+
* create_campaign: "campaign",
|
|
11
|
+
* buy_airtime: "buyAirtime",
|
|
12
|
+
* propose_tickets: { as: "tickets", from: "tickets", initial: [] },
|
|
13
|
+
* }
|
|
14
|
+
*/
|
|
15
|
+
export type ToolOutputMap = Record<string, string | {
|
|
16
|
+
/** Key written onto toolOutputs / extras. */
|
|
17
|
+
as: string;
|
|
18
|
+
/** Nested field on tool args (e.g. args.tickets). */
|
|
19
|
+
from?: string;
|
|
20
|
+
/** Seed value when nothing extracted yet. */
|
|
21
|
+
initial?: unknown;
|
|
22
|
+
}>;
|
|
7
23
|
/** Intent catalog entry used for embedding routing + sticky-flow rules. */
|
|
8
24
|
export type IntentDefinition = {
|
|
9
25
|
name: string;
|
|
@@ -12,6 +28,8 @@ export type IntentDefinition = {
|
|
|
12
28
|
sticky?: boolean;
|
|
13
29
|
/** Short description for the LLM intent router. */
|
|
14
30
|
description?: string;
|
|
31
|
+
/** Fast-path regex: if message matches, skip LLM/embeddings and use this intent directly. */
|
|
32
|
+
regex?: RegExp;
|
|
15
33
|
};
|
|
16
34
|
/** Context passed into prompt builders (app-defined shape). */
|
|
17
35
|
export type PromptContext = {
|
|
@@ -49,7 +67,7 @@ export type FlowResolution = {
|
|
|
49
67
|
promptIntent: string;
|
|
50
68
|
llmResult?: LlmIntentResult;
|
|
51
69
|
};
|
|
52
|
-
export type LlmProvider = "ollama" | "openai";
|
|
70
|
+
export type LlmProvider = "ollama" | "openai" | "openrouter";
|
|
53
71
|
export type LlmConfig = {
|
|
54
72
|
provider: LlmProvider;
|
|
55
73
|
model: string;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6CAA6C,CAAC;AACjF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AACnE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "llm-agent-runtime",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "Reusable LangGraph agent runtime: intent routing, sticky flows, Redis checkpointer, optional answer cache",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"type": "module",
|
|
@@ -13,13 +13,15 @@
|
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
15
|
"files": [
|
|
16
|
-
"dist"
|
|
16
|
+
"dist",
|
|
17
|
+
"USAGE.md",
|
|
18
|
+
"README.md"
|
|
17
19
|
],
|
|
18
20
|
"scripts": {
|
|
19
21
|
"build": "tsc -p tsconfig.json",
|
|
20
22
|
"dev": "tsc -p tsconfig.json --watch",
|
|
21
23
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
22
|
-
"test": "tsx --test src
|
|
24
|
+
"test": "tsx --test src/services/extract.test.ts && tsx --test src/services/simple-config.test.ts",
|
|
23
25
|
"prepublishOnly": "pnpm build && pnpm test"
|
|
24
26
|
},
|
|
25
27
|
"publishConfig": {
|