@endora-commerce/llm-client 0.0.0-stage → 0.107.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/LICENSE +21 -0
- package/README.md +33 -2
- package/dist/anthropic-adapter.d.ts +9 -0
- package/dist/anthropic-adapter.d.ts.map +1 -0
- package/dist/anthropic-adapter.js +84 -0
- package/dist/anthropic-adapter.js.map +1 -0
- package/dist/create-llm-adapter.d.ts +33 -0
- package/dist/create-llm-adapter.d.ts.map +1 -0
- package/dist/create-llm-adapter.js +69 -0
- package/dist/create-llm-adapter.js.map +1 -0
- package/dist/google-adapter.d.ts +9 -0
- package/dist/google-adapter.d.ts.map +1 -0
- package/dist/google-adapter.js +135 -0
- package/dist/google-adapter.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/openai-adapter.d.ts +21 -0
- package/dist/openai-adapter.d.ts.map +1 -0
- package/dist/openai-adapter.js +107 -0
- package/dist/openai-adapter.js.map +1 -0
- package/dist/provider.d.ts +78 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +73 -0
- package/dist/provider.js.map +1 -0
- package/package.json +42 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Endora sp. z o.o. and the Endora Commerce contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,34 @@
|
|
|
1
|
-
|
|
1
|
+
<!-- Generated by `pnpm --filter backend run manifests:generate`. Delete this line to take the file over; a README without it is never regenerated. -->
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
# @endora-commerce/llm-client
|
|
4
|
+
|
|
5
|
+
Provider-neutral LLM transport — fetch-based Anthropic, Google and OpenAI (and OpenAI-compatible) adapters with tool calling, shared by the modules that call a language model.
|
|
6
|
+
|
|
7
|
+
## What this is
|
|
8
|
+
|
|
9
|
+
A shared library package of **Endora Commerce**, the modular B2B/B2C commerce platform. It declares no module manifest, so the platform composes nothing from it: what is published here is what the platform and the modules built on it compile against.
|
|
10
|
+
|
|
11
|
+
## Entry points
|
|
12
|
+
|
|
13
|
+
- `@endora-commerce/llm-client`
|
|
14
|
+
|
|
15
|
+
## Depends on
|
|
16
|
+
|
|
17
|
+
**Bundled dependencies**
|
|
18
|
+
|
|
19
|
+
- `@endora-commerce/contracts`
|
|
20
|
+
- `zod` ^4.2.0
|
|
21
|
+
|
|
22
|
+
## What the tarball carries
|
|
23
|
+
|
|
24
|
+
- `dist/` — the compiled JavaScript and its type declarations
|
|
25
|
+
|
|
26
|
+
## Install
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pnpm add @endora-commerce/llm-client
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Licence
|
|
33
|
+
|
|
34
|
+
MIT — the text is in `LICENSE`, beside this file.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type FetchLike, type LlmCompletion, type LlmProviderAdapter, type LlmRequest } from './provider.js';
|
|
2
|
+
export declare class AnthropicAdapter implements LlmProviderAdapter {
|
|
3
|
+
private readonly apiKey;
|
|
4
|
+
private readonly fetchImpl;
|
|
5
|
+
readonly provider: "anthropic";
|
|
6
|
+
constructor(apiKey: string, fetchImpl?: FetchLike);
|
|
7
|
+
complete(req: LlmRequest): Promise<LlmCompletion>;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=anthropic-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic-adapter.d.ts","sourceRoot":"","sources":["../src/anthropic-adapter.ts"],"names":[],"mappings":"AACA,OAAO,EAML,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,UAAU,EAChB,MAAM,eAAe,CAAC;AAsBvB,qBAAa,gBAAiB,YAAW,kBAAkB;IAIvD,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAJ5B,QAAQ,CAAC,QAAQ,EAAG,WAAW,CAAU;gBAGtB,MAAM,EAAE,MAAM,EACd,SAAS,GAAE,SAAiB;IAGzC,QAAQ,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC;CAmExD"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { fromWireName, parseOrThrow, postJson, toWireName, wireNameMap, } from './provider.js';
|
|
3
|
+
/**
|
|
4
|
+
* Anthropic (Claude) adapter — `POST /v1/messages` with tool-use blocks.
|
|
5
|
+
* Native fetch, no SDK (research §R2).
|
|
6
|
+
*/
|
|
7
|
+
const ResponseSchema = z.object({
|
|
8
|
+
content: z.array(z.union([
|
|
9
|
+
z.object({ type: z.literal('text'), text: z.string() }),
|
|
10
|
+
z.object({
|
|
11
|
+
type: z.literal('tool_use'),
|
|
12
|
+
id: z.string(),
|
|
13
|
+
name: z.string(),
|
|
14
|
+
input: z.unknown(),
|
|
15
|
+
}),
|
|
16
|
+
])),
|
|
17
|
+
stop_reason: z.string().nullable(),
|
|
18
|
+
});
|
|
19
|
+
export class AnthropicAdapter {
|
|
20
|
+
apiKey;
|
|
21
|
+
fetchImpl;
|
|
22
|
+
provider = 'anthropic';
|
|
23
|
+
constructor(apiKey, fetchImpl = fetch) {
|
|
24
|
+
this.apiKey = apiKey;
|
|
25
|
+
this.fetchImpl = fetchImpl;
|
|
26
|
+
}
|
|
27
|
+
async complete(req) {
|
|
28
|
+
const names = wireNameMap(req.tools);
|
|
29
|
+
const body = {
|
|
30
|
+
model: req.model,
|
|
31
|
+
max_tokens: req.maxTokens,
|
|
32
|
+
system: req.system,
|
|
33
|
+
tools: req.tools.map((t) => ({
|
|
34
|
+
name: toWireName(t.name),
|
|
35
|
+
description: t.description,
|
|
36
|
+
input_schema: t.inputSchema,
|
|
37
|
+
})),
|
|
38
|
+
...(req.toolChoice ? { tool_choice: { type: 'tool', name: toWireName(req.toolChoice.name) } } : {}),
|
|
39
|
+
messages: req.messages.map((m) => {
|
|
40
|
+
if (m.role === 'user') {
|
|
41
|
+
return { role: 'user', content: [{ type: 'text', text: m.text }] };
|
|
42
|
+
}
|
|
43
|
+
if (m.role === 'assistant') {
|
|
44
|
+
return {
|
|
45
|
+
role: 'assistant',
|
|
46
|
+
content: [
|
|
47
|
+
...(m.text ? [{ type: 'text', text: m.text }] : []),
|
|
48
|
+
...m.toolCalls.map((c) => ({
|
|
49
|
+
type: 'tool_use',
|
|
50
|
+
id: c.id,
|
|
51
|
+
name: toWireName(c.name),
|
|
52
|
+
input: c.arguments,
|
|
53
|
+
})),
|
|
54
|
+
],
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
role: 'user',
|
|
59
|
+
content: [
|
|
60
|
+
{ type: 'tool_result', tool_use_id: m.toolCallId, content: m.resultJson },
|
|
61
|
+
],
|
|
62
|
+
};
|
|
63
|
+
}),
|
|
64
|
+
};
|
|
65
|
+
const json = await postJson(this.provider, this.fetchImpl, 'https://api.anthropic.com/v1/messages', { 'x-api-key': this.apiKey, 'anthropic-version': '2023-06-01' }, body, req.signal);
|
|
66
|
+
const parsed = parseOrThrow(this.provider, ResponseSchema, json);
|
|
67
|
+
const textParts = parsed.content.filter((c) => c.type === 'text').map((c) => c.text);
|
|
68
|
+
const toolCalls = parsed.content
|
|
69
|
+
.filter((c) => c.type === 'tool_use')
|
|
70
|
+
.map((c) => ({ id: c.id, name: fromWireName(c.name, names), arguments: c.input }));
|
|
71
|
+
return {
|
|
72
|
+
text: textParts.length > 0 ? textParts.join('\n') : null,
|
|
73
|
+
toolCalls,
|
|
74
|
+
stopReason: parsed.stop_reason === 'tool_use'
|
|
75
|
+
? 'tool_use'
|
|
76
|
+
: parsed.stop_reason === 'end_turn'
|
|
77
|
+
? 'end'
|
|
78
|
+
: parsed.stop_reason === 'max_tokens'
|
|
79
|
+
? 'max_tokens'
|
|
80
|
+
: 'other',
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=anthropic-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic-adapter.js","sourceRoot":"","sources":["../src/anthropic-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { FetchLike, LlmProvider, LlmProviderAdapter } from './provider.js';
|
|
2
|
+
/**
|
|
3
|
+
* One factory for every consumer (feature 151, research R21): `prompt_actions`
|
|
4
|
+
* and `cms` resolve their own credential and hand the values in; which class
|
|
5
|
+
* speaks which protocol, and which endpoint a provider defaults to, is decided
|
|
6
|
+
* here once.
|
|
7
|
+
*/
|
|
8
|
+
/** Every provider code this package can call — `LlmProviderSchema`'s options. */
|
|
9
|
+
export declare const LLM_PROVIDERS: readonly LlmProvider[];
|
|
10
|
+
/** A configuration no call could succeed with; consumers report it as "not configured". */
|
|
11
|
+
export declare class LlmConfigurationError extends Error {
|
|
12
|
+
readonly provider: LlmProvider;
|
|
13
|
+
readonly reason: 'base_url_required' | 'base_url_invalid';
|
|
14
|
+
readonly name = "LlmConfigurationError";
|
|
15
|
+
constructor(provider: LlmProvider, reason: 'base_url_required' | 'base_url_invalid');
|
|
16
|
+
}
|
|
17
|
+
/** The endpoint an OpenAI-protocol provider uses with no Base URL, or `null`. */
|
|
18
|
+
export declare function defaultBaseUrlFor(provider: LlmProvider): string | null;
|
|
19
|
+
/** `true` for an absolute `http:` / `https:` URL — the rule `credentials` applies on write too. */
|
|
20
|
+
export declare function isHttpUrl(value: string): boolean;
|
|
21
|
+
export interface CreateLlmAdapterOptions {
|
|
22
|
+
apiKey: string;
|
|
23
|
+
/** The credential's Base URL; blank or absent ⇒ the provider default. Ignored by anthropic/google. */
|
|
24
|
+
baseUrl?: string | null | undefined;
|
|
25
|
+
fetchImpl?: FetchLike | undefined;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Build the adapter for `provider`. Throws `LlmConfigurationError` synchronously
|
|
29
|
+
* for an `openai_compatible` configuration without a Base URL and for a Base URL
|
|
30
|
+
* that is not an absolute http(s) URL, so the caller learns it before any call.
|
|
31
|
+
*/
|
|
32
|
+
export declare function createLlmAdapter(provider: LlmProvider, options: CreateLlmAdapterOptions): LlmProviderAdapter;
|
|
33
|
+
//# sourceMappingURL=create-llm-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-llm-adapter.d.ts","sourceRoot":"","sources":["../src/create-llm-adapter.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAEhF;;;;;GAKG;AAEH,iFAAiF;AACjF,eAAO,MAAM,aAAa,EAAE,SAAS,WAAW,EAA8B,CAAC;AAE/E,2FAA2F;AAC3F,qBAAa,qBAAsB,SAAQ,KAAK;aAG5B,QAAQ,EAAE,WAAW;aACrB,MAAM,EAAE,mBAAmB,GAAG,kBAAkB;IAHlE,SAAkB,IAAI,2BAA2B;gBAE/B,QAAQ,EAAE,WAAW,EACrB,MAAM,EAAE,mBAAmB,GAAG,kBAAkB;CAQnE;AAOD,iFAAiF;AACjF,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI,CAEtE;AAED,mGAAmG;AACnG,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAOhD;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,sGAAsG;IACtG,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACpC,SAAS,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;CACnC;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,WAAW,EACrB,OAAO,EAAE,uBAAuB,GAC/B,kBAAkB,CAiBpB"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { LlmProviderSchema } from '@endora-commerce/contracts';
|
|
2
|
+
import { AnthropicAdapter } from './anthropic-adapter.js';
|
|
3
|
+
import { GoogleAdapter } from './google-adapter.js';
|
|
4
|
+
import { OpenAiAdapter } from './openai-adapter.js';
|
|
5
|
+
/**
|
|
6
|
+
* One factory for every consumer (feature 151, research R21): `prompt_actions`
|
|
7
|
+
* and `cms` resolve their own credential and hand the values in; which class
|
|
8
|
+
* speaks which protocol, and which endpoint a provider defaults to, is decided
|
|
9
|
+
* here once.
|
|
10
|
+
*/
|
|
11
|
+
/** Every provider code this package can call — `LlmProviderSchema`'s options. */
|
|
12
|
+
export const LLM_PROVIDERS = LlmProviderSchema.options;
|
|
13
|
+
/** A configuration no call could succeed with; consumers report it as "not configured". */
|
|
14
|
+
export class LlmConfigurationError extends Error {
|
|
15
|
+
provider;
|
|
16
|
+
reason;
|
|
17
|
+
name = 'LlmConfigurationError';
|
|
18
|
+
constructor(provider, reason) {
|
|
19
|
+
super(reason === 'base_url_required'
|
|
20
|
+
? `The ${provider} provider needs a Base URL.`
|
|
21
|
+
: `The ${provider} Base URL must be an absolute http or https URL.`);
|
|
22
|
+
this.provider = provider;
|
|
23
|
+
this.reason = reason;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const DEFAULT_BASE_URLS = {
|
|
27
|
+
openai: 'https://api.openai.com/v1',
|
|
28
|
+
deepseek: 'https://api.deepseek.com',
|
|
29
|
+
};
|
|
30
|
+
/** The endpoint an OpenAI-protocol provider uses with no Base URL, or `null`. */
|
|
31
|
+
export function defaultBaseUrlFor(provider) {
|
|
32
|
+
return DEFAULT_BASE_URLS[provider] ?? null;
|
|
33
|
+
}
|
|
34
|
+
/** `true` for an absolute `http:` / `https:` URL — the rule `credentials` applies on write too. */
|
|
35
|
+
export function isHttpUrl(value) {
|
|
36
|
+
try {
|
|
37
|
+
const url = new URL(value);
|
|
38
|
+
return url.protocol === 'http:' || url.protocol === 'https:';
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Build the adapter for `provider`. Throws `LlmConfigurationError` synchronously
|
|
46
|
+
* for an `openai_compatible` configuration without a Base URL and for a Base URL
|
|
47
|
+
* that is not an absolute http(s) URL, so the caller learns it before any call.
|
|
48
|
+
*/
|
|
49
|
+
export function createLlmAdapter(provider, options) {
|
|
50
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
51
|
+
if (provider === 'anthropic')
|
|
52
|
+
return new AnthropicAdapter(options.apiKey, fetchImpl);
|
|
53
|
+
if (provider === 'google')
|
|
54
|
+
return new GoogleAdapter(options.apiKey, fetchImpl);
|
|
55
|
+
const configured = options.baseUrl?.trim() ?? '';
|
|
56
|
+
if (configured !== '' && !isHttpUrl(configured)) {
|
|
57
|
+
throw new LlmConfigurationError(provider, 'base_url_invalid');
|
|
58
|
+
}
|
|
59
|
+
const baseUrl = configured !== '' ? configured : defaultBaseUrlFor(provider);
|
|
60
|
+
if (baseUrl === null)
|
|
61
|
+
throw new LlmConfigurationError(provider, 'base_url_required');
|
|
62
|
+
// `openai` with no Base URL passes none, so its endpoint is the adapter's own
|
|
63
|
+
// default and the request stays what it was before this factory existed.
|
|
64
|
+
return new OpenAiAdapter(options.apiKey, fetchImpl, {
|
|
65
|
+
provider,
|
|
66
|
+
...(provider === 'openai' && configured === '' ? {} : { baseUrl }),
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=create-llm-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-llm-adapter.js","sourceRoot":"","sources":["../src/create-llm-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGpD;;;;;GAKG;AAEH,iFAAiF;AACjF,MAAM,CAAC,MAAM,aAAa,GAA2B,iBAAiB,CAAC,OAAO,CAAC;AAE/E,2FAA2F;AAC3F,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IAG5B;IACA;IAHA,IAAI,GAAG,uBAAuB,CAAC;IACjD,YACkB,QAAqB,EACrB,MAAgD;QAEhE,KAAK,CACH,MAAM,KAAK,mBAAmB;YAC5B,CAAC,CAAC,OAAO,QAAQ,6BAA6B;YAC9C,CAAC,CAAC,OAAO,QAAQ,kDAAkD,CACtE,CAAC;QAPc,aAAQ,GAAR,QAAQ,CAAa;QACrB,WAAM,GAAN,MAAM,CAA0C;IAOlE,CAAC;CACF;AAED,MAAM,iBAAiB,GAAyC;IAC9D,MAAM,EAAE,2BAA2B;IACnC,QAAQ,EAAE,0BAA0B;CACrC,CAAC;AAEF,iFAAiF;AACjF,MAAM,UAAU,iBAAiB,CAAC,QAAqB;IACrD,OAAO,iBAAiB,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC;AAC7C,CAAC;AAED,mGAAmG;AACnG,MAAM,UAAU,SAAS,CAAC,KAAa;IACrC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;QAC3B,OAAO,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC;IAC/D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AASD;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAC9B,QAAqB,EACrB,OAAgC;IAEhC,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,KAAK,CAAC;IAC7C,IAAI,QAAQ,KAAK,WAAW;QAAE,OAAO,IAAI,gBAAgB,CAAC,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACrF,IAAI,QAAQ,KAAK,QAAQ;QAAE,OAAO,IAAI,aAAa,CAAC,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAE/E,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACjD,IAAI,UAAU,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,qBAAqB,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAAC;IAChE,CAAC;IACD,MAAM,OAAO,GAAG,UAAU,KAAK,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IAC7E,IAAI,OAAO,KAAK,IAAI;QAAE,MAAM,IAAI,qBAAqB,CAAC,QAAQ,EAAE,mBAAmB,CAAC,CAAC;IACrF,8EAA8E;IAC9E,yEAAyE;IACzE,OAAO,IAAI,aAAa,CAAC,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE;QAClD,QAAQ;QACR,GAAG,CAAC,QAAQ,KAAK,QAAQ,IAAI,UAAU,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC;KACnE,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type FetchLike, type LlmCompletion, type LlmProviderAdapter, type LlmRequest } from './provider.js';
|
|
2
|
+
export declare class GoogleAdapter implements LlmProviderAdapter {
|
|
3
|
+
private readonly apiKey;
|
|
4
|
+
private readonly fetchImpl;
|
|
5
|
+
readonly provider: "google";
|
|
6
|
+
constructor(apiKey: string, fetchImpl?: FetchLike);
|
|
7
|
+
complete(req: LlmRequest): Promise<LlmCompletion>;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=google-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google-adapter.d.ts","sourceRoot":"","sources":["../src/google-adapter.ts"],"names":[],"mappings":"AACA,OAAO,EAML,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,UAAU,EAChB,MAAM,eAAe,CAAC;AA4CvB,qBAAa,aAAc,YAAW,kBAAkB;IAIpD,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAJ5B,QAAQ,CAAC,QAAQ,EAAG,QAAQ,CAAU;gBAGnB,MAAM,EAAE,MAAM,EACd,SAAS,GAAE,SAAiB;IAGzC,QAAQ,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC;CA+FxD"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { fromWireName, parseOrThrow, postJson, toWireName, wireNameMap, } from './provider.js';
|
|
3
|
+
/**
|
|
4
|
+
* Google (Gemini) adapter — `POST :generateContent` with
|
|
5
|
+
* functionDeclarations / functionCall parts. Native fetch, no SDK
|
|
6
|
+
* (research §R2). Gemini returns no tool-call ids, so synthetic ids are
|
|
7
|
+
* minted per response; functionResponse parts are matched by name, which the
|
|
8
|
+
* API expects.
|
|
9
|
+
*/
|
|
10
|
+
const ResponseSchema = z.object({
|
|
11
|
+
candidates: z
|
|
12
|
+
.array(z.object({
|
|
13
|
+
content: z.object({
|
|
14
|
+
parts: z
|
|
15
|
+
.array(z.union([
|
|
16
|
+
z.object({ text: z.string() }),
|
|
17
|
+
z.object({
|
|
18
|
+
functionCall: z.object({ name: z.string(), args: z.unknown().optional() }),
|
|
19
|
+
}),
|
|
20
|
+
]))
|
|
21
|
+
.default([]),
|
|
22
|
+
}),
|
|
23
|
+
finishReason: z.string().optional(),
|
|
24
|
+
}))
|
|
25
|
+
.min(1),
|
|
26
|
+
});
|
|
27
|
+
/** Gemini's parameter schema is an OpenAPI subset — strip JSON-Schema-only keys. */
|
|
28
|
+
function sanitizeForGemini(schema) {
|
|
29
|
+
if (Array.isArray(schema))
|
|
30
|
+
return schema.map(sanitizeForGemini);
|
|
31
|
+
if (typeof schema !== 'object' || schema === null)
|
|
32
|
+
return schema;
|
|
33
|
+
const out = {};
|
|
34
|
+
for (const [k, v] of Object.entries(schema)) {
|
|
35
|
+
if (k === '$schema' || k === 'additionalProperties')
|
|
36
|
+
continue;
|
|
37
|
+
out[k] = sanitizeForGemini(v);
|
|
38
|
+
}
|
|
39
|
+
return out;
|
|
40
|
+
}
|
|
41
|
+
export class GoogleAdapter {
|
|
42
|
+
apiKey;
|
|
43
|
+
fetchImpl;
|
|
44
|
+
provider = 'google';
|
|
45
|
+
constructor(apiKey, fetchImpl = fetch) {
|
|
46
|
+
this.apiKey = apiKey;
|
|
47
|
+
this.fetchImpl = fetchImpl;
|
|
48
|
+
}
|
|
49
|
+
async complete(req) {
|
|
50
|
+
const names = wireNameMap(req.tools);
|
|
51
|
+
const body = {
|
|
52
|
+
systemInstruction: { parts: [{ text: req.system }] },
|
|
53
|
+
generationConfig: { maxOutputTokens: req.maxTokens },
|
|
54
|
+
tools: [
|
|
55
|
+
{
|
|
56
|
+
functionDeclarations: req.tools.map((t) => ({
|
|
57
|
+
name: toWireName(t.name),
|
|
58
|
+
description: t.description,
|
|
59
|
+
parameters: sanitizeForGemini(t.inputSchema),
|
|
60
|
+
})),
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
...(req.toolChoice
|
|
64
|
+
? {
|
|
65
|
+
toolConfig: {
|
|
66
|
+
functionCallingConfig: {
|
|
67
|
+
mode: 'ANY',
|
|
68
|
+
allowedFunctionNames: [toWireName(req.toolChoice.name)],
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
}
|
|
72
|
+
: {}),
|
|
73
|
+
contents: req.messages.map((m) => {
|
|
74
|
+
if (m.role === 'user')
|
|
75
|
+
return { role: 'user', parts: [{ text: m.text }] };
|
|
76
|
+
if (m.role === 'assistant') {
|
|
77
|
+
return {
|
|
78
|
+
role: 'model',
|
|
79
|
+
parts: [
|
|
80
|
+
...(m.text ? [{ text: m.text }] : []),
|
|
81
|
+
...m.toolCalls.map((c) => ({
|
|
82
|
+
functionCall: { name: toWireName(c.name), args: c.arguments ?? {} },
|
|
83
|
+
})),
|
|
84
|
+
],
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
let response;
|
|
88
|
+
try {
|
|
89
|
+
response = JSON.parse(m.resultJson);
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
response = { value: m.resultJson };
|
|
93
|
+
}
|
|
94
|
+
// functionResponse.response must be an object.
|
|
95
|
+
const wrapped = typeof response === 'object' && response !== null && !Array.isArray(response)
|
|
96
|
+
? response
|
|
97
|
+
: { value: response };
|
|
98
|
+
return {
|
|
99
|
+
role: 'user',
|
|
100
|
+
parts: [
|
|
101
|
+
{ functionResponse: { name: toWireName(m.toolName), response: wrapped } },
|
|
102
|
+
],
|
|
103
|
+
};
|
|
104
|
+
}),
|
|
105
|
+
};
|
|
106
|
+
const json = await postJson(this.provider, this.fetchImpl, `https://generativelanguage.googleapis.com/v1beta/models/${encodeURIComponent(req.model)}:generateContent`, { 'x-goog-api-key': this.apiKey }, body, req.signal);
|
|
107
|
+
const parsed = parseOrThrow(this.provider, ResponseSchema, json);
|
|
108
|
+
const candidate = parsed.candidates[0];
|
|
109
|
+
const texts = [];
|
|
110
|
+
const toolCalls = [];
|
|
111
|
+
candidate.content.parts.forEach((part, index) => {
|
|
112
|
+
if ('text' in part) {
|
|
113
|
+
texts.push(part.text);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
toolCalls.push({
|
|
117
|
+
id: `gcall_${index}_${part.functionCall.name}`,
|
|
118
|
+
name: fromWireName(part.functionCall.name, names),
|
|
119
|
+
arguments: part.functionCall.args ?? {},
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
return {
|
|
123
|
+
text: texts.length > 0 ? texts.join('\n') : null,
|
|
124
|
+
toolCalls,
|
|
125
|
+
stopReason: toolCalls.length > 0
|
|
126
|
+
? 'tool_use'
|
|
127
|
+
: candidate.finishReason === 'STOP'
|
|
128
|
+
? 'end'
|
|
129
|
+
: candidate.finishReason === 'MAX_TOKENS'
|
|
130
|
+
? 'max_tokens'
|
|
131
|
+
: 'other',
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=google-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google-adapter.js","sourceRoot":"","sources":["../src/google-adapter.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@endora-commerce/llm-client` — the platform's provider-neutral LLM transport
|
|
3
|
+
* (feature 151, research R2).
|
|
4
|
+
*
|
|
5
|
+
* Moved unchanged from `prompt_actions` so that a second module (the Page
|
|
6
|
+
* Builder translation in `cms`) can call the same three provider protocols
|
|
7
|
+
* without a module edge. Stateless: no settings, no credentials, no logging —
|
|
8
|
+
* each consumer resolves its own credential and passes the key in.
|
|
9
|
+
*/
|
|
10
|
+
export { LlmProviderError, fromWireName, toWireName, wireNameMap, type FetchLike, type LlmCompletion, type LlmMessage, type LlmProvider, type LlmProviderAdapter, type LlmRequest, type LlmToolCall, type LlmToolDefinition, } from './provider.js';
|
|
11
|
+
export { AnthropicAdapter } from './anthropic-adapter.js';
|
|
12
|
+
export { GoogleAdapter } from './google-adapter.js';
|
|
13
|
+
export { OpenAiAdapter } from './openai-adapter.js';
|
|
14
|
+
export type { OpenAiAdapterOptions, OpenAiProtocolProvider } from './openai-adapter.js';
|
|
15
|
+
export { LLM_PROVIDERS, LlmConfigurationError, createLlmAdapter, defaultBaseUrlFor, isHttpUrl, type CreateLlmAdapterOptions, } from './create-llm-adapter.js';
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,UAAU,EACV,WAAW,EACX,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACvB,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,iBAAiB,GACvB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,YAAY,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AACxF,OAAO,EACL,aAAa,EACb,qBAAqB,EACrB,gBAAgB,EAChB,iBAAiB,EACjB,SAAS,EACT,KAAK,uBAAuB,GAC7B,MAAM,yBAAyB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@endora-commerce/llm-client` — the platform's provider-neutral LLM transport
|
|
3
|
+
* (feature 151, research R2).
|
|
4
|
+
*
|
|
5
|
+
* Moved unchanged from `prompt_actions` so that a second module (the Page
|
|
6
|
+
* Builder translation in `cms`) can call the same three provider protocols
|
|
7
|
+
* without a module edge. Stateless: no settings, no credentials, no logging —
|
|
8
|
+
* each consumer resolves its own credential and passes the key in.
|
|
9
|
+
*/
|
|
10
|
+
export { LlmProviderError, fromWireName, toWireName, wireNameMap, } from './provider.js';
|
|
11
|
+
export { AnthropicAdapter } from './anthropic-adapter.js';
|
|
12
|
+
export { GoogleAdapter } from './google-adapter.js';
|
|
13
|
+
export { OpenAiAdapter } from './openai-adapter.js';
|
|
14
|
+
export { LLM_PROVIDERS, LlmConfigurationError, createLlmAdapter, defaultBaseUrlFor, isHttpUrl, } from './create-llm-adapter.js';
|
|
15
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,UAAU,EACV,WAAW,GASZ,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EACL,aAAa,EACb,qBAAqB,EACrB,gBAAgB,EAChB,iBAAiB,EACjB,SAAS,GAEV,MAAM,yBAAyB,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type FetchLike, type LlmCompletion, type LlmProviderAdapter, type LlmRequest } from './provider.js';
|
|
2
|
+
/** The providers that speak this protocol (feature 151, research R21). */
|
|
3
|
+
export type OpenAiProtocolProvider = 'openai' | 'deepseek' | 'openai_compatible';
|
|
4
|
+
export interface OpenAiAdapterOptions {
|
|
5
|
+
/** Whose endpoint this is; named in errors and `provider`. Default `openai`. */
|
|
6
|
+
provider?: OpenAiProtocolProvider | undefined;
|
|
7
|
+
/**
|
|
8
|
+
* The API root the request is posted under, as `<baseUrl>/chat/completions`.
|
|
9
|
+
* Default: OpenAI's public endpoint. Validated by `createLlmAdapter`, not here.
|
|
10
|
+
*/
|
|
11
|
+
baseUrl?: string | undefined;
|
|
12
|
+
}
|
|
13
|
+
export declare class OpenAiAdapter implements LlmProviderAdapter {
|
|
14
|
+
private readonly apiKey;
|
|
15
|
+
private readonly fetchImpl;
|
|
16
|
+
readonly provider: OpenAiProtocolProvider;
|
|
17
|
+
private readonly endpoint;
|
|
18
|
+
constructor(apiKey: string, fetchImpl?: FetchLike, options?: OpenAiAdapterOptions);
|
|
19
|
+
complete(req: LlmRequest): Promise<LlmCompletion>;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=openai-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-adapter.d.ts","sourceRoot":"","sources":["../src/openai-adapter.ts"],"names":[],"mappings":"AACA,OAAO,EAOL,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,UAAU,EAChB,MAAM,eAAe,CAAC;AA8BvB,0EAA0E;AAC1E,MAAM,MAAM,sBAAsB,GAAG,QAAQ,GAAG,UAAU,GAAG,mBAAmB,CAAC;AAEjF,MAAM,WAAW,oBAAoB;IACnC,gFAAgF;IAChF,QAAQ,CAAC,EAAE,sBAAsB,GAAG,SAAS,CAAC;IAC9C;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC9B;AAID,qBAAa,aAAc,YAAW,kBAAkB;IAKpD,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAL5B,QAAQ,CAAC,QAAQ,EAAE,sBAAsB,CAAC;IAC1C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAGf,MAAM,EAAE,MAAM,EACd,SAAS,GAAE,SAAiB,EAC7C,OAAO,GAAE,oBAAyB;IAM9B,QAAQ,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC;CAkFxD"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { LlmProviderError, fromWireName, parseOrThrow, postJson, toWireName, wireNameMap, } from './provider.js';
|
|
3
|
+
/**
|
|
4
|
+
* OpenAI (GPT) adapter — `POST /v1/chat/completions` with tools/tool_calls.
|
|
5
|
+
* Native fetch, no SDK (research §R2). Tool-call arguments arrive as a JSON
|
|
6
|
+
* string and are parsed here; the interpreter re-validates against the
|
|
7
|
+
* tool's Zod schema regardless.
|
|
8
|
+
*/
|
|
9
|
+
const ResponseSchema = z.object({
|
|
10
|
+
choices: z
|
|
11
|
+
.array(z.object({
|
|
12
|
+
message: z.object({
|
|
13
|
+
content: z.string().nullable().optional(),
|
|
14
|
+
tool_calls: z
|
|
15
|
+
.array(z.object({
|
|
16
|
+
id: z.string(),
|
|
17
|
+
function: z.object({ name: z.string(), arguments: z.string() }),
|
|
18
|
+
}))
|
|
19
|
+
.optional(),
|
|
20
|
+
}),
|
|
21
|
+
finish_reason: z.string().nullable().optional(),
|
|
22
|
+
}))
|
|
23
|
+
.min(1),
|
|
24
|
+
});
|
|
25
|
+
const OPENAI_BASE_URL = 'https://api.openai.com/v1';
|
|
26
|
+
export class OpenAiAdapter {
|
|
27
|
+
apiKey;
|
|
28
|
+
fetchImpl;
|
|
29
|
+
provider;
|
|
30
|
+
endpoint;
|
|
31
|
+
constructor(apiKey, fetchImpl = fetch, options = {}) {
|
|
32
|
+
this.apiKey = apiKey;
|
|
33
|
+
this.fetchImpl = fetchImpl;
|
|
34
|
+
this.provider = options.provider ?? 'openai';
|
|
35
|
+
this.endpoint = `${(options.baseUrl ?? OPENAI_BASE_URL).replace(/\/+$/, '')}/chat/completions`;
|
|
36
|
+
}
|
|
37
|
+
async complete(req) {
|
|
38
|
+
const names = wireNameMap(req.tools);
|
|
39
|
+
const body = {
|
|
40
|
+
model: req.model,
|
|
41
|
+
// OpenAI renamed the cap; DeepSeek and the compatible servers (vLLM,
|
|
42
|
+
// Ollama, OpenRouter, …) take the original name. `openai` keeps the
|
|
43
|
+
// field it has always sent.
|
|
44
|
+
...(this.provider === 'openai'
|
|
45
|
+
? { max_completion_tokens: req.maxTokens }
|
|
46
|
+
: { max_tokens: req.maxTokens }),
|
|
47
|
+
messages: [
|
|
48
|
+
{ role: 'system', content: req.system },
|
|
49
|
+
...req.messages.map((m) => {
|
|
50
|
+
if (m.role === 'user')
|
|
51
|
+
return { role: 'user', content: m.text };
|
|
52
|
+
if (m.role === 'assistant') {
|
|
53
|
+
return {
|
|
54
|
+
role: 'assistant',
|
|
55
|
+
content: m.text,
|
|
56
|
+
...(m.toolCalls.length > 0
|
|
57
|
+
? {
|
|
58
|
+
tool_calls: m.toolCalls.map((c) => ({
|
|
59
|
+
id: c.id,
|
|
60
|
+
type: 'function',
|
|
61
|
+
function: {
|
|
62
|
+
name: toWireName(c.name),
|
|
63
|
+
arguments: JSON.stringify(c.arguments),
|
|
64
|
+
},
|
|
65
|
+
})),
|
|
66
|
+
}
|
|
67
|
+
: {}),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
return { role: 'tool', tool_call_id: m.toolCallId, content: m.resultJson };
|
|
71
|
+
}),
|
|
72
|
+
],
|
|
73
|
+
tools: req.tools.map((t) => ({
|
|
74
|
+
type: 'function',
|
|
75
|
+
function: { name: toWireName(t.name), description: t.description, parameters: t.inputSchema },
|
|
76
|
+
})),
|
|
77
|
+
...(req.toolChoice
|
|
78
|
+
? { tool_choice: { type: 'function', function: { name: toWireName(req.toolChoice.name) } } }
|
|
79
|
+
: {}),
|
|
80
|
+
};
|
|
81
|
+
const json = await postJson(this.provider, this.fetchImpl, this.endpoint, { authorization: `Bearer ${this.apiKey}` }, body, req.signal);
|
|
82
|
+
const parsed = parseOrThrow(this.provider, ResponseSchema, json);
|
|
83
|
+
const choice = parsed.choices[0];
|
|
84
|
+
const toolCalls = (choice.message.tool_calls ?? []).map((c) => {
|
|
85
|
+
let args;
|
|
86
|
+
try {
|
|
87
|
+
args = JSON.parse(c.function.arguments);
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
throw new LlmProviderError(this.provider, 'malformed', `${this.provider} tool call "${c.function.name}" carried non-JSON arguments.`);
|
|
91
|
+
}
|
|
92
|
+
return { id: c.id, name: fromWireName(c.function.name, names), arguments: args };
|
|
93
|
+
});
|
|
94
|
+
return {
|
|
95
|
+
text: choice.message.content ?? null,
|
|
96
|
+
toolCalls,
|
|
97
|
+
stopReason: choice.finish_reason === 'tool_calls'
|
|
98
|
+
? 'tool_use'
|
|
99
|
+
: choice.finish_reason === 'stop'
|
|
100
|
+
? 'end'
|
|
101
|
+
: choice.finish_reason === 'length'
|
|
102
|
+
? 'max_tokens'
|
|
103
|
+
: 'other',
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=openai-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-adapter.js","sourceRoot":"","sources":["../src/openai-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { z } from 'zod';
|
|
2
|
+
import type { LlmProvider, LlmToolDefinition } from '@endora-commerce/contracts';
|
|
3
|
+
/**
|
|
4
|
+
* Provider-neutral LLM adapter contract (feature 043, research §R2).
|
|
5
|
+
*
|
|
6
|
+
* Three thin adapters (Anthropic / Google / OpenAI) speak the providers'
|
|
7
|
+
* native tool-calling REST APIs over injected `fetch` — no SDK dependency.
|
|
8
|
+
* Everything the interpreter consumes is normalized to this shape; provider
|
|
9
|
+
* responses are Zod-validated at the boundary (Principle V).
|
|
10
|
+
*/
|
|
11
|
+
export type { LlmProvider, LlmToolDefinition };
|
|
12
|
+
export type LlmMessage = {
|
|
13
|
+
role: 'user';
|
|
14
|
+
text: string;
|
|
15
|
+
} | {
|
|
16
|
+
role: 'assistant';
|
|
17
|
+
text: string | null;
|
|
18
|
+
toolCalls: LlmToolCall[];
|
|
19
|
+
} | {
|
|
20
|
+
role: 'tool_result';
|
|
21
|
+
toolCallId: string;
|
|
22
|
+
toolName: string;
|
|
23
|
+
resultJson: string;
|
|
24
|
+
};
|
|
25
|
+
export interface LlmToolCall {
|
|
26
|
+
id: string;
|
|
27
|
+
/** Dotted registry id, e.g. 'inventory.set_stock_level'. */
|
|
28
|
+
name: string;
|
|
29
|
+
arguments: unknown;
|
|
30
|
+
}
|
|
31
|
+
export interface LlmRequest {
|
|
32
|
+
model: string;
|
|
33
|
+
system: string;
|
|
34
|
+
messages: LlmMessage[];
|
|
35
|
+
tools: LlmToolDefinition[];
|
|
36
|
+
maxTokens: number;
|
|
37
|
+
/**
|
|
38
|
+
* Feature 151 (research R3) — forces the model to answer by calling this
|
|
39
|
+
* tool, mapped to each provider's native option. Absent ⇒ the provider's
|
|
40
|
+
* default (the model chooses), and the request body is exactly what it was
|
|
41
|
+
* before the option existed.
|
|
42
|
+
*/
|
|
43
|
+
toolChoice?: {
|
|
44
|
+
name: string;
|
|
45
|
+
};
|
|
46
|
+
/** Feature 151 — passed to `fetch`, so a caller can impose a timeout or cancel. */
|
|
47
|
+
signal?: AbortSignal;
|
|
48
|
+
}
|
|
49
|
+
export interface LlmCompletion {
|
|
50
|
+
text: string | null;
|
|
51
|
+
toolCalls: LlmToolCall[];
|
|
52
|
+
stopReason: 'tool_use' | 'end' | 'max_tokens' | 'other';
|
|
53
|
+
}
|
|
54
|
+
export interface LlmProviderAdapter {
|
|
55
|
+
readonly provider: LlmProvider;
|
|
56
|
+
complete(req: LlmRequest): Promise<LlmCompletion>;
|
|
57
|
+
}
|
|
58
|
+
export declare class LlmProviderError extends Error {
|
|
59
|
+
readonly provider: LlmProvider;
|
|
60
|
+
readonly kind: 'http' | 'network' | 'malformed';
|
|
61
|
+
readonly status?: number | undefined;
|
|
62
|
+
/** Feature 151 — `true` when a `network` failure was the request's `AbortSignal` firing. */
|
|
63
|
+
readonly aborted: boolean;
|
|
64
|
+
readonly name = "LlmProviderError";
|
|
65
|
+
constructor(provider: LlmProvider, kind: 'http' | 'network' | 'malformed', message: string, status?: number | undefined,
|
|
66
|
+
/** Feature 151 — `true` when a `network` failure was the request's `AbortSignal` firing. */
|
|
67
|
+
aborted?: boolean);
|
|
68
|
+
}
|
|
69
|
+
export type FetchLike = typeof fetch;
|
|
70
|
+
export declare function toWireName(id: string): string;
|
|
71
|
+
export declare function wireNameMap(tools: LlmToolDefinition[]): Map<string, string>;
|
|
72
|
+
export declare function fromWireName(wire: string, map: Map<string, string>): string;
|
|
73
|
+
/** Shared POST + JSON helper with uniform error mapping. */
|
|
74
|
+
export declare function postJson(provider: LlmProvider, fetchImpl: FetchLike, url: string, headers: Record<string, string>, body: unknown, signal?: AbortSignal): Promise<unknown>;
|
|
75
|
+
export declare function malformed(provider: LlmProvider, issues: unknown): LlmProviderError;
|
|
76
|
+
/** Boundary guard reused by adapters. */
|
|
77
|
+
export declare function parseOrThrow<T>(provider: LlmProvider, schema: z.ZodType<T>, value: unknown): T;
|
|
78
|
+
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"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"}
|
package/dist/provider.js
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
export class LlmProviderError extends Error {
|
|
2
|
+
provider;
|
|
3
|
+
kind;
|
|
4
|
+
status;
|
|
5
|
+
aborted;
|
|
6
|
+
name = 'LlmProviderError';
|
|
7
|
+
constructor(provider, kind, message, status,
|
|
8
|
+
/** Feature 151 — `true` when a `network` failure was the request's `AbortSignal` firing. */
|
|
9
|
+
aborted = false) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.provider = provider;
|
|
12
|
+
this.kind = kind;
|
|
13
|
+
this.status = status;
|
|
14
|
+
this.aborted = aborted;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
// Wire-name sanitization
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// Registry ids are dotted ('catalog.search_products') but Anthropic and
|
|
21
|
+
// OpenAI tool names must match ^[a-zA-Z0-9_-]{1,64}$. All adapters therefore
|
|
22
|
+
// send '__'-joined names and translate responses back through a per-request
|
|
23
|
+
// reverse map (never string surgery — ids may legitimately contain '_').
|
|
24
|
+
export function toWireName(id) {
|
|
25
|
+
return id.replace(/\./g, '__');
|
|
26
|
+
}
|
|
27
|
+
export function wireNameMap(tools) {
|
|
28
|
+
return new Map(tools.map((t) => [toWireName(t.name), t.name]));
|
|
29
|
+
}
|
|
30
|
+
export function fromWireName(wire, map) {
|
|
31
|
+
return map.get(wire) ?? wire;
|
|
32
|
+
}
|
|
33
|
+
/** Shared POST + JSON helper with uniform error mapping. */
|
|
34
|
+
export async function postJson(provider, fetchImpl, url, headers, body, signal) {
|
|
35
|
+
let response;
|
|
36
|
+
try {
|
|
37
|
+
response = await fetchImpl(url, {
|
|
38
|
+
method: 'POST',
|
|
39
|
+
headers: { 'content-type': 'application/json', ...headers },
|
|
40
|
+
body: JSON.stringify(body),
|
|
41
|
+
// Only when given, so a request without one is the same `init` as before.
|
|
42
|
+
...(signal ? { signal } : {}),
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
throw new LlmProviderError(provider, 'network', `Could not reach the ${provider} API: ${err.message}`, undefined, signal?.aborted === true);
|
|
47
|
+
}
|
|
48
|
+
let json = null;
|
|
49
|
+
try {
|
|
50
|
+
json = await response.json();
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// fall through — handled below
|
|
54
|
+
}
|
|
55
|
+
if (!response.ok) {
|
|
56
|
+
throw new LlmProviderError(provider, 'http', `${provider} API responded with HTTP ${response.status}.`, response.status);
|
|
57
|
+
}
|
|
58
|
+
if (json === null) {
|
|
59
|
+
throw new LlmProviderError(provider, 'malformed', `${provider} API returned a non-JSON body.`);
|
|
60
|
+
}
|
|
61
|
+
return json;
|
|
62
|
+
}
|
|
63
|
+
export function malformed(provider, issues) {
|
|
64
|
+
return new LlmProviderError(provider, 'malformed', `${provider} API response did not match the expected shape: ${JSON.stringify(issues).slice(0, 500)}`);
|
|
65
|
+
}
|
|
66
|
+
/** Boundary guard reused by adapters. */
|
|
67
|
+
export function parseOrThrow(provider, schema, value) {
|
|
68
|
+
const r = schema.safeParse(value);
|
|
69
|
+
if (!r.success)
|
|
70
|
+
throw malformed(provider, r.error.issues);
|
|
71
|
+
return r.data;
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,45 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@endora-commerce/llm-client",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"description": "
|
|
3
|
+
"version": "0.107.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Provider-neutral LLM transport — fetch-based Anthropic, Google and OpenAI (and OpenAI-compatible) adapters with tool calling, shared by the modules that call a language model.",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/endora-commerce/endora-commerce.git",
|
|
10
|
+
"directory": "packages/llm-client"
|
|
11
|
+
},
|
|
12
|
+
"publishConfig": {
|
|
13
|
+
"access": "public"
|
|
14
|
+
},
|
|
15
|
+
"main": "./dist/index.js",
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"default": "./dist/index.js"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist"
|
|
25
|
+
],
|
|
26
|
+
"sideEffects": false,
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=22.18.0"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"zod": "^4.2.0",
|
|
32
|
+
"@endora-commerce/contracts": "0.107.0"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@types/node": "^22.9.0",
|
|
36
|
+
"typescript": "^5.9.3",
|
|
37
|
+
"vitest": "^4.1.11"
|
|
38
|
+
},
|
|
39
|
+
"scripts": {
|
|
40
|
+
"build": "tsc -p tsconfig.build.json",
|
|
41
|
+
"typecheck": "tsc -p tsconfig.json",
|
|
42
|
+
"lint": "eslint src",
|
|
43
|
+
"test": "vitest run"
|
|
44
|
+
}
|
|
6
45
|
}
|