@mcp-abap-adt/llm-agent-server 26.0.0 → 28.0.0
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 +59 -1
- package/dist/composition/build-skill-host.d.ts +13 -0
- package/dist/composition/build-skill-host.d.ts.map +1 -0
- package/dist/composition/build-skill-host.js +20 -0
- package/dist/composition/build-skill-host.js.map +1 -0
- package/dist/composition/credential-for.d.ts +48 -0
- package/dist/composition/credential-for.d.ts.map +1 -0
- package/dist/composition/credential-for.js +95 -0
- package/dist/composition/credential-for.js.map +1 -0
- package/dist/composition/index.d.ts +14 -0
- package/dist/composition/index.d.ts.map +1 -0
- package/dist/composition/index.js +24 -0
- package/dist/composition/index.js.map +1 -0
- package/dist/composition/lookup.d.ts +28 -0
- package/dist/composition/lookup.d.ts.map +1 -0
- package/dist/composition/lookup.js +57 -0
- package/dist/composition/lookup.js.map +1 -0
- package/dist/composition/make-llm.d.ts +37 -0
- package/dist/composition/make-llm.d.ts.map +1 -0
- package/dist/composition/make-llm.js +79 -0
- package/dist/composition/make-llm.js.map +1 -0
- package/dist/composition/make-rag.d.ts +14 -0
- package/dist/composition/make-rag.d.ts.map +1 -0
- package/dist/composition/make-rag.js +52 -0
- package/dist/composition/make-rag.js.map +1 -0
- package/dist/composition/model-resolver.d.ts +12 -0
- package/dist/composition/model-resolver.d.ts.map +1 -0
- package/dist/composition/model-resolver.js +38 -0
- package/dist/composition/model-resolver.js.map +1 -0
- package/dist/composition/resolve-embedder.d.ts +15 -0
- package/dist/composition/resolve-embedder.d.ts.map +1 -0
- package/dist/composition/resolve-embedder.js +76 -0
- package/dist/composition/resolve-embedder.js.map +1 -0
- package/dist/smart-agent/check-models-cli.js +4 -4
- package/dist/smart-agent/check-models-cli.js.map +1 -1
- package/dist/smart-agent/cli.d.ts +13 -7
- package/dist/smart-agent/cli.d.ts.map +1 -1
- package/dist/smart-agent/cli.js +75 -42
- package/dist/smart-agent/cli.js.map +1 -1
- package/dist/smoke-adapters.js +2 -1
- package/dist/smoke-adapters.js.map +1 -1
- package/package.json +35 -32
- package/tools/claude-via-agent.ps1 +4 -3
- 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`, `
|
|
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":"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"}
|
|
@@ -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"}
|