llm-agent-runtime 0.1.0 → 0.1.5

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
- Usage docs deferred until the package is tested end-to-end.
5
+ **Docs:** [USAGE.md](./USAGE.md)
package/USAGE.md ADDED
@@ -0,0 +1,391 @@
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`) | Hybrid 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
+
128
+ ---
129
+
130
+ ## Intents
131
+
132
+ ```ts
133
+ intents: [
134
+ {
135
+ name: "greetings",
136
+ examples: ["hi", "hello"],
137
+ description: "Shown to the LLM router",
138
+ },
139
+ {
140
+ name: "create_campaign",
141
+ examples: ["create a campaign"],
142
+ sticky: true, // keep this flow across turns until completeOn fires
143
+ },
144
+ ]
145
+ ```
146
+
147
+ - **examples** — embedding routing
148
+ - **sticky** — multi-step wizards
149
+ - **description** — LLM intent router
150
+
151
+ ---
152
+
153
+ ## Prompts & tools (`intentRegistry`)
154
+
155
+ ```ts
156
+ intentRegistry: {
157
+ greetings: {
158
+ prompt: (ctx) => string,
159
+ tools: (phoneKey) => DynamicStructuredTool[],
160
+ },
161
+ }
162
+ ```
163
+
164
+ `prompt` receives:
165
+
166
+ ```ts
167
+ {
168
+ hasConversationHistory: boolean
169
+ intent: string
170
+ intentScore?: number
171
+ message?: string
172
+ context?: Record<string, unknown> // whatever you passed to invoke()
173
+ }
174
+ ```
175
+
176
+ Or use one builder for everything:
177
+
178
+ ```ts
179
+ buildSystemPrompt: (ctx) => combineGeneralAndIntent(ctx)
180
+ ```
181
+
182
+ ---
183
+
184
+ ## Tool outputs (`toolOutputMap`)
185
+
186
+ Replaces hand-written extractors:
187
+
188
+ ```ts
189
+ toolOutputMap: {
190
+ create_campaign: "campaign",
191
+ buy_airtime: "buyAirtime",
192
+ // Nested field on args + seed:
193
+ propose_tickets: { as: "tickets", from: "tickets", initial: [] },
194
+ }
195
+ ```
196
+
197
+ Result lands on `result.toolOutputs` and completed keys on `result.extras`.
198
+
199
+ ---
200
+
201
+ ## Flow completion (`completeOn`)
202
+
203
+ Pass tool **names**. When any of them produces output, the sticky flow ends:
204
+
205
+ ```ts
206
+ completeOn: ["create_campaign", "buy_airtime", "add_airtime"]
207
+ ```
208
+
209
+ If you omit `completeOn`, the library defaults `completeOn` to the keys of `toolOutputMap`.
210
+
211
+ 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.
212
+
213
+ ---
214
+
215
+ ## Menu digits (`menuMap`)
216
+
217
+ Optional. Needed only if users pick a numbered menu (`1`, `2`, …).
218
+
219
+ The **prompt** shows the menu text. **`menuMap`** tells the **router** that `"1"` means `create_campaign`. Without it, a bare `"1"` is not reliably routed.
220
+
221
+ ```ts
222
+ menuMap: {
223
+ "1": "create_campaign",
224
+ "2": "support_campaign",
225
+ "3": "buy_airtime_and_data",
226
+ }
227
+ ```
228
+
229
+ ---
230
+
231
+ ## Invoke
232
+
233
+ ```ts
234
+ const result = await runtime.invoke({
235
+ message: "hi",
236
+ threadId: "whatsapp:234...", // conversation / checkpoint id
237
+ phoneKey: "234...", // optional; passed to tools()
238
+ explicitIntent: "greetings", // optional; skips hybrid router
239
+ context: {
240
+ contactName: "Ada",
241
+ userInfo: { email: "ada@example.com" },
242
+ },
243
+ });
244
+ ```
245
+
246
+ **Result**
247
+
248
+ ```ts
249
+ {
250
+ messages: unknown[]
251
+ answer?: string
252
+ intent: { intent: string, score: number }
253
+ flow: { active: boolean, intent: string | null }
254
+ toolOutputs: Record<string, unknown>
255
+ flowCompleted: boolean
256
+ extras?: Record<string, unknown>
257
+ router?: { action: "continue" | "switch" | "cancel", reason?: string }
258
+ }
259
+ ```
260
+
261
+ ---
262
+
263
+ ## Lifecycle
264
+
265
+ ```ts
266
+ await runtime.connect() // Redis (if redisUrl set)
267
+ await runtime.invoke(...)
268
+ await runtime.clearFlow(id) // drop sticky flow state
269
+ await runtime.disconnect()
270
+ ```
271
+
272
+ ---
273
+
274
+ ## Env vars (when `llm` is omitted)
275
+
276
+ | Variable | Notes |
277
+ | --- | --- |
278
+ | `LLM_PROVIDER` | `ollama` (default) or `openai` |
279
+ | `EMBEDDINGS_PROVIDER` | defaults to `LLM_PROVIDER` |
280
+ | `OLLAMA_MODEL` | default `qwen2.5:7b` |
281
+ | `OLLAMA_BASE_URL` | e.g. `http://localhost:11434` |
282
+ | `INTENT_ROUTER_MODEL` | optional smaller router model |
283
+ | `OLLAMA_EMBEDDINGS_MODEL` | default `mxbai-embed-large:latest` |
284
+ | `OPENAI_API_KEY` | required for openai |
285
+ | `OPENAI_MODEL` | default `gpt-4o-mini` |
286
+ | `OPENAI_EMBEDDINGS_MODEL` | default `text-embedding-3-small` |
287
+ | `REDIS_URL` | your app usually passes this as `redisUrl` |
288
+ | `ANSWER_CACHE` | app convention: `"1"` to enable cache |
289
+
290
+ Or pass LLM explicitly:
291
+
292
+ ```ts
293
+ import { llmConfigFromEnv } from "llm-agent-runtime";
294
+
295
+ createAgentRuntime({
296
+ llm: llmConfigFromEnv(),
297
+ // or
298
+ llm: { provider: "openai", model: "gpt-4o-mini", apiKey: "..." },
299
+ })
300
+ ```
301
+
302
+ ---
303
+
304
+ ## Minimal app shape (recommended)
305
+
306
+ ```
307
+ your-app/
308
+ agent/
309
+ runtime.ts # createAgentRuntime({ ... })
310
+ intents.ts # intents + menuMap + aliases
311
+ prompts/ # prompt strings
312
+ tools/ # LangChain tools / API clients
313
+ controllers/ # HTTP / WhatsApp — call runtime.invoke()
314
+ ```
315
+
316
+ Keep channel adapters and product APIs **out** of this package.
317
+
318
+ ---
319
+
320
+ ## Full example (Xel-like)
321
+
322
+ ```ts
323
+ import { createAgentRuntime } from "llm-agent-runtime";
324
+
325
+ const runtime = await createAgentRuntime({
326
+ redisUrl: process.env.REDIS_URL ?? "redis://localhost:6379",
327
+ cache: { enabled: process.env.ANSWER_CACHE === "1" },
328
+
329
+ intents: [
330
+ { name: "greetings", examples: ["hi", "hello"] },
331
+ {
332
+ name: "create_campaign",
333
+ examples: ["create a campaign"],
334
+ sticky: true,
335
+ },
336
+ {
337
+ name: "buy_airtime_and_data",
338
+ examples: ["buy airtime", "vend airtime"],
339
+ sticky: true,
340
+ },
341
+ ],
342
+
343
+ menuMap: {
344
+ "1": "create_campaign",
345
+ "4": "buy_airtime_and_data",
346
+ },
347
+
348
+ intentAliases: {
349
+ buy_airtime: "buy_airtime_and_data",
350
+ },
351
+
352
+ intentRegistry: {
353
+ greetings: {
354
+ prompt: (ctx) => `Greet ${ctx.context?.contactName ?? "there"}. Show menu 1–7.`,
355
+ tools: () => [],
356
+ },
357
+ create_campaign: {
358
+ prompt: () => "Walk through campaign creation.",
359
+ tools: (phoneKey) => createCampaignTools(phoneKey),
360
+ },
361
+ buy_airtime_and_data: {
362
+ prompt: () => "Help buy airtime/data.",
363
+ tools: (phoneKey) => airtimeTools(phoneKey),
364
+ },
365
+ },
366
+
367
+ toolOutputMap: {
368
+ create_campaign: "campaign",
369
+ buy_airtime: "buyAirtime",
370
+ add_airtime: "addAirtime",
371
+ },
372
+ completeOn: ["create_campaign", "buy_airtime", "add_airtime"],
373
+ });
374
+
375
+ await runtime.connect();
376
+ ```
377
+
378
+ ---
379
+
380
+ ## Exports
381
+
382
+ ```ts
383
+ import {
384
+ createAgentRuntime,
385
+ llmConfigFromEnv,
386
+ getLastMessageContent,
387
+ // advanced (usually not needed)
388
+ createToolOutputExtractor,
389
+ toolOutputMapToExtractors,
390
+ } from "llm-agent-runtime";
391
+ ```
@@ -4,6 +4,8 @@ export type AgentRuntime = {
4
4
  connect: () => Promise<void>;
5
5
  disconnect: () => Promise<void>;
6
6
  clearFlow: (threadId: string) => Promise<void>;
7
+ /** Clears LangGraph checkpoint thread (conversation memory). */
8
+ clearThread: (threadId: string) => Promise<void>;
7
9
  getCachedAnswer: (message: string) => Promise<string | undefined>;
8
10
  setCachedAnswer: (message: string, answer: string) => Promise<void>;
9
11
  /** Invalidate embedding cache after changing intent examples at runtime. */
@@ -1 +1 @@
1
- {"version":3,"file":"create-runtime.d.ts","sourceRoot":"","sources":["../src/create-runtime.ts"],"names":[],"mappings":"AAgBA,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,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,CA6MvB"}
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,CA0OvB"}
@@ -1,10 +1,12 @@
1
1
  import { createAgentFactory } from "./agent.js";
2
2
  import { createModels } from "./llm.js";
3
+ import { llmConfigFromEnv } from "./env-llm.js";
3
4
  import { createRedis } from "./redis.js";
4
5
  import { createAgentRunner } from "./services/agent-runner.js";
5
6
  import { createChatCache } from "./services/chat-cache.js";
6
7
  import { createConversationService } from "./services/conversation.js";
7
8
  import { createToolOutputExtractor, extractRawToolOutputs } from "./services/extract.js";
9
+ import { createCompleteOnFinalize, toolOutputMapToExtractors, } from "./services/simple-config.js";
8
10
  import { createFlowRouter, stickySetFromIntents, } from "./services/flow-router.js";
9
11
  import { createIntentEmbeddings } from "./services/intent-embeddings.js";
10
12
  import { createIntentRouter } from "./services/intent-router.js";
@@ -40,10 +42,25 @@ export async function createAgentRuntime(config) {
40
42
  };
41
43
  const stickyFlows = stickySetFromIntents(config.intents);
42
44
  const menuMap = config.menuMap ?? {};
43
- const created = createModels(config.llm);
45
+ const llm = config.llm ?? llmConfigFromEnv();
46
+ const created = createModels(llm);
44
47
  const chat = config.models?.chat ?? created.chat;
45
48
  const intentRouterModel = config.models?.intentRouter ?? created.intentRouter;
46
49
  const embeddings = config.models?.embeddings ?? created.embeddings;
50
+ const fromMap = config.toolOutputMap
51
+ ? toolOutputMapToExtractors(config.toolOutputMap)
52
+ : null;
53
+ const toolExtractors = config.toolExtractors ?? fromMap?.toolExtractors;
54
+ const initialToolOutputs = config.initialToolOutputs ?? fromMap?.initialToolOutputs;
55
+ const completeOn = config.completeOn ??
56
+ (config.toolOutputMap ? Object.keys(config.toolOutputMap) : undefined);
57
+ const finalizeFlow = config.finalizeFlow ??
58
+ (completeOn?.length
59
+ ? createCompleteOnFinalize({
60
+ completeOn,
61
+ toolOutputMap: config.toolOutputMap,
62
+ })
63
+ : undefined);
47
64
  // Redis client when redisUrl is set (flow state + optional answer cache)
48
65
  const redis = config.redisUrl
49
66
  ? createRedis(config.redisUrl)
@@ -91,12 +108,14 @@ export async function createAgentRuntime(config) {
91
108
  classifyIntentWithLlm: intentRouter.classifyIntentWithLlm,
92
109
  mergeIntentResults: intentRouter.mergeIntentResults,
93
110
  chatCache,
94
- finalizeFlow: config.finalizeFlow,
111
+ finalizeFlow,
95
112
  thresholds: config.thresholds,
96
113
  });
