llm-agent-runtime 0.1.6 → 0.1.16
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 +8 -2
- package/USAGE.md +522 -283
- package/dist/agent.d.ts +2 -1
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +36 -4
- package/dist/create-runtime.d.ts +14 -4
- package/dist/create-runtime.d.ts.map +1 -1
- package/dist/create-runtime.js +108 -20
- package/dist/embeddings/xenova.d.ts +19 -0
- package/dist/embeddings/xenova.d.ts.map +1 -0
- package/dist/embeddings/xenova.js +69 -0
- package/dist/env-llm.d.ts +14 -4
- package/dist/env-llm.d.ts.map +1 -1
- package/dist/env-llm.js +50 -16
- package/dist/errors.d.ts +10 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +17 -0
- package/dist/index.d.ts +11 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/intents/define.d.ts +35 -0
- package/dist/intents/define.d.ts.map +1 -0
- package/dist/intents/define.js +52 -0
- package/dist/intents/general.d.ts +37 -0
- package/dist/intents/general.d.ts.map +1 -0
- package/dist/intents/general.js +67 -0
- package/dist/llm.d.ts +2 -2
- package/dist/llm.d.ts.map +1 -1
- package/dist/llm.js +45 -15
- package/dist/rag/index.d.ts +67 -0
- package/dist/rag/index.d.ts.map +1 -0
- package/dist/rag/index.js +138 -0
- package/dist/rag/loaders.d.ts +11 -0
- package/dist/rag/loaders.d.ts.map +1 -0
- package/dist/rag/loaders.js +80 -0
- package/dist/rag/sources.d.ts +29 -0
- package/dist/rag/sources.d.ts.map +1 -0
- package/dist/rag/sources.js +101 -0
- package/dist/services/intent-embeddings.d.ts.map +1 -1
- package/dist/services/intent-embeddings.js +5 -6
- package/dist/services/token-usage.d.ts +26 -0
- package/dist/services/token-usage.d.ts.map +1 -0
- package/dist/services/token-usage.js +63 -0
- package/dist/services/usage-store.d.ts +24 -0
- package/dist/services/usage-store.d.ts.map +1 -0
- package/dist/services/usage-store.js +92 -0
- package/dist/types.d.ts +47 -15
- package/dist/types.d.ts.map +1 -1
- package/package.json +10 -3
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { IntentBinding, IntentDefinition, IntentRegistry } from "../types.js";
|
|
2
|
+
import { type WithGeneralIntentOptions } from "./general.js";
|
|
3
|
+
/**
|
|
4
|
+
* One object for both routing (`name` / `examples` / …) and execution (`prompt` / `tools`).
|
|
5
|
+
* Use with {@link defineIntents} or {@link withGeneralIntents}.
|
|
6
|
+
*/
|
|
7
|
+
export type UnifiedIntent<TContext = unknown> = IntentDefinition & IntentBinding<TContext>;
|
|
8
|
+
/**
|
|
9
|
+
* Split unified intent objects into the two lists `createAgentRuntime` expects.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* const { intents, intentRegistry } = defineIntents([
|
|
14
|
+
* {
|
|
15
|
+
* name: "qa",
|
|
16
|
+
* examples: ["what is", "how do I"],
|
|
17
|
+
* description: "answer from docs",
|
|
18
|
+
* prompt: () => "Answer from knowledge.",
|
|
19
|
+
* tools: () => [],
|
|
20
|
+
* },
|
|
21
|
+
* ]);
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export declare function defineIntents<TContext = unknown>(items: UnifiedIntent<TContext>[]): {
|
|
25
|
+
intents: IntentDefinition[];
|
|
26
|
+
intentRegistry: IntentRegistry<TContext>;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Same as {@link defineIntents}, then prepends the optional general catch-all intent.
|
|
30
|
+
*/
|
|
31
|
+
export declare function withGeneralIntents<TContext = unknown>(items: UnifiedIntent<TContext>[], options?: WithGeneralIntentOptions<TContext>): {
|
|
32
|
+
intents: IntentDefinition[];
|
|
33
|
+
intentRegistry: IntentRegistry<TContext>;
|
|
34
|
+
};
|
|
35
|
+
//# sourceMappingURL=define.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define.d.ts","sourceRoot":"","sources":["../../src/intents/define.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,gBAAgB,EAChB,cAAc,EACf,MAAM,aAAa,CAAC;AACrB,OAAO,EAAqB,KAAK,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAEhF;;;GAGG;AACH,MAAM,MAAM,aAAa,CAAC,QAAQ,GAAG,OAAO,IAAI,gBAAgB,GAC9D,aAAa,CAAC,QAAQ,CAAC,CAAC;AAE1B;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,aAAa,CAAC,QAAQ,GAAG,OAAO,EAC9C,KAAK,EAAE,aAAa,CAAC,QAAQ,CAAC,EAAE,GAC/B;IACD,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,cAAc,EAAE,cAAc,CAAC,QAAQ,CAAC,CAAC;CAC1C,CAgCA;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,GAAG,OAAO,EACnD,KAAK,EAAE,aAAa,CAAC,QAAQ,CAAC,EAAE,EAChC,OAAO,CAAC,EAAE,wBAAwB,CAAC,QAAQ,CAAC,GAC3C;IACD,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,cAAc,EAAE,cAAc,CAAC,QAAQ,CAAC,CAAC;CAC1C,CAGA"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { withGeneralIntent } from "./general.js";
|
|
2
|
+
/**
|
|
3
|
+
* Split unified intent objects into the two lists `createAgentRuntime` expects.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* const { intents, intentRegistry } = defineIntents([
|
|
8
|
+
* {
|
|
9
|
+
* name: "qa",
|
|
10
|
+
* examples: ["what is", "how do I"],
|
|
11
|
+
* description: "answer from docs",
|
|
12
|
+
* prompt: () => "Answer from knowledge.",
|
|
13
|
+
* tools: () => [],
|
|
14
|
+
* },
|
|
15
|
+
* ]);
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export function defineIntents(items) {
|
|
19
|
+
const intents = [];
|
|
20
|
+
const intentRegistry = {};
|
|
21
|
+
for (const item of items) {
|
|
22
|
+
const { prompt, tools, name, examples, sticky, description, regex } = item;
|
|
23
|
+
if (!name?.trim()) {
|
|
24
|
+
throw new Error("defineIntents: each intent needs a non-empty name");
|
|
25
|
+
}
|
|
26
|
+
if (!Array.isArray(examples)) {
|
|
27
|
+
throw new Error(`defineIntents: intent "${name}" needs an examples array`);
|
|
28
|
+
}
|
|
29
|
+
if (typeof prompt !== "function" || typeof tools !== "function") {
|
|
30
|
+
throw new Error(`defineIntents: intent "${name}" needs prompt() and tools() functions`);
|
|
31
|
+
}
|
|
32
|
+
if (intentRegistry[name]) {
|
|
33
|
+
throw new Error(`defineIntents: duplicate intent name "${name}"`);
|
|
34
|
+
}
|
|
35
|
+
intents.push({
|
|
36
|
+
name,
|
|
37
|
+
examples,
|
|
38
|
+
...(sticky !== undefined ? { sticky } : {}),
|
|
39
|
+
...(description !== undefined ? { description } : {}),
|
|
40
|
+
...(regex !== undefined ? { regex } : {}),
|
|
41
|
+
});
|
|
42
|
+
intentRegistry[name] = { prompt, tools };
|
|
43
|
+
}
|
|
44
|
+
return { intents, intentRegistry };
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Same as {@link defineIntents}, then prepends the optional general catch-all intent.
|
|
48
|
+
*/
|
|
49
|
+
export function withGeneralIntents(items, options) {
|
|
50
|
+
const split = defineIntents(items);
|
|
51
|
+
return withGeneralIntent(split.intents, split.intentRegistry, options);
|
|
52
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { IntentBinding, IntentDefinition, IntentRegistry, PromptContext } from "../types.js";
|
|
2
|
+
/** Default catch-all intent name (Xel uses `greetings` the same way). */
|
|
3
|
+
export declare const GENERAL_INTENT_NAME = "general";
|
|
4
|
+
/**
|
|
5
|
+
* Optional catch-all intent (first in catalog, used as fallback).
|
|
6
|
+
* Not required — apps that already define `greetings` / `general` can skip this.
|
|
7
|
+
*/
|
|
8
|
+
export declare function createGeneralIntent(overrides?: Partial<IntentDefinition>): IntentDefinition;
|
|
9
|
+
/**
|
|
10
|
+
* Default prompt + empty tools for the general intent.
|
|
11
|
+
* Pass your own `prompt` / `tools` when you want a richer menu.
|
|
12
|
+
*/
|
|
13
|
+
export declare function createGeneralIntentBinding<TContext = unknown>(options?: {
|
|
14
|
+
prompt?: (ctx: PromptContext<TContext>) => string;
|
|
15
|
+
tools?: IntentBinding<TContext>["tools"];
|
|
16
|
+
}): IntentBinding<TContext>;
|
|
17
|
+
export type WithGeneralIntentOptions<TContext = unknown> = {
|
|
18
|
+
/** Override the general intent definition (e.g. `name: "greetings"` to match Xel). */
|
|
19
|
+
intent?: Partial<IntentDefinition>;
|
|
20
|
+
/** Prompt / tools for the general registry entry. */
|
|
21
|
+
binding?: {
|
|
22
|
+
prompt?: (ctx: PromptContext<TContext>) => string;
|
|
23
|
+
tools?: IntentBinding<TContext>["tools"];
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Prepend a general intent if missing, and merge its registry binding.
|
|
28
|
+
* Does nothing when an intent with the same name already exists.
|
|
29
|
+
*
|
|
30
|
+
* This is a **catch-all routing intent**, not shared style rules.
|
|
31
|
+
* For rules that apply to every intent, use `sharedPrompt` on `createAgentRuntime`.
|
|
32
|
+
*/
|
|
33
|
+
export declare function withGeneralIntent<TContext = unknown>(intents: IntentDefinition[], registry: IntentRegistry<TContext>, options?: WithGeneralIntentOptions<TContext>): {
|
|
34
|
+
intents: IntentDefinition[];
|
|
35
|
+
intentRegistry: IntentRegistry<TContext>;
|
|
36
|
+
};
|
|
37
|
+
//# sourceMappingURL=general.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"general.d.ts","sourceRoot":"","sources":["../../src/intents/general.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,aAAa,EACd,MAAM,aAAa,CAAC;AAErB,yEAAyE;AACzE,eAAO,MAAM,mBAAmB,YAAY,CAAC;AAkB7C;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,GACpC,gBAAgB,CAUlB;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,QAAQ,GAAG,OAAO,EAAE,OAAO,CAAC,EAAE;IACvE,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,aAAa,CAAC,QAAQ,CAAC,KAAK,MAAM,CAAC;IAClD,KAAK,CAAC,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC;CAC1C,GAAG,aAAa,CAAC,QAAQ,CAAC,CAgB1B;AAED,MAAM,MAAM,wBAAwB,CAAC,QAAQ,GAAG,OAAO,IAAI;IACzD,sFAAsF;IACtF,MAAM,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACnC,qDAAqD;IACrD,OAAO,CAAC,EAAE;QACR,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,aAAa,CAAC,QAAQ,CAAC,KAAK,MAAM,CAAC;QAClD,KAAK,CAAC,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC;KAC1C,CAAC;CACH,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,GAAG,OAAO,EAClD,OAAO,EAAE,gBAAgB,EAAE,EAC3B,QAAQ,EAAE,cAAc,CAAC,QAAQ,CAAC,EAClC,OAAO,CAAC,EAAE,wBAAwB,CAAC,QAAQ,CAAC,GAC3C;IAAE,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAAC,cAAc,EAAE,cAAc,CAAC,QAAQ,CAAC,CAAA;CAAE,CAa3E"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/** Default catch-all intent name (Xel uses `greetings` the same way). */
|
|
2
|
+
export const GENERAL_INTENT_NAME = "general";
|
|
3
|
+
const DEFAULT_GENERAL_EXAMPLES = [
|
|
4
|
+
"hello",
|
|
5
|
+
"hi",
|
|
6
|
+
"hey",
|
|
7
|
+
"how are you",
|
|
8
|
+
"good morning",
|
|
9
|
+
"good afternoon",
|
|
10
|
+
"good evening",
|
|
11
|
+
"thanks",
|
|
12
|
+
"thank you",
|
|
13
|
+
"what can you do",
|
|
14
|
+
"help",
|
|
15
|
+
"menu",
|
|
16
|
+
"show me the menu",
|
|
17
|
+
];
|
|
18
|
+
/**
|
|
19
|
+
* Optional catch-all intent (first in catalog, used as fallback).
|
|
20
|
+
* Not required — apps that already define `greetings` / `general` can skip this.
|
|
21
|
+
*/
|
|
22
|
+
export function createGeneralIntent(overrides) {
|
|
23
|
+
return {
|
|
24
|
+
name: overrides?.name ?? GENERAL_INTENT_NAME,
|
|
25
|
+
examples: overrides?.examples ?? DEFAULT_GENERAL_EXAMPLES,
|
|
26
|
+
description: overrides?.description ??
|
|
27
|
+
"general chat, greetings, small talk, help, menu, or unclear requests",
|
|
28
|
+
sticky: overrides?.sticky,
|
|
29
|
+
regex: overrides?.regex,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Default prompt + empty tools for the general intent.
|
|
34
|
+
* Pass your own `prompt` / `tools` when you want a richer menu.
|
|
35
|
+
*/
|
|
36
|
+
export function createGeneralIntentBinding(options) {
|
|
37
|
+
return {
|
|
38
|
+
prompt: options?.prompt ??
|
|
39
|
+
((ctx) => {
|
|
40
|
+
const data = ctx.context;
|
|
41
|
+
const name = typeof data?.contactName === "string" ? data.contactName : "there";
|
|
42
|
+
return (`You are a friendly general assistant. Greet ${name} warmly when appropriate. ` +
|
|
43
|
+
`Answer simple questions, explain what you can help with, and guide the user to the right flow. ` +
|
|
44
|
+
`Keep replies concise.`);
|
|
45
|
+
}),
|
|
46
|
+
tools: options?.tools ?? (() => []),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Prepend a general intent if missing, and merge its registry binding.
|
|
51
|
+
* Does nothing when an intent with the same name already exists.
|
|
52
|
+
*
|
|
53
|
+
* This is a **catch-all routing intent**, not shared style rules.
|
|
54
|
+
* For rules that apply to every intent, use `sharedPrompt` on `createAgentRuntime`.
|
|
55
|
+
*/
|
|
56
|
+
export function withGeneralIntent(intents, registry, options) {
|
|
57
|
+
const general = createGeneralIntent(options?.intent);
|
|
58
|
+
const already = intents.some((i) => i.name === general.name);
|
|
59
|
+
const nextIntents = already ? intents : [general, ...intents];
|
|
60
|
+
const nextRegistry = already
|
|
61
|
+
? registry
|
|
62
|
+
: {
|
|
63
|
+
[general.name]: createGeneralIntentBinding(options?.binding),
|
|
64
|
+
...registry,
|
|
65
|
+
};
|
|
66
|
+
return { intents: nextIntents, intentRegistry: nextRegistry };
|
|
67
|
+
}
|
package/dist/llm.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import type { BaseChatModel } from "@langchain/core/language_models/chat_models";
|
|
2
2
|
import type { Embeddings } from "@langchain/core/embeddings";
|
|
3
|
-
import type { LlmConfig, LlmProvider } from "./types.js";
|
|
3
|
+
import type { EmbeddingsProvider, LlmConfig, LlmProvider } from "./types.js";
|
|
4
4
|
export type CreatedModels = {
|
|
5
5
|
chat: BaseChatModel;
|
|
6
6
|
intentRouter: BaseChatModel;
|
|
7
7
|
embeddings: Embeddings;
|
|
8
8
|
config: {
|
|
9
9
|
provider: LlmProvider;
|
|
10
|
-
embeddingsProvider:
|
|
10
|
+
embeddingsProvider: EmbeddingsProvider;
|
|
11
11
|
model: string;
|
|
12
12
|
intentRouterModel: string;
|
|
13
13
|
embeddingsModel: string;
|
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;
|
|
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;AAI7D,OAAO,KAAK,EAAE,kBAAkB,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAuC7E,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,kBAAkB,CAAC;QACvC,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,CA8F1D"}
|
package/dist/llm.js
CHANGED
|
@@ -1,21 +1,40 @@
|
|
|
1
1
|
import { ChatOpenAI, OpenAIEmbeddings } from "@langchain/openai";
|
|
2
2
|
import { ChatOllama, OllamaEmbeddings } from "@langchain/ollama";
|
|
3
|
-
|
|
3
|
+
import { XenovaEmbeddings } from "./embeddings/xenova.js";
|
|
4
|
+
const normalizeChatProvider = (value) => {
|
|
4
5
|
const normalized = value?.trim().toLowerCase();
|
|
5
6
|
if (normalized === "openai" ||
|
|
6
7
|
normalized === "gpt" ||
|
|
7
8
|
normalized === "chatgpt") {
|
|
8
9
|
return "openai";
|
|
9
10
|
}
|
|
10
|
-
if (normalized === "openrouter" ||
|
|
11
|
-
normalized === "or") {
|
|
11
|
+
if (normalized === "openrouter" || normalized === "or") {
|
|
12
12
|
return "openrouter";
|
|
13
13
|
}
|
|
14
14
|
return "ollama";
|
|
15
15
|
};
|
|
16
|
+
const normalizeEmbeddingsProvider = (value, chatProvider) => {
|
|
17
|
+
const normalized = value?.trim().toLowerCase();
|
|
18
|
+
if (normalized === "openai" || normalized === "gpt")
|
|
19
|
+
return "openai";
|
|
20
|
+
if (normalized === "ollama")
|
|
21
|
+
return "ollama";
|
|
22
|
+
if (normalized === "xenova" ||
|
|
23
|
+
normalized === "transformers" ||
|
|
24
|
+
normalized === "local") {
|
|
25
|
+
return "xenova";
|
|
26
|
+
}
|
|
27
|
+
if (normalized === "openrouter")
|
|
28
|
+
return "xenova";
|
|
29
|
+
// Unset on LlmConfig: same rule as env — non-ollama chat → xenova.
|
|
30
|
+
if (!value) {
|
|
31
|
+
return chatProvider === "ollama" ? "ollama" : "xenova";
|
|
32
|
+
}
|
|
33
|
+
return chatProvider === "ollama" ? "ollama" : "xenova";
|
|
34
|
+
};
|
|
16
35
|
export function createModels(llm) {
|
|
17
|
-
const provider =
|
|
18
|
-
const embeddingsProvider =
|
|
36
|
+
const provider = normalizeChatProvider(llm.provider);
|
|
37
|
+
const embeddingsProvider = normalizeEmbeddingsProvider(llm.embeddingsProvider, provider);
|
|
19
38
|
const temperature = llm.temperature ?? 0;
|
|
20
39
|
const createChat = (modelName) => {
|
|
21
40
|
if (provider === "openai") {
|
|
@@ -36,6 +55,8 @@ export function createModels(llm) {
|
|
|
36
55
|
model: modelName,
|
|
37
56
|
temperature,
|
|
38
57
|
apiKey: llm.apiKey,
|
|
58
|
+
timeout: 60_000,
|
|
59
|
+
maxRetries: 2,
|
|
39
60
|
configuration: {
|
|
40
61
|
baseURL: llm.baseUrl ?? "https://openrouter.ai/api/v1",
|
|
41
62
|
},
|
|
@@ -47,26 +68,35 @@ export function createModels(llm) {
|
|
|
47
68
|
baseUrl: llm.baseUrl,
|
|
48
69
|
});
|
|
49
70
|
};
|
|
71
|
+
const embeddingsModelName = llm.embeddingsModel ??
|
|
72
|
+
(embeddingsProvider === "openai"
|
|
73
|
+
? "text-embedding-3-small"
|
|
74
|
+
: embeddingsProvider === "xenova"
|
|
75
|
+
? "Xenova/all-MiniLM-L6-v2"
|
|
76
|
+
: "mxbai-embed-large:latest");
|
|
50
77
|
const createEmbeddings = () => {
|
|
51
78
|
if (embeddingsProvider === "openai") {
|
|
52
|
-
|
|
53
|
-
|
|
79
|
+
const embeddingsApiKey = llm.embeddingsApiKey ?? llm.apiKey;
|
|
80
|
+
if (!embeddingsApiKey) {
|
|
81
|
+
throw new Error("llm.embeddingsApiKey (or llm.apiKey) is required when embeddingsProvider is openai.");
|
|
54
82
|
}
|
|
55
83
|
return new OpenAIEmbeddings({
|
|
56
|
-
model:
|
|
57
|
-
apiKey:
|
|
84
|
+
model: embeddingsModelName,
|
|
85
|
+
apiKey: embeddingsApiKey,
|
|
58
86
|
});
|
|
59
87
|
}
|
|
88
|
+
if (embeddingsProvider === "xenova") {
|
|
89
|
+
return new XenovaEmbeddings({ model: embeddingsModelName });
|
|
90
|
+
}
|
|
91
|
+
const ollamaBaseUrl = llm.embeddingsBaseUrl ??
|
|
92
|
+
(provider === "ollama" ? llm.baseUrl : undefined) ??
|
|
93
|
+
"http://localhost:11434";
|
|
60
94
|
return new OllamaEmbeddings({
|
|
61
|
-
model:
|
|
62
|
-
baseUrl:
|
|
95
|
+
model: embeddingsModelName,
|
|
96
|
+
baseUrl: ollamaBaseUrl,
|
|
63
97
|
});
|
|
64
98
|
};
|
|
65
99
|
const intentRouterModelName = llm.intentRouterModel ?? llm.model;
|
|
66
|
-
const embeddingsModelName = llm.embeddingsModel ??
|
|
67
|
-
(embeddingsProvider === "openai"
|
|
68
|
-
? "text-embedding-3-small"
|
|
69
|
-
: "mxbai-embed-large:latest");
|
|
70
100
|
return {
|
|
71
101
|
chat: createChat(llm.model),
|
|
72
102
|
intentRouter: createChat(intentRouterModelName),
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { Embeddings } from "@langchain/core/embeddings";
|
|
2
|
+
import { loadRagDocuments, loadRagDocument, type LoadedRagDocument } from "./loaders.js";
|
|
3
|
+
import { ragSourcesFromEnv, resolveRagSources, resolveRagSource, isHttpUrl, type ResolvedRagSource, type RagSourceKind } from "./sources.js";
|
|
4
|
+
export type { LoadedRagDocument, ResolvedRagSource, RagSourceKind };
|
|
5
|
+
export { loadRagDocuments, loadRagDocument, ragSourcesFromEnv, resolveRagSources, resolveRagSource, isHttpUrl, };
|
|
6
|
+
export type RagChunk = {
|
|
7
|
+
id: string;
|
|
8
|
+
source: string;
|
|
9
|
+
text: string;
|
|
10
|
+
embedding: number[];
|
|
11
|
+
};
|
|
12
|
+
export type SimpleRagStore = {
|
|
13
|
+
chunks: RagChunk[];
|
|
14
|
+
retrieve: (query: string, topK?: number) => Promise<string>;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Build an in-memory RAG store from loaded documents + any Embeddings backend
|
|
18
|
+
* (xenova / ollama / openai).
|
|
19
|
+
*/
|
|
20
|
+
export declare function createSimpleRagStore(options: {
|
|
21
|
+
documents: LoadedRagDocument[];
|
|
22
|
+
embeddings: Embeddings;
|
|
23
|
+
chunkSize?: number;
|
|
24
|
+
overlap?: number;
|
|
25
|
+
}): Promise<SimpleRagStore>;
|
|
26
|
+
/**
|
|
27
|
+
* Resolve + load + index RAG sources (local paths and/or http(s) PDF/DOCX URLs).
|
|
28
|
+
*/
|
|
29
|
+
export declare function createSimpleRagFromSources(options: {
|
|
30
|
+
sources: string[];
|
|
31
|
+
embeddings: Embeddings;
|
|
32
|
+
chunkSize?: number;
|
|
33
|
+
overlap?: number;
|
|
34
|
+
}): Promise<{
|
|
35
|
+
resolved: ResolvedRagSource[];
|
|
36
|
+
documents: LoadedRagDocument[];
|
|
37
|
+
store: SimpleRagStore;
|
|
38
|
+
}>;
|
|
39
|
+
/** Same as createSimpleRagFromSources, reading RAG_SOURCES / RAG_PDF_* / RAG_DOC_URLS. */
|
|
40
|
+
export declare function createSimpleRagFromEnv(options: {
|
|
41
|
+
embeddings: Embeddings;
|
|
42
|
+
env?: NodeJS.ProcessEnv;
|
|
43
|
+
chunkSize?: number;
|
|
44
|
+
overlap?: number;
|
|
45
|
+
}): Promise<{
|
|
46
|
+
resolved: ResolvedRagSource[];
|
|
47
|
+
documents: LoadedRagDocument[];
|
|
48
|
+
store: SimpleRagStore;
|
|
49
|
+
}>;
|
|
50
|
+
export type GetRagStoreOptions = {
|
|
51
|
+
/** Defaults to embeddings from `llmConfigFromEnv()` / `createModels()`. */
|
|
52
|
+
embeddings?: Embeddings;
|
|
53
|
+
env?: NodeJS.ProcessEnv;
|
|
54
|
+
chunkSize?: number;
|
|
55
|
+
overlap?: number;
|
|
56
|
+
/** Log `[rag] indexed N document(s)` (default true). */
|
|
57
|
+
log?: boolean;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Lazy singleton RAG store from `RAG_SOURCES` (path and/or URL).
|
|
61
|
+
* Apps do not need their own `rag/store.ts` — call this, then `store.retrieve(message)`.
|
|
62
|
+
*/
|
|
63
|
+
export declare function getRagStore(options?: GetRagStoreOptions): Promise<SimpleRagStore>;
|
|
64
|
+
export declare function getRagDocumentCount(): number;
|
|
65
|
+
/** Clear the singleton (tests / re-index). Next `getRagStore()` rebuilds. */
|
|
66
|
+
export declare function resetRagStore(): void;
|
|
67
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/rag/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAG7D,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,KAAK,iBAAiB,EACvB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EAChB,SAAS,EACT,KAAK,iBAAiB,EACtB,KAAK,aAAa,EACnB,MAAM,cAAc,CAAC;AAEtB,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,aAAa,EAAE,CAAC;AACpE,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EAChB,SAAS,GACV,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,QAAQ,EAAE,CAAC;IACnB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CAC7D,CAAC;AAgCF;;;GAGG;AACH,wBAAsB,oBAAoB,CAAC,OAAO,EAAE;IAClD,SAAS,EAAE,iBAAiB,EAAE,CAAC;IAC/B,UAAU,EAAE,UAAU,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GAAG,OAAO,CAAC,cAAc,CAAC,CAkC1B;AAED;;GAEG;AACH,wBAAsB,0BAA0B,CAAC,OAAO,EAAE;IACxD,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,EAAE,UAAU,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GAAG,OAAO,CAAC;IACV,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,SAAS,EAAE,iBAAiB,EAAE,CAAC;IAC/B,KAAK,EAAE,cAAc,CAAC;CACvB,CAAC,CAUD;AAED,0FAA0F;AAC1F,wBAAsB,sBAAsB,CAAC,OAAO,EAAE;IACpD,UAAU,EAAE,UAAU,CAAC;IACvB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;cArBW,iBAAiB,EAAE;eAClB,iBAAiB,EAAE;WACvB,cAAc;GAgCtB;AAKD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,2EAA2E;IAC3E,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wDAAwD;IACxD,GAAG,CAAC,EAAE,OAAO,CAAC;CACf,CAAC;AAEF;;;GAGG;AACH,wBAAgB,WAAW,CAAC,OAAO,GAAE,kBAAuB,2BA+B3D;AAED,wBAAgB,mBAAmB,WAElC;AAED,6EAA6E;AAC7E,wBAAgB,aAAa,SAG5B"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { llmConfigFromEnv } from "../env-llm.js";
|
|
2
|
+
import { createModels } from "../llm.js";
|
|
3
|
+
import { loadRagDocuments, loadRagDocument, } from "./loaders.js";
|
|
4
|
+
import { ragSourcesFromEnv, resolveRagSources, resolveRagSource, isHttpUrl, } from "./sources.js";
|
|
5
|
+
export { loadRagDocuments, loadRagDocument, ragSourcesFromEnv, resolveRagSources, resolveRagSource, isHttpUrl, };
|
|
6
|
+
function chunkText(text, chunkSize = 800, overlap = 120) {
|
|
7
|
+
const cleaned = text.replace(/\s+/g, " ").trim();
|
|
8
|
+
if (!cleaned)
|
|
9
|
+
return [];
|
|
10
|
+
if (cleaned.length <= chunkSize)
|
|
11
|
+
return [cleaned];
|
|
12
|
+
const chunks = [];
|
|
13
|
+
let start = 0;
|
|
14
|
+
while (start < cleaned.length) {
|
|
15
|
+
const end = Math.min(start + chunkSize, cleaned.length);
|
|
16
|
+
chunks.push(cleaned.slice(start, end));
|
|
17
|
+
if (end >= cleaned.length)
|
|
18
|
+
break;
|
|
19
|
+
start = Math.max(0, end - overlap);
|
|
20
|
+
}
|
|
21
|
+
return chunks;
|
|
22
|
+
}
|
|
23
|
+
function cosine(a, b) {
|
|
24
|
+
let dot = 0;
|
|
25
|
+
let magA = 0;
|
|
26
|
+
let magB = 0;
|
|
27
|
+
const n = Math.min(a.length, b.length);
|
|
28
|
+
for (let i = 0; i < n; i++) {
|
|
29
|
+
dot += a[i] * b[i];
|
|
30
|
+
magA += a[i] * a[i];
|
|
31
|
+
magB += b[i] * b[i];
|
|
32
|
+
}
|
|
33
|
+
if (!magA || !magB)
|
|
34
|
+
return 0;
|
|
35
|
+
return dot / (Math.sqrt(magA) * Math.sqrt(magB));
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Build an in-memory RAG store from loaded documents + any Embeddings backend
|
|
39
|
+
* (xenova / ollama / openai).
|
|
40
|
+
*/
|
|
41
|
+
export async function createSimpleRagStore(options) {
|
|
42
|
+
const chunks = [];
|
|
43
|
+
let i = 0;
|
|
44
|
+
for (const doc of options.documents) {
|
|
45
|
+
const parts = chunkText(doc.text, options.chunkSize ?? 800, options.overlap ?? 120);
|
|
46
|
+
for (const part of parts) {
|
|
47
|
+
const embedding = await options.embeddings.embedQuery(part);
|
|
48
|
+
chunks.push({
|
|
49
|
+
id: `${i++}`,
|
|
50
|
+
source: doc.source,
|
|
51
|
+
text: part,
|
|
52
|
+
embedding,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
chunks,
|
|
58
|
+
retrieve: async (query, topK = 4) => {
|
|
59
|
+
if (!chunks.length)
|
|
60
|
+
return "";
|
|
61
|
+
const q = await options.embeddings.embedQuery(query);
|
|
62
|
+
return chunks
|
|
63
|
+
.map((c) => ({ c, score: cosine(q, c.embedding) }))
|
|
64
|
+
.sort((a, b) => b.score - a.score)
|
|
65
|
+
.slice(0, topK)
|
|
66
|
+
.map(({ c }) => `[${c.source}]\n${c.text}`)
|
|
67
|
+
.join("\n---\n");
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Resolve + load + index RAG sources (local paths and/or http(s) PDF/DOCX URLs).
|
|
73
|
+
*/
|
|
74
|
+
export async function createSimpleRagFromSources(options) {
|
|
75
|
+
const resolved = await resolveRagSources(options.sources);
|
|
76
|
+
const documents = await loadRagDocuments(resolved);
|
|
77
|
+
const store = await createSimpleRagStore({
|
|
78
|
+
documents,
|
|
79
|
+
embeddings: options.embeddings,
|
|
80
|
+
chunkSize: options.chunkSize,
|
|
81
|
+
overlap: options.overlap,
|
|
82
|
+
});
|
|
83
|
+
return { resolved, documents, store };
|
|
84
|
+
}
|
|
85
|
+
/** Same as createSimpleRagFromSources, reading RAG_SOURCES / RAG_PDF_* / RAG_DOC_URLS. */
|
|
86
|
+
export async function createSimpleRagFromEnv(options) {
|
|
87
|
+
const sources = ragSourcesFromEnv(options.env ?? process.env);
|
|
88
|
+
if (!sources.length) {
|
|
89
|
+
throw new Error("No RAG sources configured. Set RAG_SOURCES=/path/a.pdf,https://example.com/b.docx");
|
|
90
|
+
}
|
|
91
|
+
return createSimpleRagFromSources({
|
|
92
|
+
sources,
|
|
93
|
+
embeddings: options.embeddings,
|
|
94
|
+
chunkSize: options.chunkSize,
|
|
95
|
+
overlap: options.overlap,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
let storePromise = null;
|
|
99
|
+
let documentCount = 0;
|
|
100
|
+
/**
|
|
101
|
+
* Lazy singleton RAG store from `RAG_SOURCES` (path and/or URL).
|
|
102
|
+
* Apps do not need their own `rag/store.ts` — call this, then `store.retrieve(message)`.
|
|
103
|
+
*/
|
|
104
|
+
export function getRagStore(options = {}) {
|
|
105
|
+
if (!storePromise) {
|
|
106
|
+
storePromise = (async () => {
|
|
107
|
+
const embeddings = options.embeddings ?? createModels(llmConfigFromEnv()).embeddings;
|
|
108
|
+
const { store, documents } = await createSimpleRagFromEnv({
|
|
109
|
+
embeddings,
|
|
110
|
+
env: options.env,
|
|
111
|
+
chunkSize: options.chunkSize,
|
|
112
|
+
overlap: options.overlap,
|
|
113
|
+
});
|
|
114
|
+
if (!documents.length) {
|
|
115
|
+
throw new Error("RAG sources were configured but none could be loaded. Check file paths and PDF/DOCX parsers.");
|
|
116
|
+
}
|
|
117
|
+
documentCount = documents.length;
|
|
118
|
+
if (options.log !== false) {
|
|
119
|
+
console.log(`[rag] indexed ${documents.length} document(s) from RAG_SOURCES`);
|
|
120
|
+
}
|
|
121
|
+
return store;
|
|
122
|
+
})().catch((err) => {
|
|
123
|
+
// Allow the next getRagStore() call to retry after a failed index.
|
|
124
|
+
storePromise = null;
|
|
125
|
+
documentCount = 0;
|
|
126
|
+
throw err;
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
return storePromise;
|
|
130
|
+
}
|
|
131
|
+
export function getRagDocumentCount() {
|
|
132
|
+
return documentCount;
|
|
133
|
+
}
|
|
134
|
+
/** Clear the singleton (tests / re-index). Next `getRagStore()` rebuilds. */
|
|
135
|
+
export function resetRagStore() {
|
|
136
|
+
storePromise = null;
|
|
137
|
+
documentCount = 0;
|
|
138
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ResolvedRagSource } from "./sources.js";
|
|
2
|
+
export type LoadedRagDocument = {
|
|
3
|
+
source: string;
|
|
4
|
+
text: string;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Extract plain text from a resolved PDF / DOCX / TXT source.
|
|
8
|
+
*/
|
|
9
|
+
export declare function loadRagDocument(resolved: ResolvedRagSource): Promise<LoadedRagDocument>;
|
|
10
|
+
export declare function loadRagDocuments(resolved: ResolvedRagSource[]): Promise<LoadedRagDocument[]>;
|
|
11
|
+
//# sourceMappingURL=loaders.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loaders.d.ts","sourceRoot":"","sources":["../../src/rag/loaders.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEtD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAiDF;;GAEG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,iBAAiB,GAC1B,OAAO,CAAC,iBAAiB,CAAC,CAsB5B;AAED,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,iBAAiB,EAAE,GAC5B,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAiB9B"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
const require = createRequire(import.meta.url);
|
|
4
|
+
function loadPdfParse() {
|
|
5
|
+
try {
|
|
6
|
+
// Prefer CJS require — ESM `import("pdf-parse")` is flaky with pdf.js (bad XRef).
|
|
7
|
+
const mod = require("pdf-parse");
|
|
8
|
+
if (typeof mod === "function")
|
|
9
|
+
return mod;
|
|
10
|
+
if (typeof mod?.default === "function")
|
|
11
|
+
return mod.default;
|
|
12
|
+
throw new Error("pdf-parse export missing");
|
|
13
|
+
}
|
|
14
|
+
catch (err) {
|
|
15
|
+
if (err instanceof Error && err.message === "pdf-parse export missing") {
|
|
16
|
+
throw err;
|
|
17
|
+
}
|
|
18
|
+
throw new Error("PDF RAG requires pdf-parse. Install with: pnpm add pdf-parse");
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
async function loadPdf(localPath) {
|
|
22
|
+
const pdfParse = loadPdfParse();
|
|
23
|
+
const data = await fs.readFile(localPath);
|
|
24
|
+
const parsed = await pdfParse(data);
|
|
25
|
+
return parsed.text ?? "";
|
|
26
|
+
}
|
|
27
|
+
async function loadDocx(localPath) {
|
|
28
|
+
let mammoth;
|
|
29
|
+
try {
|
|
30
|
+
mammoth = await import("mammoth");
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
throw new Error('DOCX RAG requires mammoth. Install with: pnpm add mammoth');
|
|
34
|
+
}
|
|
35
|
+
const result = await mammoth.extractRawText({ path: localPath });
|
|
36
|
+
return result.value ?? "";
|
|
37
|
+
}
|
|
38
|
+
async function loadText(localPath) {
|
|
39
|
+
return fs.readFile(localPath, "utf8");
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Extract plain text from a resolved PDF / DOCX / TXT source.
|
|
43
|
+
*/
|
|
44
|
+
export async function loadRagDocument(resolved) {
|
|
45
|
+
let text;
|
|
46
|
+
switch (resolved.kind) {
|
|
47
|
+
case "pdf":
|
|
48
|
+
text = await loadPdf(resolved.localPath);
|
|
49
|
+
break;
|
|
50
|
+
case "docx":
|
|
51
|
+
text = await loadDocx(resolved.localPath);
|
|
52
|
+
break;
|
|
53
|
+
case "txt":
|
|
54
|
+
text = await loadText(resolved.localPath);
|
|
55
|
+
break;
|
|
56
|
+
default:
|
|
57
|
+
throw new Error(`Unsupported RAG file type for ${resolved.source} (use .pdf, .docx, .txt, .md)`);
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
source: resolved.source,
|
|
61
|
+
text: text.replace(/\u0000/g, "").trim(),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
export async function loadRagDocuments(resolved) {
|
|
65
|
+
const docs = [];
|
|
66
|
+
for (const item of resolved) {
|
|
67
|
+
try {
|
|
68
|
+
const doc = await loadRagDocument(item);
|
|
69
|
+
if (doc.text)
|
|
70
|
+
docs.push(doc);
|
|
71
|
+
else {
|
|
72
|
+
console.warn(`[rag] skipped empty document: ${item.source}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
console.warn(`[rag] skipped unreadable source: ${item.source}`, err instanceof Error ? err.message : err);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return docs;
|
|
80
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export type RagSourceKind = "pdf" | "docx" | "txt" | "unknown";
|
|
2
|
+
export type ResolvedRagSource = {
|
|
3
|
+
/** Original path or URL from config. */
|
|
4
|
+
source: string;
|
|
5
|
+
/** Local file path after download (URL) or as given (path). */
|
|
6
|
+
localPath: string;
|
|
7
|
+
kind: RagSourceKind;
|
|
8
|
+
/** True when we downloaded a remote file into a temp location. */
|
|
9
|
+
isTemp: boolean;
|
|
10
|
+
};
|
|
11
|
+
export declare function isHttpUrl(value: string): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Collect RAG sources from env.
|
|
14
|
+
*
|
|
15
|
+
* Preferred:
|
|
16
|
+
* RAG_SOURCES=/path/a.pdf,https://cdn.example.com/b.docx
|
|
17
|
+
*
|
|
18
|
+
* Also accepted:
|
|
19
|
+
* RAG_PDF_PATH=/one.pdf
|
|
20
|
+
* RAG_PDF_PATHS=/a.pdf,/b.pdf
|
|
21
|
+
* RAG_DOC_URLS=https://.../a.pdf,https://.../b.docx
|
|
22
|
+
*/
|
|
23
|
+
export declare function ragSourcesFromEnv(env?: NodeJS.ProcessEnv): string[];
|
|
24
|
+
/**
|
|
25
|
+
* Resolve a single source (local path or http(s) URL) to a local file.
|
|
26
|
+
*/
|
|
27
|
+
export declare function resolveRagSource(source: string): Promise<ResolvedRagSource>;
|
|
28
|
+
export declare function resolveRagSources(sources: string[]): Promise<ResolvedRagSource[]>;
|
|
29
|
+
//# sourceMappingURL=sources.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sources.d.ts","sourceRoot":"","sources":["../../src/rag/sources.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS,CAAC;AAE/D,MAAM,MAAM,iBAAiB,GAAG;IAC9B,wCAAwC;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,+DAA+D;IAC/D,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,aAAa,CAAC;IACpB,kEAAkE;IAClE,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC;AAUF,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEhD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,EAAE,CAiBV;AAwBD;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,iBAAiB,CAAC,CA6B5B;AAED,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,MAAM,EAAE,GAChB,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAM9B"}
|