Prepare Effect HttpApi backend parity (#24853)
This commit is contained in:
@@ -42,7 +42,7 @@ export const OutputLengthError = namedSchemaError("MessageOutputLengthError", {}
|
||||
export const AbortedError = namedSchemaError("MessageAbortedError", { message: Schema.String })
|
||||
export const StructuredOutputError = namedSchemaError("StructuredOutputError", {
|
||||
message: Schema.String,
|
||||
retries: Schema.Number,
|
||||
retries: NonNegativeInt,
|
||||
})
|
||||
export const AuthError = namedSchemaError("ProviderAuthError", {
|
||||
providerID: Schema.String,
|
||||
@@ -50,7 +50,7 @@ export const AuthError = namedSchemaError("ProviderAuthError", {
|
||||
})
|
||||
export const APIError = namedSchemaError("APIError", {
|
||||
message: Schema.String,
|
||||
statusCode: Schema.optional(Schema.Number),
|
||||
statusCode: Schema.optional(NonNegativeInt),
|
||||
isRetryable: Schema.Boolean,
|
||||
responseHeaders: Schema.optional(Schema.Record(Schema.String, Schema.String)),
|
||||
responseBody: Schema.optional(Schema.String),
|
||||
@@ -116,8 +116,8 @@ export const TextPart = Schema.Struct({
|
||||
ignored: Schema.optional(Schema.Boolean),
|
||||
time: Schema.optional(
|
||||
Schema.Struct({
|
||||
start: Schema.Number,
|
||||
end: Schema.optional(Schema.Number),
|
||||
start: NonNegativeInt,
|
||||
end: Schema.optional(NonNegativeInt),
|
||||
}),
|
||||
),
|
||||
metadata: Schema.optional(Schema.Record(Schema.String, Schema.Any)),
|
||||
@@ -132,8 +132,8 @@ export const ReasoningPart = Schema.Struct({
|
||||
text: Schema.String,
|
||||
metadata: Schema.optional(Schema.Record(Schema.String, Schema.Any)),
|
||||
time: Schema.Struct({
|
||||
start: Schema.Number,
|
||||
end: Schema.optional(Schema.Number),
|
||||
start: NonNegativeInt,
|
||||
end: Schema.optional(NonNegativeInt),
|
||||
}),
|
||||
})
|
||||
.annotate({ identifier: "ReasoningPart" })
|
||||
@@ -143,8 +143,8 @@ export type ReasoningPart = Types.DeepMutable<Schema.Schema.Type<typeof Reasonin
|
||||
const filePartSourceBase = {
|
||||
text: Schema.Struct({
|
||||
value: Schema.String,
|
||||
start: Schema.Int,
|
||||
end: Schema.Int,
|
||||
start: NonNegativeInt,
|
||||
end: NonNegativeInt,
|
||||
}).annotate({ identifier: "FilePartSourceText" }),
|
||||
}
|
||||
|
||||
@@ -162,7 +162,7 @@ export const SymbolSource = Schema.Struct({
|
||||
path: Schema.String,
|
||||
range: LSP.Range,
|
||||
name: Schema.String,
|
||||
kind: Schema.Int,
|
||||
kind: NonNegativeInt,
|
||||
})
|
||||
.annotate({ identifier: "SymbolSource" })
|
||||
.pipe(withStatics((s) => ({ zod: zod(s) })))
|
||||
@@ -201,8 +201,8 @@ export const AgentPart = Schema.Struct({
|
||||
source: Schema.optional(
|
||||
Schema.Struct({
|
||||
value: Schema.String,
|
||||
start: Schema.Int,
|
||||
end: Schema.Int,
|
||||
start: NonNegativeInt,
|
||||
end: NonNegativeInt,
|
||||
}),
|
||||
),
|
||||
})
|
||||
@@ -242,11 +242,10 @@ export type SubtaskPart = Types.DeepMutable<Schema.Schema.Type<typeof SubtaskPar
|
||||
export const RetryPart = Schema.Struct({
|
||||
...partBase,
|
||||
type: Schema.Literal("retry"),
|
||||
attempt: Schema.Number,
|
||||
// APIError is still NamedError-based Zod; bridge via ZodOverride until errors migrate.
|
||||
error: Schema.Any.annotate({ [ZodOverride]: APIError.Schema }),
|
||||
attempt: NonNegativeInt,
|
||||
error: APIError.EffectSchema,
|
||||
time: Schema.Struct({
|
||||
created: Schema.Number,
|
||||
created: NonNegativeInt,
|
||||
}),
|
||||
})
|
||||
.annotate({ identifier: "RetryPart" })
|
||||
@@ -269,15 +268,15 @@ export const StepFinishPart = Schema.Struct({
|
||||
type: Schema.Literal("step-finish"),
|
||||
reason: Schema.String,
|
||||
snapshot: Schema.optional(Schema.String),
|
||||
cost: Schema.Number,
|
||||
cost: Schema.Finite,
|
||||
tokens: Schema.Struct({
|
||||
total: Schema.optional(Schema.Number),
|
||||
input: Schema.Number,
|
||||
output: Schema.Number,
|
||||
reasoning: Schema.Number,
|
||||
total: Schema.optional(NonNegativeInt),
|
||||
input: NonNegativeInt,
|
||||
output: NonNegativeInt,
|
||||
reasoning: NonNegativeInt,
|
||||
cache: Schema.Struct({
|
||||
read: Schema.Number,
|
||||
write: Schema.Number,
|
||||
read: NonNegativeInt,
|
||||
write: NonNegativeInt,
|
||||
}),
|
||||
}),
|
||||
})
|
||||
@@ -300,7 +299,7 @@ export const ToolStateRunning = Schema.Struct({
|
||||
title: Schema.optional(Schema.String),
|
||||
metadata: Schema.optional(Schema.Record(Schema.String, Schema.Any)),
|
||||
time: Schema.Struct({
|
||||
start: Schema.Number,
|
||||
start: NonNegativeInt,
|
||||
}),
|
||||
})
|
||||
.annotate({ identifier: "ToolStateRunning" })
|
||||
@@ -314,9 +313,9 @@ export const ToolStateCompleted = Schema.Struct({
|
||||
title: Schema.String,
|
||||
metadata: Schema.Record(Schema.String, Schema.Any),
|
||||
time: Schema.Struct({
|
||||
start: Schema.Number,
|
||||
end: Schema.Number,
|
||||
compacted: Schema.optional(Schema.Number),
|
||||
start: NonNegativeInt,
|
||||
end: NonNegativeInt,
|
||||
compacted: Schema.optional(NonNegativeInt),
|
||||
}),
|
||||
attachments: Schema.optional(Schema.Array(FilePart)),
|
||||
})
|
||||
@@ -336,8 +335,8 @@ export const ToolStateError = Schema.Struct({
|
||||
error: Schema.String,
|
||||
metadata: Schema.optional(Schema.Record(Schema.String, Schema.Any)),
|
||||
time: Schema.Struct({
|
||||
start: Schema.Number,
|
||||
end: Schema.Number,
|
||||
start: NonNegativeInt,
|
||||
end: NonNegativeInt,
|
||||
}),
|
||||
})
|
||||
.annotate({ identifier: "ToolStateError" })
|
||||
@@ -380,7 +379,7 @@ export const User = Schema.Struct({
|
||||
...messageBase,
|
||||
role: Schema.Literal("user"),
|
||||
time: Schema.Struct({
|
||||
created: Schema.Number,
|
||||
created: NonNegativeInt,
|
||||
}),
|
||||
format: Schema.optional(_Format),
|
||||
summary: Schema.optional(
|
||||
@@ -447,9 +446,7 @@ export type Part =
|
||||
| RetryPart
|
||||
| CompactionPart
|
||||
|
||||
// Errors are still NamedError-based Zod; bridge via ZodOverride so the derived
|
||||
// Zod + JSON Schema emit the original discriminatedUnion shape. Migrating the
|
||||
// error classes to Schema.TaggedErrorClass is a separate slice.
|
||||
// Zod discriminated union kept for the legacy Hono OpenAPI path.
|
||||
const AssistantErrorZod = z.discriminatedUnion("name", [
|
||||
AuthError.Schema,
|
||||
NamedError.Unknown.Schema,
|
||||
@@ -461,6 +458,17 @@ const AssistantErrorZod = z.discriminatedUnion("name", [
|
||||
])
|
||||
type AssistantError = z.infer<typeof AssistantErrorZod>
|
||||
|
||||
// Effect Schema for the same union — used by HttpApi OpenAPI generation.
|
||||
const AssistantErrorSchema = Schema.Union([
|
||||
AuthError.EffectSchema,
|
||||
Schema.Struct({ name: Schema.Literal("UnknownError"), data: Schema.Struct({ message: Schema.String }) }).annotate({ identifier: "UnknownError" }),
|
||||
OutputLengthError.EffectSchema,
|
||||
AbortedError.EffectSchema,
|
||||
StructuredOutputError.EffectSchema,
|
||||
ContextOverflowError.EffectSchema,
|
||||
APIError.EffectSchema,
|
||||
]).annotate({ discriminator: "name" })
|
||||
|
||||
// ── Prompt input schemas ─────────────────────────────────────────────────────
|
||||
//
|
||||
// Consumers of `SessionPrompt.PromptInput.parts` send part drafts without the
|
||||
@@ -477,8 +485,8 @@ export const TextPartInput = Schema.Struct({
|
||||
ignored: Schema.optional(Schema.Boolean),
|
||||
time: Schema.optional(
|
||||
Schema.Struct({
|
||||
start: Schema.Number,
|
||||
end: Schema.optional(Schema.Number),
|
||||
start: NonNegativeInt,
|
||||
end: Schema.optional(NonNegativeInt),
|
||||
}),
|
||||
),
|
||||
metadata: Schema.optional(Schema.Record(Schema.String, Schema.Any)),
|
||||
@@ -506,8 +514,8 @@ export const AgentPartInput = Schema.Struct({
|
||||
source: Schema.optional(
|
||||
Schema.Struct({
|
||||
value: Schema.String,
|
||||
start: Schema.Int,
|
||||
end: Schema.Int,
|
||||
start: NonNegativeInt,
|
||||
end: NonNegativeInt,
|
||||
}),
|
||||
),
|
||||
})
|
||||
@@ -537,10 +545,10 @@ export const Assistant = Schema.Struct({
|
||||
...messageBase,
|
||||
role: Schema.Literal("assistant"),
|
||||
time: Schema.Struct({
|
||||
created: Schema.Number,
|
||||
completed: Schema.optional(Schema.Number),
|
||||
created: NonNegativeInt,
|
||||
completed: Schema.optional(NonNegativeInt),
|
||||
}),
|
||||
error: Schema.optional(Schema.Any.annotate({ [ZodOverride]: AssistantErrorZod })),
|
||||
error: Schema.optional(AssistantErrorSchema),
|
||||
parentID: MessageID,
|
||||
modelID: ModelID,
|
||||
providerID: ProviderID,
|
||||
@@ -554,15 +562,15 @@ export const Assistant = Schema.Struct({
|
||||
root: Schema.String,
|
||||
}),
|
||||
summary: Schema.optional(Schema.Boolean),
|
||||
cost: Schema.Number,
|
||||
cost: Schema.Finite,
|
||||
tokens: Schema.Struct({
|
||||
total: Schema.optional(Schema.Number),
|
||||
input: Schema.Number,
|
||||
output: Schema.Number,
|
||||
reasoning: Schema.Number,
|
||||
total: Schema.optional(NonNegativeInt),
|
||||
input: NonNegativeInt,
|
||||
output: NonNegativeInt,
|
||||
reasoning: NonNegativeInt,
|
||||
cache: Schema.Struct({
|
||||
read: Schema.Number,
|
||||
write: Schema.Number,
|
||||
read: NonNegativeInt,
|
||||
write: NonNegativeInt,
|
||||
}),
|
||||
}),
|
||||
structured: Schema.optional(Schema.Any),
|
||||
@@ -594,7 +602,7 @@ const RemovedEventSchema = Schema.Struct({
|
||||
const PartUpdatedEventSchema = Schema.Struct({
|
||||
sessionID: SessionID,
|
||||
part: _Part,
|
||||
time: Schema.Number,
|
||||
time: NonNegativeInt,
|
||||
})
|
||||
|
||||
const PartRemovedEventSchema = Schema.Struct({
|
||||
@@ -651,7 +659,7 @@ export type WithParts = {
|
||||
|
||||
const Cursor = Schema.Struct({
|
||||
id: MessageID,
|
||||
time: Schema.Number,
|
||||
time: Schema.Finite.check(Schema.isGreaterThanOrEqualTo(0)),
|
||||
})
|
||||
type Cursor = typeof Cursor.Type
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Schema } from "effect"
|
||||
import { SessionID } from "./schema"
|
||||
import { ModelID, ProviderID } from "../provider/schema"
|
||||
import { zod } from "@/util/effect-zod"
|
||||
import { withStatics } from "@/util/schema"
|
||||
import { NonNegativeInt, withStatics } from "@/util/schema"
|
||||
import { namedSchemaError } from "@/util/named-schema-error"
|
||||
|
||||
export const OutputLengthError = namedSchemaError("MessageOutputLengthError", {})
|
||||
@@ -33,7 +33,7 @@ const UnknownErrorEffect = Schema.Struct({
|
||||
|
||||
export const ToolCall = Schema.Struct({
|
||||
state: Schema.Literal("call"),
|
||||
step: Schema.optional(Schema.Number),
|
||||
step: Schema.optional(NonNegativeInt),
|
||||
toolCallId: Schema.String,
|
||||
toolName: Schema.String,
|
||||
args: Schema.Unknown,
|
||||
@@ -44,7 +44,7 @@ export type ToolCall = Schema.Schema.Type<typeof ToolCall>
|
||||
|
||||
export const ToolPartialCall = Schema.Struct({
|
||||
state: Schema.Literal("partial-call"),
|
||||
step: Schema.optional(Schema.Number),
|
||||
step: Schema.optional(NonNegativeInt),
|
||||
toolCallId: Schema.String,
|
||||
toolName: Schema.String,
|
||||
args: Schema.Unknown,
|
||||
@@ -55,7 +55,7 @@ export type ToolPartialCall = Schema.Schema.Type<typeof ToolPartialCall>
|
||||
|
||||
export const ToolResult = Schema.Struct({
|
||||
state: Schema.Literal("result"),
|
||||
step: Schema.optional(Schema.Number),
|
||||
step: Schema.optional(NonNegativeInt),
|
||||
toolCallId: Schema.String,
|
||||
toolName: Schema.String,
|
||||
args: Schema.Unknown,
|
||||
@@ -141,8 +141,8 @@ export const Info = Schema.Struct({
|
||||
parts: Schema.Array(MessagePart),
|
||||
metadata: Schema.Struct({
|
||||
time: Schema.Struct({
|
||||
created: Schema.Number,
|
||||
completed: Schema.optional(Schema.Number),
|
||||
created: NonNegativeInt,
|
||||
completed: Schema.optional(NonNegativeInt),
|
||||
}),
|
||||
error: Schema.optional(Schema.Union([AuthErrorEffect, UnknownErrorEffect, OutputLengthErrorEffect])),
|
||||
sessionID: SessionID,
|
||||
@@ -153,8 +153,8 @@ export const Info = Schema.Struct({
|
||||
title: Schema.String,
|
||||
snapshot: Schema.optional(Schema.String),
|
||||
time: Schema.Struct({
|
||||
start: Schema.Number,
|
||||
end: Schema.Number,
|
||||
start: NonNegativeInt,
|
||||
end: NonNegativeInt,
|
||||
}),
|
||||
}),
|
||||
[Schema.Record(Schema.String, Schema.Unknown)],
|
||||
@@ -169,15 +169,15 @@ export const Info = Schema.Struct({
|
||||
cwd: Schema.String,
|
||||
root: Schema.String,
|
||||
}),
|
||||
cost: Schema.Number,
|
||||
cost: Schema.Finite,
|
||||
summary: Schema.optional(Schema.Boolean),
|
||||
tokens: Schema.Struct({
|
||||
input: Schema.Number,
|
||||
output: Schema.Number,
|
||||
reasoning: Schema.Number,
|
||||
input: NonNegativeInt,
|
||||
output: NonNegativeInt,
|
||||
reasoning: NonNegativeInt,
|
||||
cache: Schema.Struct({
|
||||
read: Schema.Number,
|
||||
write: Schema.Number,
|
||||
read: NonNegativeInt,
|
||||
write: NonNegativeInt,
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
|
||||
@@ -38,7 +38,7 @@ import { Permission } from "@/permission"
|
||||
import { Global } from "@opencode-ai/core/global"
|
||||
import { Effect, Layer, Option, Context, Schema, Types } from "effect"
|
||||
import { zod } from "@/util/effect-zod"
|
||||
import { optionalOmitUndefined, withStatics } from "@/util/schema"
|
||||
import { NonNegativeInt, optionalOmitUndefined, withStatics } from "@/util/schema"
|
||||
|
||||
const log = Log.create({ service: "session" })
|
||||
|
||||
@@ -132,9 +132,9 @@ function sessionPath(worktree: string, cwd: string) {
|
||||
}
|
||||
|
||||
const Summary = Schema.Struct({
|
||||
additions: Schema.Number,
|
||||
deletions: Schema.Number,
|
||||
files: Schema.Number,
|
||||
additions: NonNegativeInt,
|
||||
deletions: NonNegativeInt,
|
||||
files: NonNegativeInt,
|
||||
diffs: optionalOmitUndefined(Schema.Array(Snapshot.FileDiff)),
|
||||
})
|
||||
|
||||
@@ -143,10 +143,10 @@ const Share = Schema.Struct({
|
||||
})
|
||||
|
||||
const Time = Schema.Struct({
|
||||
created: Schema.Number,
|
||||
updated: Schema.Number,
|
||||
compacting: optionalOmitUndefined(Schema.Number),
|
||||
archived: optionalOmitUndefined(Schema.Number),
|
||||
created: NonNegativeInt,
|
||||
updated: NonNegativeInt,
|
||||
compacting: optionalOmitUndefined(NonNegativeInt),
|
||||
archived: optionalOmitUndefined(NonNegativeInt),
|
||||
})
|
||||
|
||||
const Revert = Schema.Struct({
|
||||
@@ -215,7 +215,7 @@ export const SetTitleInput = Schema.Struct({ sessionID: SessionID, title: Schema
|
||||
)
|
||||
export const SetArchivedInput = Schema.Struct({
|
||||
sessionID: SessionID,
|
||||
time: Schema.optional(Schema.Number),
|
||||
time: Schema.optional(NonNegativeInt),
|
||||
}).pipe(withStatics((s) => ({ zod: zod(s) })))
|
||||
export const SetPermissionInput = Schema.Struct({
|
||||
sessionID: SessionID,
|
||||
@@ -228,7 +228,7 @@ export const SetRevertInput = Schema.Struct({
|
||||
}).pipe(withStatics((s) => ({ zod: zod(s) })))
|
||||
export const MessagesInput = Schema.Struct({
|
||||
sessionID: SessionID,
|
||||
limit: Schema.optional(Schema.Number),
|
||||
limit: Schema.optional(NonNegativeInt),
|
||||
}).pipe(withStatics((s) => ({ zod: zod(s) })))
|
||||
|
||||
const CreatedEventSchema = Schema.Struct({
|
||||
@@ -241,10 +241,10 @@ const UpdatedShare = Schema.Struct({
|
||||
})
|
||||
|
||||
const UpdatedTime = Schema.Struct({
|
||||
created: Schema.optional(Schema.NullOr(Schema.Number)),
|
||||
updated: Schema.optional(Schema.NullOr(Schema.Number)),
|
||||
compacting: Schema.optional(Schema.NullOr(Schema.Number)),
|
||||
archived: Schema.optional(Schema.NullOr(Schema.Number)),
|
||||
created: Schema.optional(Schema.NullOr(NonNegativeInt)),
|
||||
updated: Schema.optional(Schema.NullOr(NonNegativeInt)),
|
||||
compacting: Schema.optional(Schema.NullOr(NonNegativeInt)),
|
||||
archived: Schema.optional(Schema.NullOr(NonNegativeInt)),
|
||||
})
|
||||
|
||||
const UpdatedInfo = Schema.Struct({
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Bus } from "@/bus"
|
||||
import { InstanceState } from "@/effect/instance-state"
|
||||
import { SessionID } from "./schema"
|
||||
import { zod } from "@/util/effect-zod"
|
||||
import { withStatics } from "@/util/schema"
|
||||
import { NonNegativeInt, withStatics } from "@/util/schema"
|
||||
import { Effect, Layer, Context, Schema } from "effect"
|
||||
import z from "zod"
|
||||
|
||||
@@ -13,9 +13,9 @@ export const Info = Schema.Union([
|
||||
}),
|
||||
Schema.Struct({
|
||||
type: Schema.Literal("retry"),
|
||||
attempt: Schema.Number,
|
||||
attempt: NonNegativeInt,
|
||||
message: Schema.String,
|
||||
next: Schema.Number,
|
||||
next: NonNegativeInt,
|
||||
}),
|
||||
Schema.Struct({
|
||||
type: Schema.Literal("busy"),
|
||||
|
||||
Reference in New Issue
Block a user