akanjs 3.0.0-beta.13 → 3.0.0-beta.14
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/dictionary/agent.dictionary.ts +4 -11
- package/local/apps/serverLifecycle/serverLifecycle-local.db-shm +0 -0
- package/local/apps/serverLifecycle/serverLifecycle-local_solid.db-shm +0 -0
- package/package.json +1 -1
- package/server/akanOption.ts +9 -2
- package/server/di/predefinedAdaptor.ts +2 -2
- package/service/predefinedAdaptor/anthropicLlm.ts +6 -4
- package/service/predefinedAdaptor/index.ts +0 -1
- package/service/predefinedAdaptor/llm.adaptor.ts +21 -1
- package/service/predefinedAdaptor/openaiLlm.ts +37 -18
- package/types/dictionary/agent.dictionary.d.ts +1 -1
- package/types/dictionary/dictionary.d.ts +3 -3
- package/types/server/akanOption.d.ts +9 -2
- package/types/server/di/predefinedAdaptor.d.ts +2 -2
- package/types/service/predefinedAdaptor/anthropicLlm.d.ts +1 -1
- package/types/service/predefinedAdaptor/index.d.ts +0 -1
- package/types/service/predefinedAdaptor/llm.adaptor.d.ts +14 -1
- package/types/service/predefinedAdaptor/openaiLlm.d.ts +20 -11
- package/service/predefinedAdaptor/deepseekLlm.ts +0 -82
- package/types/service/predefinedAdaptor/deepseekLlm.d.ts +0 -19
|
@@ -24,16 +24,9 @@ export const agentDictionary = serviceDictionary(["en", "ko"])
|
|
|
24
24
|
"The agent is unavailable — this app has no language model configured",
|
|
25
25
|
"에이전트를 사용할 수 없습니다. 이 앱에 언어 모델이 설정되어 있지 않습니다",
|
|
26
26
|
],
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
"
|
|
30
|
-
|
|
31
|
-
openaiRequestFailed: [
|
|
32
|
-
"OpenAI refused this turn with status {status}. Reason: {reason}",
|
|
33
|
-
"OpenAI가 이번 턴을 거절했습니다 (status {status}). 사유: {reason}",
|
|
34
|
-
],
|
|
35
|
-
anthropicRequestFailed: [
|
|
36
|
-
"Anthropic refused this turn with status {status}. Reason: {reason}",
|
|
37
|
-
"Anthropic이 이번 턴을 거절했습니다 (status {status}). 사유: {reason}",
|
|
27
|
+
|
|
28
|
+
llmRequestFailed: [
|
|
29
|
+
"{provider} refused this turn with status {status}. Reason: {reason}",
|
|
30
|
+
"{provider}가 이번 턴을 거절했습니다 (status {status}). 사유: {reason}",
|
|
38
31
|
],
|
|
39
32
|
});
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
package/server/akanOption.ts
CHANGED
|
@@ -73,8 +73,15 @@ export class AkanOption<Env extends BackendEnv = BackendEnv> {
|
|
|
73
73
|
this.#crossSite = crossSite;
|
|
74
74
|
return this;
|
|
75
75
|
}
|
|
76
|
-
/**
|
|
77
|
-
|
|
76
|
+
/**
|
|
77
|
+
* Settings for whichever adaptor fills `LlmAdaptorRole`, injected into it as the `llmOption` use.
|
|
78
|
+
*
|
|
79
|
+
* The argument is generic so that whatever an adaptor needs beyond `LlmOption` travels here too: an adaptor an
|
|
80
|
+
* app or a library wrote declares its own interface extending it, reads it with `use<MyLlmOption>()`, and its
|
|
81
|
+
* region or project id rides the same channel the shipped fields do. Entries merge in mount order with the
|
|
82
|
+
* app's last, so a library may name a host and the app the key.
|
|
83
|
+
*/
|
|
84
|
+
setLlm<Option extends LlmOption>(llmOrFn: Option | ((env: Env) => Option)) {
|
|
78
85
|
if (typeof llmOrFn === "function") this.#getLlms.push(llmOrFn);
|
|
79
86
|
else this.#getLlms.push(() => llmOrFn);
|
|
80
87
|
return this;
|
|
@@ -10,13 +10,13 @@ import {
|
|
|
10
10
|
ConsoleLogger,
|
|
11
11
|
type DatabaseAdaptor,
|
|
12
12
|
DatabaseAdaptorRole,
|
|
13
|
-
DeepseekLlm,
|
|
14
13
|
JsonCompressor,
|
|
15
14
|
LibsqlDatabase,
|
|
16
15
|
type LlmAdaptor,
|
|
17
16
|
LlmAdaptorRole,
|
|
18
17
|
type LoggingAdaptor,
|
|
19
18
|
LoggingAdaptorRole,
|
|
19
|
+
OpenaiLlm,
|
|
20
20
|
PostgresDatabase,
|
|
21
21
|
type QueueAdaptor,
|
|
22
22
|
QueueAdaptorRole,
|
|
@@ -68,7 +68,7 @@ export const predefinedAdaptor = {
|
|
|
68
68
|
logging: ConsoleLogger,
|
|
69
69
|
websocket: SolidPubSub,
|
|
70
70
|
compress: JsonCompressor,
|
|
71
|
-
llm:
|
|
71
|
+
llm: OpenaiLlm,
|
|
72
72
|
};
|
|
73
73
|
|
|
74
74
|
export const getPredefinedAdaptor = (mode: DatabaseMode = "single"): PredefinedAdaptor => {
|
|
@@ -9,6 +9,7 @@ import type {
|
|
|
9
9
|
LlmTurnAnswer,
|
|
10
10
|
LlmTurnRequest,
|
|
11
11
|
} from "./llm.adaptor";
|
|
12
|
+
import { llmProviderOf } from "./llm.adaptor";
|
|
12
13
|
|
|
13
14
|
type AnthropicSource = { type: "base64"; media_type: string; data: string } | { type: "url"; url: string };
|
|
14
15
|
type AnthropicBlock =
|
|
@@ -136,7 +137,7 @@ export class AnthropicLlm
|
|
|
136
137
|
|
|
137
138
|
signal: AbortSignal.timeout(120_000),
|
|
138
139
|
});
|
|
139
|
-
if (!response.ok) throw await AnthropicLlm.refusal(response);
|
|
140
|
+
if (!response.ok) throw await AnthropicLlm.refusal(this.#host, response);
|
|
140
141
|
return (await response.json()) as T;
|
|
141
142
|
}
|
|
142
143
|
|
|
@@ -147,12 +148,13 @@ export class AnthropicLlm
|
|
|
147
148
|
body: JSON.stringify(body),
|
|
148
149
|
signal: AbortSignal.timeout(120_000),
|
|
149
150
|
});
|
|
150
|
-
if (!response.ok || !response.body) throw await AnthropicLlm.refusal(response);
|
|
151
|
+
if (!response.ok || !response.body) throw await AnthropicLlm.refusal(this.#host, response);
|
|
151
152
|
return response.body;
|
|
152
153
|
}
|
|
153
154
|
|
|
154
|
-
static async refusal(response: Response): Promise<Error> {
|
|
155
|
-
return new Err("agent.error.
|
|
155
|
+
static async refusal(host: string, response: Response): Promise<Error> {
|
|
156
|
+
return new Err("agent.error.llmRequestFailed", {
|
|
157
|
+
provider: llmProviderOf(host),
|
|
156
158
|
status: String(response.status),
|
|
157
159
|
reason: await AnthropicLlm.reasonOf(response),
|
|
158
160
|
});
|
|
@@ -2,7 +2,6 @@ export * from "./anthropicLlm";
|
|
|
2
2
|
export * from "./cache.adaptor";
|
|
3
3
|
export * from "./compress.adaptor";
|
|
4
4
|
export * from "./database.adaptor";
|
|
5
|
-
export * from "./deepseekLlm";
|
|
6
5
|
export * from "./insightQuery";
|
|
7
6
|
export * from "./llm.adaptor";
|
|
8
7
|
export * from "./logging.adaptor";
|
|
@@ -131,7 +131,12 @@ export interface LlmAccepts {
|
|
|
131
131
|
/**
|
|
132
132
|
* Settings for whichever adaptor fills `LlmAdaptorRole`, registered with `option.setLlm(...)` and injected as the
|
|
133
133
|
* `llmOption` use. It belongs to the role rather than to one provider: swapping the default for another `adapt()`
|
|
134
|
-
* class re-reads the same
|
|
134
|
+
* class re-reads the same fields under that provider's own defaults.
|
|
135
|
+
*
|
|
136
|
+
* It is the floor, not the whole shape. `setLlm` keeps whatever else it is handed, so an adaptor an app or a
|
|
137
|
+
* library wrote declares its own interface extending this one and reads it with `use<MyLlmOption>()` — a region,
|
|
138
|
+
* a project id, a deployment name reach it through the same channel the fields below do, instead of a second
|
|
139
|
+
* `option.use({...})` key beside it.
|
|
135
140
|
*/
|
|
136
141
|
export interface LlmOption {
|
|
137
142
|
apiKey?: string;
|
|
@@ -156,3 +161,18 @@ export interface LlmOption {
|
|
|
156
161
|
*/
|
|
157
162
|
maxTokens?: number;
|
|
158
163
|
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* What the chat prints as the party that refused a turn, carried on `agent.error.llmRequestFailed`.
|
|
167
|
+
*
|
|
168
|
+
* It is the host rather than the adaptor's own name because one adaptor speaks one dialect to whatever host it
|
|
169
|
+
* is pointed at — an OpenAI-dialect class aimed at a gateway would otherwise credit OpenAI for that gateway's
|
|
170
|
+
* refusal. A host that is not a URL is printed as written; there is nothing better to say about it.
|
|
171
|
+
*/
|
|
172
|
+
export const llmProviderOf = (host: string): string => {
|
|
173
|
+
try {
|
|
174
|
+
return new URL(host).hostname;
|
|
175
|
+
} catch {
|
|
176
|
+
return host;
|
|
177
|
+
}
|
|
178
|
+
};
|
|
@@ -1,18 +1,27 @@
|
|
|
1
1
|
import { Err } from "akanjs/dictionary";
|
|
2
2
|
import { adapt } from "../adapt";
|
|
3
|
-
import
|
|
3
|
+
import {
|
|
4
|
+
type LlmAccepts,
|
|
5
|
+
type LlmAdaptor,
|
|
6
|
+
type LlmOption,
|
|
7
|
+
type LlmTurnAnswer,
|
|
8
|
+
type LlmTurnRequest,
|
|
9
|
+
llmProviderOf,
|
|
10
|
+
} from "./llm.adaptor";
|
|
4
11
|
import { type OpenaiAnswer, OpenaiDialect } from "./openaiDialect";
|
|
5
12
|
|
|
6
13
|
/**
|
|
7
|
-
* OpenAI
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
14
|
+
* The OpenAI chat-completions dialect, pointed at a host — and the framework's default fill for `LlmAdaptorRole`.
|
|
15
|
+
*
|
|
16
|
+
* One class rather than one per vendor: DeepSeek, Groq, Together, OpenRouter, Ollama and a self-hosted vLLM all
|
|
17
|
+
* serve this same wire, so what distinguishes them is `option.setLlm({ host, model })` and not a protocol. A
|
|
18
|
+
* provider that speaks its own wire — Anthropic's blocks, Bedrock's signed requests — is a different adaptor
|
|
19
|
+
* class, in this package or in the app's own `srvkit/`, applied with
|
|
20
|
+
* `option.applyAdaptor(LlmAdaptorRole, TheClass)`.
|
|
11
21
|
*
|
|
12
22
|
* `model` is required and has no default. A default would be a model name that ages out of the provider's
|
|
13
|
-
* catalogue into a 404 at the first turn, and — worse
|
|
14
|
-
*
|
|
15
|
-
* `accepts: { image: false }` beside it when that model is one of the provider's text-only ones.
|
|
23
|
+
* catalogue into a 404 at the first turn, and — worse — it would decide the vision claim below on the app's
|
|
24
|
+
* behalf.
|
|
16
25
|
*/
|
|
17
26
|
export class OpenaiLlm
|
|
18
27
|
extends adapt("openaiLlm" as const, ({ use }) => ({
|
|
@@ -20,13 +29,22 @@ export class OpenaiLlm
|
|
|
20
29
|
}))
|
|
21
30
|
implements LlmAdaptor
|
|
22
31
|
{
|
|
32
|
+
static readonly defaultHost = "https://api.openai.com/v1";
|
|
33
|
+
|
|
23
34
|
get #host() {
|
|
24
|
-
return this.llmOption.host ??
|
|
35
|
+
return this.llmOption.host ?? OpenaiLlm.defaultHost;
|
|
25
36
|
}
|
|
26
37
|
|
|
27
|
-
/**
|
|
28
|
-
|
|
29
|
-
|
|
38
|
+
/**
|
|
39
|
+
* OpenAI's own endpoint takes image parts, so that is what is claimed for the default host. A host the app
|
|
40
|
+
* named is a gateway this class knows nothing about, and claiming vision for one is the worst guess available:
|
|
41
|
+
* the bytes reach a model that cannot decode them and the whole turn dies on a 400, where text-only degrades
|
|
42
|
+
* them to a note the model can repeat back. So a named host is text-only until `option.setLlm({ accepts })`
|
|
43
|
+
* says otherwise — as is the OpenAI model that reads no image.
|
|
44
|
+
*/
|
|
45
|
+
get accepts(): LlmAccepts | undefined {
|
|
46
|
+
if (this.llmOption.accepts) return this.llmOption.accepts;
|
|
47
|
+
return this.llmOption.host ? undefined : { image: true };
|
|
30
48
|
}
|
|
31
49
|
|
|
32
50
|
async chat(request: LlmTurnRequest, onDelta?: (delta: string) => void): Promise<LlmTurnAnswer | null> {
|
|
@@ -52,8 +70,8 @@ export class OpenaiLlm
|
|
|
52
70
|
);
|
|
53
71
|
return await OpenaiDialect.consumeStream(body, onDelta);
|
|
54
72
|
} catch (error) {
|
|
55
|
-
|
|
56
|
-
this.logger.error(`
|
|
73
|
+
|
|
74
|
+
this.logger.error(`LLM turn failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
57
75
|
throw error;
|
|
58
76
|
}
|
|
59
77
|
}
|
|
@@ -66,7 +84,7 @@ export class OpenaiLlm
|
|
|
66
84
|
|
|
67
85
|
signal: AbortSignal.timeout(120_000),
|
|
68
86
|
});
|
|
69
|
-
if (!response.ok) throw await OpenaiLlm.refusal(response);
|
|
87
|
+
if (!response.ok) throw await OpenaiLlm.refusal(this.#host, response);
|
|
70
88
|
return (await response.json()) as T;
|
|
71
89
|
}
|
|
72
90
|
|
|
@@ -77,13 +95,14 @@ export class OpenaiLlm
|
|
|
77
95
|
body: JSON.stringify(body),
|
|
78
96
|
signal: AbortSignal.timeout(120_000),
|
|
79
97
|
});
|
|
80
|
-
if (!response.ok || !response.body) throw await OpenaiLlm.refusal(response);
|
|
98
|
+
if (!response.ok || !response.body) throw await OpenaiLlm.refusal(this.#host, response);
|
|
81
99
|
return response.body;
|
|
82
100
|
}
|
|
83
101
|
|
|
84
102
|
/** Carried on the `Err` so the chat prints the provider's own sentence rather than a status number. */
|
|
85
|
-
static async refusal(response: Response): Promise<Error> {
|
|
86
|
-
return new Err("agent.error.
|
|
103
|
+
static async refusal(host: string, response: Response): Promise<Error> {
|
|
104
|
+
return new Err("agent.error.llmRequestFailed", {
|
|
105
|
+
provider: llmProviderOf(host),
|
|
87
106
|
status: String(response.status),
|
|
88
107
|
reason: await OpenaiDialect.reasonOf(response),
|
|
89
108
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const agentDictionary: import("./dictInfo.d.ts").ServiceDictInfo<[string, string], "runAgentTurn", "llmUnavailable" | "
|
|
1
|
+
export declare const agentDictionary: import("./dictInfo.d.ts").ServiceDictInfo<[string, string], "runAgentTurn", "llmUnavailable" | "llmRequestFailed", never>;
|
|
@@ -2,12 +2,12 @@ import type { AgentEndpoint, AgentTurn, BaseEndpoint } from "akanjs/signal";
|
|
|
2
2
|
export declare const dictionary: {
|
|
3
3
|
base: import("./locale.d.ts").DictModule<import("./locale.d.ts").ServiceTranslatorKey<"base", BaseEndpoint, "error" | "remove" | "unauthorized" | "save" | "refresh" | "password" | "skip" | "stop" | "send" | "ok" | "agent" | "success" | "somethingWrong" | "connecting" | "connected" | "serverDisconnected" | "refreshing" | "tryReconnecting" | "serverHasProblem" | "checkServerStatus" | "cameraPromptHeader" | "cameraPromptPhoto" | "cameraPromptPicture" | "cameraPromptCancel" | "failed" | "processing" | "processed" | "noData" | "invalidValueError" | "emailInvalidError" | "phoneInvalidError" | "cancel" | "agentIntro" | "agentPlaceholder" | "agentClear" | "agentQuestion" | "agentAnswer" | "agentListen" | "agentVoiceFailed" | "agentAttach" | "agentAttachRemove" | "agentAttachReading" | "agentReferenceRemove" | "agentReferenceFailed" | "agentAttachTooLarge" | "agentAttachUnsupported" | "agentAttachDuplicate" | "agentAttachTooMany" | "agentAttachTooMuch" | "agentAnswerNeeded" | "agentQueue" | "agentQueuePlaceholder" | "agentQueued" | "agentQueueEdit" | "agentQueueCancel" | "agentToolDone" | "agentToolFailed" | "agentToolRunning" | "agentToolResult" | "agentTokens" | "agentSummarizing" | "agentContinue" | "agentKeepGoing" | "agentCmdNew" | "agentCmdRetry" | "agentCmdCompact" | "agentCmdCopy" | "agentCmdHelp" | "agentCmdTools" | "agentHelpIntro" | "agentHelpNote" | "agentNothingToRetry" | "agentNothingToCompact" | "agentCompacted" | "agentSummary" | "agentBusy" | "agentCopied" | "agentCopyFailed" | "agentToolsHead" | "agentToolsState" | "approve" | "decline" | "confirmClose" | "textTooShortError" | "textTooLongError" | "selectTooShortError" | "selectTooLongError" | "numberTooSmallError" | "numberTooBigError" | "passwordNotMatchError" | "selectDateError" | "priceUnit" | "passwordConfirm" | "noOptions" | "noSelection" | "addModel" | "createModel" | "createSuccess" | "updateModel" | "removeModel" | "updateSuccess" | "removeSuccess" | "sureToRemove" | "irreversibleOps" | "typeNameToRemove" | "yesRemove" | "removeMsg" | "confirmMsg" | "perPage" | "cardView" | "tableView" | "exportCsv" | "exportJson" | "actions" | "draftConflict" | "draftApplied" | "draftRestore" | "draftDiscard" | "draftStartOver" | "new" | "edit" | "view">, "base.error.gatewayTimeout" | "base.error.serverUnavailable" | "base.error.serverUnreachable" | "base.error.unexpectedResponse">;
|
|
4
4
|
agentTurn: import("./locale.d.ts").DictModule<import("./locale.d.ts").ScalarTranslatorKey<"agentTurn", AgentTurn, never> | `agentStop.${string}` | `agentStop.${string}.desc`, never>;
|
|
5
|
-
agent: import("./locale.d.ts").DictModule<import("./locale.d.ts").ServiceTranslatorKey<"agent", AgentEndpoint, never>, "agent.error.llmUnavailable" | "agent.error.
|
|
5
|
+
agent: import("./locale.d.ts").DictModule<import("./locale.d.ts").ServiceTranslatorKey<"agent", AgentEndpoint, never>, "agent.error.llmUnavailable" | "agent.error.llmRequestFailed">;
|
|
6
6
|
};
|
|
7
|
-
export declare const Err: import("./trans.d.ts").ErrConstructor<"base.error.gatewayTimeout" | "base.error.serverUnavailable" | "base.error.serverUnreachable" | "base.error.unexpectedResponse" | "agent.error.llmUnavailable" | "agent.error.
|
|
7
|
+
export declare const Err: import("./trans.d.ts").ErrConstructor<"base.error.gatewayTimeout" | "base.error.serverUnavailable" | "base.error.serverUnreachable" | "base.error.unexpectedResponse" | "agent.error.llmUnavailable" | "agent.error.llmRequestFailed">, translate: (lang: "en" | "ko" | (string & {}) | "zhChs" | "zhCht" | "ja", key: import("./locale.d.ts").ServiceTranslatorKey<"base", BaseEndpoint, "error" | "remove" | "unauthorized" | "save" | "refresh" | "password" | "skip" | "stop" | "send" | "ok" | "agent" | "success" | "somethingWrong" | "connecting" | "connected" | "serverDisconnected" | "refreshing" | "tryReconnecting" | "serverHasProblem" | "checkServerStatus" | "cameraPromptHeader" | "cameraPromptPhoto" | "cameraPromptPicture" | "cameraPromptCancel" | "failed" | "processing" | "processed" | "noData" | "invalidValueError" | "emailInvalidError" | "phoneInvalidError" | "cancel" | "agentIntro" | "agentPlaceholder" | "agentClear" | "agentQuestion" | "agentAnswer" | "agentListen" | "agentVoiceFailed" | "agentAttach" | "agentAttachRemove" | "agentAttachReading" | "agentReferenceRemove" | "agentReferenceFailed" | "agentAttachTooLarge" | "agentAttachUnsupported" | "agentAttachDuplicate" | "agentAttachTooMany" | "agentAttachTooMuch" | "agentAnswerNeeded" | "agentQueue" | "agentQueuePlaceholder" | "agentQueued" | "agentQueueEdit" | "agentQueueCancel" | "agentToolDone" | "agentToolFailed" | "agentToolRunning" | "agentToolResult" | "agentTokens" | "agentSummarizing" | "agentContinue" | "agentKeepGoing" | "agentCmdNew" | "agentCmdRetry" | "agentCmdCompact" | "agentCmdCopy" | "agentCmdHelp" | "agentCmdTools" | "agentHelpIntro" | "agentHelpNote" | "agentNothingToRetry" | "agentNothingToCompact" | "agentCompacted" | "agentSummary" | "agentBusy" | "agentCopied" | "agentCopyFailed" | "agentToolsHead" | "agentToolsState" | "approve" | "decline" | "confirmClose" | "textTooShortError" | "textTooLongError" | "selectTooShortError" | "selectTooLongError" | "numberTooSmallError" | "numberTooBigError" | "passwordNotMatchError" | "selectDateError" | "priceUnit" | "passwordConfirm" | "noOptions" | "noSelection" | "addModel" | "createModel" | "createSuccess" | "updateModel" | "removeModel" | "updateSuccess" | "removeSuccess" | "sureToRemove" | "irreversibleOps" | "typeNameToRemove" | "yesRemove" | "removeMsg" | "confirmMsg" | "perPage" | "cardView" | "tableView" | "exportCsv" | "exportJson" | "actions" | "draftConflict" | "draftApplied" | "draftRestore" | "draftDiscard" | "draftStartOver" | "new" | "edit" | "view"> | import("./locale.d.ts").ScalarTranslatorKey<"agentTurn", AgentTurn, never> | `agentStop.${string}` | `agentStop.${string}.desc` | import("./locale.d.ts").ServiceTranslatorKey<"agent", AgentEndpoint, never>, data?: import("./trans.d.ts").TranslationData) => string, msg: {
|
|
8
8
|
info: (key: import("./locale.d.ts").ServiceTranslatorKey<"base", BaseEndpoint, "error" | "remove" | "unauthorized" | "save" | "refresh" | "password" | "skip" | "stop" | "send" | "ok" | "agent" | "success" | "somethingWrong" | "connecting" | "connected" | "serverDisconnected" | "refreshing" | "tryReconnecting" | "serverHasProblem" | "checkServerStatus" | "cameraPromptHeader" | "cameraPromptPhoto" | "cameraPromptPicture" | "cameraPromptCancel" | "failed" | "processing" | "processed" | "noData" | "invalidValueError" | "emailInvalidError" | "phoneInvalidError" | "cancel" | "agentIntro" | "agentPlaceholder" | "agentClear" | "agentQuestion" | "agentAnswer" | "agentListen" | "agentVoiceFailed" | "agentAttach" | "agentAttachRemove" | "agentAttachReading" | "agentReferenceRemove" | "agentReferenceFailed" | "agentAttachTooLarge" | "agentAttachUnsupported" | "agentAttachDuplicate" | "agentAttachTooMany" | "agentAttachTooMuch" | "agentAnswerNeeded" | "agentQueue" | "agentQueuePlaceholder" | "agentQueued" | "agentQueueEdit" | "agentQueueCancel" | "agentToolDone" | "agentToolFailed" | "agentToolRunning" | "agentToolResult" | "agentTokens" | "agentSummarizing" | "agentContinue" | "agentKeepGoing" | "agentCmdNew" | "agentCmdRetry" | "agentCmdCompact" | "agentCmdCopy" | "agentCmdHelp" | "agentCmdTools" | "agentHelpIntro" | "agentHelpNote" | "agentNothingToRetry" | "agentNothingToCompact" | "agentCompacted" | "agentSummary" | "agentBusy" | "agentCopied" | "agentCopyFailed" | "agentToolsHead" | "agentToolsState" | "approve" | "decline" | "confirmClose" | "textTooShortError" | "textTooLongError" | "selectTooShortError" | "selectTooLongError" | "numberTooSmallError" | "numberTooBigError" | "passwordNotMatchError" | "selectDateError" | "priceUnit" | "passwordConfirm" | "noOptions" | "noSelection" | "addModel" | "createModel" | "createSuccess" | "updateModel" | "removeModel" | "updateSuccess" | "removeSuccess" | "sureToRemove" | "irreversibleOps" | "typeNameToRemove" | "yesRemove" | "removeMsg" | "confirmMsg" | "perPage" | "cardView" | "tableView" | "exportCsv" | "exportJson" | "actions" | "draftConflict" | "draftApplied" | "draftRestore" | "draftDiscard" | "draftStartOver" | "new" | "edit" | "view"> | import("./locale.d.ts").ScalarTranslatorKey<"agentTurn", AgentTurn, never> | `agentStop.${string}` | `agentStop.${string}.desc` | import("./locale.d.ts").ServiceTranslatorKey<"agent", AgentEndpoint, never>, option?: import("./trans.d.ts").TransMessageOption) => void;
|
|
9
9
|
success: (key: import("./locale.d.ts").ServiceTranslatorKey<"base", BaseEndpoint, "error" | "remove" | "unauthorized" | "save" | "refresh" | "password" | "skip" | "stop" | "send" | "ok" | "agent" | "success" | "somethingWrong" | "connecting" | "connected" | "serverDisconnected" | "refreshing" | "tryReconnecting" | "serverHasProblem" | "checkServerStatus" | "cameraPromptHeader" | "cameraPromptPhoto" | "cameraPromptPicture" | "cameraPromptCancel" | "failed" | "processing" | "processed" | "noData" | "invalidValueError" | "emailInvalidError" | "phoneInvalidError" | "cancel" | "agentIntro" | "agentPlaceholder" | "agentClear" | "agentQuestion" | "agentAnswer" | "agentListen" | "agentVoiceFailed" | "agentAttach" | "agentAttachRemove" | "agentAttachReading" | "agentReferenceRemove" | "agentReferenceFailed" | "agentAttachTooLarge" | "agentAttachUnsupported" | "agentAttachDuplicate" | "agentAttachTooMany" | "agentAttachTooMuch" | "agentAnswerNeeded" | "agentQueue" | "agentQueuePlaceholder" | "agentQueued" | "agentQueueEdit" | "agentQueueCancel" | "agentToolDone" | "agentToolFailed" | "agentToolRunning" | "agentToolResult" | "agentTokens" | "agentSummarizing" | "agentContinue" | "agentKeepGoing" | "agentCmdNew" | "agentCmdRetry" | "agentCmdCompact" | "agentCmdCopy" | "agentCmdHelp" | "agentCmdTools" | "agentHelpIntro" | "agentHelpNote" | "agentNothingToRetry" | "agentNothingToCompact" | "agentCompacted" | "agentSummary" | "agentBusy" | "agentCopied" | "agentCopyFailed" | "agentToolsHead" | "agentToolsState" | "approve" | "decline" | "confirmClose" | "textTooShortError" | "textTooLongError" | "selectTooShortError" | "selectTooLongError" | "numberTooSmallError" | "numberTooBigError" | "passwordNotMatchError" | "selectDateError" | "priceUnit" | "passwordConfirm" | "noOptions" | "noSelection" | "addModel" | "createModel" | "createSuccess" | "updateModel" | "removeModel" | "updateSuccess" | "removeSuccess" | "sureToRemove" | "irreversibleOps" | "typeNameToRemove" | "yesRemove" | "removeMsg" | "confirmMsg" | "perPage" | "cardView" | "tableView" | "exportCsv" | "exportJson" | "actions" | "draftConflict" | "draftApplied" | "draftRestore" | "draftDiscard" | "draftStartOver" | "new" | "edit" | "view"> | import("./locale.d.ts").ScalarTranslatorKey<"agentTurn", AgentTurn, never> | `agentStop.${string}` | `agentStop.${string}.desc` | import("./locale.d.ts").ServiceTranslatorKey<"agent", AgentEndpoint, never>, option?: import("./trans.d.ts").TransMessageOption) => void;
|
|
10
10
|
error: (key: import("./locale.d.ts").ServiceTranslatorKey<"base", BaseEndpoint, "error" | "remove" | "unauthorized" | "save" | "refresh" | "password" | "skip" | "stop" | "send" | "ok" | "agent" | "success" | "somethingWrong" | "connecting" | "connected" | "serverDisconnected" | "refreshing" | "tryReconnecting" | "serverHasProblem" | "checkServerStatus" | "cameraPromptHeader" | "cameraPromptPhoto" | "cameraPromptPicture" | "cameraPromptCancel" | "failed" | "processing" | "processed" | "noData" | "invalidValueError" | "emailInvalidError" | "phoneInvalidError" | "cancel" | "agentIntro" | "agentPlaceholder" | "agentClear" | "agentQuestion" | "agentAnswer" | "agentListen" | "agentVoiceFailed" | "agentAttach" | "agentAttachRemove" | "agentAttachReading" | "agentReferenceRemove" | "agentReferenceFailed" | "agentAttachTooLarge" | "agentAttachUnsupported" | "agentAttachDuplicate" | "agentAttachTooMany" | "agentAttachTooMuch" | "agentAnswerNeeded" | "agentQueue" | "agentQueuePlaceholder" | "agentQueued" | "agentQueueEdit" | "agentQueueCancel" | "agentToolDone" | "agentToolFailed" | "agentToolRunning" | "agentToolResult" | "agentTokens" | "agentSummarizing" | "agentContinue" | "agentKeepGoing" | "agentCmdNew" | "agentCmdRetry" | "agentCmdCompact" | "agentCmdCopy" | "agentCmdHelp" | "agentCmdTools" | "agentHelpIntro" | "agentHelpNote" | "agentNothingToRetry" | "agentNothingToCompact" | "agentCompacted" | "agentSummary" | "agentBusy" | "agentCopied" | "agentCopyFailed" | "agentToolsHead" | "agentToolsState" | "approve" | "decline" | "confirmClose" | "textTooShortError" | "textTooLongError" | "selectTooShortError" | "selectTooLongError" | "numberTooSmallError" | "numberTooBigError" | "passwordNotMatchError" | "selectDateError" | "priceUnit" | "passwordConfirm" | "noOptions" | "noSelection" | "addModel" | "createModel" | "createSuccess" | "updateModel" | "removeModel" | "updateSuccess" | "removeSuccess" | "sureToRemove" | "irreversibleOps" | "typeNameToRemove" | "yesRemove" | "removeMsg" | "confirmMsg" | "perPage" | "cardView" | "tableView" | "exportCsv" | "exportJson" | "actions" | "draftConflict" | "draftApplied" | "draftRestore" | "draftDiscard" | "draftStartOver" | "new" | "edit" | "view"> | import("./locale.d.ts").ScalarTranslatorKey<"agentTurn", AgentTurn, never> | `agentStop.${string}` | `agentStop.${string}.desc` | import("./locale.d.ts").ServiceTranslatorKey<"agent", AgentEndpoint, never>, option?: import("./trans.d.ts").TransMessageOption) => void;
|
|
11
11
|
warning: (key: import("./locale.d.ts").ServiceTranslatorKey<"base", BaseEndpoint, "error" | "remove" | "unauthorized" | "save" | "refresh" | "password" | "skip" | "stop" | "send" | "ok" | "agent" | "success" | "somethingWrong" | "connecting" | "connected" | "serverDisconnected" | "refreshing" | "tryReconnecting" | "serverHasProblem" | "checkServerStatus" | "cameraPromptHeader" | "cameraPromptPhoto" | "cameraPromptPicture" | "cameraPromptCancel" | "failed" | "processing" | "processed" | "noData" | "invalidValueError" | "emailInvalidError" | "phoneInvalidError" | "cancel" | "agentIntro" | "agentPlaceholder" | "agentClear" | "agentQuestion" | "agentAnswer" | "agentListen" | "agentVoiceFailed" | "agentAttach" | "agentAttachRemove" | "agentAttachReading" | "agentReferenceRemove" | "agentReferenceFailed" | "agentAttachTooLarge" | "agentAttachUnsupported" | "agentAttachDuplicate" | "agentAttachTooMany" | "agentAttachTooMuch" | "agentAnswerNeeded" | "agentQueue" | "agentQueuePlaceholder" | "agentQueued" | "agentQueueEdit" | "agentQueueCancel" | "agentToolDone" | "agentToolFailed" | "agentToolRunning" | "agentToolResult" | "agentTokens" | "agentSummarizing" | "agentContinue" | "agentKeepGoing" | "agentCmdNew" | "agentCmdRetry" | "agentCmdCompact" | "agentCmdCopy" | "agentCmdHelp" | "agentCmdTools" | "agentHelpIntro" | "agentHelpNote" | "agentNothingToRetry" | "agentNothingToCompact" | "agentCompacted" | "agentSummary" | "agentBusy" | "agentCopied" | "agentCopyFailed" | "agentToolsHead" | "agentToolsState" | "approve" | "decline" | "confirmClose" | "textTooShortError" | "textTooLongError" | "selectTooShortError" | "selectTooLongError" | "numberTooSmallError" | "numberTooBigError" | "passwordNotMatchError" | "selectDateError" | "priceUnit" | "passwordConfirm" | "noOptions" | "noSelection" | "addModel" | "createModel" | "createSuccess" | "updateModel" | "removeModel" | "updateSuccess" | "removeSuccess" | "sureToRemove" | "irreversibleOps" | "typeNameToRemove" | "yesRemove" | "removeMsg" | "confirmMsg" | "perPage" | "cardView" | "tableView" | "exportCsv" | "exportJson" | "actions" | "draftConflict" | "draftApplied" | "draftRestore" | "draftDiscard" | "draftStartOver" | "new" | "edit" | "view"> | import("./locale.d.ts").ScalarTranslatorKey<"agentTurn", AgentTurn, never> | `agentStop.${string}` | `agentStop.${string}.desc` | import("./locale.d.ts").ServiceTranslatorKey<"agent", AgentEndpoint, never>, option?: import("./trans.d.ts").TransMessageOption) => void;
|
|
12
12
|
loading: (key: import("./locale.d.ts").ServiceTranslatorKey<"base", BaseEndpoint, "error" | "remove" | "unauthorized" | "save" | "refresh" | "password" | "skip" | "stop" | "send" | "ok" | "agent" | "success" | "somethingWrong" | "connecting" | "connected" | "serverDisconnected" | "refreshing" | "tryReconnecting" | "serverHasProblem" | "checkServerStatus" | "cameraPromptHeader" | "cameraPromptPhoto" | "cameraPromptPicture" | "cameraPromptCancel" | "failed" | "processing" | "processed" | "noData" | "invalidValueError" | "emailInvalidError" | "phoneInvalidError" | "cancel" | "agentIntro" | "agentPlaceholder" | "agentClear" | "agentQuestion" | "agentAnswer" | "agentListen" | "agentVoiceFailed" | "agentAttach" | "agentAttachRemove" | "agentAttachReading" | "agentReferenceRemove" | "agentReferenceFailed" | "agentAttachTooLarge" | "agentAttachUnsupported" | "agentAttachDuplicate" | "agentAttachTooMany" | "agentAttachTooMuch" | "agentAnswerNeeded" | "agentQueue" | "agentQueuePlaceholder" | "agentQueued" | "agentQueueEdit" | "agentQueueCancel" | "agentToolDone" | "agentToolFailed" | "agentToolRunning" | "agentToolResult" | "agentTokens" | "agentSummarizing" | "agentContinue" | "agentKeepGoing" | "agentCmdNew" | "agentCmdRetry" | "agentCmdCompact" | "agentCmdCopy" | "agentCmdHelp" | "agentCmdTools" | "agentHelpIntro" | "agentHelpNote" | "agentNothingToRetry" | "agentNothingToCompact" | "agentCompacted" | "agentSummary" | "agentBusy" | "agentCopied" | "agentCopyFailed" | "agentToolsHead" | "agentToolsState" | "approve" | "decline" | "confirmClose" | "textTooShortError" | "textTooLongError" | "selectTooShortError" | "selectTooLongError" | "numberTooSmallError" | "numberTooBigError" | "passwordNotMatchError" | "selectDateError" | "priceUnit" | "passwordConfirm" | "noOptions" | "noSelection" | "addModel" | "createModel" | "createSuccess" | "updateModel" | "removeModel" | "updateSuccess" | "removeSuccess" | "sureToRemove" | "irreversibleOps" | "typeNameToRemove" | "yesRemove" | "removeMsg" | "confirmMsg" | "perPage" | "cardView" | "tableView" | "exportCsv" | "exportJson" | "actions" | "draftConflict" | "draftApplied" | "draftRestore" | "draftDiscard" | "draftStartOver" | "new" | "edit" | "view"> | import("./locale.d.ts").ScalarTranslatorKey<"agentTurn", AgentTurn, never> | `agentStop.${string}` | `agentStop.${string}.desc` | import("./locale.d.ts").ServiceTranslatorKey<"agent", AgentEndpoint, never>, option?: import("./trans.d.ts").TransMessageOption) => void;
|
|
13
|
-
}, getDictionary: (lang: "en" | "ko" | (string & {}) | "zhChs" | "zhCht" | "ja") => object, getAllDictionary: () => import("./trans.d.ts").RootDictionary, __Dict_Key__: import("./locale.d.ts").ServiceTranslatorKey<"base", BaseEndpoint, "error" | "remove" | "unauthorized" | "save" | "refresh" | "password" | "skip" | "stop" | "send" | "ok" | "agent" | "success" | "somethingWrong" | "connecting" | "connected" | "serverDisconnected" | "refreshing" | "tryReconnecting" | "serverHasProblem" | "checkServerStatus" | "cameraPromptHeader" | "cameraPromptPhoto" | "cameraPromptPicture" | "cameraPromptCancel" | "failed" | "processing" | "processed" | "noData" | "invalidValueError" | "emailInvalidError" | "phoneInvalidError" | "cancel" | "agentIntro" | "agentPlaceholder" | "agentClear" | "agentQuestion" | "agentAnswer" | "agentListen" | "agentVoiceFailed" | "agentAttach" | "agentAttachRemove" | "agentAttachReading" | "agentReferenceRemove" | "agentReferenceFailed" | "agentAttachTooLarge" | "agentAttachUnsupported" | "agentAttachDuplicate" | "agentAttachTooMany" | "agentAttachTooMuch" | "agentAnswerNeeded" | "agentQueue" | "agentQueuePlaceholder" | "agentQueued" | "agentQueueEdit" | "agentQueueCancel" | "agentToolDone" | "agentToolFailed" | "agentToolRunning" | "agentToolResult" | "agentTokens" | "agentSummarizing" | "agentContinue" | "agentKeepGoing" | "agentCmdNew" | "agentCmdRetry" | "agentCmdCompact" | "agentCmdCopy" | "agentCmdHelp" | "agentCmdTools" | "agentHelpIntro" | "agentHelpNote" | "agentNothingToRetry" | "agentNothingToCompact" | "agentCompacted" | "agentSummary" | "agentBusy" | "agentCopied" | "agentCopyFailed" | "agentToolsHead" | "agentToolsState" | "approve" | "decline" | "confirmClose" | "textTooShortError" | "textTooLongError" | "selectTooShortError" | "selectTooLongError" | "numberTooSmallError" | "numberTooBigError" | "passwordNotMatchError" | "selectDateError" | "priceUnit" | "passwordConfirm" | "noOptions" | "noSelection" | "addModel" | "createModel" | "createSuccess" | "updateModel" | "removeModel" | "updateSuccess" | "removeSuccess" | "sureToRemove" | "irreversibleOps" | "typeNameToRemove" | "yesRemove" | "removeMsg" | "confirmMsg" | "perPage" | "cardView" | "tableView" | "exportCsv" | "exportJson" | "actions" | "draftConflict" | "draftApplied" | "draftRestore" | "draftDiscard" | "draftStartOver" | "new" | "edit" | "view"> | import("./locale.d.ts").ScalarTranslatorKey<"agentTurn", AgentTurn, never> | `agentStop.${string}` | `agentStop.${string}.desc` | import("./locale.d.ts").ServiceTranslatorKey<"agent", AgentEndpoint, never>, __Error_Key__: "base.error.gatewayTimeout" | "base.error.serverUnavailable" | "base.error.serverUnreachable" | "base.error.unexpectedResponse" | "agent.error.llmUnavailable" | "agent.error.
|
|
13
|
+
}, getDictionary: (lang: "en" | "ko" | (string & {}) | "zhChs" | "zhCht" | "ja") => object, getAllDictionary: () => import("./trans.d.ts").RootDictionary, __Dict_Key__: import("./locale.d.ts").ServiceTranslatorKey<"base", BaseEndpoint, "error" | "remove" | "unauthorized" | "save" | "refresh" | "password" | "skip" | "stop" | "send" | "ok" | "agent" | "success" | "somethingWrong" | "connecting" | "connected" | "serverDisconnected" | "refreshing" | "tryReconnecting" | "serverHasProblem" | "checkServerStatus" | "cameraPromptHeader" | "cameraPromptPhoto" | "cameraPromptPicture" | "cameraPromptCancel" | "failed" | "processing" | "processed" | "noData" | "invalidValueError" | "emailInvalidError" | "phoneInvalidError" | "cancel" | "agentIntro" | "agentPlaceholder" | "agentClear" | "agentQuestion" | "agentAnswer" | "agentListen" | "agentVoiceFailed" | "agentAttach" | "agentAttachRemove" | "agentAttachReading" | "agentReferenceRemove" | "agentReferenceFailed" | "agentAttachTooLarge" | "agentAttachUnsupported" | "agentAttachDuplicate" | "agentAttachTooMany" | "agentAttachTooMuch" | "agentAnswerNeeded" | "agentQueue" | "agentQueuePlaceholder" | "agentQueued" | "agentQueueEdit" | "agentQueueCancel" | "agentToolDone" | "agentToolFailed" | "agentToolRunning" | "agentToolResult" | "agentTokens" | "agentSummarizing" | "agentContinue" | "agentKeepGoing" | "agentCmdNew" | "agentCmdRetry" | "agentCmdCompact" | "agentCmdCopy" | "agentCmdHelp" | "agentCmdTools" | "agentHelpIntro" | "agentHelpNote" | "agentNothingToRetry" | "agentNothingToCompact" | "agentCompacted" | "agentSummary" | "agentBusy" | "agentCopied" | "agentCopyFailed" | "agentToolsHead" | "agentToolsState" | "approve" | "decline" | "confirmClose" | "textTooShortError" | "textTooLongError" | "selectTooShortError" | "selectTooLongError" | "numberTooSmallError" | "numberTooBigError" | "passwordNotMatchError" | "selectDateError" | "priceUnit" | "passwordConfirm" | "noOptions" | "noSelection" | "addModel" | "createModel" | "createSuccess" | "updateModel" | "removeModel" | "updateSuccess" | "removeSuccess" | "sureToRemove" | "irreversibleOps" | "typeNameToRemove" | "yesRemove" | "removeMsg" | "confirmMsg" | "perPage" | "cardView" | "tableView" | "exportCsv" | "exportJson" | "actions" | "draftConflict" | "draftApplied" | "draftRestore" | "draftDiscard" | "draftStartOver" | "new" | "edit" | "view"> | import("./locale.d.ts").ScalarTranslatorKey<"agentTurn", AgentTurn, never> | `agentStop.${string}` | `agentStop.${string}.desc` | import("./locale.d.ts").ServiceTranslatorKey<"agent", AgentEndpoint, never>, __Error_Key__: "base.error.gatewayTimeout" | "base.error.serverUnavailable" | "base.error.serverUnreachable" | "base.error.unexpectedResponse" | "agent.error.llmUnavailable" | "agent.error.llmRequestFailed";
|
|
@@ -38,8 +38,15 @@ export declare class AkanOption<Env extends BackendEnv = BackendEnv> {
|
|
|
38
38
|
* itself is on by default and `{ enabled: false }` is for an API no browser reaches.
|
|
39
39
|
*/
|
|
40
40
|
setCrossSite(crossSite: CrossSiteOption): this;
|
|
41
|
-
/**
|
|
42
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Settings for whichever adaptor fills `LlmAdaptorRole`, injected into it as the `llmOption` use.
|
|
43
|
+
*
|
|
44
|
+
* The argument is generic so that whatever an adaptor needs beyond `LlmOption` travels here too: an adaptor an
|
|
45
|
+
* app or a library wrote declares its own interface extending it, reads it with `use<MyLlmOption>()`, and its
|
|
46
|
+
* region or project id rides the same channel the shipped fields do. Entries merge in mount order with the
|
|
47
|
+
* app's last, so a library may name a host and the app the key.
|
|
48
|
+
*/
|
|
49
|
+
setLlm<Option extends LlmOption>(llmOrFn: Option | ((env: Env) => Option)): this;
|
|
43
50
|
/** Every entry in declaration order, duplicates kept: the boot stage rejects a key claimed twice. */
|
|
44
51
|
getUses(env: Env): [string, PromiseOrObject<unknown>][];
|
|
45
52
|
getMiddlewares(): MiddlewareCls[];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { DatabaseMode } from "akanjs";
|
|
2
|
-
import { type AdaptorCls, BlobStorage, type CacheAdaptor, type CompressAdaptor, ConsoleLogger, type DatabaseAdaptor,
|
|
2
|
+
import { type AdaptorCls, BlobStorage, type CacheAdaptor, type CompressAdaptor, ConsoleLogger, type DatabaseAdaptor, JsonCompressor, type LlmAdaptor, type LoggingAdaptor, OpenaiLlm, type QueueAdaptor, type ScheduleAdaptor, Scheduler, SolidCache, SolidPubSub, SolidQueue, SqliteDatabase, type StorageAdaptor, type WebsocketAdaptor } from "akanjs/service";
|
|
3
3
|
export interface PredefinedAdaptor {
|
|
4
4
|
database: AdaptorCls<DatabaseAdaptor>;
|
|
5
5
|
cache: AdaptorCls<CacheAdaptor>;
|
|
@@ -31,6 +31,6 @@ export declare const predefinedAdaptor: {
|
|
|
31
31
|
logging: typeof ConsoleLogger;
|
|
32
32
|
websocket: typeof SolidPubSub;
|
|
33
33
|
compress: typeof JsonCompressor;
|
|
34
|
-
llm: typeof
|
|
34
|
+
llm: typeof OpenaiLlm;
|
|
35
35
|
};
|
|
36
36
|
export declare const getPredefinedAdaptor: (mode?: DatabaseMode) => PredefinedAdaptor;
|
|
@@ -78,7 +78,7 @@ export declare class AnthropicLlm extends AnthropicLlm_base implements LlmAdapto
|
|
|
78
78
|
/** What the API's blocks carry. A model of the family that reads neither takes the `accepts` override. */
|
|
79
79
|
get accepts(): LlmAccepts;
|
|
80
80
|
chat(request: LlmTurnRequest, onDelta?: (delta: string) => void): Promise<LlmTurnAnswer | null>;
|
|
81
|
-
static refusal(response: Response): Promise<Error>;
|
|
81
|
+
static refusal(host: string, response: Response): Promise<Error>;
|
|
82
82
|
/** The API answers a refusal as `{ error: { type, message } }`, and the sentence is the half worth printing. */
|
|
83
83
|
static reasonOf(response: Response): Promise<string>;
|
|
84
84
|
static requestBody(model: string, request: LlmTurnRequest, { accepts, stream, maxTokens }?: {
|
|
@@ -2,7 +2,6 @@ export * from "./anthropicLlm.d.ts";
|
|
|
2
2
|
export * from "./cache.adaptor";
|
|
3
3
|
export * from "./compress.adaptor";
|
|
4
4
|
export * from "./database.adaptor";
|
|
5
|
-
export * from "./deepseekLlm.d.ts";
|
|
6
5
|
export * from "./insightQuery.d.ts";
|
|
7
6
|
export * from "./llm.adaptor";
|
|
8
7
|
export * from "./logging.adaptor";
|
|
@@ -120,7 +120,12 @@ export interface LlmAccepts {
|
|
|
120
120
|
/**
|
|
121
121
|
* Settings for whichever adaptor fills `LlmAdaptorRole`, registered with `option.setLlm(...)` and injected as the
|
|
122
122
|
* `llmOption` use. It belongs to the role rather than to one provider: swapping the default for another `adapt()`
|
|
123
|
-
* class re-reads the same
|
|
123
|
+
* class re-reads the same fields under that provider's own defaults.
|
|
124
|
+
*
|
|
125
|
+
* It is the floor, not the whole shape. `setLlm` keeps whatever else it is handed, so an adaptor an app or a
|
|
126
|
+
* library wrote declares its own interface extending this one and reads it with `use<MyLlmOption>()` — a region,
|
|
127
|
+
* a project id, a deployment name reach it through the same channel the fields below do, instead of a second
|
|
128
|
+
* `option.use({...})` key beside it.
|
|
124
129
|
*/
|
|
125
130
|
export interface LlmOption {
|
|
126
131
|
apiKey?: string;
|
|
@@ -145,3 +150,11 @@ export interface LlmOption {
|
|
|
145
150
|
*/
|
|
146
151
|
maxTokens?: number;
|
|
147
152
|
}
|
|
153
|
+
/**
|
|
154
|
+
* What the chat prints as the party that refused a turn, carried on `agent.error.llmRequestFailed`.
|
|
155
|
+
*
|
|
156
|
+
* It is the host rather than the adaptor's own name because one adaptor speaks one dialect to whatever host it
|
|
157
|
+
* is pointed at — an OpenAI-dialect class aimed at a gateway would otherwise credit OpenAI for that gateway's
|
|
158
|
+
* refusal. A host that is not a URL is printed as written; there is nothing better to say about it.
|
|
159
|
+
*/
|
|
160
|
+
export declare const llmProviderOf: (host: string) => string;
|
|
@@ -1,24 +1,33 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type LlmAccepts, type LlmAdaptor, type LlmOption, type LlmTurnAnswer, type LlmTurnRequest } from "./llm.adaptor";
|
|
2
2
|
declare const OpenaiLlm_base: import("..").AdaptorCls<{}, {
|
|
3
3
|
llmOption: import("..").InjectInfo<"use", LlmOption, never, never>;
|
|
4
4
|
}>;
|
|
5
5
|
/**
|
|
6
|
-
* OpenAI
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* The OpenAI chat-completions dialect, pointed at a host — and the framework's default fill for `LlmAdaptorRole`.
|
|
7
|
+
*
|
|
8
|
+
* One class rather than one per vendor: DeepSeek, Groq, Together, OpenRouter, Ollama and a self-hosted vLLM all
|
|
9
|
+
* serve this same wire, so what distinguishes them is `option.setLlm({ host, model })` and not a protocol. A
|
|
10
|
+
* provider that speaks its own wire — Anthropic's blocks, Bedrock's signed requests — is a different adaptor
|
|
11
|
+
* class, in this package or in the app's own `srvkit/`, applied with
|
|
12
|
+
* `option.applyAdaptor(LlmAdaptorRole, TheClass)`.
|
|
10
13
|
*
|
|
11
14
|
* `model` is required and has no default. A default would be a model name that ages out of the provider's
|
|
12
|
-
* catalogue into a 404 at the first turn, and — worse
|
|
13
|
-
*
|
|
14
|
-
* `accepts: { image: false }` beside it when that model is one of the provider's text-only ones.
|
|
15
|
+
* catalogue into a 404 at the first turn, and — worse — it would decide the vision claim below on the app's
|
|
16
|
+
* behalf.
|
|
15
17
|
*/
|
|
16
18
|
export declare class OpenaiLlm extends OpenaiLlm_base implements LlmAdaptor {
|
|
17
19
|
#private;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
+
static readonly defaultHost = "https://api.openai.com/v1";
|
|
21
|
+
/**
|
|
22
|
+
* OpenAI's own endpoint takes image parts, so that is what is claimed for the default host. A host the app
|
|
23
|
+
* named is a gateway this class knows nothing about, and claiming vision for one is the worst guess available:
|
|
24
|
+
* the bytes reach a model that cannot decode them and the whole turn dies on a 400, where text-only degrades
|
|
25
|
+
* them to a note the model can repeat back. So a named host is text-only until `option.setLlm({ accepts })`
|
|
26
|
+
* says otherwise — as is the OpenAI model that reads no image.
|
|
27
|
+
*/
|
|
28
|
+
get accepts(): LlmAccepts | undefined;
|
|
20
29
|
chat(request: LlmTurnRequest, onDelta?: (delta: string) => void): Promise<LlmTurnAnswer | null>;
|
|
21
30
|
/** Carried on the `Err` so the chat prints the provider's own sentence rather than a status number. */
|
|
22
|
-
static refusal(response: Response): Promise<Error>;
|
|
31
|
+
static refusal(host: string, response: Response): Promise<Error>;
|
|
23
32
|
}
|
|
24
33
|
export {};
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { Err } from "akanjs/dictionary";
|
|
2
|
-
import { adapt } from "../adapt";
|
|
3
|
-
import type { LlmAdaptor, LlmOption, LlmTurnAnswer, LlmTurnRequest } from "./llm.adaptor";
|
|
4
|
-
import { type OpenaiAnswer, OpenaiDialect } from "./openaiDialect";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* The framework's default provider, and the one an app gets without choosing.
|
|
8
|
-
*
|
|
9
|
-
* `accepts` is left undeclared, so by the time an attachment reaches the dialect `AgentService.readable` has
|
|
10
|
-
* reduced it to its text and turned everything else into a note. That is deliberate rather than pending: DeepSeek's
|
|
11
|
-
* chat API is text, and an adaptor that claimed otherwise would hand it bytes it answers about having never seen.
|
|
12
|
-
* An app that wants vision swaps the role — `option.applyAdaptor(LlmAdaptorRole, OpenaiLlm)` or `AnthropicLlm`.
|
|
13
|
-
*/
|
|
14
|
-
export class DeepseekLlm
|
|
15
|
-
extends adapt("deepseekLlm" as const, ({ use }) => ({
|
|
16
|
-
llmOption: use<LlmOption>(),
|
|
17
|
-
}))
|
|
18
|
-
implements LlmAdaptor
|
|
19
|
-
{
|
|
20
|
-
get #model() {
|
|
21
|
-
return this.llmOption.model ?? "deepseek-v4-flash";
|
|
22
|
-
}
|
|
23
|
-
get #host() {
|
|
24
|
-
return this.llmOption.host ?? "https://api.deepseek.com";
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
async chat(request: LlmTurnRequest, onDelta?: (delta: string) => void): Promise<LlmTurnAnswer | null> {
|
|
28
|
-
if (!this.llmOption.apiKey) {
|
|
29
|
-
this.logger.warn("No LLM API key is configured — set one with option.setLlm(). Agent turns are unavailable.");
|
|
30
|
-
return null;
|
|
31
|
-
}
|
|
32
|
-
try {
|
|
33
|
-
if (!onDelta) {
|
|
34
|
-
const answer = await this.#api<OpenaiAnswer>(
|
|
35
|
-
"/chat/completions",
|
|
36
|
-
OpenaiDialect.requestBody(this.#model, request),
|
|
37
|
-
);
|
|
38
|
-
return OpenaiDialect.turnAnswer(answer);
|
|
39
|
-
}
|
|
40
|
-
const body = await this.#apiStream(
|
|
41
|
-
"/chat/completions",
|
|
42
|
-
OpenaiDialect.requestBody(this.#model, request, { stream: true }),
|
|
43
|
-
);
|
|
44
|
-
return await OpenaiDialect.consumeStream(body, onDelta);
|
|
45
|
-
} catch (error) {
|
|
46
|
-
|
|
47
|
-
this.logger.error(`DeepSeek turn failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
48
|
-
throw error;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
async #api<T>(path: string, body: object): Promise<T> {
|
|
53
|
-
const response = await fetch(`${this.#host}${path}`, {
|
|
54
|
-
method: "POST",
|
|
55
|
-
headers: { "content-type": "application/json", authorization: `Bearer ${this.llmOption.apiKey}` },
|
|
56
|
-
body: JSON.stringify(body),
|
|
57
|
-
|
|
58
|
-
signal: AbortSignal.timeout(120_000),
|
|
59
|
-
});
|
|
60
|
-
if (!response.ok) throw await DeepseekLlm.refusal(response);
|
|
61
|
-
return (await response.json()) as T;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
async #apiStream(path: string, body: object): Promise<ReadableStream<Uint8Array>> {
|
|
65
|
-
const response = await fetch(`${this.#host}${path}`, {
|
|
66
|
-
method: "POST",
|
|
67
|
-
headers: { "content-type": "application/json", authorization: `Bearer ${this.llmOption.apiKey}` },
|
|
68
|
-
body: JSON.stringify(body),
|
|
69
|
-
signal: AbortSignal.timeout(120_000),
|
|
70
|
-
});
|
|
71
|
-
if (!response.ok || !response.body) throw await DeepseekLlm.refusal(response);
|
|
72
|
-
return response.body;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/** Carried on the `Err` so the chat prints the provider's own sentence rather than a status number. */
|
|
76
|
-
static async refusal(response: Response): Promise<Error> {
|
|
77
|
-
return new Err("agent.error.deepseekRequestFailed", {
|
|
78
|
-
status: String(response.status),
|
|
79
|
-
reason: await OpenaiDialect.reasonOf(response),
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import type { LlmAdaptor, LlmOption, LlmTurnAnswer, LlmTurnRequest } from "./llm.adaptor";
|
|
2
|
-
declare const DeepseekLlm_base: import("..").AdaptorCls<{}, {
|
|
3
|
-
llmOption: import("..").InjectInfo<"use", LlmOption, never, never>;
|
|
4
|
-
}>;
|
|
5
|
-
/**
|
|
6
|
-
* The framework's default provider, and the one an app gets without choosing.
|
|
7
|
-
*
|
|
8
|
-
* `accepts` is left undeclared, so by the time an attachment reaches the dialect `AgentService.readable` has
|
|
9
|
-
* reduced it to its text and turned everything else into a note. That is deliberate rather than pending: DeepSeek's
|
|
10
|
-
* chat API is text, and an adaptor that claimed otherwise would hand it bytes it answers about having never seen.
|
|
11
|
-
* An app that wants vision swaps the role — `option.applyAdaptor(LlmAdaptorRole, OpenaiLlm)` or `AnthropicLlm`.
|
|
12
|
-
*/
|
|
13
|
-
export declare class DeepseekLlm extends DeepseekLlm_base implements LlmAdaptor {
|
|
14
|
-
#private;
|
|
15
|
-
chat(request: LlmTurnRequest, onDelta?: (delta: string) => void): Promise<LlmTurnAnswer | null>;
|
|
16
|
-
/** Carried on the `Err` so the chat prints the provider's own sentence rather than a status number. */
|
|
17
|
-
static refusal(response: Response): Promise<Error>;
|
|
18
|
-
}
|
|
19
|
-
export {};
|