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 CHANGED
@@ -1,5 +1,5 @@
1
1
  # llm-agent-runtime
2
2
 
3
- Reusable LangGraph agent runtime (intent routing, sticky flows, checkpointer, tool extractors).
3
+ Reusable LangGraph agent runtime: intent routing, sticky flows, checkpointer, tool outputs.
4
4
 
5
- See **llm-agent-runtime-usage-guide.pdf** in this folder for the usage guide.
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,CAsOvB"}
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"}
@@ -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
- (config.completeOn?.length
67
+ (completeOn?.length
57
68
  ? createCompleteOnFinalize({
58
- completeOn: config.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 (Xel / recharge defaults).
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
@@ -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;AAezD;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,SAAS,CA6BX"}
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 (Xel / recharge defaults).
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, type ToolOutputMap, } from "./services/simple-config.js";
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
@@ -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,EACxB,KAAK,aAAa,GACnB,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,GACd,MAAM,YAAY,CAAC"}
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;AAczD,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,CAgE1D"}
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;+CACV,MAAM;kDAsCT,OAAO,EAAE,KAAG,MAAM;gDAe3D,MAAM,KACf,OAAO,CAAC,MAAM,CAAC;EAUnB"}
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
- const content = String(message?.content ?? "").toLowerCase();
8
- return (!content.includes("tool failed") &&
9
- !content.includes("error") &&
10
- !content.includes("undefined"));
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(-8);
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
- return "System";
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(-6)
50
+ .slice(-INTENT_ROUTER_HISTORY_LIMIT)
39
51
  .map((message) => {
40
52
  const role = getMessageRole(message);
41
- const text = getMessageText(message).slice(0, 300);
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;+BA6JlB,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"}
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,MAAM,aAAa,CAAC;AAEpD;;;;;;;;;GASG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,CAChC,MAAM,EACJ,MAAM,GACN;IACE,6CAA6C;IAC7C,EAAE,EAAE,MAAM,CAAC;IACX,qDAAqD;IACrD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6CAA6C;IAC7C,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CACJ,CAAC;AAEF,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"}
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
- import type { ToolOutputMap } from "./services/simple-config.js";
6
- export type { ToolOutputMap };
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;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
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.2",
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/**/*.test.ts",
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": {