@opencode-ai/ai 0.0.0-bootstrap.0 → 0.0.0-next-15617
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +176 -1
- package/dist/cache-policy.d.ts +2 -0
- package/dist/cache-policy.js +108 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +9 -0
- package/dist/llm.d.ts +223 -0
- package/dist/llm.js +81 -0
- package/dist/protocols/anthropic-messages.d.ts +503 -0
- package/dist/protocols/anthropic-messages.js +745 -0
- package/dist/protocols/bedrock-converse.d.ts +476 -0
- package/dist/protocols/bedrock-converse.js +526 -0
- package/dist/protocols/bedrock-event-stream.d.ts +9 -0
- package/dist/protocols/bedrock-event-stream.js +64 -0
- package/dist/protocols/gemini.d.ts +220 -0
- package/dist/protocols/gemini.js +420 -0
- package/dist/protocols/google-vertex-anthropic.d.ts +494 -0
- package/dist/protocols/google-vertex-anthropic.js +33 -0
- package/dist/protocols/google-vertex-gemini.d.ts +59 -0
- package/dist/protocols/google-vertex-gemini.js +18 -0
- package/dist/protocols/index.d.ts +9 -0
- package/dist/protocols/index.js +9 -0
- package/dist/protocols/openai-chat.d.ts +391 -0
- package/dist/protocols/openai-chat.js +423 -0
- package/dist/protocols/openai-compatible-chat.d.ts +73 -0
- package/dist/protocols/openai-compatible-chat.js +20 -0
- package/dist/protocols/openai-compatible-responses.d.ts +85 -0
- package/dist/protocols/openai-compatible-responses.js +18 -0
- package/dist/protocols/openai-responses.d.ts +613 -0
- package/dist/protocols/openai-responses.js +828 -0
- package/dist/protocols/shared.d.ts +192 -0
- package/dist/protocols/shared.js +236 -0
- package/dist/protocols/utils/bedrock-auth.d.ts +18 -0
- package/dist/protocols/utils/bedrock-auth.js +41 -0
- package/dist/protocols/utils/bedrock-cache.d.ts +15 -0
- package/dist/protocols/utils/bedrock-cache.js +29 -0
- package/dist/protocols/utils/bedrock-media.d.ts +49 -0
- package/dist/protocols/utils/bedrock-media.js +68 -0
- package/dist/protocols/utils/cache.d.ts +6 -0
- package/dist/protocols/utils/cache.js +8 -0
- package/dist/protocols/utils/gemini-tool-schema.d.ts +2 -0
- package/dist/protocols/utils/gemini-tool-schema.js +83 -0
- package/dist/protocols/utils/lifecycle.d.ts +19 -0
- package/dist/protocols/utils/lifecycle.js +65 -0
- package/dist/protocols/utils/openai-options.d.ts +22 -0
- package/dist/protocols/utils/openai-options.js +64 -0
- package/dist/protocols/utils/tool-schema.d.ts +7 -0
- package/dist/protocols/utils/tool-schema.js +79 -0
- package/dist/protocols/utils/tool-stream.d.ts +155 -0
- package/dist/protocols/utils/tool-stream.js +136 -0
- package/dist/protocols.d.ts +1 -0
- package/dist/protocols.js +1 -0
- package/dist/provider-error.d.ts +13 -0
- package/dist/provider-error.js +122 -0
- package/dist/provider-package.d.ts +13 -0
- package/dist/provider-package.js +1 -0
- package/dist/provider.d.ts +23 -0
- package/dist/provider.js +2 -0
- package/dist/providers/amazon-bedrock.d.ts +150 -0
- package/dist/providers/amazon-bedrock.js +41 -0
- package/dist/providers/anthropic-compatible.d.ts +183 -0
- package/dist/providers/anthropic-compatible.js +44 -0
- package/dist/providers/anthropic.d.ts +181 -0
- package/dist/providers/anthropic.js +39 -0
- package/dist/providers/azure/chat.d.ts +2 -0
- package/dist/providers/azure/chat.js +1 -0
- package/dist/providers/azure/responses.d.ts +2 -0
- package/dist/providers/azure/responses.js +1 -0
- package/dist/providers/azure.d.ts +183 -0
- package/dist/providers/azure.js +89 -0
- package/dist/providers/cloudflare.d.ts +232 -0
- package/dist/providers/cloudflare.js +87 -0
- package/dist/providers/github-copilot.d.ts +167 -0
- package/dist/providers/github-copilot.js +47 -0
- package/dist/providers/google-vertex/anthropic.d.ts +2 -0
- package/dist/providers/google-vertex/anthropic.js +1 -0
- package/dist/providers/google-vertex-anthropic.d.ts +181 -0
- package/dist/providers/google-vertex-anthropic.js +46 -0
- package/dist/providers/google-vertex-shared.d.ts +22 -0
- package/dist/providers/google-vertex-shared.js +61 -0
- package/dist/providers/google-vertex.d.ts +93 -0
- package/dist/providers/google-vertex.js +49 -0
- package/dist/providers/google.d.ts +85 -0
- package/dist/providers/google.js +33 -0
- package/dist/providers/index.d.ts +15 -0
- package/dist/providers/index.js +15 -0
- package/dist/providers/openai/chat.d.ts +2 -0
- package/dist/providers/openai/chat.js +1 -0
- package/dist/providers/openai/responses.d.ts +2 -0
- package/dist/providers/openai/responses.js +1 -0
- package/dist/providers/openai-compatible/responses.d.ts +1 -0
- package/dist/providers/openai-compatible/responses.js +1 -0
- package/dist/providers/openai-compatible-profile.d.ts +43 -0
- package/dist/providers/openai-compatible-profile.js +12 -0
- package/dist/providers/openai-compatible-responses.d.ts +107 -0
- package/dist/providers/openai-compatible-responses.js +33 -0
- package/dist/providers/openai-compatible.d.ts +130 -0
- package/dist/providers/openai-compatible.js +55 -0
- package/dist/providers/openai-options.d.ts +30 -0
- package/dist/providers/openai-options.js +42 -0
- package/dist/providers/openai.d.ts +264 -0
- package/dist/providers/openai.js +62 -0
- package/dist/providers/openrouter.d.ts +321 -0
- package/dist/providers/openrouter.js +65 -0
- package/dist/providers/xai.d.ts +169 -0
- package/dist/providers/xai.js +43 -0
- package/dist/providers.d.ts +1 -0
- package/dist/providers.js +1 -0
- package/dist/route/auth-options.d.ts +34 -0
- package/dist/route/auth-options.js +14 -0
- package/dist/route/auth.d.ts +49 -0
- package/dist/route/auth.js +89 -0
- package/dist/route/client.d.ts +330 -0
- package/dist/route/client.js +211 -0
- package/dist/route/endpoint.d.ts +28 -0
- package/dist/route/endpoint.js +21 -0
- package/dist/route/executor.d.ts +12 -0
- package/dist/route/executor.js +229 -0
- package/dist/route/framing.d.ts +23 -0
- package/dist/route/framing.js +4 -0
- package/dist/route/index.d.ts +16 -0
- package/dist/route/index.js +9 -0
- package/dist/route/protocol.d.ts +76 -0
- package/dist/route/protocol.js +17 -0
- package/dist/route/transport/http.d.ts +33 -0
- package/dist/route/transport/http.js +98 -0
- package/dist/route/transport/index.d.ts +27 -0
- package/dist/route/transport/index.js +4 -0
- package/dist/route/transport/websocket.d.ts +56 -0
- package/dist/route/transport/websocket.js +181 -0
- package/dist/route.d.ts +1 -0
- package/dist/route.js +1 -0
- package/dist/schema/errors.d.ts +153 -0
- package/dist/schema/errors.js +150 -0
- package/dist/schema/events.d.ts +4292 -0
- package/dist/schema/events.js +482 -0
- package/dist/schema/ids.d.ts +30 -0
- package/dist/schema/ids.js +18 -0
- package/dist/schema/index.d.ts +5 -0
- package/dist/schema/index.js +5 -0
- package/dist/schema/messages.d.ts +385 -0
- package/dist/schema/messages.js +246 -0
- package/dist/schema/options.d.ts +143 -0
- package/dist/schema/options.js +195 -0
- package/dist/tool-runtime.d.ts +15 -0
- package/dist/tool-runtime.js +35 -0
- package/dist/tool.d.ts +134 -0
- package/dist/tool.js +66 -0
- package/dist/utils/record.d.ts +2 -0
- package/dist/utils/record.js +2 -0
- package/package.json +36 -9
- package/index.js +0 -1
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { Headers, HttpClientRequest } from "effect/unstable/http";
|
|
3
|
+
import { Framing } from "../framing";
|
|
4
|
+
import type { Transport, TransportPrepareInput } from "./index";
|
|
5
|
+
export type JsonRequestInput<Body> = TransportPrepareInput<Body>;
|
|
6
|
+
export interface JsonRequestParts<Body = unknown> {
|
|
7
|
+
readonly url: string;
|
|
8
|
+
readonly jsonBody: Body | Record<string, unknown>;
|
|
9
|
+
readonly bodyText: string;
|
|
10
|
+
readonly headers: Headers.Headers;
|
|
11
|
+
}
|
|
12
|
+
export interface HttpPrepared<Frame> {
|
|
13
|
+
readonly request: HttpClientRequest.HttpClientRequest;
|
|
14
|
+
readonly framing: Framing.Definition<Frame>;
|
|
15
|
+
}
|
|
16
|
+
export declare const jsonRequestParts: <Body>(input: JsonRequestInput<Body>) => Effect.Effect<{
|
|
17
|
+
url: string;
|
|
18
|
+
jsonBody: Record<string, unknown> | Body;
|
|
19
|
+
bodyText: string;
|
|
20
|
+
headers: Headers.Headers;
|
|
21
|
+
}, import("../..").LLMError, never>;
|
|
22
|
+
export interface HttpJsonInput<_Body, Frame> {
|
|
23
|
+
readonly framing: Framing.Definition<Frame>;
|
|
24
|
+
}
|
|
25
|
+
export type HttpJsonPatch<Body, Frame> = Partial<HttpJsonInput<Body, Frame>>;
|
|
26
|
+
export interface HttpJsonTransport<Body, Frame> extends Transport<Body, HttpPrepared<Frame>, Frame> {
|
|
27
|
+
readonly with: (patch: HttpJsonPatch<Body, Frame>) => HttpJsonTransport<Body, Frame>;
|
|
28
|
+
}
|
|
29
|
+
export declare const httpJson: <Body, Frame>(input: HttpJsonInput<Body, Frame>) => HttpJsonTransport<Body, Frame>;
|
|
30
|
+
export declare const sseJson: {
|
|
31
|
+
readonly id: "http-json/sse";
|
|
32
|
+
readonly with: <Body>() => HttpJsonTransport<Body, string>;
|
|
33
|
+
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { Effect, Stream } from "effect";
|
|
2
|
+
import { Headers, HttpClientRequest } from "effect/unstable/http";
|
|
3
|
+
import { Auth } from "../auth";
|
|
4
|
+
import { render as renderEndpoint } from "../endpoint";
|
|
5
|
+
import { Framing } from "../framing";
|
|
6
|
+
import * as ProviderShared from "../../protocols/shared";
|
|
7
|
+
import { mergeJsonRecords } from "../../schema";
|
|
8
|
+
const applyQuery = (url, query) => {
|
|
9
|
+
if (!query)
|
|
10
|
+
return url;
|
|
11
|
+
const next = new URL(url);
|
|
12
|
+
Object.entries(query).forEach(([key, value]) => next.searchParams.set(key, value));
|
|
13
|
+
return next.toString();
|
|
14
|
+
};
|
|
15
|
+
const PROTOCOL_BODY_OVERLAY_DENYLIST = new Set([
|
|
16
|
+
"anthropic_version",
|
|
17
|
+
"content",
|
|
18
|
+
"contents",
|
|
19
|
+
"frequencyPenalty",
|
|
20
|
+
"frequency_penalty",
|
|
21
|
+
"generationConfig",
|
|
22
|
+
"inferenceConfig",
|
|
23
|
+
"input",
|
|
24
|
+
"maxTokens",
|
|
25
|
+
"max_tokens",
|
|
26
|
+
"messages",
|
|
27
|
+
"model",
|
|
28
|
+
"presencePenalty",
|
|
29
|
+
"presence_penalty",
|
|
30
|
+
"responseFormat",
|
|
31
|
+
"response_format",
|
|
32
|
+
"seed",
|
|
33
|
+
"stop",
|
|
34
|
+
"stopSequences",
|
|
35
|
+
"stop_sequences",
|
|
36
|
+
"stream",
|
|
37
|
+
"streamOptions",
|
|
38
|
+
"stream_options",
|
|
39
|
+
"system",
|
|
40
|
+
"systemInstruction",
|
|
41
|
+
"system_instruction",
|
|
42
|
+
"temperature",
|
|
43
|
+
"thinking",
|
|
44
|
+
"toolChoice",
|
|
45
|
+
"toolConfig",
|
|
46
|
+
"tool_choice",
|
|
47
|
+
"tool_config",
|
|
48
|
+
"tools",
|
|
49
|
+
"topK",
|
|
50
|
+
"topP",
|
|
51
|
+
"top_k",
|
|
52
|
+
"top_p",
|
|
53
|
+
]);
|
|
54
|
+
const forbiddenBodyOverlayKeys = (body) => Object.keys(body).filter((key) => PROTOCOL_BODY_OVERLAY_DENYLIST.has(key));
|
|
55
|
+
const bodyWithOverlay = (body, request, encodeBody) => Effect.gen(function* () {
|
|
56
|
+
if (request.http?.body === undefined)
|
|
57
|
+
return { jsonBody: body, bodyText: encodeBody(body) };
|
|
58
|
+
const forbiddenKeys = forbiddenBodyOverlayKeys(request.http.body);
|
|
59
|
+
if (forbiddenKeys.length > 0)
|
|
60
|
+
return yield* ProviderShared.invalidRequest(`http.body cannot overlay protocol-owned field(s): ${forbiddenKeys.join(", ")}`);
|
|
61
|
+
if (ProviderShared.isRecord(body)) {
|
|
62
|
+
const overlaid = mergeJsonRecords(body, request.http.body) ?? {};
|
|
63
|
+
return { jsonBody: overlaid, bodyText: ProviderShared.encodeJson(overlaid) };
|
|
64
|
+
}
|
|
65
|
+
return yield* ProviderShared.invalidRequest("http.body can only overlay JSON object request bodies");
|
|
66
|
+
});
|
|
67
|
+
export const jsonRequestParts = (input) => Effect.gen(function* () {
|
|
68
|
+
const url = applyQuery(renderEndpoint(input.endpoint, { request: input.request, body: input.body }).toString(), input.request.http?.query);
|
|
69
|
+
const body = yield* bodyWithOverlay(input.body, input.request, input.encodeBody);
|
|
70
|
+
const headers = yield* Auth.toEffect(input.auth)({
|
|
71
|
+
request: input.request,
|
|
72
|
+
method: "POST",
|
|
73
|
+
url,
|
|
74
|
+
body: body.bodyText,
|
|
75
|
+
headers: Headers.fromInput({
|
|
76
|
+
...input.headers?.({ request: input.request }),
|
|
77
|
+
...input.request.http?.headers,
|
|
78
|
+
}),
|
|
79
|
+
});
|
|
80
|
+
return { url, jsonBody: body.jsonBody, bodyText: body.bodyText, headers };
|
|
81
|
+
});
|
|
82
|
+
export const httpJson = (input) => ({
|
|
83
|
+
id: "http-json",
|
|
84
|
+
with: (patch) => httpJson({ ...input, ...patch }),
|
|
85
|
+
prepare: (prepareInput) => jsonRequestParts({
|
|
86
|
+
...prepareInput,
|
|
87
|
+
}).pipe(Effect.map((parts) => ({
|
|
88
|
+
request: ProviderShared.jsonPost({ url: parts.url, body: parts.bodyText, headers: parts.headers }),
|
|
89
|
+
framing: input.framing,
|
|
90
|
+
}))),
|
|
91
|
+
frames: (prepared, request, runtime) => Stream.unwrap(runtime.http
|
|
92
|
+
.execute(prepared.request)
|
|
93
|
+
.pipe(Effect.map((response) => prepared.framing.frame(response.stream.pipe(Stream.mapError((error) => ProviderShared.eventError(`${request.model.provider}/${request.model.route.id}`, `Failed to read ${request.model.provider}/${request.model.route.id} stream`, ProviderShared.errorText(error)))))))),
|
|
94
|
+
});
|
|
95
|
+
export const sseJson = {
|
|
96
|
+
id: "http-json/sse",
|
|
97
|
+
with: () => httpJson({ framing: Framing.sse }),
|
|
98
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Effect, Stream } from "effect";
|
|
2
|
+
import { Endpoint } from "../endpoint";
|
|
3
|
+
import { Auth } from "../auth";
|
|
4
|
+
import type { Interface as RequestExecutorInterface } from "../executor";
|
|
5
|
+
import type { Interface as WebSocketExecutorInterface } from "./websocket";
|
|
6
|
+
import type { LLMError, LLMRequest } from "../../schema";
|
|
7
|
+
export interface TransportRuntime {
|
|
8
|
+
readonly http: RequestExecutorInterface;
|
|
9
|
+
readonly webSocket?: WebSocketExecutorInterface;
|
|
10
|
+
}
|
|
11
|
+
export interface Transport<Body, Prepared, Frame> {
|
|
12
|
+
readonly id: string;
|
|
13
|
+
readonly prepare: (input: TransportPrepareInput<Body>) => Effect.Effect<Prepared, LLMError>;
|
|
14
|
+
readonly frames: (prepared: Prepared, request: LLMRequest, runtime: TransportRuntime) => Stream.Stream<Frame, LLMError>;
|
|
15
|
+
}
|
|
16
|
+
export interface TransportPrepareInput<Body> {
|
|
17
|
+
readonly body: Body;
|
|
18
|
+
readonly request: LLMRequest;
|
|
19
|
+
readonly endpoint: Endpoint.Definition<Body>;
|
|
20
|
+
readonly auth: Auth.Definition;
|
|
21
|
+
readonly encodeBody: (body: Body) => string;
|
|
22
|
+
readonly headers?: (input: {
|
|
23
|
+
readonly request: LLMRequest;
|
|
24
|
+
}) => Record<string, string>;
|
|
25
|
+
}
|
|
26
|
+
export * as HttpTransport from "./http";
|
|
27
|
+
export { WebSocketExecutor, WebSocketTransport } from "./websocket";
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Context, Effect, Layer, Stream } from "effect";
|
|
2
|
+
import { Headers } from "effect/unstable/http";
|
|
3
|
+
import { LLMError } from "../../schema";
|
|
4
|
+
import type { Transport } from "./index";
|
|
5
|
+
export interface WebSocketRequest {
|
|
6
|
+
readonly url: string;
|
|
7
|
+
readonly headers: Headers.Headers;
|
|
8
|
+
}
|
|
9
|
+
export interface WebSocketConnection {
|
|
10
|
+
readonly sendText: (message: string) => Effect.Effect<void, LLMError>;
|
|
11
|
+
readonly messages: Stream.Stream<string | Uint8Array, LLMError>;
|
|
12
|
+
readonly close: Effect.Effect<void, never>;
|
|
13
|
+
}
|
|
14
|
+
export interface Interface {
|
|
15
|
+
readonly open: (input: WebSocketRequest) => Effect.Effect<WebSocketConnection, LLMError>;
|
|
16
|
+
}
|
|
17
|
+
declare const Service_base: Context.ServiceClass<Service, "@opencode/LLM/WebSocketExecutor", Interface>;
|
|
18
|
+
export declare class Service extends Service_base {
|
|
19
|
+
}
|
|
20
|
+
export declare const open: (input: WebSocketRequest) => Effect.Effect<WebSocketConnection, LLMError, never>;
|
|
21
|
+
export declare const layer: Layer.Layer<Service>;
|
|
22
|
+
export declare const fromWebSocket: (ws: globalThis.WebSocket, input: WebSocketRequest) => Effect.Effect<WebSocketConnection, LLMError>;
|
|
23
|
+
export declare const messageText: (message: string | Uint8Array, decoder: TextDecoder) => string;
|
|
24
|
+
export interface JsonPrepared {
|
|
25
|
+
readonly url: string;
|
|
26
|
+
readonly headers: Headers.Headers;
|
|
27
|
+
readonly message: string;
|
|
28
|
+
}
|
|
29
|
+
export interface JsonInput<Body, Message> {
|
|
30
|
+
readonly toMessage: (body: Body | Record<string, unknown>) => Effect.Effect<Message, LLMError>;
|
|
31
|
+
readonly encodeMessage: (message: Message) => string;
|
|
32
|
+
}
|
|
33
|
+
export type JsonPatch<Body, Message> = Partial<JsonInput<Body, Message>>;
|
|
34
|
+
export interface JsonTransport<Body, Message> extends Transport<Body, JsonPrepared, string> {
|
|
35
|
+
readonly with: (patch: JsonPatch<Body, Message>) => JsonTransport<Body, Message>;
|
|
36
|
+
}
|
|
37
|
+
export declare const json: <Body, Message>(input: JsonInput<Body, Message>) => JsonTransport<Body, Message>;
|
|
38
|
+
export declare const jsonTransport: {
|
|
39
|
+
readonly id: "websocket-json";
|
|
40
|
+
readonly with: <Body, Message>(input: JsonInput<Body, Message>) => JsonTransport<Body, Message>;
|
|
41
|
+
};
|
|
42
|
+
export declare const WebSocketExecutor: {
|
|
43
|
+
readonly Service: typeof Service;
|
|
44
|
+
readonly layer: Layer.Layer<Service, never, never>;
|
|
45
|
+
readonly open: (input: WebSocketRequest) => Effect.Effect<WebSocketConnection, LLMError, never>;
|
|
46
|
+
readonly fromWebSocket: (ws: globalThis.WebSocket, input: WebSocketRequest) => Effect.Effect<WebSocketConnection, LLMError>;
|
|
47
|
+
readonly messageText: (message: string | Uint8Array, decoder: TextDecoder) => string;
|
|
48
|
+
};
|
|
49
|
+
export declare const WebSocketTransport: {
|
|
50
|
+
readonly json: <Body, Message>(input: JsonInput<Body, Message>) => JsonTransport<Body, Message>;
|
|
51
|
+
readonly jsonTransport: {
|
|
52
|
+
readonly id: "websocket-json";
|
|
53
|
+
readonly with: <Body, Message>(input: JsonInput<Body, Message>) => JsonTransport<Body, Message>;
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
export {};
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { Cause, Context, Effect, Layer, Queue, Stream } from "effect";
|
|
2
|
+
import { Headers } from "effect/unstable/http";
|
|
3
|
+
import { LLMError, TransportReason } from "../../schema";
|
|
4
|
+
import * as HttpTransport from "./http";
|
|
5
|
+
export class Service extends Context.Service()("@opencode/LLM/WebSocketExecutor") {
|
|
6
|
+
}
|
|
7
|
+
const transportError = (method, message, input = {}) => new LLMError({
|
|
8
|
+
module: "WebSocketExecutor",
|
|
9
|
+
method,
|
|
10
|
+
reason: new TransportReason({ message, url: input.url, kind: input.kind }),
|
|
11
|
+
});
|
|
12
|
+
const eventMessage = (event) => {
|
|
13
|
+
if ("message" in event && typeof event.message === "string")
|
|
14
|
+
return event.message;
|
|
15
|
+
return event.type;
|
|
16
|
+
};
|
|
17
|
+
const binaryMessage = (data) => {
|
|
18
|
+
if (data instanceof Uint8Array)
|
|
19
|
+
return data;
|
|
20
|
+
if (data instanceof ArrayBuffer)
|
|
21
|
+
return new Uint8Array(data);
|
|
22
|
+
if (ArrayBuffer.isView(data))
|
|
23
|
+
return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
24
|
+
return undefined;
|
|
25
|
+
};
|
|
26
|
+
const waitOpen = (ws, input) => {
|
|
27
|
+
if (ws.readyState === globalThis.WebSocket.OPEN)
|
|
28
|
+
return Effect.void;
|
|
29
|
+
if (ws.readyState === globalThis.WebSocket.CLOSING || ws.readyState === globalThis.WebSocket.CLOSED) {
|
|
30
|
+
return Effect.fail(transportError("open", `WebSocket closed before opening (state ${ws.readyState})`, {
|
|
31
|
+
url: input.url,
|
|
32
|
+
kind: "open",
|
|
33
|
+
}));
|
|
34
|
+
}
|
|
35
|
+
return Effect.callback((resume, signal) => {
|
|
36
|
+
const cleanup = () => {
|
|
37
|
+
ws.removeEventListener("open", onOpen);
|
|
38
|
+
ws.removeEventListener("error", onError);
|
|
39
|
+
ws.removeEventListener("close", onClose);
|
|
40
|
+
signal.removeEventListener("abort", onAbort);
|
|
41
|
+
};
|
|
42
|
+
const onAbort = () => {
|
|
43
|
+
cleanup();
|
|
44
|
+
if (ws.readyState !== globalThis.WebSocket.CLOSED && ws.readyState !== globalThis.WebSocket.CLOSING)
|
|
45
|
+
ws.close(1000);
|
|
46
|
+
};
|
|
47
|
+
const onOpen = () => {
|
|
48
|
+
cleanup();
|
|
49
|
+
resume(Effect.void);
|
|
50
|
+
};
|
|
51
|
+
const onError = (event) => {
|
|
52
|
+
cleanup();
|
|
53
|
+
resume(Effect.fail(transportError("open", `Failed to open WebSocket: ${eventMessage(event)}`, { url: input.url, kind: "open" })));
|
|
54
|
+
};
|
|
55
|
+
const onClose = (event) => {
|
|
56
|
+
cleanup();
|
|
57
|
+
resume(Effect.fail(transportError("open", `WebSocket closed before opening with code ${event.code}`, {
|
|
58
|
+
url: input.url,
|
|
59
|
+
kind: "open",
|
|
60
|
+
})));
|
|
61
|
+
};
|
|
62
|
+
ws.addEventListener("open", onOpen, { once: true });
|
|
63
|
+
ws.addEventListener("error", onError, { once: true });
|
|
64
|
+
ws.addEventListener("close", onClose, { once: true });
|
|
65
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
66
|
+
});
|
|
67
|
+
};
|
|
68
|
+
const webSocketUrl = (value) => Effect.try({
|
|
69
|
+
try: () => {
|
|
70
|
+
const url = new URL(value);
|
|
71
|
+
if (url.protocol === "https:") {
|
|
72
|
+
url.protocol = "wss:";
|
|
73
|
+
return url.toString();
|
|
74
|
+
}
|
|
75
|
+
if (url.protocol === "http:") {
|
|
76
|
+
url.protocol = "ws:";
|
|
77
|
+
return url.toString();
|
|
78
|
+
}
|
|
79
|
+
throw new Error(`Unsupported WebSocket URL protocol ${url.protocol}`);
|
|
80
|
+
},
|
|
81
|
+
catch: (error) => transportError("prepare", error instanceof Error ? error.message : "Invalid WebSocket URL", {
|
|
82
|
+
url: value,
|
|
83
|
+
kind: "websocket",
|
|
84
|
+
}),
|
|
85
|
+
});
|
|
86
|
+
export const open = (input) => Effect.try({
|
|
87
|
+
try: () => new globalThis.WebSocket(input.url, { headers: input.headers }),
|
|
88
|
+
catch: (error) => transportError("open", error instanceof Error ? error.message : "Failed to construct WebSocket", {
|
|
89
|
+
url: input.url,
|
|
90
|
+
kind: "open",
|
|
91
|
+
}),
|
|
92
|
+
}).pipe(Effect.flatMap((ws) => fromWebSocket(ws, input)));
|
|
93
|
+
export const layer = Layer.succeed(Service, Service.of({ open }));
|
|
94
|
+
export const fromWebSocket = (ws, input) => Effect.gen(function* () {
|
|
95
|
+
yield* waitOpen(ws, input);
|
|
96
|
+
const messages = yield* Queue.bounded(128);
|
|
97
|
+
const onMessage = (event) => {
|
|
98
|
+
if (typeof event.data === "string")
|
|
99
|
+
return Queue.offerUnsafe(messages, event.data);
|
|
100
|
+
const binary = binaryMessage(event.data);
|
|
101
|
+
if (binary)
|
|
102
|
+
return Queue.offerUnsafe(messages, binary);
|
|
103
|
+
Queue.failCauseUnsafe(messages, Cause.fail(transportError("message", "Unsupported WebSocket message payload", { url: input.url, kind: "message" })));
|
|
104
|
+
};
|
|
105
|
+
const onError = (event) => {
|
|
106
|
+
Queue.failCauseUnsafe(messages, Cause.fail(transportError("message", `WebSocket error: ${eventMessage(event)}`, { url: input.url, kind: "message" })));
|
|
107
|
+
};
|
|
108
|
+
const onClose = (event) => {
|
|
109
|
+
if (event.code === 1000 || event.code === 1005)
|
|
110
|
+
return Queue.endUnsafe(messages);
|
|
111
|
+
Queue.failCauseUnsafe(messages, Cause.fail(transportError("message", `WebSocket closed with code ${event.code}`, { url: input.url, kind: "close" })));
|
|
112
|
+
};
|
|
113
|
+
const cleanup = Effect.sync(() => {
|
|
114
|
+
ws.removeEventListener("message", onMessage);
|
|
115
|
+
ws.removeEventListener("error", onError);
|
|
116
|
+
ws.removeEventListener("close", onClose);
|
|
117
|
+
}).pipe(Effect.andThen(Queue.shutdown(messages)));
|
|
118
|
+
ws.addEventListener("message", onMessage);
|
|
119
|
+
ws.addEventListener("error", onError);
|
|
120
|
+
ws.addEventListener("close", onClose);
|
|
121
|
+
return {
|
|
122
|
+
sendText: (message) => Effect.try({
|
|
123
|
+
try: () => ws.send(message),
|
|
124
|
+
catch: (error) => transportError("sendText", error instanceof Error ? error.message : "Failed to send WebSocket message", {
|
|
125
|
+
url: input.url,
|
|
126
|
+
kind: "write",
|
|
127
|
+
}),
|
|
128
|
+
}),
|
|
129
|
+
messages: Stream.fromQueue(messages),
|
|
130
|
+
close: cleanup.pipe(Effect.andThen(Effect.sync(() => {
|
|
131
|
+
if (ws.readyState === globalThis.WebSocket.CLOSED || ws.readyState === globalThis.WebSocket.CLOSING)
|
|
132
|
+
return;
|
|
133
|
+
ws.close(1000);
|
|
134
|
+
}))),
|
|
135
|
+
};
|
|
136
|
+
});
|
|
137
|
+
export const messageText = (message, decoder) => typeof message === "string" ? message : decoder.decode(message);
|
|
138
|
+
export const json = (input) => ({
|
|
139
|
+
id: "websocket-json",
|
|
140
|
+
with: (patch) => json({ ...input, ...patch }),
|
|
141
|
+
prepare: (prepareInput) => Effect.gen(function* () {
|
|
142
|
+
const parts = yield* HttpTransport.jsonRequestParts({
|
|
143
|
+
...prepareInput,
|
|
144
|
+
});
|
|
145
|
+
return {
|
|
146
|
+
url: yield* webSocketUrl(parts.url),
|
|
147
|
+
headers: parts.headers,
|
|
148
|
+
message: input.encodeMessage(yield* input.toMessage(parts.jsonBody)),
|
|
149
|
+
};
|
|
150
|
+
}),
|
|
151
|
+
frames: (prepared, _request, runtime) => {
|
|
152
|
+
const webSocket = runtime.webSocket;
|
|
153
|
+
if (!webSocket) {
|
|
154
|
+
return Stream.fail(transportError("json", "WebSocket JSON transport requires WebSocketExecutor.Service", {
|
|
155
|
+
url: prepared.url,
|
|
156
|
+
kind: "websocket",
|
|
157
|
+
}));
|
|
158
|
+
}
|
|
159
|
+
const decoder = new TextDecoder();
|
|
160
|
+
return Stream.unwrap(Effect.gen(function* () {
|
|
161
|
+
const connection = yield* Effect.acquireRelease(webSocket.open({ url: prepared.url, headers: prepared.headers }), (connection) => connection.close);
|
|
162
|
+
yield* connection.sendText(prepared.message);
|
|
163
|
+
return connection.messages.pipe(Stream.map((message) => messageText(message, decoder)));
|
|
164
|
+
}));
|
|
165
|
+
},
|
|
166
|
+
});
|
|
167
|
+
export const jsonTransport = {
|
|
168
|
+
id: "websocket-json",
|
|
169
|
+
with: json,
|
|
170
|
+
};
|
|
171
|
+
export const WebSocketExecutor = {
|
|
172
|
+
Service,
|
|
173
|
+
layer,
|
|
174
|
+
open,
|
|
175
|
+
fromWebSocket,
|
|
176
|
+
messageText,
|
|
177
|
+
};
|
|
178
|
+
export const WebSocketTransport = {
|
|
179
|
+
json,
|
|
180
|
+
jsonTransport,
|
|
181
|
+
};
|
package/dist/route.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./route/index";
|
package/dist/route.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./route/index";
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
export declare const ProviderFailureClassification: Schema.Literal<"context-overflow">;
|
|
3
|
+
export type ProviderFailureClassification = typeof ProviderFailureClassification.Type;
|
|
4
|
+
declare const HttpRequestDetails_base: Schema.Class<HttpRequestDetails, Schema.Struct<{
|
|
5
|
+
readonly method: Schema.String;
|
|
6
|
+
readonly url: Schema.String;
|
|
7
|
+
readonly headers: Schema.$Record<Schema.String, Schema.String>;
|
|
8
|
+
}>, {}>;
|
|
9
|
+
export declare class HttpRequestDetails extends HttpRequestDetails_base {
|
|
10
|
+
}
|
|
11
|
+
declare const HttpResponseDetails_base: Schema.Class<HttpResponseDetails, Schema.Struct<{
|
|
12
|
+
readonly status: Schema.Number;
|
|
13
|
+
readonly headers: Schema.$Record<Schema.String, Schema.String>;
|
|
14
|
+
}>, {}>;
|
|
15
|
+
export declare class HttpResponseDetails extends HttpResponseDetails_base {
|
|
16
|
+
}
|
|
17
|
+
declare const HttpRateLimitDetails_base: Schema.Class<HttpRateLimitDetails, Schema.Struct<{
|
|
18
|
+
readonly retryAfterMs: Schema.optional<Schema.Number>;
|
|
19
|
+
readonly limit: Schema.optional<Schema.$Record<Schema.String, Schema.String>>;
|
|
20
|
+
readonly remaining: Schema.optional<Schema.$Record<Schema.String, Schema.String>>;
|
|
21
|
+
readonly reset: Schema.optional<Schema.$Record<Schema.String, Schema.String>>;
|
|
22
|
+
}>, {}>;
|
|
23
|
+
export declare class HttpRateLimitDetails extends HttpRateLimitDetails_base {
|
|
24
|
+
}
|
|
25
|
+
declare const HttpContext_base: Schema.Class<HttpContext, Schema.Struct<{
|
|
26
|
+
readonly request: typeof HttpRequestDetails;
|
|
27
|
+
readonly response: Schema.optional<typeof HttpResponseDetails>;
|
|
28
|
+
readonly body: Schema.optional<Schema.String>;
|
|
29
|
+
readonly bodyTruncated: Schema.optional<Schema.Boolean>;
|
|
30
|
+
readonly requestId: Schema.optional<Schema.String>;
|
|
31
|
+
readonly rateLimit: Schema.optional<typeof HttpRateLimitDetails>;
|
|
32
|
+
}>, {}>;
|
|
33
|
+
export declare class HttpContext extends HttpContext_base {
|
|
34
|
+
}
|
|
35
|
+
declare const InvalidRequestReason_base: Schema.Class<InvalidRequestReason, Schema.Struct<{
|
|
36
|
+
readonly _tag: Schema.tag<"InvalidRequest">;
|
|
37
|
+
readonly message: Schema.String;
|
|
38
|
+
readonly parameter: Schema.optional<Schema.String>;
|
|
39
|
+
readonly classification: Schema.optional<Schema.Literal<"context-overflow">>;
|
|
40
|
+
readonly providerMetadata: Schema.optional<Schema.$Record<Schema.String, Schema.$Record<Schema.String, Schema.Unknown>>>;
|
|
41
|
+
readonly http: Schema.optional<typeof HttpContext>;
|
|
42
|
+
}>, {}>;
|
|
43
|
+
export declare class InvalidRequestReason extends InvalidRequestReason_base {
|
|
44
|
+
}
|
|
45
|
+
declare const NoRouteReason_base: Schema.Class<NoRouteReason, Schema.Struct<{
|
|
46
|
+
readonly _tag: Schema.tag<"NoRoute">;
|
|
47
|
+
readonly route: Schema.String;
|
|
48
|
+
readonly provider: Schema.brand<Schema.String, "LLM.ProviderID">;
|
|
49
|
+
readonly model: Schema.brand<Schema.String, "LLM.ModelID">;
|
|
50
|
+
}>, {}>;
|
|
51
|
+
export declare class NoRouteReason extends NoRouteReason_base {
|
|
52
|
+
get message(): string;
|
|
53
|
+
}
|
|
54
|
+
declare const AuthenticationReason_base: Schema.Class<AuthenticationReason, Schema.Struct<{
|
|
55
|
+
readonly _tag: Schema.tag<"Authentication">;
|
|
56
|
+
readonly message: Schema.String;
|
|
57
|
+
readonly kind: Schema.Literals<readonly ["missing", "invalid", "expired", "insufficient-permissions", "unknown"]>;
|
|
58
|
+
readonly providerMetadata: Schema.optional<Schema.$Record<Schema.String, Schema.$Record<Schema.String, Schema.Unknown>>>;
|
|
59
|
+
readonly http: Schema.optional<typeof HttpContext>;
|
|
60
|
+
}>, {}>;
|
|
61
|
+
export declare class AuthenticationReason extends AuthenticationReason_base {
|
|
62
|
+
}
|
|
63
|
+
declare const RateLimitReason_base: Schema.Class<RateLimitReason, Schema.Struct<{
|
|
64
|
+
readonly _tag: Schema.tag<"RateLimit">;
|
|
65
|
+
readonly message: Schema.String;
|
|
66
|
+
readonly retryAfterMs: Schema.optional<Schema.Number>;
|
|
67
|
+
readonly rateLimit: Schema.optional<typeof HttpRateLimitDetails>;
|
|
68
|
+
readonly providerMetadata: Schema.optional<Schema.$Record<Schema.String, Schema.$Record<Schema.String, Schema.Unknown>>>;
|
|
69
|
+
readonly http: Schema.optional<typeof HttpContext>;
|
|
70
|
+
}>, {}>;
|
|
71
|
+
export declare class RateLimitReason extends RateLimitReason_base {
|
|
72
|
+
}
|
|
73
|
+
declare const QuotaExceededReason_base: Schema.Class<QuotaExceededReason, Schema.Struct<{
|
|
74
|
+
readonly _tag: Schema.tag<"QuotaExceeded">;
|
|
75
|
+
readonly message: Schema.String;
|
|
76
|
+
readonly providerMetadata: Schema.optional<Schema.$Record<Schema.String, Schema.$Record<Schema.String, Schema.Unknown>>>;
|
|
77
|
+
readonly http: Schema.optional<typeof HttpContext>;
|
|
78
|
+
}>, {}>;
|
|
79
|
+
export declare class QuotaExceededReason extends QuotaExceededReason_base {
|
|
80
|
+
}
|
|
81
|
+
declare const ContentPolicyReason_base: Schema.Class<ContentPolicyReason, Schema.Struct<{
|
|
82
|
+
readonly _tag: Schema.tag<"ContentPolicy">;
|
|
83
|
+
readonly message: Schema.String;
|
|
84
|
+
readonly providerMetadata: Schema.optional<Schema.$Record<Schema.String, Schema.$Record<Schema.String, Schema.Unknown>>>;
|
|
85
|
+
readonly http: Schema.optional<typeof HttpContext>;
|
|
86
|
+
}>, {}>;
|
|
87
|
+
export declare class ContentPolicyReason extends ContentPolicyReason_base {
|
|
88
|
+
}
|
|
89
|
+
declare const ProviderInternalReason_base: Schema.Class<ProviderInternalReason, Schema.Struct<{
|
|
90
|
+
readonly _tag: Schema.tag<"ProviderInternal">;
|
|
91
|
+
readonly message: Schema.String;
|
|
92
|
+
readonly status: Schema.optional<Schema.Number>;
|
|
93
|
+
readonly retryAfterMs: Schema.optional<Schema.Number>;
|
|
94
|
+
readonly providerMetadata: Schema.optional<Schema.$Record<Schema.String, Schema.$Record<Schema.String, Schema.Unknown>>>;
|
|
95
|
+
readonly http: Schema.optional<typeof HttpContext>;
|
|
96
|
+
}>, {}>;
|
|
97
|
+
export declare class ProviderInternalReason extends ProviderInternalReason_base {
|
|
98
|
+
}
|
|
99
|
+
declare const TransportReason_base: Schema.Class<TransportReason, Schema.Struct<{
|
|
100
|
+
readonly _tag: Schema.tag<"Transport">;
|
|
101
|
+
readonly message: Schema.String;
|
|
102
|
+
readonly kind: Schema.optional<Schema.String>;
|
|
103
|
+
readonly url: Schema.optional<Schema.String>;
|
|
104
|
+
readonly http: Schema.optional<typeof HttpContext>;
|
|
105
|
+
}>, {}>;
|
|
106
|
+
export declare class TransportReason extends TransportReason_base {
|
|
107
|
+
}
|
|
108
|
+
declare const InvalidProviderOutputReason_base: Schema.Class<InvalidProviderOutputReason, Schema.Struct<{
|
|
109
|
+
readonly _tag: Schema.tag<"InvalidProviderOutput">;
|
|
110
|
+
readonly message: Schema.String;
|
|
111
|
+
readonly route: Schema.optional<Schema.String>;
|
|
112
|
+
readonly raw: Schema.optional<Schema.String>;
|
|
113
|
+
readonly providerMetadata: Schema.optional<Schema.$Record<Schema.String, Schema.$Record<Schema.String, Schema.Unknown>>>;
|
|
114
|
+
}>, {}>;
|
|
115
|
+
export declare class InvalidProviderOutputReason extends InvalidProviderOutputReason_base {
|
|
116
|
+
}
|
|
117
|
+
declare const UnknownProviderReason_base: Schema.Class<UnknownProviderReason, Schema.Struct<{
|
|
118
|
+
readonly _tag: Schema.tag<"UnknownProvider">;
|
|
119
|
+
readonly message: Schema.String;
|
|
120
|
+
readonly status: Schema.optional<Schema.Number>;
|
|
121
|
+
readonly providerMetadata: Schema.optional<Schema.$Record<Schema.String, Schema.$Record<Schema.String, Schema.Unknown>>>;
|
|
122
|
+
readonly http: Schema.optional<typeof HttpContext>;
|
|
123
|
+
}>, {}>;
|
|
124
|
+
export declare class UnknownProviderReason extends UnknownProviderReason_base {
|
|
125
|
+
}
|
|
126
|
+
export declare const LLMErrorReason: Schema.toTaggedUnion<"_tag", readonly [typeof InvalidRequestReason, typeof NoRouteReason, typeof AuthenticationReason, typeof RateLimitReason, typeof QuotaExceededReason, typeof ContentPolicyReason, typeof ProviderInternalReason, typeof TransportReason, typeof InvalidProviderOutputReason, typeof UnknownProviderReason]>;
|
|
127
|
+
export type LLMErrorReason = Schema.Schema.Type<typeof LLMErrorReason>;
|
|
128
|
+
declare const LLMError_base: Schema.Class<LLMError, Schema.TaggedStruct<"LLM.Error", {
|
|
129
|
+
readonly module: Schema.String;
|
|
130
|
+
readonly method: Schema.String;
|
|
131
|
+
readonly reason: Schema.toTaggedUnion<"_tag", readonly [typeof InvalidRequestReason, typeof NoRouteReason, typeof AuthenticationReason, typeof RateLimitReason, typeof QuotaExceededReason, typeof ContentPolicyReason, typeof ProviderInternalReason, typeof TransportReason, typeof InvalidProviderOutputReason, typeof UnknownProviderReason]>;
|
|
132
|
+
}>, import("effect/Cause").YieldableError>;
|
|
133
|
+
export declare class LLMError extends LLMError_base {
|
|
134
|
+
readonly cause: InvalidRequestReason | NoRouteReason | AuthenticationReason | RateLimitReason | QuotaExceededReason | ContentPolicyReason | ProviderInternalReason | TransportReason | InvalidProviderOutputReason | UnknownProviderReason;
|
|
135
|
+
get message(): string;
|
|
136
|
+
}
|
|
137
|
+
declare const ToolFailure_base: Schema.Class<ToolFailure, Schema.TaggedStruct<"LLM.ToolFailure", {
|
|
138
|
+
readonly message: Schema.String;
|
|
139
|
+
readonly error: Schema.optional<Schema.Defect>;
|
|
140
|
+
readonly metadata: Schema.optional<Schema.$Record<Schema.String, Schema.Unknown>>;
|
|
141
|
+
}>, import("effect/Cause").YieldableError>;
|
|
142
|
+
/**
|
|
143
|
+
* Failure type for tool execute handlers. Handlers must map their internal
|
|
144
|
+
* errors to this shape; the runtime catches `ToolFailure`s and surfaces them
|
|
145
|
+
* as `tool-error` events plus a `tool-result` of `type: "error"` so the model
|
|
146
|
+
* can self-correct.
|
|
147
|
+
*
|
|
148
|
+
* Anything thrown or yielded by a handler that is not a `ToolFailure` is
|
|
149
|
+
* treated as a defect and fails the stream.
|
|
150
|
+
*/
|
|
151
|
+
export declare class ToolFailure extends ToolFailure_base {
|
|
152
|
+
}
|
|
153
|
+
export {};
|