Merge remote-tracking branch 'origin/v2' into search-integration
# Conflicts: # packages/client/test/promise.test.ts # packages/core/schema.json # packages/core/src/database/migration.gen.ts # packages/core/src/tool/websearch.ts # packages/sdk-next/src/index.ts # packages/sdk/js/src/v2/gen/types.gen.ts
This commit is contained in:
commit
7b8d8b8861
666 changed files with 46671 additions and 20220 deletions
|
|
@ -69,9 +69,9 @@ export const endpointNames = {
|
|||
"integration.attempt.status": "attemptStatus",
|
||||
"integration.attempt.complete": "attemptComplete",
|
||||
"integration.attempt.cancel": "attemptCancel",
|
||||
"session.context.entry.list": "listContextEntries",
|
||||
"session.context.entry.put": "putContextEntry",
|
||||
"session.context.entry.remove": "removeContextEntry",
|
||||
"session.instructions.entry.list": ["instructions", "entry", "list"],
|
||||
"session.instructions.entry.put": ["instructions", "entry", "put"],
|
||||
"session.instructions.entry.remove": ["instructions", "entry", "remove"],
|
||||
"session.revert.stage": "revertStage",
|
||||
"session.revert.clear": "revertClear",
|
||||
"session.revert.commit": "revertCommit",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { Event } from "@opencode-ai/schema/event"
|
||||
import { EventLog } from "@opencode-ai/schema/event-log"
|
||||
import { EventManifest } from "@opencode-ai/schema/event-manifest"
|
||||
import { Location } from "@opencode-ai/schema/location"
|
||||
import type { Definition } from "@opencode-ai/schema/event"
|
||||
|
|
@ -39,19 +38,7 @@ const make = <const Definitions extends ReadonlyArray<Definition>>(definitions:
|
|||
identifier: "v2.event.subscribe",
|
||||
summary: "Subscribe to events",
|
||||
description:
|
||||
"Subscribe to native event payloads for the server. Volatile by contract: a slow consumer overflows and fails the stream, and events during disconnection are missed. Consumers that need reliability should combine the changes feed with durable session log reads.",
|
||||
}),
|
||||
),
|
||||
)
|
||||
.add(
|
||||
HttpApiEndpoint.get("event.changes", "/api/event/changes", {
|
||||
success: HttpApiSchema.StreamSse({ data: EventLog.Change }),
|
||||
}).annotateMerge(
|
||||
OpenApi.annotations({
|
||||
identifier: "v2.event.changes",
|
||||
summary: "Subscribe to change hints",
|
||||
description:
|
||||
"Payload-free hint channel: after an event commits, a subscriber eventually receives a hint for that aggregate with seq at or beyond the event, or a sweep-required marker. Hints coalesce to the latest seq per aggregate under backpressure and the stream never fails from overflow. No consumer may derive correctness from receiving a hint; correctness always comes from durable log reads plus the consumer's own checkpoint. A sweep-required marker is emitted first on every (re)subscribe and whenever hint retention is exceeded: treat every aggregate as potentially dirty and recover via bounded sweep plus log reads.",
|
||||
"Subscribe to native event payloads for the server. Volatile by contract: a slow consumer overflows and fails the stream, and events during disconnection are missed.",
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
import { Session } from "@opencode-ai/schema/session"
|
||||
import { SessionMessage } from "@opencode-ai/schema/session-message"
|
||||
import { optional } from "@opencode-ai/schema/schema"
|
||||
import { Event } from "@opencode-ai/schema/event"
|
||||
import { Schema } from "effect"
|
||||
import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi"
|
||||
import { InvalidCursorError, SessionNotFoundError, UnknownError } from "../errors.js"
|
||||
|
|
@ -30,10 +28,6 @@ export const MessageGroup = HttpApiGroup.make("server.message")
|
|||
query: SessionMessagesQuery,
|
||||
success: Schema.Struct({
|
||||
data: Schema.Array(SessionMessage.Message),
|
||||
watermark: optional(Event.Seq).annotate({
|
||||
description:
|
||||
"Durable log seq this snapshot was computed at, read before the snapshot. Attach a live log read after the watermark to compose fetch and stream gap-free; events between the watermark and the snapshot read may be redelivered by the tail and are safe to re-apply. Absent when the session has no durable events.",
|
||||
}),
|
||||
cursor: Schema.Struct({
|
||||
previous: Schema.String.pipe(Schema.optional),
|
||||
next: Schema.String.pipe(Schema.optional),
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { SessionMessage } from "@opencode-ai/schema/session-message"
|
|||
import { SessionInput } from "@opencode-ai/schema/session-input"
|
||||
import { PromptInput } from "@opencode-ai/schema/prompt-input"
|
||||
import { Session } from "@opencode-ai/schema/session"
|
||||
import { SessionContextEntry } from "@opencode-ai/schema/session-context-entry"
|
||||
import { InstructionEntry } from "@opencode-ai/schema/instruction-entry"
|
||||
import { Project } from "@opencode-ai/schema/project"
|
||||
import { AbsolutePath, PositiveInt, RelativePath, statics } from "@opencode-ai/schema/schema"
|
||||
import { Event } from "@opencode-ai/schema/event"
|
||||
|
|
@ -104,12 +104,6 @@ const SessionActive = Schema.Struct({
|
|||
type: Schema.Literal("running"),
|
||||
}).annotate({ identifier: "SessionActive" })
|
||||
|
||||
const SessionWatermarks = Schema.Record(Session.ID, Event.Seq).annotate({
|
||||
identifier: "SessionWatermarks",
|
||||
description:
|
||||
"Durable log seq each session's snapshot was computed at. Attach a live log read after the watermark to compose fetch and stream gap-free; apply a snapshot only where its watermark is at or beyond already-applied events. Sessions without durable events are absent.",
|
||||
})
|
||||
|
||||
const BooleanFromString = Schema.Literals(["true", "false"]).pipe(
|
||||
Schema.decodeTo(Schema.Boolean, {
|
||||
decode: SchemaGetter.transform((value) => value === "true"),
|
||||
|
|
@ -136,7 +130,6 @@ export const makeSessionGroup = <I extends HttpApiMiddleware.AnyId, S>(sessionLo
|
|||
query: SessionsQuery,
|
||||
success: Schema.Struct({
|
||||
data: Schema.Array(Session.Info),
|
||||
watermarks: SessionWatermarks,
|
||||
cursor: Schema.Struct({
|
||||
previous: SessionsCursor.pipe(Schema.optional),
|
||||
next: SessionsCursor.pipe(Schema.optional),
|
||||
|
|
@ -171,13 +164,13 @@ export const makeSessionGroup = <I extends HttpApiMiddleware.AnyId, S>(sessionLo
|
|||
)
|
||||
.add(
|
||||
HttpApiEndpoint.get("session.active", "/api/session/active", {
|
||||
success: Schema.Struct({ data: Schema.Record(Session.ID, SessionActive), watermarks: SessionWatermarks }),
|
||||
success: Schema.Struct({ data: Schema.Record(Session.ID, SessionActive) }),
|
||||
}).annotateMerge(
|
||||
OpenApi.annotations({
|
||||
identifier: "v2.session.active",
|
||||
summary: "List active sessions",
|
||||
description:
|
||||
"Retrieve foreground Session drains currently owned by this OpenCode process. Sessions absent from the result are inactive. Watermarks are the durable log positions read alongside the activity snapshot; activity itself is process state, so the pairing is advisory rather than transactional.",
|
||||
"Retrieve foreground Session drains currently owned by this OpenCode process. Sessions absent from the result are inactive.",
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
|
@ -196,6 +189,21 @@ export const makeSessionGroup = <I extends HttpApiMiddleware.AnyId, S>(sessionLo
|
|||
}),
|
||||
),
|
||||
)
|
||||
.add(
|
||||
HttpApiEndpoint.delete("session.remove", "/api/session/:sessionID", {
|
||||
params: { sessionID: Session.ID },
|
||||
success: HttpApiSchema.NoContent,
|
||||
error: SessionNotFoundError,
|
||||
})
|
||||
.middleware(sessionLocationMiddleware)
|
||||
.annotateMerge(
|
||||
OpenApi.annotations({
|
||||
identifier: "v2.session.remove",
|
||||
summary: "Delete session",
|
||||
description: "Delete a session and its child sessions.",
|
||||
}),
|
||||
),
|
||||
)
|
||||
.add(
|
||||
HttpApiEndpoint.post("session.fork", "/api/session/:sessionID/fork", {
|
||||
params: { sessionID: Session.ID },
|
||||
|
|
@ -271,7 +279,7 @@ export const makeSessionGroup = <I extends HttpApiMiddleware.AnyId, S>(sessionLo
|
|||
resume: Schema.Boolean.pipe(Schema.optional),
|
||||
}),
|
||||
success: Schema.Struct({ data: SessionInput.Admitted }),
|
||||
error: [ConflictError, SessionNotFoundError],
|
||||
error: [ConflictError, InvalidRequestError, SessionNotFoundError],
|
||||
})
|
||||
.middleware(sessionLocationMiddleware)
|
||||
.annotateMerge(
|
||||
|
|
@ -297,7 +305,7 @@ export const makeSessionGroup = <I extends HttpApiMiddleware.AnyId, S>(sessionLo
|
|||
resume: Schema.Boolean.pipe(Schema.optional),
|
||||
}),
|
||||
success: Schema.Struct({ data: SessionInput.Admitted }),
|
||||
error: [ConflictError, SessionNotFoundError, CommandNotFoundError, CommandEvaluationError],
|
||||
error: [ConflictError, InvalidRequestError, SessionNotFoundError, CommandNotFoundError, CommandEvaluationError],
|
||||
})
|
||||
.middleware(sessionLocationMiddleware)
|
||||
.annotateMerge(
|
||||
|
|
@ -372,15 +380,16 @@ export const makeSessionGroup = <I extends HttpApiMiddleware.AnyId, S>(sessionLo
|
|||
.add(
|
||||
HttpApiEndpoint.post("session.compact", "/api/session/:sessionID/compact", {
|
||||
params: { sessionID: Session.ID },
|
||||
success: HttpApiSchema.NoContent,
|
||||
error: [SessionNotFoundError, SessionBusyError, ServiceUnavailableError, UnknownError],
|
||||
payload: Schema.Struct({ id: SessionMessage.ID.pipe(Schema.optional) }),
|
||||
success: Schema.Struct({ data: SessionInput.Compaction }),
|
||||
error: [ConflictError, SessionNotFoundError],
|
||||
})
|
||||
.middleware(sessionLocationMiddleware)
|
||||
.annotateMerge(
|
||||
OpenApi.annotations({
|
||||
identifier: "v2.session.compact",
|
||||
summary: "Compact session",
|
||||
description: "Compact a session conversation.",
|
||||
description: "Queue a durable session compaction request.",
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
|
@ -451,23 +460,23 @@ export const makeSessionGroup = <I extends HttpApiMiddleware.AnyId, S>(sessionLo
|
|||
),
|
||||
)
|
||||
.add(
|
||||
HttpApiEndpoint.get("session.context.entry.list", "/api/session/:sessionID/context-entry", {
|
||||
HttpApiEndpoint.get("session.instructions.entry.list", "/api/session/:sessionID/instructions/entries", {
|
||||
params: { sessionID: Session.ID },
|
||||
success: Schema.Struct({ data: Schema.Array(SessionContextEntry.Info) }),
|
||||
success: Schema.Struct({ data: Schema.Array(InstructionEntry.Info) }),
|
||||
error: SessionNotFoundError,
|
||||
})
|
||||
.middleware(sessionLocationMiddleware)
|
||||
.annotateMerge(
|
||||
OpenApi.annotations({
|
||||
identifier: "v2.session.context.entry.list",
|
||||
summary: "List context entries",
|
||||
description: "List API-managed context entries attached to the session's system context.",
|
||||
identifier: "v2.session.instructions.entry.list",
|
||||
summary: "List instruction entries",
|
||||
description: "List API-managed instruction entries attached to the session.",
|
||||
}),
|
||||
),
|
||||
)
|
||||
.add(
|
||||
HttpApiEndpoint.put("session.context.entry.put", "/api/session/:sessionID/context-entry/:key", {
|
||||
params: { sessionID: Session.ID, key: SessionContextEntry.Key },
|
||||
HttpApiEndpoint.put("session.instructions.entry.put", "/api/session/:sessionID/instructions/entries/:key", {
|
||||
params: { sessionID: Session.ID, key: InstructionEntry.Key },
|
||||
payload: Schema.Struct({ value: Schema.Json }),
|
||||
success: HttpApiSchema.NoContent,
|
||||
error: SessionNotFoundError,
|
||||
|
|
@ -475,30 +484,31 @@ export const makeSessionGroup = <I extends HttpApiMiddleware.AnyId, S>(sessionLo
|
|||
.middleware(sessionLocationMiddleware)
|
||||
.annotateMerge(
|
||||
OpenApi.annotations({
|
||||
identifier: "v2.session.context.entry.put",
|
||||
summary: "Put context entry",
|
||||
identifier: "v2.session.instructions.entry.put",
|
||||
summary: "Put instruction entry",
|
||||
description:
|
||||
"Attach or replace one durable context entry. The value is rendered into the session's system context; changes announce as updates at the next turn boundary.",
|
||||
"Attach or replace one durable instruction entry. Changes announce as updates at the next step boundary.",
|
||||
}),
|
||||
),
|
||||
)
|
||||
.add(
|
||||
HttpApiEndpoint.delete("session.context.entry.remove", "/api/session/:sessionID/context-entry/:key", {
|
||||
params: { sessionID: Session.ID, key: SessionContextEntry.Key },
|
||||
HttpApiEndpoint.delete("session.instructions.entry.remove", "/api/session/:sessionID/instructions/entries/:key", {
|
||||
params: { sessionID: Session.ID, key: InstructionEntry.Key },
|
||||
success: HttpApiSchema.NoContent,
|
||||
error: SessionNotFoundError,
|
||||
})
|
||||
.middleware(sessionLocationMiddleware)
|
||||
.annotateMerge(
|
||||
OpenApi.annotations({
|
||||
identifier: "v2.session.context.entry.remove",
|
||||
summary: "Remove context entry",
|
||||
description: "Remove one context entry; the removal is announced to the model at the next turn boundary.",
|
||||
identifier: "v2.session.instructions.entry.remove",
|
||||
summary: "Remove instruction entry",
|
||||
description:
|
||||
"Remove one instruction entry; the removal is announced to the model at the next step boundary.",
|
||||
}),
|
||||
),
|
||||
)
|
||||
.add(
|
||||
HttpApiEndpoint.get("session.log", "/api/session/:sessionID/log", {
|
||||
HttpApiEndpoint.get("session.log", "/api/experimental/session/:sessionID/log", {
|
||||
params: { sessionID: Session.ID },
|
||||
query: {
|
||||
after: Schema.NumberFromString.pipe(Schema.decodeTo(Event.Seq), Schema.optional),
|
||||
|
|
@ -515,7 +525,7 @@ export const makeSessionGroup = <I extends HttpApiMiddleware.AnyId, S>(sessionLo
|
|||
identifier: "v2.session.log",
|
||||
summary: "Read the session log",
|
||||
description:
|
||||
"Durable, ordered, gap-free read of public session events after an exclusive aggregate sequence. Emits a synced marker once replay reaches the captured watermark, then completes; with follow=true it continues with live events instead. The only event API that promises reliability: attach after a snapshot watermark to compose fetch and stream without a race window.",
|
||||
"Experimental durable session event log. Reads events after an exclusive aggregate sequence and continues with live events when follow=true.",
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,15 @@
|
|||
import { Shell } from "@opencode-ai/schema/shell"
|
||||
import { Location } from "@opencode-ai/schema/location"
|
||||
import { NonNegativeInt } from "@opencode-ai/schema/schema"
|
||||
import { Schema } from "effect"
|
||||
import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema, OpenApi } from "effect/unstable/httpapi"
|
||||
import { ShellNotFoundError } from "../errors.js"
|
||||
import { LocationQuery, locationQueryOpenApi } from "./location.js"
|
||||
|
||||
const TimeoutInput = Schema.Struct({
|
||||
timeout: NonNegativeInt,
|
||||
})
|
||||
|
||||
export const ShellGroup = HttpApiGroup.make("server.shell")
|
||||
.add(
|
||||
HttpApiEndpoint.get("shell.list", "/api/shell", {
|
||||
|
|
@ -52,6 +57,23 @@ export const ShellGroup = HttpApiGroup.make("server.shell")
|
|||
}),
|
||||
),
|
||||
)
|
||||
.add(
|
||||
HttpApiEndpoint.patch("shell.timeout", "/api/shell/:id/timeout", {
|
||||
params: { id: Shell.ID },
|
||||
query: LocationQuery,
|
||||
payload: TimeoutInput,
|
||||
success: Location.response(Shell.Info),
|
||||
error: ShellNotFoundError,
|
||||
})
|
||||
.annotateMerge(locationQueryOpenApi)
|
||||
.annotateMerge(
|
||||
OpenApi.annotations({
|
||||
identifier: "v2.shell.timeout",
|
||||
summary: "Update shell timeout",
|
||||
description: "Replace a running shell command's timeout from now, or clear it with zero.",
|
||||
}),
|
||||
),
|
||||
)
|
||||
.add(
|
||||
HttpApiEndpoint.get("shell.output", "/api/shell/:id/output", {
|
||||
params: { id: Shell.ID },
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue