soraacode 0.1.7 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/bin/soraacode.exe +10 -0
- package/package.json +17 -114
- package/{script/postinstall.mjs → postinstall.mjs} +5 -5
- package/AGENTS.md +0 -131
- package/Dockerfile +0 -18
- package/README.md +0 -15
- package/bin/opencode +0 -199
- package/bin/soraacode +0 -199
- package/bunfig.toml +0 -7
- package/git +0 -0
- package/migration/20260511173437_session-metadata/migration.sql +0 -1
- package/migration/20260511173437_session-metadata/snapshot.json +0 -1500
- package/parsers-config.ts +0 -1
- package/script/bench-search.ts +0 -94
- package/script/bench-test-suite.ts +0 -52
- package/script/build-headless.ts +0 -51
- package/script/build.ts +0 -245
- package/script/generate.ts +0 -14
- package/script/httpapi-exercise.ts +0 -1
- package/script/profile-test-files.ts +0 -42
- package/script/publish.ts +0 -213
- package/script/run-workspace-server +0 -106
- package/script/schema.ts +0 -77
- package/script/time.ts +0 -6
- package/script/trace-imports.ts +0 -153
- package/specs/effect/error-boundaries-plan.md +0 -235
- package/specs/effect/errors.md +0 -207
- package/specs/effect/facades.md +0 -218
- package/specs/effect/guide.md +0 -247
- package/specs/effect/instance-context.md +0 -13
- package/specs/effect/loose-ends.md +0 -30
- package/specs/effect/migration.md +0 -62
- package/specs/effect/routes.md +0 -61
- package/specs/effect/schema.md +0 -88
- package/specs/effect/server-package.md +0 -58
- package/specs/effect/todo.md +0 -241
- package/specs/effect/tools.md +0 -88
- package/specs/openapi-translation-cleanup.md +0 -204
- package/specs/tui-plugins.md +0 -544
- package/specs/v2/api.ts +0 -67
- package/specs/v2/message-shape.md +0 -136
- package/specs/v2/notifications.md +0 -13
- package/specs/v2/tui-command-shim.md +0 -67
- package/src/account/account.ts +0 -481
- package/src/account/repo.ts +0 -171
- package/src/account/schema.ts +0 -99
- package/src/account/url.ts +0 -8
- package/src/acp/agent.ts +0 -95
- package/src/acp/config-option.ts +0 -206
- package/src/acp/content.ts +0 -269
- package/src/acp/directory.ts +0 -212
- package/src/acp/error.ts +0 -97
- package/src/acp/event.ts +0 -421
- package/src/acp/permission.ts +0 -254
- package/src/acp/profile.ts +0 -42
- package/src/acp/service.ts +0 -1226
- package/src/acp/session.ts +0 -232
- package/src/acp/tool.ts +0 -364
- package/src/acp/usage.ts +0 -243
- package/src/agent/agent.ts +0 -450
- package/src/agent/generate.txt +0 -75
- package/src/agent/prompt/compaction.txt +0 -5
- package/src/agent/prompt/explore.txt +0 -18
- package/src/agent/prompt/summary.txt +0 -11
- package/src/agent/prompt/title.txt +0 -44
- package/src/agent/subagent-permissions.ts +0 -27
- package/src/audio.d.ts +0 -14
- package/src/auth/index.ts +0 -97
- package/src/background/job.ts +0 -37
- package/src/bus/global.ts +0 -22
- package/src/cli/bootstrap.ts +0 -11
- package/src/cli/cmd/cmd.ts +0 -7
- package/src/cli/cmd/serve.ts +0 -24
- package/src/cli/effect/prompt.ts +0 -37
- package/src/cli/effect-cmd.ts +0 -96
- package/src/cli/error.ts +0 -130
- package/src/cli/heap.ts +0 -45
- package/src/cli/logo.ts +0 -2
- package/src/cli/network.ts +0 -80
- package/src/cli/ui.ts +0 -132
- package/src/command/index.ts +0 -177
- package/src/command/template/initialize.txt +0 -66
- package/src/command/template/review.txt +0 -101
- package/src/config/agent.ts +0 -59
- package/src/config/command.ts +0 -39
- package/src/config/config.ts +0 -707
- package/src/config/entry-name.ts +0 -19
- package/src/config/managed.ts +0 -69
- package/src/config/markdown.ts +0 -36
- package/src/config/parse.ts +0 -61
- package/src/config/paths.ts +0 -45
- package/src/config/plugin.ts +0 -79
- package/src/config/v2-compat.ts +0 -449
- package/src/config/variable.ts +0 -91
- package/src/control-plane/adapters/index.ts +0 -41
- package/src/control-plane/adapters/worktree.ts +0 -96
- package/src/control-plane/dev/README.md +0 -19
- package/src/control-plane/dev/debug-workspace-plugin.ts +0 -73
- package/src/control-plane/types.ts +0 -59
- package/src/control-plane/util.ts +0 -39
- package/src/control-plane/workspace-adapter-runtime.ts +0 -51
- package/src/control-plane/workspace-context.ts +0 -26
- package/src/control-plane/workspace.ts +0 -966
- package/src/effect/app-node-builder-v1.ts +0 -12
- package/src/effect/app-runtime.ts +0 -135
- package/src/effect/bootstrap-runtime.ts +0 -19
- package/src/effect/bridge.ts +0 -84
- package/src/effect/config-service.ts +0 -67
- package/src/effect/instance-ref.ts +0 -11
- package/src/effect/instance-registry.ts +0 -12
- package/src/effect/instance-state.ts +0 -69
- package/src/effect/promise.ts +0 -17
- package/src/effect/run-service.ts +0 -47
- package/src/effect/runner.ts +0 -217
- package/src/effect/runtime-flags.ts +0 -78
- package/src/env/index.ts +0 -41
- package/src/event-manifest.ts +0 -3
- package/src/event-v2-bridge.ts +0 -71
- package/src/format/formatter.ts +0 -404
- package/src/format/index.ts +0 -203
- package/src/git/index.ts +0 -348
- package/src/id/id.ts +0 -80
- package/src/ide/index.ts +0 -54
- package/src/image/image.ts +0 -172
- package/src/index-headless.ts +0 -89
- package/src/index.ts +0 -93
- package/src/installation/index.ts +0 -336
- package/src/lsp/client.ts +0 -650
- package/src/lsp/diagnostic.ts +0 -29
- package/src/lsp/language.ts +0 -121
- package/src/lsp/launch.ts +0 -21
- package/src/lsp/lsp.ts +0 -507
- package/src/lsp/server.ts +0 -1983
- package/src/markdown.d.ts +0 -4
- package/src/mcp/auth.ts +0 -163
- package/src/mcp/browser.ts +0 -37
- package/src/mcp/catalog.ts +0 -170
- package/src/mcp/index.ts +0 -1004
- package/src/mcp/oauth-callback.ts +0 -194
- package/src/mcp/oauth-provider.ts +0 -259
- package/src/node.ts +0 -4
- package/src/patch/index.ts +0 -686
- package/src/permission/arity.ts +0 -163
- package/src/permission/evaluate.ts +0 -1
- package/src/permission/index.ts +0 -223
- package/src/plugin/github-copilot/copilot.ts +0 -415
- package/src/plugin/github-copilot/models.ts +0 -261
- package/src/plugin/index.ts +0 -298
- package/src/plugin/install.ts +0 -439
- package/src/plugin/loader.ts +0 -237
- package/src/plugin/meta.ts +0 -188
- package/src/plugin/openai/README.md +0 -31
- package/src/plugin/openai/codex.ts +0 -575
- package/src/plugin/openai/ws-pool.ts +0 -271
- package/src/plugin/openai/ws.ts +0 -383
- package/src/plugin/pty-environment.ts +0 -24
- package/src/plugin/shared.ts +0 -323
- package/src/project/bootstrap-service.ts +0 -9
- package/src/project/bootstrap.ts +0 -58
- package/src/project/instance-context.ts +0 -24
- package/src/project/instance-runtime.ts +0 -16
- package/src/project/instance-store.ts +0 -213
- package/src/project/project.ts +0 -483
- package/src/project/vcs.ts +0 -423
- package/src/provider/auth.ts +0 -229
- package/src/provider/error.ts +0 -195
- package/src/provider/model-status.ts +0 -8
- package/src/provider/provider.ts +0 -1955
- package/src/provider/transform.ts +0 -1923
- package/src/question/index.ts +0 -161
- package/src/question/schema.ts +0 -4
- package/src/server/auth.ts +0 -48
- package/src/server/event.ts +0 -10
- package/src/server/global-lifecycle.ts +0 -28
- package/src/server/mdns.ts +0 -47
- package/src/server/proxy-util.ts +0 -48
- package/src/server/routes/instance/httpapi/AGENTS.md +0 -39
- package/src/server/routes/instance/httpapi/api.ts +0 -97
- package/src/server/routes/instance/httpapi/errors.ts +0 -193
- package/src/server/routes/instance/httpapi/groups/config.ts +0 -65
- package/src/server/routes/instance/httpapi/groups/control-plane.ts +0 -35
- package/src/server/routes/instance/httpapi/groups/control.ts +0 -76
- package/src/server/routes/instance/httpapi/groups/event.ts +0 -29
- package/src/server/routes/instance/httpapi/groups/experimental.ts +0 -275
- package/src/server/routes/instance/httpapi/groups/file.ts +0 -185
- package/src/server/routes/instance/httpapi/groups/global.ts +0 -139
- package/src/server/routes/instance/httpapi/groups/instance.ts +0 -206
- package/src/server/routes/instance/httpapi/groups/mcp.ts +0 -156
- package/src/server/routes/instance/httpapi/groups/metadata.ts +0 -18
- package/src/server/routes/instance/httpapi/groups/permission.ts +0 -61
- package/src/server/routes/instance/httpapi/groups/project-copy.ts +0 -32
- package/src/server/routes/instance/httpapi/groups/project.ts +0 -93
- package/src/server/routes/instance/httpapi/groups/provider.ts +0 -101
- package/src/server/routes/instance/httpapi/groups/pty.ts +0 -172
- package/src/server/routes/instance/httpapi/groups/query.ts +0 -12
- package/src/server/routes/instance/httpapi/groups/question.ts +0 -74
- package/src/server/routes/instance/httpapi/groups/session.ts +0 -462
- package/src/server/routes/instance/httpapi/groups/sync.ts +0 -113
- package/src/server/routes/instance/httpapi/groups/tui.ts +0 -208
- package/src/server/routes/instance/httpapi/groups/workspace.ts +0 -141
- package/src/server/routes/instance/httpapi/handlers/config.ts +0 -34
- package/src/server/routes/instance/httpapi/handlers/control-plane.ts +0 -37
- package/src/server/routes/instance/httpapi/handlers/control.ts +0 -43
- package/src/server/routes/instance/httpapi/handlers/event.ts +0 -99
- package/src/server/routes/instance/httpapi/handlers/experimental.ts +0 -193
- package/src/server/routes/instance/httpapi/handlers/file.ts +0 -139
- package/src/server/routes/instance/httpapi/handlers/global.ts +0 -126
- package/src/server/routes/instance/httpapi/handlers/instance.ts +0 -110
- package/src/server/routes/instance/httpapi/handlers/mcp.ts +0 -111
- package/src/server/routes/instance/httpapi/handlers/permission.ts +0 -41
- package/src/server/routes/instance/httpapi/handlers/project-copy.ts +0 -83
- package/src/server/routes/instance/httpapi/handlers/project.ts +0 -63
- package/src/server/routes/instance/httpapi/handlers/provider.ts +0 -116
- package/src/server/routes/instance/httpapi/handlers/pty.ts +0 -273
- package/src/server/routes/instance/httpapi/handlers/question.ts +0 -54
- package/src/server/routes/instance/httpapi/handlers/session-errors.ts +0 -21
- package/src/server/routes/instance/httpapi/handlers/session.ts +0 -442
- package/src/server/routes/instance/httpapi/handlers/sync.ts +0 -89
- package/src/server/routes/instance/httpapi/handlers/tui.ts +0 -131
- package/src/server/routes/instance/httpapi/handlers/workspace.ts +0 -102
- package/src/server/routes/instance/httpapi/lifecycle.ts +0 -54
- package/src/server/routes/instance/httpapi/middleware/authorization.ts +0 -150
- package/src/server/routes/instance/httpapi/middleware/compression.ts +0 -64
- package/src/server/routes/instance/httpapi/middleware/cors-vary.ts +0 -29
- package/src/server/routes/instance/httpapi/middleware/error.ts +0 -44
- package/src/server/routes/instance/httpapi/middleware/fence.ts +0 -25
- package/src/server/routes/instance/httpapi/middleware/instance-context.ts +0 -43
- package/src/server/routes/instance/httpapi/middleware/proxy.ts +0 -131
- package/src/server/routes/instance/httpapi/middleware/schema-error.ts +0 -41
- package/src/server/routes/instance/httpapi/middleware/workspace-routing.ts +0 -250
- package/src/server/routes/instance/httpapi/public.ts +0 -537
- package/src/server/routes/instance/httpapi/server.ts +0 -325
- package/src/server/routes/instance/httpapi/websocket-tracker.ts +0 -60
- package/src/server/server.ts +0 -224
- package/src/server/shared/fence.ts +0 -60
- package/src/server/shared/pty-ticket.ts +0 -15
- package/src/server/shared/public-ui.ts +0 -12
- package/src/server/shared/tui-control.ts +0 -28
- package/src/server/shared/ui.ts +0 -108
- package/src/server/shared/workspace-routing.ts +0 -45
- package/src/server/tui-event.ts +0 -1
- package/src/session/compaction.ts +0 -608
- package/src/session/instruction.ts +0 -237
- package/src/session/llm/AGENTS.md +0 -90
- package/src/session/llm/ai-sdk.ts +0 -291
- package/src/session/llm/native-request.ts +0 -196
- package/src/session/llm/native-runtime.ts +0 -195
- package/src/session/llm/request.ts +0 -226
- package/src/session/llm.ts +0 -390
- package/src/session/message-error.ts +0 -14
- package/src/session/message-v2.ts +0 -742
- package/src/session/message.ts +0 -148
- package/src/session/overflow.ts +0 -34
- package/src/session/processor.ts +0 -732
- package/src/session/prompt/build-switch.txt +0 -5
- package/src/session/prompt/default.txt +0 -35
- package/src/session/prompt/plan-mode.txt +0 -70
- package/src/session/prompt/plan.txt +0 -26
- package/src/session/prompt.ts +0 -1631
- package/src/session/reminders.ts +0 -92
- package/src/session/retry.ts +0 -209
- package/src/session/revert.ts +0 -136
- package/src/session/run-state.ts +0 -151
- package/src/session/schema.ts +0 -26
- package/src/session/session.ts +0 -1016
- package/src/session/status.ts +0 -56
- package/src/session/summary.ts +0 -160
- package/src/session/system.ts +0 -123
- package/src/session/todo.ts +0 -74
- package/src/session/tools.ts +0 -590
- package/src/share/session.ts +0 -58
- package/src/share/share-next.ts +0 -371
- package/src/skill/discovery.ts +0 -140
- package/src/skill/index.ts +0 -354
- package/src/snapshot/index.ts +0 -807
- package/src/sql.d.ts +0 -4
- package/src/storage/schema.ts +0 -5
- package/src/storage/storage.ts +0 -327
- package/src/sync/README.md +0 -179
- package/src/sync/schema.ts +0 -11
- package/src/temporary.ts +0 -31
- package/src/tool/apply_patch.ts +0 -313
- package/src/tool/apply_patch.txt +0 -14
- package/src/tool/code-mode.ts +0 -310
- package/src/tool/edit.ts +0 -737
- package/src/tool/edit.txt +0 -13
- package/src/tool/external-directory.ts +0 -49
- package/src/tool/glob.ts +0 -76
- package/src/tool/glob.txt +0 -7
- package/src/tool/grep.ts +0 -115
- package/src/tool/grep.txt +0 -7
- package/src/tool/invalid.ts +0 -21
- package/src/tool/json-schema.ts +0 -164
- package/src/tool/lsp.ts +0 -113
- package/src/tool/lsp.txt +0 -1
- package/src/tool/mcp-websearch.ts +0 -96
- package/src/tool/plan-enter.txt +0 -1
- package/src/tool/plan-exit.txt +0 -1
- package/src/tool/plan.ts +0 -79
- package/src/tool/question.ts +0 -44
- package/src/tool/question.txt +0 -1
- package/src/tool/read.ts +0 -386
- package/src/tool/read.txt +0 -13
- package/src/tool/registry.ts +0 -455
- package/src/tool/schema.ts +0 -14
- package/src/tool/shell/id.ts +0 -19
- package/src/tool/shell/prompt.ts +0 -293
- package/src/tool/shell/shell.txt +0 -21
- package/src/tool/shell.ts +0 -645
- package/src/tool/skill.ts +0 -70
- package/src/tool/skill.txt +0 -1
- package/src/tool/task.ts +0 -371
- package/src/tool/task.txt +0 -11
- package/src/tool/todo.ts +0 -46
- package/src/tool/todowrite.txt +0 -11
- package/src/tool/tool.ts +0 -183
- package/src/tool/truncate.ts +0 -156
- package/src/tool/truncation-dir.ts +0 -4
- package/src/tool/webfetch.ts +0 -192
- package/src/tool/webfetch.txt +0 -9
- package/src/tool/websearch.ts +0 -143
- package/src/tool/websearch.txt +0 -9
- package/src/tool/write.ts +0 -104
- package/src/tool/write.txt +0 -11
- package/src/util/archive.ts +0 -17
- package/src/util/bom.ts +0 -27
- package/src/util/data-url.ts +0 -9
- package/src/util/defer.ts +0 -10
- package/src/util/effect-http-client.ts +0 -11
- package/src/util/error.ts +0 -16
- package/src/util/filesystem.ts +0 -251
- package/src/util/html.ts +0 -8
- package/src/util/iife.ts +0 -3
- package/src/util/lazy.ts +0 -20
- package/src/util/local-context.ts +0 -25
- package/src/util/locale.ts +0 -4
- package/src/util/media.ts +0 -26
- package/src/util/process.ts +0 -177
- package/src/util/proxy-env.ts +0 -72
- package/src/util/queue.ts +0 -32
- package/src/util/record.ts +0 -3
- package/src/util/repository.ts +0 -232
- package/src/util/rpc.ts +0 -66
- package/src/util/signal.ts +0 -12
- package/src/util/timeout.ts +0 -13
- package/src/util/token.ts +0 -1
- package/src/util/wildcard.ts +0 -59
- package/src/worktree/index.ts +0 -623
- package/sst-env.d.ts +0 -10
- package/tsconfig.headless.json +0 -13
- package/tsconfig.json +0 -16
|
@@ -1,271 +0,0 @@
|
|
|
1
|
-
import WebSocket from "ws"
|
|
2
|
-
import { ProviderError } from "@/provider/error"
|
|
3
|
-
import { isRecord } from "@/util/record"
|
|
4
|
-
import { OpenAIWebSocket } from "./ws"
|
|
5
|
-
|
|
6
|
-
export const TITLE_HEADER = "x-opencode-title"
|
|
7
|
-
|
|
8
|
-
export interface CreateWebSocketFetchOptions {
|
|
9
|
-
httpFetch?: typeof globalThis.fetch
|
|
10
|
-
url?: string
|
|
11
|
-
connectTimeout?: number
|
|
12
|
-
idleTimeout?: number
|
|
13
|
-
maxConnectionAge?: number
|
|
14
|
-
streamRetries?: number
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
interface PoolEntry {
|
|
18
|
-
socket?: WebSocket
|
|
19
|
-
connectedAt?: number
|
|
20
|
-
lastUsedAt: number
|
|
21
|
-
busy: boolean
|
|
22
|
-
fallback: boolean
|
|
23
|
-
streamFailures: number
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const DEFAULT_CONNECT_TIMEOUT = 15_000
|
|
27
|
-
const DEFAULT_IDLE_TIMEOUT = 5 * 60 * 1000
|
|
28
|
-
const DEFAULT_MAX_CONNECTION_AGE = 55 * 60 * 1000
|
|
29
|
-
const CONNECTION_LIMIT_REACHED_CODE = "websocket_connection_limit_reached"
|
|
30
|
-
|
|
31
|
-
export function createWebSocketFetch(options?: CreateWebSocketFetchOptions) {
|
|
32
|
-
const httpFetch = options?.httpFetch ?? globalThis.fetch
|
|
33
|
-
const pool = new Map<string, PoolEntry>()
|
|
34
|
-
const connectTimeout = options?.connectTimeout ?? DEFAULT_CONNECT_TIMEOUT
|
|
35
|
-
const idleTimeout = options?.idleTimeout ?? DEFAULT_IDLE_TIMEOUT
|
|
36
|
-
const maxConnectionAge = options?.maxConnectionAge ?? DEFAULT_MAX_CONNECTION_AGE
|
|
37
|
-
const streamRetries = options?.streamRetries ?? 5
|
|
38
|
-
const pruneTimer = setInterval(() => prune(), Math.min(idleTimeout, 60_000))
|
|
39
|
-
if (typeof pruneTimer === "object" && "unref" in pruneTimer && typeof pruneTimer.unref === "function") {
|
|
40
|
-
pruneTimer.unref()
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
async function websocketFetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response> {
|
|
44
|
-
const url = input instanceof URL ? input.toString() : typeof input === "string" ? input : input.url
|
|
45
|
-
const internalHeaders = OpenAIWebSocket.normalizeHeaders(init?.headers)
|
|
46
|
-
const httpInit = withoutInternalHeaders(init)
|
|
47
|
-
|
|
48
|
-
if (init?.method !== "POST" || !new URL(url).pathname.endsWith("/responses")) {
|
|
49
|
-
return httpFetch(input, httpInit)
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const body = (() => {
|
|
53
|
-
try {
|
|
54
|
-
if (typeof init?.body !== "string") return undefined
|
|
55
|
-
const parsed = JSON.parse(init.body)
|
|
56
|
-
return typeof parsed === "object" && parsed !== null ? parsed : undefined
|
|
57
|
-
} catch {
|
|
58
|
-
return undefined
|
|
59
|
-
}
|
|
60
|
-
})()
|
|
61
|
-
if (!body?.stream) return httpFetch(input, httpInit)
|
|
62
|
-
if (internalHeaders[TITLE_HEADER] === "true") {
|
|
63
|
-
return httpFetch(input, httpInit)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const sessionID = internalHeaders["x-session-affinity"] ?? internalHeaders["session-id"]
|
|
67
|
-
if (!sessionID) {
|
|
68
|
-
return httpFetch(input, httpInit)
|
|
69
|
-
}
|
|
70
|
-
const key = `${sessionID}:conversation`
|
|
71
|
-
|
|
72
|
-
const entry = pool.get(key) ?? { lastUsedAt: Date.now(), busy: false, fallback: false, streamFailures: 0 }
|
|
73
|
-
pool.set(key, entry)
|
|
74
|
-
|
|
75
|
-
if (entry.fallback) {
|
|
76
|
-
return httpFetch(input, httpInit)
|
|
77
|
-
}
|
|
78
|
-
if (entry.busy) {
|
|
79
|
-
return httpFetch(input, httpInit)
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
entry.busy = true
|
|
83
|
-
entry.lastUsedAt = Date.now()
|
|
84
|
-
try {
|
|
85
|
-
entry.socket = await socket(
|
|
86
|
-
entry,
|
|
87
|
-
options?.url ?? url,
|
|
88
|
-
OpenAIWebSocket.normalizeHeaders(httpInit?.headers),
|
|
89
|
-
connectTimeout,
|
|
90
|
-
maxConnectionAge,
|
|
91
|
-
init?.signal,
|
|
92
|
-
)
|
|
93
|
-
let resolveFirstEvent: (event: boolean | OpenAIWebSocket.WrappedError) => void = () => {}
|
|
94
|
-
let rejectFirstEvent: (error: Error) => void = () => {}
|
|
95
|
-
const firstEvent = new Promise<boolean | OpenAIWebSocket.WrappedError>((resolve, reject) => {
|
|
96
|
-
resolveFirstEvent = resolve
|
|
97
|
-
rejectFirstEvent = reject
|
|
98
|
-
})
|
|
99
|
-
const response = OpenAIWebSocket.streamResponsesWebSocket({
|
|
100
|
-
socket: entry.socket,
|
|
101
|
-
body,
|
|
102
|
-
idleTimeout,
|
|
103
|
-
signal: init?.signal ?? undefined,
|
|
104
|
-
onFirstEvent: (error) => resolveFirstEvent(error ?? true),
|
|
105
|
-
onTerminal: (event) => {
|
|
106
|
-
entry.busy = false
|
|
107
|
-
entry.lastUsedAt = Date.now()
|
|
108
|
-
entry.streamFailures = 0
|
|
109
|
-
if (event.type !== "response.completed" && event.type !== "response.done") {
|
|
110
|
-
invalidate(entry)
|
|
111
|
-
}
|
|
112
|
-
},
|
|
113
|
-
onConnectionInvalid: (_error, closeCode) => {
|
|
114
|
-
entry.busy = false
|
|
115
|
-
entry.lastUsedAt = Date.now()
|
|
116
|
-
if (closeCode === OpenAIWebSocket.MESSAGE_TOO_BIG_CLOSE_CODE) entry.fallback = true
|
|
117
|
-
else if (!entry.fallback) recordStreamFailure(entry)
|
|
118
|
-
invalidate(entry)
|
|
119
|
-
resolveFirstEvent(false)
|
|
120
|
-
},
|
|
121
|
-
onAbort: (error) => {
|
|
122
|
-
entry.busy = false
|
|
123
|
-
entry.lastUsedAt = Date.now()
|
|
124
|
-
entry.streamFailures = 0
|
|
125
|
-
invalidate(entry)
|
|
126
|
-
rejectFirstEvent(error)
|
|
127
|
-
},
|
|
128
|
-
onRetryableTerminal: async (event) => {
|
|
129
|
-
const error = connectionLimitError(event)
|
|
130
|
-
if (!error) return undefined
|
|
131
|
-
throw error
|
|
132
|
-
},
|
|
133
|
-
})
|
|
134
|
-
const first = await firstEvent
|
|
135
|
-
if (first !== false) {
|
|
136
|
-
if (first === true || first.status < 200 || first.status > 599) return response
|
|
137
|
-
return new Response(first.body, {
|
|
138
|
-
status: first.status,
|
|
139
|
-
headers: { "content-type": "application/json", ...first.headers },
|
|
140
|
-
})
|
|
141
|
-
}
|
|
142
|
-
if (!entry.fallback) return response
|
|
143
|
-
return httpFetch(input, httpInit)
|
|
144
|
-
} catch (error) {
|
|
145
|
-
entry.busy = false
|
|
146
|
-
entry.lastUsedAt = Date.now()
|
|
147
|
-
if (OpenAIWebSocket.isAbortError(error)) {
|
|
148
|
-
entry.streamFailures = 0
|
|
149
|
-
invalidate(entry)
|
|
150
|
-
throw error
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
recordStreamFailure(entry)
|
|
154
|
-
invalidate(entry)
|
|
155
|
-
if (entry.fallback) return httpFetch(input, httpInit)
|
|
156
|
-
return failedResponse(
|
|
157
|
-
new ProviderError.ResponseStreamError(error instanceof Error ? error.message : String(error), {
|
|
158
|
-
cause: error,
|
|
159
|
-
}),
|
|
160
|
-
)
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
function recordStreamFailure(entry: PoolEntry) {
|
|
165
|
-
entry.streamFailures++
|
|
166
|
-
// Codex counts retries after the initial failed WebSocket attempt.
|
|
167
|
-
if (entry.streamFailures > streamRetries) entry.fallback = true
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
function prune() {
|
|
171
|
-
const now = Date.now()
|
|
172
|
-
for (const [key, entry] of pool) {
|
|
173
|
-
if (entry.busy) continue
|
|
174
|
-
if (entry.fallback) continue
|
|
175
|
-
if (now - entry.lastUsedAt < idleTimeout) continue
|
|
176
|
-
invalidate(entry)
|
|
177
|
-
pool.delete(key)
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
function close() {
|
|
182
|
-
clearInterval(pruneTimer)
|
|
183
|
-
for (const entry of pool.values()) invalidate(entry)
|
|
184
|
-
pool.clear()
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
function remove(sessionID: string) {
|
|
188
|
-
const key = `${sessionID}:conversation`
|
|
189
|
-
const entry = pool.get(key)
|
|
190
|
-
if (!entry) return
|
|
191
|
-
invalidate(entry)
|
|
192
|
-
pool.delete(key)
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
return Object.assign(websocketFetch, { close, remove })
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
function connectionLimitError(event: Record<string, unknown>) {
|
|
199
|
-
if (event.type !== "error" || !isRecord(event.error) || event.error.code !== CONNECTION_LIMIT_REACHED_CODE) return
|
|
200
|
-
return new Error(typeof event.error.message === "string" ? event.error.message : CONNECTION_LIMIT_REACHED_CODE)
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
function failedResponse(error: ProviderError.ResponseStreamError) {
|
|
204
|
-
return new Response(
|
|
205
|
-
new ReadableStream({
|
|
206
|
-
start(controller) {
|
|
207
|
-
controller.error(error)
|
|
208
|
-
},
|
|
209
|
-
}),
|
|
210
|
-
{
|
|
211
|
-
status: 200,
|
|
212
|
-
headers: { "content-type": "text/event-stream" },
|
|
213
|
-
},
|
|
214
|
-
)
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
async function socket(
|
|
218
|
-
entry: PoolEntry,
|
|
219
|
-
url: string,
|
|
220
|
-
headers: Record<string, string>,
|
|
221
|
-
connectTimeout: number,
|
|
222
|
-
maxConnectionAge: number,
|
|
223
|
-
signal?: AbortSignal | null,
|
|
224
|
-
) {
|
|
225
|
-
if (
|
|
226
|
-
entry.socket?.readyState === WebSocket.OPEN &&
|
|
227
|
-
entry.connectedAt &&
|
|
228
|
-
Date.now() - entry.connectedAt < maxConnectionAge
|
|
229
|
-
) {
|
|
230
|
-
return entry.socket
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
invalidate(entry)
|
|
234
|
-
const next = await OpenAIWebSocket.connectResponsesWebSocket({
|
|
235
|
-
url: OpenAIWebSocket.toWebSocketUrl(url),
|
|
236
|
-
headers,
|
|
237
|
-
timeout: connectTimeout,
|
|
238
|
-
signal: signal ?? undefined,
|
|
239
|
-
})
|
|
240
|
-
entry.connectedAt = Date.now()
|
|
241
|
-
return next
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
function invalidate(entry: PoolEntry) {
|
|
245
|
-
if (entry.socket) {
|
|
246
|
-
entry.socket.on("error", () => {})
|
|
247
|
-
entry.socket.terminate()
|
|
248
|
-
entry.socket = undefined
|
|
249
|
-
}
|
|
250
|
-
entry.connectedAt = undefined
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
export function withoutInternalHeaders<T extends { headers?: HeadersInit }>(init: T | undefined): T | undefined {
|
|
254
|
-
if (!init?.headers) return init
|
|
255
|
-
if (init.headers instanceof Headers) {
|
|
256
|
-
const headers = new Headers(init.headers)
|
|
257
|
-
headers.delete(TITLE_HEADER)
|
|
258
|
-
return { ...init, headers }
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
if (Array.isArray(init.headers)) {
|
|
262
|
-
return { ...init, headers: init.headers.filter((item) => item[0].toLowerCase() !== TITLE_HEADER) }
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
return {
|
|
266
|
-
...init,
|
|
267
|
-
headers: Object.fromEntries(Object.entries(init.headers).filter(([key]) => key.toLowerCase() !== TITLE_HEADER)),
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
export * as OpenAIWebSocketPool from "./ws-pool"
|
package/src/plugin/openai/ws.ts
DELETED
|
@@ -1,383 +0,0 @@
|
|
|
1
|
-
// Low-level OpenAI Responses WebSocket protocol helpers. Session pooling,
|
|
2
|
-
// fallback, and continuation state intentionally live above this file.
|
|
3
|
-
|
|
4
|
-
import WebSocket from "ws"
|
|
5
|
-
import { APICallError } from "ai"
|
|
6
|
-
import { ProviderError } from "@/provider/error"
|
|
7
|
-
import { errorMessage } from "@/util/error"
|
|
8
|
-
import { ProxyEnv } from "@/util/proxy-env"
|
|
9
|
-
import { isRecord } from "@/util/record"
|
|
10
|
-
|
|
11
|
-
export const PROTOCOL_HEADER = "responses_websockets=2026-02-06"
|
|
12
|
-
export const MESSAGE_TOO_BIG_CLOSE_CODE = 1009
|
|
13
|
-
|
|
14
|
-
export interface ConnectResponsesWebSocketOptions {
|
|
15
|
-
url: string
|
|
16
|
-
headers: Record<string, string>
|
|
17
|
-
timeout?: number
|
|
18
|
-
signal?: AbortSignal
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export interface StreamResponsesWebSocketOptions {
|
|
22
|
-
socket: WebSocket
|
|
23
|
-
body: Record<string, unknown>
|
|
24
|
-
idleTimeout?: number
|
|
25
|
-
signal?: AbortSignal
|
|
26
|
-
onFirstEvent?: (error?: WrappedError) => void
|
|
27
|
-
onComplete?: (event: Record<string, unknown>) => void
|
|
28
|
-
onTerminal?: (event: Record<string, unknown>) => void
|
|
29
|
-
onRetryableTerminal?: (event: Record<string, unknown>) => Promise<WebSocket | undefined>
|
|
30
|
-
onConnectionInvalid?: (error: ProviderError.ResponseStreamError, closeCode?: number) => void
|
|
31
|
-
onAbort?: (error: Error) => void
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export interface WrappedError {
|
|
35
|
-
status: number
|
|
36
|
-
headers?: Record<string, string>
|
|
37
|
-
body: string
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export function toWebSocketUrl(url: string) {
|
|
41
|
-
return url.replace(/^http/, "ws")
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export function normalizeHeaders(headers: HeadersInit | undefined): Record<string, string> {
|
|
45
|
-
const result: Record<string, string> = {}
|
|
46
|
-
if (!headers) return result
|
|
47
|
-
|
|
48
|
-
if (headers instanceof Headers) {
|
|
49
|
-
headers.forEach((value, key) => {
|
|
50
|
-
result[key.toLowerCase()] = value
|
|
51
|
-
})
|
|
52
|
-
return result
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (Array.isArray(headers)) {
|
|
56
|
-
for (const [key, value] of headers) {
|
|
57
|
-
result[key.toLowerCase()] = value
|
|
58
|
-
}
|
|
59
|
-
return result
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
for (const [key, value] of Object.entries(headers)) {
|
|
63
|
-
if (value != null) result[key.toLowerCase()] = value
|
|
64
|
-
}
|
|
65
|
-
return result
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export function isAbortError(error: unknown): error is DOMException {
|
|
69
|
-
return error instanceof DOMException && error.name === "AbortError"
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export function connectResponsesWebSocket(options: ConnectResponsesWebSocketOptions) {
|
|
73
|
-
return new Promise<WebSocket>((resolve, reject) => {
|
|
74
|
-
if (options.signal?.aborted) {
|
|
75
|
-
reject(abortError(options.signal))
|
|
76
|
-
return
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const headers: Record<string, string> = {
|
|
80
|
-
...options.headers,
|
|
81
|
-
"openai-beta": options.headers["openai-beta"] ?? PROTOCOL_HEADER,
|
|
82
|
-
}
|
|
83
|
-
delete headers["content-length"]
|
|
84
|
-
|
|
85
|
-
// Bun does not apply HTTP(S)_PROXY to WebSockets unless the proxy is supplied explicitly.
|
|
86
|
-
const proxy =
|
|
87
|
-
typeof Bun === "undefined"
|
|
88
|
-
? undefined
|
|
89
|
-
: ProxyEnv.getProxyForUrl(options.url.replace(/^wss:/, "https:").replace(/^ws:/, "http:"))
|
|
90
|
-
const connect = { headers, ...(proxy ? { proxy } : {}) }
|
|
91
|
-
const socket = new WebSocket(options.url, connect)
|
|
92
|
-
const timeout = options.timeout
|
|
93
|
-
? setTimeout(() => {
|
|
94
|
-
cleanup()
|
|
95
|
-
socket.on("error", () => {})
|
|
96
|
-
socket.terminate()
|
|
97
|
-
reject(new Error("WebSocket connect timed out"))
|
|
98
|
-
}, options.timeout)
|
|
99
|
-
: undefined
|
|
100
|
-
|
|
101
|
-
function cleanup() {
|
|
102
|
-
if (timeout) clearTimeout(timeout)
|
|
103
|
-
socket.off("open", onOpen)
|
|
104
|
-
socket.off("error", onError)
|
|
105
|
-
socket.off("close", onClose)
|
|
106
|
-
options.signal?.removeEventListener("abort", onAbort)
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function onOpen() {
|
|
110
|
-
cleanup()
|
|
111
|
-
resolve(socket)
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function onError(error: unknown) {
|
|
115
|
-
socket.on("error", () => {})
|
|
116
|
-
cleanup()
|
|
117
|
-
reject(error instanceof Error ? error : new Error(errorMessage(error), { cause: error }))
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
function onClose(code: number, reason: Buffer) {
|
|
121
|
-
cleanup()
|
|
122
|
-
reject(new Error(closeMessage("WebSocket closed before open", code, reason)))
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function onAbort() {
|
|
126
|
-
cleanup()
|
|
127
|
-
socket.on("error", () => {})
|
|
128
|
-
socket.terminate()
|
|
129
|
-
reject(abortError(options.signal))
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
socket.once("open", onOpen)
|
|
133
|
-
socket.once("error", onError)
|
|
134
|
-
socket.once("close", onClose)
|
|
135
|
-
options.signal?.addEventListener("abort", onAbort, { once: true })
|
|
136
|
-
})
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
export function streamResponsesWebSocket(options: StreamResponsesWebSocketOptions) {
|
|
140
|
-
const encoder = new TextEncoder()
|
|
141
|
-
|
|
142
|
-
let socket = options.socket
|
|
143
|
-
let controller: ReadableStreamDefaultController<Uint8Array> | undefined
|
|
144
|
-
let cleanupSocket = () => {}
|
|
145
|
-
let completed = false
|
|
146
|
-
let emitted = false
|
|
147
|
-
let idleTimer: ReturnType<typeof setTimeout> | undefined
|
|
148
|
-
|
|
149
|
-
function cleanup() {
|
|
150
|
-
if (idleTimer) clearTimeout(idleTimer)
|
|
151
|
-
cleanupSocket()
|
|
152
|
-
options.signal?.removeEventListener("abort", onAbort)
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
function terminateSocket(target = socket) {
|
|
156
|
-
target.on("error", () => {})
|
|
157
|
-
target.terminate()
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
function closeCompleted() {
|
|
161
|
-
cleanup()
|
|
162
|
-
controller?.enqueue(encoder.encode("data: [DONE]\n\n"))
|
|
163
|
-
controller?.close()
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
function invalidate(error: ProviderError.ResponseStreamError, closeCode?: number) {
|
|
167
|
-
if (completed) return
|
|
168
|
-
completed = true
|
|
169
|
-
cleanup()
|
|
170
|
-
options.onConnectionInvalid?.(error, closeCode)
|
|
171
|
-
controller?.error(error)
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
function resetIdleTimeout(message: string) {
|
|
175
|
-
if (completed) return
|
|
176
|
-
if (!options.idleTimeout) return
|
|
177
|
-
if (idleTimer) clearTimeout(idleTimer)
|
|
178
|
-
idleTimer = setTimeout(() => invalidate(new ProviderError.ResponseStreamError(message)), options.idleTimeout)
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
async function onMessage(data: WebSocket.RawData, isBinary: boolean) {
|
|
182
|
-
if (completed) return
|
|
183
|
-
if (isBinary) {
|
|
184
|
-
invalidate(new ProviderError.ResponseStreamError("Unexpected binary WebSocket frame"))
|
|
185
|
-
return
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
const text = data.toString()
|
|
189
|
-
const event = (() => {
|
|
190
|
-
try {
|
|
191
|
-
const parsed = JSON.parse(text)
|
|
192
|
-
return typeof parsed === "object" && parsed !== null ? parsed : undefined
|
|
193
|
-
} catch {
|
|
194
|
-
return undefined
|
|
195
|
-
}
|
|
196
|
-
})()
|
|
197
|
-
|
|
198
|
-
if (event?.type === "error" && options.onRetryableTerminal) {
|
|
199
|
-
cleanupSocket()
|
|
200
|
-
if (idleTimer) clearTimeout(idleTimer)
|
|
201
|
-
idleTimer = undefined
|
|
202
|
-
try {
|
|
203
|
-
const next = await options.onRetryableTerminal(event)
|
|
204
|
-
if (completed) {
|
|
205
|
-
if (next) terminateSocket(next)
|
|
206
|
-
return
|
|
207
|
-
}
|
|
208
|
-
if (next) {
|
|
209
|
-
attach(next)
|
|
210
|
-
return
|
|
211
|
-
}
|
|
212
|
-
} catch (error) {
|
|
213
|
-
invalidate(
|
|
214
|
-
new ProviderError.ResponseStreamError(error instanceof Error ? error.message : String(error), {
|
|
215
|
-
cause: error,
|
|
216
|
-
}),
|
|
217
|
-
)
|
|
218
|
-
return
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
const wrappedError = parseWrappedError(event, text)
|
|
223
|
-
if (wrappedError && event) {
|
|
224
|
-
if (!emitted) options.onFirstEvent?.(wrappedError)
|
|
225
|
-
completed = true
|
|
226
|
-
cleanup()
|
|
227
|
-
options.onTerminal?.(event)
|
|
228
|
-
controller?.error(
|
|
229
|
-
new APICallError({
|
|
230
|
-
message: wrappedError.message,
|
|
231
|
-
url: socket.url,
|
|
232
|
-
requestBodyValues: options.body,
|
|
233
|
-
statusCode: wrappedError.status,
|
|
234
|
-
responseHeaders: wrappedError.headers,
|
|
235
|
-
responseBody: wrappedError.body,
|
|
236
|
-
}),
|
|
237
|
-
)
|
|
238
|
-
return
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
if (!emitted) options.onFirstEvent?.()
|
|
242
|
-
controller?.enqueue(
|
|
243
|
-
encoder.encode(
|
|
244
|
-
`${text
|
|
245
|
-
.split(/\r?\n/)
|
|
246
|
-
.map((line) => `data: ${line}`)
|
|
247
|
-
.join("\n")}\n\n`,
|
|
248
|
-
),
|
|
249
|
-
)
|
|
250
|
-
emitted = true
|
|
251
|
-
resetIdleTimeout("idle timeout waiting for websocket")
|
|
252
|
-
|
|
253
|
-
if (!event) return
|
|
254
|
-
|
|
255
|
-
if (event.type === "response.completed" || event.type === "response.done") {
|
|
256
|
-
completed = true
|
|
257
|
-
options.onComplete?.(event)
|
|
258
|
-
options.onTerminal?.(event)
|
|
259
|
-
closeCompleted()
|
|
260
|
-
return
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
if (event.type === "response.failed" || event.type === "response.incomplete" || event.type === "error") {
|
|
264
|
-
completed = true
|
|
265
|
-
options.onTerminal?.(event)
|
|
266
|
-
closeCompleted()
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
function onError(error: Error) {
|
|
271
|
-
invalidate(new ProviderError.ResponseStreamError(error.message, { cause: error }))
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
function onClose(code: number, reason: Buffer) {
|
|
275
|
-
if (completed) return
|
|
276
|
-
invalidate(
|
|
277
|
-
new ProviderError.ResponseStreamError(closeMessage("WebSocket closed before response.completed", code, reason)),
|
|
278
|
-
code,
|
|
279
|
-
)
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
function onAbort() {
|
|
283
|
-
const error = abortError(options.signal)
|
|
284
|
-
if (completed) return
|
|
285
|
-
completed = true
|
|
286
|
-
cleanup()
|
|
287
|
-
terminateSocket()
|
|
288
|
-
options.onAbort?.(error)
|
|
289
|
-
controller?.error(error)
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
function onCancel(reason: unknown) {
|
|
293
|
-
if (completed) return
|
|
294
|
-
completed = true
|
|
295
|
-
cleanup()
|
|
296
|
-
terminateSocket()
|
|
297
|
-
options.onAbort?.(cancelError(reason))
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
function attach(next: WebSocket) {
|
|
301
|
-
cleanupSocket()
|
|
302
|
-
socket = next
|
|
303
|
-
socket.on("message", onMessage)
|
|
304
|
-
socket.once("error", onError)
|
|
305
|
-
socket.once("close", onClose)
|
|
306
|
-
cleanupSocket = () => {
|
|
307
|
-
socket.off("message", onMessage)
|
|
308
|
-
socket.off("error", onError)
|
|
309
|
-
socket.off("close", onClose)
|
|
310
|
-
}
|
|
311
|
-
const { stream: _stream, background: _background, ...payload } = options.body
|
|
312
|
-
resetIdleTimeout("idle timeout sending websocket request")
|
|
313
|
-
socket.send(JSON.stringify({ type: "response.create", ...payload }), (error) => {
|
|
314
|
-
if (completed) return
|
|
315
|
-
resetIdleTimeout("idle timeout waiting for websocket")
|
|
316
|
-
if (error) invalidate(new ProviderError.ResponseStreamError(error.message, { cause: error }))
|
|
317
|
-
})
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
return new Response(
|
|
321
|
-
new ReadableStream<Uint8Array>({
|
|
322
|
-
start(next) {
|
|
323
|
-
controller = next
|
|
324
|
-
options.signal?.addEventListener("abort", onAbort, { once: true })
|
|
325
|
-
|
|
326
|
-
if (options.signal?.aborted) {
|
|
327
|
-
onAbort()
|
|
328
|
-
return
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
attach(socket)
|
|
332
|
-
},
|
|
333
|
-
cancel(reason) {
|
|
334
|
-
onCancel(reason)
|
|
335
|
-
},
|
|
336
|
-
}),
|
|
337
|
-
{
|
|
338
|
-
status: 200,
|
|
339
|
-
headers: { "content-type": "text/event-stream" },
|
|
340
|
-
},
|
|
341
|
-
)
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
function parseWrappedError(event: Record<string, unknown> | undefined, body: string) {
|
|
345
|
-
if (event?.type !== "error") return
|
|
346
|
-
const status = event.status ?? event.status_code
|
|
347
|
-
if (typeof status !== "number" || (status >= 200 && status < 300)) return
|
|
348
|
-
return {
|
|
349
|
-
status,
|
|
350
|
-
headers: isRecord(event.headers)
|
|
351
|
-
? Object.fromEntries(
|
|
352
|
-
Object.entries(event.headers).flatMap(([key, value]) =>
|
|
353
|
-
typeof value === "string" || typeof value === "number" || typeof value === "boolean"
|
|
354
|
-
? [[key, String(value)]]
|
|
355
|
-
: [],
|
|
356
|
-
),
|
|
357
|
-
)
|
|
358
|
-
: undefined,
|
|
359
|
-
body,
|
|
360
|
-
message: isRecord(event.error) && typeof event.error.message === "string" ? event.error.message : `${status}`,
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
function cancelError(reason: unknown) {
|
|
365
|
-
if (isAbortError(reason)) return reason
|
|
366
|
-
if (reason instanceof Error) return reason
|
|
367
|
-
return new DOMException(typeof reason === "string" ? reason : "Aborted", "AbortError")
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
function abortError(signal: AbortSignal | undefined) {
|
|
371
|
-
const reason = signal?.reason
|
|
372
|
-
if (isAbortError(reason)) return reason
|
|
373
|
-
return new DOMException(reason instanceof Error ? reason.message : "Aborted", "AbortError")
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
function closeMessage(message: string, code: number, reason: Buffer) {
|
|
377
|
-
const details = [`code ${code}`]
|
|
378
|
-
if (code === MESSAGE_TOO_BIG_CLOSE_CODE) details.push("message too big")
|
|
379
|
-
if (reason.length > 0) details.push(reason.toString())
|
|
380
|
-
return `${message} (${details.join(": ")})`
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
export * as OpenAIWebSocket from "./ws"
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
export * as PluginPtyEnvironment from "./pty-environment"
|
|
2
|
-
|
|
3
|
-
import { PtyEnvironment } from "@soraacode/server/pty-environment"
|
|
4
|
-
import { Effect, Layer } from "effect"
|
|
5
|
-
import { InstanceStore } from "@/project/instance-store"
|
|
6
|
-
import { Plugin } from "."
|
|
7
|
-
|
|
8
|
-
export const layer = Layer.effect(
|
|
9
|
-
PtyEnvironment.Service,
|
|
10
|
-
Effect.gen(function* () {
|
|
11
|
-
const plugin = yield* Plugin.Service
|
|
12
|
-
const instances = yield* InstanceStore.Service
|
|
13
|
-
return PtyEnvironment.Service.of({
|
|
14
|
-
get: Effect.fn("PtyEnvironment.get")(function* (input) {
|
|
15
|
-
return yield* instances.provide(
|
|
16
|
-
{ directory: input.directory },
|
|
17
|
-
plugin
|
|
18
|
-
.trigger("shell.env", { cwd: input.cwd }, { env: {} as Record<string, string> })
|
|
19
|
-
.pipe(Effect.map((result) => result.env)),
|
|
20
|
-
)
|
|
21
|
-
}),
|
|
22
|
-
})
|
|
23
|
-
}),
|
|
24
|
-
)
|