@bitkyc08/opencodex 2.10.0 → 2.10.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/AGENTS_INSTALL.md +77 -0
- package/README.md +4 -10
- package/bin/ocx.mjs +71 -18
- package/gui/dist/assets/index-Cd6_PBKn.css +1 -0
- package/gui/dist/assets/index-ChZQsmBY.js +70 -0
- package/gui/dist/index.html +2 -2
- package/gui/dist/provider-icons/alibaba-color.svg +1 -1
- package/gui/dist/provider-icons/antigravity-color.svg +1 -1
- package/gui/dist/provider-icons/claude-color.svg +1 -1
- package/gui/dist/provider-icons/cline-color.svg +16 -0
- package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -1
- package/gui/dist/provider-icons/copilot-color.svg +1 -1
- package/gui/dist/provider-icons/cursor-color.svg +1 -1
- package/gui/dist/provider-icons/deepseek-color.svg +1 -1
- package/gui/dist/provider-icons/firepass-color.svg +1 -1
- package/gui/dist/provider-icons/fireworks-color.svg +1 -1
- package/gui/dist/provider-icons/gemini-color.svg +1 -1
- package/gui/dist/provider-icons/github-copilot-color.svg +1 -1
- package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -1
- package/gui/dist/provider-icons/grok.svg +1 -1
- package/gui/dist/provider-icons/groq-color.svg +1 -1
- package/gui/dist/provider-icons/huggingface-color.svg +1 -1
- package/gui/dist/provider-icons/kimi-color.svg +1 -1
- package/gui/dist/provider-icons/kiro-color.svg +2 -2
- package/gui/dist/provider-icons/lm-studio-color.svg +1 -1
- package/gui/dist/provider-icons/mistral-color.svg +1 -1
- package/gui/dist/provider-icons/moonshot-color.svg +1 -1
- package/gui/dist/provider-icons/nvidia-color.svg +1 -1
- package/gui/dist/provider-icons/ollama-color.svg +1 -1
- package/gui/dist/provider-icons/openai.svg +1 -1
- package/gui/dist/provider-icons/opencode.svg +2 -1
- package/gui/dist/provider-icons/openrouter-color.svg +1 -1
- package/gui/dist/provider-icons/pi.svg +2 -2
- package/gui/dist/provider-icons/qianfan-color.svg +1 -1
- package/gui/dist/provider-icons/qwen-portal-color.svg +1 -1
- package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -1
- package/gui/dist/provider-icons/vllm-color.svg +1 -1
- package/gui/dist/provider-icons/xiaomi-color.svg +1 -1
- package/package.json +8 -4
- package/src/adapters/anthropic.ts +208 -14
- package/src/adapters/base.ts +16 -5
- package/src/adapters/cursor/effort-map.ts +3 -2
- package/src/adapters/cursor/framing.ts +39 -0
- package/src/adapters/cursor/live-transport.ts +105 -95
- package/src/adapters/cursor/native-exec.ts +32 -6
- package/src/adapters/cursor/protobuf-request.ts +20 -15
- package/src/adapters/cursor/request-builder.ts +21 -7
- package/src/adapters/cursor/types.ts +7 -0
- package/src/adapters/google-antigravity-replay.ts +237 -21
- package/src/adapters/google-truncation.ts +11 -0
- package/src/adapters/google.ts +50 -9
- package/src/adapters/identity.ts +39 -6
- package/src/adapters/kiro-errors.ts +11 -0
- package/src/adapters/kiro-events.ts +19 -1
- package/src/adapters/kiro-thinking.ts +10 -2
- package/src/adapters/kiro-tools.ts +10 -1
- package/src/adapters/kiro.ts +37 -11
- package/src/adapters/openai-chat.ts +284 -83
- package/src/adapters/openai-responses.ts +182 -24
- package/src/bridge.ts +177 -7
- package/src/chat/outbound.ts +78 -23
- package/src/claude/agents-inject.ts +27 -5
- package/src/claude/inbound.ts +11 -1
- package/src/claude/model-info.ts +13 -10
- package/src/claude/outbound.ts +17 -0
- package/src/cli/account-api.ts +24 -0
- package/src/cli/account-auth.ts +31 -6
- package/src/cli/account-main.ts +317 -0
- package/src/cli/account.ts +5 -0
- package/src/cli/claude.ts +2 -1
- package/src/cli/doctor.ts +93 -22
- package/src/cli/export-command.ts +26 -12
- package/src/cli/help.ts +8 -6
- package/src/cli/index.ts +56 -22
- package/src/cli/integrations.ts +84 -1
- package/src/cli/observe.ts +54 -1
- package/src/cli/opencode.ts +2 -1
- package/src/cli/provider-runtime.ts +18 -1
- package/src/cli/route-policy.ts +92 -0
- package/src/cli/runtime-api.ts +6 -3
- package/src/cli/star-prompt.ts +71 -15
- package/src/cli/status.ts +1 -1
- package/src/cli/v2.ts +36 -9
- package/src/clients/config-export.ts +687 -10
- package/src/codex/account-lifecycle.ts +30 -5
- package/src/codex/account-usability.ts +22 -2
- package/src/codex/admission.ts +255 -0
- package/src/codex/auth-api.ts +427 -140
- package/src/codex/auth-context.ts +155 -30
- package/src/codex/autostart-health.ts +8 -1
- package/src/codex/catalog/account-models.ts +62 -0
- package/src/codex/catalog/aggregation.ts +14 -1
- package/src/codex/catalog/bundled.ts +282 -32
- package/src/codex/catalog/filesystem-evidence.ts +302 -0
- package/src/codex/catalog/metadata.ts +51 -6
- package/src/codex/catalog/parsing.ts +6 -3
- package/src/codex/catalog/provider-fetch.ts +576 -41
- package/src/codex/catalog/sync.ts +505 -66
- package/src/codex/catalog-admission.ts +197 -0
- package/src/codex/catalog-write-serialization.ts +241 -0
- package/src/codex/catalog.ts +2 -1
- package/src/codex/codex-write-lock.ts +372 -0
- package/src/codex/convergence-types.ts +593 -0
- package/src/codex/convergence.ts +441 -0
- package/src/codex/desired-state.ts +177 -0
- package/src/codex/features.ts +52 -8
- package/src/codex/generation.ts +202 -0
- package/src/codex/history-job.ts +257 -0
- package/src/codex/history-lock.ts +241 -0
- package/src/codex/history-migration-guardian.ts +18 -5
- package/src/codex/history-provider.ts +9 -2
- package/src/codex/history-transition.ts +105 -0
- package/src/codex/history-worker.ts +176 -0
- package/src/codex/inject-coordination.ts +245 -0
- package/src/codex/inject.ts +605 -124
- package/src/codex/integration-record.ts +266 -0
- package/src/codex/internal/catalog-writer.ts +203 -0
- package/src/codex/internal/history-writer.ts +80 -0
- package/src/codex/journal.ts +10 -1
- package/src/codex/main-account-cache.ts +24 -0
- package/src/codex/management-convergence.ts +114 -0
- package/src/codex/native-main-admission.ts +47 -0
- package/src/codex/native-main-auth-temp.ts +187 -0
- package/src/codex/native-main-claim.ts +167 -0
- package/src/codex/native-main-lock-file.ts +158 -0
- package/src/codex/native-main-owner.ts +315 -0
- package/src/codex/native-profile-api.ts +247 -0
- package/src/codex/native-profile-manager.ts +1512 -0
- package/src/codex/native-profile-processes.ts +121 -0
- package/src/codex/native-profile-recovery.ts +99 -0
- package/src/codex/native-profile-stage-store.ts +387 -0
- package/src/codex/native-profile-startup.ts +340 -0
- package/src/codex/native-profile-store.ts +855 -0
- package/src/codex/native-profile-types.ts +120 -0
- package/src/codex/native-residue.ts +557 -0
- package/src/codex/project-config-warnings.ts +18 -4
- package/src/codex/prompt-journal.ts +311 -0
- package/src/codex/prompt-layers.ts +967 -0
- package/src/codex/prompt-lock.ts +143 -0
- package/src/codex/quota-rejection.ts +224 -0
- package/src/codex/quota.ts +86 -3
- package/src/codex/routing.ts +299 -62
- package/src/codex/runtime.ts +159 -38
- package/src/codex/shim.ts +39 -13
- package/src/codex/subagent-model-fallback.ts +73 -12
- package/src/codex/transition-state.ts +604 -0
- package/src/codex/upstream-host-health.ts +70 -0
- package/src/codex/user-identity.ts +266 -0
- package/src/codex/write-coordination.ts +114 -0
- package/src/config.ts +562 -26
- package/src/generated/jawcode-model-metadata.ts +2 -2
- package/src/grok/inject.ts +15 -4
- package/src/grok/inspect.ts +45 -0
- package/src/images/loop.ts +113 -20
- package/src/integrations/config-io.ts +151 -0
- package/src/integrations/journal.ts +315 -0
- package/src/integrations/merge.ts +135 -0
- package/src/integrations/native/ownership-preflight.ts +165 -0
- package/src/integrations/ownership.ts +111 -0
- package/src/integrations/registry.ts +101 -0
- package/src/integrations/serialize.ts +235 -0
- package/src/integrations/state.ts +290 -0
- package/src/integrations/store.ts +103 -0
- package/src/integrations/writer.ts +492 -0
- package/src/lib/bounded-body.ts +46 -8
- package/src/lib/bun-runtime.ts +110 -1
- package/src/lib/bun-stream-caps.ts +2 -1
- package/src/lib/redact.ts +407 -2
- package/src/lib/shadow-call.ts +24 -0
- package/src/lib/translator-budget.ts +10 -0
- package/src/lib/upstream-reachability.ts +91 -0
- package/src/lib/upstream-retry.ts +154 -2
- package/src/lib/windows-secret-acl.ts +212 -11
- package/src/lib/winsw.ts +9 -3
- package/src/oauth/index.ts +61 -3
- package/src/oauth/key-providers.ts +4 -0
- package/src/oauth/kiro.ts +50 -6
- package/src/oauth/store.ts +31 -6
- package/src/oauth/token-guardian.ts +9 -3
- package/src/providers/codex-capacity.ts +288 -0
- package/src/providers/derive.ts +33 -1
- package/src/providers/free-directory.ts +3 -1
- package/src/providers/key-failover.ts +71 -3
- package/src/providers/openai-sidecar.ts +64 -4
- package/src/providers/openai-virtual-models.ts +1 -0
- package/src/providers/quota.ts +334 -26
- package/src/providers/registry.ts +284 -16
- package/src/providers/xai-transport.ts +11 -4
- package/src/responses/compaction.ts +8 -1
- package/src/responses/hosted-tool-policy.ts +9 -0
- package/src/responses/parser.ts +44 -2
- package/src/responses/reasoning-envelope.ts +9 -1
- package/src/responses/reasoning-replay-cache.ts +105 -0
- package/src/responses/spill-store.ts +45 -8
- package/src/responses/state.ts +161 -17
- package/src/router.ts +302 -16
- package/src/routing/analytics.ts +377 -0
- package/src/routing/capability.ts +204 -0
- package/src/routing/cost.ts +77 -0
- package/src/routing/evaluator.ts +444 -0
- package/src/routing/health.ts +401 -0
- package/src/routing/history/cursor.ts +43 -0
- package/src/routing/history/indexer.ts +590 -0
- package/src/routing/history/schema.ts +72 -0
- package/src/routing/profile.ts +423 -0
- package/src/routing/quota.ts +124 -0
- package/src/routing/request-evidence.ts +45 -0
- package/src/routing/trace.ts +686 -0
- package/src/server/auth-cors.ts +46 -6
- package/src/server/chat-completions.ts +28 -13
- package/src/server/claude-messages.ts +23 -15
- package/src/server/gui-static.ts +39 -10
- package/src/server/images.ts +10 -1
- package/src/server/index.ts +238 -52
- package/src/server/lifecycle.ts +228 -9
- package/src/server/live.ts +14 -3
- package/src/server/management/agent-settings-routes.ts +64 -14
- package/src/server/management/combo-routes.ts +5 -5
- package/src/server/management/config-routes.ts +1 -1
- package/src/server/management/context.ts +42 -2
- package/src/server/management/integration-routes.ts +538 -0
- package/src/server/management/logs-usage-routes.ts +1 -1
- package/src/server/management/model-routes.ts +32 -113
- package/src/server/management/model-rows.ts +117 -0
- package/src/server/management/native-integration-routes.ts +587 -0
- package/src/server/management/oauth-account-routes.ts +1 -1
- package/src/server/management/provider-routes.ts +218 -117
- package/src/server/management/request-history-routes.ts +191 -0
- package/src/server/management/routing-analytics-routes.ts +74 -0
- package/src/server/management/routing-profile-routes.ts +177 -0
- package/src/server/management/shared.ts +2 -2
- package/src/server/management/sidebar-routes.ts +47 -31
- package/src/server/management/sync-response.ts +69 -0
- package/src/server/management/system-restart.ts +276 -24
- package/src/server/management/system-routes.ts +4 -0
- package/src/server/management-api.ts +84 -9
- package/src/server/management-auth.ts +43 -5
- package/src/server/relay-eager.ts +82 -42
- package/src/server/relay.ts +120 -6
- package/src/server/request-log.ts +26 -6
- package/src/server/responses/collaboration.ts +63 -8
- package/src/server/responses/compact.ts +272 -41
- package/src/server/responses/core.ts +730 -132
- package/src/server/responses/fetch-helpers.ts +15 -1
- package/src/server/responses-item-id-repair.ts +32 -3
- package/src/server/responses-json-events.ts +52 -0
- package/src/server/responses-snapshot-repair.ts +621 -0
- package/src/server/search.ts +51 -6
- package/src/server/sse-payload-rewrite.ts +89 -12
- package/src/server/startup-health-cache.ts +7 -1
- package/src/server/ws-bridge.ts +11 -17
- package/src/service-manager-probe.ts +297 -0
- package/src/service.ts +222 -32
- package/src/tray/windows-tray.ps1 +9 -0
- package/src/tray/windows.ts +15 -7
- package/src/types.ts +194 -14
- package/src/update/index.ts +13 -13
- package/src/update/job.ts +24 -21
- package/src/update/notify.ts +7 -3
- package/src/usage/cost.ts +0 -0
- package/src/usage/expected-prices.ts +129 -10
- package/src/usage/log.ts +50 -15
- package/src/usage/summary.ts +4 -4
- package/src/vision/index.ts +6 -1
- package/src/web-search/loop.ts +161 -34
- package/gui/dist/assets/index-OY43ubAq.css +0 -1
- package/gui/dist/assets/index-YwNnKZcL.js +0 -67
- package/gui/dist/provider-icons/antigravity.svg +0 -1
- package/gui/dist/provider-icons/claude.svg +0 -1
- package/gui/dist/provider-icons/copilot.svg +0 -1
- package/gui/dist/provider-icons/cursor.svg +0 -2
- package/gui/dist/provider-icons/gemini.svg +0 -1
- package/gui/dist/provider-icons/grok-color.svg +0 -1
- package/gui/dist/provider-icons/kiro.svg +0 -14
|
@@ -118,6 +118,16 @@ export function safeHostLabel(url: string): string {
|
|
|
118
118
|
}
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
+
/** Canonical origin (scheme + host) for failure-attribution keys: http and
|
|
122
|
+
* https for the same host must not share one ledger entry (#914 review). */
|
|
123
|
+
export function safeOriginLabel(url: string): string {
|
|
124
|
+
try {
|
|
125
|
+
return new URL(url).origin.toLowerCase();
|
|
126
|
+
} catch {
|
|
127
|
+
return "upstream";
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
121
131
|
|
|
122
132
|
|
|
123
133
|
export function providerFetch(provider: OcxProviderConfig): typeof globalThis.fetch {
|
|
@@ -133,6 +143,7 @@ export async function fetchWithHeaderTimeout(
|
|
|
133
143
|
timeoutMs: number,
|
|
134
144
|
preferIdentityEncoding = false,
|
|
135
145
|
executor: typeof globalThis.fetch = globalThis.fetch,
|
|
146
|
+
manualRedirect = false,
|
|
136
147
|
): Promise<Response> {
|
|
137
148
|
const timeout = new AbortController();
|
|
138
149
|
const timer = setTimeout(() => {
|
|
@@ -148,10 +159,13 @@ export async function fetchWithHeaderTimeout(
|
|
|
148
159
|
return await executor(url, {
|
|
149
160
|
...init,
|
|
150
161
|
headers,
|
|
162
|
+
// Credential-bearing sends opt into manual redirects so a 3xx is relayed
|
|
163
|
+
// as a Response instead of being followed into a rejection that is
|
|
164
|
+
// indistinguishable from a pre-connection failure (#914).
|
|
165
|
+
...(manualRedirect ? { redirect: "manual" as const } : {}),
|
|
151
166
|
signal: AbortSignal.any([abortSignal, timeout.signal]),
|
|
152
167
|
});
|
|
153
168
|
} finally {
|
|
154
169
|
clearTimeout(timer);
|
|
155
170
|
}
|
|
156
171
|
}
|
|
157
|
-
|
|
@@ -7,6 +7,7 @@ type RepairableItemType = "message" | "reasoning";
|
|
|
7
7
|
|
|
8
8
|
interface ResponsesItemIdRepairState {
|
|
9
9
|
readonly repairMissingTerminalIds: boolean;
|
|
10
|
+
readonly repairInvalidIds: boolean;
|
|
10
11
|
readonly placeholders: Record<RepairableItemType, ReadonlySet<string>>;
|
|
11
12
|
readonly outputIds: Record<RepairableItemType, Map<number, string>>;
|
|
12
13
|
readonly scope: string;
|
|
@@ -53,6 +54,7 @@ function mintCanonicalId(type: RepairableItemType, scope: string, outputIndex: n
|
|
|
53
54
|
function createRepairState(config: ResponsesItemIdRepairConfig, budget?: TranslatorBudget): ResponsesItemIdRepairState {
|
|
54
55
|
const state = {
|
|
55
56
|
repairMissingTerminalIds: config.repairMissingTerminalIds === true,
|
|
57
|
+
repairInvalidIds: config.repairInvalidIds === true,
|
|
56
58
|
placeholders: {
|
|
57
59
|
message: new Set(config.message ?? []),
|
|
58
60
|
reasoning: new Set(config.reasoning ?? []),
|
|
@@ -85,9 +87,13 @@ function rememberMappedId(
|
|
|
85
87
|
if (!rawId) return null;
|
|
86
88
|
const mapped = state.placeholders[type].has(rawId)
|
|
87
89
|
? mintCanonicalId(type, state.scope, outputIndex)
|
|
88
|
-
: state.
|
|
89
|
-
|
|
90
|
-
|
|
90
|
+
: state.repairInvalidIds && !rawId.startsWith(REPAIRABLE_PREFIXES[type])
|
|
91
|
+
// An existing id without the canonical msg_/rs_ prefix (bare UUIDs from
|
|
92
|
+
// DeepSeek's Responses route) leaves Codex stuck on Thinking (#938).
|
|
93
|
+
? mintCanonicalId(type, state.scope, outputIndex)
|
|
94
|
+
: state.repairMissingTerminalIds
|
|
95
|
+
? rawId
|
|
96
|
+
: null;
|
|
91
97
|
if (!mapped) return null;
|
|
92
98
|
state.budget?.chargeRetained(new TextEncoder().encode(JSON.stringify([outputIndex, rawId, mapped])).byteLength, { kind: "item_ids" });
|
|
93
99
|
state.outputIds[type].set(outputIndex, mapped);
|
|
@@ -219,6 +225,29 @@ export function relaySseWithResponsesItemIdRepair(
|
|
|
219
225
|
|
|
220
226
|
export function hasResponsesItemIdRepair(config: ResponsesItemIdRepairConfig | undefined): boolean {
|
|
221
227
|
return config?.repairMissingTerminalIds === true
|
|
228
|
+
|| config?.repairInvalidIds === true
|
|
222
229
|
|| (config?.message?.length ?? 0) > 0
|
|
223
230
|
|| (config?.reasoning?.length ?? 0) > 0;
|
|
224
231
|
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Client-facing id normalization for a WHOLE bounded-JSON Responses object.
|
|
235
|
+
*
|
|
236
|
+
* The bounded-JSON policy (#875) answers a streaming client by synthesizing SSE
|
|
237
|
+
* from a completed JSON body, and reframes the same body into events for WS
|
|
238
|
+
* turns. Neither path goes through the SSE relay, so neither picks up the SSE
|
|
239
|
+
* item-id rewrite — a provider that needs id repair would get it on a streaming
|
|
240
|
+
* response and silently lose it the moment the reliability policy switched the
|
|
241
|
+
* upstream to bounded JSON. This applies the same rewrite to the object so all
|
|
242
|
+
* three paths agree. Raw recorded state is untouched: recording happens before
|
|
243
|
+
* any normalization.
|
|
244
|
+
*/
|
|
245
|
+
export function repairResponsesJsonItemIds(
|
|
246
|
+
response: Record<string, unknown>,
|
|
247
|
+
config: ResponsesItemIdRepairConfig,
|
|
248
|
+
budget?: TranslatorBudget,
|
|
249
|
+
): Record<string, unknown> {
|
|
250
|
+
const state = createRepairState(config, budget);
|
|
251
|
+
const rewritten = rewriteResponseSnapshot(state, response);
|
|
252
|
+
return rewritten.changed ? rewritten.response : response;
|
|
253
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared bounded-JSON → Responses event sequence (#875): the same pure event
|
|
3
|
+
* list used by the WebSocket bridge (sendResponsesJsonAsEvents) and by the
|
|
4
|
+
* HTTP SSE synthesis for models whose reliability policy forces a bounded
|
|
5
|
+
* JSON upstream. One algorithm, two serializations — no duplicated drift.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export type ResponsesJsonEventFrame = Record<string, unknown>;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The canonical minimal sequence Codex commits: response.created (empty
|
|
12
|
+
* output, in_progress) → one response.output_item.done per output item → a
|
|
13
|
+
* status-preserving terminal (completed / failed / incomplete).
|
|
14
|
+
*/
|
|
15
|
+
export function responsesJsonEventSequence(
|
|
16
|
+
response: Record<string, unknown>,
|
|
17
|
+
rewritePayload?: (payload: Record<string, unknown>) => Record<string, unknown>,
|
|
18
|
+
): ResponsesJsonEventFrame[] {
|
|
19
|
+
const rewrite = rewritePayload ?? ((payload: Record<string, unknown>) => payload);
|
|
20
|
+
const output = Array.isArray(response.output) ? response.output : [];
|
|
21
|
+
const finalStatus = response.status === "failed" || response.status === "incomplete"
|
|
22
|
+
? response.status
|
|
23
|
+
: "completed";
|
|
24
|
+
return [
|
|
25
|
+
rewrite({
|
|
26
|
+
type: "response.created",
|
|
27
|
+
response: { ...response, status: "in_progress", output: [] },
|
|
28
|
+
}),
|
|
29
|
+
...output.map((item, outputIndex) => rewrite({
|
|
30
|
+
type: "response.output_item.done",
|
|
31
|
+
output_index: outputIndex,
|
|
32
|
+
item,
|
|
33
|
+
})),
|
|
34
|
+
rewrite({
|
|
35
|
+
type: `response.${finalStatus}`,
|
|
36
|
+
response: { ...response, status: finalStatus },
|
|
37
|
+
}),
|
|
38
|
+
];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Serialize the event sequence as one SSE body with exactly one
|
|
43
|
+
* `data: [DONE]\n\n` trailer.
|
|
44
|
+
*/
|
|
45
|
+
export function responsesJsonToSseBody(
|
|
46
|
+
response: Record<string, unknown>,
|
|
47
|
+
rewritePayload?: (payload: Record<string, unknown>) => Record<string, unknown>,
|
|
48
|
+
): string {
|
|
49
|
+
const frames = responsesJsonEventSequence(response, rewritePayload)
|
|
50
|
+
.map(frame => `data: ${JSON.stringify(frame)}\n\n`);
|
|
51
|
+
return `${frames.join("")}data: [DONE]\n\n`;
|
|
52
|
+
}
|