97
114
  const extractToolOutputs = config.extractToolOutputs ??
98
- (config.toolExtractors
99
- ? createToolOutputExtractor(config.toolExtractors, config.initialToolOutputs, { includeUnknown: config.includeUnknownToolOutputs ?? false })
115
+ (toolExtractors
116
+ ? createToolOutputExtractor(toolExtractors, initialToolOutputs, {
117
+ includeUnknown: config.includeUnknownToolOutputs ?? false,
118
+ })
100
119
  : extractRawToolOutputs);
101
120
  const buildSystemPrompt = config.buildSystemPrompt ??
102
121
  ((ctx) => {
@@ -190,6 +209,13 @@ export async function createAgentRuntime(config) {
190
209
  await redis?.disconnect();
191
210
  },
192
211
  clearFlow: chatCache.clearChatCacheFlowState,
212
+ clearThread: async (threadId) => {
213
+ const saver = agentFactory.checkpointer;
214
+ if (typeof saver.deleteThread === "function") {
215
+ await saver.deleteThread(threadId);
216
+ }
217
+ await chatCache.clearChatCacheFlowState(threadId);
218
+ },
193
219
  getCachedAnswer: chatCache.getCachedAnswer,
194
220
  setCachedAnswer: chatCache.setCachedAnswer,
195
221
  invalidateIntentEmbeddings: intentEmbeddings.invalidate,
@@ -0,0 +1,13 @@
1
+ import type { LlmConfig } from "./types.js";
2
+ /**
3
+ * Build LlmConfig from process.env (Xel / recharge defaults).
4
+ *
5
+ * Env knobs:
6
+ * - LLM_PROVIDER / EMBEDDINGS_PROVIDER — ollama | openai
7
+ * - OLLAMA_MODEL / OPENAI_MODEL
8
+ * - INTENT_ROUTER_MODEL / OPENAI_INTENT_ROUTER_MODEL
9
+ * - OLLAMA_EMBEDDINGS_MODEL / OPENAI_EMBEDDINGS_MODEL
10
+ * - OLLAMA_BASE_URL / OPENAI_API_KEY
11
+ */
12
+ export declare function llmConfigFromEnv(env?: NodeJS.ProcessEnv): LlmConfig;
13
+ //# sourceMappingURL=env-llm.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,44 @@
1
+ const asProvider = (value, fallback) => {
2
+ const normalized = value?.trim().toLowerCase();
3
+ if (normalized === "openai" ||
4
+ normalized === "gpt" ||
5
+ normalized === "chatgpt") {
6
+ return "openai";
7
+ }
8
+ if (normalized === "ollama")
9
+ return "ollama";
10
+ return fallback;
11
+ };
12
+ /**
13
+ * Build LlmConfig from process.env (Xel / recharge defaults).
14
+ *
15
+ * Env knobs:
16
+ * - LLM_PROVIDER / EMBEDDINGS_PROVIDER — ollama | openai
17
+ * - OLLAMA_MODEL / OPENAI_MODEL
18
+ * - INTENT_ROUTER_MODEL / OPENAI_INTENT_ROUTER_MODEL
19
+ * - OLLAMA_EMBEDDINGS_MODEL / OPENAI_EMBEDDINGS_MODEL
20
+ * - OLLAMA_BASE_URL / OPENAI_API_KEY
21
+ */
22
+ export function llmConfigFromEnv(env = process.env) {
23
+ const provider = asProvider(env.LLM_PROVIDER, "ollama");
24
+ const embeddingsProvider = asProvider(env.EMBEDDINGS_PROVIDER ?? env.LLM_PROVIDER, provider);
25
+ return {
26
+ provider,
27
+ embeddingsProvider,
28
+ model: provider === "openai"
29
+ ? (env.OPENAI_MODEL ?? "gpt-4o-mini")
30
+ : (env.OLLAMA_MODEL ?? "qwen2.5:7b"),
31
+ intentRouterModel: provider === "openai"
32
+ ? (env.OPENAI_INTENT_ROUTER_MODEL ??
33
+ env.OPENAI_MODEL ??
34
+ "gpt-4o-mini")
35
+ : (env.INTENT_ROUTER_MODEL ??
36
+ env.OLLAMA_INTENT_ROUTER_MODEL ??
37
+ "qwen2.5:7b"),
38
+ embeddingsModel: embeddingsProvider === "openai"
39
+ ? (env.OPENAI_EMBEDDINGS_MODEL ?? "text-embedding-3-small")
40
+ : (env.OLLAMA_EMBEDDINGS_MODEL ?? "mxbai-embed-large:latest"),
41
+ baseUrl: env.OLLAMA_BASE_URL,
42
+ apiKey: env.OPENAI_API_KEY,
43
+ };
44
+ }
package/dist/index.d.ts CHANGED
@@ -1,9 +1,11 @@
1
1
  export { createAgentRuntime, type AgentRuntime } from "./create-runtime.js";
2
2
  export { createModels } from "./llm.js";
3
+ export { llmConfigFromEnv } from "./env-llm.js";
3
4
  export { createRedis } from "./redis.js";
4
5
  export { extractRawToolOutputs, extractToolCallArgs, getToolCallsFromMessages, createToolOutputExtractor, } from "./services/extract.js";
6
+ export { toolOutputMapToExtractors, createCompleteOnFinalize, } from "./services/simple-config.js";
5
7
  export { isWizardInput } from "./services/flow-router.js";
6
8
  export { getLastMessageContent } from "./utils/message.js";
7
9
  export { normalize } from "./utils/normalize.js";
8
- 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";
9
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,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,wBAAwB,EACxB,yBAAyB,GAC1B,MAAM,uBAAuB,CAAC;AAC/B,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/index.js CHANGED
@@ -1,7 +1,9 @@
1
1
  export { createAgentRuntime } from "./create-runtime.js";
2
2
  export { createModels } from "./llm.js";
3
+ export { llmConfigFromEnv } from "./env-llm.js";
3
4
  export { createRedis } from "./redis.js";
4
5
  export { extractRawToolOutputs, extractToolCallArgs, getToolCallsFromMessages, createToolOutputExtractor, } from "./services/extract.js";
6
+ export { toolOutputMapToExtractors, createCompleteOnFinalize, } from "./services/simple-config.js";
5
7
  export { isWizardInput } from "./services/flow-router.js";
6
8
  export { getLastMessageContent } from "./utils/message.js";
7
9
  export { normalize } from "./utils/normalize.js";
@@ -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)
@@ -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,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;+BA4KlB,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);
@@ -0,0 +1,32 @@
1
+ import type { ToolExtractorMap, ToolOutputMap } from "../types.js";
2
+ export type { ToolOutputMap };
3
+ export declare function resolveToolOutputKey(toolName: string, map: ToolOutputMap): string;
4
+ /** Build first-wins extractors + initial seed from a simple map. */
5
+ export declare function toolOutputMapToExtractors(map: ToolOutputMap): {
6
+ toolExtractors: ToolExtractorMap;
7
+ initialToolOutputs: () => Record<string, unknown>;
8
+ };
9
+ /**
10
+ * Default finalize: complete sticky flow when any listed tool produced output.
11
+ * `completeOn` is tool names (keys of toolOutputMap / LangChain tool name).
12
+ */
13
+ export declare function createCompleteOnFinalize(options: {
14
+ completeOn: string[];
15
+ toolOutputMap?: ToolOutputMap;
16
+ }): ({ flow, toolOutputs, }: {
17
+ threadId: string;
18
+ promptIntent: string;
19
+ flow: {
20
+ active: boolean;
21
+ intent: string | null;
22
+ };
23
+ toolOutputs: Record<string, unknown>;
24
+ }) => {
25
+ flowCompleted: boolean;
26
+ flow: {
27
+ active: boolean;
28
+ intent: string | null;
29
+ };
30
+ extras: Record<string, unknown>;
31
+ };
32
+ //# sourceMappingURL=simple-config.d.ts.map
@@ -0,0 +1 @@
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"}
@@ -0,0 +1,70 @@
1
+ export function resolveToolOutputKey(toolName, map) {
2
+ const entry = map[toolName];
3
+ if (!entry)
4
+ return toolName;
5
+ return typeof entry === "string" ? entry : entry.as;
6
+ }
7
+ /** Build first-wins extractors + initial seed from a simple map. */
8
+ export function toolOutputMapToExtractors(map) {
9
+ const toolExtractors = {};
10
+ const initial = {};
11
+ for (const [toolName, entry] of Object.entries(map)) {
12
+ if (typeof entry === "string") {
13
+ toolExtractors[toolName] = (args, acc) => {
14
+ if (acc[entry] !== undefined)
15
+ return;
16
+ acc[entry] = args;
17
+ };
18
+ continue;
19
+ }
20
+ const key = entry.as;
21
+ if (entry.initial !== undefined && !(key in initial)) {
22
+ initial[key] = entry.initial;
23
+ }
24
+ toolExtractors[toolName] = (args, acc) => {
25
+ const current = acc[key];
26
+ if (Array.isArray(current) && current.length > 0)
27
+ return;
28
+ if (current !== undefined && !Array.isArray(current))
29
+ return;
30
+ acc[key] =
31
+ entry.from !== undefined
32
+ ? (args[entry.from] ?? entry.initial ?? [])
33
+ : args;
34
+ };
35
+ }
36
+ return {
37
+ toolExtractors,
38
+ initialToolOutputs: () => ({ ...initial }),
39
+ };
40
+ }
41
+ /**
42
+ * Default finalize: complete sticky flow when any listed tool produced output.
43
+ * `completeOn` is tool names (keys of toolOutputMap / LangChain tool name).
44
+ */
45
+ export function createCompleteOnFinalize(options) {
46
+ const { completeOn, toolOutputMap = {} } = options;
47
+ return ({ flow, toolOutputs, }) => {
48
+ const extras = {};
49
+ let flowCompleted = false;
50
+ for (const toolName of completeOn) {
51
+ const key = resolveToolOutputKey(toolName, toolOutputMap);
52
+ const value = toolOutputs[key];
53
+ const hit = Array.isArray(value)
54
+ ? value.length > 0
55
+ : value !== undefined && value !== null;
56
+ if (hit) {
57
+ flowCompleted = true;
58
+ extras[key] = value;
59
+ }
60
+ }
61
+ return {
62
+ flowCompleted,
63
+ flow: {
64
+ active: flow.active && !flowCompleted,
65
+ intent: flowCompleted ? null : flow.intent,
66
+ },
67
+ extras,
68
+ };
69
+ };
70
+ }
package/dist/types.d.ts CHANGED
@@ -2,6 +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
+ * 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
+ }>;
5
23
  /** Intent catalog entry used for embedding routing + sticky-flow rules. */
