@mcp-abap-adt/llm-agent-server 26.0.0 → 27.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +59 -1
  2. package/dist/composition/build-skill-host.d.ts +13 -0
  3. package/dist/composition/build-skill-host.d.ts.map +1 -0
  4. package/dist/composition/build-skill-host.js +20 -0
  5. package/dist/composition/build-skill-host.js.map +1 -0
  6. package/dist/composition/credential-for.d.ts +48 -0
  7. package/dist/composition/credential-for.d.ts.map +1 -0
  8. package/dist/composition/credential-for.js +95 -0
  9. package/dist/composition/credential-for.js.map +1 -0
  10. package/dist/composition/index.d.ts +14 -0
  11. package/dist/composition/index.d.ts.map +1 -0
  12. package/dist/composition/index.js +24 -0
  13. package/dist/composition/index.js.map +1 -0
  14. package/dist/composition/lookup.d.ts +28 -0
  15. package/dist/composition/lookup.d.ts.map +1 -0
  16. package/dist/composition/lookup.js +57 -0
  17. package/dist/composition/lookup.js.map +1 -0
  18. package/dist/composition/make-llm.d.ts +37 -0
  19. package/dist/composition/make-llm.d.ts.map +1 -0
  20. package/dist/composition/make-llm.js +79 -0
  21. package/dist/composition/make-llm.js.map +1 -0
  22. package/dist/composition/make-rag.d.ts +14 -0
  23. package/dist/composition/make-rag.d.ts.map +1 -0
  24. package/dist/composition/make-rag.js +52 -0
  25. package/dist/composition/make-rag.js.map +1 -0
  26. package/dist/composition/model-resolver.d.ts +12 -0
  27. package/dist/composition/model-resolver.d.ts.map +1 -0
  28. package/dist/composition/model-resolver.js +38 -0
  29. package/dist/composition/model-resolver.js.map +1 -0
  30. package/dist/composition/resolve-embedder.d.ts +15 -0
  31. package/dist/composition/resolve-embedder.d.ts.map +1 -0
  32. package/dist/composition/resolve-embedder.js +76 -0
  33. package/dist/composition/resolve-embedder.js.map +1 -0
  34. package/dist/smart-agent/check-models-cli.js +4 -4
  35. package/dist/smart-agent/check-models-cli.js.map +1 -1
  36. package/dist/smart-agent/cli.d.ts +13 -7
  37. package/dist/smart-agent/cli.d.ts.map +1 -1
  38. package/dist/smart-agent/cli.js +75 -42
  39. package/dist/smart-agent/cli.js.map +1 -1
  40. package/dist/smoke-adapters.js +2 -1
  41. package/dist/smoke-adapters.js.map +1 -1
  42. package/package.json +29 -27
  43. package/tools/claude-via-agent.ps1 +4 -3
  44. package/tools/claude-via-agent.sh +5 -5
package/README.md CHANGED
@@ -9,7 +9,7 @@ Runnable distribution of SmartAgent (CLI + HTTP server). **Binary-only.**
9
9
 
10
10
  Importing from `@mcp-abap-adt/llm-agent-server` as a library is not supported as of 12.0.1. Composition surface lives elsewhere:
11
11
 
12
- - `@mcp-abap-adt/llm-agent-libs` — `SmartAgentBuilder`, `SessionManager`, `makeLlm`, `InMemoryMetrics`, etc.
12
+ - `@mcp-abap-adt/llm-agent-libs` — `SmartAgentBuilder`, `SessionManager`, `LlmAdapter`, `InMemoryMetrics`, etc.
13
13
  - `@mcp-abap-adt/llm-agent-mcp` — `MCPClientWrapper`, `McpClientAdapter`, connection strategies.
14
14
  - `@mcp-abap-adt/llm-agent-rag` — `makeRag`, `resolveEmbedder`, prefetch helpers.
15
15
  - `@mcp-abap-adt/llm-agent` — interfaces and DTOs (`IMetrics`, `IRag`, `Message`, etc.).
@@ -25,6 +25,64 @@ Importing from `@mcp-abap-adt/llm-agent-server` as a library is not supported as
25
25
  See the repo docs for architecture, pipeline configuration and deployment:
26
26
  [`docs/ARCHITECTURE.md`](https://github.com/fr0ster/llm-agent/blob/main/docs/ARCHITECTURE.md), [`docs/PIPELINES.md`](https://github.com/fr0ster/llm-agent/blob/main/docs/PIPELINES.md), [`docs/DEPLOYMENT.md`](https://github.com/fr0ster/llm-agent/blob/main/docs/DEPLOYMENT.md).
27
27
 
28
+ ## Credentials
29
+
30
+ **TL;DR** — a config file carries no secrets, only names. Each section that authenticates may say
31
+ `credentialRef: <REF>`; the binary reads that account from the environment by one naming rule. Omit the
32
+ ref and the section uses its role's default.
33
+
34
+ ### The naming rule
35
+
36
+ | Set in the environment | You get |
37
+ |---|---|
38
+ | `<REF>_API_KEY` | an API key — OpenAI, Anthropic, DeepSeek, an OpenAI embedder, Qdrant |
39
+ | `<REF>_SERVICE_KEY` | a SAP AI Core service key (the JSON) — the token **and** the API base URL both come from it |
40
+ | `<REF>_USER` + `<REF>_PASSWORD` | a login — pg-vector, HANA |
41
+
42
+ - Set **one** of the three per ref. Two at once is refused as ambiguous; `<REF>_USER` without
43
+ `<REF>_PASSWORD` (or the reverse) is refused.
44
+ - A **named** ref must resolve. `credentialRef: OPENAI` with no `OPENAI_*` variable set fails at
45
+ startup, naming `OPENAI`. A ref holding the wrong kind fails, naming the kind wanted and the kind found.
46
+ - The same ref named in several sections is **one** credential — one rate-limit bucket.
47
+
48
+ ### Defaults, when a section names no ref
49
+
50
+ | Section | Default ref | A single-account deployment sets |
51
+ |---|---|---|
52
+ | each `llm:` entry | `LLM` | `LLM_API_KEY`, or `LLM_SERVICE_KEY` for SAP AI Core |
53
+ | `rag.store`, a qdrant `skillPlugins.store` | `RAG_STORE` | `RAG_STORE_API_KEY` (Qdrant) or `RAG_STORE_USER` + `RAG_STORE_PASSWORD` |
54
+ | `rag.embedder` | `RAG_EMBEDDER` | `RAG_EMBEDDER_API_KEY`, or `RAG_EMBEDDER_SERVICE_KEY` for SAP AI Core |
55
+
56
+ **The skill store shares `RAG_STORE` with `rag.store`.** A qdrant `skillPlugins.store` with no
57
+ `credentialRef` reads the `RAG_STORE` default too, so the two share its one credential kind:
58
+
59
+ - A pg-vector or HANA `rag.store` on `RAG_STORE_USER` + `RAG_STORE_PASSWORD`, beside a qdrant skill
60
+ store you meant to run **anonymously**, fails at startup: the skill store finds a login where it
61
+ wants an API key (wrong kind). "Anonymous" applies only when the default is unset.
62
+ - Fix it by naming the ref explicitly on the pg/HANA store — `rag.store.credentialRef: PG` with
63
+ `PG_USER` + `PG_PASSWORD` — and leaving `RAG_STORE_*` unset, so the skill store stays anonymous.
64
+ - If the skill store has a key of its own, name that instead: `skillPlugins.store.credentialRef: SKILLS`
65
+ with `SKILLS_API_KEY`. A named ref must resolve, so this does not work for an anonymous store.
66
+
67
+ A default is read only when the target needs a credential. Where a target can work without one (a Qdrant
68
+ without auth, a pg-vector connection that needs no login), an unset default means anonymous.
69
+
70
+ ### Ollama and other targets that send nothing
71
+
72
+ - An **Ollama LLM** gets a credential only from a `credentialRef` that names one — never the `LLM`
73
+ default, which usually holds a hosted provider's key.
74
+ - An **Ollama embedder**, an **in-memory store** and an embedder **`factory`** send nothing from the
75
+ binary, so naming a ref for them is refused.
76
+
77
+ ### Coming from `AICORE_SERVICE_KEY` or `apiKey: ${…}`
78
+
79
+ - The binary no longer reads `AICORE_SERVICE_KEY`. Set `LLM_SERVICE_KEY` instead (and
80
+ `RAG_EMBEDDER_SERVICE_KEY` for a SAP AI Core embedder) — or keep the variable and name it:
81
+ `credentialRef: AICORE` reads `AICORE_SERVICE_KEY`.
82
+ - `apiKey: ${DEEPSEEK_API_KEY}` is refused in YAML. Delete the line and set `LLM_API_KEY`, or write
83
+ `credentialRef: DEEPSEEK`, which reads `DEEPSEEK_API_KEY`.
84
+ - SAP AI Core's API base URL is never written in YAML: it travels inside `<REF>_SERVICE_KEY`.
85
+
28
86
  ## License
29
87
 
30
88
  **GNU General Public License v3.0 only** (`GPL-3.0-only`) — see
@@ -0,0 +1,13 @@
1
+ import { type BuildAgentDeps, buildSkillHostFromConfig } from '@mcp-abap-adt/llm-agent-server-libs';
2
+ import type { Lookup } from './lookup.js';
3
+ /**
4
+ * `BuildAgentDeps.buildSkillHost`: the skill store's account. §8 item 4 has a
5
+ * qdrant skill store's `credentialRef` resolved through the same `credentialFor`
6
+ * as every other ref — a named ref must resolve to an api key; an omitted one
7
+ * reads the store default and, finding no entry, stays anonymous — and the
8
+ * credential reaches the library's factory as `storeCredential` (B11), merged
9
+ * into the deps `SmartServer` passes. An in-memory skill store sends nothing and
10
+ * reads no entry.
11
+ */
12
+ export declare function createBuildSkillHost(lookup: Lookup, impl?: typeof buildSkillHostFromConfig): NonNullable<BuildAgentDeps['buildSkillHost']>;
13
+ //# sourceMappingURL=build-skill-host.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-skill-host.d.ts","sourceRoot":"","sources":["../../src/composition/build-skill-host.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,cAAc,EAEnB,wBAAwB,EAEzB,MAAM,qCAAqC,CAAC;AAE7C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,EACd,IAAI,GAAE,OAAO,wBAAmD,GAC/D,WAAW,CAAC,cAAc,CAAC,gBAAgB,CAAC,CAAC,CAgB/C"}
@@ -0,0 +1,20 @@
1
+ import { buildSkillHostFromConfig, } from '@mcp-abap-adt/llm-agent-server-libs';
2
+ import { DEFAULT_STORE_REF } from './credential-for.js';
3
+ /**
4
+ * `BuildAgentDeps.buildSkillHost`: the skill store's account. §8 item 4 has a
5
+ * qdrant skill store's `credentialRef` resolved through the same `credentialFor`
6
+ * as every other ref — a named ref must resolve to an api key; an omitted one
7
+ * reads the store default and, finding no entry, stays anonymous — and the
8
+ * credential reaches the library's factory as `storeCredential` (B11), merged
9
+ * into the deps `SmartServer` passes. An in-memory skill store sends nothing and
10
+ * reads no entry.
11
+ */
12
+ export function createBuildSkillHost(lookup, impl = buildSkillHostFromConfig) {
13
+ return async (cfg, deps) => {
14
+ if (cfg.store.type !== 'qdrant')
15
+ return impl(cfg, deps);
16
+ const { credential } = lookup(cfg.store.credentialRef, DEFAULT_STORE_REF, 'skill store (qdrant)').optional('api-key');
17
+ return impl(cfg, credential ? { ...deps, storeCredential: credential } : deps);
18
+ };
19
+ }
20
+ //# sourceMappingURL=build-skill-host.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-skill-host.js","sourceRoot":"","sources":["../../src/composition/build-skill-host.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,wBAAwB,GAEzB,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAGxD;;;;;;;;GAQG;AACH,MAAM,UAAU,oBAAoB,CAClC,MAAc,EACd,OAAwC,wBAAwB;IAEhE,OAAO,KAAK,EACV,GAAuB,EACvB,IAAwB,EACG,EAAE;QAC7B,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACxD,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,CAC3B,GAAG,CAAC,KAAK,CAAC,aAAa,EACvB,iBAAiB,EACjB,sBAAsB,CACvB,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QACtB,OAAO,IAAI,CACT,GAAG,EACH,UAAU,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,eAAe,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,IAAI,CAC7D,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,48 @@
1
+ import type { IApiKeyCredential, IBearerCredential, ISecretLoginCredential } from '@mcp-abap-adt/interfaces-auth';
2
+ export type AnyCredential = IApiKeyCredential | IBearerCredential | ISecretLoginCredential;
3
+ export type CredentialEntry = {
4
+ /** Absent means this target needs none. Any of the three kinds is admissible:
5
+ * a store entry holds a secret-login, an LLM entry an api key or a bearer. */
6
+ credential?: AnyCredential;
7
+ /** SAP AI Core only; it travels with the credential from the same service key. */
8
+ apiBaseUrl?: string;
9
+ };
10
+ export type CredentialFor = (ref: string) => CredentialEntry | undefined;
11
+ /**
12
+ * What a section with no `credentialRef` resolves to — one per ROLE, because an
13
+ * entry holds one credential and a store's kind need not match an embedder's
14
+ * (§8 item 4). The root's choice, not a provider's. A deployment where they are
15
+ * one account names that account explicitly in each section.
16
+ */
17
+ export declare const DEFAULT_LLM_REF = "LLM";
18
+ export declare const DEFAULT_STORE_REF = "RAG_STORE";
19
+ export declare const DEFAULT_EMBEDDER_REF = "RAG_EMBEDDER";
20
+ /**
21
+ * A function, not a map literal, so nothing is read or parsed until a ref asks —
22
+ * and memoized, so the same ref always hands back the SAME credential object.
23
+ * That identity is load-bearing: the 429 gate keys a quota bucket on it
24
+ * (§4.6.5), so a fresh object per lookup would quietly stop the gate gating.
25
+ */
26
+ export declare function memoizeCredentials(buildEntry: (ref: string) => CredentialEntry | undefined): CredentialFor;
27
+ /**
28
+ * The shipped app's registry (§8 item 4): a ref names a family of environment
29
+ * variables.
30
+ * <REF>_API_KEY → an api-key credential
31
+ * <REF>_SERVICE_KEY → a SAP AI Core service key: bearer + apiBaseUrl
32
+ * <REF>_USER + <REF>_PASSWORD → a secret-login credential
33
+ * None set → no entry. More than one set → refused: an entry holds ONE
34
+ * credential. A rule rather than a switch, so it serves every deployment; a
35
+ * consumer with its own composition root passes its own `buildEntry` to
36
+ * `memoizeCredentials`.
37
+ */
38
+ export declare function envCredentialEntries(env: NodeJS.ProcessEnv): (ref: string) => CredentialEntry | undefined;
39
+ /**
40
+ * Before v27 the shipped app read one fixed variable, `AICORE_SERVICE_KEY`; now
41
+ * a ref names the family (`LLM_SERVICE_KEY` for the default LLM). A deployment
42
+ * that upgraded without renaming it fails with "got none", which does not say
43
+ * why. Given only for THAT failure — the default LLM ref resolving to nothing —
44
+ * because `AICORE_SERVICE_KEY` is still a valid variable for `credentialRef:
45
+ * AICORE`, and a hint beside any other failure would be false.
46
+ */
47
+ export declare function legacyEnvHint(env: NodeJS.ProcessEnv, failure: unknown): string | undefined;
48
+ //# sourceMappingURL=credential-for.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credential-for.d.ts","sourceRoot":"","sources":["../../src/composition/credential-for.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,iBAAiB,EACjB,iBAAiB,EACjB,sBAAsB,EACvB,MAAM,+BAA+B,CAAC;AAIvC,MAAM,MAAM,aAAa,GACrB,iBAAiB,GACjB,iBAAiB,GACjB,sBAAsB,CAAC;AAE3B,MAAM,MAAM,eAAe,GAAG;IAC5B;mFAC+E;IAC/E,UAAU,CAAC,EAAE,aAAa,CAAC;IAC3B,kFAAkF;IAClF,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,eAAe,GAAG,SAAS,CAAC;AAEzE;;;;;GAKG;AACH,eAAO,MAAM,eAAe,QAAQ,CAAC;AACrC,eAAO,MAAM,iBAAiB,cAAc,CAAC;AAC7C,eAAO,MAAM,oBAAoB,iBAAiB,CAAC;AAEnD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,eAAe,GAAG,SAAS,GACvD,aAAa,CAQf;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,MAAM,CAAC,UAAU,GACrB,CAAC,GAAG,EAAE,MAAM,KAAK,eAAe,GAAG,SAAS,CAuC9C;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,MAAM,CAAC,UAAU,EACtB,OAAO,EAAE,OAAO,GACf,MAAM,GAAG,SAAS,CAWpB"}
@@ -0,0 +1,95 @@
1
+ import { staticApiKey, staticLogin } from '@mcp-abap-adt/llm-agent';
2
+ import { serviceKeyCredential } from '@mcp-abap-adt/sap-aicore-auth';
3
+ /**
4
+ * What a section with no `credentialRef` resolves to — one per ROLE, because an
5
+ * entry holds one credential and a store's kind need not match an embedder's
6
+ * (§8 item 4). The root's choice, not a provider's. A deployment where they are
7
+ * one account names that account explicitly in each section.
8
+ */
9
+ export const DEFAULT_LLM_REF = 'LLM';
10
+ export const DEFAULT_STORE_REF = 'RAG_STORE';
11
+ export const DEFAULT_EMBEDDER_REF = 'RAG_EMBEDDER';
12
+ /**
13
+ * A function, not a map literal, so nothing is read or parsed until a ref asks —
14
+ * and memoized, so the same ref always hands back the SAME credential object.
15
+ * That identity is load-bearing: the 429 gate keys a quota bucket on it
16
+ * (§4.6.5), so a fresh object per lookup would quietly stop the gate gating.
17
+ */
18
+ export function memoizeCredentials(buildEntry) {
19
+ const entries = new Map();
20
+ return (ref) => {
21
+ if (entries.has(ref))
22
+ return entries.get(ref);
23
+ const entry = buildEntry(ref);
24
+ entries.set(ref, entry);
25
+ return entry;
26
+ };
27
+ }
28
+ /**
29
+ * The shipped app's registry (§8 item 4): a ref names a family of environment
30
+ * variables.
31
+ * <REF>_API_KEY → an api-key credential
32
+ * <REF>_SERVICE_KEY → a SAP AI Core service key: bearer + apiBaseUrl
33
+ * <REF>_USER + <REF>_PASSWORD → a secret-login credential
34
+ * None set → no entry. More than one set → refused: an entry holds ONE
35
+ * credential. A rule rather than a switch, so it serves every deployment; a
36
+ * consumer with its own composition root passes its own `buildEntry` to
37
+ * `memoizeCredentials`.
38
+ */
39
+ export function envCredentialEntries(env) {
40
+ return (ref) => {
41
+ const apiKey = env[`${ref}_API_KEY`];
42
+ const serviceKey = env[`${ref}_SERVICE_KEY`];
43
+ const user = env[`${ref}_USER`];
44
+ const password = env[`${ref}_PASSWORD`];
45
+ const set = [
46
+ apiKey ? `${ref}_API_KEY` : undefined,
47
+ serviceKey ? `${ref}_SERVICE_KEY` : undefined,
48
+ user || password ? `${ref}_USER/${ref}_PASSWORD` : undefined,
49
+ ].filter((s) => s !== undefined);
50
+ if (set.length > 1) {
51
+ throw new Error(`credentialRef '${ref}' is ambiguous: ${set.join(' and ')} are all set, ` +
52
+ 'but an entry holds one credential');
53
+ }
54
+ if (apiKey)
55
+ return { credential: staticApiKey(apiKey) };
56
+ if (serviceKey) {
57
+ const k = serviceKeyCredential(serviceKey);
58
+ let apiBaseUrl;
59
+ try {
60
+ apiBaseUrl = k.apiBaseUrl;
61
+ }
62
+ catch (err) {
63
+ // The parser cannot know which variable held the key; this rule does.
64
+ throw new Error(`${ref}_SERVICE_KEY: ${err.message}`);
65
+ }
66
+ return { credential: k.credential, apiBaseUrl };
67
+ }
68
+ if (user || password) {
69
+ if (!user || !password) {
70
+ throw new Error(`credentialRef '${ref}' needs both ${ref}_USER and ${ref}_PASSWORD`);
71
+ }
72
+ return { credential: staticLogin(user, password) };
73
+ }
74
+ return undefined;
75
+ };
76
+ }
77
+ /**
78
+ * Before v27 the shipped app read one fixed variable, `AICORE_SERVICE_KEY`; now
79
+ * a ref names the family (`LLM_SERVICE_KEY` for the default LLM). A deployment
80
+ * that upgraded without renaming it fails with "got none", which does not say
81
+ * why. Given only for THAT failure — the default LLM ref resolving to nothing —
82
+ * because `AICORE_SERVICE_KEY` is still a valid variable for `credentialRef:
83
+ * AICORE`, and a hint beside any other failure would be false.
84
+ */
85
+ export function legacyEnvHint(env, failure) {
86
+ const message = failure instanceof Error ? failure.message : String(failure);
87
+ const llmRefMissing = message.startsWith(`credentialRef '${DEFAULT_LLM_REF}' must hold`) &&
88
+ message.endsWith('got none');
89
+ if (!llmRefMissing || !env.AICORE_SERVICE_KEY)
90
+ return undefined;
91
+ return (`AICORE_SERVICE_KEY is set, but the default LLM reads ${DEFAULT_LLM_REF}_SERVICE_KEY ` +
92
+ `since v27 — rename it, or name it with credentialRef: AICORE ` +
93
+ '(see docs/MIGRATION-v27.md, item 4).');
94
+ }
95
+ //# sourceMappingURL=credential-for.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credential-for.js","sourceRoot":"","sources":["../../src/composition/credential-for.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { BuildAgentDeps } from '@mcp-abap-adt/llm-agent-server-libs';
2
+ export { legacyEnvHint } from './credential-for.js';
3
+ export { createModelResolver } from './model-resolver.js';
4
+ export type CompositionDeps = Pick<BuildAgentDeps, 'makeLlm' | 'resolveEmbedder' | 'makeRag'> & {
5
+ buildSkillHost: NonNullable<BuildAgentDeps['buildSkillHost']>;
6
+ };
7
+ /**
8
+ * The three construction seams the library no longer defaults (§4.6.3, §4.6.4)
9
+ * and the skill-store wrapper, over ONE memoized registry, so an account named
10
+ * by an LLM, a store, an embedder and a skill store is one credential object and
11
+ * one quota bucket (§4.6.5).
12
+ */
13
+ export declare function buildCompositionDeps(env?: NodeJS.ProcessEnv): CompositionDeps;
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/composition/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AAQ1E,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE1D,MAAM,MAAM,eAAe,GAAG,IAAI,CAChC,cAAc,EACd,SAAS,GAAG,iBAAiB,GAAG,SAAS,CAC1C,GAAG;IACF,cAAc,EAAE,WAAW,CAAC,cAAc,CAAC,gBAAgB,CAAC,CAAC,CAAC;CAC/D,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,eAAe,CAQjB"}
@@ -0,0 +1,24 @@
1
+ import { createBuildSkillHost } from './build-skill-host.js';
2
+ import { envCredentialEntries, memoizeCredentials } from './credential-for.js';
3
+ import { createLookup } from './lookup.js';
4
+ import { createMakeLlm } from './make-llm.js';
5
+ import { createMakeRag } from './make-rag.js';
6
+ import { createResolveEmbedder } from './resolve-embedder.js';
7
+ export { legacyEnvHint } from './credential-for.js';
8
+ export { createModelResolver } from './model-resolver.js';
9
+ /**
10
+ * The three construction seams the library no longer defaults (§4.6.3, §4.6.4)
11
+ * and the skill-store wrapper, over ONE memoized registry, so an account named
12
+ * by an LLM, a store, an embedder and a skill store is one credential object and
13
+ * one quota bucket (§4.6.5).
14
+ */
15
+ export function buildCompositionDeps(env = process.env) {
16
+ const lookup = createLookup(memoizeCredentials(envCredentialEntries(env)));
17
+ return {
18
+ makeLlm: createMakeLlm(lookup),
19
+ resolveEmbedder: createResolveEmbedder(lookup),
20
+ makeRag: createMakeRag(lookup),
21
+ buildSkillHost: createBuildSkillHost(lookup),
22
+ };
23
+ }
24
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/composition/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC/E,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAE9D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAS1D;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAClC,MAAyB,OAAO,CAAC,GAAG;IAEpC,MAAM,MAAM,GAAG,YAAY,CAAC,kBAAkB,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAC3E,OAAO;QACL,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC;QAC9B,eAAe,EAAE,qBAAqB,CAAC,MAAM,CAAC;QAC9C,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC;QAC9B,cAAc,EAAE,oBAAoB,CAAC,MAAM,CAAC;KAC7C,CAAC;AACJ,CAAC"}
@@ -0,0 +1,28 @@
1
+ import type { AnyCredential, CredentialFor } from './credential-for.js';
2
+ export type CredentialKind = AnyCredential['kind'];
3
+ type OfKind<K extends CredentialKind> = Extract<AnyCredential, {
4
+ kind: K;
5
+ }>;
6
+ export interface ResolvedRef {
7
+ /** A target that cannot work without one. */
8
+ require<K extends CredentialKind>(kind: K): OfKind<K>;
9
+ /** A target that can work without one — but only when none was asked for. */
10
+ optional<K extends CredentialKind>(kind: K): {
11
+ credential?: OfKind<K>;
12
+ };
13
+ requireApiBaseUrl(): string;
14
+ /** A target that sends nothing: naming a ref for it is a mistake worth reporting. */
15
+ refuseAny(): void;
16
+ }
17
+ export type Lookup = (ref: string | undefined, roleDefault: string, target: string) => ResolvedRef;
18
+ /**
19
+ * The lookup that makes "optional" mean what it says (§4.6.4): a ref may be
20
+ * OMITTED, but a ref that was NAMED must resolve and hold the right kind — the
21
+ * difference between a deployment that chose anonymous access and one with a
22
+ * typo in it. The role default is read only when a target asks for a
23
+ * credential (§8 item 4), so a target that takes none (an in-memory store, an
24
+ * Ollama embedder) never parses the default entry.
25
+ */
26
+ export declare function createLookup(credentialFor: CredentialFor): Lookup;
27
+ export {};
28
+ //# sourceMappingURL=lookup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lookup.d.ts","sourceRoot":"","sources":["../../src/composition/lookup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EAEb,aAAa,EACd,MAAM,qBAAqB,CAAC;AAE7B,MAAM,MAAM,cAAc,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;AACnD,KAAK,MAAM,CAAC,CAAC,SAAS,cAAc,IAAI,OAAO,CAAC,aAAa,EAAE;IAAE,IAAI,EAAE,CAAC,CAAA;CAAE,CAAC,CAAC;AAE5E,MAAM,WAAW,WAAW;IAC1B,6CAA6C;IAC7C,OAAO,CAAC,CAAC,SAAS,cAAc,EAAE,IAAI,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IACtD,6EAA6E;IAC7E,QAAQ,CAAC,CAAC,SAAS,cAAc,EAAE,IAAI,EAAE,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAA;KAAE,CAAC;IACxE,iBAAiB,IAAI,MAAM,CAAC;IAC5B,qFAAqF;IACrF,SAAS,IAAI,IAAI,CAAC;CACnB;AAED,MAAM,MAAM,MAAM,GAAG,CACnB,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,KACX,WAAW,CAAC;AAEjB;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,aAAa,EAAE,aAAa,GAAG,MAAM,CAwDjE"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * The lookup that makes "optional" mean what it says (§4.6.4): a ref may be
3
+ * OMITTED, but a ref that was NAMED must resolve and hold the right kind — the
4
+ * difference between a deployment that chose anonymous access and one with a
5
+ * typo in it. The role default is read only when a target asks for a
6
+ * credential (§8 item 4), so a target that takes none (an in-memory store, an
7
+ * Ollama embedder) never parses the default entry.
8
+ */
9
+ export function createLookup(credentialFor) {
10
+ return (ref, roleDefault, target) => {
11
+ const named = ref !== undefined;
12
+ const key = ref ?? roleDefault;
13
+ const namedEntry = named ? credentialFor(key) : undefined;
14
+ if (named && !namedEntry) {
15
+ throw new Error(`credentialRef '${key}' for ${target} has no entry configured`);
16
+ }
17
+ const entry = () => named ? namedEntry : credentialFor(key);
18
+ const wrongKind = (kind, got) => {
19
+ throw new Error(`credentialRef '${key}' must hold a ${kind} credential for ${target}, ` +
20
+ `got ${got?.credential?.kind ?? 'none'}`);
21
+ };
22
+ return {
23
+ require(kind) {
24
+ const e = entry();
25
+ const c = e?.credential;
26
+ if (c?.kind !== kind)
27
+ return wrongKind(kind, e);
28
+ return c;
29
+ },
30
+ optional(kind) {
31
+ const e = entry();
32
+ const c = e?.credential;
33
+ if (!c) {
34
+ if (named)
35
+ return wrongKind(kind, e); // named, resolved, empty
36
+ return {}; // omitted and empty: anonymous, on purpose
37
+ }
38
+ if (c.kind !== kind)
39
+ return wrongKind(kind, e); // never "ignore it"
40
+ return { credential: c };
41
+ },
42
+ requireApiBaseUrl() {
43
+ const e = entry();
44
+ if (!e?.apiBaseUrl) {
45
+ throw new Error(`credentialRef '${key}' must carry an apiBaseUrl for ${target}`);
46
+ }
47
+ return e.apiBaseUrl;
48
+ },
49
+ refuseAny() {
50
+ if (named) {
51
+ throw new Error(`${target} takes no credential, so credentialRef '${key}' cannot apply`);
52
+ }
53
+ },
54
+ };
55
+ };
56
+ }
57
+ //# sourceMappingURL=lookup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lookup.js","sourceRoot":"","sources":["../../src/composition/lookup.ts"],"names":[],"mappings":"AAyBA;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAC,aAA4B;IACvD,OAAO,CAAC,GAAG,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE;QAClC,MAAM,KAAK,GAAG,GAAG,KAAK,SAAS,CAAC;QAChC,MAAM,GAAG,GAAG,GAAG,IAAI,WAAW,CAAC;QAC/B,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAC1D,IAAI,KAAK,IAAI,CAAC,UAAU,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CACb,kBAAkB,GAAG,SAAS,MAAM,0BAA0B,CAC/D,CAAC;QACJ,CAAC;QACD,MAAM,KAAK,GAAG,GAAgC,EAAE,CAC9C,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;QAC1C,MAAM,SAAS,GAAG,CAChB,IAAY,EACZ,GAAgC,EACzB,EAAE;YACT,MAAM,IAAI,KAAK,CACb,kBAAkB,GAAG,iBAAiB,IAAI,mBAAmB,MAAM,IAAI;gBACrE,OAAO,GAAG,EAAE,UAAU,EAAE,IAAI,IAAI,MAAM,EAAE,CAC3C,CAAC;QACJ,CAAC,CAAC;QACF,OAAO;YACL,OAAO,CAA2B,IAAO;gBACvC,MAAM,CAAC,GAAG,KAAK,EAAE,CAAC;gBAClB,MAAM,CAAC,GAAG,CAAC,EAAE,UAAU,CAAC;gBACxB,IAAI,CAAC,EAAE,IAAI,KAAK,IAAI;oBAAE,OAAO,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;gBAChD,OAAO,CAAc,CAAC;YACxB,CAAC;YACD,QAAQ,CAA2B,IAAO;gBACxC,MAAM,CAAC,GAAG,KAAK,EAAE,CAAC;gBAClB,MAAM,CAAC,GAAG,CAAC,EAAE,UAAU,CAAC;gBACxB,IAAI,CAAC,CAAC,EAAE,CAAC;oBACP,IAAI,KAAK;wBAAE,OAAO,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,yBAAyB;oBAC/D,OAAO,EAAE,CAAC,CAAC,2CAA2C;gBACxD,CAAC;gBACD,IAAI,CAAC,CAAC,IAAI,KAAK,IAAI;oBAAE,OAAO,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,oBAAoB;gBACpE,OAAO,EAAE,UAAU,EAAE,CAAc,EAAE,CAAC;YACxC,CAAC;YACD,iBAAiB;gBACf,MAAM,CAAC,GAAG,KAAK,EAAE,CAAC;gBAClB,IAAI,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC;oBACnB,MAAM,IAAI,KAAK,CACb,kBAAkB,GAAG,kCAAkC,MAAM,EAAE,CAChE,CAAC;gBACJ,CAAC;gBACD,OAAO,CAAC,CAAC,UAAU,CAAC;YACtB,CAAC;YACD,SAAS;gBACP,IAAI,KAAK,EAAE,CAAC;oBACV,MAAM,IAAI,KAAK,CACb,GAAG,MAAM,2CAA2C,GAAG,gBAAgB,CACxE,CAAC;gBACJ,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,37 @@
1
+ import { type AnthropicConfig } from '@mcp-abap-adt/anthropic-llm';
2
+ import { type DeepSeekConfig } from '@mcp-abap-adt/deepseek-llm';
3
+ import type { ILlm, LLMProvider } from '@mcp-abap-adt/llm-agent';
4
+ import type { SmartServerLlmConfig } from '@mcp-abap-adt/llm-agent-server-libs';
5
+ import { type OllamaConfig } from '@mcp-abap-adt/ollama-llm';
6
+ import { type OpenAIConfig } from '@mcp-abap-adt/openai-llm';
7
+ import type { SapCoreAIConfig } from '@mcp-abap-adt/sap-aicore-llm';
8
+ import type { Lookup } from './lookup.js';
9
+ type ProviderInstance = LLMProvider & {
10
+ readonly model: string;
11
+ };
12
+ type SapCoreAICtor = new (cfg: SapCoreAIConfig) => ProviderInstance;
13
+ /** The five constructors, injectable so a test records what each receives. */
14
+ export interface LlmProviderCtors {
15
+ openai: new (cfg: OpenAIConfig) => ProviderInstance;
16
+ anthropic: new (cfg: AnthropicConfig) => ProviderInstance;
17
+ deepseek: new (cfg: DeepSeekConfig) => ProviderInstance;
18
+ ollama: new (cfg: OllamaConfig) => ProviderInstance;
19
+ /**
20
+ * A loader, not the constructor: `@mcp-abap-adt/sap-aicore-llm` pulls
21
+ * `@sap-ai-sdk/orchestration`, which installs process `uncaughtException`
22
+ * listeners at import time. Imported statically, every deployment would survive
23
+ * uncaught exceptions; loaded here, only one that selects `sap-ai-sdk` pays.
24
+ */
25
+ 'sap-ai-sdk': () => Promise<SapCoreAICtor>;
26
+ }
27
+ export declare const SHIPPED_LLM_PROVIDERS: LlmProviderCtors;
28
+ /**
29
+ * `BuildAgentDeps.makeLlm` (§8 item 4). Every provider config is built from NAMED
30
+ * fields — nothing spreads `cfg` — so `credentialRef` cannot ride along into a
31
+ * provider (§4.6.4). The knobs the library's `makeLlm` used to forward are
32
+ * forwarded here: without `temperature` the server's main (0.7) and classifier
33
+ * (0.1) roles would collapse onto one provider default.
34
+ */
35
+ export declare function createMakeLlm(lookup: Lookup, ctors?: LlmProviderCtors): (cfg: SmartServerLlmConfig) => Promise<ILlm>;
36
+ export {};
37
+ //# sourceMappingURL=make-llm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"make-llm.d.ts","sourceRoot":"","sources":["../../src/composition/make-llm.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,eAAe,EAErB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,KAAK,cAAc,EAEpB,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAEjE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qCAAqC,CAAC;AAChF,OAAO,EAAE,KAAK,YAAY,EAAkB,MAAM,0BAA0B,CAAC;AAC7E,OAAO,EAAE,KAAK,YAAY,EAAkB,MAAM,0BAA0B,CAAC;AAC7E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAEpE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,KAAK,gBAAgB,GAAG,WAAW,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjE,KAAK,aAAa,GAAG,KAAK,GAAG,EAAE,eAAe,KAAK,gBAAgB,CAAC;AAEpE,8EAA8E;AAC9E,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,KAAK,GAAG,EAAE,YAAY,KAAK,gBAAgB,CAAC;IACpD,SAAS,EAAE,KAAK,GAAG,EAAE,eAAe,KAAK,gBAAgB,CAAC;IAC1D,QAAQ,EAAE,KAAK,GAAG,EAAE,cAAc,KAAK,gBAAgB,CAAC;IACxD,MAAM,EAAE,KAAK,GAAG,EAAE,YAAY,KAAK,gBAAgB,CAAC;IACpD;;;;;OAKG;IACH,YAAY,EAAE,MAAM,OAAO,CAAC,aAAa,CAAC,CAAC;CAC5C;AAED,eAAO,MAAM,qBAAqB,EAAE,gBAOnC,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,MAAM,EACd,KAAK,GAAE,gBAAwC,GAC9C,CAAC,GAAG,EAAE,oBAAoB,KAAK,OAAO,CAAC,IAAI,CAAC,CA8D9C"}
@@ -0,0 +1,79 @@
1
+ import { AnthropicProvider, } from '@mcp-abap-adt/anthropic-llm';
2
+ import { DeepSeekProvider, } from '@mcp-abap-adt/deepseek-llm';
3
+ import { LlmAdapter, LlmProviderBridge } from '@mcp-abap-adt/llm-agent-libs';
4
+ import { OllamaProvider } from '@mcp-abap-adt/ollama-llm';
5
+ import { OpenAIProvider } from '@mcp-abap-adt/openai-llm';
6
+ import { DEFAULT_LLM_REF } from './credential-for.js';
7
+ export const SHIPPED_LLM_PROVIDERS = {
8
+ openai: OpenAIProvider,
9
+ anthropic: AnthropicProvider,
10
+ deepseek: DeepSeekProvider,
11
+ ollama: OllamaProvider,
12
+ 'sap-ai-sdk': async () => (await import('@mcp-abap-adt/sap-aicore-llm')).SapCoreAIProvider,
13
+ };
14
+ /**
15
+ * `BuildAgentDeps.makeLlm` (§8 item 4). Every provider config is built from NAMED
16
+ * fields — nothing spreads `cfg` — so `credentialRef` cannot ride along into a
17
+ * provider (§4.6.4). The knobs the library's `makeLlm` used to forward are
18
+ * forwarded here: without `temperature` the server's main (0.7) and classifier
19
+ * (0.1) roles would collapse onto one provider default.
20
+ */
21
+ export function createMakeLlm(lookup, ctors = SHIPPED_LLM_PROVIDERS) {
22
+ return async (cfg) => {
23
+ const entry = lookup(cfg.credentialRef, DEFAULT_LLM_REF, cfg.provider ?? 'llm');
24
+ const knobs = {
25
+ model: cfg.model,
26
+ temperature: cfg.temperature,
27
+ maxTokens: cfg.maxTokens,
28
+ whenThrottled: cfg.whenThrottled,
29
+ };
30
+ const provider = await (async () => {
31
+ switch (cfg.provider) {
32
+ case 'openai':
33
+ return new ctors.openai({
34
+ ...knobs,
35
+ baseURL: cfg.url,
36
+ credential: entry.require('api-key'),
37
+ });
38
+ case 'anthropic':
39
+ return new ctors.anthropic({
40
+ ...knobs,
41
+ baseURL: cfg.url,
42
+ credential: entry.require('api-key'),
43
+ });
44
+ case 'deepseek':
45
+ return new ctors.deepseek({
46
+ ...knobs,
47
+ baseURL: cfg.url,
48
+ credential: entry.require('api-key'),
49
+ });
50
+ case 'ollama':
51
+ // Optional, and only from a ref that NAMES one: the LLM role default
52
+ // usually holds a hosted provider's key, and sending it to a local
53
+ // Ollama (or whatever sits at cfg.url) would hand a secret to a target
54
+ // nobody authorized for it.
55
+ return new ctors.ollama({
56
+ ...knobs,
57
+ baseURL: cfg.url,
58
+ ...(cfg.credentialRef === undefined
59
+ ? {}
60
+ : entry.optional('api-key')),
61
+ });
62
+ case 'sap-ai-sdk':
63
+ return new (await ctors['sap-ai-sdk']())({
64
+ ...knobs,
65
+ credential: entry.require('bearer'),
66
+ apiBaseUrl: entry.requireApiBaseUrl(),
67
+ });
68
+ default:
69
+ throw new Error(`unknown llm provider '${String(cfg.provider)}'`);
70
+ }
71
+ })();
72
+ return new LlmAdapter(new LlmProviderBridge(provider), {
73
+ model: provider.model,
74
+ getModels: () => provider.getModels?.() ?? Promise.resolve([]),
75
+ getEmbeddingModels: () => provider.getEmbeddingModels?.() ?? Promise.resolve([]),
76
+ });
77
+ };
78
+ }
79
+ //# sourceMappingURL=make-llm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"make-llm.js","sourceRoot":"","sources":["../../src/composition/make-llm.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,iBAAiB,GAClB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAEL,gBAAgB,GACjB,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAE7E,OAAO,EAAqB,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC7E,OAAO,EAAqB,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE7E,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAsBtD,MAAM,CAAC,MAAM,qBAAqB,GAAqB;IACrD,MAAM,EAAE,cAAc;IACtB,SAAS,EAAE,iBAAiB;IAC5B,QAAQ,EAAE,gBAAgB;IAC1B,MAAM,EAAE,cAAc;IACtB,YAAY,EAAE,KAAK,IAAI,EAAE,CACvB,CAAC,MAAM,MAAM,CAAC,8BAA8B,CAAC,CAAC,CAAC,iBAAiB;CACnE,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAC3B,MAAc,EACd,QAA0B,qBAAqB;IAE/C,OAAO,KAAK,EAAE,GAAG,EAAE,EAAE;QACnB,MAAM,KAAK,GAAG,MAAM,CAClB,GAAG,CAAC,aAAa,EACjB,eAAe,EACf,GAAG,CAAC,QAAQ,IAAI,KAAK,CACtB,CAAC;QACF,MAAM,KAAK,GAAG;YACZ,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,WAAW,EAAE,GAAG,CAAC,WAAW;YAC5B,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,aAAa,EAAE,GAAG,CAAC,aAAa;SACjC,CAAC;QACF,MAAM,QAAQ,GAAqB,MAAM,CAAC,KAAK,IAAI,EAAE;YACnD,QAAQ,GAAG,CAAC,QAAQ,EAAE,CAAC;gBACrB,KAAK,QAAQ;oBACX,OAAO,IAAI,KAAK,CAAC,MAAM,CAAC;wBACtB,GAAG,KAAK;wBACR,OAAO,EAAE,GAAG,CAAC,GAAG;wBAChB,UAAU,EAAE,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC;qBACrC,CAAC,CAAC;gBACL,KAAK,WAAW;oBACd,OAAO,IAAI,KAAK,CAAC,SAAS,CAAC;wBACzB,GAAG,KAAK;wBACR,OAAO,EAAE,GAAG,CAAC,GAAG;wBAChB,UAAU,EAAE,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC;qBACrC,CAAC,CAAC;gBACL,KAAK,UAAU;oBACb,OAAO,IAAI,KAAK,CAAC,QAAQ,CAAC;wBACxB,GAAG,KAAK;wBACR,OAAO,EAAE,GAAG,CAAC,GAAG;wBAChB,UAAU,EAAE,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC;qBACrC,CAAC,CAAC;gBACL,KAAK,QAAQ;oBACX,qEAAqE;oBACrE,mEAAmE;oBACnE,uEAAuE;oBACvE,4BAA4B;oBAC5B,OAAO,IAAI,KAAK,CAAC,MAAM,CAAC;wBACtB,GAAG,KAAK;wBACR,OAAO,EAAE,GAAG,CAAC,GAAG;wBAChB,GAAG,CAAC,GAAG,CAAC,aAAa,KAAK,SAAS;4BACjC,CAAC,CAAC,EAAE;4BACJ,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;qBAC/B,CAAC,CAAC;gBACL,KAAK,YAAY;oBACf,OAAO,IAAI,CAAC,MAAM,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;wBACvC,GAAG,KAAK;wBACR,UAAU,EAAE,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;wBACnC,UAAU,EAAE,KAAK,CAAC,iBAAiB,EAAE;qBACtC,CAAC,CAAC;gBACL;oBACE,MAAM,IAAI,KAAK,CAAC,yBAAyB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;YACtE,CAAC;QACH,CAAC,CAAC,EAAE,CAAC;QACL,OAAO,IAAI,UAAU,CAAC,IAAI,iBAAiB,CAAC,QAAQ,CAAC,EAAE;YACrD,KAAK,EAAE,QAAQ,CAAC,KAAK;YACrB,SAAS,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,SAAS,EAAE,EAAE,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;YAC9D,kBAAkB,EAAE,GAAG,EAAE,CACvB,QAAQ,CAAC,kBAAkB,EAAE,EAAE,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;SACzD,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,14 @@
1
+ import { type IRag } from '@mcp-abap-adt/llm-agent';
2
+ import { makeRag as libMakeRag } from '@mcp-abap-adt/llm-agent-rag';
3
+ import { type MakeRagInput } from '@mcp-abap-adt/llm-agent-server-libs';
4
+ import type { Lookup } from './lookup.js';
5
+ /**
6
+ * `BuildAgentDeps.makeRag` (§8 item 4): the serializable store section plus,
7
+ * where the store needs one, a resolved embedder — and this body is the
8
+ * conversion into the library's typed `RagResolution` (§4.6.4). The pair's
9
+ * discriminant is nested (`store.type`), which does not narrow the pair, so
10
+ * B10's `isInMemoryInput` narrows the whole input before `embedder` is known
11
+ * to be present.
12
+ */
13
+ export declare function createMakeRag(lookup: Lookup, impl?: typeof libMakeRag): (input: MakeRagInput) => Promise<IRag>;
14
+ //# sourceMappingURL=make-rag.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"make-rag.d.ts","sourceRoot":"","sources":["../../src/composition/make-rag.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,IAAI,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACpE,OAAO,EAEL,KAAK,YAAY,EAClB,MAAM,qCAAqC,CAAC;AAE7C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,MAAM,EACd,IAAI,GAAE,OAAO,UAAuB,GACnC,CAAC,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,CAsCxC"}
@@ -0,0 +1,52 @@
1
+ import { InMemoryRag } from '@mcp-abap-adt/llm-agent';
2
+ import { makeRag as libMakeRag } from '@mcp-abap-adt/llm-agent-rag';
3
+ import { isInMemoryInput, } from '@mcp-abap-adt/llm-agent-server-libs';
4
+ import { DEFAULT_STORE_REF } from './credential-for.js';
5
+ /**
6
+ * `BuildAgentDeps.makeRag` (§8 item 4): the serializable store section plus,
7
+ * where the store needs one, a resolved embedder — and this body is the
8
+ * conversion into the library's typed `RagResolution` (§4.6.4). The pair's
9
+ * discriminant is nested (`store.type`), which does not narrow the pair, so
10
+ * B10's `isInMemoryInput` narrows the whole input before `embedder` is known
11
+ * to be present.
12
+ */
13
+ export function createMakeRag(lookup, impl = libMakeRag) {
14
+ return async (input) => {
15
+ if (isInMemoryInput(input)) {
16
+ const { credentialRef, ...address } = input.store;
17
+ lookup(credentialRef, DEFAULT_STORE_REF, 'in-memory').refuseAny();
18
+ return input.embedder
19
+ ? impl({ ...address, embedder: input.embedder })
20
+ : // keyword-only: no namespace, as on main; preprocessors/enrichers are
21
+ // not YAML fields, so nothing a file configured is lost (§4.6.4)
22
+ new InMemoryRag({ dedupThreshold: address.dedupThreshold });
23
+ }
24
+ const { embedder, store } = input;
25
+ switch (store.type) {
26
+ case 'qdrant': {
27
+ const { credentialRef, ...address } = store;
28
+ const entry = lookup(credentialRef, DEFAULT_STORE_REF, 'qdrant');
29
+ return impl({ ...address, embedder, ...entry.optional('api-key') });
30
+ }
31
+ case 'pg-vector': {
32
+ const { credentialRef, ...address } = store;
33
+ const entry = lookup(credentialRef, DEFAULT_STORE_REF, 'pg-vector');
34
+ return impl({
35
+ ...address,
36
+ embedder,
37
+ ...entry.optional('secret-login'),
38
+ });
39
+ }
40
+ case 'hana-vector': {
41
+ const { credentialRef, ...address } = store;
42
+ const entry = lookup(credentialRef, DEFAULT_STORE_REF, 'hana-vector');
43
+ return impl({
44
+ ...address,
45
+ embedder,
46
+ credential: entry.require('secret-login'),
47
+ });
48
+ }
49
+ }
50
+ };
51
+ }
52
+ //# sourceMappingURL=make-rag.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"make-rag.js","sourceRoot":"","sources":["../../src/composition/make-rag.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAa,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACpE,OAAO,EACL,eAAe,GAEhB,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAGxD;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAC3B,MAAc,EACd,OAA0B,UAAU;IAEpC,OAAO,KAAK,EAAE,KAAK,EAAE,EAAE;QACrB,IAAI,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3B,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC;YAClD,MAAM,CAAC,aAAa,EAAE,iBAAiB,EAAE,WAAW,CAAC,CAAC,SAAS,EAAE,CAAC;YAClE,OAAO,KAAK,CAAC,QAAQ;gBACnB,CAAC,CAAC,IAAI,CAAC,EAAE,GAAG,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC;gBAChD,CAAC,CAAC,sEAAsE;oBACtE,iEAAiE;oBACjE,IAAI,WAAW,CAAC,EAAE,cAAc,EAAE,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;QAClE,CAAC;QACD,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC;QAClC,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;YACnB,KAAK,QAAQ,CAAC,CAAC,CAAC;gBACd,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,EAAE,GAAG,KAAK,CAAC;gBAC5C,MAAM,KAAK,GAAG,MAAM,CAAC,aAAa,EAAE,iBAAiB,EAAE,QAAQ,CAAC,CAAC;gBACjE,OAAO,IAAI,CAAC,EAAE,GAAG,OAAO,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;YACtE,CAAC;YACD,KAAK,WAAW,CAAC,CAAC,CAAC;gBACjB,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,EAAE,GAAG,KAAK,CAAC;gBAC5C,MAAM,KAAK,GAAG,MAAM,CAAC,aAAa,EAAE,iBAAiB,EAAE,WAAW,CAAC,CAAC;gBACpE,OAAO,IAAI,CAAC;oBACV,GAAG,OAAO;oBACV,QAAQ;oBACR,GAAG,KAAK,CAAC,QAAQ,CAAC,cAAc,CAAC;iBAClC,CAAC,CAAC;YACL,CAAC;YACD,KAAK,aAAa,CAAC,CAAC,CAAC;gBACnB,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,EAAE,GAAG,KAAK,CAAC;gBAC5C,MAAM,KAAK,GAAG,MAAM,CAAC,aAAa,EAAE,iBAAiB,EAAE,aAAa,CAAC,CAAC;gBACtE,OAAO,IAAI,CAAC;oBACV,GAAG,OAAO;oBACV,QAAQ;oBACR,UAAU,EAAE,KAAK,CAAC,OAAO,CAAC,cAAc,CAAC;iBAC1C,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}