mirror of
https://github.com/anomalyco/opencode.git
synced 2026-07-10 04:18:30 +00:00
fix(sdk): preserve V2Event name for SSE streams (#34171)
This commit is contained in:
parent
ae53163cad
commit
6446b8ae3b
7 changed files with 89 additions and 13 deletions
1
bun.lock
1
bun.lock
|
|
@ -1051,6 +1051,7 @@
|
|||
"@modelcontextprotocol/sdk@1.29.0": "patches/@modelcontextprotocol%2Fsdk@1.29.0.patch",
|
||||
"gcp-metadata@8.1.2": "patches/gcp-metadata@8.1.2.patch",
|
||||
"@standard-community/standard-openapi@0.2.9": "patches/@standard-community%2Fstandard-openapi@0.2.9.patch",
|
||||
"effect@4.0.0-beta.83": "patches/effect@4.0.0-beta.83.patch",
|
||||
"@npmcli/agent@4.0.2": "patches/@npmcli%2Fagent@4.0.2.patch",
|
||||
"@silvia-odwyer/photon-node@0.3.4": "patches/@silvia-odwyer%2Fphoton-node@0.3.4.patch",
|
||||
"@tanstack/solid-virtual@3.13.28": "patches/@tanstack%2Fsolid-virtual@3.13.28.patch",
|
||||
|
|
|
|||
|
|
@ -153,6 +153,7 @@
|
|||
"@tanstack/solid-virtual@3.13.28": "patches/@tanstack%2Fsolid-virtual@3.13.28.patch",
|
||||
"@pierre/trees@1.0.0-beta.4": "patches/@pierre%2Ftrees@1.0.0-beta.4.patch",
|
||||
"@modelcontextprotocol/sdk@1.29.0": "patches/@modelcontextprotocol%2Fsdk@1.29.0.patch",
|
||||
"@tanstack/virtual-core@3.17.0": "patches/@tanstack%2Fvirtual-core@3.17.0.patch"
|
||||
"@tanstack/virtual-core@3.17.0": "patches/@tanstack%2Fvirtual-core@3.17.0.patch",
|
||||
"effect@4.0.0-beta.83": "patches/effect@4.0.0-beta.83.patch"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ type OpenApiSchema = {
|
|||
readonly enum?: readonly unknown[]
|
||||
readonly properties?: Record<string, OpenApiSchema>
|
||||
readonly required?: readonly string[]
|
||||
readonly contentSchema?: OpenApiSchema
|
||||
readonly contentMediaType?: string
|
||||
}
|
||||
type OpenApiResponse = {
|
||||
readonly description?: string
|
||||
|
|
@ -99,6 +101,21 @@ describe("PublicApi OpenAPI v2 errors", () => {
|
|||
})
|
||||
})
|
||||
|
||||
test("names the v2 event union without the SSE string wrapper collision", () => {
|
||||
const spec = OpenApi.fromApi(PublicApi) as OpenApiSpec
|
||||
|
||||
expect(spec.components.schemas.V2Event1).toBeUndefined()
|
||||
expect(spec.components.schemas.V2Event?.anyOf?.length).toBeGreaterThan(0)
|
||||
expect(spec.components.schemas.V2EventStream).toMatchObject({
|
||||
type: "string",
|
||||
contentMediaType: "application/json",
|
||||
contentSchema: { $ref: "#/components/schemas/V2Event" },
|
||||
})
|
||||
expect(spec.paths["/api/event"]?.get?.responses?.["200"]?.content?.["text/event-stream"]?.schema).toEqual({
|
||||
$ref: "#/components/schemas/V2Event",
|
||||
})
|
||||
})
|
||||
|
||||
test("preserves /api auth responses", () => {
|
||||
const spec = OpenApi.fromApi(PublicApi) as OpenApiSpec
|
||||
|
||||
|
|
|
|||
|
|
@ -2766,7 +2766,7 @@ export type SessionHistory = {
|
|||
hasMore: boolean
|
||||
}
|
||||
|
||||
export type SessionDurableEvent1 = string
|
||||
export type SessionDurableEventStream = string
|
||||
|
||||
export type SessionMessagesResponse = {
|
||||
data: Array<SessionMessage>
|
||||
|
|
@ -2847,7 +2847,7 @@ export type QuestionRejected2 = {
|
|||
}
|
||||
}
|
||||
|
||||
export type V2Event1 =
|
||||
export type V2Event =
|
||||
| ModelsDevRefreshed
|
||||
| IntegrationUpdated
|
||||
| IntegrationConnectionUpdated
|
||||
|
|
@ -2937,7 +2937,7 @@ export type V2Event1 =
|
|||
| ServerConnected
|
||||
| GlobalDisposed
|
||||
|
||||
export type V2Event = string
|
||||
export type V2EventStream = string
|
||||
|
||||
export type ForbiddenError = {
|
||||
_tag: "ForbiddenError"
|
||||
|
|
@ -11901,7 +11901,7 @@ export type V2SessionEventsResponses = {
|
|||
200: {
|
||||
id: string
|
||||
event: string
|
||||
data: SessionDurableEvent1
|
||||
data: SessionDurableEventStream
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11260,7 +11260,7 @@
|
|||
"type": "string"
|
||||
},
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/SessionDurableEvent1"
|
||||
"$ref": "#/components/schemas/SessionDurableEventStream"
|
||||
}
|
||||
},
|
||||
"required": ["id", "event", "data"],
|
||||
|
|
@ -23732,7 +23732,7 @@
|
|||
"required": ["data", "hasMore"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"SessionDurableEvent1": {
|
||||
"SessionDurableEventStream": {
|
||||
"type": "string",
|
||||
"contentSchema": {
|
||||
"$ref": "#/components/schemas/SessionDurableEvent"
|
||||
|
|
@ -23975,7 +23975,7 @@
|
|||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"V2Event1": {
|
||||
"V2Event": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/Models-devRefreshed"
|
||||
|
|
@ -24243,10 +24243,10 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"V2Event": {
|
||||
"V2EventStream": {
|
||||
"type": "string",
|
||||
"contentSchema": {
|
||||
"$ref": "#/components/schemas/V2Event1"
|
||||
"$ref": "#/components/schemas/V2Event"
|
||||
},
|
||||
"contentMediaType": "application/json"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import type {
|
|||
SessionMessageAssistantTool,
|
||||
SessionV2Info,
|
||||
SkillV2Info,
|
||||
V2Event1,
|
||||
V2Event,
|
||||
} from "@opencode-ai/sdk/v2"
|
||||
import { createStore, produce } from "solid-js/store"
|
||||
import { createSimpleContext } from "./helper"
|
||||
|
|
@ -121,7 +121,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||
},
|
||||
}
|
||||
|
||||
function handleEvent(event: V2Event1) {
|
||||
function handleEvent(event: V2Event) {
|
||||
switch (event.type) {
|
||||
case "catalog.updated":
|
||||
void Promise.all([
|
||||
|
|
@ -408,7 +408,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||
...event,
|
||||
data: event.properties,
|
||||
location: { directory: metadata.directory, workspaceID: metadata.workspace },
|
||||
} as V2Event1)
|
||||
} as V2Event)
|
||||
})
|
||||
onCleanup(unsub)
|
||||
})
|
||||
|
|
|
|||
57
patches/effect@4.0.0-beta.83.patch
Normal file
57
patches/effect@4.0.0-beta.83.patch
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
diff --git a/dist/unstable/httpapi/HttpApiSchema.js b/dist/unstable/httpapi/HttpApiSchema.js
|
||||
index ecb6603d1ee4e89e92174b3a1100e8c9c720b3f3..08b832b6b3e9e4d10df156eca36b16f571f67f6e 100644
|
||||
--- a/dist/unstable/httpapi/HttpApiSchema.js
|
||||
+++ b/dist/unstable/httpapi/HttpApiSchema.js
|
||||
@@ -151,7 +151,7 @@ export const StreamSse = options => {
|
||||
const events = options.events ?? (options.data === undefined ? undefined : Schema.Struct({
|
||||
id: Schema.UndefinedOr(Schema.String),
|
||||
event: Schema.String,
|
||||
- data: Schema.fromJsonString(options.data)
|
||||
+ data: sseDataJsonSchema(options.data)
|
||||
}));
|
||||
if (events === undefined) {
|
||||
throw new Error("StreamSse requires either an events schema or a data schema");
|
||||
@@ -166,6 +166,14 @@ export const StreamSse = options => {
|
||||
error: options.error ?? Schema.Never
|
||||
});
|
||||
};
|
||||
+const sseDataJsonSchema = data => {
|
||||
+ const identifier = SchemaAST.resolveIdentifier(data.ast);
|
||||
+ return identifier === undefined ? Schema.fromJsonString(data) : Schema.fromJsonString(data).annotate({
|
||||
+ // The SSE transport field is a JSON string. Give that wrapper its own
|
||||
+ // OpenAPI identifier so it does not claim the decoded data schema's name.
|
||||
+ identifier: `${identifier}Stream`
|
||||
+ });
|
||||
+};
|
||||
/**
|
||||
* Creates a streaming `Uint8Array` success response schema.
|
||||
*
|
||||
diff --git a/src/unstable/httpapi/HttpApiSchema.ts b/src/unstable/httpapi/HttpApiSchema.ts
|
||||
index f2920365cf0328146523ce2e2dba04d6a8809a4a..5482d635cdf01a72063ff683d244fab891910211 100644
|
||||
--- a/src/unstable/httpapi/HttpApiSchema.ts
|
||||
+++ b/src/unstable/httpapi/HttpApiSchema.ts
|
||||
@@ -433,7 +433,7 @@ export const StreamSse: {
|
||||
const events = options.events ?? (options.data === undefined ? undefined : Schema.Struct({
|
||||
id: Schema.UndefinedOr(Schema.String),
|
||||
event: Schema.String,
|
||||
- data: Schema.fromJsonString(options.data)
|
||||
+ data: sseDataJsonSchema(options.data)
|
||||
}))
|
||||
if (events === undefined) {
|
||||
throw new Error("StreamSse requires either an events schema or a data schema")
|
||||
@@ -449,6 +449,15 @@ export const StreamSse: {
|
||||
})
|
||||
}
|
||||
|
||||
+const sseDataJsonSchema = (data: Schema.Constraint) => {
|
||||
+ const identifier = SchemaAST.resolveIdentifier(data.ast)
|
||||
+ return identifier === undefined ? Schema.fromJsonString(data) : Schema.fromJsonString(data).annotate({
|
||||
+ // The SSE transport field is a JSON string. Give that wrapper its own
|
||||
+ // OpenAPI identifier so it does not claim the decoded data schema's name.
|
||||
+ identifier: `${identifier}Stream`
|
||||
+ })
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* Creates a streaming `Uint8Array` success response schema.
|
||||
*
|
||||
Loading…
Add table
Add a link
Reference in a new issue