@uptimizr/agent-core 0.1.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/AGENTS.md +40 -0
- package/LICENSE +201 -0
- package/README.md +125 -0
- package/dist/client.d.ts +33 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +38 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/loop.d.ts +47 -0
- package/dist/loop.d.ts.map +1 -0
- package/dist/loop.js +84 -0
- package/dist/loop.js.map +1 -0
- package/dist/provider.d.ts +73 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +12 -0
- package/dist/provider.js.map +1 -0
- package/dist/providers/anthropic.d.ts +56 -0
- package/dist/providers/anthropic.d.ts.map +1 -0
- package/dist/providers/anthropic.js +75 -0
- package/dist/providers/anthropic.js.map +1 -0
- package/dist/providers/config.d.ts +74 -0
- package/dist/providers/config.d.ts.map +1 -0
- package/dist/providers/config.js +93 -0
- package/dist/providers/config.js.map +1 -0
- package/dist/providers/hosted.d.ts +50 -0
- package/dist/providers/hosted.d.ts.map +1 -0
- package/dist/providers/hosted.js +102 -0
- package/dist/providers/hosted.js.map +1 -0
- package/dist/providers/index.d.ts +16 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +16 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/openai.d.ts +53 -0
- package/dist/providers/openai.d.ts.map +1 -0
- package/dist/providers/openai.js +79 -0
- package/dist/providers/openai.js.map +1 -0
- package/dist/providers/webllm.d.ts +128 -0
- package/dist/providers/webllm.d.ts.map +1 -0
- package/dist/providers/webllm.js +158 -0
- package/dist/providers/webllm.js.map +1 -0
- package/dist/tools.d.ts +28 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +327 -0
- package/dist/tools.js.map +1 -0
- package/llms.txt +20 -0
- package/package.json +86 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Headless LLM provider-adapter interface for Uptimizr agents.
|
|
3
|
+
*
|
|
4
|
+
* The agent core is provider-agnostic: it hands a provider the running
|
|
5
|
+
* conversation plus the read-only tool schemas and receives back either tool
|
|
6
|
+
* calls to execute or a final natural-language answer. Concrete adapters
|
|
7
|
+
* (WebLLM/WebGPU, an OpenAI-compatible endpoint, an Anthropic endpoint, …) live
|
|
8
|
+
* outside this package and are user-selected and user-controlled — the core
|
|
9
|
+
* ships no model and no key (ADR 0050 §4).
|
|
10
|
+
*/
|
|
11
|
+
/** A single message in the agent conversation. */
|
|
12
|
+
export type AgentMessage = {
|
|
13
|
+
role: "system";
|
|
14
|
+
content: string;
|
|
15
|
+
} | {
|
|
16
|
+
role: "user";
|
|
17
|
+
content: string;
|
|
18
|
+
} | {
|
|
19
|
+
role: "assistant";
|
|
20
|
+
content: string;
|
|
21
|
+
toolCalls?: AgentToolCall[];
|
|
22
|
+
} | {
|
|
23
|
+
role: "tool";
|
|
24
|
+
toolCallId: string;
|
|
25
|
+
name: string;
|
|
26
|
+
content: string;
|
|
27
|
+
};
|
|
28
|
+
/** A tool invocation requested by the model. */
|
|
29
|
+
export interface AgentToolCall {
|
|
30
|
+
/** Provider-assigned id, echoed back on the matching tool result message. */
|
|
31
|
+
id: string;
|
|
32
|
+
/** Name of the tool to invoke (must match a catalog tool). */
|
|
33
|
+
name: string;
|
|
34
|
+
/** Arguments for the tool, validated against the tool's input schema. */
|
|
35
|
+
arguments: Record<string, unknown>;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* A tool advertised to the model: its name, a short description, and a
|
|
39
|
+
* JSON-Schema description of its parameters (derived from the catalog's Zod
|
|
40
|
+
* shapes, see {@link toToolSchemas}).
|
|
41
|
+
*/
|
|
42
|
+
export interface AgentToolSchema {
|
|
43
|
+
name: string;
|
|
44
|
+
description: string;
|
|
45
|
+
parameters: Record<string, unknown>;
|
|
46
|
+
}
|
|
47
|
+
/** The two possible outcomes of a provider turn. */
|
|
48
|
+
export type ProviderResponse = {
|
|
49
|
+
kind: "tool_calls";
|
|
50
|
+
toolCalls: AgentToolCall[];
|
|
51
|
+
content?: string;
|
|
52
|
+
} | {
|
|
53
|
+
kind: "final";
|
|
54
|
+
content: string;
|
|
55
|
+
};
|
|
56
|
+
/** A single provider completion request. */
|
|
57
|
+
export interface ProviderRequest {
|
|
58
|
+
/** The conversation so far (system + user + prior assistant/tool turns). */
|
|
59
|
+
messages: AgentMessage[];
|
|
60
|
+
/** The read-only tools the model may call this turn. */
|
|
61
|
+
tools: AgentToolSchema[];
|
|
62
|
+
/** Optional cancellation signal, forwarded by the loop. */
|
|
63
|
+
signal?: AbortSignal;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* A pluggable LLM backend. Implementations translate {@link ProviderRequest}
|
|
67
|
+
* into their own wire format and normalise the reply into a
|
|
68
|
+
* {@link ProviderResponse}.
|
|
69
|
+
*/
|
|
70
|
+
export interface LlmProvider {
|
|
71
|
+
complete(request: ProviderRequest): Promise<ProviderResponse>;
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,kDAAkD;AAClD,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,aAAa,EAAE,CAAA;CAAE,GACnE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAExE,gDAAgD;AAChD,MAAM,WAAW,aAAa;IAC5B,6EAA6E;IAC7E,EAAE,EAAE,MAAM,CAAC;IACX,8DAA8D;IAC9D,IAAI,EAAE,MAAM,CAAC;IACb,yEAAyE;IACzE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAED,oDAAoD;AACpD,MAAM,MAAM,gBAAgB,GACxB;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,SAAS,EAAE,aAAa,EAAE,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GACpE;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvC,4CAA4C;AAC5C,MAAM,WAAW,eAAe;IAC9B,4EAA4E;IAC5E,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,wDAAwD;IACxD,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,2DAA2D;IAC3D,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;CAC/D"}
|
package/dist/provider.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Headless LLM provider-adapter interface for Uptimizr agents.
|
|
3
|
+
*
|
|
4
|
+
* The agent core is provider-agnostic: it hands a provider the running
|
|
5
|
+
* conversation plus the read-only tool schemas and receives back either tool
|
|
6
|
+
* calls to execute or a final natural-language answer. Concrete adapters
|
|
7
|
+
* (WebLLM/WebGPU, an OpenAI-compatible endpoint, an Anthropic endpoint, …) live
|
|
8
|
+
* outside this package and are user-selected and user-controlled — the core
|
|
9
|
+
* ships no model and no key (ADR 0050 §4).
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure translation between the agent-core conversation shape and the Anthropic
|
|
3
|
+
* Messages API wire format. No I/O, no dependencies — the hosted adapter owns
|
|
4
|
+
* the actual `fetch`. Anthropic differs from OpenAI in three ways this module
|
|
5
|
+
* hides: the system prompt is a top-level field (not a message), tool calls are
|
|
6
|
+
* `tool_use` content blocks, and tool results are `tool_result` blocks carried
|
|
7
|
+
* in a following user turn.
|
|
8
|
+
*/
|
|
9
|
+
import type { AgentMessage, AgentToolSchema, ProviderResponse } from "../provider.js";
|
|
10
|
+
/** An Anthropic content block (the subset used here). */
|
|
11
|
+
export type AnthropicContentBlock = {
|
|
12
|
+
type: "text";
|
|
13
|
+
text: string;
|
|
14
|
+
} | {
|
|
15
|
+
type: "tool_use";
|
|
16
|
+
id: string;
|
|
17
|
+
name: string;
|
|
18
|
+
input: Record<string, unknown>;
|
|
19
|
+
} | {
|
|
20
|
+
type: "tool_result";
|
|
21
|
+
tool_use_id: string;
|
|
22
|
+
content: string;
|
|
23
|
+
};
|
|
24
|
+
/** An Anthropic request message. */
|
|
25
|
+
export interface AnthropicMessage {
|
|
26
|
+
role: "user" | "assistant";
|
|
27
|
+
content: AnthropicContentBlock[];
|
|
28
|
+
}
|
|
29
|
+
/** An Anthropic tool advertisement. */
|
|
30
|
+
export interface AnthropicTool {
|
|
31
|
+
name: string;
|
|
32
|
+
description: string;
|
|
33
|
+
input_schema: Record<string, unknown>;
|
|
34
|
+
}
|
|
35
|
+
/** The parts of an Anthropic request this module builds. */
|
|
36
|
+
export interface AnthropicRequestBody {
|
|
37
|
+
system?: string;
|
|
38
|
+
messages: AnthropicMessage[];
|
|
39
|
+
tools: AnthropicTool[];
|
|
40
|
+
}
|
|
41
|
+
/** The subset of an Anthropic Messages response this module reads. */
|
|
42
|
+
export interface AnthropicCompletion {
|
|
43
|
+
content?: AnthropicContentBlock[];
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Build the Anthropic request pieces (system prompt, messages, tools) from the
|
|
47
|
+
* agent conversation and tool schemas.
|
|
48
|
+
*/
|
|
49
|
+
export declare function toAnthropicRequest(messages: readonly AgentMessage[], tools: readonly AgentToolSchema[]): AnthropicRequestBody;
|
|
50
|
+
/**
|
|
51
|
+
* Normalise an Anthropic Messages response into a {@link ProviderResponse}.
|
|
52
|
+
* Any `tool_use` blocks become tool calls; otherwise the joined text blocks are
|
|
53
|
+
* the final answer.
|
|
54
|
+
*/
|
|
55
|
+
export declare function parseAnthropicCompletion(completion: AnthropicCompletion): ProviderResponse;
|
|
56
|
+
//# sourceMappingURL=anthropic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../src/providers/anthropic.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EACV,YAAY,EAEZ,eAAe,EACf,gBAAgB,EACjB,MAAM,gBAAgB,CAAC;AAExB,yDAAyD;AACzD,MAAM,MAAM,qBAAqB,GAC7B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAC9E;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAElE,oCAAoC;AACpC,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAC3B,OAAO,EAAE,qBAAqB,EAAE,CAAC;CAClC;AAED,uCAAuC;AACvC,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACvC;AAED,4DAA4D;AAC5D,MAAM,WAAW,oBAAoB;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,KAAK,EAAE,aAAa,EAAE,CAAC;CACxB;AAED,sEAAsE;AACtE,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,EAAE,qBAAqB,EAAE,CAAC;CACnC;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,SAAS,YAAY,EAAE,EACjC,KAAK,EAAE,SAAS,eAAe,EAAE,GAChC,oBAAoB,CAuCtB;AAMD;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,mBAAmB,GAAG,gBAAgB,CAc1F"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure translation between the agent-core conversation shape and the Anthropic
|
|
3
|
+
* Messages API wire format. No I/O, no dependencies — the hosted adapter owns
|
|
4
|
+
* the actual `fetch`. Anthropic differs from OpenAI in three ways this module
|
|
5
|
+
* hides: the system prompt is a top-level field (not a message), tool calls are
|
|
6
|
+
* `tool_use` content blocks, and tool results are `tool_result` blocks carried
|
|
7
|
+
* in a following user turn.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Build the Anthropic request pieces (system prompt, messages, tools) from the
|
|
11
|
+
* agent conversation and tool schemas.
|
|
12
|
+
*/
|
|
13
|
+
export function toAnthropicRequest(messages, tools) {
|
|
14
|
+
const systemParts = [];
|
|
15
|
+
const out = [];
|
|
16
|
+
for (const message of messages) {
|
|
17
|
+
switch (message.role) {
|
|
18
|
+
case "system":
|
|
19
|
+
systemParts.push(message.content);
|
|
20
|
+
break;
|
|
21
|
+
case "user":
|
|
22
|
+
out.push({ role: "user", content: [{ type: "text", text: message.content }] });
|
|
23
|
+
break;
|
|
24
|
+
case "assistant": {
|
|
25
|
+
const blocks = [];
|
|
26
|
+
if (message.content)
|
|
27
|
+
blocks.push({ type: "text", text: message.content });
|
|
28
|
+
for (const call of message.toolCalls ?? [])
|
|
29
|
+
blocks.push(toToolUse(call));
|
|
30
|
+
out.push({ role: "assistant", content: blocks });
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
case "tool":
|
|
34
|
+
out.push({
|
|
35
|
+
role: "user",
|
|
36
|
+
content: [
|
|
37
|
+
{ type: "tool_result", tool_use_id: message.toolCallId, content: message.content },
|
|
38
|
+
],
|
|
39
|
+
});
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
...(systemParts.length > 0 ? { system: systemParts.join("\n\n") } : {}),
|
|
45
|
+
messages: out,
|
|
46
|
+
tools: tools.map((tool) => ({
|
|
47
|
+
name: tool.name,
|
|
48
|
+
description: tool.description,
|
|
49
|
+
input_schema: tool.parameters,
|
|
50
|
+
})),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function toToolUse(call) {
|
|
54
|
+
return { type: "tool_use", id: call.id, name: call.name, input: call.arguments ?? {} };
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Normalise an Anthropic Messages response into a {@link ProviderResponse}.
|
|
58
|
+
* Any `tool_use` blocks become tool calls; otherwise the joined text blocks are
|
|
59
|
+
* the final answer.
|
|
60
|
+
*/
|
|
61
|
+
export function parseAnthropicCompletion(completion) {
|
|
62
|
+
const blocks = completion.content ?? [];
|
|
63
|
+
const toolCalls = blocks
|
|
64
|
+
.filter((b) => b.type === "tool_use")
|
|
65
|
+
.map((b) => ({ id: b.id, name: b.name, arguments: b.input ?? {} }));
|
|
66
|
+
const text = blocks
|
|
67
|
+
.filter((b) => b.type === "text")
|
|
68
|
+
.map((b) => b.text)
|
|
69
|
+
.join("");
|
|
70
|
+
if (toolCalls.length > 0) {
|
|
71
|
+
return { kind: "tool_calls", toolCalls, ...(text ? { content: text } : {}) };
|
|
72
|
+
}
|
|
73
|
+
return { kind: "final", content: text };
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=anthropic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../src/providers/anthropic.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User-controlled backend selection and its browser persistence (ADR 0050 §4).
|
|
3
|
+
*
|
|
4
|
+
* The assistant ships no model and no key: the user picks a backend and the
|
|
5
|
+
* choice persists per-user in `localStorage`. Nothing here talks to a network —
|
|
6
|
+
* it only records which backend the user chose and the parameters needed to
|
|
7
|
+
* construct the matching provider adapter. Everything is injectable and
|
|
8
|
+
* SSR/Node-safe so the same module runs in the browser, in tests, and during a
|
|
9
|
+
* static export where `localStorage`/`navigator` may be absent.
|
|
10
|
+
*/
|
|
11
|
+
/** The two user-controlled backends (ADR 0050 §4). */
|
|
12
|
+
export type BackendKind = "local" | "hosted";
|
|
13
|
+
/** Wire format of a bring-your-own hosted provider. */
|
|
14
|
+
export type HostedApi = "openai" | "anthropic";
|
|
15
|
+
/** Persisted parameters for the local (WebLLM/WebGPU) backend. */
|
|
16
|
+
export interface WebLlmBackendConfig {
|
|
17
|
+
/** Curated model id to load (see `CURATED_MODELS`). */
|
|
18
|
+
model: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Persisted parameters for a bring-your-own hosted backend. The key and
|
|
22
|
+
* endpoint live only in the user's browser and are sent only to the user's own
|
|
23
|
+
* provider (ADR 0050 §5).
|
|
24
|
+
*/
|
|
25
|
+
export interface HostedBackendConfig {
|
|
26
|
+
/** Which wire format the endpoint speaks. */
|
|
27
|
+
api: HostedApi;
|
|
28
|
+
/** Base URL of the user's provider (e.g. https://api.openai.com/v1). */
|
|
29
|
+
endpoint: string;
|
|
30
|
+
/** The user's provider API key, stored in-browser only. */
|
|
31
|
+
apiKey: string;
|
|
32
|
+
/** Model identifier to request from the provider. */
|
|
33
|
+
model: string;
|
|
34
|
+
}
|
|
35
|
+
/** The persisted assistant backend selection. */
|
|
36
|
+
export interface AssistantBackendConfig {
|
|
37
|
+
/** Which backend the user selected. */
|
|
38
|
+
backend: BackendKind;
|
|
39
|
+
/** Local backend parameters (present when `backend === "local"`). */
|
|
40
|
+
webllm?: WebLlmBackendConfig;
|
|
41
|
+
/** Hosted backend parameters (present when `backend === "hosted"`). */
|
|
42
|
+
hosted?: HostedBackendConfig;
|
|
43
|
+
}
|
|
44
|
+
/** The `localStorage` key the selection is stored under. */
|
|
45
|
+
export declare const BACKEND_CONFIG_STORAGE_KEY = "uptimizr.assistant.backend";
|
|
46
|
+
/** The minimal `localStorage`-like surface this module needs. */
|
|
47
|
+
export interface KeyValueStorage {
|
|
48
|
+
getItem(key: string): string | null;
|
|
49
|
+
setItem(key: string, value: string): void;
|
|
50
|
+
removeItem(key: string): void;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Feature-detect WebGPU. The local backend is only offered when this returns
|
|
54
|
+
* `true`; callers should hide/disable the local option otherwise (ADR 0050 §4).
|
|
55
|
+
*/
|
|
56
|
+
export declare function isWebGpuAvailable(nav?: Navigator | undefined): boolean;
|
|
57
|
+
/**
|
|
58
|
+
* The privacy-preserving default backend: local (zero egress) when WebGPU is
|
|
59
|
+
* present, otherwise hosted (ADR 0050 §4/§5).
|
|
60
|
+
*/
|
|
61
|
+
export declare function defaultBackendKind(nav?: Navigator): BackendKind;
|
|
62
|
+
/**
|
|
63
|
+
* Load the persisted backend selection, or `null` when nothing is stored (or
|
|
64
|
+
* storage is unavailable / corrupt). Corrupt entries are treated as absent.
|
|
65
|
+
*/
|
|
66
|
+
export declare function loadBackendConfig(storage?: KeyValueStorage | undefined): AssistantBackendConfig | null;
|
|
67
|
+
/**
|
|
68
|
+
* Persist the backend selection. No-op when storage is unavailable so callers
|
|
69
|
+
* don't have to guard SSR/Node.
|
|
70
|
+
*/
|
|
71
|
+
export declare function saveBackendConfig(config: AssistantBackendConfig, storage?: KeyValueStorage | undefined): void;
|
|
72
|
+
/** Clear any persisted backend selection. */
|
|
73
|
+
export declare function clearBackendConfig(storage?: KeyValueStorage | undefined): void;
|
|
74
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/providers/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,sDAAsD;AACtD,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,QAAQ,CAAC;AAE7C,uDAAuD;AACvD,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,WAAW,CAAC;AAE/C,kEAAkE;AAClE,MAAM,WAAW,mBAAmB;IAClC,uDAAuD;IACvD,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,6CAA6C;IAC7C,GAAG,EAAE,SAAS,CAAC;IACf,wEAAwE;IACxE,QAAQ,EAAE,MAAM,CAAC;IACjB,2DAA2D;IAC3D,MAAM,EAAE,MAAM,CAAC;IACf,qDAAqD;IACrD,KAAK,EAAE,MAAM,CAAC;CACf;AAED,iDAAiD;AACjD,MAAM,WAAW,sBAAsB;IACrC,uCAAuC;IACvC,OAAO,EAAE,WAAW,CAAC;IACrB,qEAAqE;IACrE,MAAM,CAAC,EAAE,mBAAmB,CAAC;IAC7B,uEAAuE;IACvE,MAAM,CAAC,EAAE,mBAAmB,CAAC;CAC9B;AAED,4DAA4D;AAC5D,eAAO,MAAM,0BAA0B,+BAA+B,CAAC;AAEvE,iEAAiE;AACjE,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACpC,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1C,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAWD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,GAAE,SAAS,GAAG,SAAgC,GAAG,OAAO,CAE5F;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,CAAC,EAAE,SAAS,GAAG,WAAW,CAE/D;AAMD;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,GAAE,eAAe,GAAG,SAA4B,GACtD,sBAAsB,GAAG,IAAI,CAkB/B;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,sBAAsB,EAC9B,OAAO,GAAE,eAAe,GAAG,SAA4B,GACtD,IAAI,CAON;AAED,6CAA6C;AAC7C,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,eAAe,GAAG,SAA4B,GAAG,IAAI,CAOhG"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User-controlled backend selection and its browser persistence (ADR 0050 §4).
|
|
3
|
+
*
|
|
4
|
+
* The assistant ships no model and no key: the user picks a backend and the
|
|
5
|
+
* choice persists per-user in `localStorage`. Nothing here talks to a network —
|
|
6
|
+
* it only records which backend the user chose and the parameters needed to
|
|
7
|
+
* construct the matching provider adapter. Everything is injectable and
|
|
8
|
+
* SSR/Node-safe so the same module runs in the browser, in tests, and during a
|
|
9
|
+
* static export where `localStorage`/`navigator` may be absent.
|
|
10
|
+
*/
|
|
11
|
+
/** The `localStorage` key the selection is stored under. */
|
|
12
|
+
export const BACKEND_CONFIG_STORAGE_KEY = "uptimizr.assistant.backend";
|
|
13
|
+
function defaultStorage() {
|
|
14
|
+
try {
|
|
15
|
+
return globalThis.localStorage;
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
// Accessing localStorage can throw in sandboxed iframes / disabled storage.
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Feature-detect WebGPU. The local backend is only offered when this returns
|
|
24
|
+
* `true`; callers should hide/disable the local option otherwise (ADR 0050 §4).
|
|
25
|
+
*/
|
|
26
|
+
export function isWebGpuAvailable(nav = globalThis.navigator) {
|
|
27
|
+
return Boolean(nav && "gpu" in nav && nav.gpu);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The privacy-preserving default backend: local (zero egress) when WebGPU is
|
|
31
|
+
* present, otherwise hosted (ADR 0050 §4/§5).
|
|
32
|
+
*/
|
|
33
|
+
export function defaultBackendKind(nav) {
|
|
34
|
+
return isWebGpuAvailable(nav) ? "local" : "hosted";
|
|
35
|
+
}
|
|
36
|
+
function isBackendKind(value) {
|
|
37
|
+
return value === "local" || value === "hosted";
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Load the persisted backend selection, or `null` when nothing is stored (or
|
|
41
|
+
* storage is unavailable / corrupt). Corrupt entries are treated as absent.
|
|
42
|
+
*/
|
|
43
|
+
export function loadBackendConfig(storage = defaultStorage()) {
|
|
44
|
+
if (!storage)
|
|
45
|
+
return null;
|
|
46
|
+
let raw;
|
|
47
|
+
try {
|
|
48
|
+
raw = storage.getItem(BACKEND_CONFIG_STORAGE_KEY);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
if (!raw)
|
|
54
|
+
return null;
|
|
55
|
+
try {
|
|
56
|
+
const parsed = JSON.parse(raw);
|
|
57
|
+
if (!parsed || typeof parsed !== "object")
|
|
58
|
+
return null;
|
|
59
|
+
const backend = parsed.backend;
|
|
60
|
+
if (!isBackendKind(backend))
|
|
61
|
+
return null;
|
|
62
|
+
return parsed;
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Persist the backend selection. No-op when storage is unavailable so callers
|
|
70
|
+
* don't have to guard SSR/Node.
|
|
71
|
+
*/
|
|
72
|
+
export function saveBackendConfig(config, storage = defaultStorage()) {
|
|
73
|
+
if (!storage)
|
|
74
|
+
return;
|
|
75
|
+
try {
|
|
76
|
+
storage.setItem(BACKEND_CONFIG_STORAGE_KEY, JSON.stringify(config));
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
// Ignore quota/security errors — persistence is best-effort.
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/** Clear any persisted backend selection. */
|
|
83
|
+
export function clearBackendConfig(storage = defaultStorage()) {
|
|
84
|
+
if (!storage)
|
|
85
|
+
return;
|
|
86
|
+
try {
|
|
87
|
+
storage.removeItem(BACKEND_CONFIG_STORAGE_KEY);
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
// Ignore.
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/providers/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAwCH,4DAA4D;AAC5D,MAAM,CAAC,MAAM,0BAA0B,GAAG,4BAA4B,CAAC;AASvE,SAAS,cAAc;IACrB,IAAI,CAAC;QACH,OAAQ,UAAiD,CAAC,YAAY,CAAC;IACzE,CAAC;IAAC,MAAM,CAAC;QACP,4EAA4E;QAC5E,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAA6B,UAAU,CAAC,SAAS;IACjF,OAAO,OAAO,CAAC,GAAG,IAAI,KAAK,IAAI,GAAG,IAAK,GAAyB,CAAC,GAAG,CAAC,CAAC;AACxE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAe;IAChD,OAAO,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC;AACrD,CAAC;AAED,SAAS,aAAa,CAAC,KAAc;IACnC,OAAO,KAAK,KAAK,OAAO,IAAI,KAAK,KAAK,QAAQ,CAAC;AACjD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAC/B,UAAuC,cAAc,EAAE;IAEvD,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAC1B,IAAI,GAAkB,CAAC;IACvB,IAAI,CAAC;QACH,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,0BAA0B,CAAC,CAAC;IACpD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAY,CAAC;QAC1C,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;QACvD,MAAM,OAAO,GAAI,MAAgC,CAAC,OAAO,CAAC;QAC1D,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC;YAAE,OAAO,IAAI,CAAC;QACzC,OAAO,MAAgC,CAAC;IAC1C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAC/B,MAA8B,EAC9B,UAAuC,cAAc,EAAE;IAEvD,IAAI,CAAC,OAAO;QAAE,OAAO;IACrB,IAAI,CAAC;QACH,OAAO,CAAC,OAAO,CAAC,0BAA0B,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;IACtE,CAAC;IAAC,MAAM,CAAC;QACP,6DAA6D;IAC/D,CAAC;AACH,CAAC;AAED,6CAA6C;AAC7C,MAAM,UAAU,kBAAkB,CAAC,UAAuC,cAAc,EAAE;IACxF,IAAI,CAAC,OAAO;QAAE,OAAO;IACrB,IAAI,CAAC;QACH,OAAO,CAAC,UAAU,CAAC,0BAA0B,CAAC,CAAC;IACjD,CAAC;IAAC,MAAM,CAAC;QACP,UAAU;IACZ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bring-your-own hosted LLM adapter (ADR 0050 §4/§5).
|
|
3
|
+
*
|
|
4
|
+
* The user supplies an OpenAI-compatible **or** Anthropic endpoint + key, stored
|
|
5
|
+
* only in their browser. The browser calls the user's own provider directly —
|
|
6
|
+
* Uptimizr operates no proxy. Only the prompt and the aggregated tool results
|
|
7
|
+
* the loop produces leave the browser (never raw events or PII), and only to the
|
|
8
|
+
* user's chosen provider after explicit opt-in.
|
|
9
|
+
*
|
|
10
|
+
* Both providers require CORS to be reachable from a browser:
|
|
11
|
+
* - OpenAI-compatible: the endpoint must send permissive `Access-Control-*`
|
|
12
|
+
* headers (some gateways/self-hosted servers do; api.openai.com does not).
|
|
13
|
+
* - Anthropic: pass the `anthropic-dangerous-direct-browser-access` header
|
|
14
|
+
* (added below) which enables their browser CORS path.
|
|
15
|
+
* See the docs (guides/assistant) for the exact requirements.
|
|
16
|
+
*/
|
|
17
|
+
import type { LlmProvider } from "../provider.js";
|
|
18
|
+
import type { HostedApi } from "./config.js";
|
|
19
|
+
/** Configuration for a bring-your-own hosted provider. */
|
|
20
|
+
export interface HostedProviderConfig {
|
|
21
|
+
/** Which wire format the endpoint speaks. */
|
|
22
|
+
api: HostedApi;
|
|
23
|
+
/**
|
|
24
|
+
* Base URL of the user's provider. The provider appends the well-known path
|
|
25
|
+
* (`/chat/completions` or `/messages`) if the URL doesn't already end in it.
|
|
26
|
+
*/
|
|
27
|
+
endpoint: string;
|
|
28
|
+
/** The user's provider API key (in-browser only). */
|
|
29
|
+
apiKey: string;
|
|
30
|
+
/** Model identifier to request. */
|
|
31
|
+
model: string;
|
|
32
|
+
/** Max tokens to generate (Anthropic requires it; default 1024). */
|
|
33
|
+
maxTokens?: number;
|
|
34
|
+
/** Anthropic API version header (default "2023-06-01"). */
|
|
35
|
+
anthropicVersion?: string;
|
|
36
|
+
/** Injectable fetch for testing; defaults to the global `fetch`. */
|
|
37
|
+
fetchImpl?: typeof fetch;
|
|
38
|
+
}
|
|
39
|
+
/** Thrown when the user's provider responds with a non-2xx status. */
|
|
40
|
+
export declare class HostedProviderError extends Error {
|
|
41
|
+
readonly status: number;
|
|
42
|
+
constructor(message: string, status: number);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Create a hosted provider bound to one `(api, endpoint, apiKey, model)`. The
|
|
46
|
+
* returned {@link LlmProvider} issues one direct request per turn to the user's
|
|
47
|
+
* provider and normalises the reply.
|
|
48
|
+
*/
|
|
49
|
+
export declare function createHostedProvider(config: HostedProviderConfig): LlmProvider;
|
|
50
|
+
//# sourceMappingURL=hosted.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hosted.d.ts","sourceRoot":"","sources":["../../src/providers/hosted.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAqC,MAAM,gBAAgB,CAAC;AACrF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAa7C,0DAA0D;AAC1D,MAAM,WAAW,oBAAoB;IACnC,6CAA6C;IAC7C,GAAG,EAAE,SAAS,CAAC;IACf;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC;IACf,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2DAA2D;IAC3D,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,oEAAoE;IACpE,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AAED,sEAAsE;AACtE,qBAAa,mBAAoB,SAAQ,KAAK;IAG1C,QAAQ,CAAC,MAAM,EAAE,MAAM;gBADvB,OAAO,EAAE,MAAM,EACN,MAAM,EAAE,MAAM;CAK1B;AAYD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,oBAAoB,GAAG,WAAW,CAS9E"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bring-your-own hosted LLM adapter (ADR 0050 §4/§5).
|
|
3
|
+
*
|
|
4
|
+
* The user supplies an OpenAI-compatible **or** Anthropic endpoint + key, stored
|
|
5
|
+
* only in their browser. The browser calls the user's own provider directly —
|
|
6
|
+
* Uptimizr operates no proxy. Only the prompt and the aggregated tool results
|
|
7
|
+
* the loop produces leave the browser (never raw events or PII), and only to the
|
|
8
|
+
* user's chosen provider after explicit opt-in.
|
|
9
|
+
*
|
|
10
|
+
* Both providers require CORS to be reachable from a browser:
|
|
11
|
+
* - OpenAI-compatible: the endpoint must send permissive `Access-Control-*`
|
|
12
|
+
* headers (some gateways/self-hosted servers do; api.openai.com does not).
|
|
13
|
+
* - Anthropic: pass the `anthropic-dangerous-direct-browser-access` header
|
|
14
|
+
* (added below) which enables their browser CORS path.
|
|
15
|
+
* See the docs (guides/assistant) for the exact requirements.
|
|
16
|
+
*/
|
|
17
|
+
import { parseOpenAiCompletion, toOpenAiMessages, toOpenAiTools, } from "./openai.js";
|
|
18
|
+
import { parseAnthropicCompletion, toAnthropicRequest, } from "./anthropic.js";
|
|
19
|
+
/** Thrown when the user's provider responds with a non-2xx status. */
|
|
20
|
+
export class HostedProviderError extends Error {
|
|
21
|
+
status;
|
|
22
|
+
constructor(message, status) {
|
|
23
|
+
super(message);
|
|
24
|
+
this.status = status;
|
|
25
|
+
this.name = "HostedProviderError";
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const DEFAULT_MAX_TOKENS = 1024;
|
|
29
|
+
const DEFAULT_ANTHROPIC_VERSION = "2023-06-01";
|
|
30
|
+
function joinUrl(base, suffix) {
|
|
31
|
+
let end = base.length;
|
|
32
|
+
while (end > 0 && base[end - 1] === "/")
|
|
33
|
+
end--;
|
|
34
|
+
const trimmed = base.slice(0, end);
|
|
35
|
+
return trimmed.endsWith(suffix) ? trimmed : `${trimmed}${suffix}`;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Create a hosted provider bound to one `(api, endpoint, apiKey, model)`. The
|
|
39
|
+
* returned {@link LlmProvider} issues one direct request per turn to the user's
|
|
40
|
+
* provider and normalises the reply.
|
|
41
|
+
*/
|
|
42
|
+
export function createHostedProvider(config) {
|
|
43
|
+
const fetchImpl = config.fetchImpl ?? fetch;
|
|
44
|
+
return {
|
|
45
|
+
complete(request) {
|
|
46
|
+
return config.api === "anthropic"
|
|
47
|
+
? completeAnthropic(config, fetchImpl, request)
|
|
48
|
+
: completeOpenAi(config, fetchImpl, request);
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
async function completeOpenAi(config, fetchImpl, request) {
|
|
53
|
+
const url = joinUrl(config.endpoint, "/chat/completions");
|
|
54
|
+
const body = {
|
|
55
|
+
model: config.model,
|
|
56
|
+
messages: toOpenAiMessages(request.messages),
|
|
57
|
+
tools: toOpenAiTools(request.tools),
|
|
58
|
+
tool_choice: "auto",
|
|
59
|
+
};
|
|
60
|
+
const res = await fetchImpl(url, {
|
|
61
|
+
method: "POST",
|
|
62
|
+
headers: {
|
|
63
|
+
"content-type": "application/json",
|
|
64
|
+
authorization: `Bearer ${config.apiKey}`,
|
|
65
|
+
},
|
|
66
|
+
body: JSON.stringify(body),
|
|
67
|
+
signal: request.signal,
|
|
68
|
+
});
|
|
69
|
+
const completion = (await readJson(res));
|
|
70
|
+
return parseOpenAiCompletion(completion);
|
|
71
|
+
}
|
|
72
|
+
async function completeAnthropic(config, fetchImpl, request) {
|
|
73
|
+
const url = joinUrl(config.endpoint, "/messages");
|
|
74
|
+
const shaped = toAnthropicRequest(request.messages, request.tools);
|
|
75
|
+
const body = {
|
|
76
|
+
model: config.model,
|
|
77
|
+
max_tokens: config.maxTokens ?? DEFAULT_MAX_TOKENS,
|
|
78
|
+
...shaped,
|
|
79
|
+
};
|
|
80
|
+
const res = await fetchImpl(url, {
|
|
81
|
+
method: "POST",
|
|
82
|
+
headers: {
|
|
83
|
+
"content-type": "application/json",
|
|
84
|
+
"x-api-key": config.apiKey,
|
|
85
|
+
"anthropic-version": config.anthropicVersion ?? DEFAULT_ANTHROPIC_VERSION,
|
|
86
|
+
// Enables Anthropic's browser CORS path for direct client-side calls.
|
|
87
|
+
"anthropic-dangerous-direct-browser-access": "true",
|
|
88
|
+
},
|
|
89
|
+
body: JSON.stringify(body),
|
|
90
|
+
signal: request.signal,
|
|
91
|
+
});
|
|
92
|
+
const completion = (await readJson(res));
|
|
93
|
+
return parseAnthropicCompletion(completion);
|
|
94
|
+
}
|
|
95
|
+
async function readJson(res) {
|
|
96
|
+
if (!res.ok) {
|
|
97
|
+
const detail = await res.text().catch(() => "");
|
|
98
|
+
throw new HostedProviderError(detail || res.statusText, res.status);
|
|
99
|
+
}
|
|
100
|
+
return res.json();
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=hosted.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hosted.js","sourceRoot":"","sources":["../../src/providers/hosted.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User-controlled LLM provider adapters for `@uptimizr/agent-core` (ADR 0050 §4).
|
|
3
|
+
*
|
|
4
|
+
* Import from the specific subpaths to keep the local runtime code-split:
|
|
5
|
+
* - `@uptimizr/agent-core/providers/webllm` — local WebGPU backend
|
|
6
|
+
* - `@uptimizr/agent-core/providers/hosted` — bring-your-own hosted backend
|
|
7
|
+
*
|
|
8
|
+
* This barrel re-exports both plus the shared backend-selection/persistence
|
|
9
|
+
* helpers for consumers who want everything from one entry point. Importing the
|
|
10
|
+
* barrel pulls in the WebLLM adapter *module* (small), but never the heavy
|
|
11
|
+
* `@mlc-ai/web-llm` runtime — that still loads lazily on first use.
|
|
12
|
+
*/
|
|
13
|
+
export { type AssistantBackendConfig, type BackendKind, type HostedApi, type HostedBackendConfig, type KeyValueStorage, type WebLlmBackendConfig, BACKEND_CONFIG_STORAGE_KEY, clearBackendConfig, defaultBackendKind, isWebGpuAvailable, loadBackendConfig, saveBackendConfig, } from "./config.js";
|
|
14
|
+
export { type HostedProviderConfig, HostedProviderError, createHostedProvider } from "./hosted.js";
|
|
15
|
+
export { type CuratedModel, type InitProgress, type WebLlmEngine, type WebLlmProvider, type WebLlmProviderOptions, type WebLlmRuntime, CURATED_MODELS, SUPPORTED_TOOL_CALLING_MODELS, UnsupportedToolCallingModelError, WebGpuUnavailableError, WebLlmConsentError, createWebLlmProvider, } from "./webllm.js";
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/providers/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EACL,KAAK,sBAAsB,EAC3B,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,mBAAmB,EACxB,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,0BAA0B,EAC1B,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,KAAK,oBAAoB,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAEnG,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC1B,KAAK,aAAa,EAClB,cAAc,EACd,6BAA6B,EAC7B,gCAAgC,EAChC,sBAAsB,EACtB,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User-controlled LLM provider adapters for `@uptimizr/agent-core` (ADR 0050 §4).
|
|
3
|
+
*
|
|
4
|
+
* Import from the specific subpaths to keep the local runtime code-split:
|
|
5
|
+
* - `@uptimizr/agent-core/providers/webllm` — local WebGPU backend
|
|
6
|
+
* - `@uptimizr/agent-core/providers/hosted` — bring-your-own hosted backend
|
|
7
|
+
*
|
|
8
|
+
* This barrel re-exports both plus the shared backend-selection/persistence
|
|
9
|
+
* helpers for consumers who want everything from one entry point. Importing the
|
|
10
|
+
* barrel pulls in the WebLLM adapter *module* (small), but never the heavy
|
|
11
|
+
* `@mlc-ai/web-llm` runtime — that still loads lazily on first use.
|
|
12
|
+
*/
|
|
13
|
+
export { BACKEND_CONFIG_STORAGE_KEY, clearBackendConfig, defaultBackendKind, isWebGpuAvailable, loadBackendConfig, saveBackendConfig, } from "./config.js";
|
|
14
|
+
export { HostedProviderError, createHostedProvider } from "./hosted.js";
|
|
15
|
+
export { CURATED_MODELS, SUPPORTED_TOOL_CALLING_MODELS, UnsupportedToolCallingModelError, WebGpuUnavailableError, WebLlmConsentError, createWebLlmProvider, } from "./webllm.js";
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/providers/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAOL,0BAA0B,EAC1B,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,aAAa,CAAC;AAErB,OAAO,EAA6B,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAEnG,OAAO,EAOL,cAAc,EACd,6BAA6B,EAC7B,gCAAgC,EAChC,sBAAsB,EACtB,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,aAAa,CAAC"}
|