@opencode/ai 0.0.0-beta-19275
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 +682 -0
- package/dist/cache-policy.d.ts +2 -0
- package/dist/cache-policy.js +129 -0
- package/dist/image-client.d.ts +19 -0
- package/dist/image-client.js +28 -0
- package/dist/image.d.ts +110 -0
- package/dist/image.js +103 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +12 -0
- package/dist/llm.d.ts +252 -0
- package/dist/llm.js +74 -0
- package/dist/protocols/anthropic-messages.d.ts +957 -0
- package/dist/protocols/anthropic-messages.js +1414 -0
- package/dist/protocols/bedrock-converse.d.ts +499 -0
- package/dist/protocols/bedrock-converse.js +643 -0
- package/dist/protocols/bedrock-event-stream.d.ts +9 -0
- package/dist/protocols/bedrock-event-stream.js +97 -0
- package/dist/protocols/gemini.d.ts +285 -0
- package/dist/protocols/gemini.js +671 -0
- package/dist/protocols/google-images.d.ts +30 -0
- package/dist/protocols/google-images.js +181 -0
- package/dist/protocols/index.d.ts +12 -0
- package/dist/protocols/index.js +12 -0
- package/dist/protocols/meta-images.d.ts +26 -0
- package/dist/protocols/meta-images.js +89 -0
- package/dist/protocols/meta-messages.d.ts +350 -0
- package/dist/protocols/meta-messages.js +41 -0
- package/dist/protocols/meta-responses.d.ts +473 -0
- package/dist/protocols/meta-responses.js +173 -0
- package/dist/protocols/mistral-chat.d.ts +540 -0
- package/dist/protocols/mistral-chat.js +624 -0
- package/dist/protocols/open-responses-channel.d.ts +23 -0
- package/dist/protocols/open-responses-channel.js +141 -0
- package/dist/protocols/open-responses-continuation.d.ts +12 -0
- package/dist/protocols/open-responses-continuation.js +161 -0
- package/dist/protocols/open-responses.d.ts +1583 -0
- package/dist/protocols/open-responses.js +1206 -0
- package/dist/protocols/openai-chat.d.ts +860 -0
- package/dist/protocols/openai-chat.js +966 -0
- package/dist/protocols/openai-compatible-chat.d.ts +109 -0
- package/dist/protocols/openai-compatible-chat.js +19 -0
- package/dist/protocols/openai-compatible-responses.d.ts +172 -0
- package/dist/protocols/openai-compatible-responses.js +18 -0
- package/dist/protocols/openai-images.d.ts +32 -0
- package/dist/protocols/openai-images.js +183 -0
- package/dist/protocols/openai-responses.d.ts +1389 -0
- package/dist/protocols/openai-responses.js +260 -0
- package/dist/protocols/shared.d.ts +193 -0
- package/dist/protocols/shared.js +290 -0
- package/dist/protocols/utils/bedrock-auth.d.ts +60 -0
- package/dist/protocols/utils/bedrock-auth.js +85 -0
- package/dist/protocols/utils/bedrock-cache.d.ts +19 -0
- package/dist/protocols/utils/bedrock-cache.js +49 -0
- package/dist/protocols/utils/bedrock-media.d.ts +55 -0
- package/dist/protocols/utils/bedrock-media.js +73 -0
- package/dist/protocols/utils/cache.d.ts +6 -0
- package/dist/protocols/utils/cache.js +5 -0
- package/dist/protocols/utils/gemini-tool-schema.d.ts +2 -0
- package/dist/protocols/utils/gemini-tool-schema.js +103 -0
- package/dist/protocols/utils/image-input.d.ts +21 -0
- package/dist/protocols/utils/image-input.js +20 -0
- package/dist/protocols/utils/lifecycle.d.ts +24 -0
- package/dist/protocols/utils/lifecycle.js +72 -0
- package/dist/protocols/utils/meta-image.d.ts +2 -0
- package/dist/protocols/utils/meta-image.js +13 -0
- package/dist/protocols/utils/open-responses-options.d.ts +56 -0
- package/dist/protocols/utils/open-responses-options.js +61 -0
- package/dist/protocols/utils/openai-image.d.ts +5 -0
- package/dist/protocols/utils/openai-image.js +18 -0
- package/dist/protocols/utils/openai-options.d.ts +16 -0
- package/dist/protocols/utils/openai-options.js +14 -0
- package/dist/protocols/utils/partial-json-options.d.ts +62 -0
- package/dist/protocols/utils/partial-json-options.js +52 -0
- package/dist/protocols/utils/partial-json.d.ts +8 -0
- package/dist/protocols/utils/partial-json.js +279 -0
- package/dist/protocols/utils/responses-checkpoint.d.ts +4 -0
- package/dist/protocols/utils/responses-checkpoint.js +107 -0
- package/dist/protocols/utils/responses-compaction.d.ts +4 -0
- package/dist/protocols/utils/responses-compaction.js +129 -0
- package/dist/protocols/utils/responses-hosted-tools.d.ts +26 -0
- package/dist/protocols/utils/responses-hosted-tools.js +32 -0
- package/dist/protocols/utils/tool-schema.d.ts +8 -0
- package/dist/protocols/utils/tool-schema.js +54 -0
- package/dist/protocols/utils/tool-stream.d.ts +710 -0
- package/dist/protocols/utils/tool-stream.js +155 -0
- package/dist/protocols/xai-images.d.ts +26 -0
- package/dist/protocols/xai-images.js +106 -0
- package/dist/protocols/xai-responses.d.ts +250 -0
- package/dist/protocols/xai-responses.js +81 -0
- package/dist/protocols/zai-images.d.ts +22 -0
- package/dist/protocols/zai-images.js +79 -0
- package/dist/protocols.d.ts +1 -0
- package/dist/protocols.js +1 -0
- package/dist/provider-error.d.ts +15 -0
- package/dist/provider-error.js +125 -0
- package/dist/provider-package.d.ts +11 -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/mantle/chat.d.ts +2 -0
- package/dist/providers/amazon-bedrock/mantle/chat.js +1 -0
- package/dist/providers/amazon-bedrock/mantle/responses.d.ts +2 -0
- package/dist/providers/amazon-bedrock/mantle/responses.js +1 -0
- package/dist/providers/amazon-bedrock/mantle.d.ts +2 -0
- package/dist/providers/amazon-bedrock/mantle.js +1 -0
- package/dist/providers/amazon-bedrock-mantle.d.ts +371 -0
- package/dist/providers/amazon-bedrock-mantle.js +76 -0
- package/dist/providers/amazon-bedrock.d.ts +173 -0
- package/dist/providers/amazon-bedrock.js +41 -0
- package/dist/providers/anthropic-compatible.d.ts +304 -0
- package/dist/providers/anthropic-compatible.js +44 -0
- package/dist/providers/anthropic.d.ts +302 -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 +599 -0
- package/dist/providers/azure.js +115 -0
- package/dist/providers/baseten.d.ts +229 -0
- package/dist/providers/baseten.js +38 -0
- package/dist/providers/cerebras.d.ts +228 -0
- package/dist/providers/cerebras.js +40 -0
- package/dist/providers/cloudflare-ai-gateway.d.ts +238 -0
- package/dist/providers/cloudflare-ai-gateway.js +59 -0
- package/dist/providers/cloudflare-workers-ai.d.ts +232 -0
- package/dist/providers/cloudflare-workers-ai.js +45 -0
- package/dist/providers/deepinfra.d.ts +228 -0
- package/dist/providers/deepinfra.js +43 -0
- package/dist/providers/deepseek.d.ts +229 -0
- package/dist/providers/deepseek.js +41 -0
- package/dist/providers/fireworks.d.ts +229 -0
- package/dist/providers/fireworks.js +38 -0
- package/dist/providers/google-vertex/chat.d.ts +2 -0
- package/dist/providers/google-vertex/chat.js +1 -0
- package/dist/providers/google-vertex/gemini.d.ts +2 -0
- package/dist/providers/google-vertex/gemini.js +1 -0
- package/dist/providers/google-vertex/messages.d.ts +2 -0
- package/dist/providers/google-vertex/messages.js +1 -0
- package/dist/providers/google-vertex/responses.d.ts +2 -0
- package/dist/providers/google-vertex/responses.js +1 -0
- package/dist/providers/google-vertex-chat.d.ts +133 -0
- package/dist/providers/google-vertex-chat.js +55 -0
- package/dist/providers/google-vertex-messages.d.ts +301 -0
- package/dist/providers/google-vertex-messages.js +75 -0
- package/dist/providers/google-vertex-responses.d.ts +198 -0
- package/dist/providers/google-vertex-responses.js +56 -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 +120 -0
- package/dist/providers/google-vertex.js +92 -0
- package/dist/providers/google.d.ts +115 -0
- package/dist/providers/google.js +42 -0
- package/dist/providers/groq.d.ts +315 -0
- package/dist/providers/groq.js +81 -0
- package/dist/providers/index.d.ts +28 -0
- package/dist/providers/index.js +28 -0
- package/dist/providers/meta/chat.d.ts +2 -0
- package/dist/providers/meta/chat.js +1 -0
- package/dist/providers/meta/messages.d.ts +2 -0
- package/dist/providers/meta/messages.js +1 -0
- package/dist/providers/meta/responses.d.ts +2 -0
- package/dist/providers/meta/responses.js +1 -0
- package/dist/providers/meta.d.ts +631 -0
- package/dist/providers/meta.js +113 -0
- package/dist/providers/minimax/chat.d.ts +4 -0
- package/dist/providers/minimax/chat.js +8 -0
- package/dist/providers/minimax/messages.d.ts +1 -0
- package/dist/providers/minimax/messages.js +1 -0
- package/dist/providers/minimax/responses.d.ts +4 -0
- package/dist/providers/minimax/responses.js +8 -0
- package/dist/providers/minimax.d.ts +593 -0
- package/dist/providers/minimax.js +89 -0
- package/dist/providers/mistral.d.ts +208 -0
- package/dist/providers/mistral.js +28 -0
- package/dist/providers/open-responses-options.d.ts +6 -0
- package/dist/providers/open-responses-options.js +1 -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-responses.d.ts +196 -0
- package/dist/providers/openai-compatible-responses.js +32 -0
- package/dist/providers/openai-compatible.d.ts +131 -0
- package/dist/providers/openai-compatible.js +33 -0
- package/dist/providers/openai-options.d.ts +26 -0
- package/dist/providers/openai-options.js +41 -0
- package/dist/providers/openai.d.ts +405 -0
- package/dist/providers/openai.js +82 -0
- package/dist/providers/openrouter.d.ts +564 -0
- package/dist/providers/openrouter.js +114 -0
- package/dist/providers/togetherai.d.ts +228 -0
- package/dist/providers/togetherai.js +40 -0
- package/dist/providers/xai.d.ts +164 -0
- package/dist/providers/xai.js +84 -0
- package/dist/providers/zai.d.ts +24 -0
- package/dist/providers/zai.js +21 -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 +51 -0
- package/dist/route/auth.js +87 -0
- package/dist/route/client.d.ts +430 -0
- package/dist/route/client.js +304 -0
- package/dist/route/endpoint.d.ts +28 -0
- package/dist/route/endpoint.js +21 -0
- package/dist/route/executor.d.ts +27 -0
- package/dist/route/executor.js +183 -0
- package/dist/route/framing.d.ts +29 -0
- package/dist/route/framing.js +14 -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 +16 -0
- package/dist/route/transport/http.d.ts +34 -0
- package/dist/route/transport/http.js +68 -0
- package/dist/route/transport/index.d.ts +41 -0
- package/dist/route/transport/index.js +4 -0
- package/dist/route/transport/websocket-channel.d.ts +57 -0
- package/dist/route/transport/websocket-channel.js +1 -0
- package/dist/route/transport/websocket.d.ts +56 -0
- package/dist/route/transport/websocket.js +366 -0
- package/dist/route.d.ts +1 -0
- package/dist/route.js +1 -0
- package/dist/schema/errors.d.ts +158 -0
- package/dist/schema/errors.js +120 -0
- package/dist/schema/events.d.ts +8123 -0
- package/dist/schema/events.js +550 -0
- package/dist/schema/ids.d.ts +17 -0
- package/dist/schema/ids.js +10 -0
- package/dist/schema/index.d.ts +5 -0
- package/dist/schema/index.js +5 -0
- package/dist/schema/messages.d.ts +646 -0
- package/dist/schema/messages.js +301 -0
- package/dist/schema/options.d.ts +157 -0
- package/dist/schema/options.js +187 -0
- package/dist/testing.d.ts +1693 -0
- package/dist/testing.js +129 -0
- package/dist/tool-history.d.ts +2 -0
- package/dist/tool-history.js +84 -0
- package/dist/tool-runtime.d.ts +15 -0
- package/dist/tool-runtime.js +62 -0
- package/dist/tool.d.ts +136 -0
- package/dist/tool.js +66 -0
- package/dist/utils/record.d.ts +2 -0
- package/dist/utils/record.js +2 -0
- package/dist/utils/sanitize.d.ts +1 -0
- package/dist/utils/sanitize.js +12 -0
- package/package.json +48 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { Effect, Schema, Stream } from "effect";
|
|
2
|
+
import { Headers } from "effect/unstable/http";
|
|
3
|
+
import { Framing } from "../route/framing.js";
|
|
4
|
+
import { HttpTransport, WebSocketTransport, } from "../route/transport/index.js";
|
|
5
|
+
import * as ProviderShared from "./shared.js";
|
|
6
|
+
import { OpenResponses } from "./open-responses.js";
|
|
7
|
+
import { OpenResponsesContinuation } from "./open-responses-continuation.js";
|
|
8
|
+
const WebSocketResponseCreate = Schema.StructWithRest(Schema.Struct({ type: Schema.tag("response.create") }), [
|
|
9
|
+
Schema.Record(Schema.String, Schema.Unknown),
|
|
10
|
+
]);
|
|
11
|
+
const decodeMessage = ProviderShared.validateWith(Schema.decodeUnknownEffect(WebSocketResponseCreate));
|
|
12
|
+
const encodeMessage = Schema.encodeSync(Schema.fromJsonString(WebSocketResponseCreate));
|
|
13
|
+
const decodeEvent = Schema.decodeUnknownEffect(OpenResponses.protocol.stream.event);
|
|
14
|
+
const message = (body) => Effect.gen(function* () {
|
|
15
|
+
if (!ProviderShared.isRecord(body))
|
|
16
|
+
return yield* ProviderShared.invalidRequest("Open Responses WebSocket body must be a JSON object");
|
|
17
|
+
const { stream: _stream, stream_options: _streamOptions, background: _background, ...request } = body;
|
|
18
|
+
const decoded = yield* decodeMessage({ ...request, type: "response.create" });
|
|
19
|
+
return { request: decoded, message: encodeMessage(decoded) };
|
|
20
|
+
});
|
|
21
|
+
const driver = (options, body) => {
|
|
22
|
+
let responseID;
|
|
23
|
+
let terminal = false;
|
|
24
|
+
return {
|
|
25
|
+
create: () => Effect.sync(() => {
|
|
26
|
+
responseID = undefined;
|
|
27
|
+
terminal = false;
|
|
28
|
+
return { message: body, mode: "full" };
|
|
29
|
+
}),
|
|
30
|
+
observe: (_create, frame) => Effect.gen(function* () {
|
|
31
|
+
const event = yield* decodeEvent(frame).pipe(Effect.mapError((cause) => ProviderShared.eventError(options.id, `Invalid ${options.name} WebSocket event`, frame, cause)));
|
|
32
|
+
if (terminal)
|
|
33
|
+
return yield* ProviderShared.eventError(options.id, `${options.name} emitted ${event.type} after a terminal event`, frame);
|
|
34
|
+
if (event.type === "error") {
|
|
35
|
+
terminal = true;
|
|
36
|
+
yield* OpenResponses.decodeKnownErrorEvent(event).pipe(Effect.mapError((cause) => ProviderShared.eventError(options.id, `${options.name} returned a malformed error event`, frame, cause)));
|
|
37
|
+
return {
|
|
38
|
+
type: "provider-failure",
|
|
39
|
+
error: OpenResponses.providerFailure(event, `${options.name} stream error`, frame),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
if (event.type === "response.failed") {
|
|
43
|
+
terminal = true;
|
|
44
|
+
if (responseID && event.response?.id && event.response.id !== responseID)
|
|
45
|
+
return yield* ProviderShared.eventError(options.id, `${options.name} response ID changed during execution`, frame);
|
|
46
|
+
return {
|
|
47
|
+
type: "provider-failure",
|
|
48
|
+
error: OpenResponses.providerFailure(event, `${options.name} response failed`, frame),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
if (event.type === "response.created") {
|
|
52
|
+
const created = event.response?.id;
|
|
53
|
+
if (responseID)
|
|
54
|
+
return yield* ProviderShared.eventError(options.id, `${options.name} emitted duplicate response.created`, frame);
|
|
55
|
+
if (!created)
|
|
56
|
+
return yield* ProviderShared.eventError(options.id, `${options.name} response.created is missing response.id`, frame);
|
|
57
|
+
responseID = created;
|
|
58
|
+
return { type: "frame", frame };
|
|
59
|
+
}
|
|
60
|
+
// Keepalives and provider notifications carry no response state and may precede response.created.
|
|
61
|
+
if (!event.type.startsWith("response."))
|
|
62
|
+
return { type: "frame", frame };
|
|
63
|
+
if (!responseID)
|
|
64
|
+
return yield* ProviderShared.eventError(options.id, `${options.name} emitted ${event.type} before response.created`, frame);
|
|
65
|
+
if (event.response?.id && event.response.id !== responseID)
|
|
66
|
+
return yield* ProviderShared.eventError(options.id, `${options.name} response ID changed during execution`, frame);
|
|
67
|
+
if (event.type === "response.completed") {
|
|
68
|
+
terminal = true;
|
|
69
|
+
return { type: "completed", frame };
|
|
70
|
+
}
|
|
71
|
+
if (event.type === "response.incomplete") {
|
|
72
|
+
terminal = true;
|
|
73
|
+
return { type: "incomplete", frame };
|
|
74
|
+
}
|
|
75
|
+
return { type: "frame", frame };
|
|
76
|
+
}),
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
export const transport = (options) => {
|
|
80
|
+
const http = HttpTransport.sseJson.with();
|
|
81
|
+
return {
|
|
82
|
+
id: http.id,
|
|
83
|
+
prepare: (input) => Effect.gen(function* () {
|
|
84
|
+
const parts = yield* HttpTransport.jsonRequestParts(input);
|
|
85
|
+
const headers = Headers.remove(options.headers?.(parts.headers) ?? parts.headers, "content-length");
|
|
86
|
+
const channel = input.webSocket && (options.enabled?.(parts.url) ?? true)
|
|
87
|
+
? yield* Effect.gen(function* () {
|
|
88
|
+
const create = yield* message(parts.jsonBody);
|
|
89
|
+
const base = driver(options, create.message);
|
|
90
|
+
return {
|
|
91
|
+
url: yield* WebSocketTransport.toWebSocketUrl(options.url?.(parts.url) ?? parts.url),
|
|
92
|
+
headers,
|
|
93
|
+
rotateAfterMs: options.rotateAfterMs,
|
|
94
|
+
driver: OpenResponsesContinuation.driver({
|
|
95
|
+
id: options.id,
|
|
96
|
+
name: options.name,
|
|
97
|
+
request: create.request,
|
|
98
|
+
message: create.message,
|
|
99
|
+
base,
|
|
100
|
+
}),
|
|
101
|
+
};
|
|
102
|
+
})
|
|
103
|
+
: undefined;
|
|
104
|
+
return {
|
|
105
|
+
http: {
|
|
106
|
+
request: ProviderShared.jsonPost({ url: parts.url, body: parts.bodyText, headers: parts.headers }),
|
|
107
|
+
framing: Framing.sse,
|
|
108
|
+
middleware: input.middleware,
|
|
109
|
+
},
|
|
110
|
+
channel,
|
|
111
|
+
};
|
|
112
|
+
}),
|
|
113
|
+
execute: (prepared, request, runtime, executeOptions) => Effect.gen(function* () {
|
|
114
|
+
if (!executeOptions?.webSocket || !prepared.channel)
|
|
115
|
+
return yield* http.execute(prepared.http, request, runtime);
|
|
116
|
+
let fallbackHttp;
|
|
117
|
+
const exchange = {
|
|
118
|
+
id: request.id ?? "request",
|
|
119
|
+
connect: {
|
|
120
|
+
url: prepared.channel.url,
|
|
121
|
+
headers: prepared.channel.headers,
|
|
122
|
+
rotateAfterMs: prepared.channel.rotateAfterMs,
|
|
123
|
+
},
|
|
124
|
+
fallback: () => Stream.unwrap(http.execute(prepared.http, request, runtime).pipe(Effect.map((execution) => {
|
|
125
|
+
fallbackHttp = execution.http;
|
|
126
|
+
return execution.frames;
|
|
127
|
+
}))),
|
|
128
|
+
driver: prepared.channel.driver,
|
|
129
|
+
};
|
|
130
|
+
const execution = yield* executeOptions.webSocket.execute(exchange);
|
|
131
|
+
return {
|
|
132
|
+
frames: execution.frames,
|
|
133
|
+
complete: execution.complete,
|
|
134
|
+
get http() {
|
|
135
|
+
return fallbackHttp ?? execution.http;
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
}),
|
|
139
|
+
};
|
|
140
|
+
};
|
|
141
|
+
export const OpenResponsesChannel = { transport };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { WebSocketChannelDriver } from "../route/transport/index.js";
|
|
2
|
+
export interface DriverInput {
|
|
3
|
+
readonly id: string;
|
|
4
|
+
readonly name: string;
|
|
5
|
+
readonly request: Readonly<Record<string, unknown>>;
|
|
6
|
+
readonly message: string;
|
|
7
|
+
readonly base: WebSocketChannelDriver;
|
|
8
|
+
}
|
|
9
|
+
export declare const driver: (input: DriverInput) => WebSocketChannelDriver;
|
|
10
|
+
export declare const OpenResponsesContinuation: {
|
|
11
|
+
readonly driver: (input: DriverInput) => WebSocketChannelDriver;
|
|
12
|
+
};
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { AIError, TransportError } from "../schema/index.js";
|
|
2
|
+
import { Effect, Option, Schema } from "effect";
|
|
3
|
+
import * as ProviderShared from "./shared.js";
|
|
4
|
+
import { OpenResponses } from "./open-responses.js";
|
|
5
|
+
const PROTOCOL = "open-responses.websocket.v1";
|
|
6
|
+
const VERSION = 1;
|
|
7
|
+
const decodeEvent = Schema.decodeUnknownEffect(OpenResponses.protocol.stream.event);
|
|
8
|
+
const checkpointValue = (checkpoint) => {
|
|
9
|
+
if (checkpoint?.protocol !== PROTOCOL || !ProviderShared.isRecord(checkpoint.value))
|
|
10
|
+
return undefined;
|
|
11
|
+
if (checkpoint.value.version !== VERSION)
|
|
12
|
+
return undefined;
|
|
13
|
+
if (typeof checkpoint.value.responseID !== "string" || checkpoint.value.responseID.trim().length === 0)
|
|
14
|
+
return undefined;
|
|
15
|
+
if (!ProviderShared.isRecord(checkpoint.value.request) || !Array.isArray(checkpoint.value.output))
|
|
16
|
+
return undefined;
|
|
17
|
+
return {
|
|
18
|
+
version: VERSION,
|
|
19
|
+
responseID: checkpoint.value.responseID,
|
|
20
|
+
request: checkpoint.value.request,
|
|
21
|
+
output: checkpoint.value.output,
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
const canonical = (value) => {
|
|
25
|
+
if (value === undefined)
|
|
26
|
+
return "undefined";
|
|
27
|
+
if (Array.isArray(value))
|
|
28
|
+
return `[${value.map(canonical).join(",")}]`;
|
|
29
|
+
if (!ProviderShared.isRecord(value))
|
|
30
|
+
return ProviderShared.encodeJson(value);
|
|
31
|
+
return `{${Object.keys(value)
|
|
32
|
+
.filter((key) => value[key] !== undefined)
|
|
33
|
+
.sort()
|
|
34
|
+
.map((key) => `${ProviderShared.encodeJson(key)}:${canonical(value[key])}`)
|
|
35
|
+
.join(",")}}`;
|
|
36
|
+
};
|
|
37
|
+
const json = (value) => {
|
|
38
|
+
if (typeof value !== "string")
|
|
39
|
+
return value;
|
|
40
|
+
return Option.getOrElse(Schema.decodeUnknownOption(ProviderShared.Json)(value), () => value);
|
|
41
|
+
};
|
|
42
|
+
const comparable = (value) => {
|
|
43
|
+
if (!ProviderShared.isRecord(value))
|
|
44
|
+
return value;
|
|
45
|
+
if (value.type === "message" && value.role === "assistant")
|
|
46
|
+
return {
|
|
47
|
+
role: "assistant",
|
|
48
|
+
// Annotations and logprobs describe the response, not the text replayed in model input.
|
|
49
|
+
content: Array.isArray(value.content)
|
|
50
|
+
? value.content.map((part) => ProviderShared.isRecord(part) && part.type === "output_text" ? { type: part.type, text: part.text } : part)
|
|
51
|
+
: value.content,
|
|
52
|
+
...(value.phase === undefined ? {} : { phase: value.phase }),
|
|
53
|
+
};
|
|
54
|
+
if (value.type === "function_call")
|
|
55
|
+
return {
|
|
56
|
+
type: value.type,
|
|
57
|
+
call_id: value.call_id,
|
|
58
|
+
name: value.name,
|
|
59
|
+
arguments: json(value.arguments),
|
|
60
|
+
};
|
|
61
|
+
if (value.type === "reasoning")
|
|
62
|
+
return {
|
|
63
|
+
type: value.type,
|
|
64
|
+
summary: value.summary,
|
|
65
|
+
encrypted_content: value.encrypted_content,
|
|
66
|
+
};
|
|
67
|
+
return value;
|
|
68
|
+
};
|
|
69
|
+
const invariant = (request) => {
|
|
70
|
+
const { type: _type, input: _input, previous_response_id: _previousResponseID, ...rest } = request;
|
|
71
|
+
return rest;
|
|
72
|
+
};
|
|
73
|
+
const incremental = (request, checkpoint) => {
|
|
74
|
+
const input = request.input;
|
|
75
|
+
const previousInput = checkpoint.request.input;
|
|
76
|
+
if (!Array.isArray(input) || !Array.isArray(previousInput))
|
|
77
|
+
return undefined;
|
|
78
|
+
if (canonical(invariant(request)) !== canonical(invariant(checkpoint.request)))
|
|
79
|
+
return undefined;
|
|
80
|
+
const baseline = [...previousInput, ...checkpoint.output];
|
|
81
|
+
if (input.length <= baseline.length)
|
|
82
|
+
return undefined;
|
|
83
|
+
if (!baseline.every((item, index) => canonical(comparable(item)) === canonical(comparable(input[index]))))
|
|
84
|
+
return undefined;
|
|
85
|
+
return input.slice(baseline.length);
|
|
86
|
+
};
|
|
87
|
+
const code = (event) => event.code || event.error?.code || event.response?.error?.code || undefined;
|
|
88
|
+
const rejected = (observation, recovery) => ({
|
|
89
|
+
type: "rejected",
|
|
90
|
+
recovery,
|
|
91
|
+
error: new AIError({
|
|
92
|
+
reason: new TransportError({
|
|
93
|
+
message: observation.error.message,
|
|
94
|
+
body: observation.error.reason.body,
|
|
95
|
+
http: observation.error.reason.http,
|
|
96
|
+
cause: observation.error.reason.cause,
|
|
97
|
+
transport: "websocket",
|
|
98
|
+
operation: "read",
|
|
99
|
+
phase: "receive",
|
|
100
|
+
delivery: "rejected",
|
|
101
|
+
recovery,
|
|
102
|
+
}),
|
|
103
|
+
}),
|
|
104
|
+
});
|
|
105
|
+
export const driver = (input) => {
|
|
106
|
+
const { previous_response_id: _previousResponseID, ...request } = input.request;
|
|
107
|
+
let output = [];
|
|
108
|
+
return {
|
|
109
|
+
create: (checkpoint) => Effect.sync(() => {
|
|
110
|
+
output = [];
|
|
111
|
+
const previous = checkpointValue(checkpoint);
|
|
112
|
+
const delta = previous ? incremental(request, previous) : undefined;
|
|
113
|
+
if (!previous || !delta)
|
|
114
|
+
return { message: ProviderShared.encodeJson(request), mode: "full" };
|
|
115
|
+
return {
|
|
116
|
+
message: ProviderShared.encodeJson({ ...request, input: delta, previous_response_id: previous.responseID }),
|
|
117
|
+
mode: "incremental",
|
|
118
|
+
};
|
|
119
|
+
}),
|
|
120
|
+
observe: (create, frame) => Effect.gen(function* () {
|
|
121
|
+
const event = yield* decodeEvent(frame).pipe(Effect.mapError((cause) => ProviderShared.eventError(input.id, `Invalid ${input.name} WebSocket event`, frame, cause)));
|
|
122
|
+
const observation = yield* input.base.observe(create, frame);
|
|
123
|
+
if (event.type === "response.output_item.done" && event.item)
|
|
124
|
+
output.push(event.item);
|
|
125
|
+
if (observation.type === "provider-failure") {
|
|
126
|
+
const rejection = code(event);
|
|
127
|
+
if (rejection === "previous_response_not_found")
|
|
128
|
+
return rejected(observation, "retry-full");
|
|
129
|
+
if (rejection === "websocket_connection_limit_reached")
|
|
130
|
+
return rejected(observation, "rotate-and-retry-full");
|
|
131
|
+
}
|
|
132
|
+
if (observation.type !== "completed")
|
|
133
|
+
return observation;
|
|
134
|
+
// A trigger installs a different context window. Clear the append baseline, retaining the socket.
|
|
135
|
+
if (Array.isArray(request.input) &&
|
|
136
|
+
request.input.some((item) => ProviderShared.isRecord(item) && item.type === "compaction_trigger"))
|
|
137
|
+
return observation;
|
|
138
|
+
const responseID = event.response?.id;
|
|
139
|
+
if (!responseID || responseID.trim().length === 0)
|
|
140
|
+
return observation;
|
|
141
|
+
return {
|
|
142
|
+
...observation,
|
|
143
|
+
checkpoint: {
|
|
144
|
+
protocol: PROTOCOL,
|
|
145
|
+
value: {
|
|
146
|
+
version: VERSION,
|
|
147
|
+
responseID,
|
|
148
|
+
request,
|
|
149
|
+
// Completion can re-encrypt reasoning. Callers replay the item already emitted by output_item.done.
|
|
150
|
+
output: event.response?.output
|
|
151
|
+
? event.response.output.map((item) => item.type === "reasoning" && item.id !== undefined
|
|
152
|
+
? (output.find((done) => done.type === item.type && done.id === item.id) ?? item)
|
|
153
|
+
: item)
|
|
154
|
+
: output.slice(),
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
}),
|
|
159
|
+
};
|
|
160
|
+
};
|
|
161
|
+
export const OpenResponsesContinuation = { driver };
|