6
24
  export type IntentDefinition = {
7
25
  name: string;
@@ -118,12 +136,19 @@ export type InvokeResult = {
118
136
  };
119
137
  export type AgentRuntimeConfig = {
120
138
  redisUrl?: string;
121
- llm: LlmConfig;
139
+ /**
140
+ * LLM config. Omit to use `llmConfigFromEnv()` (OLLAMA_* / OPENAI_* env vars).
141
+ */
142
+ llm?: LlmConfig;
122
143
  /** Intent catalog for embeddings + sticky flags. */
123
144
  intents: IntentDefinition[];
124
145
  /** Per-intent prompt + tools factory. */
125
146
  intentRegistry: IntentRegistry;
126
- /** Digit / short-code → intent (e.g. greeting menu "1" → create_campaign). */
147
+ /**
148
+ * Optional digit → intent routing (e.g. menu "1" → create_campaign).
149
+ * Prompt text alone cannot switch intent when the user types a number —
150
+ * keep this if you use a numbered menu. Safe to omit otherwise.
151
+ */
127
152
  menuMap?: Record<string, string>;
128
153
  /** Map legacy/alias names onto catalog intents. */
129
154
  intentAliases?: Record<string, string>;
@@ -133,19 +158,27 @@ export type AgentRuntimeConfig = {
133
158
  /** Custom system prompt builder; default uses intentRegistry[intent].prompt. */
134
159
  buildSystemPrompt?: (ctx: PromptContext) => string;
135
160
  /**
136
- * Per-tool extractors (Xel extractToolCall style).
137
- * Prefer this over a custom `extractToolOutputs` unless you need full control.
161
+ * Simple toolName output key map (preferred).
162
+ * @example { create_campaign: "campaign", buy_airtime: "buyAirtime" }
163
+ */
164
+ toolOutputMap?: ToolOutputMap;
165
+ /**
166
+ * Tool names that complete a sticky flow when they produce output.
167
+ * Library owns finalize logic — you only pass the list.
168
+ */
169
+ completeOn?: string[];
170
+ /**
171
+ * Per-tool extractors (advanced). Prefer `toolOutputMap` instead.
138
172
  */
139
173
  toolExtractors?: ToolExtractorMap;
140
174
  /** Seed object for tool extractors (e.g. () => ({ tickets: [] })). */
141
175
  initialToolOutputs?: () => Record<string, unknown>;
142
176
  /** If true, unknown tool names are kept as raw args. Default false when using toolExtractors. */
143
177
  includeUnknownToolOutputs?: boolean;
144
- /** Full custom extractor. Overrides toolExtractors when provided. */
178
+ /** Full custom extractor. Overrides toolOutputMap / toolExtractors when provided. */
145
179
  extractToolOutputs?: (messages: unknown[]) => Record<string, unknown>;
146
180
  /**
147
- * Decide when a sticky flow is done.
148
- * Default: never auto-complete (app must clear via finalize or clearFlow).
181
+ * Custom finalize. Prefer `completeOn` for the common case.
149
182
  */
150
183
  finalizeFlow?: (input: FinalizeFlowInput) => FinalizeFlowResult | Promise<FinalizeFlowResult>;
151
184
  /** Derive phone/session key for tools. Default: phoneKey ?? threadId. */
@@ -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.0",
3
+ "version": "0.1.5",
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": {