Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e74453145d | |||
| 1b57c71eb9 | |||
| e263664963 | |||
| 47fdf60e76 | |||
| d5ca70fbc1 |
@@ -0,0 +1,36 @@
|
||||
export default {
|
||||
id: "Orchestrator",
|
||||
setup: async (ctx) => {
|
||||
await ctx.agent.transform((agents) => {
|
||||
agents.update("orchestrator", (agent) => {
|
||||
agent.description = "Coordinates work by delegating implementation tasks to the minion subagent."
|
||||
agent.mode = "primary"
|
||||
agent.system = [
|
||||
"You are Orchestrator, the primary coordinating agent for this repository. You do meta work only: you coordinate, brief, and synthesize — you do not perform the work itself.",
|
||||
"Delegate ALL actual work to the minion subagent — implementation, exploration, discovery, searching the codebase, reading files to understand a problem, and even trivial one-line edits. Task size is never a reason to do it yourself, and there is no 'final integration' exception.",
|
||||
"You are not hard-banned from tools, but direct tool use is reserved for coordination overhead: a quick peek to phrase a better brief, a fast read-only check to verify a minion's reported result, or answering a question about coordination state. If a tool call is producing the answer or the artifact the user asked for, that call belongs to a minion, not you.",
|
||||
"Exploration is work. If the user asks how something works or where something lives, delegate the investigation to a minion rather than exploring yourself.",
|
||||
"Always start minion subagents in the background. Even if you have nothing else to coordinate right now, the user may assign you new work while a Minion runs, and you must stay free to receive it. Never poll; you will be notified when they finish.",
|
||||
"Give each minion a clear, self-contained brief: the goal, constraints, expected output, and any files or context already known from the user or previous minion reports.",
|
||||
"Synthesize minion results, decide next steps, and report back concisely.",
|
||||
].join("\n")
|
||||
})
|
||||
|
||||
agents.update("minion", (agent) => {
|
||||
agent.description = "Subagent that executes focused tasks delegated by Orchestrator."
|
||||
agent.mode = "subagent"
|
||||
agent.model = { providerID: "opencode", id: "glm-5.2" }
|
||||
agent.system = [
|
||||
"You are minion, a focused execution subagent for this repository.",
|
||||
"Complete the specific task delegated to you by Orchestrator using the available tools.",
|
||||
"Inspect the codebase before making assumptions, make targeted changes when requested, and verify your work when feasible.",
|
||||
"Follow the repository's AGENTS.md conventions: respect the style guide, run `bun typecheck` from the affected package directory after code changes, never run tests from the repo root, and do not modify packages/opencode unless the task explicitly says V1 work.",
|
||||
"If the task is ambiguous or you hit a blocker, stop and report your findings instead of guessing.",
|
||||
"Keep your final response concise: summarize what you did, list important files changed or findings, and call out blockers or verification gaps.",
|
||||
"Do not delegate to other subagents; execute the assigned work yourself.",
|
||||
].join("\n")
|
||||
agent.permissions.push({ action: "subagent", resource: "*", effect: "deny" })
|
||||
})
|
||||
})
|
||||
},
|
||||
}
|
||||
@@ -104,25 +104,6 @@ bun dev api <operationId> --param key=value
|
||||
- If no compatible background server is registered, `bun dev api` starts one through the daemon service. Use `bun dev service status`, `bun dev service restart`, and `bun dev service stop` when you need explicit lifecycle control.
|
||||
- Prefer raw method/path calls for quick server debugging and operation IDs when exercising documented OpenAPI routes with path or query parameters.
|
||||
|
||||
## Auditing installed `opencode2` sessions
|
||||
|
||||
Installed next-channel sessions normally use `~/.local/share/opencode/opencode-next.db` and `~/.local/share/opencode/log/opencode.log`; `OPENCODE_DB` can override the database. Before calling `opencode2 api`, inspect `~/.local/state/opencode/service.json` because the command may start a daemon when none is healthy.
|
||||
|
||||
For a supplied `ses_...` ID, compare three sources:
|
||||
|
||||
- `opencode2 api get /api/session/active` and the Session/message endpoints for live server state.
|
||||
- The database's ordered `event` rows for durable history.
|
||||
- `packages/tui/src/context/data.tsx` and the relevant route for client projection and rendering.
|
||||
|
||||
Locate an uncertain database without modifying it:
|
||||
|
||||
```bash
|
||||
SESSION=ses_...
|
||||
for db in ~/.local/share/opencode/*.db; do
|
||||
sqlite3 "file:$db?mode=ro" "select 1 from session where id='$SESSION' limit 1" 2>/dev/null | grep -q 1 && printf '%s\n' "$db"
|
||||
done
|
||||
```
|
||||
|
||||
## Logs
|
||||
|
||||
- Log files live under `~/.local/share/opencode/log/`. In a local/dev checkout the active file is `opencode-local.log`; `opencode.log` is used for non-local (released) channel installs. Both are append-only, shared across every CLI and server process on the machine.
|
||||
|
||||
@@ -151,7 +151,6 @@ const table = sqliteTable("session", {
|
||||
|
||||
## V2 Session Core
|
||||
|
||||
- Keep durable events minimal: record irreducible new facts and do not repeat state derivable by folding the ordered aggregate history. Enrich projections and read models with previous or derived state when consumers need self-contained views.
|
||||
- Keep durable prompt admission separate from model execution. `SessionV2.prompt(...)` admits one durable `session_input` row before scheduling advisory `SessionExecution.wake(sessionID)` unless `resume: false` requests admit-only behavior. The serialized runner promotes admitted inputs into visible user messages at safe boundaries.
|
||||
- Reusing a Session ID adopts the existing Session. Reusing a prompt message ID reconciles an exact retry only when Session, prompt, and delivery mode match; conflicting reuse fails. Historical projected prompts lazily synthesize promoted inbox records during exact retry.
|
||||
- Keep `SessionExecution` process-global and Session-ID based. Its local implementation owns the process-local Session coordinator and discovers placement through `SessionStore` plus `LocationServiceMap.get(session.location)` only when a drain starts; no layer should take a Session ID. V2 interruption targets the active process-local ownership chain for that Session; idle or missing interruption is a no-op.
|
||||
|
||||
@@ -163,11 +163,8 @@ export type Endpoint4_12Output = EffectValue<ReturnType<RawClient["server.sessio
|
||||
export type SessionShellOperation<E = never> = (input: Endpoint4_12Input) => Effect.Effect<Endpoint4_12Output, E>
|
||||
|
||||
type Endpoint4_13Request = Parameters<RawClient["server.session"]["session.compact"]>[0]
|
||||
export type Endpoint4_13Input = {
|
||||
readonly sessionID: Endpoint4_13Request["params"]["sessionID"]
|
||||
readonly id?: Endpoint4_13Request["payload"]["id"]
|
||||
}
|
||||
export type Endpoint4_13Output = EffectValue<ReturnType<RawClient["server.session"]["session.compact"]>>["data"]
|
||||
export type Endpoint4_13Input = { readonly sessionID: Endpoint4_13Request["params"]["sessionID"] }
|
||||
export type Endpoint4_13Output = EffectValue<ReturnType<RawClient["server.session"]["session.compact"]>>
|
||||
export type SessionCompactOperation<E = never> = (input: Endpoint4_13Input) => Effect.Effect<Endpoint4_13Output, E>
|
||||
|
||||
type Endpoint4_14Request = Parameters<RawClient["server.session"]["session.wait"]>[0]
|
||||
|
||||
@@ -221,15 +221,9 @@ const Endpoint4_12 = (raw: RawClient["server.session"]) => (input: Endpoint4_12I
|
||||
}).pipe(Effect.mapError(mapClientError))
|
||||
|
||||
type Endpoint4_13Request = Parameters<RawClient["server.session"]["session.compact"]>[0]
|
||||
type Endpoint4_13Input = {
|
||||
readonly sessionID: Endpoint4_13Request["params"]["sessionID"]
|
||||
readonly id?: Endpoint4_13Request["payload"]["id"]
|
||||
}
|
||||
type Endpoint4_13Input = { readonly sessionID: Endpoint4_13Request["params"]["sessionID"] }
|
||||
const Endpoint4_13 = (raw: RawClient["server.session"]) => (input: Endpoint4_13Input) =>
|
||||
raw["session.compact"]({ params: { sessionID: input["sessionID"] }, payload: { id: input["id"] } }).pipe(
|
||||
Effect.mapError(mapClientError),
|
||||
Effect.map((value) => value.data),
|
||||
)
|
||||
raw["session.compact"]({ params: { sessionID: input["sessionID"] } }).pipe(Effect.mapError(mapClientError))
|
||||
|
||||
type Endpoint4_14Request = Parameters<RawClient["server.session"]["session.wait"]>[0]
|
||||
type Endpoint4_14Input = { readonly sessionID: Endpoint4_14Request["params"]["sessionID"] }
|
||||
|
||||
@@ -540,17 +540,16 @@ export function make(options: ClientOptions) {
|
||||
requestOptions,
|
||||
),
|
||||
compact: (input: SessionCompactInput, requestOptions?: RequestOptions) =>
|
||||
request<{ readonly data: SessionCompactOutput }>(
|
||||
request<SessionCompactOutput>(
|
||||
{
|
||||
method: "POST",
|
||||
path: `/api/session/${encodeURIComponent(input.sessionID)}/compact`,
|
||||
body: { id: input["id"] },
|
||||
successStatus: 200,
|
||||
declaredStatuses: [409, 404, 400, 401],
|
||||
empty: false,
|
||||
successStatus: 204,
|
||||
declaredStatuses: [404, 409, 503, 500, 400, 401],
|
||||
empty: true,
|
||||
},
|
||||
requestOptions,
|
||||
).then((value) => value.data),
|
||||
),
|
||||
wait: (input: SessionWaitInput, requestOptions?: RequestOptions) =>
|
||||
request<SessionWaitOutput>(
|
||||
{
|
||||
|
||||
@@ -74,14 +74,6 @@ export type SkillNotFoundError = {
|
||||
export const isSkillNotFoundError = (value: unknown): value is SkillNotFoundError =>
|
||||
typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "SkillNotFoundError"
|
||||
|
||||
export type ServiceUnavailableError = {
|
||||
readonly _tag: "ServiceUnavailableError"
|
||||
readonly message: string
|
||||
readonly service?: string | undefined
|
||||
}
|
||||
export const isServiceUnavailableError = (value: unknown): value is ServiceUnavailableError =>
|
||||
typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "ServiceUnavailableError"
|
||||
|
||||
export type SessionBusyError = {
|
||||
readonly _tag: "SessionBusyError"
|
||||
readonly sessionID: string
|
||||
@@ -90,6 +82,14 @@ export type SessionBusyError = {
|
||||
export const isSessionBusyError = (value: unknown): value is SessionBusyError =>
|
||||
typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "SessionBusyError"
|
||||
|
||||
export type ServiceUnavailableError = {
|
||||
readonly _tag: "ServiceUnavailableError"
|
||||
readonly message: string
|
||||
readonly service?: string | undefined
|
||||
}
|
||||
export const isServiceUnavailableError = (value: unknown): value is ServiceUnavailableError =>
|
||||
typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "ServiceUnavailableError"
|
||||
|
||||
export type UnknownError = {
|
||||
readonly _tag: "UnknownError"
|
||||
readonly message: string
|
||||
@@ -873,21 +873,9 @@ export type SessionShellInput = {
|
||||
|
||||
export type SessionShellOutput = void
|
||||
|
||||
export type SessionCompactInput = {
|
||||
readonly sessionID: { readonly sessionID: string }["sessionID"]
|
||||
readonly id?: { readonly id?: string | undefined }["id"]
|
||||
}
|
||||
export type SessionCompactInput = { readonly sessionID: { readonly sessionID: string }["sessionID"] }
|
||||
|
||||
export type SessionCompactOutput = {
|
||||
readonly data: {
|
||||
readonly type: "compaction"
|
||||
readonly admittedSeq: number
|
||||
readonly id: string
|
||||
readonly sessionID: string
|
||||
readonly timeCreated: number
|
||||
readonly handledSeq?: number
|
||||
}
|
||||
}["data"]
|
||||
export type SessionCompactOutput = void
|
||||
|
||||
export type SessionWaitInput = { readonly sessionID: { readonly sessionID: string }["sessionID"] }
|
||||
|
||||
@@ -940,7 +928,6 @@ export type SessionContextOutput = {
|
||||
readonly time: { readonly created: number }
|
||||
readonly type: "model-switched"
|
||||
readonly model: { readonly id: string; readonly providerID: string; readonly variant?: string }
|
||||
readonly previous?: { readonly id: string; readonly providerID: string; readonly variant?: string }
|
||||
}
|
||||
| {
|
||||
readonly id: string
|
||||
@@ -1070,7 +1057,37 @@ export type SessionContextOutput = {
|
||||
| { readonly type: "file"; readonly uri: string; readonly mime: string; readonly name?: string }
|
||||
>
|
||||
readonly structured: { readonly [x: string]: JsonValue }
|
||||
readonly error: { readonly type: string; readonly message: string }
|
||||
readonly error:
|
||||
| {
|
||||
readonly type: "provider.rate-limit"
|
||||
readonly message: string
|
||||
readonly retryAfterMs?: number
|
||||
}
|
||||
| { readonly type: "provider.auth"; readonly message: string }
|
||||
| { readonly type: "provider.quota"; readonly message: string }
|
||||
| { readonly type: "provider.content-filter"; readonly message: string }
|
||||
| { readonly type: "provider.transport"; readonly message: string }
|
||||
| { readonly type: "provider.internal"; readonly message: string }
|
||||
| { readonly type: "provider.invalid-output"; readonly message: string }
|
||||
| { readonly type: "provider.invalid-request"; readonly message: string }
|
||||
| { readonly type: "provider.no-route"; readonly message: string }
|
||||
| { readonly type: "provider.unknown"; readonly message: string }
|
||||
| {
|
||||
readonly type: "permission.rejected"
|
||||
readonly message: string
|
||||
readonly permission: string
|
||||
readonly resources: ReadonlyArray<string>
|
||||
}
|
||||
| { readonly type: "tool.unknown"; readonly message: string; readonly name: string }
|
||||
| { readonly type: "tool.stale"; readonly message: string; readonly name?: string }
|
||||
| { readonly type: "tool.execution"; readonly message: string }
|
||||
| { readonly type: "tool.result-missing"; readonly message: string; readonly callID?: string }
|
||||
| {
|
||||
readonly type: "aborted"
|
||||
readonly message: string
|
||||
readonly reason?: "user" | "shutdown" | "timeout"
|
||||
}
|
||||
| { readonly type: "unknown"; readonly message: string; readonly agent?: string }
|
||||
readonly result?: JsonValue
|
||||
}
|
||||
readonly time: {
|
||||
@@ -1090,16 +1107,59 @@ export type SessionContextOutput = {
|
||||
readonly reasoning: number
|
||||
readonly cache: { readonly read: number; readonly write: number }
|
||||
}
|
||||
readonly error?: { readonly type: string; readonly message: string }
|
||||
readonly error?:
|
||||
| { readonly type: "provider.rate-limit"; readonly message: string; readonly retryAfterMs?: number }
|
||||
| { readonly type: "provider.auth"; readonly message: string }
|
||||
| { readonly type: "provider.quota"; readonly message: string }
|
||||
| { readonly type: "provider.content-filter"; readonly message: string }
|
||||
| { readonly type: "provider.transport"; readonly message: string }
|
||||
| { readonly type: "provider.internal"; readonly message: string }
|
||||
| { readonly type: "provider.invalid-output"; readonly message: string }
|
||||
| { readonly type: "provider.invalid-request"; readonly message: string }
|
||||
| { readonly type: "provider.no-route"; readonly message: string }
|
||||
| { readonly type: "provider.unknown"; readonly message: string }
|
||||
| {
|
||||
readonly type: "permission.rejected"
|
||||
readonly message: string
|
||||
readonly permission: string
|
||||
readonly resources: ReadonlyArray<string>
|
||||
}
|
||||
| { readonly type: "tool.unknown"; readonly message: string; readonly name: string }
|
||||
| { readonly type: "tool.stale"; readonly message: string; readonly name?: string }
|
||||
| { readonly type: "tool.execution"; readonly message: string }
|
||||
| { readonly type: "tool.result-missing"; readonly message: string; readonly callID?: string }
|
||||
| { readonly type: "aborted"; readonly message: string; readonly reason?: "user" | "shutdown" | "timeout" }
|
||||
| { readonly type: "unknown"; readonly message: string; readonly agent?: string }
|
||||
readonly retry?: {
|
||||
readonly attempt: number
|
||||
readonly at: number
|
||||
readonly error: { readonly type: string; readonly message: string }
|
||||
readonly error:
|
||||
| { readonly type: "provider.rate-limit"; readonly message: string; readonly retryAfterMs?: number }
|
||||
| { readonly type: "provider.auth"; readonly message: string }
|
||||
| { readonly type: "provider.quota"; readonly message: string }
|
||||
| { readonly type: "provider.content-filter"; readonly message: string }
|
||||
| { readonly type: "provider.transport"; readonly message: string }
|
||||
| { readonly type: "provider.internal"; readonly message: string }
|
||||
| { readonly type: "provider.invalid-output"; readonly message: string }
|
||||
| { readonly type: "provider.invalid-request"; readonly message: string }
|
||||
| { readonly type: "provider.no-route"; readonly message: string }
|
||||
| { readonly type: "provider.unknown"; readonly message: string }
|
||||
| {
|
||||
readonly type: "permission.rejected"
|
||||
readonly message: string
|
||||
readonly permission: string
|
||||
readonly resources: ReadonlyArray<string>
|
||||
}
|
||||
| { readonly type: "tool.unknown"; readonly message: string; readonly name: string }
|
||||
| { readonly type: "tool.stale"; readonly message: string; readonly name?: string }
|
||||
| { readonly type: "tool.execution"; readonly message: string }
|
||||
| { readonly type: "tool.result-missing"; readonly message: string; readonly callID?: string }
|
||||
| { readonly type: "aborted"; readonly message: string; readonly reason?: "user" | "shutdown" | "timeout" }
|
||||
| { readonly type: "unknown"; readonly message: string; readonly agent?: string }
|
||||
}
|
||||
}
|
||||
| {
|
||||
readonly type: "compaction"
|
||||
readonly status: "queued" | "running" | "completed" | "failed"
|
||||
readonly reason: "auto" | "manual"
|
||||
readonly summary: string
|
||||
readonly recent: string
|
||||
@@ -1254,7 +1314,33 @@ export type SessionLogOutput =
|
||||
readonly location?: { readonly directory: string; readonly workspaceID?: string }
|
||||
readonly data: {
|
||||
readonly sessionID: string
|
||||
readonly error: { readonly type: string; readonly message: string }
|
||||
readonly error:
|
||||
| { readonly type: "provider.rate-limit"; readonly message: string; readonly retryAfterMs?: number }
|
||||
| { readonly type: "provider.auth"; readonly message: string }
|
||||
| { readonly type: "provider.quota"; readonly message: string }
|
||||
| { readonly type: "provider.content-filter"; readonly message: string }
|
||||
| { readonly type: "provider.transport"; readonly message: string }
|
||||
| { readonly type: "provider.internal"; readonly message: string }
|
||||
| { readonly type: "provider.invalid-output"; readonly message: string }
|
||||
| { readonly type: "provider.invalid-request"; readonly message: string }
|
||||
| { readonly type: "provider.no-route"; readonly message: string }
|
||||
| { readonly type: "provider.unknown"; readonly message: string }
|
||||
| {
|
||||
readonly type: "permission.rejected"
|
||||
readonly message: string
|
||||
readonly permission: string
|
||||
readonly resources: ReadonlyArray<string>
|
||||
}
|
||||
| { readonly type: "tool.unknown"; readonly message: string; readonly name: string }
|
||||
| { readonly type: "tool.stale"; readonly message: string; readonly name?: string }
|
||||
| { readonly type: "tool.execution"; readonly message: string }
|
||||
| { readonly type: "tool.result-missing"; readonly message: string; readonly callID?: string }
|
||||
| {
|
||||
readonly type: "aborted"
|
||||
readonly message: string
|
||||
readonly reason?: "user" | "shutdown" | "timeout"
|
||||
}
|
||||
| { readonly type: "unknown"; readonly message: string; readonly agent?: string }
|
||||
}
|
||||
}
|
||||
| {
|
||||
@@ -1397,7 +1483,33 @@ export type SessionLogOutput =
|
||||
readonly data: {
|
||||
readonly sessionID: string
|
||||
readonly assistantMessageID: string
|
||||
readonly error: { readonly type: string; readonly message: string }
|
||||
readonly error:
|
||||
| { readonly type: "provider.rate-limit"; readonly message: string; readonly retryAfterMs?: number }
|
||||
| { readonly type: "provider.auth"; readonly message: string }
|
||||
| { readonly type: "provider.quota"; readonly message: string }
|
||||
| { readonly type: "provider.content-filter"; readonly message: string }
|
||||
| { readonly type: "provider.transport"; readonly message: string }
|
||||
| { readonly type: "provider.internal"; readonly message: string }
|
||||
| { readonly type: "provider.invalid-output"; readonly message: string }
|
||||
| { readonly type: "provider.invalid-request"; readonly message: string }
|
||||
| { readonly type: "provider.no-route"; readonly message: string }
|
||||
| { readonly type: "provider.unknown"; readonly message: string }
|
||||
| {
|
||||
readonly type: "permission.rejected"
|
||||
readonly message: string
|
||||
readonly permission: string
|
||||
readonly resources: ReadonlyArray<string>
|
||||
}
|
||||
| { readonly type: "tool.unknown"; readonly message: string; readonly name: string }
|
||||
| { readonly type: "tool.stale"; readonly message: string; readonly name?: string }
|
||||
| { readonly type: "tool.execution"; readonly message: string }
|
||||
| { readonly type: "tool.result-missing"; readonly message: string; readonly callID?: string }
|
||||
| {
|
||||
readonly type: "aborted"
|
||||
readonly message: string
|
||||
readonly reason?: "user" | "shutdown" | "timeout"
|
||||
}
|
||||
| { readonly type: "unknown"; readonly message: string; readonly agent?: string }
|
||||
}
|
||||
}
|
||||
| {
|
||||
@@ -1407,7 +1519,7 @@ export type SessionLogOutput =
|
||||
readonly type: "session.text.started"
|
||||
readonly durable: { readonly aggregateID: string; readonly seq: number; readonly version: number }
|
||||
readonly location?: { readonly directory: string; readonly workspaceID?: string }
|
||||
readonly data: { readonly sessionID: string; readonly assistantMessageID: string; readonly ordinal: number }
|
||||
readonly data: { readonly sessionID: string; readonly assistantMessageID: string }
|
||||
}
|
||||
| {
|
||||
readonly id: string
|
||||
@@ -1416,12 +1528,7 @@ export type SessionLogOutput =
|
||||
readonly type: "session.text.ended"
|
||||
readonly durable: { readonly aggregateID: string; readonly seq: number; readonly version: number }
|
||||
readonly location?: { readonly directory: string; readonly workspaceID?: string }
|
||||
readonly data: {
|
||||
readonly sessionID: string
|
||||
readonly assistantMessageID: string
|
||||
readonly ordinal: number
|
||||
readonly text: string
|
||||
}
|
||||
readonly data: { readonly sessionID: string; readonly assistantMessageID: string; readonly text: string }
|
||||
}
|
||||
| {
|
||||
readonly id: string
|
||||
@@ -1433,7 +1540,6 @@ export type SessionLogOutput =
|
||||
readonly data: {
|
||||
readonly sessionID: string
|
||||
readonly assistantMessageID: string
|
||||
readonly ordinal: number
|
||||
readonly state?: { readonly [x: string]: unknown }
|
||||
}
|
||||
}
|
||||
@@ -1447,7 +1553,6 @@ export type SessionLogOutput =
|
||||
readonly data: {
|
||||
readonly sessionID: string
|
||||
readonly assistantMessageID: string
|
||||
readonly ordinal: number
|
||||
readonly text: string
|
||||
readonly state?: { readonly [x: string]: unknown }
|
||||
}
|
||||
@@ -1547,7 +1652,33 @@ export type SessionLogOutput =
|
||||
readonly sessionID: string
|
||||
readonly assistantMessageID: string
|
||||
readonly callID: string
|
||||
readonly error: { readonly type: string; readonly message: string }
|
||||
readonly error:
|
||||
| { readonly type: "provider.rate-limit"; readonly message: string; readonly retryAfterMs?: number }
|
||||
| { readonly type: "provider.auth"; readonly message: string }
|
||||
| { readonly type: "provider.quota"; readonly message: string }
|
||||
| { readonly type: "provider.content-filter"; readonly message: string }
|
||||
| { readonly type: "provider.transport"; readonly message: string }
|
||||
| { readonly type: "provider.internal"; readonly message: string }
|
||||
| { readonly type: "provider.invalid-output"; readonly message: string }
|
||||
| { readonly type: "provider.invalid-request"; readonly message: string }
|
||||
| { readonly type: "provider.no-route"; readonly message: string }
|
||||
| { readonly type: "provider.unknown"; readonly message: string }
|
||||
| {
|
||||
readonly type: "permission.rejected"
|
||||
readonly message: string
|
||||
readonly permission: string
|
||||
readonly resources: ReadonlyArray<string>
|
||||
}
|
||||
| { readonly type: "tool.unknown"; readonly message: string; readonly name: string }
|
||||
| { readonly type: "tool.stale"; readonly message: string; readonly name?: string }
|
||||
| { readonly type: "tool.execution"; readonly message: string }
|
||||
| { readonly type: "tool.result-missing"; readonly message: string; readonly callID?: string }
|
||||
| {
|
||||
readonly type: "aborted"
|
||||
readonly message: string
|
||||
readonly reason?: "user" | "shutdown" | "timeout"
|
||||
}
|
||||
| { readonly type: "unknown"; readonly message: string; readonly agent?: string }
|
||||
readonly result?: unknown
|
||||
readonly executed: boolean
|
||||
readonly resultState?: { readonly [x: string]: unknown }
|
||||
@@ -1565,18 +1696,35 @@ export type SessionLogOutput =
|
||||
readonly assistantMessageID: string
|
||||
readonly attempt: number
|
||||
readonly at: number
|
||||
readonly error: { readonly type: string; readonly message: string }
|
||||
readonly error:
|
||||
| { readonly type: "provider.rate-limit"; readonly message: string; readonly retryAfterMs?: number }
|
||||
| { readonly type: "provider.auth"; readonly message: string }
|
||||
| { readonly type: "provider.quota"; readonly message: string }
|
||||
| { readonly type: "provider.content-filter"; readonly message: string }
|
||||
| { readonly type: "provider.transport"; readonly message: string }
|
||||
| { readonly type: "provider.internal"; readonly message: string }
|
||||
| { readonly type: "provider.invalid-output"; readonly message: string }
|
||||
| { readonly type: "provider.invalid-request"; readonly message: string }
|
||||
| { readonly type: "provider.no-route"; readonly message: string }
|
||||
| { readonly type: "provider.unknown"; readonly message: string }
|
||||
| {
|
||||
readonly type: "permission.rejected"
|
||||
readonly message: string
|
||||
readonly permission: string
|
||||
readonly resources: ReadonlyArray<string>
|
||||
}
|
||||
| { readonly type: "tool.unknown"; readonly message: string; readonly name: string }
|
||||
| { readonly type: "tool.stale"; readonly message: string; readonly name?: string }
|
||||
| { readonly type: "tool.execution"; readonly message: string }
|
||||
| { readonly type: "tool.result-missing"; readonly message: string; readonly callID?: string }
|
||||
| {
|
||||
readonly type: "aborted"
|
||||
readonly message: string
|
||||
readonly reason?: "user" | "shutdown" | "timeout"
|
||||
}
|
||||
| { readonly type: "unknown"; readonly message: string; readonly agent?: string }
|
||||
}
|
||||
}
|
||||
| {
|
||||
readonly id: string
|
||||
readonly created: number
|
||||
readonly metadata?: { readonly [x: string]: unknown }
|
||||
readonly type: "session.compaction.admitted"
|
||||
readonly durable: { readonly aggregateID: string; readonly seq: number; readonly version: number }
|
||||
readonly location?: { readonly directory: string; readonly workspaceID?: string }
|
||||
readonly data: { readonly sessionID: string; readonly inputID: string }
|
||||
}
|
||||
| {
|
||||
readonly id: string
|
||||
readonly created: number
|
||||
@@ -1600,15 +1748,6 @@ export type SessionLogOutput =
|
||||
readonly recent: string
|
||||
}
|
||||
}
|
||||
| {
|
||||
readonly id: string
|
||||
readonly created: number
|
||||
readonly metadata?: { readonly [x: string]: unknown }
|
||||
readonly type: "session.compaction.failed"
|
||||
readonly durable: { readonly aggregateID: string; readonly seq: number; readonly version: number }
|
||||
readonly location?: { readonly directory: string; readonly workspaceID?: string }
|
||||
readonly data: { readonly sessionID: string }
|
||||
}
|
||||
| {
|
||||
readonly id: string
|
||||
readonly created: number
|
||||
@@ -1682,7 +1821,6 @@ export type SessionMessageOutput = {
|
||||
readonly time: { readonly created: number }
|
||||
readonly type: "model-switched"
|
||||
readonly model: { readonly id: string; readonly providerID: string; readonly variant?: string }
|
||||
readonly previous?: { readonly id: string; readonly providerID: string; readonly variant?: string }
|
||||
}
|
||||
| {
|
||||
readonly id: string
|
||||
@@ -1812,7 +1950,37 @@ export type SessionMessageOutput = {
|
||||
| { readonly type: "file"; readonly uri: string; readonly mime: string; readonly name?: string }
|
||||
>
|
||||
readonly structured: { readonly [x: string]: JsonValue }
|
||||
readonly error: { readonly type: string; readonly message: string }
|
||||
readonly error:
|
||||
| {
|
||||
readonly type: "provider.rate-limit"
|
||||
readonly message: string
|
||||
readonly retryAfterMs?: number
|
||||
}
|
||||
| { readonly type: "provider.auth"; readonly message: string }
|
||||
| { readonly type: "provider.quota"; readonly message: string }
|
||||
| { readonly type: "provider.content-filter"; readonly message: string }
|
||||
| { readonly type: "provider.transport"; readonly message: string }
|
||||
| { readonly type: "provider.internal"; readonly message: string }
|
||||
| { readonly type: "provider.invalid-output"; readonly message: string }
|
||||
| { readonly type: "provider.invalid-request"; readonly message: string }
|
||||
| { readonly type: "provider.no-route"; readonly message: string }
|
||||
| { readonly type: "provider.unknown"; readonly message: string }
|
||||
| {
|
||||
readonly type: "permission.rejected"
|
||||
readonly message: string
|
||||
readonly permission: string
|
||||
readonly resources: ReadonlyArray<string>
|
||||
}
|
||||
| { readonly type: "tool.unknown"; readonly message: string; readonly name: string }
|
||||
| { readonly type: "tool.stale"; readonly message: string; readonly name?: string }
|
||||
| { readonly type: "tool.execution"; readonly message: string }
|
||||
| { readonly type: "tool.result-missing"; readonly message: string; readonly callID?: string }
|
||||
| {
|
||||
readonly type: "aborted"
|
||||
readonly message: string
|
||||
readonly reason?: "user" | "shutdown" | "timeout"
|
||||
}
|
||||
| { readonly type: "unknown"; readonly message: string; readonly agent?: string }
|
||||
readonly result?: JsonValue
|
||||
}
|
||||
readonly time: {
|
||||
@@ -1832,16 +2000,59 @@ export type SessionMessageOutput = {
|
||||
readonly reasoning: number
|
||||
readonly cache: { readonly read: number; readonly write: number }
|
||||
}
|
||||
readonly error?: { readonly type: string; readonly message: string }
|
||||
readonly error?:
|
||||
| { readonly type: "provider.rate-limit"; readonly message: string; readonly retryAfterMs?: number }
|
||||
| { readonly type: "provider.auth"; readonly message: string }
|
||||
| { readonly type: "provider.quota"; readonly message: string }
|
||||
| { readonly type: "provider.content-filter"; readonly message: string }
|
||||
| { readonly type: "provider.transport"; readonly message: string }
|
||||
| { readonly type: "provider.internal"; readonly message: string }
|
||||
| { readonly type: "provider.invalid-output"; readonly message: string }
|
||||
| { readonly type: "provider.invalid-request"; readonly message: string }
|
||||
| { readonly type: "provider.no-route"; readonly message: string }
|
||||
| { readonly type: "provider.unknown"; readonly message: string }
|
||||
| {
|
||||
readonly type: "permission.rejected"
|
||||
readonly message: string
|
||||
readonly permission: string
|
||||
readonly resources: ReadonlyArray<string>
|
||||
}
|
||||
| { readonly type: "tool.unknown"; readonly message: string; readonly name: string }
|
||||
| { readonly type: "tool.stale"; readonly message: string; readonly name?: string }
|
||||
| { readonly type: "tool.execution"; readonly message: string }
|
||||
| { readonly type: "tool.result-missing"; readonly message: string; readonly callID?: string }
|
||||
| { readonly type: "aborted"; readonly message: string; readonly reason?: "user" | "shutdown" | "timeout" }
|
||||
| { readonly type: "unknown"; readonly message: string; readonly agent?: string }
|
||||
readonly retry?: {
|
||||
readonly attempt: number
|
||||
readonly at: number
|
||||
readonly error: { readonly type: string; readonly message: string }
|
||||
readonly error:
|
||||
| { readonly type: "provider.rate-limit"; readonly message: string; readonly retryAfterMs?: number }
|
||||
| { readonly type: "provider.auth"; readonly message: string }
|
||||
| { readonly type: "provider.quota"; readonly message: string }
|
||||
| { readonly type: "provider.content-filter"; readonly message: string }
|
||||
| { readonly type: "provider.transport"; readonly message: string }
|
||||
| { readonly type: "provider.internal"; readonly message: string }
|
||||
| { readonly type: "provider.invalid-output"; readonly message: string }
|
||||
| { readonly type: "provider.invalid-request"; readonly message: string }
|
||||
| { readonly type: "provider.no-route"; readonly message: string }
|
||||
| { readonly type: "provider.unknown"; readonly message: string }
|
||||
| {
|
||||
readonly type: "permission.rejected"
|
||||
readonly message: string
|
||||
readonly permission: string
|
||||
readonly resources: ReadonlyArray<string>
|
||||
}
|
||||
| { readonly type: "tool.unknown"; readonly message: string; readonly name: string }
|
||||
| { readonly type: "tool.stale"; readonly message: string; readonly name?: string }
|
||||
| { readonly type: "tool.execution"; readonly message: string }
|
||||
| { readonly type: "tool.result-missing"; readonly message: string; readonly callID?: string }
|
||||
| { readonly type: "aborted"; readonly message: string; readonly reason?: "user" | "shutdown" | "timeout" }
|
||||
| { readonly type: "unknown"; readonly message: string; readonly agent?: string }
|
||||
}
|
||||
}
|
||||
| {
|
||||
readonly type: "compaction"
|
||||
readonly status: "queued" | "running" | "completed" | "failed"
|
||||
readonly reason: "auto" | "manual"
|
||||
readonly summary: string
|
||||
readonly recent: string
|
||||
@@ -1885,7 +2096,6 @@ export type MessageListOutput = {
|
||||
readonly time: { readonly created: number }
|
||||
readonly type: "model-switched"
|
||||
readonly model: { readonly id: string; readonly providerID: string; readonly variant?: string }
|
||||
readonly previous?: { readonly id: string; readonly providerID: string; readonly variant?: string }
|
||||
}
|
||||
| {
|
||||
readonly id: string
|
||||
@@ -2015,7 +2225,37 @@ export type MessageListOutput = {
|
||||
| { readonly type: "file"; readonly uri: string; readonly mime: string; readonly name?: string }
|
||||
>
|
||||
readonly structured: { readonly [x: string]: JsonValue }
|
||||
readonly error: { readonly type: string; readonly message: string }
|
||||
readonly error:
|
||||
| {
|
||||
readonly type: "provider.rate-limit"
|
||||
readonly message: string
|
||||
readonly retryAfterMs?: number
|
||||
}
|
||||
| { readonly type: "provider.auth"; readonly message: string }
|
||||
| { readonly type: "provider.quota"; readonly message: string }
|
||||
| { readonly type: "provider.content-filter"; readonly message: string }
|
||||
| { readonly type: "provider.transport"; readonly message: string }
|
||||
| { readonly type: "provider.internal"; readonly message: string }
|
||||
| { readonly type: "provider.invalid-output"; readonly message: string }
|
||||
| { readonly type: "provider.invalid-request"; readonly message: string }
|
||||
| { readonly type: "provider.no-route"; readonly message: string }
|
||||
| { readonly type: "provider.unknown"; readonly message: string }
|
||||
| {
|
||||
readonly type: "permission.rejected"
|
||||
readonly message: string
|
||||
readonly permission: string
|
||||
readonly resources: ReadonlyArray<string>
|
||||
}
|
||||
| { readonly type: "tool.unknown"; readonly message: string; readonly name: string }
|
||||
| { readonly type: "tool.stale"; readonly message: string; readonly name?: string }
|
||||
| { readonly type: "tool.execution"; readonly message: string }
|
||||
| { readonly type: "tool.result-missing"; readonly message: string; readonly callID?: string }
|
||||
| {
|
||||
readonly type: "aborted"
|
||||
readonly message: string
|
||||
readonly reason?: "user" | "shutdown" | "timeout"
|
||||
}
|
||||
| { readonly type: "unknown"; readonly message: string; readonly agent?: string }
|
||||
readonly result?: JsonValue
|
||||
}
|
||||
readonly time: {
|
||||
@@ -2035,16 +2275,59 @@ export type MessageListOutput = {
|
||||
readonly reasoning: number
|
||||
readonly cache: { readonly read: number; readonly write: number }
|
||||
}
|
||||
readonly error?: { readonly type: string; readonly message: string }
|
||||
readonly error?:
|
||||
| { readonly type: "provider.rate-limit"; readonly message: string; readonly retryAfterMs?: number }
|
||||
| { readonly type: "provider.auth"; readonly message: string }
|
||||
| { readonly type: "provider.quota"; readonly message: string }
|
||||
| { readonly type: "provider.content-filter"; readonly message: string }
|
||||
| { readonly type: "provider.transport"; readonly message: string }
|
||||
| { readonly type: "provider.internal"; readonly message: string }
|
||||
| { readonly type: "provider.invalid-output"; readonly message: string }
|
||||
| { readonly type: "provider.invalid-request"; readonly message: string }
|
||||
| { readonly type: "provider.no-route"; readonly message: string }
|
||||
| { readonly type: "provider.unknown"; readonly message: string }
|
||||
| {
|
||||
readonly type: "permission.rejected"
|
||||
readonly message: string
|
||||
readonly permission: string
|
||||
readonly resources: ReadonlyArray<string>
|
||||
}
|
||||
| { readonly type: "tool.unknown"; readonly message: string; readonly name: string }
|
||||
| { readonly type: "tool.stale"; readonly message: string; readonly name?: string }
|
||||
| { readonly type: "tool.execution"; readonly message: string }
|
||||
| { readonly type: "tool.result-missing"; readonly message: string; readonly callID?: string }
|
||||
| { readonly type: "aborted"; readonly message: string; readonly reason?: "user" | "shutdown" | "timeout" }
|
||||
| { readonly type: "unknown"; readonly message: string; readonly agent?: string }
|
||||
readonly retry?: {
|
||||
readonly attempt: number
|
||||
readonly at: number
|
||||
readonly error: { readonly type: string; readonly message: string }
|
||||
readonly error:
|
||||
| { readonly type: "provider.rate-limit"; readonly message: string; readonly retryAfterMs?: number }
|
||||
| { readonly type: "provider.auth"; readonly message: string }
|
||||
| { readonly type: "provider.quota"; readonly message: string }
|
||||
| { readonly type: "provider.content-filter"; readonly message: string }
|
||||
| { readonly type: "provider.transport"; readonly message: string }
|
||||
| { readonly type: "provider.internal"; readonly message: string }
|
||||
| { readonly type: "provider.invalid-output"; readonly message: string }
|
||||
| { readonly type: "provider.invalid-request"; readonly message: string }
|
||||
| { readonly type: "provider.no-route"; readonly message: string }
|
||||
| { readonly type: "provider.unknown"; readonly message: string }
|
||||
| {
|
||||
readonly type: "permission.rejected"
|
||||
readonly message: string
|
||||
readonly permission: string
|
||||
readonly resources: ReadonlyArray<string>
|
||||
}
|
||||
| { readonly type: "tool.unknown"; readonly message: string; readonly name: string }
|
||||
| { readonly type: "tool.stale"; readonly message: string; readonly name?: string }
|
||||
| { readonly type: "tool.execution"; readonly message: string }
|
||||
| { readonly type: "tool.result-missing"; readonly message: string; readonly callID?: string }
|
||||
| { readonly type: "aborted"; readonly message: string; readonly reason?: "user" | "shutdown" | "timeout" }
|
||||
| { readonly type: "unknown"; readonly message: string; readonly agent?: string }
|
||||
}
|
||||
}
|
||||
| {
|
||||
readonly type: "compaction"
|
||||
readonly status: "queued" | "running" | "completed" | "failed"
|
||||
readonly reason: "auto" | "manual"
|
||||
readonly summary: string
|
||||
readonly recent: string
|
||||
@@ -4575,7 +4858,32 @@ export type EventSubscribeOutput =
|
||||
readonly type: "session.execution.failed"
|
||||
readonly durable: { readonly aggregateID: string; readonly seq: number; readonly version: number }
|
||||
readonly location?: { readonly directory: string; readonly workspaceID?: string }
|
||||
readonly data: { readonly sessionID: string; readonly error: { readonly type: string; readonly message: string } }
|
||||
readonly data: {
|
||||
readonly sessionID: string
|
||||
readonly error:
|
||||
| { readonly type: "provider.rate-limit"; readonly message: string; readonly retryAfterMs?: number }
|
||||
| { readonly type: "provider.auth"; readonly message: string }
|
||||
| { readonly type: "provider.quota"; readonly message: string }
|
||||
| { readonly type: "provider.content-filter"; readonly message: string }
|
||||
| { readonly type: "provider.transport"; readonly message: string }
|
||||
| { readonly type: "provider.internal"; readonly message: string }
|
||||
| { readonly type: "provider.invalid-output"; readonly message: string }
|
||||
| { readonly type: "provider.invalid-request"; readonly message: string }
|
||||
| { readonly type: "provider.no-route"; readonly message: string }
|
||||
| { readonly type: "provider.unknown"; readonly message: string }
|
||||
| {
|
||||
readonly type: "permission.rejected"
|
||||
readonly message: string
|
||||
readonly permission: string
|
||||
readonly resources: ReadonlyArray<string>
|
||||
}
|
||||
| { readonly type: "tool.unknown"; readonly message: string; readonly name: string }
|
||||
| { readonly type: "tool.stale"; readonly message: string; readonly name?: string }
|
||||
| { readonly type: "tool.execution"; readonly message: string }
|
||||
| { readonly type: "tool.result-missing"; readonly message: string; readonly callID?: string }
|
||||
| { readonly type: "aborted"; readonly message: string; readonly reason?: "user" | "shutdown" | "timeout" }
|
||||
| { readonly type: "unknown"; readonly message: string; readonly agent?: string }
|
||||
}
|
||||
}
|
||||
| {
|
||||
readonly id: string
|
||||
@@ -4717,7 +5025,29 @@ export type EventSubscribeOutput =
|
||||
readonly data: {
|
||||
readonly sessionID: string
|
||||
readonly assistantMessageID: string
|
||||
readonly error: { readonly type: string; readonly message: string }
|
||||
readonly error:
|
||||
| { readonly type: "provider.rate-limit"; readonly message: string; readonly retryAfterMs?: number }
|
||||
| { readonly type: "provider.auth"; readonly message: string }
|
||||
| { readonly type: "provider.quota"; readonly message: string }
|
||||
| { readonly type: "provider.content-filter"; readonly message: string }
|
||||
| { readonly type: "provider.transport"; readonly message: string }
|
||||
| { readonly type: "provider.internal"; readonly message: string }
|
||||
| { readonly type: "provider.invalid-output"; readonly message: string }
|
||||
| { readonly type: "provider.invalid-request"; readonly message: string }
|
||||
| { readonly type: "provider.no-route"; readonly message: string }
|
||||
| { readonly type: "provider.unknown"; readonly message: string }
|
||||
| {
|
||||
readonly type: "permission.rejected"
|
||||
readonly message: string
|
||||
readonly permission: string
|
||||
readonly resources: ReadonlyArray<string>
|
||||
}
|
||||
| { readonly type: "tool.unknown"; readonly message: string; readonly name: string }
|
||||
| { readonly type: "tool.stale"; readonly message: string; readonly name?: string }
|
||||
| { readonly type: "tool.execution"; readonly message: string }
|
||||
| { readonly type: "tool.result-missing"; readonly message: string; readonly callID?: string }
|
||||
| { readonly type: "aborted"; readonly message: string; readonly reason?: "user" | "shutdown" | "timeout" }
|
||||
| { readonly type: "unknown"; readonly message: string; readonly agent?: string }
|
||||
}
|
||||
}
|
||||
| {
|
||||
@@ -4727,7 +5057,7 @@ export type EventSubscribeOutput =
|
||||
readonly type: "session.text.started"
|
||||
readonly durable: { readonly aggregateID: string; readonly seq: number; readonly version: number }
|
||||
readonly location?: { readonly directory: string; readonly workspaceID?: string }
|
||||
readonly data: { readonly sessionID: string; readonly assistantMessageID: string; readonly ordinal: number }
|
||||
readonly data: { readonly sessionID: string; readonly assistantMessageID: string }
|
||||
}
|
||||
| {
|
||||
readonly id: string
|
||||
@@ -4735,12 +5065,7 @@ export type EventSubscribeOutput =
|
||||
readonly metadata?: { readonly [x: string]: unknown }
|
||||
readonly type: "session.text.delta"
|
||||
readonly location?: { readonly directory: string; readonly workspaceID?: string }
|
||||
readonly data: {
|
||||
readonly sessionID: string
|
||||
readonly assistantMessageID: string
|
||||
readonly ordinal: number
|
||||
readonly delta: string
|
||||
}
|
||||
readonly data: { readonly sessionID: string; readonly assistantMessageID: string; readonly delta: string }
|
||||
}
|
||||
| {
|
||||
readonly id: string
|
||||
@@ -4749,12 +5074,7 @@ export type EventSubscribeOutput =
|
||||
readonly type: "session.text.ended"
|
||||
readonly durable: { readonly aggregateID: string; readonly seq: number; readonly version: number }
|
||||
readonly location?: { readonly directory: string; readonly workspaceID?: string }
|
||||
readonly data: {
|
||||
readonly sessionID: string
|
||||
readonly assistantMessageID: string
|
||||
readonly ordinal: number
|
||||
readonly text: string
|
||||
}
|
||||
readonly data: { readonly sessionID: string; readonly assistantMessageID: string; readonly text: string }
|
||||
}
|
||||
| {
|
||||
readonly id: string
|
||||
@@ -4766,7 +5086,6 @@ export type EventSubscribeOutput =
|
||||
readonly data: {
|
||||
readonly sessionID: string
|
||||
readonly assistantMessageID: string
|
||||
readonly ordinal: number
|
||||
readonly state?: { readonly [x: string]: unknown }
|
||||
}
|
||||
}
|
||||
@@ -4776,12 +5095,7 @@ export type EventSubscribeOutput =
|
||||
readonly metadata?: { readonly [x: string]: unknown }
|
||||
readonly type: "session.reasoning.delta"
|
||||
readonly location?: { readonly directory: string; readonly workspaceID?: string }
|
||||
readonly data: {
|
||||
readonly sessionID: string
|
||||
readonly assistantMessageID: string
|
||||
readonly ordinal: number
|
||||
readonly delta: string
|
||||
}
|
||||
readonly data: { readonly sessionID: string; readonly assistantMessageID: string; readonly delta: string }
|
||||
}
|
||||
| {
|
||||
readonly id: string
|
||||
@@ -4793,7 +5107,6 @@ export type EventSubscribeOutput =
|
||||
readonly data: {
|
||||
readonly sessionID: string
|
||||
readonly assistantMessageID: string
|
||||
readonly ordinal: number
|
||||
readonly text: string
|
||||
readonly state?: { readonly [x: string]: unknown }
|
||||
}
|
||||
@@ -4906,7 +5219,29 @@ export type EventSubscribeOutput =
|
||||
readonly sessionID: string
|
||||
readonly assistantMessageID: string
|
||||
readonly callID: string
|
||||
readonly error: { readonly type: string; readonly message: string }
|
||||
readonly error:
|
||||
| { readonly type: "provider.rate-limit"; readonly message: string; readonly retryAfterMs?: number }
|
||||
| { readonly type: "provider.auth"; readonly message: string }
|
||||
| { readonly type: "provider.quota"; readonly message: string }
|
||||
| { readonly type: "provider.content-filter"; readonly message: string }
|
||||
| { readonly type: "provider.transport"; readonly message: string }
|
||||
| { readonly type: "provider.internal"; readonly message: string }
|
||||
| { readonly type: "provider.invalid-output"; readonly message: string }
|
||||
| { readonly type: "provider.invalid-request"; readonly message: string }
|
||||
| { readonly type: "provider.no-route"; readonly message: string }
|
||||
| { readonly type: "provider.unknown"; readonly message: string }
|
||||
| {
|
||||
readonly type: "permission.rejected"
|
||||
readonly message: string
|
||||
readonly permission: string
|
||||
readonly resources: ReadonlyArray<string>
|
||||
}
|
||||
| { readonly type: "tool.unknown"; readonly message: string; readonly name: string }
|
||||
| { readonly type: "tool.stale"; readonly message: string; readonly name?: string }
|
||||
| { readonly type: "tool.execution"; readonly message: string }
|
||||
| { readonly type: "tool.result-missing"; readonly message: string; readonly callID?: string }
|
||||
| { readonly type: "aborted"; readonly message: string; readonly reason?: "user" | "shutdown" | "timeout" }
|
||||
| { readonly type: "unknown"; readonly message: string; readonly agent?: string }
|
||||
readonly result?: unknown
|
||||
readonly executed: boolean
|
||||
readonly resultState?: { readonly [x: string]: unknown }
|
||||
@@ -4924,18 +5259,31 @@ export type EventSubscribeOutput =
|
||||
readonly assistantMessageID: string
|
||||
readonly attempt: number
|
||||
readonly at: number
|
||||
readonly error: { readonly type: string; readonly message: string }
|
||||
readonly error:
|
||||
| { readonly type: "provider.rate-limit"; readonly message: string; readonly retryAfterMs?: number }
|
||||
| { readonly type: "provider.auth"; readonly message: string }
|
||||
| { readonly type: "provider.quota"; readonly message: string }
|
||||
| { readonly type: "provider.content-filter"; readonly message: string }
|
||||
| { readonly type: "provider.transport"; readonly message: string }
|
||||
| { readonly type: "provider.internal"; readonly message: string }
|
||||
| { readonly type: "provider.invalid-output"; readonly message: string }
|
||||
| { readonly type: "provider.invalid-request"; readonly message: string }
|
||||
| { readonly type: "provider.no-route"; readonly message: string }
|
||||
| { readonly type: "provider.unknown"; readonly message: string }
|
||||
| {
|
||||
readonly type: "permission.rejected"
|
||||
readonly message: string
|
||||
readonly permission: string
|
||||
readonly resources: ReadonlyArray<string>
|
||||
}
|
||||
| { readonly type: "tool.unknown"; readonly message: string; readonly name: string }
|
||||
| { readonly type: "tool.stale"; readonly message: string; readonly name?: string }
|
||||
| { readonly type: "tool.execution"; readonly message: string }
|
||||
| { readonly type: "tool.result-missing"; readonly message: string; readonly callID?: string }
|
||||
| { readonly type: "aborted"; readonly message: string; readonly reason?: "user" | "shutdown" | "timeout" }
|
||||
| { readonly type: "unknown"; readonly message: string; readonly agent?: string }
|
||||
}
|
||||
}
|
||||
| {
|
||||
readonly id: string
|
||||
readonly created: number
|
||||
readonly metadata?: { readonly [x: string]: unknown }
|
||||
readonly type: "session.compaction.admitted"
|
||||
readonly durable: { readonly aggregateID: string; readonly seq: number; readonly version: number }
|
||||
readonly location?: { readonly directory: string; readonly workspaceID?: string }
|
||||
readonly data: { readonly sessionID: string; readonly inputID: string }
|
||||
}
|
||||
| {
|
||||
readonly id: string
|
||||
readonly created: number
|
||||
@@ -4967,15 +5315,6 @@ export type EventSubscribeOutput =
|
||||
readonly recent: string
|
||||
}
|
||||
}
|
||||
| {
|
||||
readonly id: string
|
||||
readonly created: number
|
||||
readonly metadata?: { readonly [x: string]: unknown }
|
||||
readonly type: "session.compaction.failed"
|
||||
readonly durable: { readonly aggregateID: string; readonly seq: number; readonly version: number }
|
||||
readonly location?: { readonly directory: string; readonly workspaceID?: string }
|
||||
readonly data: { readonly sessionID: string }
|
||||
}
|
||||
| {
|
||||
readonly id: string
|
||||
readonly created: number
|
||||
|
||||
@@ -89,9 +89,6 @@ test("session methods retain decoded Effect inputs and outputs", async () => {
|
||||
if (url.includes("/prompt")) {
|
||||
return Effect.succeed(HttpClientResponse.fromWeb(request, Response.json(admission)))
|
||||
}
|
||||
if (url.endsWith("/compact")) {
|
||||
return Effect.succeed(HttpClientResponse.fromWeb(request, Response.json(compactionAdmission)))
|
||||
}
|
||||
if (url.includes("/context")) {
|
||||
return Effect.succeed(HttpClientResponse.fromWeb(request, Response.json({ data: [] })))
|
||||
}
|
||||
@@ -221,16 +218,6 @@ const admission = {
|
||||
},
|
||||
}
|
||||
|
||||
const compactionAdmission = {
|
||||
data: {
|
||||
type: "compaction",
|
||||
admittedSeq: 1,
|
||||
id: "msg_compaction",
|
||||
sessionID: "ses_test",
|
||||
timeCreated: 1_717_171_717_000,
|
||||
},
|
||||
}
|
||||
|
||||
const modelSwitchedMessage = {
|
||||
id: "msg_model",
|
||||
type: "model-switched",
|
||||
|
||||
@@ -193,7 +193,6 @@ test("session methods use the public HTTP contract", async () => {
|
||||
})
|
||||
}
|
||||
if (url.includes("/prompt")) return Response.json(admission)
|
||||
if (url.endsWith("/compact")) return Response.json(compactionAdmission)
|
||||
if (url.includes("/context")) return Response.json({ data: [] })
|
||||
if (url.includes("/message/")) return Response.json({ data: modelSwitchedMessage })
|
||||
if (url.endsWith("/api/session/active"))
|
||||
@@ -318,16 +317,6 @@ const admission = {
|
||||
},
|
||||
}
|
||||
|
||||
const compactionAdmission = {
|
||||
data: {
|
||||
type: "compaction",
|
||||
admittedSeq: 1,
|
||||
id: "msg_compaction",
|
||||
sessionID: "ses_test",
|
||||
timeCreated: 1_717_171_717_000,
|
||||
},
|
||||
}
|
||||
|
||||
const modelSwitchedMessage = {
|
||||
id: "msg_model",
|
||||
type: "model-switched",
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"version": "7",
|
||||
"dialect": "sqlite",
|
||||
"id": "afa00750-fad8-473a-b877-13ff35ea3411",
|
||||
"id": "96e9fe64-d810-4102-8f79-3317a88bb6d2",
|
||||
"prevIds": [
|
||||
"96e9fe64-d810-4102-8f79-3317a88bb6d2"
|
||||
"22e57fed-b9b8-4e94-a3b4-f94bece680a8"
|
||||
],
|
||||
"ddl": [
|
||||
{
|
||||
@@ -1012,23 +1012,13 @@
|
||||
"autoincrement": false,
|
||||
"default": null,
|
||||
"generated": null,
|
||||
"name": "type",
|
||||
"entityType": "columns",
|
||||
"table": "session_input"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"notNull": false,
|
||||
"autoincrement": false,
|
||||
"default": null,
|
||||
"generated": null,
|
||||
"name": "prompt",
|
||||
"entityType": "columns",
|
||||
"table": "session_input"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"notNull": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": null,
|
||||
"generated": null,
|
||||
@@ -2076,10 +2066,6 @@
|
||||
"value": "promoted_seq",
|
||||
"isExpression": false
|
||||
},
|
||||
{
|
||||
"value": "type",
|
||||
"isExpression": false
|
||||
},
|
||||
{
|
||||
"value": "delivery",
|
||||
"isExpression": false
|
||||
@@ -2092,21 +2078,7 @@
|
||||
"isUnique": false,
|
||||
"where": null,
|
||||
"origin": "manual",
|
||||
"name": "session_input_session_pending_type_delivery_seq_idx",
|
||||
"entityType": "indexes",
|
||||
"table": "session_input"
|
||||
},
|
||||
{
|
||||
"columns": [
|
||||
{
|
||||
"value": "session_id",
|
||||
"isExpression": false
|
||||
}
|
||||
],
|
||||
"isUnique": true,
|
||||
"where": "\"session_input\".\"type\" = 'compaction' and \"session_input\".\"promoted_seq\" is null",
|
||||
"origin": "manual",
|
||||
"name": "session_input_session_pending_compaction_idx",
|
||||
"name": "session_input_session_pending_delivery_seq_idx",
|
||||
"entityType": "indexes",
|
||||
"table": "session_input"
|
||||
},
|
||||
|
||||
@@ -2,7 +2,8 @@ export * as ConfigExternalPlugin from "./external"
|
||||
|
||||
import type { Plugin as EffectPlugin } from "@opencode-ai/plugin/v2/effect"
|
||||
import type { Plugin as PromisePlugin } from "@opencode-ai/plugin/v2/promise"
|
||||
import { Effect, Schema } from "effect"
|
||||
import { Effect, Schema, Stream } from "effect"
|
||||
import { createRequire } from "node:module"
|
||||
import path from "path"
|
||||
import { fileURLToPath, pathToFileURL } from "url"
|
||||
import { Config } from "../../config"
|
||||
@@ -35,6 +36,9 @@ const PluginPackage = Schema.Struct({
|
||||
module: Schema.optional(Schema.String),
|
||||
})
|
||||
|
||||
let importGeneration = 0
|
||||
const moduleCache = createRequire(import.meta.url).cache
|
||||
|
||||
export const Plugin = define({
|
||||
id: "config-plugin",
|
||||
effect: Effect.fn(function* (ctx) {
|
||||
@@ -42,6 +46,7 @@ export const Plugin = define({
|
||||
const fs = yield* FSUtil.Service
|
||||
const location = yield* Location.Service
|
||||
const npm = yield* Npm.Service
|
||||
const active = new Set<string>()
|
||||
const load = Effect.fn("ConfigExternalPlugin.load")(function* () {
|
||||
const configured: { package: string; options?: Record<string, unknown> }[] = []
|
||||
|
||||
@@ -105,7 +110,7 @@ export const Plugin = define({
|
||||
: (yield* npm.add(ref.package)).entrypoint
|
||||
if (!entrypoint) return
|
||||
yield* Effect.log({ msg: "loading plugin", id: ref.package, entrypoint })
|
||||
const mod = yield* Effect.promise(() => import(entrypoint))
|
||||
const mod = yield* Effect.promise(() => import(cacheBust(entrypoint)))
|
||||
const value = (yield* Schema.decodeUnknownEffect(PluginModule)(mod)).default
|
||||
const plugin = "effect" in value ? value : PluginPromise.fromPromise(value)
|
||||
return {
|
||||
@@ -113,13 +118,40 @@ export const Plugin = define({
|
||||
effect: (host: Parameters<typeof plugin.effect>[0]) =>
|
||||
plugin.effect({ ...host, options: ref.options ?? {} }),
|
||||
}
|
||||
}).pipe(Effect.catchCause(() => Effect.succeed(undefined))),
|
||||
}).pipe(
|
||||
Effect.catchCause((cause) =>
|
||||
Effect.logError("failed to load plugin", { package: ref.package, cause }).pipe(Effect.as(undefined)),
|
||||
),
|
||||
),
|
||||
).pipe(Effect.map((plugins) => plugins.filter((plugin) => plugin !== undefined)))
|
||||
})
|
||||
for (const plugin of yield* load()) yield* ctx.plugin.add(plugin)
|
||||
const reconcile = Effect.fn("ConfigExternalPlugin.reconcile")(function* () {
|
||||
const plugins = yield* load()
|
||||
const next = new Set(plugins.map((plugin) => plugin.id))
|
||||
for (const id of active) {
|
||||
if (!next.has(id)) yield* ctx.plugin.remove(id)
|
||||
}
|
||||
for (const plugin of plugins) yield* ctx.plugin.add(plugin)
|
||||
active.clear()
|
||||
for (const id of next) active.add(id)
|
||||
})
|
||||
|
||||
yield* reconcile()
|
||||
yield* ctx.event.subscribe().pipe(
|
||||
Stream.filter((event) => event.type === "config.updated"),
|
||||
Stream.runForEach(() => reconcile()),
|
||||
Effect.forkScoped({ startImmediately: true }),
|
||||
)
|
||||
}),
|
||||
})
|
||||
|
||||
function cacheBust(entrypoint: string) {
|
||||
const url = path.isAbsolute(entrypoint) ? pathToFileURL(entrypoint) : new URL(entrypoint)
|
||||
if (url.protocol === "file:") delete moduleCache[fileURLToPath(url)]
|
||||
url.searchParams.set("opencode-reload", String(++importGeneration))
|
||||
return url.href
|
||||
}
|
||||
|
||||
const resolvePackageEntrypoint = Effect.fnUntraced(function* (fs: FSUtil.Interface, directory: string) {
|
||||
const pkg = yield* fs.readJson(path.join(directory, "package.json")).pipe(
|
||||
Effect.flatMap(Schema.decodeUnknownEffect(PluginPackage)),
|
||||
|
||||
+2
-2
@@ -44,7 +44,7 @@ export const migrations = (
|
||||
import("./migration/20260703090000_reset_v2_event_rename_sweep"),
|
||||
import("./migration/20260703181610_event_created_column"),
|
||||
import("./migration/20260703190000_reset_v2_shell_event_payloads"),
|
||||
import("./migration/20260703200000_reset_v2_session_events"),
|
||||
import("./migration/20260704161518_durable_session_inbox"),
|
||||
import("./migration/20260703200000_reset_v2_event_fragments"),
|
||||
import("./migration/20260703210000_reset_v2_execution_errors"),
|
||||
])
|
||||
).map((module) => module.default) satisfies DatabaseMigration.Migration[]
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ import { Effect } from "effect"
|
||||
import type { DatabaseMigration } from "../migration"
|
||||
|
||||
export default {
|
||||
id: "20260703200000_reset_v2_session_events",
|
||||
id: "20260703200000_reset_v2_event_fragments",
|
||||
up(tx) {
|
||||
return Effect.gen(function* () {
|
||||
yield* tx.run(`DELETE FROM \`session_input\`;`)
|
||||
@@ -0,0 +1,14 @@
|
||||
import { Effect } from "effect"
|
||||
import type { DatabaseMigration } from "../migration"
|
||||
|
||||
export default {
|
||||
id: "20260703210000_reset_v2_execution_errors",
|
||||
up(tx) {
|
||||
return Effect.gen(function* () {
|
||||
yield* tx.run(`DELETE FROM \`session_input\`;`)
|
||||
yield* tx.run(`DELETE FROM \`session_message\`;`)
|
||||
yield* tx.run(`DELETE FROM \`event\`;`)
|
||||
yield* tx.run(`DELETE FROM \`event_sequence\`;`)
|
||||
})
|
||||
},
|
||||
} satisfies DatabaseMigration.Migration
|
||||
@@ -1,43 +0,0 @@
|
||||
import { Effect } from "effect"
|
||||
import type { DatabaseMigration } from "../migration"
|
||||
|
||||
export default {
|
||||
id: "20260704161518_durable_session_inbox",
|
||||
up(tx) {
|
||||
return Effect.gen(function* () {
|
||||
yield* tx.run(`PRAGMA foreign_keys=OFF;`)
|
||||
yield* tx.run(`
|
||||
CREATE TABLE \`__new_session_input\` (
|
||||
\`id\` text PRIMARY KEY,
|
||||
\`session_id\` text NOT NULL,
|
||||
\`type\` text NOT NULL,
|
||||
\`prompt\` text,
|
||||
\`delivery\` text,
|
||||
\`admitted_seq\` integer NOT NULL,
|
||||
\`promoted_seq\` integer,
|
||||
\`time_created\` integer NOT NULL,
|
||||
CONSTRAINT \`fk_session_input_session_id_session_id_fk\` FOREIGN KEY (\`session_id\`) REFERENCES \`session\`(\`id\`) ON DELETE CASCADE
|
||||
);
|
||||
`)
|
||||
yield* tx.run(
|
||||
`INSERT INTO \`__new_session_input\`(\`id\`, \`session_id\`, \`type\`, \`prompt\`, \`delivery\`, \`admitted_seq\`, \`promoted_seq\`, \`time_created\`) SELECT \`id\`, \`session_id\`, 'prompt', \`prompt\`, \`delivery\`, \`admitted_seq\`, \`promoted_seq\`, \`time_created\` FROM \`session_input\`;`,
|
||||
)
|
||||
yield* tx.run(`DROP TABLE \`session_input\`;`)
|
||||
yield* tx.run(`ALTER TABLE \`__new_session_input\` RENAME TO \`session_input\`;`)
|
||||
yield* tx.run(`PRAGMA foreign_keys=ON;`)
|
||||
yield* tx.run(`DROP INDEX IF EXISTS \`session_input_session_pending_delivery_seq_idx\`;`)
|
||||
yield* tx.run(
|
||||
`CREATE INDEX \`session_input_session_pending_type_delivery_seq_idx\` ON \`session_input\` (\`session_id\`,\`promoted_seq\`,\`type\`,\`delivery\`,\`admitted_seq\`);`,
|
||||
)
|
||||
yield* tx.run(
|
||||
`CREATE UNIQUE INDEX \`session_input_session_pending_compaction_idx\` ON \`session_input\` (\`session_id\`) WHERE "session_input"."type" = 'compaction' and "session_input"."promoted_seq" is null;`,
|
||||
)
|
||||
yield* tx.run(
|
||||
`CREATE UNIQUE INDEX \`session_input_session_admitted_seq_idx\` ON \`session_input\` (\`session_id\`,\`admitted_seq\`);`,
|
||||
)
|
||||
yield* tx.run(
|
||||
`CREATE UNIQUE INDEX \`session_input_session_promoted_seq_idx\` ON \`session_input\` (\`session_id\`,\`promoted_seq\`);`,
|
||||
)
|
||||
})
|
||||
},
|
||||
} satisfies DatabaseMigration.Migration
|
||||
@@ -170,9 +170,8 @@ export default {
|
||||
CREATE TABLE \`session_input\` (
|
||||
\`id\` text PRIMARY KEY,
|
||||
\`session_id\` text NOT NULL,
|
||||
\`type\` text NOT NULL,
|
||||
\`prompt\` text,
|
||||
\`delivery\` text,
|
||||
\`prompt\` text NOT NULL,
|
||||
\`delivery\` text NOT NULL,
|
||||
\`admitted_seq\` integer NOT NULL,
|
||||
\`promoted_seq\` integer,
|
||||
\`time_created\` integer NOT NULL,
|
||||
@@ -260,10 +259,7 @@ export default {
|
||||
yield* tx.run(`CREATE INDEX \`part_message_id_id_idx\` ON \`part\` (\`message_id\`,\`id\`);`)
|
||||
yield* tx.run(`CREATE INDEX \`part_session_idx\` ON \`part\` (\`session_id\`);`)
|
||||
yield* tx.run(
|
||||
`CREATE INDEX \`session_input_session_pending_type_delivery_seq_idx\` ON \`session_input\` (\`session_id\`,\`promoted_seq\`,\`type\`,\`delivery\`,\`admitted_seq\`);`,
|
||||
)
|
||||
yield* tx.run(
|
||||
`CREATE UNIQUE INDEX \`session_input_session_pending_compaction_idx\` ON \`session_input\` (\`session_id\`) WHERE "session_input"."type" = 'compaction' and "session_input"."promoted_seq" is null;`,
|
||||
`CREATE INDEX \`session_input_session_pending_delivery_seq_idx\` ON \`session_input\` (\`session_id\`,\`promoted_seq\`,\`delivery\`,\`admitted_seq\`);`,
|
||||
)
|
||||
yield* tx.run(
|
||||
`CREATE UNIQUE INDEX \`session_input_session_admitted_seq_idx\` ON \`session_input\` (\`session_id\`,\`admitted_seq\`);`,
|
||||
|
||||
@@ -45,7 +45,7 @@ const FILES = [
|
||||
"**/.nyc_output/**",
|
||||
]
|
||||
|
||||
export const PATTERNS = [...FILES, ...FOLDERS, `**/{${Array.from(FOLDERS).join(",")}}/**`]
|
||||
export const PATTERNS = [...FILES, ...FOLDERS]
|
||||
|
||||
export function match(filepath: string, opts?: { extra?: string[]; whitelist?: string[] }) {
|
||||
for (const pattern of opts?.whitelist || []) {
|
||||
|
||||
@@ -130,13 +130,19 @@ const layer = Layer.effect(
|
||||
const sessions = yield* SessionStore.Service
|
||||
const saved = yield* PermissionSaved.Service
|
||||
const pending = new Map<ID, Pending>()
|
||||
const rejected = (request: Request) =>
|
||||
new RejectedError({ permission: request.action, resources: [...request.resources] })
|
||||
|
||||
yield* Effect.addFinalizer(() =>
|
||||
Effect.forEach(pending.values(), (item) => Deferred.fail(item.deferred, rejected(item.request)), {
|
||||
discard: true,
|
||||
}).pipe(
|
||||
Effect.forEach(
|
||||
pending.values(),
|
||||
(item) =>
|
||||
Deferred.fail(
|
||||
item.deferred,
|
||||
new RejectedError({ permission: item.request.action, resources: [...item.request.resources] }),
|
||||
),
|
||||
{
|
||||
discard: true,
|
||||
},
|
||||
).pipe(
|
||||
Effect.ensuring(
|
||||
Effect.sync(() => {
|
||||
pending.clear()
|
||||
@@ -247,7 +253,12 @@ const layer = Layer.effect(
|
||||
if (input.reply === "reject") {
|
||||
yield* Deferred.fail(
|
||||
existing.deferred,
|
||||
input.message ? new CorrectedError({ feedback: input.message }) : rejected(existing.request),
|
||||
input.message
|
||||
? new CorrectedError({ feedback: input.message })
|
||||
: new RejectedError({
|
||||
permission: existing.request.action,
|
||||
resources: [...existing.request.resources],
|
||||
}),
|
||||
)
|
||||
pending.delete(input.requestID)
|
||||
for (const [id, item] of pending) {
|
||||
@@ -257,7 +268,10 @@ const layer = Layer.effect(
|
||||
requestID: item.request.id,
|
||||
reply: "reject",
|
||||
})
|
||||
yield* Deferred.fail(item.deferred, rejected(item.request))
|
||||
yield* Deferred.fail(
|
||||
item.deferred,
|
||||
new RejectedError({ permission: item.request.action, resources: [...item.request.resources] }),
|
||||
)
|
||||
pending.delete(id)
|
||||
}
|
||||
return
|
||||
|
||||
@@ -33,6 +33,7 @@ import { MessageDecodeError } from "./session/error"
|
||||
import { SessionEvent } from "./session/event"
|
||||
import { SessionInput } from "./session/input"
|
||||
import { Snapshot } from "./snapshot"
|
||||
import { SessionCompaction } from "./session/compaction"
|
||||
import { SessionRevert } from "./session/revert"
|
||||
import { Revert } from "@opencode-ai/schema/revert"
|
||||
import { FSUtil } from "./fs-util"
|
||||
@@ -93,7 +94,6 @@ type CreateInput = CreateBaseInput &
|
||||
({ location: Location.Ref; parentID?: never } | { parentID: SessionSchema.ID; location?: never })
|
||||
|
||||
type CompactInput = {
|
||||
id?: SessionMessage.ID
|
||||
sessionID: SessionSchema.ID
|
||||
}
|
||||
|
||||
@@ -119,13 +119,6 @@ export class PromptConflictError extends Schema.TaggedErrorClass<PromptConflictE
|
||||
sessionID: SessionSchema.ID,
|
||||
messageID: SessionMessage.ID,
|
||||
}) {}
|
||||
export class CompactionConflictError extends Schema.TaggedErrorClass<CompactionConflictError>()(
|
||||
"Session.CompactionConflictError",
|
||||
{
|
||||
sessionID: SessionSchema.ID,
|
||||
inputID: SessionMessage.ID,
|
||||
},
|
||||
) {}
|
||||
export class BusyError extends Schema.TaggedErrorClass<BusyError>()("Session.BusyError", {
|
||||
sessionID: SessionSchema.ID,
|
||||
}) {}
|
||||
@@ -140,7 +133,6 @@ export type Error =
|
||||
| MessageDecodeError
|
||||
| OperationUnavailableError
|
||||
| PromptConflictError
|
||||
| CompactionConflictError
|
||||
| BusyError
|
||||
| SkillNotFoundError
|
||||
| CommandV2.NotFoundError
|
||||
@@ -228,7 +220,7 @@ export interface Interface {
|
||||
}) => Effect.Effect<void, NotFoundError | SkillNotFoundError>
|
||||
readonly compact: (
|
||||
input: CompactInput,
|
||||
) => Effect.Effect<SessionInput.Compaction, NotFoundError | CompactionConflictError>
|
||||
) => Effect.Effect<void, NotFoundError | BusyError | MessageDecodeError | OperationUnavailableError>
|
||||
readonly wait: (id: SessionSchema.ID) => Effect.Effect<void, NotFoundError>
|
||||
readonly active: Effect.Effect<ReadonlySet<SessionSchema.ID>>
|
||||
readonly background: (sessionID: SessionSchema.ID) => Effect.Effect<void, NotFoundError>
|
||||
@@ -548,8 +540,7 @@ const layer = Layer.effect(
|
||||
const started = yield* Effect.gen(function* () {
|
||||
const shell = yield* Shell.Service
|
||||
return yield* shell.create({ command: input.command, cwd: session.location.directory })
|
||||
})
|
||||
.pipe(Effect.provide(locations.get(session.location)))
|
||||
}).pipe(Effect.provide(locations.get(session.location)))
|
||||
yield* events.publish(
|
||||
SessionEvent.Shell.Started,
|
||||
{
|
||||
@@ -572,7 +563,8 @@ const layer = Layer.effect(
|
||||
.pipe(Effect.catchTag("Shell.NotFoundError", () => Effect.succeed(missingShellOutput())))
|
||||
: missingShellOutput()
|
||||
return { shell: terminal.info, output }
|
||||
}).pipe(Effect.provide(locations.get(session.location)))
|
||||
})
|
||||
.pipe(Effect.provide(locations.get(session.location)))
|
||||
yield* events.publish(SessionEvent.Shell.Ended, {
|
||||
sessionID: input.sessionID,
|
||||
shell: completed.shell,
|
||||
@@ -631,20 +623,19 @@ const layer = Layer.effect(
|
||||
})
|
||||
}),
|
||||
compact: Effect.fn("V2Session.compact")(function* (input) {
|
||||
yield* result.get(input.sessionID)
|
||||
const inputID = input.id ?? SessionMessage.ID.create()
|
||||
const admitted = yield* SessionInput.admitCompaction(db, events, {
|
||||
id: inputID,
|
||||
sessionID: input.sessionID,
|
||||
const session = yield* result.get(input.sessionID)
|
||||
// TODO: admit manual compaction as durable pending work, like prompt input, instead of rejecting active sessions.
|
||||
if ((yield* execution.active).has(input.sessionID)) return yield* new BusyError({ sessionID: input.sessionID })
|
||||
const context = yield* store.context(input.sessionID)
|
||||
const compacted = yield* Effect.gen(function* () {
|
||||
const compaction = yield* SessionCompaction.Service
|
||||
return yield* compaction.compactManual({ session, messages: context })
|
||||
}).pipe(
|
||||
Effect.catchDefect((defect) =>
|
||||
defect instanceof SessionInput.LifecycleConflict
|
||||
? new CompactionConflictError({ sessionID: input.sessionID, inputID })
|
||||
: Effect.die(defect),
|
||||
),
|
||||
Effect.provide(locations.get(session.location)),
|
||||
Effect.catch(() => Effect.succeed(false)),
|
||||
)
|
||||
yield* execution.wake(input.sessionID)
|
||||
return admitted
|
||||
if (!compacted) return yield* new OperationUnavailableError({ operation: "compact" })
|
||||
return undefined
|
||||
}),
|
||||
wait: Effect.fn("V2Session.wait")(function* (sessionID) {
|
||||
yield* result.get(sessionID)
|
||||
|
||||
@@ -18,32 +18,32 @@ const TOOL_OUTPUT_MAX_CHARS = 2_000
|
||||
const SUMMARY_OUTPUT_TOKENS = 4_096
|
||||
const SUMMARY_TEMPLATE = `Output exactly the Markdown structure shown inside <template> and keep the section order unchanged. Do not include the <template> tags in your response.
|
||||
<template>
|
||||
## Continuation Goal
|
||||
## Goal
|
||||
- [single-sentence task summary]
|
||||
|
||||
## Operating Constraints
|
||||
## Constraints & Preferences
|
||||
- [user constraints, preferences, specs, or "(none)"]
|
||||
|
||||
## Progress
|
||||
### Completed
|
||||
### Done
|
||||
- [completed work or "(none)"]
|
||||
|
||||
### In Flight
|
||||
### In Progress
|
||||
- [current work or "(none)"]
|
||||
|
||||
### Blocked
|
||||
- [blockers or "(none)"]
|
||||
|
||||
## Decisions To Preserve
|
||||
## Key Decisions
|
||||
- [decision and why, or "(none)"]
|
||||
|
||||
## Resume From Here
|
||||
## Next Steps
|
||||
- [ordered next actions or "(none)"]
|
||||
|
||||
## Context To Preserve
|
||||
## Critical Context
|
||||
- [important technical facts, errors, open questions, or "(none)"]
|
||||
|
||||
## Working Files
|
||||
## Relevant Files
|
||||
- [file or directory path: why it matters, or "(none)"]
|
||||
</template>
|
||||
|
||||
@@ -268,9 +268,7 @@ const make = (dependencies: Dependencies) => {
|
||||
if (context === undefined || context <= 0) return false
|
||||
const selected = select(input.messages, config.tokens)
|
||||
if (!selected) return false
|
||||
const previousSummary = input.messages.find(
|
||||
(message) => message.type === "compaction" && message.status === "completed",
|
||||
)
|
||||
const previousSummary = input.messages.find((message) => message.type === "compaction")
|
||||
const hasHead = selected.head.length > 0
|
||||
if (!hasHead && previousSummary?.type !== "compaction" && !input.force) return false
|
||||
const forcedShortContext = input.force && !hasHead
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { and, asc, desc, eq, gt, gte, ne, or, sql } from "drizzle-orm"
|
||||
import { and, asc, desc, eq, gt, gte, ne, or } from "drizzle-orm"
|
||||
import { Effect, Schema } from "effect"
|
||||
import { Database } from "../database/database"
|
||||
import { MessageDecodeError } from "./error"
|
||||
@@ -14,13 +14,7 @@ export const latestCompaction = Effect.fnUntraced(function* (db: DatabaseService
|
||||
return yield* db
|
||||
.select({ seq: SessionMessageTable.seq })
|
||||
.from(SessionMessageTable)
|
||||
.where(
|
||||
and(
|
||||
eq(SessionMessageTable.session_id, sessionID),
|
||||
eq(SessionMessageTable.type, "compaction"),
|
||||
sql`json_extract(${SessionMessageTable.data}, '$.status') = 'completed'`,
|
||||
),
|
||||
)
|
||||
.where(and(eq(SessionMessageTable.session_id, sessionID), eq(SessionMessageTable.type, "compaction")))
|
||||
.orderBy(desc(SessionMessageTable.seq))
|
||||
.limit(1)
|
||||
.get()
|
||||
|
||||
@@ -2,10 +2,9 @@ export * as SessionInput from "./input"
|
||||
|
||||
import { and, asc, eq, isNull } from "drizzle-orm"
|
||||
import { DateTime, Effect, Schema } from "effect"
|
||||
import { Admitted, Compaction, Delivery, Entry, PromptEntry } from "@opencode-ai/schema/session-input"
|
||||
import { Admitted, Delivery } from "@opencode-ai/schema/session-input"
|
||||
import type { Database } from "../database/database"
|
||||
import type { EventV2 } from "../event"
|
||||
import { KeyedMutex } from "../effect/keyed-mutex"
|
||||
import { SessionEvent } from "./event"
|
||||
import { SessionMessage } from "./message"
|
||||
import { Prompt } from "./prompt"
|
||||
@@ -14,77 +13,30 @@ import { SessionInputTable, SessionMessageTable } from "./sql"
|
||||
|
||||
type DatabaseService = Database.Interface["db"]
|
||||
|
||||
export { Admitted, Compaction, Delivery, Entry, PromptEntry }
|
||||
export { Admitted, Delivery }
|
||||
|
||||
const decodePrompt = Schema.decodeUnknownSync(Prompt)
|
||||
const encodePrompt = Schema.encodeSync(Prompt)
|
||||
const inboxLocks = KeyedMutex.makeUnsafe<SessionSchema.ID>()
|
||||
|
||||
export class LifecycleConflict extends Schema.TaggedErrorClass<LifecycleConflict>()("SessionInput.LifecycleConflict", {
|
||||
id: SessionMessage.ID,
|
||||
}) {}
|
||||
|
||||
const fromRow = (row: typeof SessionInputTable.$inferSelect): Entry => {
|
||||
const base = {
|
||||
const fromRow = (row: typeof SessionInputTable.$inferSelect): Admitted =>
|
||||
Admitted.make({
|
||||
admittedSeq: row.admitted_seq,
|
||||
id: SessionMessage.ID.make(row.id),
|
||||
sessionID: SessionSchema.ID.make(row.session_id),
|
||||
timeCreated: DateTime.makeUnsafe(row.time_created),
|
||||
}
|
||||
if (row.type === "compaction")
|
||||
return Compaction.make({
|
||||
...base,
|
||||
type: "compaction",
|
||||
...(row.promoted_seq === null ? {} : { handledSeq: row.promoted_seq }),
|
||||
})
|
||||
if (!row.prompt || !row.delivery) throw new LifecycleConflict({ id: base.id })
|
||||
return PromptEntry.make({
|
||||
...base,
|
||||
type: "prompt",
|
||||
prompt: decodePrompt(row.prompt),
|
||||
delivery: row.delivery,
|
||||
timeCreated: DateTime.makeUnsafe(row.time_created),
|
||||
...(row.promoted_seq === null ? {} : { promotedSeq: row.promoted_seq }),
|
||||
})
|
||||
}
|
||||
|
||||
const toAdmitted = (entry: PromptEntry): Admitted =>
|
||||
Admitted.make({
|
||||
admittedSeq: entry.admittedSeq,
|
||||
id: entry.id,
|
||||
sessionID: entry.sessionID,
|
||||
prompt: entry.prompt,
|
||||
delivery: entry.delivery,
|
||||
timeCreated: entry.timeCreated,
|
||||
...(entry.promotedSeq === undefined ? {} : { promotedSeq: entry.promotedSeq }),
|
||||
})
|
||||
|
||||
export const find = Effect.fn("SessionInput.find")(function* (db: DatabaseService, id: SessionMessage.ID) {
|
||||
const row = yield* db.select().from(SessionInputTable).where(eq(SessionInputTable.id, id)).get().pipe(Effect.orDie)
|
||||
return row === undefined ? undefined : fromRow(row)
|
||||
})
|
||||
|
||||
export const pendingCompaction = Effect.fn("SessionInput.pendingCompaction")(function* (
|
||||
db: DatabaseService,
|
||||
sessionID: SessionSchema.ID,
|
||||
) {
|
||||
const row = yield* db
|
||||
.select()
|
||||
.from(SessionInputTable)
|
||||
.where(
|
||||
and(
|
||||
eq(SessionInputTable.session_id, sessionID),
|
||||
eq(SessionInputTable.type, "compaction"),
|
||||
isNull(SessionInputTable.promoted_seq),
|
||||
),
|
||||
)
|
||||
.orderBy(asc(SessionInputTable.admitted_seq))
|
||||
.limit(1)
|
||||
.get()
|
||||
.pipe(Effect.orDie)
|
||||
if (!row) return
|
||||
const entry = fromRow(row)
|
||||
return entry.type === "compaction" ? entry : undefined
|
||||
})
|
||||
export class LifecycleConflict extends Schema.TaggedErrorClass<LifecycleConflict>()("SessionInput.LifecycleConflict", {
|
||||
id: SessionMessage.ID,
|
||||
}) {}
|
||||
|
||||
export const admit = Effect.fn("SessionInput.admit")(function* (
|
||||
db: DatabaseService,
|
||||
@@ -97,10 +49,7 @@ export const admit = Effect.fn("SessionInput.admit")(function* (
|
||||
},
|
||||
) {
|
||||
const existing = yield* find(db, input.id)
|
||||
if (existing !== undefined) {
|
||||
if (existing.type !== "prompt") return yield* Effect.die(new LifecycleConflict({ id: input.id }))
|
||||
return toAdmitted(existing)
|
||||
}
|
||||
if (existing !== undefined) return existing
|
||||
return yield* events
|
||||
.publish(SessionEvent.PromptAdmitted, {
|
||||
inputID: input.id,
|
||||
@@ -124,54 +73,11 @@ export const admit = Effect.fn("SessionInput.admit")(function* (
|
||||
),
|
||||
),
|
||||
Effect.catchDefect((defect) =>
|
||||
find(db, input.id).pipe(
|
||||
Effect.flatMap((stored) =>
|
||||
stored?.type === "prompt" ? Effect.succeed(toAdmitted(stored)) : Effect.die(defect),
|
||||
),
|
||||
),
|
||||
find(db, input.id).pipe(Effect.flatMap((stored) => (stored ? Effect.succeed(stored) : Effect.die(defect)))),
|
||||
),
|
||||
)
|
||||
})
|
||||
|
||||
export const admitCompaction = Effect.fn("SessionInput.admitCompaction")(function* (
|
||||
db: DatabaseService,
|
||||
events: EventV2.Interface,
|
||||
input: { readonly id: SessionMessage.ID; readonly sessionID: SessionSchema.ID },
|
||||
) {
|
||||
return yield* inboxLocks.withLock(input.sessionID)(
|
||||
Effect.gen(function* () {
|
||||
const exact = yield* find(db, input.id)
|
||||
if (exact) {
|
||||
if (exact.type === "compaction" && exact.sessionID === input.sessionID) return exact
|
||||
return yield* Effect.die(new LifecycleConflict({ id: input.id }))
|
||||
}
|
||||
const pending = yield* pendingCompaction(db, input.sessionID)
|
||||
if (pending) return pending
|
||||
return yield* events
|
||||
.publish(SessionEvent.Compaction.Admitted, {
|
||||
inputID: input.id,
|
||||
sessionID: input.sessionID,
|
||||
})
|
||||
.pipe(
|
||||
Effect.flatMap((event) => {
|
||||
if (event.durable === undefined)
|
||||
return Effect.die(new Error("Compaction admission event is missing aggregate sequence"))
|
||||
return pendingCompaction(db, input.sessionID).pipe(
|
||||
Effect.flatMap((stored) =>
|
||||
stored ? Effect.succeed(stored) : Effect.die(new LifecycleConflict({ id: input.id })),
|
||||
),
|
||||
)
|
||||
}),
|
||||
Effect.catchDefect((defect) =>
|
||||
pendingCompaction(db, input.sessionID).pipe(
|
||||
Effect.flatMap((stored) => (stored ? Effect.succeed(stored) : Effect.die(defect))),
|
||||
),
|
||||
),
|
||||
)
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
export const projectAdmitted = Effect.fn("SessionInput.projectAdmitted")(function* (
|
||||
db: DatabaseService,
|
||||
input: {
|
||||
@@ -195,7 +101,6 @@ export const projectAdmitted = Effect.fn("SessionInput.projectAdmitted")(functio
|
||||
.values({
|
||||
id: input.id,
|
||||
session_id: input.sessionID,
|
||||
type: "prompt",
|
||||
admitted_seq: input.admittedSeq,
|
||||
prompt: encodePrompt(input.prompt),
|
||||
delivery: input.delivery,
|
||||
@@ -208,44 +113,6 @@ export const projectAdmitted = Effect.fn("SessionInput.projectAdmitted")(functio
|
||||
if (!stored) return yield* Effect.die(new LifecycleConflict({ id: input.id }))
|
||||
})
|
||||
|
||||
export const projectCompactionAdmitted = Effect.fn("SessionInput.projectCompactionAdmitted")(function* (
|
||||
db: DatabaseService,
|
||||
input: {
|
||||
readonly admittedSeq: number
|
||||
readonly id: SessionMessage.ID
|
||||
readonly sessionID: SessionSchema.ID
|
||||
readonly timeCreated: DateTime.Utc
|
||||
},
|
||||
) {
|
||||
const message = yield* db
|
||||
.select({ id: SessionMessageTable.id })
|
||||
.from(SessionMessageTable)
|
||||
.where(eq(SessionMessageTable.id, input.id))
|
||||
.get()
|
||||
.pipe(Effect.orDie)
|
||||
if (message !== undefined) return yield* Effect.die(new LifecycleConflict({ id: input.id }))
|
||||
const stored = yield* db
|
||||
.insert(SessionInputTable)
|
||||
.values({
|
||||
id: input.id,
|
||||
session_id: input.sessionID,
|
||||
type: "compaction",
|
||||
admitted_seq: input.admittedSeq,
|
||||
time_created: DateTime.toEpochMillis(input.timeCreated),
|
||||
})
|
||||
.onConflictDoNothing()
|
||||
.returning()
|
||||
.get()
|
||||
.pipe(Effect.orDie)
|
||||
if (stored) {
|
||||
const entry = fromRow(stored)
|
||||
return entry.type === "compaction" ? entry : yield* Effect.die(new LifecycleConflict({ id: entry.id }))
|
||||
}
|
||||
const pending = yield* pendingCompaction(db, input.sessionID)
|
||||
if (pending) return pending
|
||||
return yield* Effect.die(new LifecycleConflict({ id: input.id }))
|
||||
})
|
||||
|
||||
export const projectPromptPromoted = Effect.fn("SessionInput.projectPromptPromoted")(function* (
|
||||
db: DatabaseService,
|
||||
input: {
|
||||
@@ -254,7 +121,6 @@ export const projectPromptPromoted = Effect.fn("SessionInput.projectPromptPromot
|
||||
readonly promotedSeq: number
|
||||
},
|
||||
) {
|
||||
if (yield* pendingCompaction(db, input.sessionID)) return yield* Effect.die(new LifecycleConflict({ id: input.id }))
|
||||
const updated = yield* db
|
||||
.update(SessionInputTable)
|
||||
.set({ promoted_seq: input.promotedSeq })
|
||||
@@ -262,7 +128,6 @@ export const projectPromptPromoted = Effect.fn("SessionInput.projectPromptPromot
|
||||
and(
|
||||
eq(SessionInputTable.id, input.id),
|
||||
eq(SessionInputTable.session_id, input.sessionID),
|
||||
eq(SessionInputTable.type, "prompt"),
|
||||
isNull(SessionInputTable.promoted_seq),
|
||||
),
|
||||
)
|
||||
@@ -271,58 +136,29 @@ export const projectPromptPromoted = Effect.fn("SessionInput.projectPromptPromot
|
||||
.pipe(Effect.orDie)
|
||||
if (updated) {
|
||||
const stored = fromRow(updated)
|
||||
if (stored.type !== "prompt" || stored.sessionID !== input.sessionID)
|
||||
return yield* Effect.die(new LifecycleConflict({ id: input.id }))
|
||||
if (stored.sessionID !== input.sessionID) return yield* Effect.die(new LifecycleConflict({ id: input.id }))
|
||||
return stored
|
||||
}
|
||||
|
||||
// Every PromptPromoted event is published from an admitted inbox row, so a missing or
|
||||
// divergent row on replay is an invariant violation.
|
||||
const stored = yield* find(db, input.id)
|
||||
if (
|
||||
!stored ||
|
||||
stored.type !== "prompt" ||
|
||||
stored.sessionID !== input.sessionID ||
|
||||
stored.promotedSeq !== input.promotedSeq
|
||||
)
|
||||
if (!stored || stored.sessionID !== input.sessionID || stored.promotedSeq !== input.promotedSeq)
|
||||
return yield* Effect.die(new LifecycleConflict({ id: input.id }))
|
||||
return stored
|
||||
})
|
||||
|
||||
export const settleCompaction = Effect.fn("SessionInput.settleCompaction")(function* (
|
||||
db: DatabaseService,
|
||||
input: { readonly sessionID: SessionSchema.ID; readonly handledSeq: number },
|
||||
) {
|
||||
const updated = yield* db
|
||||
.update(SessionInputTable)
|
||||
.set({ promoted_seq: input.handledSeq })
|
||||
.where(
|
||||
and(
|
||||
eq(SessionInputTable.session_id, input.sessionID),
|
||||
eq(SessionInputTable.type, "compaction"),
|
||||
isNull(SessionInputTable.promoted_seq),
|
||||
),
|
||||
)
|
||||
.returning()
|
||||
.get()
|
||||
.pipe(Effect.orDie)
|
||||
if (updated) {
|
||||
const stored = fromRow(updated)
|
||||
return stored.type === "compaction" ? stored : yield* Effect.die(new LifecycleConflict({ id: stored.id }))
|
||||
}
|
||||
return undefined
|
||||
})
|
||||
|
||||
export const hasPending = Effect.fn("SessionInput.hasPending")(function* (
|
||||
db: DatabaseService,
|
||||
sessionID: SessionSchema.ID,
|
||||
delivery: Delivery,
|
||||
) {
|
||||
if (yield* pendingCompaction(db, sessionID)) return false
|
||||
const row = yield* db
|
||||
.select({ id: SessionInputTable.id })
|
||||
.from(SessionInputTable)
|
||||
.where(
|
||||
and(
|
||||
eq(SessionInputTable.session_id, sessionID),
|
||||
eq(SessionInputTable.type, "prompt"),
|
||||
isNull(SessionInputTable.promoted_seq),
|
||||
eq(SessionInputTable.delivery, delivery),
|
||||
),
|
||||
@@ -345,44 +181,42 @@ export const equivalent = (
|
||||
input.sessionID === expected.sessionID &&
|
||||
JSON.stringify(encodePrompt(input.prompt)) === JSON.stringify(encodePrompt(expected.prompt))
|
||||
|
||||
const matchesProjection = (
|
||||
input: Admitted,
|
||||
expected: {
|
||||
readonly sessionID: SessionSchema.ID
|
||||
readonly prompt: Prompt
|
||||
readonly delivery: Delivery
|
||||
readonly timeCreated: DateTime.Utc
|
||||
},
|
||||
) =>
|
||||
equivalent(input, expected) &&
|
||||
DateTime.toEpochMillis(input.timeCreated) === DateTime.toEpochMillis(expected.timeCreated)
|
||||
|
||||
const publish = Effect.fn("SessionInput.publish")(function* (
|
||||
db: DatabaseService,
|
||||
events: EventV2.Interface,
|
||||
sessionID: SessionSchema.ID,
|
||||
rows: ReadonlyArray<typeof SessionInputTable.$inferSelect>,
|
||||
) {
|
||||
return yield* inboxLocks.withLock(sessionID)(
|
||||
Effect.gen(function* () {
|
||||
if (yield* pendingCompaction(db, sessionID)) return 0
|
||||
yield* Effect.forEach(
|
||||
rows,
|
||||
(row) => {
|
||||
const entry = fromRow(row)
|
||||
if (entry.type !== "prompt") return Effect.die(new LifecycleConflict({ id: entry.id }))
|
||||
return events
|
||||
.publish(SessionEvent.PromptPromoted, {
|
||||
sessionID,
|
||||
inputID: entry.id,
|
||||
})
|
||||
.pipe(
|
||||
Effect.catchDefect((defect) =>
|
||||
defect instanceof LifecycleConflict
|
||||
? find(db, entry.id).pipe(
|
||||
Effect.flatMap((stored) =>
|
||||
stored?.type === "prompt" && stored.promotedSeq !== undefined
|
||||
? Effect.void
|
||||
: Effect.die(defect),
|
||||
),
|
||||
)
|
||||
: Effect.die(defect),
|
||||
),
|
||||
)
|
||||
},
|
||||
{ discard: true },
|
||||
for (const row of rows) {
|
||||
const id = SessionMessage.ID.make(row.id)
|
||||
yield* events
|
||||
.publish(SessionEvent.PromptPromoted, {
|
||||
sessionID,
|
||||
inputID: id,
|
||||
})
|
||||
.pipe(
|
||||
Effect.catchDefect((defect) =>
|
||||
defect instanceof LifecycleConflict
|
||||
? find(db, id).pipe(
|
||||
Effect.flatMap((stored) => (stored?.promotedSeq === undefined ? Effect.die(defect) : Effect.void)),
|
||||
)
|
||||
: Effect.die(defect),
|
||||
),
|
||||
)
|
||||
return rows.length
|
||||
}),
|
||||
)
|
||||
}
|
||||
return rows.length
|
||||
})
|
||||
|
||||
export const promoteSteers = Effect.fn("SessionInput.promoteSteers")(function* (
|
||||
@@ -390,14 +224,12 @@ export const promoteSteers = Effect.fn("SessionInput.promoteSteers")(function* (
|
||||
events: EventV2.Interface,
|
||||
sessionID: SessionSchema.ID,
|
||||
) {
|
||||
if (yield* pendingCompaction(db, sessionID)) return 0
|
||||
const rows = yield* db
|
||||
.select()
|
||||
.from(SessionInputTable)
|
||||
.where(
|
||||
and(
|
||||
eq(SessionInputTable.session_id, sessionID),
|
||||
eq(SessionInputTable.type, "prompt"),
|
||||
isNull(SessionInputTable.promoted_seq),
|
||||
eq(SessionInputTable.delivery, "steer"),
|
||||
),
|
||||
@@ -413,14 +245,12 @@ export const promoteNextQueued = Effect.fn("SessionInput.promoteNextQueued")(fun
|
||||
events: EventV2.Interface,
|
||||
sessionID: SessionSchema.ID,
|
||||
) {
|
||||
if (yield* pendingCompaction(db, sessionID)) return false
|
||||
const row = yield* db
|
||||
.select()
|
||||
.from(SessionInputTable)
|
||||
.where(
|
||||
and(
|
||||
eq(SessionInputTable.session_id, sessionID),
|
||||
eq(SessionInputTable.type, "prompt"),
|
||||
isNull(SessionInputTable.promoted_seq),
|
||||
eq(SessionInputTable.delivery, "queue"),
|
||||
),
|
||||
|
||||
@@ -8,7 +8,6 @@ export type MemoryState = {
|
||||
}
|
||||
|
||||
export interface Adapter {
|
||||
readonly getModel: () => Effect.Effect<SessionMessage.ModelSelected["model"] | undefined, never, never>
|
||||
readonly getCurrentAssistant: () => Effect.Effect<SessionMessage.Assistant | undefined, never, never>
|
||||
readonly getAssistant: (
|
||||
messageID: SessionMessage.ID,
|
||||
@@ -16,10 +15,8 @@ export interface Adapter {
|
||||
readonly getShell: (
|
||||
shellID: SessionMessage.Shell["shell"]["id"],
|
||||
) => Effect.Effect<SessionMessage.Shell | undefined, never, never>
|
||||
readonly getCompaction: () => Effect.Effect<SessionMessage.Compaction | undefined, never, never>
|
||||
readonly updateAssistant: (assistant: SessionMessage.Assistant) => Effect.Effect<void, never, never>
|
||||
readonly updateShell: (shell: SessionMessage.Shell) => Effect.Effect<void, never, never>
|
||||
readonly updateCompaction: (compaction: SessionMessage.Compaction) => Effect.Effect<void, never, never>
|
||||
readonly appendMessage: (message: SessionMessage.Message) => Effect.Effect<void, never, never>
|
||||
}
|
||||
|
||||
@@ -28,23 +25,10 @@ export function memory(state: MemoryState): Adapter {
|
||||
state.messages.findLastIndex((message) => message.id === messageID)
|
||||
const shellIndex = (messageID: SessionMessage.ID) =>
|
||||
state.messages.findLastIndex((message) => message.id === messageID)
|
||||
const compactionIndex = () =>
|
||||
state.messages.findLastIndex(
|
||||
(message) => message.type === "compaction" && (message.status === "queued" || message.status === "running"),
|
||||
)
|
||||
// A newer step supersedes stale incomplete rows; never resume an older assistant projection.
|
||||
const latestAssistantIndex = () => state.messages.findLastIndex((message) => message.type === "assistant")
|
||||
|
||||
return {
|
||||
getModel() {
|
||||
return Effect.sync(
|
||||
() =>
|
||||
state.messages.findLast(
|
||||
(message): message is SessionMessage.ModelSelected | SessionMessage.Assistant =>
|
||||
message.type === "model-switched" || message.type === "assistant",
|
||||
)?.model,
|
||||
)
|
||||
},
|
||||
getCurrentAssistant() {
|
||||
return Effect.sync(() => {
|
||||
const index = latestAssistantIndex()
|
||||
@@ -68,13 +52,6 @@ export function memory(state: MemoryState): Adapter {
|
||||
})
|
||||
})
|
||||
},
|
||||
getCompaction() {
|
||||
return Effect.sync(() => {
|
||||
const index = compactionIndex()
|
||||
const message = state.messages[index]
|
||||
return message?.type === "compaction" ? message : undefined
|
||||
})
|
||||
},
|
||||
updateAssistant(assistant) {
|
||||
return Effect.sync(() => {
|
||||
const index = assistantIndex(assistant.id)
|
||||
@@ -93,12 +70,6 @@ export function memory(state: MemoryState): Adapter {
|
||||
state.messages[index] = shell
|
||||
})
|
||||
},
|
||||
updateCompaction(compaction) {
|
||||
return Effect.sync(() => {
|
||||
const index = state.messages.findLastIndex((message) => message.id === compaction.id)
|
||||
if (index >= 0) state.messages[index] = compaction
|
||||
})
|
||||
},
|
||||
appendMessage(message) {
|
||||
return Effect.sync(() => {
|
||||
state.messages.push(message)
|
||||
@@ -155,19 +126,15 @@ export function update(adapter: Adapter, event: SessionEvent.Event) {
|
||||
)
|
||||
},
|
||||
"session.model.selected": (event) => {
|
||||
return Effect.gen(function* () {
|
||||
const previous = yield* adapter.getModel()
|
||||
yield* adapter.appendMessage(
|
||||
SessionMessage.ModelSelected.make({
|
||||
id: SessionMessage.ID.fromEvent(event.id),
|
||||
type: "model-switched",
|
||||
metadata: event.metadata,
|
||||
model: event.data.model,
|
||||
previous,
|
||||
time: { created: event.created },
|
||||
}),
|
||||
)
|
||||
})
|
||||
return adapter.appendMessage(
|
||||
SessionMessage.ModelSelected.make({
|
||||
id: SessionMessage.ID.fromEvent(event.id),
|
||||
type: "model-switched",
|
||||
metadata: event.metadata,
|
||||
model: event.data.model,
|
||||
time: { created: event.created },
|
||||
}),
|
||||
)
|
||||
},
|
||||
"session.moved": () => Effect.void,
|
||||
"session.renamed": () => Effect.void,
|
||||
@@ -442,60 +409,21 @@ export function update(adapter: Adapter, event: SessionEvent.Event) {
|
||||
}
|
||||
})
|
||||
},
|
||||
"session.compaction.admitted": (event) =>
|
||||
adapter.appendMessage(
|
||||
SessionMessage.Compaction.make({
|
||||
id: event.data.inputID,
|
||||
type: "compaction",
|
||||
status: "queued",
|
||||
metadata: event.metadata,
|
||||
reason: "manual",
|
||||
summary: "",
|
||||
recent: "",
|
||||
time: { created: event.created },
|
||||
}),
|
||||
),
|
||||
"session.compaction.started": (event) =>
|
||||
Effect.gen(function* () {
|
||||
if (event.data.reason !== "manual") return
|
||||
const current = yield* adapter.getCompaction()
|
||||
if (!current) return
|
||||
yield* adapter.updateCompaction({ ...current, status: "running" })
|
||||
}),
|
||||
"session.compaction.started": () => Effect.void,
|
||||
"session.compaction.delta": () => Effect.void,
|
||||
"session.compaction.ended": (event) => {
|
||||
return Effect.gen(function* () {
|
||||
const current = event.data.reason === "manual" ? yield* adapter.getCompaction() : undefined
|
||||
if (current) {
|
||||
yield* adapter.updateCompaction({
|
||||
...current,
|
||||
status: "completed",
|
||||
reason: event.data.reason,
|
||||
summary: event.data.text,
|
||||
recent: event.data.recent,
|
||||
})
|
||||
return
|
||||
}
|
||||
yield* adapter.appendMessage(
|
||||
SessionMessage.Compaction.make({
|
||||
id: SessionMessage.ID.fromEvent(event.id),
|
||||
type: "compaction",
|
||||
status: "completed",
|
||||
metadata: event.metadata,
|
||||
reason: event.data.reason,
|
||||
summary: event.data.text,
|
||||
recent: event.data.recent,
|
||||
time: { created: event.created },
|
||||
}),
|
||||
)
|
||||
})
|
||||
return adapter.appendMessage(
|
||||
SessionMessage.Compaction.make({
|
||||
id: SessionMessage.ID.fromEvent(event.id),
|
||||
type: "compaction",
|
||||
metadata: event.metadata,
|
||||
reason: event.data.reason,
|
||||
summary: event.data.text,
|
||||
recent: event.data.recent,
|
||||
time: { created: event.created },
|
||||
}),
|
||||
)
|
||||
},
|
||||
"session.compaction.failed": () =>
|
||||
Effect.gen(function* () {
|
||||
const current = yield* adapter.getCompaction()
|
||||
if (!current) return
|
||||
yield* adapter.updateCompaction({ ...current, status: "failed" })
|
||||
}),
|
||||
"session.revert.staged": () => Effect.void,
|
||||
"session.revert.cleared": () => Effect.void,
|
||||
"session.revert.committed": () => Effect.void,
|
||||
|
||||
@@ -5,7 +5,6 @@ import { DateTime, Effect, Layer, Schema } from "effect"
|
||||
import { Database } from "../database/database"
|
||||
import { EventV2 } from "../event"
|
||||
import { makeGlobalNode } from "../effect/app-node"
|
||||
import { ModelV2 } from "../model"
|
||||
import { SessionEvent } from "./event"
|
||||
import { SessionV1 } from "../v1/session"
|
||||
import { WorkspaceTable } from "../control-plane/workspace.sql"
|
||||
@@ -243,7 +242,6 @@ const projectFork = Effect.fn("SessionProjector.projectFork")(function* (
|
||||
eq(SessionMessageTable.session_id, event.data.parentID),
|
||||
gt(SessionMessageTable.seq, cursor),
|
||||
copiedSeq === 0 ? undefined : lt(SessionMessageTable.seq, copiedSeq + 1),
|
||||
sql`${SessionMessageTable.type} != 'compaction' or json_extract(${SessionMessageTable.data}, '$.status') not in ('queued', 'running')`,
|
||||
),
|
||||
)
|
||||
.orderBy(asc(SessionMessageTable.seq))
|
||||
@@ -293,12 +291,11 @@ const projectFork = Effect.fn("SessionProjector.projectFork")(function* (
|
||||
.values(
|
||||
inputRows.flatMap((row) => {
|
||||
const id = idMap.get(row.id)
|
||||
return id && row.type === "prompt"
|
||||
return id
|
||||
? [
|
||||
{
|
||||
id,
|
||||
session_id: event.data.sessionID,
|
||||
type: "prompt" as const,
|
||||
prompt: row.prompt,
|
||||
delivery: row.delivery,
|
||||
admitted_seq: row.admitted_seq,
|
||||
@@ -359,17 +356,6 @@ function run(db: DatabaseService, event: MessageEvent) {
|
||||
}
|
||||
const appendMessage = (message: SessionMessage.Message) => insertMessage(db, event, message)
|
||||
const adapter: SessionMessageUpdater.Adapter = {
|
||||
getModel() {
|
||||
return db
|
||||
.select({ model: SessionTable.model })
|
||||
.from(SessionTable)
|
||||
.where(eq(SessionTable.id, event.data.sessionID))
|
||||
.get()
|
||||
.pipe(
|
||||
Effect.orDie,
|
||||
Effect.map((row) => (row?.model ? Schema.decodeUnknownSync(ModelV2.Ref)(row.model) : undefined)),
|
||||
)
|
||||
},
|
||||
getCurrentAssistant() {
|
||||
return Effect.gen(function* () {
|
||||
// A newer step supersedes stale incomplete rows; never resume an older assistant projection.
|
||||
@@ -428,30 +414,8 @@ function run(db: DatabaseService, event: MessageEvent) {
|
||||
return message.type === "shell" ? message : undefined
|
||||
})
|
||||
},
|
||||
getCompaction() {
|
||||
return Effect.gen(function* () {
|
||||
const row = yield* db
|
||||
.select()
|
||||
.from(SessionMessageTable)
|
||||
.where(
|
||||
and(
|
||||
eq(SessionMessageTable.session_id, event.data.sessionID),
|
||||
eq(SessionMessageTable.type, "compaction"),
|
||||
sql`json_extract(${SessionMessageTable.data}, '$.status') in ('queued', 'running')`,
|
||||
),
|
||||
)
|
||||
.orderBy(desc(SessionMessageTable.seq))
|
||||
.limit(1)
|
||||
.get()
|
||||
.pipe(Effect.orDie)
|
||||
if (!row) return
|
||||
const message = decodeRow(row)
|
||||
return message.type === "compaction" ? message : undefined
|
||||
})
|
||||
},
|
||||
updateAssistant: updateMessage,
|
||||
updateShell: updateMessage,
|
||||
updateCompaction: updateMessage,
|
||||
appendMessage,
|
||||
}
|
||||
yield* SessionMessageUpdater.update(adapter, event)
|
||||
@@ -606,13 +570,13 @@ const layer = Layer.effectDiscard(
|
||||
)
|
||||
yield* events.project(SessionEvent.ModelSelected, (event) =>
|
||||
Effect.gen(function* () {
|
||||
yield* run(db, event)
|
||||
yield* db
|
||||
.update(SessionTable)
|
||||
.set({ model: event.data.model, time_updated: DateTime.toEpochMillis(event.created) })
|
||||
.where(eq(SessionTable.id, event.data.sessionID))
|
||||
.run()
|
||||
.pipe(Effect.orDie)
|
||||
yield* run(db, event)
|
||||
}),
|
||||
)
|
||||
yield* events.project(SessionEvent.Renamed, (event) =>
|
||||
@@ -658,20 +622,6 @@ const layer = Layer.effectDiscard(
|
||||
})
|
||||
}),
|
||||
)
|
||||
yield* events.project(SessionEvent.Compaction.Admitted, (event) =>
|
||||
Effect.gen(function* () {
|
||||
if (event.durable === undefined)
|
||||
return yield* Effect.die(new Error("Durable Session event is missing aggregate sequence"))
|
||||
const admitted = yield* SessionInput.projectCompactionAdmitted(db, {
|
||||
admittedSeq: event.durable.seq,
|
||||
id: event.data.inputID,
|
||||
sessionID: event.data.sessionID,
|
||||
timeCreated: event.created,
|
||||
})
|
||||
if (admitted.id !== event.data.inputID) return
|
||||
yield* run(db, event)
|
||||
}),
|
||||
)
|
||||
yield* events.project(SessionEvent.Execution.Succeeded, (event) => run(db, event))
|
||||
yield* events.project(SessionEvent.Execution.Failed, (event) => run(db, event))
|
||||
yield* events.project(SessionEvent.Execution.Interrupted, (event) => run(db, event))
|
||||
@@ -702,30 +652,7 @@ const layer = Layer.effectDiscard(
|
||||
yield* events.project(SessionEvent.Reasoning.Started, (event) => run(db, event))
|
||||
yield* events.project(SessionEvent.Reasoning.Ended, (event) => run(db, event))
|
||||
yield* events.project(SessionEvent.RetryScheduled, (event) => run(db, event))
|
||||
yield* events.project(SessionEvent.Compaction.Started, (event) => run(db, event))
|
||||
yield* events.project(SessionEvent.Compaction.Ended, (event) =>
|
||||
Effect.gen(function* () {
|
||||
yield* run(db, event)
|
||||
if (event.durable === undefined)
|
||||
return yield* Effect.die(new Error("Durable Session event is missing aggregate sequence"))
|
||||
if (event.data.reason === "manual")
|
||||
yield* SessionInput.settleCompaction(db, {
|
||||
sessionID: event.data.sessionID,
|
||||
handledSeq: event.durable.seq,
|
||||
})
|
||||
}),
|
||||
)
|
||||
yield* events.project(SessionEvent.Compaction.Failed, (event) =>
|
||||
Effect.gen(function* () {
|
||||
yield* run(db, event)
|
||||
if (event.durable === undefined)
|
||||
return yield* Effect.die(new Error("Durable Session event is missing aggregate sequence"))
|
||||
yield* SessionInput.settleCompaction(db, {
|
||||
sessionID: event.data.sessionID,
|
||||
handledSeq: event.durable.seq,
|
||||
})
|
||||
}),
|
||||
)
|
||||
yield* events.project(SessionEvent.Compaction.Ended, (event) => run(db, event))
|
||||
yield* events.project(SessionEvent.RevertEvent.Staged, (event) =>
|
||||
db
|
||||
.update(SessionTable)
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
type ProviderErrorEvent,
|
||||
} from "@opencode-ai/llm"
|
||||
import { SessionError } from "@opencode-ai/schema/session-error"
|
||||
import { Cause, Effect, Exit, Fiber, FiberSet, Layer, Option, Semaphore, Stream } from "effect"
|
||||
import { Cause, Effect, Exit, FiberSet, Layer, Option, Semaphore, Stream } from "effect"
|
||||
import { AgentV2 } from "../../agent"
|
||||
import { Config } from "../../config"
|
||||
import { Database } from "../../database/database"
|
||||
@@ -141,13 +141,16 @@ const layer = Layer.effect(
|
||||
sessionID,
|
||||
assistantMessageID: message.id,
|
||||
callID: tool.id,
|
||||
error: { type: "tool.stale", message: `Tool execution interrupted: ${tool.name}` },
|
||||
error: { type: "tool.stale", message: "Tool execution interrupted", name: tool.name },
|
||||
executed: tool.executed === true,
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const awaitToolFibers = (fibers: FiberSet.FiberSet<void, ToolOutputStore.Error | UserInterruptedError>) =>
|
||||
Effect.raceFirst(FiberSet.join(fibers), FiberSet.awaitEmpty(fibers))
|
||||
|
||||
// Match V1: dismissing a question halts the loop instead of becoming model-facing tool output.
|
||||
const isQuestionRejected = (cause: Cause.Cause<unknown>) =>
|
||||
cause.reasons.some((reason) => Cause.isDieReason(reason) && reason.defect instanceof QuestionV2.RejectedError)
|
||||
@@ -185,7 +188,6 @@ const layer = Layer.effect(
|
||||
session.id,
|
||||
)
|
||||
const toolFibers = yield* FiberSet.make<void, ToolOutputStore.Error | UserInterruptedError>()
|
||||
const ownedToolFibers: Array<Fiber.Fiber<void, ToolOutputStore.Error | UserInterruptedError>> = []
|
||||
let needsContinuation = false
|
||||
let currentStep = step
|
||||
if (promotion) {
|
||||
@@ -220,10 +222,7 @@ const layer = Layer.effect(
|
||||
toolChoice: isLastStep ? "none" : undefined,
|
||||
})
|
||||
// Automatic compaction completed; rebuild the request from compacted history.
|
||||
if (
|
||||
!(yield* SessionInput.pendingCompaction(db, session.id)) &&
|
||||
(yield* compaction.compactIfNeeded({ sessionID: session.id, messages: context, request }))
|
||||
)
|
||||
if (yield* compaction.compactIfNeeded({ sessionID: session.id, messages: context, request }))
|
||||
return { _tag: "RestartAfterCompaction", step: currentStep } as const
|
||||
const startSnapshot = yield* snapshots.capture()
|
||||
const publisher = createLLMEventPublisher(events, {
|
||||
@@ -266,39 +265,37 @@ const layer = Layer.effect(
|
||||
}
|
||||
needsContinuation = true
|
||||
const assistantMessageID = yield* publisher.assistantMessageID(event.id)
|
||||
ownedToolFibers.push(
|
||||
yield* Effect.uninterruptibleMask((restore) =>
|
||||
restore(
|
||||
toolMaterialization.settle({
|
||||
sessionID: session.id,
|
||||
agent: agent.id,
|
||||
assistantMessageID,
|
||||
call: event,
|
||||
}),
|
||||
).pipe(
|
||||
Effect.flatMap((settlement) =>
|
||||
publish(
|
||||
LLMEvent.toolResult({
|
||||
id: event.id,
|
||||
name: event.name,
|
||||
result: settlement.result,
|
||||
output: settlement.output,
|
||||
}),
|
||||
settlement.outputPaths ?? [],
|
||||
settlement.error,
|
||||
).pipe(
|
||||
Effect.andThen(
|
||||
settlement.error?.type === "permission.rejected"
|
||||
? serialized(publisher.failAssistant(settlement.error)).pipe(
|
||||
Effect.andThen(Effect.fail(new UserInterruptedError())),
|
||||
)
|
||||
: Effect.void,
|
||||
),
|
||||
yield* Effect.uninterruptibleMask((restore) =>
|
||||
restore(
|
||||
toolMaterialization.settle({
|
||||
sessionID: session.id,
|
||||
agent: agent.id,
|
||||
assistantMessageID,
|
||||
call: event,
|
||||
}),
|
||||
).pipe(
|
||||
Effect.flatMap((settlement) =>
|
||||
publish(
|
||||
LLMEvent.toolResult({
|
||||
id: event.id,
|
||||
name: event.name,
|
||||
result: settlement.result,
|
||||
output: settlement.output,
|
||||
}),
|
||||
settlement.outputPaths ?? [],
|
||||
settlement.error,
|
||||
).pipe(
|
||||
Effect.andThen(
|
||||
settlement.error?.type === "permission.rejected"
|
||||
? serialized(publisher.failAssistant(settlement.error)).pipe(
|
||||
Effect.andThen(Effect.fail(new UserInterruptedError())),
|
||||
)
|
||||
: Effect.void,
|
||||
),
|
||||
),
|
||||
),
|
||||
).pipe(FiberSet.run(toolFibers)),
|
||||
)
|
||||
),
|
||||
).pipe(FiberSet.run(toolFibers))
|
||||
}),
|
||||
),
|
||||
Effect.ensuring(serialized(publisher.flush())),
|
||||
@@ -348,8 +345,8 @@ const layer = Layer.effect(
|
||||
return { _tag: "RestartAfterOverflowCompaction", step: currentStep } as const
|
||||
|
||||
// An unrecovered held-back overflow becomes the step's durable provider error. A
|
||||
// thrown LLM failure records the assistant failure unless a provider error was
|
||||
// already recorded from the stream. Terminal publication waits for owned tools.
|
||||
// thrown LLM failure fails hosted tool calls and the assistant unless a provider
|
||||
// error was already recorded from the stream.
|
||||
if (overflowFailure) yield* publish(overflowFailure)
|
||||
const llmFailure = streamFailure instanceof LLMError ? streamFailure : undefined
|
||||
if (llmFailure && !publisher.hasProviderError()) {
|
||||
@@ -366,39 +363,39 @@ const layer = Layer.effect(
|
||||
step: currentStep,
|
||||
})
|
||||
}
|
||||
yield* serialized(
|
||||
publisher.failUnsettledTools(
|
||||
{ type: "tool.result-missing", message: "Provider did not return a tool result" },
|
||||
true,
|
||||
),
|
||||
)
|
||||
yield* serialized(publisher.failAssistant(error))
|
||||
}
|
||||
// Provider error events only arrive from the stream, so the flag is final here.
|
||||
const providerFailed = publisher.hasProviderError()
|
||||
|
||||
// Settle every owned tool fiber. FiberSet.join returns on the first failure, so retain
|
||||
// the individual fibers and await all exits before publishing the terminal step event.
|
||||
// Settle tool fibers: an interrupted stream abandons unstarted tool work first.
|
||||
if (streamInterrupted) yield* FiberSet.clear(toolFibers)
|
||||
const settled = yield* restore(
|
||||
Effect.forEach(ownedToolFibers, Fiber.await, { concurrency: "unbounded" }),
|
||||
).pipe(Effect.exit)
|
||||
const settledCauses =
|
||||
settled._tag === "Failure"
|
||||
? [settled.cause]
|
||||
: settled.value.flatMap((exit) => (exit._tag === "Failure" ? [exit.cause] : []))
|
||||
const toolsInterrupted = settledCauses.some(Cause.hasInterrupts)
|
||||
const questionDismissed = settledCauses.some(isQuestionRejected)
|
||||
const permissionRejected = settledCauses.some(
|
||||
(cause) => Option.getOrUndefined(Cause.findErrorOption(cause)) instanceof UserInterruptedError,
|
||||
)
|
||||
const settled = yield* restore(awaitToolFibers(toolFibers)).pipe(Effect.exit)
|
||||
const toolsInterrupted = settled._tag === "Failure" && Cause.hasInterrupts(settled.cause)
|
||||
const questionDismissed = settled._tag === "Failure" && isQuestionRejected(settled.cause)
|
||||
const settledError =
|
||||
settled._tag === "Failure" ? Option.getOrUndefined(Cause.findErrorOption(settled.cause)) : undefined
|
||||
const permissionRejected = settledError instanceof UserInterruptedError
|
||||
|
||||
if (questionDismissed || permissionRejected || streamInterrupted || toolsInterrupted) {
|
||||
yield* FiberSet.clear(toolFibers)
|
||||
yield* serialized(publisher.failUnsettledTools({ type: "aborted", message: "Tool execution interrupted" }))
|
||||
yield* serialized(publisher.failAssistant({ type: "aborted", message: "Step interrupted" }))
|
||||
// Match V1: dismissing a question halts the loop like an interruption.
|
||||
if (questionDismissed || permissionRejected) return yield* new UserInterruptedError()
|
||||
}
|
||||
// A settled tool fiber failure is one of two things. A defect from a tool
|
||||
// implementation becomes a failed tool call the model can read, and the step still
|
||||
// settles so the model may recover. A typed infrastructure failure (tool output
|
||||
// could not be persisted) also fails the assistant and then fails the drain.
|
||||
const settledFailure = settledCauses.find(
|
||||
(cause) => !Cause.hasInterrupts(cause) && !isQuestionRejected(cause) && !permissionRejected,
|
||||
)
|
||||
const settledFailure =
|
||||
settled._tag === "Failure" && !toolsInterrupted && !permissionRejected ? settled.cause : undefined
|
||||
const infraError =
|
||||
settledFailure === undefined ? undefined : Option.getOrUndefined(Cause.findErrorOption(settledFailure))
|
||||
if (settledFailure !== undefined) {
|
||||
@@ -408,50 +405,26 @@ const layer = Layer.effect(
|
||||
if (infraError !== undefined) yield* serialized(publisher.failAssistant(error))
|
||||
}
|
||||
|
||||
// Fail unresolved calls before the terminal step event. Local calls have joined, so
|
||||
// these sweeps only close calls that could not produce a truthful settlement.
|
||||
const stepSettlement = publisher.stepSettlement()
|
||||
const stepEndedCleanly =
|
||||
!streamInterrupted && !toolsInterrupted && infraError === undefined && !providerFailed
|
||||
if (stepSettlement && stepEndedCleanly) yield* publishStepEnd(stepSettlement)
|
||||
// A provider error orphans recorded local calls; a clean stream can still leave
|
||||
// hosted calls without results.
|
||||
if (providerFailed)
|
||||
yield* serialized(publisher.failUnsettledTools({ type: "aborted", message: "Tool execution interrupted" }))
|
||||
if (llmFailure && !providerFailed)
|
||||
if (stream._tag === "Success" && !providerFailed)
|
||||
yield* serialized(
|
||||
publisher.failUnsettledTools(
|
||||
{
|
||||
type: "tool.result-missing",
|
||||
message: "Provider did not return a tool result",
|
||||
},
|
||||
{ type: "tool.result-missing", message: "Provider did not return a tool result" },
|
||||
true,
|
||||
),
|
||||
)
|
||||
const hostedResultMissing =
|
||||
stream._tag === "Success" && !providerFailed
|
||||
? yield* serialized(
|
||||
publisher.failUnsettledTools(
|
||||
{ type: "tool.result-missing", message: "Provider did not return a tool result" },
|
||||
true,
|
||||
),
|
||||
)
|
||||
: false
|
||||
if (hostedResultMissing && !publisher.stepSettlement())
|
||||
yield* serialized(
|
||||
publisher.failAssistant({
|
||||
type: "tool.result-missing",
|
||||
message: "Provider did not return a tool result",
|
||||
}),
|
||||
)
|
||||
|
||||
const stepFailure = publisher.stepFailure()
|
||||
const stepSettlement = publisher.stepSettlement()
|
||||
const stepEndedCleanly =
|
||||
!streamInterrupted && !toolsInterrupted && infraError === undefined && !providerFailed && !stepFailure
|
||||
if (stepSettlement && stepEndedCleanly) yield* publishStepEnd(stepSettlement)
|
||||
if (stepFailure) yield* serialized(publisher.publishStepFailure())
|
||||
|
||||
if (stream._tag === "Failure") return yield* Effect.failCause(stream.cause)
|
||||
// Match V1: dismissing a question halts the loop like an interruption.
|
||||
if (questionDismissed || permissionRejected) return yield* new UserInterruptedError()
|
||||
if ((toolsInterrupted || infraError !== undefined) && settledFailure)
|
||||
return yield* Effect.failCause(settledFailure)
|
||||
if (toolsInterrupted && settled._tag === "Failure") return yield* Effect.failCause(settled.cause)
|
||||
if (settled._tag === "Failure" && (toolsInterrupted || infraError !== undefined))
|
||||
return yield* Effect.failCause(settled.cause)
|
||||
const stepFailure = publisher.stepFailure()
|
||||
if (stepFailure) return yield* new StepFailedError({ error: stepFailure })
|
||||
return {
|
||||
_tag: "Completed",
|
||||
@@ -506,36 +479,11 @@ const layer = Layer.effect(
|
||||
}
|
||||
})
|
||||
|
||||
const runPendingCompaction = Effect.fn("SessionRunner.runPendingCompaction")(function* (
|
||||
sessionID: SessionSchema.ID,
|
||||
) {
|
||||
const pending = yield* SessionInput.pendingCompaction(db, sessionID)
|
||||
if (!pending) return false
|
||||
const session = yield* getSession(sessionID)
|
||||
return yield* Effect.uninterruptibleMask((restore) =>
|
||||
Effect.gen(function* () {
|
||||
const compacted = yield* restore(
|
||||
Effect.gen(function* () {
|
||||
return yield* compaction.compactManual({
|
||||
session,
|
||||
messages: yield* store.context(sessionID),
|
||||
})
|
||||
}),
|
||||
).pipe(Effect.exit)
|
||||
if (Exit.isSuccess(compacted) && compacted.value) return true
|
||||
yield* events.publish(SessionEvent.Compaction.Failed, { sessionID })
|
||||
if (Exit.isFailure(compacted)) return yield* Effect.failCause(compacted.cause)
|
||||
return true
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
// Execution lifecycle is published per busy period by SessionExecution, not per drain here.
|
||||
const drain = Effect.fn("SessionRunner.drain")(function* (input: {
|
||||
readonly sessionID: SessionSchema.ID
|
||||
readonly force: boolean
|
||||
}) {
|
||||
yield* runPendingCompaction(input.sessionID)
|
||||
const hasSteer = yield* SessionInput.hasPending(db, input.sessionID, "steer")
|
||||
const hasQueue = hasSteer ? false : yield* SessionInput.hasPending(db, input.sessionID, "queue")
|
||||
if (!input.force && !hasSteer && !hasQueue) return
|
||||
@@ -559,19 +507,11 @@ const layer = Layer.effect(
|
||||
}
|
||||
needsContinuation = result.needsContinuation
|
||||
step = result.step + 1
|
||||
if (needsContinuation) {
|
||||
promotion = (yield* SessionInput.pendingCompaction(db, input.sessionID)) ? undefined : "steer"
|
||||
continue
|
||||
}
|
||||
yield* runPendingCompaction(input.sessionID)
|
||||
promotion = "steer"
|
||||
needsContinuation = yield* SessionInput.hasPending(db, input.sessionID, "steer")
|
||||
if (!needsContinuation) needsContinuation = yield* SessionInput.hasPending(db, input.sessionID, "steer")
|
||||
}
|
||||
yield* runPendingCompaction(input.sessionID)
|
||||
const hasSteer = yield* SessionInput.hasPending(db, input.sessionID, "steer")
|
||||
const hasQueue = hasSteer ? false : yield* SessionInput.hasPending(db, input.sessionID, "queue")
|
||||
shouldRun = hasSteer || hasQueue
|
||||
promotion = hasSteer ? "steer" : hasQueue ? "queue" : undefined
|
||||
shouldRun = yield* SessionInput.hasPending(db, input.sessionID, "queue")
|
||||
promotion = shouldRun ? "queue" : undefined
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ export const createLLMEventPublisher = (events: EventV2.Interface, input: Input)
|
||||
>()
|
||||
let assistantMessageID = input.assistantMessageID
|
||||
let stepStarted = false
|
||||
let stepFailed = false
|
||||
let assistantFailed = false
|
||||
let providerFailed = false
|
||||
let retryEvidence = false
|
||||
let stepFailure: SessionError.Error | undefined
|
||||
@@ -98,30 +98,28 @@ export const createLLMEventPublisher = (events: EventV2.Interface, input: Input)
|
||||
|
||||
const fragments = (
|
||||
name: string,
|
||||
ended: (id: string, value: string, ordinal: number, state?: Record<string, unknown>) => Effect.Effect<void>,
|
||||
ended: (id: string, value: string, state?: Record<string, unknown>) => Effect.Effect<void>,
|
||||
single = false,
|
||||
) => {
|
||||
const chunks = new Map<string, { readonly ordinal: number; readonly values: string[] }>()
|
||||
let nextOrdinal = 0
|
||||
const chunks = new Map<string, string[]>()
|
||||
const start = (id: string) =>
|
||||
Effect.suspend(() => {
|
||||
if (chunks.has(id)) return Effect.die(new Error(`Duplicate ${name} start: ${id}`))
|
||||
if (single && chunks.size > 0) return Effect.die(new Error(`${name} start before end: ${id}`))
|
||||
const ordinal = nextOrdinal++
|
||||
chunks.set(id, { ordinal, values: [] })
|
||||
return Effect.succeed(ordinal)
|
||||
chunks.set(id, [])
|
||||
return Effect.void
|
||||
})
|
||||
const append = (id: string, value: string) =>
|
||||
Effect.suspend(() => {
|
||||
const current = chunks.get(id)
|
||||
if (!current) return Effect.die(new Error(`${name} delta before start: ${id}`))
|
||||
current.values.push(value)
|
||||
return Effect.succeed(current.ordinal)
|
||||
current.push(value)
|
||||
return Effect.void
|
||||
})
|
||||
const end = Effect.fnUntraced(function* (id: string, state?: Record<string, unknown>) {
|
||||
const current = chunks.get(id)
|
||||
if (!current) return yield* Effect.die(new Error(`${name} end before start: ${id}`))
|
||||
yield* ended(id, current.values.join(""), current.ordinal, state)
|
||||
yield* ended(id, current.join(""), state)
|
||||
chunks.delete(id)
|
||||
})
|
||||
const flush = Effect.fnUntraced(function* () {
|
||||
@@ -132,12 +130,11 @@ export const createLLMEventPublisher = (events: EventV2.Interface, input: Input)
|
||||
|
||||
const text = fragments(
|
||||
"text",
|
||||
(_textID, value, ordinal) =>
|
||||
(_textID, value) =>
|
||||
Effect.gen(function* () {
|
||||
yield* events.publish(SessionEvent.Text.Ended, {
|
||||
sessionID: input.sessionID,
|
||||
assistantMessageID: yield* currentAssistantMessageID(),
|
||||
ordinal,
|
||||
text: value,
|
||||
})
|
||||
}),
|
||||
@@ -145,12 +142,11 @@ export const createLLMEventPublisher = (events: EventV2.Interface, input: Input)
|
||||
)
|
||||
const reasoning = fragments(
|
||||
"reasoning",
|
||||
(_reasoningID, value, ordinal, state) =>
|
||||
(_reasoningID, value, state) =>
|
||||
Effect.gen(function* () {
|
||||
yield* events.publish(SessionEvent.Reasoning.Ended, {
|
||||
sessionID: input.sessionID,
|
||||
assistantMessageID: yield* currentAssistantMessageID(),
|
||||
ordinal,
|
||||
text: value,
|
||||
state,
|
||||
})
|
||||
@@ -210,20 +206,16 @@ export const createLLMEventPublisher = (events: EventV2.Interface, input: Input)
|
||||
yield* flushFragments()
|
||||
})
|
||||
|
||||
const failAssistant = Effect.fnUntraced(function* (error: SessionError.Error, replace = false) {
|
||||
const failAssistant = Effect.fnUntraced(function* (error: SessionError.Error) {
|
||||
if (assistantFailed) return
|
||||
yield* flush()
|
||||
yield* startAssistant()
|
||||
if (replace || stepFailure === undefined) stepFailure = error
|
||||
})
|
||||
|
||||
const publishStepFailure = Effect.fnUntraced(function* () {
|
||||
if (stepFailed || stepFailure === undefined) return
|
||||
const assistantMessageID = yield* startAssistant()
|
||||
stepFailed = true
|
||||
assistantFailed = true
|
||||
stepFailure = error
|
||||
yield* events.publish(SessionEvent.Step.Failed, {
|
||||
sessionID: input.sessionID,
|
||||
assistantMessageID,
|
||||
error: stepFailure,
|
||||
error,
|
||||
})
|
||||
})
|
||||
|
||||
@@ -231,11 +223,9 @@ export const createLLMEventPublisher = (events: EventV2.Interface, input: Input)
|
||||
error: SessionError.Error,
|
||||
hostedOnly = false,
|
||||
) {
|
||||
let failed = false
|
||||
for (const [callID, tool] of tools) {
|
||||
if (tool.settled || (hostedOnly && !tool.providerExecuted)) continue
|
||||
tool.settled = true
|
||||
failed = true
|
||||
yield* events.publish(SessionEvent.Tool.Failed, {
|
||||
sessionID: input.sessionID,
|
||||
assistantMessageID: tool.assistantMessageID,
|
||||
@@ -244,7 +234,6 @@ export const createLLMEventPublisher = (events: EventV2.Interface, input: Input)
|
||||
executed: tool.providerExecuted,
|
||||
})
|
||||
}
|
||||
return failed
|
||||
})
|
||||
|
||||
const assistantMessageIDForTool = (callID: string) => {
|
||||
@@ -263,19 +252,17 @@ export const createLLMEventPublisher = (events: EventV2.Interface, input: Input)
|
||||
return
|
||||
case "text-start":
|
||||
retryEvidence = true
|
||||
const startedTextOrdinal = yield* text.start(event.id)
|
||||
yield* text.start(event.id)
|
||||
yield* events.publish(SessionEvent.Text.Started, {
|
||||
sessionID: input.sessionID,
|
||||
assistantMessageID: yield* startAssistant(),
|
||||
ordinal: startedTextOrdinal,
|
||||
})
|
||||
return
|
||||
case "text-delta":
|
||||
const deltaTextOrdinal = yield* text.append(event.id, event.text)
|
||||
yield* text.append(event.id, event.text)
|
||||
yield* events.publish(SessionEvent.Text.Delta, {
|
||||
sessionID: input.sessionID,
|
||||
assistantMessageID: yield* currentAssistantMessageID(),
|
||||
ordinal: deltaTextOrdinal,
|
||||
delta: event.text,
|
||||
})
|
||||
return
|
||||
@@ -284,20 +271,18 @@ export const createLLMEventPublisher = (events: EventV2.Interface, input: Input)
|
||||
return
|
||||
case "reasoning-start":
|
||||
retryEvidence = true
|
||||
const startedReasoningOrdinal = yield* reasoning.start(event.id)
|
||||
yield* reasoning.start(event.id)
|
||||
yield* events.publish(SessionEvent.Reasoning.Started, {
|
||||
sessionID: input.sessionID,
|
||||
assistantMessageID: yield* startAssistant(),
|
||||
ordinal: startedReasoningOrdinal,
|
||||
state: providerState(event.providerMetadata),
|
||||
})
|
||||
return
|
||||
case "reasoning-delta":
|
||||
const deltaReasoningOrdinal = yield* reasoning.append(event.id, event.text)
|
||||
yield* reasoning.append(event.id, event.text)
|
||||
yield* events.publish(SessionEvent.Reasoning.Delta, {
|
||||
sessionID: input.sessionID,
|
||||
assistantMessageID: yield* currentAssistantMessageID(),
|
||||
ordinal: deltaReasoningOrdinal,
|
||||
delta: event.text,
|
||||
})
|
||||
return
|
||||
@@ -399,7 +384,7 @@ export const createLLMEventPublisher = (events: EventV2.Interface, input: Input)
|
||||
callID: event.id,
|
||||
error:
|
||||
event.message === `Unknown tool: ${event.name}`
|
||||
? { type: "tool.unknown", message: event.message }
|
||||
? { type: "tool.unknown", message: event.message, name: event.name }
|
||||
: { type: "tool.execution", message: event.message },
|
||||
executed: tool.providerExecuted,
|
||||
resultState: providerState(event.providerMetadata),
|
||||
@@ -411,7 +396,7 @@ export const createLLMEventPublisher = (events: EventV2.Interface, input: Input)
|
||||
if (stepSettlement) return yield* Effect.die(new Error("Duplicate step finish"))
|
||||
if (event.reason === "content-filter") {
|
||||
providerFailed = true
|
||||
yield* failAssistant({ type: "provider.content-filter", message: "Provider blocked the response" }, true)
|
||||
yield* failAssistant({ type: "provider.content-filter", message: "Provider blocked the response" })
|
||||
return
|
||||
}
|
||||
stepSettlement = { finish: event.reason, tokens: tokens(event.usage) }
|
||||
@@ -420,7 +405,7 @@ export const createLLMEventPublisher = (events: EventV2.Interface, input: Input)
|
||||
return
|
||||
case "provider-error":
|
||||
providerFailed = true
|
||||
yield* failAssistant({ type: "provider.unknown", message: event.message }, true)
|
||||
yield* failAssistant({ type: "provider.unknown", message: event.message })
|
||||
return
|
||||
}
|
||||
})
|
||||
@@ -429,7 +414,6 @@ export const createLLMEventPublisher = (events: EventV2.Interface, input: Input)
|
||||
publish,
|
||||
flush,
|
||||
failAssistant,
|
||||
publishStepFailure,
|
||||
failUnsettledTools,
|
||||
hasProviderError: () => providerFailed,
|
||||
hasRetryEvidence: () => retryEvidence,
|
||||
|
||||
@@ -161,7 +161,6 @@ function toLLMMessage(message: SessionMessage.Message, model: Model): Message[]
|
||||
case "assistant":
|
||||
return assistant(message, model)
|
||||
case "compaction":
|
||||
if (message.status !== "completed") return []
|
||||
return [
|
||||
Message.make({
|
||||
id: message.id,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { sqliteTable, text, integer, index, primaryKey, real, uniqueIndex } from "drizzle-orm/sqlite-core"
|
||||
import { sql } from "drizzle-orm"
|
||||
import { directoryColumn, pathColumn } from "../database/path"
|
||||
import { ProjectTable } from "../project/sql"
|
||||
import type { SessionMessage } from "./message"
|
||||
@@ -147,9 +146,8 @@ export const SessionInputTable = sqliteTable(
|
||||
.$type<SessionSchema.ID>()
|
||||
.notNull()
|
||||
.references(() => SessionTable.id, { onDelete: "cascade" }),
|
||||
type: text().$type<SessionInput.Entry["type"]>().notNull(),
|
||||
prompt: text({ mode: "json" }).$type<Prompt>(),
|
||||
delivery: text().$type<SessionInput.Delivery>(),
|
||||
prompt: text({ mode: "json" }).notNull().$type<Prompt>(),
|
||||
delivery: text().$type<SessionInput.Delivery>().notNull(),
|
||||
admitted_seq: integer().notNull(),
|
||||
promoted_seq: integer(),
|
||||
time_created: integer()
|
||||
@@ -157,16 +155,12 @@ export const SessionInputTable = sqliteTable(
|
||||
.$default(() => Date.now()),
|
||||
},
|
||||
(table) => [
|
||||
index("session_input_session_pending_type_delivery_seq_idx").on(
|
||||
index("session_input_session_pending_delivery_seq_idx").on(
|
||||
table.session_id,
|
||||
table.promoted_seq,
|
||||
table.type,
|
||||
table.delivery,
|
||||
table.admitted_seq,
|
||||
),
|
||||
uniqueIndex("session_input_session_pending_compaction_idx")
|
||||
.on(table.session_id)
|
||||
.where(sql`${table.type} = 'compaction' and ${table.promoted_seq} is null`),
|
||||
uniqueIndex("session_input_session_admitted_seq_idx").on(table.session_id, table.admitted_seq),
|
||||
uniqueIndex("session_input_session_promoted_seq_idx").on(table.session_id, table.promoted_seq),
|
||||
],
|
||||
|
||||
@@ -11,7 +11,11 @@ export function toSessionError(cause: unknown): SessionError.Error {
|
||||
if (cause instanceof LLMError) {
|
||||
switch (cause.reason._tag) {
|
||||
case "RateLimit":
|
||||
return { type: "provider.rate-limit", message: cause.reason.message }
|
||||
return {
|
||||
type: "provider.rate-limit",
|
||||
message: cause.reason.message,
|
||||
retryAfterMs: cause.reason.retryAfterMs,
|
||||
}
|
||||
case "Authentication":
|
||||
return { type: "provider.auth", message: cause.reason.message }
|
||||
case "QuotaExceeded":
|
||||
@@ -37,12 +41,17 @@ export function toSessionError(cause: unknown): SessionError.Error {
|
||||
}
|
||||
}
|
||||
if (cause instanceof PermissionV2.DeniedError || cause instanceof PermissionV2.RejectedError)
|
||||
return { type: "permission.rejected", message: cause.message }
|
||||
if (cause instanceof QuestionV2.RejectedError) return { type: "aborted", message: cause.message }
|
||||
return {
|
||||
type: "permission.rejected",
|
||||
message: cause.message,
|
||||
permission: cause.permission,
|
||||
resources: [...cause.resources],
|
||||
}
|
||||
if (cause instanceof QuestionV2.RejectedError) return { type: "aborted", message: cause.message, reason: "user" }
|
||||
if (cause instanceof ToolFailure)
|
||||
return cause.error === undefined ? { type: "tool.execution", message: cause.message } : toSessionError(cause.error)
|
||||
if (cause instanceof StepFailedError) return cause.error
|
||||
if (cause instanceof UserInterruptedError) return { type: "aborted", message: cause.message }
|
||||
if (cause instanceof UserInterruptedError) return { type: "aborted", message: cause.message, reason: "user" }
|
||||
if (
|
||||
cause instanceof SessionRunnerModel.ModelNotSelectedError ||
|
||||
cause instanceof SessionRunnerModel.ModelUnavailableError ||
|
||||
|
||||
@@ -5,7 +5,6 @@ import type { PluginContext } from "@opencode-ai/plugin/v2/effect"
|
||||
import { Effect, Schema } from "effect"
|
||||
import path from "path"
|
||||
import { FileSystem } from "../filesystem"
|
||||
import { FSUtil } from "../fs-util"
|
||||
import { Location } from "../location"
|
||||
import { Ripgrep } from "../ripgrep"
|
||||
import { RelativePath } from "../schema"
|
||||
@@ -37,7 +36,6 @@ export const toModelOutput = (output: ModelOutput) => {
|
||||
export const Plugin = {
|
||||
id: "core-glob-tool",
|
||||
effect: Effect.fn("GlobTool.Plugin")(function* (ctx: PluginContext) {
|
||||
const fs = yield* FSUtil.Service
|
||||
const ripgrep = yield* Ripgrep.Service
|
||||
const location = yield* Location.Service
|
||||
const permission = yield* PermissionV2.Service
|
||||
@@ -73,13 +71,6 @@ export const Plugin = {
|
||||
source: { type: "tool", messageID: context.assistantMessageID, callID: context.toolCallID },
|
||||
})
|
||||
const cwd = path.resolve(location.directory, input.path ?? ".")
|
||||
yield* fs
|
||||
.stat(cwd)
|
||||
.pipe(
|
||||
Effect.catchReason("PlatformError", "NotFound", () =>
|
||||
Effect.fail(new ToolFailure({ message: `Search path does not exist: ${input.path ?? "."}` })),
|
||||
),
|
||||
)
|
||||
return yield* ripgrep
|
||||
.glob({
|
||||
cwd,
|
||||
@@ -97,10 +88,8 @@ export const Plugin = {
|
||||
),
|
||||
)
|
||||
}).pipe(
|
||||
Effect.mapError((error) =>
|
||||
error instanceof ToolFailure
|
||||
? error
|
||||
: new ToolFailure({ message: `Unable to find files matching ${input.pattern}`, error }),
|
||||
Effect.mapError(
|
||||
(error) => new ToolFailure({ message: `Unable to find files matching ${input.pattern}`, error }),
|
||||
),
|
||||
),
|
||||
}),
|
||||
|
||||
@@ -91,13 +91,7 @@ export const Plugin = {
|
||||
source: { type: "tool", messageID: context.assistantMessageID, callID: context.toolCallID },
|
||||
})
|
||||
const target = path.resolve(location.directory, input.path ?? ".")
|
||||
const info = yield* fs
|
||||
.stat(target)
|
||||
.pipe(
|
||||
Effect.catchReason("PlatformError", "NotFound", () =>
|
||||
Effect.fail(new ToolFailure({ message: `Search path does not exist: ${input.path ?? "."}` })),
|
||||
),
|
||||
)
|
||||
const info = yield* fs.stat(target).pipe(Effect.catch(() => Effect.succeed(undefined)))
|
||||
return yield* ripgrep
|
||||
.grep({
|
||||
cwd: info?.type === "Directory" ? target : path.dirname(target),
|
||||
@@ -128,11 +122,7 @@ export const Plugin = {
|
||||
),
|
||||
)
|
||||
}).pipe(
|
||||
Effect.mapError((error) =>
|
||||
error instanceof ToolFailure
|
||||
? error
|
||||
: new ToolFailure({ message: `Unable to grep for ${input.pattern}`, error }),
|
||||
),
|
||||
Effect.mapError((error) => new ToolFailure({ message: `Unable to grep for ${input.pattern}`, error })),
|
||||
),
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -64,13 +64,13 @@ const registryLayer = Layer.effect(
|
||||
value: advertised ? `Stale tool call: ${input.call.name}` : `Unknown tool: ${input.call.name}`,
|
||||
},
|
||||
error: advertised
|
||||
? ({ type: "tool.stale", message: `Stale tool call: ${input.call.name}` } as const)
|
||||
: ({ type: "tool.unknown", message: `Unknown tool: ${input.call.name}` } as const),
|
||||
? ({ type: "tool.stale", message: `Stale tool call: ${input.call.name}`, name: input.call.name } as const)
|
||||
: ({ type: "tool.unknown", message: `Unknown tool: ${input.call.name}`, name: input.call.name } as const),
|
||||
}
|
||||
if (advertised && registration.identity !== advertised)
|
||||
return {
|
||||
result: { type: "error" as const, value: `Stale tool call: ${input.call.name}` },
|
||||
error: { type: "tool.stale" as const, message: `Stale tool call: ${input.call.name}` },
|
||||
error: { type: "tool.stale" as const, message: `Stale tool call: ${input.call.name}`, name: input.call.name },
|
||||
}
|
||||
// Hooks fire only for hosted/local tools; provider-executed calls never reach settleWith.
|
||||
const beforeEvent: ToolHooks.BeforeEvent = {
|
||||
@@ -180,7 +180,7 @@ const registryLayer = Layer.effect(
|
||||
if (registration) return settleWith(input, registration.identity)
|
||||
return Effect.succeed({
|
||||
result: { type: "error", value: `Unknown tool: ${input.call.name}` },
|
||||
error: { type: "tool.unknown", message: `Unknown tool: ${input.call.name}` },
|
||||
error: { type: "tool.unknown", message: `Unknown tool: ${input.call.name}`, name: input.call.name },
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
@@ -18,9 +18,7 @@ export const DEFAULT_TIMEOUT_MS = 2 * 60 * 1_000
|
||||
export const MAX_TIMEOUT_MS = 10 * 60 * 1_000
|
||||
export const MAX_CAPTURE_BYTES = 1024 * 1024
|
||||
|
||||
const BACKGROUND_STARTED = "The command was moved to the background."
|
||||
const BACKGROUND_INSTRUCTION =
|
||||
"You will be notified automatically when the command finishes. DO NOT sleep, poll, or proactively check on its progress."
|
||||
const BACKGROUND_STARTED = "The command has not completed; it is now running in the background."
|
||||
|
||||
export const Input = Schema.Struct({
|
||||
command: Schema.String.annotate({ description: "Shell command string to execute" }),
|
||||
@@ -55,11 +53,10 @@ const Output = Schema.Struct({
|
||||
type Output = typeof Output.Type
|
||||
|
||||
const modelOutput = (output: Output): string | undefined => {
|
||||
if (output.status === "running") return undefined
|
||||
const warnings = output.warnings?.length
|
||||
? `\n\nWarnings:\n${output.warnings.map((warning) => `- ${warning}`).join("\n")}`
|
||||
: ""
|
||||
if (output.status === "running")
|
||||
return `${warnings.trimStart()}${warnings ? "\n\n" : ""}${BACKGROUND_INSTRUCTION}`
|
||||
if (output.timeout) return `${warnings.trimStart()}${warnings ? "\n\n" : ""}Command timed out before completion.`
|
||||
return `${warnings.trimStart()}${warnings ? "\n\n" : ""}Command exited with code ${output.exit}.`
|
||||
}
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
import fs from "fs/promises"
|
||||
import path from "path"
|
||||
import { describe, expect } from "bun:test"
|
||||
import { Config as ConfigSchema } from "@opencode-ai/schema/config"
|
||||
import { Effect, Schema } from "effect"
|
||||
import { AgentV2 } from "@opencode-ai/core/agent"
|
||||
import { Config } from "@opencode-ai/core/config"
|
||||
import { ConfigExternalPlugin } from "@opencode-ai/core/config/plugin/external"
|
||||
import { EventV2 } from "@opencode-ai/core/event"
|
||||
import { FSUtil } from "@opencode-ai/core/fs-util"
|
||||
import { Location } from "@opencode-ai/core/location"
|
||||
import { Npm } from "@opencode-ai/core/npm"
|
||||
import { PluginV2 } from "@opencode-ai/core/plugin"
|
||||
import { PluginHost } from "@opencode-ai/core/plugin/host"
|
||||
import { AbsolutePath } from "@opencode-ai/core/schema"
|
||||
import { tmpdir } from "../fixture/tmpdir"
|
||||
import { testEffect } from "../lib/effect"
|
||||
import { PluginTestLayer } from "../plugin/fixture"
|
||||
|
||||
@@ -240,6 +244,49 @@ describe("ConfigExternalPlugin", () => {
|
||||
})
|
||||
}),
|
||||
)
|
||||
|
||||
it.live("reloads changed plugin source from the same entrypoint", () =>
|
||||
Effect.acquireRelease(
|
||||
Effect.promise(() => tmpdir()),
|
||||
(tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]()),
|
||||
).pipe(
|
||||
Effect.flatMap((tmp) =>
|
||||
Effect.gen(function* () {
|
||||
const plugins = yield* PluginV2.Service
|
||||
const agents = yield* AgentV2.Service
|
||||
const events = yield* EventV2.Service
|
||||
const fsUtil = yield* FSUtil.Service
|
||||
const location = yield* Location.Service
|
||||
const npm = yield* Npm.Service
|
||||
const host = yield* PluginHost.make(plugins)
|
||||
const plugin = path.join(tmp.path, "plugin.ts")
|
||||
const config = Config.Service.of({
|
||||
entries: () =>
|
||||
Effect.succeed([
|
||||
new Config.Document({
|
||||
type: "document",
|
||||
info: decode({ plugins: [plugin] }),
|
||||
}),
|
||||
]),
|
||||
})
|
||||
|
||||
yield* Effect.promise(() => fs.writeFile(plugin, pluginSource("First source")))
|
||||
yield* ConfigExternalPlugin.Plugin.effect(host).pipe(
|
||||
Effect.provideService(PluginV2.Service, plugins),
|
||||
Effect.provideService(FSUtil.Service, fsUtil),
|
||||
Effect.provideService(Location.Service, location),
|
||||
Effect.provideService(Npm.Service, npm),
|
||||
Effect.provideService(Config.Service, config),
|
||||
)
|
||||
expect((yield* waitForAgent(agents, "hot-reload"))?.description).toBe("First source")
|
||||
|
||||
yield* Effect.promise(() => fs.writeFile(plugin, pluginSource("Second source")))
|
||||
yield* events.publish(ConfigSchema.Event.Updated, {})
|
||||
expect(yield* waitForAgentDescription(agents, "hot-reload", "Second source")).toBe(true)
|
||||
}),
|
||||
),
|
||||
),
|
||||
)
|
||||
})
|
||||
|
||||
const waitForAgent = Effect.fnUntraced(function* (agents: AgentV2.Interface, id: string) {
|
||||
@@ -250,3 +297,29 @@ const waitForAgent = Effect.fnUntraced(function* (agents: AgentV2.Interface, id:
|
||||
}
|
||||
return yield* Effect.die(`Timed out waiting for agent ${id}`)
|
||||
})
|
||||
|
||||
const waitForAgentDescription = Effect.fnUntraced(function* (
|
||||
agents: AgentV2.Interface,
|
||||
id: string,
|
||||
description: string,
|
||||
) {
|
||||
for (let attempt = 0; attempt < 100; attempt++) {
|
||||
if ((yield* agents.get(AgentV2.ID.make(id)))?.description === description) return true
|
||||
yield* Effect.sleep("10 millis")
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
function pluginSource(description: string) {
|
||||
return `export default {
|
||||
id: "source-hot-reload",
|
||||
setup: async (ctx) => {
|
||||
await ctx.agent.transform((agents) => {
|
||||
agents.update("hot-reload", (agent) => {
|
||||
agent.description = ${JSON.stringify(description)}
|
||||
agent.mode = "subagent"
|
||||
})
|
||||
})
|
||||
},
|
||||
}`
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ const decode = Schema.decodeUnknownSync(Config.Info)
|
||||
const document = path.join(import.meta.dir, "opencode.json")
|
||||
|
||||
describe("config plugin reloads", () => {
|
||||
it.live("reloads config-backed domains without reloading external plugins", () =>
|
||||
it.live("reloads every config-backed domain", () =>
|
||||
Effect.gen(function* () {
|
||||
const agents = yield* AgentV2.Service
|
||||
const catalog = yield* Catalog.Service
|
||||
@@ -69,7 +69,8 @@ describe("config plugin reloads", () => {
|
||||
(yield* commands.get("second"))?.description === "Second command" &&
|
||||
(yield* references.list()).some((reference) => reference.name === "second") &&
|
||||
(yield* catalog.provider.get(ProviderV2.ID.make("first"))) === undefined &&
|
||||
(yield* catalog.provider.get(ProviderV2.ID.make("second"))) !== undefined
|
||||
(yield* catalog.provider.get(ProviderV2.ID.make("second"))) !== undefined &&
|
||||
(yield* agents.get(AgentV2.ID.make("configured")))?.description === "Second plugin"
|
||||
)
|
||||
}),
|
||||
)
|
||||
@@ -80,7 +81,10 @@ describe("config plugin reloads", () => {
|
||||
expect(
|
||||
(yield* skills.sources()).some((source) => source.type === "directory" && source.path === "/skills/second"),
|
||||
).toBe(true)
|
||||
expect((yield* agents.get(AgentV2.ID.make("configured")))?.description).toBe("First plugin")
|
||||
|
||||
entries = [config("second")]
|
||||
yield* events.publish(ConfigSchema.Event.Updated, {})
|
||||
yield* waitUntil(agents.get(AgentV2.ID.make("configured")).pipe(Effect.map((agent) => agent === undefined)))
|
||||
}).pipe(Effect.provideService(Global.Service, Global.Service.of(Global.make()))),
|
||||
)
|
||||
})
|
||||
|
||||
@@ -15,8 +15,7 @@ import eventSourcedSessionInputMigration from "@opencode-ai/core/database/migrat
|
||||
import contextEpochAgentMigration from "@opencode-ai/core/database/migration/20260605042240_add_context_epoch_agent"
|
||||
import simplifyIntegrationCredentialsMigration from "@opencode-ai/core/database/migration/20260611192811_lush_chimera"
|
||||
import simplifySessionInputMigration from "@opencode-ai/core/database/migration/20260622202450_simplify_session_input"
|
||||
import resetSessionEventsMigration from "@opencode-ai/core/database/migration/20260703200000_reset_v2_session_events"
|
||||
import durableSessionInboxMigration from "@opencode-ai/core/database/migration/20260704161518_durable_session_inbox"
|
||||
import resetExecutionErrorsMigration from "@opencode-ai/core/database/migration/20260703210000_reset_v2_execution_errors"
|
||||
import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
|
||||
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
||||
import { EventV2 } from "@opencode-ai/core/event"
|
||||
@@ -40,7 +39,7 @@ const run = <A, E>(effect: Effect.Effect<A, E, SqlClientService>) =>
|
||||
const makeDb = EffectDrizzleSqlite.makeWithDefaults()
|
||||
|
||||
describe("DatabaseMigration", () => {
|
||||
test("resets incompatible V2 Session event history", async () => {
|
||||
test("resets incompatible V2 execution and error history", async () => {
|
||||
await run(
|
||||
Effect.gen(function* () {
|
||||
const db = yield* makeDb
|
||||
@@ -53,7 +52,7 @@ describe("DatabaseMigration", () => {
|
||||
yield* db.run(sql`INSERT INTO event (id) VALUES ('event')`)
|
||||
yield* db.run(sql`INSERT INTO event_sequence (aggregate_id, seq) VALUES ('session', 1)`)
|
||||
|
||||
yield* DatabaseMigration.applyOnly(db, [resetSessionEventsMigration])
|
||||
yield* DatabaseMigration.applyOnly(db, [resetExecutionErrorsMigration])
|
||||
|
||||
expect(yield* db.get(sql`SELECT id FROM session_input`)).toBeUndefined()
|
||||
expect(yield* db.get(sql`SELECT id FROM session_message`)).toBeUndefined()
|
||||
@@ -108,14 +107,13 @@ describe("DatabaseMigration", () => {
|
||||
expect(yield* db.get(sql`SELECT count(*) as count FROM migration`)).toEqual({ count: migrations.length })
|
||||
expect(
|
||||
yield* db.all(
|
||||
sql`SELECT name FROM sqlite_master WHERE type = 'index' AND name IN ('event_aggregate_seq_idx', 'event_aggregate_type_seq_idx', 'session_input_session_pending_seq_idx', 'session_input_session_pending_delivery_seq_idx', 'session_input_session_pending_type_delivery_seq_idx', 'session_input_session_pending_compaction_idx', 'session_input_session_admitted_seq_idx', 'session_input_session_promoted_seq_idx', 'session_message_session_idx', 'session_message_session_type_idx', 'session_message_session_seq_idx', 'session_message_session_type_seq_idx', 'session_message_session_time_created_id_idx') ORDER BY name`,
|
||||
sql`SELECT name FROM sqlite_master WHERE type = 'index' AND name IN ('event_aggregate_seq_idx', 'event_aggregate_type_seq_idx', 'session_input_session_pending_seq_idx', 'session_input_session_pending_delivery_seq_idx', 'session_input_session_admitted_seq_idx', 'session_input_session_promoted_seq_idx', 'session_message_session_idx', 'session_message_session_type_idx', 'session_message_session_seq_idx', 'session_message_session_type_seq_idx', 'session_message_session_time_created_id_idx') ORDER BY name`,
|
||||
),
|
||||
).toEqual([
|
||||
{ name: "event_aggregate_seq_idx" },
|
||||
{ name: "event_aggregate_type_seq_idx" },
|
||||
{ name: "session_input_session_admitted_seq_idx" },
|
||||
{ name: "session_input_session_pending_compaction_idx" },
|
||||
{ name: "session_input_session_pending_type_delivery_seq_idx" },
|
||||
{ name: "session_input_session_pending_delivery_seq_idx" },
|
||||
{ name: "session_input_session_promoted_seq_idx" },
|
||||
{ name: "session_message_session_seq_idx" },
|
||||
{ name: "session_message_session_time_created_id_idx" },
|
||||
@@ -284,7 +282,7 @@ describe("DatabaseMigration", () => {
|
||||
sql`INSERT INTO event (id, aggregate_id, seq, type, data, created) VALUES ('event', 'session', 9, 'session.updated.1', '{}', 1)`,
|
||||
)
|
||||
yield* db.run(
|
||||
sql`INSERT INTO session_input (id, session_id, type, prompt, delivery, admitted_seq, time_created) VALUES ('input', 'session', 'prompt', '{}', 'steer', 9, 1)`,
|
||||
sql`INSERT INTO session_input (id, session_id, prompt, delivery, admitted_seq, time_created) VALUES ('input', 'session', '{}', 'steer', 9, 1)`,
|
||||
)
|
||||
yield* db.run(
|
||||
sql`INSERT INTO session_message (id, session_id, type, seq, time_created, time_updated, data) VALUES ('projected', 'session', 'user', 9, 1, 1, '{}')`,
|
||||
@@ -345,37 +343,6 @@ describe("DatabaseMigration", () => {
|
||||
)
|
||||
})
|
||||
|
||||
test("preserves admitted prompts while generalizing the durable inbox", async () => {
|
||||
await run(
|
||||
Effect.gen(function* () {
|
||||
const db = yield* makeDb
|
||||
yield* db.run(
|
||||
sql`CREATE TABLE session_input (id text PRIMARY KEY, session_id text NOT NULL, prompt text NOT NULL, delivery text NOT NULL, admitted_seq integer NOT NULL, promoted_seq integer, time_created integer NOT NULL)`,
|
||||
)
|
||||
yield* db.run(
|
||||
sql`INSERT INTO session_input (id, session_id, prompt, delivery, admitted_seq, promoted_seq, time_created) VALUES ('input', 'session', '{"text":"hello"}', 'steer', 4, NULL, 1)`,
|
||||
)
|
||||
|
||||
yield* DatabaseMigration.applyOnly(db, [durableSessionInboxMigration])
|
||||
|
||||
expect(
|
||||
yield* db.all(
|
||||
sql`SELECT id, type, prompt, delivery, admitted_seq, promoted_seq FROM session_input ORDER BY admitted_seq`,
|
||||
),
|
||||
).toEqual([
|
||||
{
|
||||
id: "input",
|
||||
type: "prompt",
|
||||
prompt: '{"text":"hello"}',
|
||||
delivery: "steer",
|
||||
admitted_seq: 4,
|
||||
promoted_seq: null,
|
||||
},
|
||||
])
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
test("resets incompatible projected Session messages before adding sequence order", async () => {
|
||||
await run(
|
||||
Effect.gen(function* () {
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import { expect, test } from "bun:test"
|
||||
import { Ignore } from "@opencode-ai/core/filesystem/ignore"
|
||||
// @ts-ignore
|
||||
import { createWrapper } from "@parcel/watcher/wrapper"
|
||||
|
||||
test("match nested and non-nested", () => {
|
||||
expect(Ignore.match("node_modules/index.js")).toBe(true)
|
||||
@@ -10,30 +8,3 @@ test("match nested and non-nested", () => {
|
||||
expect(Ignore.match("node_modules/bar")).toBe(true)
|
||||
expect(Ignore.match("node_modules/bar/")).toBe(true)
|
||||
})
|
||||
|
||||
test("parcel patterns ignore built-in folders at any depth", async () => {
|
||||
let ignoreGlobs: string[] = []
|
||||
const watcher = createWrapper({
|
||||
subscribe: async (
|
||||
_directory: string,
|
||||
_callback: (...args: unknown[]) => unknown,
|
||||
options: { ignoreGlobs?: string[] },
|
||||
) => {
|
||||
ignoreGlobs = options.ignoreGlobs ?? []
|
||||
},
|
||||
})
|
||||
await watcher.subscribe("/tmp/project", () => {}, { ignore: Ignore.PATTERNS })
|
||||
const patterns = ignoreGlobs.map((source) => new RegExp(source))
|
||||
|
||||
for (const path of [
|
||||
"nested/node_modules",
|
||||
"nested/node_modules/package/index.js",
|
||||
"nested/.git",
|
||||
"nested/.git/HEAD",
|
||||
"nested/dist",
|
||||
"nested/dist/index.js",
|
||||
]) {
|
||||
expect(patterns.some((pattern) => pattern.test(path))).toBe(true)
|
||||
}
|
||||
expect(patterns.some((pattern) => pattern.test("nested/src/index.ts"))).toBe(false)
|
||||
})
|
||||
|
||||
@@ -2,7 +2,7 @@ import { $ } from "bun"
|
||||
import { describe, expect } from "bun:test"
|
||||
import fs from "fs/promises"
|
||||
import path from "path"
|
||||
import { Deferred, Duration, Effect, Fiber, Layer, Option, Schedule, Stream } from "effect"
|
||||
import { Deferred, Duration, Effect, Fiber, Layer, Option, Stream } from "effect"
|
||||
import { Config } from "@opencode-ai/core/config"
|
||||
import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
|
||||
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
||||
@@ -149,14 +149,12 @@ describeWatcher("LocationWatcher", () => {
|
||||
const update = yield* watcher
|
||||
.subscribe({ path: target, type: "file" })
|
||||
.pipe(Stream.take(1), Stream.runHead, Effect.forkScoped({ startImmediately: true }))
|
||||
yield* fs.writeFileString(sibling, "sibling")
|
||||
const writes = yield* Effect.suspend(() => fs.writeFileString(target, `target-${Math.random()}`)).pipe(
|
||||
Effect.repeat(Schedule.spaced("10 millis")),
|
||||
Effect.forkScoped,
|
||||
)
|
||||
const event = yield* Fiber.join(update).pipe(Effect.ensuring(Fiber.interrupt(writes)))
|
||||
yield* Effect.yieldNow
|
||||
|
||||
expect(event.valueOrUndefined?.path).toBe(target)
|
||||
yield* fs.writeFileString(sibling, "sibling")
|
||||
yield* fs.writeFileString(target, "target")
|
||||
|
||||
expect((yield* Fiber.join(update)).valueOrUndefined?.path).toBe(target)
|
||||
}).pipe(Effect.provide(AppNodeBuilder.build(Watcher.node))),
|
||||
),
|
||||
)
|
||||
@@ -199,24 +197,6 @@ describeWatcher("LocationWatcher", () => {
|
||||
),
|
||||
)
|
||||
|
||||
it.live("ignores dependency, VCS, and build directories at any depth", () =>
|
||||
withTmp((directory) =>
|
||||
Effect.gen(function* () {
|
||||
const afs = yield* FSUtil.Service
|
||||
yield* ready(directory)
|
||||
const roots = ["node_modules", ".git", "dist"].map((name) => path.join(directory, "nested", name))
|
||||
const files = roots.map((root) => path.join(root, "package", "index.js"))
|
||||
yield* noUpdate(
|
||||
(event) => roots.some((root) => event.file === root || event.file.startsWith(`${root}${path.sep}`)),
|
||||
Effect.forEach(files, (file) => afs.writeWithDirs(file, "ignored"), {
|
||||
concurrency: "unbounded",
|
||||
discard: true,
|
||||
}),
|
||||
)
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
||||
it.live("cleanup stops publishing events", () =>
|
||||
Effect.gen(function* () {
|
||||
const events = yield* EventV2.Service
|
||||
|
||||
@@ -74,7 +74,7 @@ const it = testEffect(
|
||||
)
|
||||
|
||||
describe("SessionV2.compact", () => {
|
||||
it.effect("durably admits and coalesces manual compaction", () =>
|
||||
it.effect("manually compacts the active session context", () =>
|
||||
Effect.gen(function* () {
|
||||
requests = []
|
||||
const session = yield* SessionV2.Service
|
||||
@@ -94,22 +94,13 @@ describe("SessionV2.compact", () => {
|
||||
inputID: messageID,
|
||||
})
|
||||
|
||||
expect(yield* session.compact({ id: messageID, sessionID: created.id }).pipe(Effect.flip)).toMatchObject({
|
||||
_tag: "Session.CompactionConflictError",
|
||||
inputID: messageID,
|
||||
})
|
||||
const first = yield* session.compact({ sessionID: created.id })
|
||||
const second = yield* session.compact({ sessionID: created.id })
|
||||
yield* session.compact({ sessionID: created.id })
|
||||
|
||||
expect(second.id).toBe(first.id)
|
||||
expect(requests).toHaveLength(0)
|
||||
expect((yield* session.context(created.id)).find((message) => message.id === first.id)).toMatchObject({
|
||||
type: "compaction",
|
||||
status: "queued",
|
||||
reason: "manual",
|
||||
summary: "",
|
||||
recent: "",
|
||||
})
|
||||
expect(requests).toHaveLength(1)
|
||||
expect(JSON.stringify(requests[0]?.messages)).toContain("Please compact this session history.")
|
||||
expect(yield* session.context(created.id)).toMatchObject([
|
||||
{ type: "compaction", reason: "manual", summary: "manual session summary", recent: "" },
|
||||
])
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
@@ -68,32 +68,6 @@ test("compaction describes tool media without embedding base64", () => {
|
||||
expect(serialized).not.toContain(base64)
|
||||
})
|
||||
|
||||
test("compaction prompt requires the continuation checkpoint headings in order", () => {
|
||||
const prompt = SessionCompaction.buildPrompt({ context: ["Conversation history"] })
|
||||
expect(prompt.match(/^#{2,3} .+$/gm)).toEqual([
|
||||
"## Continuation Goal",
|
||||
"## Operating Constraints",
|
||||
"## Progress",
|
||||
"### Completed",
|
||||
"### In Flight",
|
||||
"### Blocked",
|
||||
"## Decisions To Preserve",
|
||||
"## Resume From Here",
|
||||
"## Context To Preserve",
|
||||
"## Working Files",
|
||||
])
|
||||
expect(prompt).toContain("single-sentence task summary")
|
||||
expect(prompt).toContain("user constraints, preferences, specs")
|
||||
expect(prompt).toContain("completed work")
|
||||
expect(prompt).toContain("current work")
|
||||
expect(prompt).toContain("blockers")
|
||||
expect(prompt).toContain("decision and why")
|
||||
expect(prompt).toContain("ordered next actions")
|
||||
expect(prompt).toContain("important technical facts, errors, open questions")
|
||||
expect(prompt).toContain("file or directory path: why it matters")
|
||||
expect(prompt).toContain("Keep every section, even when empty.")
|
||||
})
|
||||
|
||||
it.effect("manual compaction summarizes short context instead of no-op", () =>
|
||||
Effect.gen(function* () {
|
||||
requests = []
|
||||
|
||||
@@ -562,9 +562,9 @@ describe("SessionV2.create", () => {
|
||||
yield* session.switchModel({ sessionID: created.id, model })
|
||||
|
||||
expect(yield* session.get(created.id)).toMatchObject({ model })
|
||||
const events = Array.from(yield* logEvents(session, created.id, true).pipe(Stream.take(1), Stream.runCollect))
|
||||
expect(events).toMatchObject([{ type: "session.model.selected" }])
|
||||
expect(events[0]?.data).toEqual({ sessionID: created.id, model })
|
||||
expect(
|
||||
Array.from(yield* logEvents(session, created.id, true).pipe(Stream.take(1), Stream.runCollect)),
|
||||
).toMatchObject([{ type: "session.model.selected", data: { model } }])
|
||||
}),
|
||||
)
|
||||
|
||||
|
||||
@@ -22,10 +22,11 @@ import { SessionRunnerRetry } from "@opencode-ai/core/session/runner/retry"
|
||||
const llm = (reason: LLMError["reason"]) => new LLMError({ module: "test", method: "stream", reason })
|
||||
|
||||
describe("toSessionError", () => {
|
||||
test("maps every LLM reason to the open wire type", () => {
|
||||
test("maps every LLM reason to the closed wire type", () => {
|
||||
expect(toSessionError(llm(new RateLimitReason({ message: "rate", retryAfterMs: 123 })))).toEqual({
|
||||
type: "provider.rate-limit",
|
||||
message: "rate",
|
||||
retryAfterMs: 123,
|
||||
})
|
||||
expect(toSessionError(llm(new AuthenticationReason({ message: "auth", kind: "invalid" }))).type).toBe(
|
||||
"provider.auth",
|
||||
@@ -54,15 +55,19 @@ describe("toSessionError", () => {
|
||||
expect(toSessionError(llm(new UnknownProviderReason({ message: "unknown" }))).type).toBe("provider.unknown")
|
||||
})
|
||||
|
||||
test("preserves the permission rejection type without exposing internal fields", () => {
|
||||
test("preserves structured permission rejection data without inventing resources", () => {
|
||||
const rejected = new PermissionV2.RejectedError({ permission: "external_directory", resources: [] })
|
||||
expect(toSessionError(rejected)).toEqual({
|
||||
type: "permission.rejected",
|
||||
message: "Permission rejected: external_directory",
|
||||
permission: "external_directory",
|
||||
resources: [],
|
||||
})
|
||||
expect(toSessionError(new ToolFailure({ message: rejected.message, error: rejected }))).toEqual({
|
||||
type: "permission.rejected",
|
||||
message: "Permission rejected: external_directory",
|
||||
permission: "external_directory",
|
||||
resources: [],
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@ const sessionsLayer = AppNodeBuilder.build(SessionV2.node, [[SessionExecution.no
|
||||
const sessionID = SessionV2.ID.make("ses_projector_test")
|
||||
const created = DateTime.makeUnsafe(0)
|
||||
const model = { id: ModelV2.ID.make("model"), providerID: ProviderV2.ID.make("provider") }
|
||||
const previousModel = { ...model, variant: ModelV2.VariantID.make("medium") }
|
||||
const encodeMessage = Schema.encodeSync(SessionMessage.Message)
|
||||
|
||||
const assistantRow = (
|
||||
@@ -239,7 +238,6 @@ describe("SessionProjector", () => {
|
||||
directory: "/project",
|
||||
title: "test",
|
||||
version: "test",
|
||||
model: previousModel,
|
||||
})
|
||||
.run()
|
||||
.pipe(Effect.orDie)
|
||||
@@ -339,7 +337,6 @@ describe("SessionProjector", () => {
|
||||
text: "synthetic context",
|
||||
metadata: { source: "projector-test" },
|
||||
})
|
||||
expect(messages.find((message) => message.type === "model-switched")).toMatchObject({ previous: previousModel })
|
||||
expect(messages.find((message) => message.type === "shell")).toMatchObject({
|
||||
shell: { command: "pwd", status: "exited", exit: 0 },
|
||||
output: { output: "/project", truncated: false },
|
||||
@@ -592,7 +589,6 @@ describe("SessionProjector", () => {
|
||||
yield* service.publish(SessionEvent.Text.Started, {
|
||||
sessionID,
|
||||
assistantMessageID: SessionMessage.ID.make("msg_assistant_completed"),
|
||||
ordinal: 0,
|
||||
})
|
||||
|
||||
const rows = yield* db
|
||||
|
||||
@@ -233,9 +233,7 @@ describe("SessionV2.prompt", () => {
|
||||
expect(message.prompt.files).toEqual([
|
||||
{ uri: "data:image/png;base64,aGVsbG8=", name: "image.png", mime: "image/png" },
|
||||
])
|
||||
const stored = yield* admitted(message.id)
|
||||
expect(stored?.type).toBe("prompt")
|
||||
if (stored?.type === "prompt") expect(stored.prompt.files).toEqual(message.prompt.files)
|
||||
expect((yield* admitted(message.id))?.prompt.files).toEqual(message.prompt.files)
|
||||
}),
|
||||
)
|
||||
|
||||
|
||||
@@ -101,9 +101,8 @@ describe("toLLMMessages", () => {
|
||||
}),
|
||||
SessionMessage.Compaction.make({
|
||||
id: id("compaction"),
|
||||
type: "compaction",
|
||||
status: "completed",
|
||||
reason: "auto",
|
||||
type: "compaction",
|
||||
reason: "auto",
|
||||
summary: "Earlier work",
|
||||
recent: "Recent work",
|
||||
time: { created },
|
||||
|
||||
@@ -150,13 +150,11 @@ test("step finish records settlement without publishing step ended", async () =>
|
||||
expect(publisher.stepSettlement()).toMatchObject({ finish: "stop" })
|
||||
})
|
||||
|
||||
test("content-filter finish retains failure evidence until step closeout", async () => {
|
||||
test("content-filter finish fails a contentless step", async () => {
|
||||
const { published, publisher } = capture()
|
||||
await Effect.runPromise(publisher.publish(LLMEvent.stepStart({ index: 0 })))
|
||||
await Effect.runPromise(publisher.publish(LLMEvent.stepFinish({ index: 0, reason: "content-filter" })))
|
||||
|
||||
expect(published.map((event) => event.type)).toEqual(["session.step.started.1"])
|
||||
await Effect.runPromise(publisher.publishStepFailure())
|
||||
expect(published.map((event) => event.type)).toEqual(["session.step.started.1", "session.step.failed.1"])
|
||||
expect(published.at(-1)?.data).toMatchObject({
|
||||
error: { type: "provider.content-filter", message: "Provider blocked the response" },
|
||||
@@ -178,7 +176,6 @@ test("content-filter finish preserves partial streamed text and never ends the s
|
||||
{ discard: true },
|
||||
),
|
||||
)
|
||||
await Effect.runPromise(publisher.publishStepFailure())
|
||||
|
||||
expect(published.some((event) => event.type === "session.step.ended.1")).toBe(false)
|
||||
expect(published.find((event) => event.type === "session.text.ended.1")?.data).toMatchObject({ text: "Partial" })
|
||||
|
||||
@@ -157,10 +157,7 @@ const echo = Layer.effectDiscard(
|
||||
description: "Fail unexpectedly",
|
||||
input: Schema.Struct({}),
|
||||
output: Schema.Struct({}),
|
||||
execute: () =>
|
||||
(toolExecutionGate ? Deferred.await(toolExecutionGate) : Effect.void).pipe(
|
||||
Effect.andThen(Effect.die("unexpected tool defect")),
|
||||
),
|
||||
execute: () => Effect.die("unexpected tool defect"),
|
||||
}),
|
||||
// BigInt output with no model content forces ToolOutputStore.bound onto its
|
||||
// JSON.stringify encode path, which fails with a typed StorageError.
|
||||
@@ -426,34 +423,6 @@ const recordedEventTypes = (id: SessionV2.ID) =>
|
||||
)
|
||||
})
|
||||
|
||||
const recordedStepSettlementEvents = (id: SessionV2.ID, assistantMessageID: SessionMessage.ID) =>
|
||||
Effect.gen(function* () {
|
||||
const { db } = yield* Database.Service
|
||||
const settlementTypes = new Set([
|
||||
"session.step.started.1",
|
||||
"session.tool.called.1",
|
||||
"session.tool.success.1",
|
||||
"session.tool.failed.1",
|
||||
"session.step.ended.1",
|
||||
"session.step.failed.1",
|
||||
])
|
||||
return (yield* db
|
||||
.select({ type: EventTable.type, data: EventTable.data })
|
||||
.from(EventTable)
|
||||
.where(eq(EventTable.aggregate_id, id))
|
||||
.orderBy(asc(EventTable.seq))
|
||||
.all()
|
||||
.pipe(Effect.orDie)).filter(
|
||||
(event) => settlementTypes.has(event.type) && event.data.assistantMessageID === assistantMessageID,
|
||||
)
|
||||
})
|
||||
|
||||
const requireAssistant = (messages: readonly SessionMessage.Message[]) => {
|
||||
const assistant = messages.find((message) => message.type === "assistant")
|
||||
if (!assistant) throw new Error("Assistant message missing")
|
||||
return assistant
|
||||
}
|
||||
|
||||
const replaySessionProjection = (id: SessionV2.ID) =>
|
||||
Effect.gen(function* () {
|
||||
const { db } = yield* Database.Service
|
||||
@@ -1316,97 +1285,6 @@ describe("SessionRunnerLLM", () => {
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("runs one durable compaction barrier before later steer and queued prompts", () =>
|
||||
Effect.gen(function* () {
|
||||
yield* setup
|
||||
requests.length = 0
|
||||
currentModel = recoveryModel
|
||||
const session = yield* SessionV2.Service
|
||||
streamGate = yield* Deferred.make<void>()
|
||||
streamStarted = yield* Deferred.make<void>()
|
||||
responses = [
|
||||
fragmentFixture("text", "text-active", ["Active complete"]).completeEvents,
|
||||
[LLMEvent.textDelta({ id: "summary", text: "durable summary" })],
|
||||
fragmentFixture("text", "text-steer", ["Steer complete"]).completeEvents,
|
||||
fragmentFixture("text", "text-queue", ["Queue complete"]).completeEvents,
|
||||
]
|
||||
yield* session.prompt({ sessionID, prompt: Prompt.make({ text: "Active work" }), resume: false })
|
||||
const active = yield* session.resume(sessionID).pipe(Effect.forkChild)
|
||||
yield* Deferred.await(streamStarted)
|
||||
|
||||
const first = yield* session.compact({ sessionID })
|
||||
const second = yield* session.compact({ sessionID })
|
||||
expect(second.id).toBe(first.id)
|
||||
expect(yield* SessionInput.pendingCompaction((yield* Database.Service).db, sessionID)).toMatchObject({
|
||||
id: first.id,
|
||||
})
|
||||
expect((yield* session.messages({ sessionID })).find((message) => message.id === first.id)).toMatchObject({
|
||||
type: "compaction",
|
||||
status: "queued",
|
||||
})
|
||||
|
||||
yield* session.prompt({ sessionID, prompt: Prompt.make({ text: "Steer after compaction" }), resume: false })
|
||||
yield* session.prompt({
|
||||
sessionID,
|
||||
prompt: Prompt.make({ text: "Queue after compaction" }),
|
||||
delivery: "queue",
|
||||
resume: false,
|
||||
})
|
||||
expect(yield* SessionInput.hasPending((yield* Database.Service).db, sessionID, "steer")).toBe(false)
|
||||
|
||||
yield* Deferred.succeed(streamGate, undefined)
|
||||
yield* Fiber.join(active)
|
||||
|
||||
expect(requests).toHaveLength(4)
|
||||
expect(userTexts(requests[1])[0]).toContain("Create a new anchored summary")
|
||||
expect(userTexts(requests[2])).toContain("Steer after compaction")
|
||||
expect(userTexts(requests[3])).toContain("Queue after compaction")
|
||||
expect(yield* SessionInput.pendingCompaction((yield* Database.Service).db, sessionID)).toBeUndefined()
|
||||
expect((yield* session.messages({ sessionID })).find((message) => message.id === first.id)).toMatchObject({
|
||||
type: "compaction",
|
||||
status: "completed",
|
||||
summary: "durable summary",
|
||||
})
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("releases queued prompts when durable compaction fails", () =>
|
||||
Effect.gen(function* () {
|
||||
yield* setup
|
||||
requests.length = 0
|
||||
currentModel = recoveryModel
|
||||
const session = yield* SessionV2.Service
|
||||
streamGate = yield* Deferred.make<void>()
|
||||
streamStarted = yield* Deferred.make<void>()
|
||||
responses = [
|
||||
fragmentFixture("text", "text-active-failure", ["Active complete"]).completeEvents,
|
||||
[],
|
||||
fragmentFixture("text", "text-after-failure", ["Continued"]).completeEvents,
|
||||
]
|
||||
yield* session.prompt({ sessionID, prompt: Prompt.make({ text: "Active work" }), resume: false })
|
||||
const active = yield* session.resume(sessionID).pipe(Effect.forkChild)
|
||||
yield* Deferred.await(streamStarted)
|
||||
|
||||
const compaction = yield* session.compact({ sessionID })
|
||||
yield* session.prompt({
|
||||
sessionID,
|
||||
prompt: Prompt.make({ text: "Continue after failure" }),
|
||||
delivery: "queue",
|
||||
resume: false,
|
||||
})
|
||||
yield* Deferred.succeed(streamGate, undefined)
|
||||
yield* Fiber.join(active)
|
||||
|
||||
expect(requests).toHaveLength(3)
|
||||
expect(userTexts(requests[2])).toContain("Continue after failure")
|
||||
expect(yield* SessionInput.pendingCompaction((yield* Database.Service).db, sessionID)).toBeUndefined()
|
||||
expect((yield* session.messages({ sessionID })).find((message) => message.id === compaction.id)).toMatchObject({
|
||||
type: "compaction",
|
||||
status: "failed",
|
||||
})
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("automatically compacts into a completed summary and retained recent turn", () =>
|
||||
Effect.gen(function* () {
|
||||
yield* setup
|
||||
@@ -1422,7 +1300,7 @@ describe("SessionRunnerLLM", () => {
|
||||
currentModel = compactModel
|
||||
requests.length = 0
|
||||
responses = [
|
||||
fragmentFixture("text", "text-summary", ["## Continuation Goal\n- Preserve the task"]).completeEvents,
|
||||
fragmentFixture("text", "text-summary", ["## Goal\n- Preserve the task"]).completeEvents,
|
||||
fragmentFixture("text", "text-final", ["Continued"]).completeEvents,
|
||||
]
|
||||
yield* session.prompt({
|
||||
@@ -1433,22 +1311,22 @@ describe("SessionRunnerLLM", () => {
|
||||
yield* session.resume(sessionID)
|
||||
|
||||
expect(requests).toHaveLength(2)
|
||||
expect(userTexts(requests[0])[0]).toContain("## Continuation Goal")
|
||||
expect(userTexts(requests[0])[0]).toContain("## Goal")
|
||||
expect(userTexts(requests[1])).toHaveLength(1)
|
||||
expect(userTexts(requests[1])[0]).toContain("<summary>\n## Continuation Goal\n- Preserve the task\n</summary>")
|
||||
expect(userTexts(requests[1])[0]).toContain("<summary>\n## Goal\n- Preserve the task\n</summary>")
|
||||
expect(userTexts(requests[1])[0]).toContain(`[User]: ${"Recent exact request ".repeat(180)}`)
|
||||
|
||||
const context = yield* (yield* SessionStore.Service).context(sessionID)
|
||||
expect(context.map((message) => message.type)).toEqual(["compaction", "assistant"])
|
||||
expect(context[0]).toMatchObject({
|
||||
type: "compaction",
|
||||
summary: "## Continuation Goal\n- Preserve the task",
|
||||
summary: "## Goal\n- Preserve the task",
|
||||
})
|
||||
|
||||
requests.length = 0
|
||||
executions.length = 0
|
||||
responses = [
|
||||
fragmentFixture("text", "text-summary-2", ["## Continuation Goal\n- Preserve the updated task"]).completeEvents,
|
||||
fragmentFixture("text", "text-summary-2", ["## Goal\n- Preserve the updated task"]).completeEvents,
|
||||
fragmentFixture("text", "text-final-2", ["Continued again"]).completeEvents,
|
||||
]
|
||||
yield* session.prompt({
|
||||
@@ -1460,12 +1338,12 @@ describe("SessionRunnerLLM", () => {
|
||||
|
||||
expect(requests).toHaveLength(2)
|
||||
expect(userTexts(requests[0])[0]).toContain(
|
||||
"<previous-summary>\n## Continuation Goal\n- Preserve the task\n</previous-summary>",
|
||||
"<previous-summary>\n## Goal\n- Preserve the task\n</previous-summary>",
|
||||
)
|
||||
expect(userTexts(requests[0])[0]).toContain("Recent exact request")
|
||||
expect((yield* (yield* SessionStore.Service).context(sessionID))[0]).toMatchObject({
|
||||
type: "compaction",
|
||||
summary: "## Continuation Goal\n- Preserve the updated task",
|
||||
summary: "## Goal\n- Preserve the updated task",
|
||||
})
|
||||
}),
|
||||
)
|
||||
@@ -1478,17 +1356,17 @@ describe("SessionRunnerLLM", () => {
|
||||
LLMEvent.stepStart({ index: 0 }),
|
||||
LLMEvent.providerError({ message: "prompt too long", classification: "context-overflow" }),
|
||||
],
|
||||
fragmentFixture("text", "text-summary", ["## Continuation Goal\n- Recover overflow"]).completeEvents,
|
||||
fragmentFixture("text", "text-summary", ["## Goal\n- Recover overflow"]).completeEvents,
|
||||
fragmentFixture("text", "text-final", ["Recovered"]).completeEvents,
|
||||
]
|
||||
yield* session.prompt({ sessionID, prompt: Prompt.make({ text: "Continue" }), resume: false })
|
||||
yield* session.resume(sessionID)
|
||||
|
||||
expect(requests).toHaveLength(3)
|
||||
expect(userTexts(requests[1])[0]).toContain("## Continuation Goal")
|
||||
expect(userTexts(requests[2])[0]).toContain("<summary>\n## Continuation Goal\n- Recover overflow\n</summary>")
|
||||
expect(userTexts(requests[1])[0]).toContain("## Goal")
|
||||
expect(userTexts(requests[2])[0]).toContain("<summary>\n## Goal\n- Recover overflow\n</summary>")
|
||||
expect(yield* session.context(sessionID)).toMatchObject([
|
||||
{ type: "compaction", summary: "## Continuation Goal\n- Recover overflow" },
|
||||
{ type: "compaction", summary: "## Goal\n- Recover overflow" },
|
||||
{ type: "assistant", finish: "stop" },
|
||||
])
|
||||
yield* replaySessionProjection(sessionID)
|
||||
@@ -1508,7 +1386,7 @@ describe("SessionRunnerLLM", () => {
|
||||
]
|
||||
responses = [
|
||||
overflow(),
|
||||
fragmentFixture("text", "text-summary", ["## Continuation Goal\n- Recover once"]).completeEvents,
|
||||
fragmentFixture("text", "text-summary", ["## Goal\n- Recover once"]).completeEvents,
|
||||
overflow(),
|
||||
]
|
||||
yield* session.prompt({ sessionID, prompt: Prompt.make({ text: "Continue" }), resume: false })
|
||||
@@ -1536,7 +1414,7 @@ describe("SessionRunnerLLM", () => {
|
||||
}),
|
||||
)
|
||||
responses = [
|
||||
fragmentFixture("text", "text-summary", ["## Continuation Goal\n- Recover raw overflow"]).completeEvents,
|
||||
fragmentFixture("text", "text-summary", ["## Goal\n- Recover raw overflow"]).completeEvents,
|
||||
fragmentFixture("text", "text-final", ["Recovered"]).completeEvents,
|
||||
]
|
||||
yield* session.prompt({ sessionID, prompt: Prompt.make({ text: "Continue" }), resume: false })
|
||||
@@ -1544,7 +1422,7 @@ describe("SessionRunnerLLM", () => {
|
||||
|
||||
expect(requests).toHaveLength(3)
|
||||
expect(yield* session.context(sessionID)).toMatchObject([
|
||||
{ type: "compaction", summary: "## Continuation Goal\n- Recover raw overflow" },
|
||||
{ type: "compaction", summary: "## Goal\n- Recover raw overflow" },
|
||||
{ type: "assistant", finish: "stop" },
|
||||
])
|
||||
}),
|
||||
@@ -1575,7 +1453,7 @@ describe("SessionRunnerLLM", () => {
|
||||
const session = yield* setupOverflowRecovery
|
||||
responses = [
|
||||
[LLMEvent.providerError({ message: "prompt too long", classification: "context-overflow" })],
|
||||
fragmentFixture("text", "text-summary", ["## Continuation Goal\n- Interrupted"]).completeEvents,
|
||||
fragmentFixture("text", "text-summary", ["## Goal\n- Interrupted"]).completeEvents,
|
||||
]
|
||||
const firstGate = yield* Deferred.make<void>()
|
||||
const summaryGate = yield* Deferred.make<void>()
|
||||
@@ -1763,8 +1641,7 @@ describe("SessionRunnerLLM", () => {
|
||||
expect(requests[1]?.messages.map((message) => message.role)).toEqual(["user", "assistant", "tool"])
|
||||
expect(authorizations).toMatchObject([{ sessionID, toolCallID: "call-echo" }])
|
||||
expect(executions).toEqual(["hello"])
|
||||
const context = yield* session.context(sessionID)
|
||||
expect(context).toMatchObject([
|
||||
expect(yield* session.context(sessionID)).toMatchObject([
|
||||
{ type: "user", text: "Echo this" },
|
||||
{
|
||||
type: "assistant",
|
||||
@@ -1785,13 +1662,6 @@ describe("SessionRunnerLLM", () => {
|
||||
},
|
||||
{ type: "assistant", finish: "stop", content: [{ type: "text", text: "Done" }] },
|
||||
])
|
||||
const assistant = requireAssistant(context)
|
||||
expect((yield* recordedStepSettlementEvents(sessionID, assistant.id)).map((event) => event.type)).toEqual([
|
||||
"session.step.started.1",
|
||||
"session.tool.called.1",
|
||||
"session.tool.success.1",
|
||||
"session.step.ended.1",
|
||||
])
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -2583,7 +2453,7 @@ describe("SessionRunnerLLM", () => {
|
||||
id: "call-interrupted",
|
||||
state: {
|
||||
status: "error",
|
||||
error: { type: "tool.stale", message: "Tool execution interrupted: echo" },
|
||||
error: { type: "tool.stale", message: "Tool execution interrupted", name: "echo" },
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -2923,8 +2793,7 @@ describe("SessionRunnerLLM", () => {
|
||||
|
||||
expect(requests).toHaveLength(2)
|
||||
expect(requests[1]?.messages.map((message) => message.role)).toEqual(["user", "assistant", "tool"])
|
||||
const context = yield* session.context(sessionID)
|
||||
expect(context).toMatchObject([
|
||||
expect(yield* session.context(sessionID)).toMatchObject([
|
||||
{ type: "user", text: "Call defect" },
|
||||
{
|
||||
type: "assistant",
|
||||
@@ -2941,13 +2810,6 @@ describe("SessionRunnerLLM", () => {
|
||||
},
|
||||
{ type: "assistant", finish: "stop", content: [{ type: "text", text: "Recovered" }] },
|
||||
])
|
||||
const assistant = requireAssistant(context)
|
||||
expect((yield* recordedStepSettlementEvents(sessionID, assistant.id)).map((event) => event.type)).toEqual([
|
||||
"session.step.started.1",
|
||||
"session.tool.called.1",
|
||||
"session.tool.failed.1",
|
||||
"session.step.ended.1",
|
||||
])
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -3037,6 +2899,8 @@ describe("SessionRunnerLLM", () => {
|
||||
error: {
|
||||
type: "permission.rejected",
|
||||
message: "Permission rejected: edit",
|
||||
permission: "edit",
|
||||
resources: ["src/index.ts"],
|
||||
},
|
||||
content: [
|
||||
{
|
||||
@@ -3047,6 +2911,8 @@ describe("SessionRunnerLLM", () => {
|
||||
error: {
|
||||
type: "permission.rejected",
|
||||
message: "Permission rejected: edit",
|
||||
permission: "edit",
|
||||
resources: ["src/index.ts"],
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -3136,8 +3002,7 @@ describe("SessionRunnerLLM", () => {
|
||||
expect(yield* Fiber.join(run).pipe(Effect.flip)).toBe(failure)
|
||||
toolExecutionGate = undefined
|
||||
|
||||
const context = yield* session.context(sessionID)
|
||||
expect(context).toMatchObject([
|
||||
expect(yield* session.context(sessionID)).toMatchObject([
|
||||
{ type: "user", text: "Settle before failing" },
|
||||
{
|
||||
type: "assistant",
|
||||
@@ -3146,13 +3011,6 @@ describe("SessionRunnerLLM", () => {
|
||||
],
|
||||
},
|
||||
])
|
||||
const assistant = requireAssistant(context)
|
||||
expect((yield* recordedStepSettlementEvents(sessionID, assistant.id)).map((event) => event.type)).toEqual([
|
||||
"session.step.started.1",
|
||||
"session.tool.called.1",
|
||||
"session.tool.success.1",
|
||||
"session.step.failed.1",
|
||||
])
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -3178,8 +3036,7 @@ describe("SessionRunnerLLM", () => {
|
||||
|
||||
expect(yield* Fiber.await(run)).toMatchObject({ _tag: "Failure" })
|
||||
yield* session.interrupt(sessionID)
|
||||
const context = yield* session.context(sessionID)
|
||||
expect(context).toMatchObject([
|
||||
expect(yield* session.context(sessionID)).toMatchObject([
|
||||
{ type: "user", text: "Interrupt blocked tool" },
|
||||
{
|
||||
type: "assistant",
|
||||
@@ -3192,13 +3049,6 @@ describe("SessionRunnerLLM", () => {
|
||||
],
|
||||
},
|
||||
])
|
||||
const assistant = requireAssistant(context)
|
||||
expect((yield* recordedStepSettlementEvents(sessionID, assistant.id)).map((event) => event.type)).toEqual([
|
||||
"session.step.started.1",
|
||||
"session.tool.called.1",
|
||||
"session.tool.failed.1",
|
||||
"session.step.failed.1",
|
||||
])
|
||||
|
||||
yield* replaySessionProjection(sessionID)
|
||||
|
||||
@@ -3454,42 +3304,6 @@ describe("SessionRunnerLLM", () => {
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("settles a local tool before one content-filter step failure", () =>
|
||||
Effect.gen(function* () {
|
||||
yield* setup
|
||||
const session = yield* SessionV2.Service
|
||||
yield* session.prompt({ sessionID, prompt: Prompt.make({ text: "Tool before blocked response" }), resume: false })
|
||||
toolExecutionGate = yield* Deferred.make<void>()
|
||||
toolExecutionsStarted = yield* Deferred.make<void>()
|
||||
toolExecutionsReady = 1
|
||||
response = [
|
||||
LLMEvent.stepStart({ index: 0 }),
|
||||
LLMEvent.toolCall({ id: "call-before-content-filter", name: "echo", input: { text: "settled" } }),
|
||||
LLMEvent.stepFinish({ index: 0, reason: "content-filter" }),
|
||||
LLMEvent.finish({ reason: "content-filter" }),
|
||||
]
|
||||
|
||||
const run = yield* session.resume(sessionID).pipe(Effect.forkChild)
|
||||
yield* Deferred.await(toolExecutionsStarted)
|
||||
yield* Deferred.succeed(toolExecutionGate, undefined)
|
||||
expect((yield* Fiber.join(run).pipe(Effect.flip)).message).toBe("Provider blocked the response")
|
||||
toolExecutionGate = undefined
|
||||
toolExecutionsStarted = undefined
|
||||
|
||||
const assistant = requireAssistant(yield* session.context(sessionID))
|
||||
const events = yield* recordedStepSettlementEvents(sessionID, assistant.id)
|
||||
expect(events.map((event) => event.type)).toEqual([
|
||||
"session.step.started.1",
|
||||
"session.tool.called.1",
|
||||
"session.tool.success.1",
|
||||
"session.step.failed.1",
|
||||
])
|
||||
expect(
|
||||
events.filter((event) => event.type.startsWith("session.step.") && event.type !== "session.step.started.1"),
|
||||
).toHaveLength(1)
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("does not recover context overflow after durable assistant output", () =>
|
||||
Effect.gen(function* () {
|
||||
yield* setup
|
||||
@@ -3676,32 +3490,16 @@ describe("SessionRunnerLLM", () => {
|
||||
|
||||
requests.length = 0
|
||||
const executionCount = executions.length
|
||||
toolExecutionGate = yield* Deferred.make<void>()
|
||||
toolExecutionsStarted = yield* Deferred.make<void>()
|
||||
toolExecutionsReady = 1
|
||||
response = [
|
||||
LLMEvent.stepStart({ index: 0 }),
|
||||
LLMEvent.toolCall({ id: "call-before-provider-error", name: "echo", input: { text: "settled" } }),
|
||||
LLMEvent.providerError({ message: "Provider unavailable" }),
|
||||
]
|
||||
|
||||
const run = yield* session.resume(sessionID).pipe(Effect.forkChild)
|
||||
yield* Deferred.await(toolExecutionsStarted)
|
||||
yield* Deferred.succeed(toolExecutionGate, undefined)
|
||||
expect((yield* Fiber.join(run).pipe(Effect.flip)).message).toBe("Provider unavailable")
|
||||
toolExecutionGate = undefined
|
||||
toolExecutionsStarted = undefined
|
||||
expect((yield* session.resume(sessionID).pipe(Effect.flip)).message).toBe("Provider unavailable")
|
||||
|
||||
expect(requests).toHaveLength(1)
|
||||
expect(executions.slice(executionCount)).toEqual(["settled"])
|
||||
const context = yield* session.context(sessionID)
|
||||
const assistant = requireAssistant(context)
|
||||
expect((yield* recordedStepSettlementEvents(sessionID, assistant.id)).map((event) => event.type)).toEqual([
|
||||
"session.step.started.1",
|
||||
"session.tool.called.1",
|
||||
"session.tool.success.1",
|
||||
"session.step.failed.1",
|
||||
])
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -3726,47 +3524,13 @@ describe("SessionRunnerLLM", () => {
|
||||
expect((yield* session.resume(sessionID).pipe(Effect.flip)).message).toBe("Provider unavailable")
|
||||
|
||||
expect(requests).toHaveLength(1)
|
||||
const context = yield* session.context(sessionID)
|
||||
expect(context).toMatchObject([
|
||||
expect(yield* session.context(sessionID)).toMatchObject([
|
||||
{ type: "user", text: "Fail hosted tool durably" },
|
||||
{
|
||||
type: "assistant",
|
||||
content: [{ type: "tool", id: "call-hosted-provider-error", state: { status: "error" } }],
|
||||
},
|
||||
])
|
||||
const assistant = requireAssistant(context)
|
||||
expect((yield* recordedStepSettlementEvents(sessionID, assistant.id)).map((event) => event.type)).toEqual([
|
||||
"session.step.started.1",
|
||||
"session.tool.called.1",
|
||||
"session.tool.failed.1",
|
||||
"session.step.failed.1",
|
||||
])
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("preserves a tool defect before provider failure settlement", () =>
|
||||
Effect.gen(function* () {
|
||||
yield* setup
|
||||
const session = yield* SessionV2.Service
|
||||
yield* session.prompt({ sessionID, prompt: Prompt.make({ text: "Defect while provider fails" }), resume: false })
|
||||
response = [
|
||||
LLMEvent.stepStart({ index: 0 }),
|
||||
LLMEvent.toolCall({ id: "call-defect-provider-error", name: "defect", input: {} }),
|
||||
LLMEvent.providerError({ message: "Provider unavailable" }),
|
||||
]
|
||||
|
||||
expect((yield* session.resume(sessionID).pipe(Effect.flip)).message).toBe("Provider unavailable")
|
||||
|
||||
const context = yield* session.context(sessionID)
|
||||
const assistant = requireAssistant(context)
|
||||
const events = yield* recordedStepSettlementEvents(sessionID, assistant.id)
|
||||
expect(events.map((event) => event.type)).toEqual([
|
||||
"session.step.started.1",
|
||||
"session.tool.called.1",
|
||||
"session.tool.failed.1",
|
||||
"session.step.failed.1",
|
||||
])
|
||||
expect(events[2]?.data.error).toMatchObject({ type: "unknown", message: "unexpected tool defect" })
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -3785,113 +3549,16 @@ describe("SessionRunnerLLM", () => {
|
||||
}),
|
||||
]
|
||||
|
||||
expect((yield* session.resume(sessionID).pipe(Effect.flip)).message).toBe("Provider did not return a tool result")
|
||||
const assistant = requireAssistant(yield* session.context(sessionID))
|
||||
const events = yield* recordedStepSettlementEvents(sessionID, assistant.id)
|
||||
expect(events.map((event) => event.type)).toEqual([
|
||||
"session.step.started.1",
|
||||
"session.tool.called.1",
|
||||
"session.tool.failed.1",
|
||||
"session.step.failed.1",
|
||||
])
|
||||
expect(
|
||||
events.filter((event) => event.type.startsWith("session.step.") && event.type !== "session.step.started.1"),
|
||||
).toHaveLength(1)
|
||||
yield* session.resume(sessionID)
|
||||
yield* replaySessionProjection(sessionID)
|
||||
|
||||
expect(yield* session.context(sessionID)).toMatchObject([
|
||||
{ type: "user", text: "Fail hosted tool at EOF" },
|
||||
{
|
||||
type: "assistant",
|
||||
finish: "error",
|
||||
error: { type: "tool.result-missing" },
|
||||
content: [{ type: "tool", id: "call-hosted-eof", state: { status: "error" } }],
|
||||
},
|
||||
{ type: "assistant", content: [{ type: "tool", id: "call-hosted-eof", state: { status: "error" } }] },
|
||||
])
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("fails an unresolved hosted tool before one clean step end", () =>
|
||||
Effect.gen(function* () {
|
||||
yield* setup
|
||||
const session = yield* SessionV2.Service
|
||||
yield* session.prompt({
|
||||
sessionID,
|
||||
prompt: Prompt.make({ text: "Settle hosted tool before ending" }),
|
||||
resume: false,
|
||||
})
|
||||
response = [
|
||||
LLMEvent.stepStart({ index: 0 }),
|
||||
LLMEvent.toolCall({
|
||||
id: "call-hosted-clean-end",
|
||||
name: "web_search",
|
||||
input: { query: "effect" },
|
||||
providerExecuted: true,
|
||||
}),
|
||||
LLMEvent.stepFinish({ index: 0, reason: "stop" }),
|
||||
LLMEvent.finish({ reason: "stop" }),
|
||||
]
|
||||
|
||||
yield* session.resume(sessionID)
|
||||
|
||||
const assistant = requireAssistant(yield* session.context(sessionID))
|
||||
const events = yield* recordedStepSettlementEvents(sessionID, assistant.id)
|
||||
expect(events.map((event) => event.type)).toEqual([
|
||||
"session.step.started.1",
|
||||
"session.tool.called.1",
|
||||
"session.tool.failed.1",
|
||||
"session.step.ended.1",
|
||||
])
|
||||
expect(
|
||||
events.filter((event) => event.type.startsWith("session.step.") && event.type !== "session.step.started.1"),
|
||||
).toHaveLength(1)
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("settles unresolved local and hosted tools before one raw provider failure", () =>
|
||||
Effect.gen(function* () {
|
||||
yield* setup
|
||||
const session = yield* SessionV2.Service
|
||||
yield* session.prompt({ sessionID, prompt: Prompt.make({ text: "Fail unresolved tools" }), resume: false })
|
||||
const failure = invalidRequest()
|
||||
const providerFailed = yield* Deferred.make<void>()
|
||||
toolExecutionGate = yield* Deferred.make<void>()
|
||||
responseStream = Stream.concat(
|
||||
Stream.fromIterable([
|
||||
LLMEvent.stepStart({ index: 0 }),
|
||||
LLMEvent.toolCall({ id: "call-local-raw-failure", name: "defect", input: {} }),
|
||||
LLMEvent.toolCall({
|
||||
id: "call-hosted-raw-failure-pair",
|
||||
name: "web_search",
|
||||
input: { query: "effect" },
|
||||
providerExecuted: true,
|
||||
}),
|
||||
]),
|
||||
Stream.fromEffect(Deferred.succeed(providerFailed, undefined)).pipe(Stream.flatMap(() => Stream.fail(failure))),
|
||||
)
|
||||
|
||||
const run = yield* session.resume(sessionID).pipe(Effect.forkChild)
|
||||
yield* Deferred.await(providerFailed)
|
||||
yield* Deferred.succeed(toolExecutionGate, undefined)
|
||||
expect(yield* Fiber.join(run).pipe(Effect.flip)).toBe(failure)
|
||||
toolExecutionGate = undefined
|
||||
|
||||
const assistant = requireAssistant(yield* session.context(sessionID))
|
||||
const events = yield* recordedStepSettlementEvents(sessionID, assistant.id)
|
||||
expect(events.map((event) => ({ type: event.type, callID: event.data.callID }))).toEqual([
|
||||
{ type: "session.step.started.1", callID: undefined },
|
||||
{ type: "session.tool.called.1", callID: "call-local-raw-failure" },
|
||||
{ type: "session.tool.called.1", callID: "call-hosted-raw-failure-pair" },
|
||||
{ type: "session.tool.failed.1", callID: "call-local-raw-failure" },
|
||||
{ type: "session.tool.failed.1", callID: "call-hosted-raw-failure-pair" },
|
||||
{ type: "session.step.failed.1", callID: undefined },
|
||||
])
|
||||
expect(
|
||||
events.filter((event) => event.type.startsWith("session.step.") && event.type !== "session.step.started.1"),
|
||||
).toHaveLength(1)
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("durably fails a hosted tool left unresolved by a raw provider stream failure", () =>
|
||||
Effect.gen(function* () {
|
||||
yield* setup
|
||||
@@ -3918,17 +3585,6 @@ describe("SessionRunnerLLM", () => {
|
||||
|
||||
expect(yield* session.resume(sessionID).pipe(Effect.flip)).toBe(failure)
|
||||
expect(requests).toHaveLength(1)
|
||||
const assistant = requireAssistant(yield* session.context(sessionID))
|
||||
const events = yield* recordedStepSettlementEvents(sessionID, assistant.id)
|
||||
expect(events.map((event) => event.type)).toEqual([
|
||||
"session.step.started.1",
|
||||
"session.tool.called.1",
|
||||
"session.tool.failed.1",
|
||||
"session.step.failed.1",
|
||||
])
|
||||
expect(
|
||||
events.filter((event) => event.type.startsWith("session.step.") && event.type !== "session.step.started.1"),
|
||||
).toHaveLength(1)
|
||||
yield* replaySessionProjection(sessionID)
|
||||
expect(yield* session.context(sessionID)).toMatchObject([
|
||||
{ type: "user", text: "Fail hosted tool on raw failure" },
|
||||
@@ -4043,8 +3699,6 @@ describe("SessionRunnerLLM", () => {
|
||||
LLMEvent.toolInputDelta({ id: "call-parsed", name: "web_search", text: '{"query":"hello"}' }),
|
||||
LLMEvent.toolInputEnd({ id: "call-parsed", name: "web_search" }),
|
||||
LLMEvent.toolCall({ id: "call-parsed", name: "web_search", input: { query: "hello" }, providerExecuted: true }),
|
||||
LLMEvent.stepFinish({ index: 0, reason: "stop" }),
|
||||
LLMEvent.finish({ reason: "stop" }),
|
||||
]
|
||||
|
||||
yield* session.resume(sessionID)
|
||||
|
||||
@@ -87,6 +87,8 @@ describe("QuestionTool", () => {
|
||||
error: {
|
||||
type: "permission.rejected",
|
||||
message: "Permission denied: question",
|
||||
permission: "question",
|
||||
resources: ["*"],
|
||||
},
|
||||
})
|
||||
expect(capturedInput()).toBeUndefined()
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
import { describe, expect } from "bun:test"
|
||||
import { Effect, Layer } from "effect"
|
||||
import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
|
||||
import { makeLocationNode } from "@opencode-ai/core/effect/app-node"
|
||||
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
||||
import { FSUtil } from "@opencode-ai/core/fs-util"
|
||||
import { Location } from "@opencode-ai/core/location"
|
||||
import { PermissionV2 } from "@opencode-ai/core/permission"
|
||||
import { Ripgrep } from "@opencode-ai/core/ripgrep"
|
||||
import { AbsolutePath } from "@opencode-ai/core/schema"
|
||||
import { SessionV2 } from "@opencode-ai/core/session"
|
||||
import { GlobTool } from "@opencode-ai/core/tool/glob"
|
||||
import { GrepTool } from "@opencode-ai/core/tool/grep"
|
||||
import { ToolRegistry } from "@opencode-ai/core/tool/registry"
|
||||
import { ToolOutputStore } from "@opencode-ai/core/tool-output-store"
|
||||
import { location } from "./fixture/location"
|
||||
import { tmpdir } from "./fixture/tmpdir"
|
||||
import { testEffect } from "./lib/effect"
|
||||
import { executeTool, registerToolPlugin, toolIdentity } from "./lib/tool"
|
||||
|
||||
const globToolNode = makeLocationNode({
|
||||
name: "test/glob-tool-plugin",
|
||||
layer: Layer.effectDiscard(registerToolPlugin(GlobTool.Plugin)),
|
||||
deps: [ToolRegistry.toolsNode, FSUtil.node, Ripgrep.node, Location.node, PermissionV2.node],
|
||||
})
|
||||
const grepToolNode = makeLocationNode({
|
||||
name: "test/grep-tool-plugin",
|
||||
layer: Layer.effectDiscard(registerToolPlugin(GrepTool.Plugin)),
|
||||
deps: [ToolRegistry.toolsNode, FSUtil.node, Ripgrep.node, Location.node, PermissionV2.node],
|
||||
})
|
||||
const permission = Layer.succeed(
|
||||
PermissionV2.Service,
|
||||
PermissionV2.Service.of({
|
||||
assert: () => Effect.void,
|
||||
ask: () => Effect.die("unused"),
|
||||
reply: () => Effect.die("unused"),
|
||||
get: () => Effect.die("unused"),
|
||||
forSession: () => Effect.die("unused"),
|
||||
list: () => Effect.die("unused"),
|
||||
}),
|
||||
)
|
||||
const sessionID = SessionV2.ID.make("ses_search_tool_test")
|
||||
|
||||
const withTools = <A, E, R>(directory: string, body: (registry: ToolRegistry.Interface) => Effect.Effect<A, E, R>) =>
|
||||
Effect.gen(function* () {
|
||||
return yield* body(yield* ToolRegistry.Service)
|
||||
}).pipe(
|
||||
Effect.provide(
|
||||
AppNodeBuilder.build(LayerNode.group([ToolRegistry.node, ToolRegistry.toolsNode, globToolNode, grepToolNode]), [
|
||||
[
|
||||
Location.node,
|
||||
Layer.succeed(Location.Service, Location.Service.of(location({ directory: AbsolutePath.make(directory) }))),
|
||||
],
|
||||
[PermissionV2.node, permission],
|
||||
[ToolOutputStore.node, ToolOutputStore.nodeWithoutConfig],
|
||||
]),
|
||||
),
|
||||
)
|
||||
|
||||
const call = (name: "glob" | "grep", input: unknown) => ({
|
||||
sessionID,
|
||||
...toolIdentity,
|
||||
call: { type: "tool-call" as const, id: `call-${name}`, name, input },
|
||||
})
|
||||
|
||||
const it = testEffect(Layer.empty)
|
||||
|
||||
describe("search tools", () => {
|
||||
for (const name of ["glob", "grep"] as const) {
|
||||
it.live(`${name} reports a missing search path`, () =>
|
||||
Effect.acquireUseRelease(
|
||||
Effect.promise(() => tmpdir()),
|
||||
(tmp) =>
|
||||
withTools(tmp.path, (registry) =>
|
||||
Effect.gen(function* () {
|
||||
const result = yield* executeTool(
|
||||
registry,
|
||||
call(name, { path: "missing", pattern: name === "glob" ? "*" : "needle" }),
|
||||
)
|
||||
expect(result).toEqual({ type: "error", value: "Search path does not exist: missing" })
|
||||
}),
|
||||
),
|
||||
(tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]()),
|
||||
),
|
||||
)
|
||||
}
|
||||
})
|
||||
@@ -92,12 +92,10 @@ const executionNode = makeGlobalNode({
|
||||
yield* events.publish(SessionEvent.Text.Started, {
|
||||
sessionID: id,
|
||||
assistantMessageID,
|
||||
ordinal: 0,
|
||||
})
|
||||
yield* events.publish(SessionEvent.Text.Ended, {
|
||||
sessionID: id,
|
||||
assistantMessageID,
|
||||
ordinal: 0,
|
||||
text: "ok",
|
||||
})
|
||||
yield* events.publish(SessionEvent.Step.Ended, {
|
||||
@@ -487,13 +485,9 @@ describe("ShellTool", () => {
|
||||
const structured = settled.output?.structured as Record<string, unknown> | undefined
|
||||
const shellID = typeof structured?.shellID === "string" ? structured.shellID : undefined
|
||||
expect(settled.output?.structured).toMatchObject({ truncated: false })
|
||||
expect(settled.output?.content[0]).toEqual({
|
||||
expect(settled.output?.content[0]).toMatchObject({
|
||||
type: "text",
|
||||
text: "The command was moved to the background.",
|
||||
})
|
||||
expect(settled.output?.content[1]).toMatchObject({
|
||||
type: "text",
|
||||
text: expect.stringContaining("DO NOT sleep, poll"),
|
||||
text: expect.stringContaining("running in the background"),
|
||||
})
|
||||
expect(shellID).toStartWith("sh_")
|
||||
|
||||
|
||||
@@ -58,12 +58,10 @@ const executionNode = makeGlobalNode({
|
||||
yield* events.publish(SessionEvent.Text.Started, {
|
||||
sessionID,
|
||||
assistantMessageID,
|
||||
ordinal: 0,
|
||||
})
|
||||
yield* events.publish(SessionEvent.Text.Ended, {
|
||||
sessionID,
|
||||
assistantMessageID,
|
||||
ordinal: 0,
|
||||
text: childText,
|
||||
})
|
||||
yield* events.publish(SessionEvent.Step.Ended, {
|
||||
|
||||
@@ -113,6 +113,16 @@ export function legacyTool(input: {
|
||||
}
|
||||
}
|
||||
|
||||
export function nextFragmentID(kind: "text" | "reasoning", ordinals: Map<string, number>, messageID: string) {
|
||||
const ordinal = ordinals.get(messageID) ?? 0
|
||||
ordinals.set(messageID, ordinal + 1)
|
||||
return `${kind}:${ordinal}`
|
||||
}
|
||||
|
||||
export function currentFragmentID(kind: "text" | "reasoning", ordinals: Map<string, number>, messageID: string) {
|
||||
return `${kind}:${Math.max(0, (ordinals.get(messageID) ?? 1) - 1)}`
|
||||
}
|
||||
|
||||
export function toolCommit(part: ToolPart, phase: "start" | "progress" | "final"): StreamCommit {
|
||||
const status = part.state.status
|
||||
const text =
|
||||
@@ -165,6 +175,8 @@ type ChildState = {
|
||||
projectedText: Map<string, string>
|
||||
reasoning: Map<string, string>
|
||||
projectedReasoning: Map<string, string>
|
||||
textOrdinals: Map<string, number>
|
||||
reasoningOrdinals: Map<string, number>
|
||||
tools: Map<string, ToolTrack>
|
||||
finishedTools: Set<string>
|
||||
messageIDs: Set<string>
|
||||
@@ -250,6 +262,8 @@ export function createSubagentTracker(input: SubagentTrackerInput): SubagentTrac
|
||||
projectedText: new Map(),
|
||||
reasoning: new Map(),
|
||||
projectedReasoning: new Map(),
|
||||
textOrdinals: new Map(),
|
||||
reasoningOrdinals: new Map(),
|
||||
tools: new Map(),
|
||||
finishedTools: new Set(),
|
||||
messageIDs: new Set(),
|
||||
@@ -332,6 +346,8 @@ export function createSubagentTracker(input: SubagentTrackerInput): SubagentTrac
|
||||
child.projectedText.clear()
|
||||
child.reasoning.clear()
|
||||
child.projectedReasoning.clear()
|
||||
child.textOrdinals.clear()
|
||||
child.reasoningOrdinals.clear()
|
||||
child.finishedTools.clear()
|
||||
child.messageIDs.clear()
|
||||
child.callIDs.clear()
|
||||
@@ -378,6 +394,8 @@ export function createSubagentTracker(input: SubagentTrackerInput): SubagentTrac
|
||||
}
|
||||
childTool(child, item, message.id)
|
||||
}
|
||||
child.textOrdinals.set(message.id, textOrdinal)
|
||||
child.reasoningOrdinals.set(message.id, reasoningOrdinal)
|
||||
if (message.error) {
|
||||
setFrame(child, `error:${message.id}`, {
|
||||
kind: "error",
|
||||
@@ -450,10 +468,11 @@ export function createSubagentTracker(input: SubagentTrackerInput): SubagentTrac
|
||||
return
|
||||
}
|
||||
if (event.type === "session.text.started") {
|
||||
nextFragmentID("text", child.textOrdinals, event.data.assistantMessageID)
|
||||
return
|
||||
}
|
||||
if (event.type === "session.text.delta") {
|
||||
const id = `text:${event.data.ordinal}`
|
||||
const id = currentFragmentID("text", child.textOrdinals, event.data.assistantMessageID)
|
||||
const key = fragmentKey(event.data.assistantMessageID, id)
|
||||
const projected = child.projectedText.get(key)
|
||||
const covered = projected?.indexOf(event.data.delta) ?? -1
|
||||
@@ -476,7 +495,7 @@ export function createSubagentTracker(input: SubagentTrackerInput): SubagentTrac
|
||||
return
|
||||
}
|
||||
if (event.type === "session.text.ended") {
|
||||
const id = `text:${event.data.ordinal}`
|
||||
const id = currentFragmentID("text", child.textOrdinals, event.data.assistantMessageID)
|
||||
const key = fragmentKey(event.data.assistantMessageID, id)
|
||||
child.text.set(key, event.data.text)
|
||||
child.projectedText.delete(key)
|
||||
@@ -493,10 +512,11 @@ export function createSubagentTracker(input: SubagentTrackerInput): SubagentTrac
|
||||
return
|
||||
}
|
||||
if (event.type === "session.reasoning.started") {
|
||||
nextFragmentID("reasoning", child.reasoningOrdinals, event.data.assistantMessageID)
|
||||
return
|
||||
}
|
||||
if (event.type === "session.reasoning.delta") {
|
||||
const id = `reasoning:${event.data.ordinal}`
|
||||
const id = currentFragmentID("reasoning", child.reasoningOrdinals, event.data.assistantMessageID)
|
||||
const key = fragmentKey(event.data.assistantMessageID, id)
|
||||
const projected = child.projectedReasoning.get(key)
|
||||
const covered = projected?.indexOf(event.data.delta) ?? -1
|
||||
@@ -519,7 +539,7 @@ export function createSubagentTracker(input: SubagentTrackerInput): SubagentTrac
|
||||
return
|
||||
}
|
||||
if (event.type === "session.reasoning.ended") {
|
||||
const id = `reasoning:${event.data.ordinal}`
|
||||
const id = currentFragmentID("reasoning", child.reasoningOrdinals, event.data.assistantMessageID)
|
||||
const key = fragmentKey(event.data.assistantMessageID, id)
|
||||
child.reasoning.set(key, event.data.text)
|
||||
child.projectedReasoning.delete(key)
|
||||
@@ -606,8 +626,14 @@ export function createSubagentTracker(input: SubagentTrackerInput): SubagentTrac
|
||||
notifyDetail(child)
|
||||
return
|
||||
}
|
||||
if (event.type === "session.step.ended") return
|
||||
if (event.type === "session.step.ended") {
|
||||
child.textOrdinals.delete(event.data.assistantMessageID)
|
||||
child.reasoningOrdinals.delete(event.data.assistantMessageID)
|
||||
return
|
||||
}
|
||||
if (event.type === "session.step.failed") {
|
||||
child.textOrdinals.delete(event.data.assistantMessageID)
|
||||
child.reasoningOrdinals.delete(event.data.assistantMessageID)
|
||||
setFrame(child, `error:step:${event.data.assistantMessageID}`, {
|
||||
kind: "error",
|
||||
source: "system",
|
||||
|
||||
@@ -10,7 +10,7 @@ import type {
|
||||
} from "@opencode-ai/sdk/v2"
|
||||
import { blockerStatus, pickBlockerView } from "./session-data"
|
||||
import { writeSessionOutput } from "./stream"
|
||||
import { createSubagentTracker, legacyTool, toolCommit } from "./stream-v2.subagent"
|
||||
import { createSubagentTracker, currentFragmentID, legacyTool, nextFragmentID, toolCommit } from "./stream-v2.subagent"
|
||||
import type {
|
||||
FooterApi,
|
||||
FooterView,
|
||||
@@ -106,6 +106,8 @@ type State = {
|
||||
projectedText: Map<string, string>
|
||||
reasoning: Map<string, string>
|
||||
projectedReasoning: Map<string, string>
|
||||
textOrdinals: Map<string, number>
|
||||
reasoningOrdinals: Map<string, number>
|
||||
tools: Map<string, ToolState>
|
||||
finishedTools: Set<string>
|
||||
skillMessages: Set<string>
|
||||
@@ -288,6 +290,8 @@ export async function createSessionTransport(input: StreamInput): Promise<Sessio
|
||||
projectedText: new Map(),
|
||||
reasoning: new Map(),
|
||||
projectedReasoning: new Map(),
|
||||
textOrdinals: new Map(),
|
||||
reasoningOrdinals: new Map(),
|
||||
tools: new Map(),
|
||||
finishedTools: new Set(),
|
||||
skillMessages: new Set(),
|
||||
@@ -483,6 +487,8 @@ export async function createSessionTransport(input: StreamInput): Promise<Sessio
|
||||
}
|
||||
if (render) renderTool(message.id, item)
|
||||
}
|
||||
state.textOrdinals.set(message.id, textOrdinal)
|
||||
state.reasoningOrdinals.set(message.id, reasoningOrdinal)
|
||||
if (render && message.error && !state.errors.has(message.id)) {
|
||||
state.errors.add(message.id)
|
||||
write([
|
||||
@@ -598,10 +604,11 @@ export async function createSessionTransport(input: StreamInput): Promise<Sessio
|
||||
return
|
||||
}
|
||||
if (event.type === "session.text.started") {
|
||||
nextFragmentID("text", state.textOrdinals, event.data.assistantMessageID)
|
||||
return
|
||||
}
|
||||
if (event.type === "session.text.delta") {
|
||||
const id = `text:${event.data.ordinal}`
|
||||
const id = currentFragmentID("text", state.textOrdinals, event.data.assistantMessageID)
|
||||
const key = streamPartKey(event.data.assistantMessageID, id)
|
||||
const projected = state.projectedText.get(key)
|
||||
const covered = projected?.indexOf(event.data.delta) ?? -1
|
||||
@@ -624,7 +631,7 @@ export async function createSessionTransport(input: StreamInput): Promise<Sessio
|
||||
return
|
||||
}
|
||||
if (event.type === "session.text.ended") {
|
||||
const id = `text:${event.data.ordinal}`
|
||||
const id = currentFragmentID("text", state.textOrdinals, event.data.assistantMessageID)
|
||||
const key = streamPartKey(event.data.assistantMessageID, id)
|
||||
const previous = state.text.get(key) ?? ""
|
||||
if (event.data.text.length > previous.length)
|
||||
@@ -643,10 +650,11 @@ export async function createSessionTransport(input: StreamInput): Promise<Sessio
|
||||
return
|
||||
}
|
||||
if (event.type === "session.reasoning.started") {
|
||||
nextFragmentID("reasoning", state.reasoningOrdinals, event.data.assistantMessageID)
|
||||
return
|
||||
}
|
||||
if (event.type === "session.reasoning.delta") {
|
||||
const id = `reasoning:${event.data.ordinal}`
|
||||
const id = currentFragmentID("reasoning", state.reasoningOrdinals, event.data.assistantMessageID)
|
||||
const key = streamPartKey(event.data.assistantMessageID, id)
|
||||
const projected = state.projectedReasoning.get(key)
|
||||
const covered = projected?.indexOf(event.data.delta) ?? -1
|
||||
@@ -670,7 +678,7 @@ export async function createSessionTransport(input: StreamInput): Promise<Sessio
|
||||
return
|
||||
}
|
||||
if (event.type === "session.reasoning.ended") {
|
||||
const id = `reasoning:${event.data.ordinal}`
|
||||
const id = currentFragmentID("reasoning", state.reasoningOrdinals, event.data.assistantMessageID)
|
||||
const key = streamPartKey(event.data.assistantMessageID, id)
|
||||
const previous = state.reasoning.get(key) ?? ""
|
||||
if (input.thinking && event.data.text.length > previous.length)
|
||||
@@ -767,6 +775,8 @@ export async function createSessionTransport(input: StreamInput): Promise<Sessio
|
||||
return
|
||||
}
|
||||
if (event.type === "session.step.ended") {
|
||||
state.textOrdinals.delete(event.data.assistantMessageID)
|
||||
state.reasoningOrdinals.delete(event.data.assistantMessageID)
|
||||
const total =
|
||||
event.data.tokens.input +
|
||||
event.data.tokens.output +
|
||||
@@ -780,6 +790,8 @@ export async function createSessionTransport(input: StreamInput): Promise<Sessio
|
||||
return
|
||||
}
|
||||
if (event.type === "session.step.failed") {
|
||||
state.textOrdinals.delete(event.data.assistantMessageID)
|
||||
state.reasoningOrdinals.delete(event.data.assistantMessageID)
|
||||
state.errors.add(event.data.assistantMessageID)
|
||||
if (state.wait) state.wait.failureRendered = true
|
||||
write([{ kind: "error", source: "system", text: errorMessage(event.data.error), phase: "start" }])
|
||||
@@ -1071,6 +1083,8 @@ export async function createSessionTransport(input: StreamInput): Promise<Sessio
|
||||
state.projectedText.clear()
|
||||
state.reasoning.clear()
|
||||
state.projectedReasoning.clear()
|
||||
state.textOrdinals.clear()
|
||||
state.reasoningOrdinals.clear()
|
||||
state.tools.clear()
|
||||
state.finishedTools.clear()
|
||||
state.skillMessages.clear()
|
||||
|
||||
@@ -214,7 +214,6 @@ describe("V2 mini transport", () => {
|
||||
data: {
|
||||
sessionID: "ses_1",
|
||||
assistantMessageID: "msg_assistant",
|
||||
ordinal: 0,
|
||||
delta: "answer",
|
||||
},
|
||||
})
|
||||
@@ -725,17 +724,6 @@ describe("V2 mini transport", () => {
|
||||
reset = resolve
|
||||
})
|
||||
const replay = transport.replayOnResize({ localRows: () => [], reset: () => resetting })
|
||||
events.push({
|
||||
id: "evt_text_started",
|
||||
created: 0,
|
||||
type: "session.text.started",
|
||||
durable: durable("ses_1"),
|
||||
data: {
|
||||
sessionID: "ses_1",
|
||||
assistantMessageID: "msg_assistant",
|
||||
ordinal: 0,
|
||||
},
|
||||
})
|
||||
events.push({
|
||||
id: "evt_text",
|
||||
created: 0,
|
||||
@@ -743,7 +731,6 @@ describe("V2 mini transport", () => {
|
||||
data: {
|
||||
sessionID: "ses_1",
|
||||
assistantMessageID: "msg_assistant",
|
||||
ordinal: 0,
|
||||
delta: "answer",
|
||||
},
|
||||
})
|
||||
@@ -829,7 +816,6 @@ describe("V2 mini transport", () => {
|
||||
data: {
|
||||
sessionID: "ses_1",
|
||||
assistantMessageID: "msg_assistant",
|
||||
ordinal: 0,
|
||||
text: "considering",
|
||||
},
|
||||
})
|
||||
@@ -1577,7 +1563,6 @@ describe("V2 mini transport", () => {
|
||||
data: {
|
||||
sessionID: "ses_child",
|
||||
assistantMessageID: "msg_child_a",
|
||||
ordinal: 0,
|
||||
delta: "child answer",
|
||||
},
|
||||
})
|
||||
|
||||
@@ -101,7 +101,6 @@ test.skip("text ended populates assistant text content", () => {
|
||||
data: {
|
||||
sessionID,
|
||||
assistantMessageID,
|
||||
ordinal: 0,
|
||||
},
|
||||
} satisfies SessionEvent.Event),
|
||||
)
|
||||
@@ -115,7 +114,6 @@ test.skip("text ended populates assistant text content", () => {
|
||||
data: {
|
||||
sessionID,
|
||||
assistantMessageID,
|
||||
ordinal: 0,
|
||||
text: "hello assistant",
|
||||
},
|
||||
} satisfies SessionEvent.Event),
|
||||
|
||||
@@ -372,16 +372,15 @@ export const makeSessionGroup = <I extends HttpApiMiddleware.AnyId, S>(sessionLo
|
||||
.add(
|
||||
HttpApiEndpoint.post("session.compact", "/api/session/:sessionID/compact", {
|
||||
params: { sessionID: Session.ID },
|
||||
payload: Schema.Struct({ id: SessionMessage.ID.pipe(Schema.optional) }),
|
||||
success: Schema.Struct({ data: SessionInput.Compaction }),
|
||||
error: [ConflictError, SessionNotFoundError],
|
||||
success: HttpApiSchema.NoContent,
|
||||
error: [SessionNotFoundError, SessionBusyError, ServiceUnavailableError, UnknownError],
|
||||
})
|
||||
.middleware(sessionLocationMiddleware)
|
||||
.annotateMerge(
|
||||
OpenApi.annotations({
|
||||
identifier: "v2.session.compact",
|
||||
summary: "Compact session",
|
||||
description: "Queue a durable session compaction request.",
|
||||
description: "Compact a session conversation.",
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
||||
@@ -1,9 +1,72 @@
|
||||
export * as SessionError from "./session-error.js"
|
||||
|
||||
import { Schema } from "effect"
|
||||
import { optional } from "./schema.js"
|
||||
|
||||
export interface Error extends Schema.Schema.Type<typeof Error> {}
|
||||
export const Error = Schema.Struct({
|
||||
type: Schema.String,
|
||||
message: Schema.String,
|
||||
}).annotate({ identifier: "Session.StructuredError" })
|
||||
const Message = { message: Schema.String }
|
||||
|
||||
const ProviderRateLimit = Schema.Struct({
|
||||
type: Schema.Literal("provider.rate-limit"),
|
||||
...Message,
|
||||
retryAfterMs: Schema.Finite.pipe(optional),
|
||||
})
|
||||
const ProviderAuth = Schema.Struct({ type: Schema.Literal("provider.auth"), ...Message })
|
||||
const ProviderQuota = Schema.Struct({ type: Schema.Literal("provider.quota"), ...Message })
|
||||
const ProviderContentFilter = Schema.Struct({ type: Schema.Literal("provider.content-filter"), ...Message })
|
||||
const ProviderTransport = Schema.Struct({ type: Schema.Literal("provider.transport"), ...Message })
|
||||
const ProviderInternal = Schema.Struct({ type: Schema.Literal("provider.internal"), ...Message })
|
||||
const ProviderInvalidOutput = Schema.Struct({ type: Schema.Literal("provider.invalid-output"), ...Message })
|
||||
const ProviderInvalidRequest = Schema.Struct({ type: Schema.Literal("provider.invalid-request"), ...Message })
|
||||
const ProviderNoRoute = Schema.Struct({ type: Schema.Literal("provider.no-route"), ...Message })
|
||||
const ProviderUnknown = Schema.Struct({ type: Schema.Literal("provider.unknown"), ...Message })
|
||||
const PermissionRejected = Schema.Struct({
|
||||
type: Schema.Literal("permission.rejected"),
|
||||
...Message,
|
||||
permission: Schema.String,
|
||||
resources: Schema.Array(Schema.String),
|
||||
})
|
||||
const ToolUnknown = Schema.Struct({ type: Schema.Literal("tool.unknown"), ...Message, name: Schema.String })
|
||||
const ToolStale = Schema.Struct({
|
||||
type: Schema.Literal("tool.stale"),
|
||||
...Message,
|
||||
name: Schema.String.pipe(optional),
|
||||
})
|
||||
const ToolExecution = Schema.Struct({ type: Schema.Literal("tool.execution"), ...Message })
|
||||
const ToolResultMissing = Schema.Struct({
|
||||
type: Schema.Literal("tool.result-missing"),
|
||||
...Message,
|
||||
callID: Schema.String.pipe(optional),
|
||||
})
|
||||
const Aborted = Schema.Struct({
|
||||
type: Schema.Literal("aborted"),
|
||||
...Message,
|
||||
reason: Schema.Literals(["user", "shutdown", "timeout"]).pipe(optional),
|
||||
})
|
||||
const Unknown = Schema.Struct({
|
||||
type: Schema.Literal("unknown"),
|
||||
...Message,
|
||||
agent: Schema.String.pipe(optional),
|
||||
})
|
||||
|
||||
export const Error = Schema.Union([
|
||||
ProviderRateLimit,
|
||||
ProviderAuth,
|
||||
ProviderQuota,
|
||||
ProviderContentFilter,
|
||||
ProviderTransport,
|
||||
ProviderInternal,
|
||||
ProviderInvalidOutput,
|
||||
ProviderInvalidRequest,
|
||||
ProviderNoRoute,
|
||||
ProviderUnknown,
|
||||
PermissionRejected,
|
||||
ToolUnknown,
|
||||
ToolStale,
|
||||
ToolExecution,
|
||||
ToolResultMissing,
|
||||
Aborted,
|
||||
Unknown,
|
||||
])
|
||||
.pipe(Schema.toTaggedUnion("type"))
|
||||
.annotate({ identifier: "Session.StructuredError" })
|
||||
export type Error = typeof Error.Type
|
||||
|
||||
@@ -248,7 +248,6 @@ export namespace Text {
|
||||
schema: {
|
||||
...Base,
|
||||
assistantMessageID: SessionMessage.ID,
|
||||
ordinal: NonNegativeInt,
|
||||
},
|
||||
})
|
||||
export type Started = typeof Started.Type
|
||||
@@ -259,7 +258,6 @@ export namespace Text {
|
||||
schema: {
|
||||
...Base,
|
||||
assistantMessageID: SessionMessage.ID,
|
||||
ordinal: NonNegativeInt,
|
||||
delta: Schema.String,
|
||||
},
|
||||
})
|
||||
@@ -271,7 +269,6 @@ export namespace Text {
|
||||
schema: {
|
||||
...Base,
|
||||
assistantMessageID: SessionMessage.ID,
|
||||
ordinal: NonNegativeInt,
|
||||
text: Schema.String,
|
||||
},
|
||||
})
|
||||
@@ -285,7 +282,6 @@ export namespace Reasoning {
|
||||
schema: {
|
||||
...Base,
|
||||
assistantMessageID: SessionMessage.ID,
|
||||
ordinal: NonNegativeInt,
|
||||
state: SessionMessage.ProviderState.pipe(optional),
|
||||
},
|
||||
})
|
||||
@@ -297,7 +293,6 @@ export namespace Reasoning {
|
||||
schema: {
|
||||
...Base,
|
||||
assistantMessageID: SessionMessage.ID,
|
||||
ordinal: NonNegativeInt,
|
||||
delta: Schema.String,
|
||||
},
|
||||
})
|
||||
@@ -309,7 +304,6 @@ export namespace Reasoning {
|
||||
schema: {
|
||||
...Base,
|
||||
assistantMessageID: SessionMessage.ID,
|
||||
ordinal: NonNegativeInt,
|
||||
text: Schema.String,
|
||||
state: SessionMessage.ProviderState.pipe(optional),
|
||||
},
|
||||
@@ -426,16 +420,6 @@ export const RetryScheduled = Event.durable({
|
||||
export type RetryScheduled = typeof RetryScheduled.Type
|
||||
|
||||
export namespace Compaction {
|
||||
export const Admitted = Event.durable({
|
||||
type: "session.compaction.admitted",
|
||||
...options,
|
||||
schema: {
|
||||
...Base,
|
||||
inputID: SessionMessage.ID,
|
||||
},
|
||||
})
|
||||
export type Admitted = typeof Admitted.Type
|
||||
|
||||
export const Started = Event.durable({
|
||||
type: "session.compaction.started",
|
||||
...options,
|
||||
@@ -466,13 +450,6 @@ export namespace Compaction {
|
||||
},
|
||||
})
|
||||
export type Ended = typeof Ended.Type
|
||||
|
||||
export const Failed = Event.durable({
|
||||
type: "session.compaction.failed",
|
||||
...options,
|
||||
schema: Base,
|
||||
})
|
||||
export type Failed = typeof Failed.Type
|
||||
}
|
||||
|
||||
export namespace RevertEvent {
|
||||
@@ -523,11 +500,9 @@ export const Definitions = Event.inventory(
|
||||
Tool.Success,
|
||||
Tool.Failed,
|
||||
RetryScheduled,
|
||||
Compaction.Admitted,
|
||||
Compaction.Started,
|
||||
Compaction.Delta,
|
||||
Compaction.Ended,
|
||||
Compaction.Failed,
|
||||
RevertEvent.Staged,
|
||||
RevertEvent.Cleared,
|
||||
RevertEvent.Committed,
|
||||
|
||||
@@ -21,22 +21,3 @@ export const Admitted = Schema.Struct({
|
||||
timeCreated: DateTimeUtcFromMillis,
|
||||
promotedSeq: NonNegativeInt.pipe(optional),
|
||||
}).annotate({ identifier: "SessionInput.Admitted" })
|
||||
|
||||
export interface PromptEntry extends Schema.Schema.Type<typeof PromptEntry> {}
|
||||
export const PromptEntry = Schema.Struct({
|
||||
type: Schema.Literal("prompt"),
|
||||
...Admitted.fields,
|
||||
}).annotate({ identifier: "SessionInput.PromptEntry" })
|
||||
|
||||
export interface Compaction extends Schema.Schema.Type<typeof Compaction> {}
|
||||
export const Compaction = Schema.Struct({
|
||||
type: Schema.Literal("compaction"),
|
||||
admittedSeq: NonNegativeInt,
|
||||
id: SessionMessage.ID,
|
||||
sessionID: SessionID,
|
||||
timeCreated: DateTimeUtcFromMillis,
|
||||
handledSeq: NonNegativeInt.pipe(optional),
|
||||
}).annotate({ identifier: "SessionInput.Compaction" })
|
||||
|
||||
export const Entry = Schema.Union([PromptEntry, Compaction]).pipe(Schema.toTaggedUnion("type"))
|
||||
export type Entry = typeof Entry.Type
|
||||
|
||||
@@ -45,7 +45,6 @@ export const ModelSelected = Schema.Struct({
|
||||
...Base,
|
||||
type: Schema.Literal("model-switched"),
|
||||
model: Model.Ref,
|
||||
previous: Model.Ref.pipe(optional),
|
||||
}).annotate({ identifier: "Session.Message.ModelSelected" })
|
||||
|
||||
export interface User extends Schema.Schema.Type<typeof User> {}
|
||||
@@ -210,7 +209,6 @@ export const Assistant = Schema.Struct({
|
||||
export interface Compaction extends Schema.Schema.Type<typeof Compaction> {}
|
||||
export const Compaction = Schema.Struct({
|
||||
type: Schema.Literal("compaction"),
|
||||
status: Schema.Literals(["queued", "running", "completed", "failed"]),
|
||||
reason: Schema.Literals(["auto", "manual"]),
|
||||
summary: Schema.String,
|
||||
recent: Schema.String,
|
||||
|
||||
@@ -124,10 +124,8 @@ describe("public event manifest", () => {
|
||||
"session.reasoning.started.1",
|
||||
"session.reasoning.ended.1",
|
||||
"session.retry.scheduled.1",
|
||||
"session.compaction.admitted.1",
|
||||
"session.compaction.started.1",
|
||||
"session.compaction.ended.1",
|
||||
"session.compaction.failed.1",
|
||||
"session.revert.staged.1",
|
||||
"session.revert.cleared.1",
|
||||
"session.revert.committed.1",
|
||||
@@ -142,11 +140,10 @@ describe("public event manifest", () => {
|
||||
test("keeps simplified session fragment and tool payloads on durable version 1", () => {
|
||||
const sessionID = SessionID.make("ses_test")
|
||||
const assistantMessageID = SessionMessage.ID.make("msg_test")
|
||||
const text = SessionEvent.Text.Started.data.make({ sessionID, assistantMessageID, ordinal: 0 })
|
||||
const text = SessionEvent.Text.Started.data.make({ sessionID, assistantMessageID })
|
||||
const reasoning = SessionEvent.Reasoning.Ended.data.make({
|
||||
sessionID,
|
||||
assistantMessageID,
|
||||
ordinal: 0,
|
||||
text: "thought",
|
||||
state: { signature: "sig" },
|
||||
})
|
||||
|
||||
@@ -3,17 +3,30 @@ import { Schema } from "effect"
|
||||
import { LLM, SessionError } from "../src/index.js"
|
||||
|
||||
describe("SessionError", () => {
|
||||
test("exports one identified open envelope", () => {
|
||||
test("exports one identified closed union", () => {
|
||||
expect(SessionError.Error.ast.annotations?.identifier).toBe("Session.StructuredError")
|
||||
expect(Object.keys(SessionError).filter((key) => key !== "SessionError")).toEqual(["Error"])
|
||||
})
|
||||
|
||||
test("round trips current and future error types through JSON", () => {
|
||||
test("round trips every closed error type through JSON", () => {
|
||||
const values: SessionError.Error[] = [
|
||||
{ type: "provider.rate-limit", message: "Slow down" },
|
||||
{ type: "provider.rate-limit", message: "Slow down", retryAfterMs: 2_500 },
|
||||
{ type: "provider.auth", message: "Authentication failed" },
|
||||
{ type: "provider.future-condition", message: "A future provider failure" },
|
||||
{ type: "unknown", message: "Unexpected" },
|
||||
{ type: "provider.quota", message: "Quota exhausted" },
|
||||
{ type: "provider.content-filter", message: "Response blocked" },
|
||||
{ type: "provider.transport", message: "Connection failed" },
|
||||
{ type: "provider.internal", message: "Provider failed" },
|
||||
{ type: "provider.invalid-output", message: "Malformed response" },
|
||||
{ type: "provider.invalid-request", message: "Invalid request" },
|
||||
{ type: "provider.no-route", message: "No route" },
|
||||
{ type: "provider.unknown", message: "Unknown provider failure" },
|
||||
{ type: "permission.rejected", message: "Permission rejected", permission: "read", resources: ["a"] },
|
||||
{ type: "tool.unknown", message: "Unknown tool", name: "missing" },
|
||||
{ type: "tool.stale", message: "Stale tool", name: "old" },
|
||||
{ type: "tool.execution", message: "Tool failed" },
|
||||
{ type: "tool.result-missing", message: "Missing result", callID: "call_1" },
|
||||
{ type: "aborted", message: "Interrupted", reason: "user" },
|
||||
{ type: "unknown", message: "Unexpected", agent: "build" },
|
||||
]
|
||||
const codec = Schema.fromJsonString(SessionError.Error)
|
||||
|
||||
@@ -23,19 +36,11 @@ describe("SessionError", () => {
|
||||
}
|
||||
})
|
||||
|
||||
test("accepts future fields while exposing only the stable envelope", () => {
|
||||
expect(
|
||||
Schema.decodeUnknownSync(SessionError.Error)({
|
||||
type: "provider.timeout",
|
||||
message: "Timeout",
|
||||
retryAfterMs: 2_500,
|
||||
}),
|
||||
).toEqual({ type: "provider.timeout", message: "Timeout" })
|
||||
})
|
||||
|
||||
test("rejects missing envelope fields", () => {
|
||||
test("rejects unknown types and missing messages", () => {
|
||||
expect(() =>
|
||||
Schema.decodeUnknownSync(SessionError.Error)({ type: "provider.timeout", message: "Timeout" }),
|
||||
).toThrow()
|
||||
expect(() => Schema.decodeUnknownSync(SessionError.Error)({ type: "provider.auth" })).toThrow()
|
||||
expect(() => Schema.decodeUnknownSync(SessionError.Error)({ message: "Missing type" })).toThrow()
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
+11
-144
@@ -30,8 +30,6 @@ type OpenApiDocument = {
|
||||
|
||||
const document = (await Bun.file("./openapi.json").json()) as OpenApiDocument
|
||||
const v2Document = (await Bun.file("./openapi-v2.json").json()) as OpenApiDocument
|
||||
normalizeComponentNames(v2Document)
|
||||
deduplicateEquivalentComponent(v2Document, "Shell", "Shell1")
|
||||
renameCollidingComponents(document, v2Document)
|
||||
document.paths = { ...document.paths, ...v2Document.paths }
|
||||
document.components = {
|
||||
@@ -62,7 +60,7 @@ if (schemas) {
|
||||
visit({ ...document, components: { ...document.components, schemas: undefined } })
|
||||
for (const name of Object.keys(schemas)) {
|
||||
if (
|
||||
/^(SessionAgentSelected|SessionModelSelected|SessionMoved|SessionRenamed|SessionForked|SessionPromptPromoted|SessionPromptAdmitted|SessionExecutionStarted|SessionExecutionSucceeded|SessionExecutionFailed|SessionExecutionInterrupted|SessionContextUpdated|SessionSynthetic|SessionSkillActivated|SessionShellStarted|SessionShellEnded|SessionStepStarted|SessionStepEnded|SessionStepFailed|SessionTextStarted|SessionTextDelta|SessionTextEnded|SessionReasoningStarted|SessionReasoningDelta|SessionReasoningEnded|SessionToolInputStarted|SessionToolInputDelta|SessionToolInputEnded|SessionToolCalled|SessionToolProgress|SessionToolSuccess|SessionToolFailed|SessionRetryScheduled|SessionCompactionStarted|SessionCompactionDelta|SessionCompactionEnded|SessionRevertStaged|SessionRevertCleared|SessionRevertCommitted)\d+$/.test(
|
||||
/^(SessionAgentSelected|SessionModelSelected|SessionMoved|SessionRenamed|SessionForked|SessionPromptPromoted|SessionPromptAdmitted|SessionExecutionStarted|SessionExecutionSucceeded|SessionExecutionFailed|SessionExecutionInterrupted|SessionContextUpdated|SessionSynthetic|SessionSkillActivated|SessionShellStarted|SessionShellEnded|SessionStepStarted|SessionStepEnded|SessionStepFailed|SessionTextStarted|SessionTextDelta|SessionTextEnded|SessionReasoningStarted|SessionReasoningDelta|SessionReasoningEnded|SessionToolInputStarted|SessionToolInputDelta|SessionToolInputEnded|SessionToolCalled|SessionToolProgress|SessionToolSuccess|SessionToolFailed|SessionRetryScheduled|SessionCompactionStarted|SessionCompactionDelta|SessionCompactionEnded|SessionRevertStaged|SessionRevertCleared|SessionRevertCommitted)1$/.test(
|
||||
name,
|
||||
) &&
|
||||
!reachable.has(name)
|
||||
@@ -102,27 +100,22 @@ await createClient({
|
||||
const generatedTypesPath = "./src/v2/gen/types.gen.ts"
|
||||
const generatedTypes = await Bun.file(generatedTypesPath).text()
|
||||
if (
|
||||
/export type (SessionAgentSelected|SessionModelSelected|SessionMoved|SessionRenamed|SessionForked|SessionPromptPromoted|SessionPromptAdmitted|SessionExecutionStarted|SessionExecutionSucceeded|SessionExecutionFailed|SessionExecutionInterrupted|SessionContextUpdated|SessionSynthetic|SessionSkillActivated|SessionShellStarted|SessionShellEnded|SessionStepStarted|SessionStepEnded|SessionStepFailed|SessionTextStarted|SessionTextDelta|SessionTextEnded|SessionReasoningStarted|SessionReasoningDelta|SessionReasoningEnded|SessionToolInputStarted|SessionToolInputDelta|SessionToolInputEnded|SessionToolCalled|SessionToolProgress|SessionToolSuccess|SessionToolFailed|SessionRetryScheduled|SessionCompactionStarted|SessionCompactionDelta|SessionCompactionEnded|SessionRevertStaged|SessionRevertCleared|SessionRevertCommitted)\d+ =/.test(
|
||||
/export type (SessionAgentSelected|SessionModelSelected|SessionMoved|SessionRenamed|SessionForked|SessionPromptPromoted|SessionPromptAdmitted|SessionExecutionStarted|SessionExecutionSucceeded|SessionExecutionFailed|SessionExecutionInterrupted|SessionContextUpdated|SessionSynthetic|SessionSkillActivated|SessionShellStarted|SessionShellEnded|SessionStepStarted|SessionStepEnded|SessionStepFailed|SessionTextStarted|SessionTextDelta|SessionTextEnded|SessionReasoningStarted|SessionReasoningDelta|SessionReasoningEnded|SessionToolInputStarted|SessionToolInputDelta|SessionToolInputEnded|SessionToolCalled|SessionToolProgress|SessionToolSuccess|SessionToolFailed|SessionRetryScheduled|SessionCompactionStarted|SessionCompactionDelta|SessionCompactionEnded|SessionRevertStaged|SessionRevertCleared|SessionRevertCommitted)1 =/.test(
|
||||
generatedTypes,
|
||||
)
|
||||
) {
|
||||
throw new Error("Session history generated duplicate Session event variants")
|
||||
}
|
||||
const sessionErrorTypesPatched = deduplicateEquivalentGeneratedTypes(
|
||||
generatedTypes,
|
||||
"SessionStructuredError",
|
||||
/^SessionStructuredError\d+$/,
|
||||
)
|
||||
const obsoleteSessionNext = [...sessionErrorTypesPatched.matchAll(/export type (SessionNext\w*) =/g)].map(
|
||||
(match) => match[1],
|
||||
)
|
||||
if (obsoleteSessionNext.length > 0) {
|
||||
throw new Error(`Obsolete SessionNext generated type noise reintroduced: ${obsoleteSessionNext.join(", ")}`)
|
||||
const duplicateSessionErrorStart = generatedTypes.indexOf("export type SessionStructuredError2 =")
|
||||
const duplicateSessionErrorEnd = generatedTypes.indexOf("\n\nexport type ", duplicateSessionErrorStart + 1)
|
||||
if (duplicateSessionErrorStart === -1 || duplicateSessionErrorEnd === -1) {
|
||||
throw new Error("Session structured error duplicate prune did not apply")
|
||||
}
|
||||
const logTypesPatched = sessionErrorTypesPatched.replace(
|
||||
/(export type V2SessionLogData = \{[\s\S]*?query\?: \{\s*after\?: )string/,
|
||||
"$1number",
|
||||
)
|
||||
const sessionErrorTypesPatched =
|
||||
generatedTypes.slice(0, duplicateSessionErrorStart) + generatedTypes.slice(duplicateSessionErrorEnd + 2)
|
||||
const logTypesPatched = sessionErrorTypesPatched
|
||||
.replaceAll("SessionStructuredError2", "SessionStructuredError")
|
||||
.replace(/(export type V2SessionLogData = \{[\s\S]*?query\?: \{\s*after\?: )string/, "$1number")
|
||||
if (logTypesPatched === sessionErrorTypesPatched) {
|
||||
throw new Error("Session log numeric query patch did not apply")
|
||||
}
|
||||
@@ -150,12 +143,6 @@ if (eventSubscribeTypesPatched === sessionMessagesTypesPatched) {
|
||||
if (/SessionStructuredError\d/.test(eventSubscribeTypesPatched)) {
|
||||
throw new Error("Session structured error generated a name-mangled duplicate")
|
||||
}
|
||||
if (/\bSessionNext\w*\b/.test(eventSubscribeTypesPatched)) {
|
||||
throw new Error("Obsolete SessionNext generated type noise reintroduced")
|
||||
}
|
||||
if (/export type Shell\d+V2 =/.test(eventSubscribeTypesPatched)) {
|
||||
throw new Error("Shell generated a name-mangled duplicate")
|
||||
}
|
||||
await Bun.write(generatedTypesPath, eventSubscribeTypesPatched)
|
||||
|
||||
const querySerializerPath = "./src/v2/gen/client/utils.gen.ts"
|
||||
@@ -228,10 +215,6 @@ function renameCollidingComponents(target: OpenApiDocument, source: OpenApiDocum
|
||||
const renames = new Map<string, string>()
|
||||
for (const name of Object.keys(sourceSchemas)) {
|
||||
if (!Object.hasOwn(targetSchemas, name)) continue
|
||||
if (JSON.stringify(normalizeSchema(sourceSchemas[name])) === JSON.stringify(normalizeSchema(targetSchemas[name]))) {
|
||||
delete sourceSchemas[name]
|
||||
continue
|
||||
}
|
||||
let renamed = `${name}V2`
|
||||
let index = 2
|
||||
while (Object.hasOwn(targetSchemas, renamed) || Object.hasOwn(sourceSchemas, renamed)) {
|
||||
@@ -251,122 +234,6 @@ function renameCollidingComponents(target: OpenApiDocument, source: OpenApiDocum
|
||||
source.paths = rewriteRefs(source.paths, renames) as Record<string, unknown> | undefined
|
||||
}
|
||||
|
||||
function normalizeComponentNames(document: OpenApiDocument) {
|
||||
let schemas = document.components?.schemas
|
||||
if (!schemas) return
|
||||
|
||||
for (const name of Object.keys(schemas)) {
|
||||
if (!Object.hasOwn(schemas, name)) continue
|
||||
const next = componentTypeName(name)
|
||||
if (next === name) continue
|
||||
if (schemas[next] !== undefined) {
|
||||
if (JSON.stringify(normalizeSchema(schemas[name])) !== JSON.stringify(normalizeSchema(schemas[next]))) continue
|
||||
const renames = new Map([[name, next]])
|
||||
schemas = rewriteRefs(schemas, renames) as Record<string, unknown>
|
||||
delete schemas[name]
|
||||
document.paths = rewriteRefs(document.paths, renames) as Record<string, unknown> | undefined
|
||||
continue
|
||||
}
|
||||
const renames = new Map([[name, next]])
|
||||
schemas = rewriteRefs(schemas, renames) as Record<string, unknown>
|
||||
schemas[next] = schemas[name]
|
||||
delete schemas[name]
|
||||
document.paths = rewriteRefs(document.paths, renames) as Record<string, unknown> | undefined
|
||||
}
|
||||
document.components = { ...document.components, schemas }
|
||||
}
|
||||
|
||||
function componentTypeName(name: string) {
|
||||
if (!name.includes(".")) return name
|
||||
return name
|
||||
.split(".")
|
||||
.filter((part) => !/^\d+$/.test(part))
|
||||
.map((part) => part.slice(0, 1).toUpperCase() + part.slice(1))
|
||||
.join("")
|
||||
}
|
||||
|
||||
function deduplicateEquivalentComponent(document: OpenApiDocument, canonical: string, duplicate: string) {
|
||||
const schemas = document.components?.schemas
|
||||
if (!schemas?.[canonical] || !schemas[duplicate]) return
|
||||
if (JSON.stringify(normalizeSchema(schemas[canonical])) !== JSON.stringify(normalizeSchema(schemas[duplicate]))) {
|
||||
throw new Error(`${duplicate} no longer has the same wire shape as ${canonical}`)
|
||||
}
|
||||
|
||||
const renames = new Map([[duplicate, canonical]])
|
||||
const rewritten = rewriteRefs(schemas, renames) as Record<string, unknown>
|
||||
delete rewritten[duplicate]
|
||||
document.components = { ...document.components, schemas: rewritten }
|
||||
document.paths = rewriteRefs(document.paths, renames) as Record<string, unknown> | undefined
|
||||
}
|
||||
|
||||
function deduplicateEquivalentGeneratedTypes(source: string, canonical: string, duplicates: RegExp) {
|
||||
const canonicalType = generatedType(source, canonical)
|
||||
if (!canonicalType) throw new Error(`Generated canonical type missing: ${canonical}`)
|
||||
const names = [...source.matchAll(/export type (\w+) =/g)]
|
||||
.map((match) => match[1])
|
||||
.filter((name): name is string => name !== undefined && duplicates.test(name))
|
||||
|
||||
return names.reduce((patched, name) => {
|
||||
const duplicate = generatedType(patched, name)
|
||||
const currentCanonical = generatedType(patched, canonical)
|
||||
if (!duplicate || !currentCanonical) throw new Error(`Generated type declaration missing while comparing ${name}`)
|
||||
if (normalizeGeneratedType(currentCanonical.shape) !== normalizeGeneratedType(duplicate.shape)) {
|
||||
throw new Error(`${name} no longer has the same generated type shape as ${canonical}`)
|
||||
}
|
||||
return (patched.slice(0, duplicate.start) + patched.slice(duplicate.end)).replaceAll(name, canonical)
|
||||
}, source)
|
||||
}
|
||||
|
||||
function generatedType(source: string, name: string) {
|
||||
const start = source.indexOf(`export type ${name} =`)
|
||||
if (start === -1) return undefined
|
||||
const next = source.indexOf("\n\nexport type ", start + 1)
|
||||
const shapeEnd = next === -1 ? source.length : next
|
||||
return {
|
||||
start,
|
||||
end: next === -1 ? source.length : next + 2,
|
||||
shape: source.slice(source.indexOf("=", start) + 1, shapeEnd),
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeGeneratedType(shape: string) {
|
||||
return shape.replaceAll(/\s/g, "")
|
||||
}
|
||||
|
||||
function normalizeSchema(value: unknown, key?: string): unknown {
|
||||
if (Array.isArray(value)) {
|
||||
const flattened =
|
||||
key === "anyOf"
|
||||
? value.flatMap((item) =>
|
||||
typeof item === "object" && item !== null && Object.keys(item).length === 1 && "anyOf" in item
|
||||
? Array.isArray(item.anyOf)
|
||||
? item.anyOf
|
||||
: [item]
|
||||
: [item],
|
||||
)
|
||||
: value
|
||||
const expanded =
|
||||
key === "anyOf"
|
||||
? flattened.flatMap((item) => {
|
||||
if (typeof item !== "object" || item === null || !("type" in item) || !("enum" in item)) return [item]
|
||||
if (Object.keys(item).some((property) => property !== "type" && property !== "enum")) return [item]
|
||||
if (!Array.isArray(item.enum)) return [item]
|
||||
return item.enum.map((member) => ({ type: item.type, enum: [member] }))
|
||||
})
|
||||
: flattened
|
||||
const normalized = expanded.map((item) => normalizeSchema(item))
|
||||
return [...new Map(normalized.map((item) => [JSON.stringify(item), item])).values()].sort((a, b) =>
|
||||
JSON.stringify(a).localeCompare(JSON.stringify(b)),
|
||||
)
|
||||
}
|
||||
if (typeof value !== "object" || value === null) return value
|
||||
return Object.fromEntries(
|
||||
Object.entries(value)
|
||||
.sort(([left], [right]) => left.localeCompare(right))
|
||||
.map(([property, child]) => [property, normalizeSchema(child, property)]),
|
||||
)
|
||||
}
|
||||
|
||||
function rewriteRefs(value: unknown, renames: Map<string, string>): unknown {
|
||||
if (Array.isArray(value)) return value.map((item) => rewriteRefs(item, renames))
|
||||
if (typeof value !== "object" || value === null) return value
|
||||
|
||||
@@ -76,8 +76,8 @@ import type {
|
||||
FindTextResponses,
|
||||
FormatterStatusErrors,
|
||||
FormatterStatusResponses,
|
||||
FormCreatePayloadV2,
|
||||
FormReply,
|
||||
FormCreatePayload2,
|
||||
FormReply2,
|
||||
GlobalConfigGetErrors,
|
||||
GlobalConfigGetResponses,
|
||||
GlobalConfigUpdateErrors,
|
||||
@@ -92,7 +92,7 @@ import type {
|
||||
GlobalUpgradeResponses,
|
||||
InstanceDisposeErrors,
|
||||
InstanceDisposeResponses,
|
||||
LocationRefV2,
|
||||
LocationRef2,
|
||||
LspStatusErrors,
|
||||
LspStatusResponses,
|
||||
McpAddErrors,
|
||||
@@ -113,7 +113,7 @@ import type {
|
||||
McpRemoteConfig,
|
||||
McpStatusErrors,
|
||||
McpStatusResponses,
|
||||
ModelRef,
|
||||
ModelRef2,
|
||||
MoveSessionDestination,
|
||||
OutputFormat,
|
||||
Part as Part2,
|
||||
@@ -130,8 +130,8 @@ import type {
|
||||
PermissionRespondErrors,
|
||||
PermissionRespondResponses,
|
||||
PermissionRuleset,
|
||||
PermissionV2Reply,
|
||||
PermissionV2SourceV2,
|
||||
PermissionV2Reply2,
|
||||
PermissionV2Source2,
|
||||
ProjectCommands,
|
||||
ProjectCurrentErrors,
|
||||
ProjectCurrentResponses,
|
||||
@@ -144,9 +144,9 @@ import type {
|
||||
ProjectListResponses,
|
||||
ProjectUpdateErrors,
|
||||
ProjectUpdateResponses,
|
||||
PromptAgentAttachment,
|
||||
PromptInput,
|
||||
PromptInputFileAttachment,
|
||||
PromptAgentAttachment2,
|
||||
PromptInputFileAttachment2,
|
||||
PromptInputV2,
|
||||
ProviderAuthErrors,
|
||||
ProviderAuthResponses,
|
||||
ProviderListErrors,
|
||||
@@ -178,14 +178,14 @@ import type {
|
||||
QuestionRejectResponses,
|
||||
QuestionReplyErrors,
|
||||
QuestionReplyResponses,
|
||||
QuestionV2Reply,
|
||||
QuestionV2Reply2,
|
||||
SessionAbortErrors,
|
||||
SessionAbortResponses,
|
||||
SessionChildrenErrors,
|
||||
SessionChildrenResponses,
|
||||
SessionCommandErrors,
|
||||
SessionCommandResponses,
|
||||
SessionContextEntryKeyV2,
|
||||
SessionContextEntryKey2,
|
||||
SessionCreateErrors,
|
||||
SessionCreateResponses,
|
||||
SessionDeleteErrors,
|
||||
@@ -458,7 +458,7 @@ import type {
|
||||
VcsDiffResponses,
|
||||
VcsGetErrors,
|
||||
VcsGetResponses,
|
||||
VcsMode,
|
||||
VcsMode2,
|
||||
VcsStatusErrors,
|
||||
VcsStatusResponses,
|
||||
WorktreeCreateErrors,
|
||||
@@ -5290,7 +5290,7 @@ export class Entry extends HeyApiClient {
|
||||
public remove<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
sessionID: string
|
||||
key: SessionContextEntryKeyV2
|
||||
key: SessionContextEntryKey2
|
||||
},
|
||||
options?: Options<never, ThrowOnError>,
|
||||
) {
|
||||
@@ -5324,7 +5324,7 @@ export class Entry extends HeyApiClient {
|
||||
public put<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
sessionID: string
|
||||
key: SessionContextEntryKeyV2
|
||||
key: SessionContextEntryKey2
|
||||
value?: unknown
|
||||
},
|
||||
options?: Options<never, ThrowOnError>,
|
||||
@@ -5393,7 +5393,7 @@ export class Form extends HeyApiClient {
|
||||
public create<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
sessionID: string
|
||||
formCreatePayloadV2: FormCreatePayloadV2
|
||||
formCreatePayload: FormCreatePayload2
|
||||
},
|
||||
options?: Options<never, ThrowOnError>,
|
||||
) {
|
||||
@@ -5403,7 +5403,7 @@ export class Form extends HeyApiClient {
|
||||
{
|
||||
args: [
|
||||
{ in: "path", key: "sessionID" },
|
||||
{ key: "formCreatePayloadV2", map: "body" },
|
||||
{ key: "formCreatePayload", map: "body" },
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -5491,7 +5491,7 @@ export class Form extends HeyApiClient {
|
||||
parameters: {
|
||||
sessionID: string
|
||||
formID: string
|
||||
formReply: FormReply
|
||||
formReply: FormReply2
|
||||
},
|
||||
options?: Options<never, ThrowOnError>,
|
||||
) {
|
||||
@@ -5591,7 +5591,7 @@ export class Permission2 extends HeyApiClient {
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
source?: PermissionV2SourceV2
|
||||
source?: PermissionV2Source2
|
||||
agent?: string | null
|
||||
},
|
||||
options?: Options<never, ThrowOnError>,
|
||||
@@ -5672,7 +5672,7 @@ export class Permission2 extends HeyApiClient {
|
||||
parameters: {
|
||||
sessionID: string
|
||||
requestID: string
|
||||
reply?: PermissionV2Reply
|
||||
reply?: PermissionV2Reply2
|
||||
message?: string | null
|
||||
},
|
||||
options?: Options<never, ThrowOnError>,
|
||||
@@ -5740,7 +5740,7 @@ export class Question2 extends HeyApiClient {
|
||||
parameters: {
|
||||
sessionID: string
|
||||
requestID: string
|
||||
questionV2Reply: QuestionV2Reply
|
||||
questionV2Reply: QuestionV2Reply2
|
||||
},
|
||||
options?: Options<never, ThrowOnError>,
|
||||
) {
|
||||
@@ -5861,8 +5861,8 @@ export class Session3 extends HeyApiClient {
|
||||
parameters?: {
|
||||
id?: string | null
|
||||
agent?: string | null
|
||||
model?: ModelRef | null
|
||||
location?: LocationRefV2 | null
|
||||
model?: ModelRef2 | null
|
||||
location?: LocationRef2 | null
|
||||
},
|
||||
options?: Options<never, ThrowOnError>,
|
||||
) {
|
||||
@@ -6004,7 +6004,7 @@ export class Session3 extends HeyApiClient {
|
||||
public switchModel<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
sessionID: string
|
||||
model?: ModelRef
|
||||
model?: ModelRef2
|
||||
},
|
||||
options?: Options<never, ThrowOnError>,
|
||||
) {
|
||||
@@ -6079,7 +6079,7 @@ export class Session3 extends HeyApiClient {
|
||||
parameters: {
|
||||
sessionID: string
|
||||
id?: string | null
|
||||
prompt?: PromptInput
|
||||
prompt?: PromptInputV2
|
||||
delivery?: "steer" | "queue" | null
|
||||
resume?: boolean | null
|
||||
},
|
||||
@@ -6123,9 +6123,9 @@ export class Session3 extends HeyApiClient {
|
||||
command?: string
|
||||
arguments?: string | null
|
||||
agent?: string | null
|
||||
model?: ModelRef | null
|
||||
files?: Array<PromptInputFileAttachment>
|
||||
agents?: Array<PromptAgentAttachment>
|
||||
model?: ModelRef2 | null
|
||||
files?: Array<PromptInputFileAttachment2>
|
||||
agents?: Array<PromptAgentAttachment2>
|
||||
delivery?: "steer" | "queue" | null
|
||||
resume?: boolean | null
|
||||
},
|
||||
@@ -6282,35 +6282,19 @@ export class Session3 extends HeyApiClient {
|
||||
/**
|
||||
* Compact session
|
||||
*
|
||||
* Queue a durable session compaction request.
|
||||
* Compact a session conversation.
|
||||
*/
|
||||
public compact<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
sessionID: string
|
||||
id?: string | null
|
||||
},
|
||||
options?: Options<never, ThrowOnError>,
|
||||
) {
|
||||
const params = buildClientParams(
|
||||
[parameters],
|
||||
[
|
||||
{
|
||||
args: [
|
||||
{ in: "path", key: "sessionID" },
|
||||
{ in: "body", key: "id" },
|
||||
],
|
||||
},
|
||||
],
|
||||
)
|
||||
const params = buildClientParams([parameters], [{ args: [{ in: "path", key: "sessionID" }] }])
|
||||
return (options?.client ?? this.client).post<V2SessionCompactResponses, V2SessionCompactErrors, ThrowOnError>({
|
||||
url: "/api/session/{sessionID}/compact",
|
||||
...options,
|
||||
...params,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
...options?.headers,
|
||||
...params.headers,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -6573,7 +6557,7 @@ export class Generate extends HeyApiClient {
|
||||
workspace?: string | null
|
||||
} | null
|
||||
prompt?: string
|
||||
model?: ModelRef | null
|
||||
model?: ModelRef2 | null
|
||||
},
|
||||
options?: Options<never, ThrowOnError>,
|
||||
) {
|
||||
@@ -8027,7 +8011,7 @@ export class Vcs2 extends HeyApiClient {
|
||||
directory?: string | null
|
||||
workspace?: string | null
|
||||
} | null
|
||||
mode: VcsMode
|
||||
mode: VcsMode2
|
||||
context?: string | null
|
||||
},
|
||||
options?: Options<never, ThrowOnError>,
|
||||
|
||||
+3216
-2392
@@ -50,11 +50,9 @@ export type Event =
|
||||
| EventSessionToolSuccess
|
||||
| EventSessionToolFailed
|
||||
| EventSessionRetryScheduled
|
||||
| EventSessionCompactionAdmitted
|
||||
| EventSessionCompactionStarted
|
||||
| EventSessionCompactionDelta
|
||||
| EventSessionCompactionEnded
|
||||
| EventSessionCompactionFailed
|
||||
| EventSessionRevertStaged
|
||||
| EventSessionRevertCleared
|
||||
| EventSessionRevertCommitted
|
||||
@@ -1050,7 +1048,6 @@ export type GlobalEvent = {
|
||||
properties: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
ordinal: number
|
||||
}
|
||||
}
|
||||
| {
|
||||
@@ -1059,7 +1056,6 @@ export type GlobalEvent = {
|
||||
properties: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
ordinal: number
|
||||
delta: string
|
||||
}
|
||||
}
|
||||
@@ -1069,7 +1065,6 @@ export type GlobalEvent = {
|
||||
properties: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
ordinal: number
|
||||
text: string
|
||||
}
|
||||
}
|
||||
@@ -1079,7 +1074,6 @@ export type GlobalEvent = {
|
||||
properties: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
ordinal: number
|
||||
state?: SessionMessageProviderState
|
||||
}
|
||||
}
|
||||
@@ -1089,7 +1083,6 @@ export type GlobalEvent = {
|
||||
properties: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
ordinal: number
|
||||
delta: string
|
||||
}
|
||||
}
|
||||
@@ -1099,7 +1092,6 @@ export type GlobalEvent = {
|
||||
properties: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
ordinal: number
|
||||
text: string
|
||||
state?: SessionMessageProviderState
|
||||
}
|
||||
@@ -1202,14 +1194,6 @@ export type GlobalEvent = {
|
||||
error: SessionStructuredError
|
||||
}
|
||||
}
|
||||
| {
|
||||
id: string
|
||||
type: "session.compaction.admitted"
|
||||
properties: {
|
||||
sessionID: string
|
||||
inputID: string
|
||||
}
|
||||
}
|
||||
| {
|
||||
id: string
|
||||
type: "session.compaction.started"
|
||||
@@ -1236,13 +1220,6 @@ export type GlobalEvent = {
|
||||
recent: string
|
||||
}
|
||||
}
|
||||
| {
|
||||
id: string
|
||||
type: "session.compaction.failed"
|
||||
properties: {
|
||||
sessionID: string
|
||||
}
|
||||
}
|
||||
| {
|
||||
id: string
|
||||
type: "session.revert.staged"
|
||||
@@ -1782,10 +1759,8 @@ export type GlobalEvent = {
|
||||
| SyncEventSessionToolSuccess
|
||||
| SyncEventSessionToolFailed
|
||||
| SyncEventSessionRetryScheduled
|
||||
| SyncEventSessionCompactionAdmitted
|
||||
| SyncEventSessionCompactionStarted
|
||||
| SyncEventSessionCompactionEnded
|
||||
| SyncEventSessionCompactionFailed
|
||||
| SyncEventSessionRevertStaged
|
||||
| SyncEventSessionRevertCleared
|
||||
| SyncEventSessionRevertCommitted
|
||||
@@ -2956,10 +2931,8 @@ export type SessionDurableEvent =
|
||||
| SessionToolSuccess
|
||||
| SessionToolFailed
|
||||
| SessionRetryScheduled
|
||||
| SessionCompactionAdmitted
|
||||
| SessionCompactionStarted
|
||||
| SessionCompactionEnded
|
||||
| SessionCompactionFailed
|
||||
| SessionRevertStaged
|
||||
| SessionRevertCleared
|
||||
| SessionRevertCommitted
|
||||
@@ -3106,11 +3079,9 @@ export type V2Event =
|
||||
| SessionToolSuccess
|
||||
| SessionToolFailed
|
||||
| SessionRetryScheduled
|
||||
| SessionCompactionAdmitted
|
||||
| SessionCompactionStarted
|
||||
| SessionCompactionDelta
|
||||
| SessionCompactionEnded
|
||||
| SessionCompactionFailed
|
||||
| SessionRevertStaged
|
||||
| SessionRevertCleared
|
||||
| SessionRevertCommitted
|
||||
@@ -3324,10 +3295,83 @@ export type PromptAgentAttachment = {
|
||||
source?: PromptSource
|
||||
}
|
||||
|
||||
export type SessionStructuredError = {
|
||||
type: string
|
||||
message: string
|
||||
}
|
||||
export type SessionStructuredError =
|
||||
| {
|
||||
type: "provider.rate-limit"
|
||||
message: string
|
||||
retryAfterMs?: number
|
||||
}
|
||||
| {
|
||||
type: "provider.auth"
|
||||
message: string
|
||||
}
|
||||
| {
|
||||
type: "provider.quota"
|
||||
message: string
|
||||
}
|
||||
| {
|
||||
type: "provider.content-filter"
|
||||
message: string
|
||||
}
|
||||
| {
|
||||
type: "provider.transport"
|
||||
message: string
|
||||
}
|
||||
| {
|
||||
type: "provider.internal"
|
||||
message: string
|
||||
}
|
||||
| {
|
||||
type: "provider.invalid-output"
|
||||
message: string
|
||||
}
|
||||
| {
|
||||
type: "provider.invalid-request"
|
||||
message: string
|
||||
}
|
||||
| {
|
||||
type: "provider.no-route"
|
||||
message: string
|
||||
}
|
||||
| {
|
||||
type: "provider.unknown"
|
||||
message: string
|
||||
}
|
||||
| {
|
||||
type: "permission.rejected"
|
||||
message: string
|
||||
permission: string
|
||||
resources: Array<string>
|
||||
}
|
||||
| {
|
||||
type: "tool.unknown"
|
||||
message: string
|
||||
name: string
|
||||
}
|
||||
| {
|
||||
type: "tool.stale"
|
||||
message: string
|
||||
name?: string
|
||||
}
|
||||
| {
|
||||
type: "tool.execution"
|
||||
message: string
|
||||
}
|
||||
| {
|
||||
type: "tool.result-missing"
|
||||
message: string
|
||||
callID?: string
|
||||
}
|
||||
| {
|
||||
type: "aborted"
|
||||
message: string
|
||||
reason?: "user" | "shutdown" | "timeout"
|
||||
}
|
||||
| {
|
||||
type: "unknown"
|
||||
message: string
|
||||
agent?: string
|
||||
}
|
||||
|
||||
export type SessionMessageProviderState = {
|
||||
[key: string]: unknown
|
||||
@@ -3983,7 +4027,6 @@ export type SyncEventSessionTextStarted = {
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
ordinal: number
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3999,7 +4042,6 @@ export type SyncEventSessionTextEnded = {
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
ordinal: number
|
||||
text: string
|
||||
}
|
||||
}
|
||||
@@ -4016,7 +4058,6 @@ export type SyncEventSessionReasoningStarted = {
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
ordinal: number
|
||||
state?: SessionMessageProviderState
|
||||
}
|
||||
}
|
||||
@@ -4033,7 +4074,6 @@ export type SyncEventSessionReasoningEnded = {
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
ordinal: number
|
||||
text: string
|
||||
state?: SessionMessageProviderState
|
||||
}
|
||||
@@ -4177,21 +4217,6 @@ export type SyncEventSessionRetryScheduled = {
|
||||
}
|
||||
}
|
||||
|
||||
export type SyncEventSessionCompactionAdmitted = {
|
||||
type: "sync"
|
||||
id: string
|
||||
syncEvent: {
|
||||
type: "session.compaction.admitted.1"
|
||||
id: string
|
||||
seq: number
|
||||
aggregateID: string
|
||||
data: {
|
||||
sessionID: string
|
||||
inputID: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export type SyncEventSessionCompactionStarted = {
|
||||
type: "sync"
|
||||
id: string
|
||||
@@ -4224,20 +4249,6 @@ export type SyncEventSessionCompactionEnded = {
|
||||
}
|
||||
}
|
||||
|
||||
export type SyncEventSessionCompactionFailed = {
|
||||
type: "sync"
|
||||
id: string
|
||||
syncEvent: {
|
||||
type: "session.compaction.failed.1"
|
||||
id: string
|
||||
seq: number
|
||||
aggregateID: string
|
||||
data: {
|
||||
sessionID: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export type SyncEventSessionRevertStaged = {
|
||||
type: "sync"
|
||||
id: string
|
||||
@@ -4408,15 +4419,6 @@ export type SessionInputAdmitted = {
|
||||
promotedSeq?: number
|
||||
}
|
||||
|
||||
export type SessionInputCompaction = {
|
||||
type: "compaction"
|
||||
admittedSeq: number
|
||||
id: string
|
||||
sessionID: string
|
||||
timeCreated: number
|
||||
handledSeq?: number
|
||||
}
|
||||
|
||||
export type SessionMessageAgentSelected = {
|
||||
id: string
|
||||
metadata?: {
|
||||
@@ -4439,7 +4441,6 @@ export type SessionMessageModelSelected = {
|
||||
}
|
||||
type: "model-switched"
|
||||
model: ModelRef
|
||||
previous?: ModelRef
|
||||
}
|
||||
|
||||
export type SessionMessageUser = {
|
||||
@@ -4633,7 +4634,6 @@ export type SessionMessageAssistant = {
|
||||
|
||||
export type SessionMessageCompaction = {
|
||||
type: "compaction"
|
||||
status: "queued" | "running" | "completed" | "failed"
|
||||
reason: "auto" | "manual"
|
||||
summary: string
|
||||
recent: string
|
||||
@@ -5071,7 +5071,6 @@ export type SessionTextStarted = {
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
ordinal: number
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5091,7 +5090,6 @@ export type SessionTextEnded = {
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
ordinal: number
|
||||
text: string
|
||||
}
|
||||
}
|
||||
@@ -5112,7 +5110,6 @@ export type SessionReasoningStarted = {
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
ordinal: number
|
||||
state?: SessionMessageProviderState
|
||||
}
|
||||
}
|
||||
@@ -5133,7 +5130,6 @@ export type SessionReasoningEnded = {
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
ordinal: number
|
||||
text: string
|
||||
state?: SessionMessageProviderState
|
||||
}
|
||||
@@ -5304,25 +5300,6 @@ export type SessionRetryScheduled = {
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionCompactionAdmitted = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.compaction.admitted"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef
|
||||
data: {
|
||||
sessionID: string
|
||||
inputID: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionCompactionStarted = {
|
||||
id: string
|
||||
created: number
|
||||
@@ -5363,24 +5340,6 @@ export type SessionCompactionEnded = {
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionCompactionFailed = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.compaction.failed"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef
|
||||
data: {
|
||||
sessionID: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionRevertStaged = {
|
||||
id: string
|
||||
created: number
|
||||
@@ -5975,7 +5934,6 @@ export type SessionTextDelta = {
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
ordinal: number
|
||||
delta: string
|
||||
}
|
||||
}
|
||||
@@ -5991,7 +5949,6 @@ export type SessionReasoningDelta = {
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
ordinal: number
|
||||
delta: string
|
||||
}
|
||||
}
|
||||
@@ -7191,7 +7148,6 @@ export type EventSessionTextStarted = {
|
||||
properties: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
ordinal: number
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7201,7 +7157,6 @@ export type EventSessionTextDelta = {
|
||||
properties: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
ordinal: number
|
||||
delta: string
|
||||
}
|
||||
}
|
||||
@@ -7212,7 +7167,6 @@ export type EventSessionTextEnded = {
|
||||
properties: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
ordinal: number
|
||||
text: string
|
||||
}
|
||||
}
|
||||
@@ -7223,7 +7177,6 @@ export type EventSessionReasoningStarted = {
|
||||
properties: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
ordinal: number
|
||||
state?: SessionMessageProviderState
|
||||
}
|
||||
}
|
||||
@@ -7234,7 +7187,6 @@ export type EventSessionReasoningDelta = {
|
||||
properties: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
ordinal: number
|
||||
delta: string
|
||||
}
|
||||
}
|
||||
@@ -7245,7 +7197,6 @@ export type EventSessionReasoningEnded = {
|
||||
properties: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
ordinal: number
|
||||
text: string
|
||||
state?: SessionMessageProviderState
|
||||
}
|
||||
@@ -7357,15 +7308,6 @@ export type EventSessionRetryScheduled = {
|
||||
}
|
||||
}
|
||||
|
||||
export type EventSessionCompactionAdmitted = {
|
||||
id: string
|
||||
type: "session.compaction.admitted"
|
||||
properties: {
|
||||
sessionID: string
|
||||
inputID: string
|
||||
}
|
||||
}
|
||||
|
||||
export type EventSessionCompactionStarted = {
|
||||
id: string
|
||||
type: "session.compaction.started"
|
||||
@@ -7395,14 +7337,6 @@ export type EventSessionCompactionEnded = {
|
||||
}
|
||||
}
|
||||
|
||||
export type EventSessionCompactionFailed = {
|
||||
id: string
|
||||
type: "session.compaction.failed"
|
||||
properties: {
|
||||
sessionID: string
|
||||
}
|
||||
}
|
||||
|
||||
export type EventSessionRevertStaged = {
|
||||
id: string
|
||||
type: "session.revert.staged"
|
||||
@@ -7971,6 +7905,11 @@ export type BadRequestError = {
|
||||
}
|
||||
}
|
||||
|
||||
export type UnauthorizedErrorV2 = {
|
||||
_tag: "UnauthorizedError"
|
||||
message: string
|
||||
}
|
||||
|
||||
export type InvalidRequestErrorV2 = {
|
||||
_tag: "InvalidRequestError"
|
||||
message: string
|
||||
@@ -7978,6 +7917,112 @@ export type InvalidRequestErrorV2 = {
|
||||
field?: string | null
|
||||
}
|
||||
|
||||
export type LocationInfo2 = {
|
||||
directory: string
|
||||
workspaceID?: string
|
||||
project: {
|
||||
id: string
|
||||
directory: string
|
||||
}
|
||||
}
|
||||
|
||||
export type ModelRef2 = {
|
||||
id: string
|
||||
providerID: string
|
||||
variant?: string
|
||||
}
|
||||
|
||||
export type ProviderSettings2 = {
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export type ProviderRequest2 = {
|
||||
settings: ProviderSettings2
|
||||
headers: {
|
||||
[key: string]: string
|
||||
}
|
||||
body: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
}
|
||||
|
||||
export type AgentColor2 = string | "primary" | "secondary" | "accent" | "success" | "warning" | "error" | "info"
|
||||
|
||||
export type PermissionV2Effect2 = "allow" | "deny" | "ask"
|
||||
|
||||
export type PermissionV2Rule2 = {
|
||||
action: string
|
||||
resource: string
|
||||
effect: PermissionV2Effect2
|
||||
}
|
||||
|
||||
export type PermissionV2Ruleset2 = Array<PermissionV2Rule2>
|
||||
|
||||
export type AgentV2Info2 = {
|
||||
id: string
|
||||
model?: ModelRef2
|
||||
request: ProviderRequest2
|
||||
system?: string
|
||||
description?: string
|
||||
mode: "subagent" | "primary" | "all"
|
||||
hidden: boolean
|
||||
color?: AgentColor2
|
||||
steps?: number
|
||||
permissions: PermissionV2Ruleset2
|
||||
}
|
||||
|
||||
export type PluginInfo2 = {
|
||||
id: string
|
||||
}
|
||||
|
||||
export type LocationRef2 = {
|
||||
directory: string
|
||||
workspaceID?: string
|
||||
}
|
||||
|
||||
export type FileDiff2 = {
|
||||
path: string
|
||||
status: "added" | "modified" | "deleted"
|
||||
additions: number
|
||||
deletions: number
|
||||
patch: string
|
||||
}
|
||||
|
||||
export type RevertState2 = {
|
||||
messageID: string
|
||||
partID?: string
|
||||
snapshot?: string
|
||||
diff?: string
|
||||
files?: Array<FileDiff2>
|
||||
}
|
||||
|
||||
export type SessionV2Info2 = {
|
||||
id: string
|
||||
parentID?: string
|
||||
projectID: string
|
||||
agent?: string
|
||||
model?: ModelRef2
|
||||
cost: number
|
||||
tokens: {
|
||||
input: number
|
||||
output: number
|
||||
reasoning: number
|
||||
cache: {
|
||||
read: number
|
||||
write: number
|
||||
}
|
||||
}
|
||||
time: {
|
||||
created: number
|
||||
updated: number
|
||||
archived?: number
|
||||
}
|
||||
title: string
|
||||
location: LocationRef2
|
||||
subpath?: string
|
||||
revert?: RevertState2
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@@ -7986,7 +8031,7 @@ export type SessionWatermarksV2 = {
|
||||
}
|
||||
|
||||
export type SessionsResponseV2 = {
|
||||
data: Array<SessionV2InfoV2>
|
||||
data: Array<SessionV2Info2>
|
||||
watermarks: SessionWatermarksV2
|
||||
cursor: {
|
||||
previous?: string | null
|
||||
@@ -7994,6 +8039,11 @@ export type SessionsResponseV2 = {
|
||||
}
|
||||
}
|
||||
|
||||
export type InvalidCursorErrorV2 = {
|
||||
_tag: "InvalidCursorError"
|
||||
message: string
|
||||
}
|
||||
|
||||
export type InvalidRequestError1 = {
|
||||
_tag: "InvalidRequestError"
|
||||
message: string
|
||||
@@ -8001,12 +8051,101 @@ export type InvalidRequestError1 = {
|
||||
field?: string | null
|
||||
}
|
||||
|
||||
export type SessionActiveV2 = {
|
||||
type: "running"
|
||||
}
|
||||
|
||||
export type SessionNotFoundErrorV2 = {
|
||||
_tag: "SessionNotFoundError"
|
||||
sessionID: string
|
||||
message: string
|
||||
}
|
||||
|
||||
export type MessageNotFoundErrorV2 = {
|
||||
_tag: "MessageNotFoundError"
|
||||
sessionID: string
|
||||
messageID: string
|
||||
message: string
|
||||
}
|
||||
|
||||
export type PromptSource2 = {
|
||||
start: number
|
||||
end: number
|
||||
text: string
|
||||
}
|
||||
|
||||
export type PromptInputFileAttachment2 = {
|
||||
uri: string
|
||||
name?: string
|
||||
description?: string
|
||||
source?: PromptSource2
|
||||
}
|
||||
|
||||
export type PromptAgentAttachment2 = {
|
||||
name: string
|
||||
source?: PromptSource2
|
||||
}
|
||||
|
||||
export type PromptInputV2 = {
|
||||
text: string
|
||||
files?: Array<PromptInputFileAttachment2>
|
||||
agents?: Array<PromptAgentAttachment2>
|
||||
}
|
||||
|
||||
export type PromptFileAttachment2 = {
|
||||
uri: string
|
||||
mime: string
|
||||
name?: string
|
||||
description?: string
|
||||
source?: PromptSource2
|
||||
}
|
||||
|
||||
export type PromptV2 = {
|
||||
text: string
|
||||
files?: Array<PromptFileAttachment2>
|
||||
agents?: Array<PromptAgentAttachment2>
|
||||
}
|
||||
|
||||
export type SessionInputAdmitted2 = {
|
||||
admittedSeq: number
|
||||
id: string
|
||||
sessionID: string
|
||||
prompt: PromptV2
|
||||
delivery: "steer" | "queue"
|
||||
timeCreated: number
|
||||
promotedSeq?: number
|
||||
}
|
||||
|
||||
export type ConflictErrorV2 = {
|
||||
_tag: "ConflictError"
|
||||
message: string
|
||||
resource?: string | null
|
||||
}
|
||||
|
||||
export type CommandNotFoundErrorV2 = {
|
||||
_tag: "CommandNotFoundError"
|
||||
command: string
|
||||
message: string
|
||||
}
|
||||
|
||||
export type CommandEvaluationErrorV2 = {
|
||||
_tag: "CommandEvaluationError"
|
||||
command: string
|
||||
message: string
|
||||
}
|
||||
|
||||
export type SkillNotFoundErrorV2 = {
|
||||
_tag: "SkillNotFoundError"
|
||||
skill: string
|
||||
message: string
|
||||
}
|
||||
|
||||
export type SessionBusyErrorV2 = {
|
||||
_tag: "SessionBusyError"
|
||||
sessionID: string
|
||||
message: string
|
||||
}
|
||||
|
||||
export type ServiceUnavailableErrorV2 = {
|
||||
_tag: "ServiceUnavailableError"
|
||||
message: string
|
||||
@@ -8019,6 +8158,83 @@ export type UnknownErrorV2 = {
|
||||
ref?: string | null
|
||||
}
|
||||
|
||||
export type SessionMessageAgentSelected2 = {
|
||||
id: string
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
time: {
|
||||
created: number
|
||||
}
|
||||
type: "agent-switched"
|
||||
agent: string
|
||||
}
|
||||
|
||||
export type SessionMessageModelSelected2 = {
|
||||
id: string
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
time: {
|
||||
created: number
|
||||
}
|
||||
type: "model-switched"
|
||||
model: ModelRef2
|
||||
}
|
||||
|
||||
export type SessionMessageUser2 = {
|
||||
id: string
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
time: {
|
||||
created: number
|
||||
}
|
||||
text: string
|
||||
files?: Array<PromptFileAttachment2>
|
||||
agents?: Array<PromptAgentAttachment2>
|
||||
type: "user"
|
||||
}
|
||||
|
||||
export type SessionMessageSynthetic2 = {
|
||||
id: string
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
time: {
|
||||
created: number
|
||||
}
|
||||
sessionID: string
|
||||
text: string
|
||||
description?: string
|
||||
type: "synthetic"
|
||||
}
|
||||
|
||||
export type SessionMessageSystem2 = {
|
||||
id: string
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
time: {
|
||||
created: number
|
||||
}
|
||||
type: "system"
|
||||
text: string
|
||||
}
|
||||
|
||||
export type SessionMessageSkill2 = {
|
||||
id: string
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
time: {
|
||||
created: number
|
||||
}
|
||||
type: "skill"
|
||||
name: string
|
||||
text: string
|
||||
}
|
||||
|
||||
export type ShellV2 = {
|
||||
id: string
|
||||
status: "running" | "exited" | "timeout" | "killed"
|
||||
@@ -8037,8 +8253,1017 @@ export type ShellV2 = {
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionMessageShell2 = {
|
||||
id: string
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
time: {
|
||||
created: number
|
||||
completed?: number
|
||||
}
|
||||
type: "shell"
|
||||
shell: ShellV2
|
||||
output?: {
|
||||
output: string
|
||||
cursor: number
|
||||
size: number
|
||||
truncated: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionMessageAssistantText2 = {
|
||||
type: "text"
|
||||
text: string
|
||||
}
|
||||
|
||||
export type SessionMessageProviderState2 = {
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export type SessionMessageAssistantReasoning2 = {
|
||||
type: "reasoning"
|
||||
text: string
|
||||
state?: SessionMessageProviderState2
|
||||
time?: {
|
||||
created: number
|
||||
completed?: number
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionMessageToolStatePending2 = {
|
||||
status: "pending"
|
||||
input: string
|
||||
}
|
||||
|
||||
export type ToolTextContent2 = {
|
||||
type: "text"
|
||||
text: string
|
||||
}
|
||||
|
||||
export type ToolFileContent2 = {
|
||||
type: "file"
|
||||
uri: string
|
||||
mime: string
|
||||
name?: string
|
||||
}
|
||||
|
||||
export type LlmToolContent2 = ToolTextContent2 | ToolFileContent2
|
||||
|
||||
export type SessionMessageToolStateRunning2 = {
|
||||
status: "running"
|
||||
input: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
structured: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
content: Array<LlmToolContent2>
|
||||
}
|
||||
|
||||
export type SessionMessageToolStateCompleted2 = {
|
||||
status: "completed"
|
||||
input: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
attachments?: Array<PromptFileAttachment2>
|
||||
content: Array<LlmToolContent2>
|
||||
outputPaths?: Array<string>
|
||||
structured: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
result?: unknown
|
||||
}
|
||||
|
||||
export type SessionMessageToolStateError2 = {
|
||||
status: "error"
|
||||
input: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
content: Array<LlmToolContent2>
|
||||
structured: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
error: SessionStructuredError
|
||||
result?: unknown
|
||||
}
|
||||
|
||||
export type SessionMessageAssistantTool2 = {
|
||||
type: "tool"
|
||||
id: string
|
||||
name: string
|
||||
executed?: boolean
|
||||
providerState?: SessionMessageProviderState2
|
||||
providerResultState?: SessionMessageProviderState2
|
||||
state:
|
||||
| SessionMessageToolStatePending2
|
||||
| SessionMessageToolStateRunning2
|
||||
| SessionMessageToolStateCompleted2
|
||||
| SessionMessageToolStateError2
|
||||
time: {
|
||||
created: number
|
||||
ran?: number
|
||||
completed?: number
|
||||
pruned?: number
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionMessageAssistantRetry2 = {
|
||||
attempt: number
|
||||
at: number
|
||||
error: SessionStructuredError
|
||||
}
|
||||
|
||||
export type SessionMessageAssistant2 = {
|
||||
id: string
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
time: {
|
||||
created: number
|
||||
completed?: number
|
||||
}
|
||||
type: "assistant"
|
||||
agent: string
|
||||
model: ModelRef2
|
||||
content: Array<SessionMessageAssistantText2 | SessionMessageAssistantReasoning2 | SessionMessageAssistantTool2>
|
||||
snapshot?: {
|
||||
start?: string
|
||||
end?: string
|
||||
files?: Array<string>
|
||||
}
|
||||
finish?: "stop" | "length" | "tool-calls" | "content-filter" | "error" | "unknown"
|
||||
cost?: number
|
||||
tokens?: {
|
||||
input: number
|
||||
output: number
|
||||
reasoning: number
|
||||
cache: {
|
||||
read: number
|
||||
write: number
|
||||
}
|
||||
}
|
||||
error?: SessionStructuredError
|
||||
retry?: SessionMessageAssistantRetry2
|
||||
}
|
||||
|
||||
export type SessionMessageCompaction2 = {
|
||||
type: "compaction"
|
||||
reason: "auto" | "manual"
|
||||
summary: string
|
||||
recent: string
|
||||
id: string
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
time: {
|
||||
created: number
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionMessage2 =
|
||||
| SessionMessageAgentSelected2
|
||||
| SessionMessageModelSelected2
|
||||
| SessionMessageUser2
|
||||
| SessionMessageSynthetic2
|
||||
| SessionMessageSystem2
|
||||
| SessionMessageSkill2
|
||||
| SessionMessageShell2
|
||||
| SessionMessageAssistant2
|
||||
| SessionMessageCompaction2
|
||||
|
||||
/**
|
||||
* Context entry key (lowercase alphanumerics plus . _ -)
|
||||
*/
|
||||
export type SessionContextEntryKey2 = string
|
||||
|
||||
export type SessionContextEntryInfo2 = {
|
||||
key: SessionContextEntryKey2
|
||||
value: unknown
|
||||
}
|
||||
|
||||
export type SessionAgentSelected2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.agent.selected"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
agent: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionModelSelected2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.model.selected"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
model: ModelRef2
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionMoved2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.moved"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
location: LocationRef2
|
||||
subpath?: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionRenamed2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.renamed"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
title: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionForked2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.forked"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
parentID: string
|
||||
from?: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionPromptPromoted2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.prompt.promoted"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
inputID: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionPromptAdmitted2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.prompt.admitted"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
inputID: string
|
||||
prompt: PromptV2
|
||||
delivery: "steer" | "queue"
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionExecutionStarted2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.execution.started"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionExecutionSucceeded2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.execution.succeeded"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionExecutionFailed2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.execution.failed"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
error: SessionStructuredError
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionExecutionInterrupted2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.execution.interrupted"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
reason: "user" | "shutdown" | "superseded"
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionContextUpdated2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.context.updated"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
text: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionSynthetic2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.synthetic"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
text: string
|
||||
description?: string
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionSkillActivated2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.skill.activated"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
name: string
|
||||
text: string
|
||||
}
|
||||
}
|
||||
|
||||
export type Shell1V2 = {
|
||||
id: string
|
||||
status: "running" | "exited" | "timeout" | "killed"
|
||||
command: string
|
||||
cwd: string
|
||||
shell: string
|
||||
file: string
|
||||
pid?: number
|
||||
exit?: number | "NaN" | "Infinity" | "-Infinity"
|
||||
metadata: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
time: {
|
||||
started: number | "NaN" | "Infinity" | "-Infinity"
|
||||
completed?: number | "NaN" | "Infinity" | "-Infinity"
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionShellStarted2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.shell.started"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
shell: Shell1V2
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionShellEnded2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.shell.ended"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
shell: Shell1V2
|
||||
output: {
|
||||
output: string
|
||||
cursor: number
|
||||
size: number
|
||||
truncated: boolean
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionStepStarted2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.step.started"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
agent: string
|
||||
model: ModelRef2
|
||||
snapshot?: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionStepEnded2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.step.ended"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
finish: "stop" | "length" | "tool-calls" | "content-filter" | "error" | "unknown"
|
||||
cost: number
|
||||
tokens: {
|
||||
input: number
|
||||
output: number
|
||||
reasoning: number
|
||||
cache: {
|
||||
read: number
|
||||
write: number
|
||||
}
|
||||
}
|
||||
snapshot?: string
|
||||
files?: Array<string>
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionStepFailed2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.step.failed"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
error: SessionStructuredError
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionTextStarted2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.text.started"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionTextEnded2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.text.ended"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
text: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionMessageProviderState3 = {
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export type SessionReasoningStarted2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.reasoning.started"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
state?: SessionMessageProviderState3
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionMessageProviderState4 = {
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export type SessionReasoningEnded2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.reasoning.ended"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
text: string
|
||||
state?: SessionMessageProviderState4
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionToolInputStarted2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.tool.input.started"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
callID: string
|
||||
name: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionToolInputEnded2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.tool.input.ended"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
callID: string
|
||||
text: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionMessageProviderState5 = {
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export type SessionToolCalled2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.tool.called"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
callID: string
|
||||
input: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
executed: boolean
|
||||
state?: SessionMessageProviderState5
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionToolProgress2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.tool.progress"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
callID: string
|
||||
structured: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
content: Array<LlmToolContent2>
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionMessageProviderState6 = {
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export type SessionToolSuccess2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.tool.success"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
callID: string
|
||||
structured: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
content: Array<LlmToolContent2>
|
||||
outputPaths?: Array<string>
|
||||
result?: unknown
|
||||
executed: boolean
|
||||
resultState?: SessionMessageProviderState6
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionMessageProviderState7 = {
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export type SessionToolFailed2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.tool.failed"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
callID: string
|
||||
error: SessionStructuredError
|
||||
result?: unknown
|
||||
executed: boolean
|
||||
resultState?: SessionMessageProviderState7
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionRetryScheduled2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.retry.scheduled"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
attempt: number
|
||||
at: number
|
||||
error: SessionStructuredError
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionCompactionStarted2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.compaction.started"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
reason: "auto" | "manual"
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionCompactionEnded2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.compaction.ended"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
reason: "auto" | "manual"
|
||||
text: string
|
||||
recent: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionRevertStaged2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.revert.staged"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
revert: RevertState2
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionRevertCleared2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.revert.cleared"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionRevertCommitted2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.revert.committed"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
to: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionDurableEventV2 =
|
||||
| SessionAgentSelected2
|
||||
| SessionModelSelected2
|
||||
| SessionMoved2
|
||||
| SessionRenamed2
|
||||
| SessionForked2
|
||||
| SessionPromptPromoted2
|
||||
| SessionPromptAdmitted2
|
||||
| SessionExecutionStarted2
|
||||
| SessionExecutionSucceeded2
|
||||
| SessionExecutionFailed2
|
||||
| SessionExecutionInterrupted2
|
||||
| SessionContextUpdated2
|
||||
| SessionSynthetic2
|
||||
| SessionSkillActivated2
|
||||
| SessionShellStarted2
|
||||
| SessionShellEnded2
|
||||
| SessionStepStarted2
|
||||
| SessionStepEnded2
|
||||
| SessionStepFailed2
|
||||
| SessionTextStarted2
|
||||
| SessionTextEnded2
|
||||
| SessionReasoningStarted2
|
||||
| SessionReasoningEnded2
|
||||
| SessionToolInputStarted2
|
||||
| SessionToolInputEnded2
|
||||
| SessionToolCalled2
|
||||
| SessionToolProgress2
|
||||
| SessionToolSuccess2
|
||||
| SessionToolFailed2
|
||||
| SessionRetryScheduled2
|
||||
| SessionCompactionStarted2
|
||||
| SessionCompactionEnded2
|
||||
| SessionRevertStaged2
|
||||
| SessionRevertCleared2
|
||||
| SessionRevertCommitted2
|
||||
|
||||
/**
|
||||
* Marker emitted once when a log read reaches its captured watermark. The reader holds every event committed at or below seq.
|
||||
*/
|
||||
export type EventLogSynced2 = {
|
||||
type: "log.synced"
|
||||
aggregateID: string
|
||||
seq?: number
|
||||
}
|
||||
|
||||
export type SessionLogItemV2 = SessionDurableEventV2 | EventLogSynced2
|
||||
|
||||
export type SessionLogItemStreamV2 = string
|
||||
|
||||
export type SessionMessagesResponseV2 = {
|
||||
data: Array<SessionMessage>
|
||||
data: Array<SessionMessage2>
|
||||
watermark?: number
|
||||
cursor: {
|
||||
previous?: string | null
|
||||
@@ -8046,6 +9271,588 @@ export type SessionMessagesResponseV2 = {
|
||||
}
|
||||
}
|
||||
|
||||
export type ModelApi2 =
|
||||
| {
|
||||
id: string
|
||||
type: "aisdk"
|
||||
package: string
|
||||
url?: string
|
||||
settings?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
}
|
||||
| {
|
||||
id: string
|
||||
type: "native"
|
||||
url?: string
|
||||
settings: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
}
|
||||
|
||||
export type ModelCapabilities2 = {
|
||||
tools: boolean
|
||||
input: Array<string>
|
||||
output: Array<string>
|
||||
}
|
||||
|
||||
export type ModelCost2 = {
|
||||
tier?: {
|
||||
type: "context"
|
||||
size: number
|
||||
}
|
||||
input: number
|
||||
output: number
|
||||
cache: {
|
||||
read: number
|
||||
write: number
|
||||
}
|
||||
}
|
||||
|
||||
export type ModelV2Info2 = {
|
||||
id: string
|
||||
providerID: string
|
||||
family?: string
|
||||
name: string
|
||||
api: ModelApi2
|
||||
capabilities: ModelCapabilities2
|
||||
request: {
|
||||
settings: ProviderSettings2
|
||||
headers: {
|
||||
[key: string]: string
|
||||
}
|
||||
body: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
variant?: string
|
||||
}
|
||||
variants: Array<{
|
||||
id: string
|
||||
settings: ProviderSettings2
|
||||
headers: {
|
||||
[key: string]: string
|
||||
}
|
||||
body: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
}>
|
||||
time: {
|
||||
released: number
|
||||
}
|
||||
cost: Array<ModelCost2>
|
||||
status: "alpha" | "beta" | "deprecated" | "active"
|
||||
enabled: boolean
|
||||
limit: {
|
||||
context: number
|
||||
input?: number
|
||||
output: number
|
||||
}
|
||||
}
|
||||
|
||||
export type GenerateTextResponseV2 = {
|
||||
data: {
|
||||
text: string
|
||||
}
|
||||
}
|
||||
|
||||
export type ProviderAisdk2 = {
|
||||
type: "aisdk"
|
||||
package: string
|
||||
url?: string
|
||||
settings?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
}
|
||||
|
||||
export type ProviderNative2 = {
|
||||
type: "native"
|
||||
url?: string
|
||||
settings: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
}
|
||||
|
||||
export type ProviderApi2 = ProviderAisdk2 | ProviderNative2
|
||||
|
||||
export type ProviderV2Info2 = {
|
||||
id: string
|
||||
integrationID?: string
|
||||
name: string
|
||||
disabled?: boolean
|
||||
api: ProviderApi2
|
||||
request: ProviderRequest2
|
||||
}
|
||||
|
||||
export type ProviderNotFoundErrorV2 = {
|
||||
_tag: "ProviderNotFoundError"
|
||||
providerID: string
|
||||
message: string
|
||||
}
|
||||
|
||||
export type IntegrationWhen2 = {
|
||||
key: string
|
||||
op: "eq" | "neq"
|
||||
value: string
|
||||
}
|
||||
|
||||
export type IntegrationTextPrompt2 = {
|
||||
type: "text"
|
||||
key: string
|
||||
message: string
|
||||
placeholder?: string
|
||||
when?: IntegrationWhen2
|
||||
}
|
||||
|
||||
export type IntegrationSelectPrompt2 = {
|
||||
type: "select"
|
||||
key: string
|
||||
message: string
|
||||
options: Array<{
|
||||
label: string
|
||||
value: string
|
||||
hint?: string
|
||||
}>
|
||||
when?: IntegrationWhen2
|
||||
}
|
||||
|
||||
export type IntegrationOAuthMethod2 = {
|
||||
id: string
|
||||
type: "oauth"
|
||||
label: string
|
||||
prompts?: Array<IntegrationTextPrompt2 | IntegrationSelectPrompt2>
|
||||
}
|
||||
|
||||
export type IntegrationKeyMethod2 = {
|
||||
type: "key"
|
||||
label?: string
|
||||
}
|
||||
|
||||
export type IntegrationEnvMethod2 = {
|
||||
type: "env"
|
||||
names: Array<string>
|
||||
}
|
||||
|
||||
export type IntegrationMethod2 = IntegrationOAuthMethod2 | IntegrationKeyMethod2 | IntegrationEnvMethod2
|
||||
|
||||
export type ConnectionCredentialInfo2 = {
|
||||
type: "credential"
|
||||
id: string
|
||||
label: string
|
||||
}
|
||||
|
||||
export type ConnectionEnvInfo2 = {
|
||||
type: "env"
|
||||
name: string
|
||||
}
|
||||
|
||||
export type ConnectionInfo2 = ConnectionCredentialInfo2 | ConnectionEnvInfo2
|
||||
|
||||
export type IntegrationInfo2 = {
|
||||
id: string
|
||||
name: string
|
||||
methods: Array<IntegrationMethod2>
|
||||
connections: Array<ConnectionInfo2>
|
||||
}
|
||||
|
||||
export type IntegrationAttempt2 = {
|
||||
attemptID: string
|
||||
url: string
|
||||
instructions: string
|
||||
mode: "auto" | "code"
|
||||
time: {
|
||||
created: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
|
||||
expires: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
|
||||
}
|
||||
}
|
||||
|
||||
export type IntegrationAttemptStatus2 =
|
||||
| {
|
||||
status: "pending"
|
||||
time: {
|
||||
created: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
|
||||
expires: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
|
||||
}
|
||||
}
|
||||
| {
|
||||
status: "complete"
|
||||
time: {
|
||||
created: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
|
||||
expires: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
|
||||
}
|
||||
}
|
||||
| {
|
||||
status: "failed"
|
||||
message: string
|
||||
time: {
|
||||
created: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
|
||||
expires: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
|
||||
}
|
||||
}
|
||||
| {
|
||||
status: "expired"
|
||||
time: {
|
||||
created: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
|
||||
expires: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
|
||||
}
|
||||
}
|
||||
|
||||
export type McpStatusConnected3 = {
|
||||
status: "connected"
|
||||
}
|
||||
|
||||
export type McpStatusPending2 = {
|
||||
status: "pending"
|
||||
}
|
||||
|
||||
export type McpStatusDisabled3 = {
|
||||
status: "disabled"
|
||||
}
|
||||
|
||||
export type McpStatusFailed3 = {
|
||||
status: "failed"
|
||||
error: string
|
||||
}
|
||||
|
||||
export type McpStatusNeedsAuth3 = {
|
||||
status: "needs_auth"
|
||||
}
|
||||
|
||||
export type McpStatusNeedsClientRegistration3 = {
|
||||
status: "needs_client_registration"
|
||||
error: string
|
||||
}
|
||||
|
||||
export type McpServer2 = {
|
||||
name: string
|
||||
status:
|
||||
| McpStatusConnected3
|
||||
| McpStatusPending2
|
||||
| McpStatusDisabled3
|
||||
| McpStatusFailed3
|
||||
| McpStatusNeedsAuth3
|
||||
| McpStatusNeedsClientRegistration3
|
||||
integrationID?: string
|
||||
}
|
||||
|
||||
export type ProjectCurrent2 = {
|
||||
id: string
|
||||
directory: string
|
||||
}
|
||||
|
||||
export type ProjectDirectory2 = {
|
||||
directory: string
|
||||
strategy?: string
|
||||
}
|
||||
|
||||
export type ProjectDirectories2 = Array<ProjectDirectory2>
|
||||
|
||||
export type FormMetadata2 = {
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export type FormWhen2 = {
|
||||
key: string
|
||||
op: "eq" | "neq"
|
||||
value: string | number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||
}
|
||||
|
||||
export type FormOption2 = {
|
||||
value: string
|
||||
label: string
|
||||
description?: string
|
||||
}
|
||||
|
||||
export type FormStringField2 = {
|
||||
key: string
|
||||
title?: string
|
||||
description?: string
|
||||
required?: boolean
|
||||
when?: Array<FormWhen2>
|
||||
type: "string"
|
||||
format?: "email" | "uri" | "date" | "date-time"
|
||||
minLength?: number
|
||||
maxLength?: number
|
||||
pattern?: string
|
||||
placeholder?: string
|
||||
default?: string
|
||||
options?: Array<FormOption2>
|
||||
custom?: boolean
|
||||
}
|
||||
|
||||
export type FormNumberField3 = {
|
||||
key: string
|
||||
title?: string
|
||||
description?: string
|
||||
required?: boolean
|
||||
when?: Array<FormWhen2>
|
||||
type: "number"
|
||||
minimum?: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
|
||||
maximum?: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
|
||||
default?: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
|
||||
}
|
||||
|
||||
export type FormIntegerField3 = {
|
||||
key: string
|
||||
title?: string
|
||||
description?: string
|
||||
required?: boolean
|
||||
when?: Array<FormWhen2>
|
||||
type: "integer"
|
||||
minimum?: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
|
||||
maximum?: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
|
||||
default?: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
|
||||
}
|
||||
|
||||
export type FormBooleanField2 = {
|
||||
key: string
|
||||
title?: string
|
||||
description?: string
|
||||
required?: boolean
|
||||
when?: Array<FormWhen2>
|
||||
type: "boolean"
|
||||
default?: boolean
|
||||
}
|
||||
|
||||
export type FormMultiselectField2 = {
|
||||
key: string
|
||||
title?: string
|
||||
description?: string
|
||||
required?: boolean
|
||||
when?: Array<FormWhen2>
|
||||
type: "multiselect"
|
||||
options: Array<FormOption2>
|
||||
minItems?: number
|
||||
maxItems?: number
|
||||
custom?: boolean
|
||||
default?: Array<string>
|
||||
}
|
||||
|
||||
export type FormFormInfo2 = {
|
||||
id: string
|
||||
sessionID: string
|
||||
title?: string
|
||||
metadata?: FormMetadata2
|
||||
mode: "form"
|
||||
fields: Array<FormStringField2 | FormNumberField3 | FormIntegerField3 | FormBooleanField2 | FormMultiselectField2>
|
||||
}
|
||||
|
||||
export type FormUrlInfo2 = {
|
||||
id: string
|
||||
sessionID: string
|
||||
title?: string
|
||||
metadata?: FormMetadata2
|
||||
mode: "url"
|
||||
url: string
|
||||
}
|
||||
|
||||
export type FormCreatePayload2 = {
|
||||
id?: string | null
|
||||
title?: string
|
||||
metadata?: FormMetadata2
|
||||
mode: "form" | "url"
|
||||
fields?: Array<
|
||||
FormStringField2 | FormNumberField3 | FormIntegerField3 | FormBooleanField2 | FormMultiselectField2
|
||||
> | null
|
||||
url?: string | null
|
||||
}
|
||||
|
||||
export type FormNotFoundErrorV2 = {
|
||||
_tag: "FormNotFoundError"
|
||||
id: string
|
||||
message: string
|
||||
}
|
||||
|
||||
export type FormValue2 =
|
||||
| string
|
||||
| number
|
||||
| "NaN"
|
||||
| "Infinity"
|
||||
| "-Infinity"
|
||||
| "Infinity"
|
||||
| "-Infinity"
|
||||
| "NaN"
|
||||
| boolean
|
||||
| Array<string>
|
||||
|
||||
export type FormAnswer2 = {
|
||||
[key: string]: FormValue2
|
||||
}
|
||||
|
||||
export type FormState2 =
|
||||
| {
|
||||
status: "pending"
|
||||
}
|
||||
| {
|
||||
status: "answered"
|
||||
answer: FormAnswer2
|
||||
}
|
||||
| {
|
||||
status: "cancelled"
|
||||
}
|
||||
|
||||
export type FormReply2 = {
|
||||
answer: FormAnswer2
|
||||
}
|
||||
|
||||
export type FormAlreadySettledErrorV2 = {
|
||||
_tag: "FormAlreadySettledError"
|
||||
id: string
|
||||
message: string
|
||||
}
|
||||
|
||||
export type FormInvalidAnswerErrorV2 = {
|
||||
_tag: "FormInvalidAnswerError"
|
||||
id: string
|
||||
message: string
|
||||
}
|
||||
|
||||
export type PermissionV2Source2 = {
|
||||
type: "tool"
|
||||
messageID: string
|
||||
callID: string
|
||||
}
|
||||
|
||||
export type PermissionV2Request2 = {
|
||||
id: string
|
||||
sessionID: string
|
||||
action: string
|
||||
resources: Array<string>
|
||||
save?: Array<string>
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
source?: PermissionV2Source2
|
||||
}
|
||||
|
||||
export type PermissionSavedInfo2 = {
|
||||
id: string
|
||||
projectID: string
|
||||
action: string
|
||||
resource: string
|
||||
}
|
||||
|
||||
export type PermissionNotFoundErrorV2 = {
|
||||
_tag: "PermissionNotFoundError"
|
||||
requestID: string
|
||||
message: string
|
||||
}
|
||||
|
||||
export type PermissionV2Reply2 = "once" | "always" | "reject"
|
||||
|
||||
export type FileSystemEntry2 = {
|
||||
path: string
|
||||
type: "file" | "directory"
|
||||
}
|
||||
|
||||
export type CommandV2Info2 = {
|
||||
name: string
|
||||
template: string
|
||||
description?: string
|
||||
agent?: string
|
||||
model?: ModelRef2
|
||||
subtask?: boolean
|
||||
}
|
||||
|
||||
export type SkillV2Info2 = {
|
||||
name: string
|
||||
description?: string
|
||||
slash?: boolean
|
||||
autoinvoke?: boolean
|
||||
location: string
|
||||
content: string
|
||||
}
|
||||
|
||||
export type ModelsDevRefreshed2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "models-dev.refreshed"
|
||||
location?: LocationRef2
|
||||
data:
|
||||
| {
|
||||
[key: string]: unknown
|
||||
}
|
||||
| Array<unknown>
|
||||
}
|
||||
|
||||
export type IntegrationUpdated2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "integration.updated"
|
||||
location?: LocationRef2
|
||||
data:
|
||||
| {
|
||||
[key: string]: unknown
|
||||
}
|
||||
| Array<unknown>
|
||||
}
|
||||
|
||||
export type IntegrationConnectionUpdated2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "integration.connection.updated"
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
integrationID: string
|
||||
}
|
||||
}
|
||||
|
||||
export type CatalogUpdated2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "catalog.updated"
|
||||
location?: LocationRef2
|
||||
data:
|
||||
| {
|
||||
[key: string]: unknown
|
||||
}
|
||||
| Array<unknown>
|
||||
}
|
||||
|
||||
export type AgentUpdated2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "agent.updated"
|
||||
location?: LocationRef2
|
||||
data:
|
||||
| {
|
||||
[key: string]: unknown
|
||||
}
|
||||
| Array<unknown>
|
||||
}
|
||||
|
||||
export type SnapshotFileDiffV2 = {
|
||||
file?: string
|
||||
patch?: string
|
||||
additions: number
|
||||
deletions: number
|
||||
status?: "added" | "deleted" | "modified"
|
||||
}
|
||||
|
||||
export type PermissionActionV2 = "allow" | "deny" | "ask"
|
||||
|
||||
export type PermissionRuleV2 = {
|
||||
permission: string
|
||||
pattern: string
|
||||
action: PermissionActionV2
|
||||
}
|
||||
|
||||
export type PermissionRulesetV2 = Array<PermissionRuleV2>
|
||||
|
||||
export type SessionV2 = {
|
||||
id: string
|
||||
slug: string
|
||||
@@ -8058,7 +9865,7 @@ export type SessionV2 = {
|
||||
additions: number
|
||||
deletions: number
|
||||
files: number
|
||||
diffs?: Array<SnapshotFileDiff>
|
||||
diffs?: Array<SnapshotFileDiffV2>
|
||||
}
|
||||
cost?: number
|
||||
tokens?: {
|
||||
@@ -8090,7 +9897,7 @@ export type SessionV2 = {
|
||||
compacting?: number
|
||||
archived?: number
|
||||
}
|
||||
permission?: PermissionRuleset
|
||||
permission?: PermissionRulesetV2
|
||||
revert?: {
|
||||
messageID: string
|
||||
partID?: string
|
||||
@@ -8099,13 +9906,74 @@ export type SessionV2 = {
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionCreated2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.created"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
info: SessionV2
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionUpdated2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.updated"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
info: SessionV2
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionDeleted2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.deleted"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
info: SessionV2
|
||||
}
|
||||
}
|
||||
|
||||
export type JsonSchemaV2 = {
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export type OutputFormatV2 =
|
||||
| {
|
||||
type: "text"
|
||||
}
|
||||
| {
|
||||
type: "json_schema"
|
||||
schema: JsonSchema
|
||||
schema: JsonSchemaV2
|
||||
retryCount?: number | null | null
|
||||
}
|
||||
|
||||
@@ -8120,7 +9988,7 @@ export type UserMessageV2 = {
|
||||
summary?: {
|
||||
title?: string | null
|
||||
body?: string | null
|
||||
diffs: Array<SnapshotFileDiff>
|
||||
diffs: Array<SnapshotFileDiffV2>
|
||||
} | null
|
||||
agent: string
|
||||
model: {
|
||||
@@ -8134,6 +10002,14 @@ export type UserMessageV2 = {
|
||||
} | null
|
||||
}
|
||||
|
||||
export type ProviderAuthErrorV2 = {
|
||||
name: "ProviderAuthError"
|
||||
data: {
|
||||
providerID: string
|
||||
message: string
|
||||
}
|
||||
}
|
||||
|
||||
export type UnknownError1V2 = {
|
||||
name: "UnknownError"
|
||||
data: {
|
||||
@@ -8151,6 +10027,13 @@ export type MessageOutputLengthErrorV2 = {
|
||||
| Array<unknown>
|
||||
}
|
||||
|
||||
export type MessageAbortedErrorV2 = {
|
||||
name: "MessageAbortedError"
|
||||
data: {
|
||||
message: string
|
||||
}
|
||||
}
|
||||
|
||||
export type StructuredOutputErrorV2 = {
|
||||
name: "StructuredOutputError"
|
||||
data: {
|
||||
@@ -8167,6 +10050,13 @@ export type ContextOverflowErrorV2 = {
|
||||
}
|
||||
}
|
||||
|
||||
export type ContentFilterErrorV2 = {
|
||||
name: "ContentFilterError"
|
||||
data: {
|
||||
message: string
|
||||
}
|
||||
}
|
||||
|
||||
export type ApiErrorV2 = {
|
||||
name: "APIError"
|
||||
data: {
|
||||
@@ -8192,13 +10082,13 @@ export type AssistantMessageV2 = {
|
||||
completed?: number | null
|
||||
}
|
||||
error?:
|
||||
| ProviderAuthError
|
||||
| ProviderAuthErrorV2
|
||||
| UnknownError1V2
|
||||
| MessageOutputLengthErrorV2
|
||||
| MessageAbortedError
|
||||
| MessageAbortedErrorV2
|
||||
| StructuredOutputErrorV2
|
||||
| ContextOverflowErrorV2
|
||||
| ContentFilterError
|
||||
| ContentFilterErrorV2
|
||||
| ApiErrorV2
|
||||
| null
|
||||
parentID: string
|
||||
@@ -8227,6 +10117,46 @@ export type AssistantMessageV2 = {
|
||||
finish?: string | null
|
||||
}
|
||||
|
||||
export type MessageV2 = UserMessageV2 | AssistantMessageV2
|
||||
|
||||
export type MessageUpdated2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "message.updated"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
info: MessageV2
|
||||
}
|
||||
}
|
||||
|
||||
export type MessageRemoved2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "message.removed"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
messageID: string
|
||||
}
|
||||
}
|
||||
|
||||
export type TextPartV2 = {
|
||||
id: string
|
||||
sessionID: string
|
||||
@@ -8274,6 +10204,18 @@ export type ReasoningPartV2 = {
|
||||
}
|
||||
}
|
||||
|
||||
export type FilePartSourceTextV2 = {
|
||||
value: string
|
||||
start: number
|
||||
end: number
|
||||
}
|
||||
|
||||
export type FileSourceV2 = {
|
||||
text: FilePartSourceTextV2
|
||||
type: "file"
|
||||
path: string
|
||||
}
|
||||
|
||||
export type RangeV2 = {
|
||||
start: {
|
||||
line: number
|
||||
@@ -8286,7 +10228,7 @@ export type RangeV2 = {
|
||||
}
|
||||
|
||||
export type SymbolSourceV2 = {
|
||||
text: FilePartSourceText
|
||||
text: FilePartSourceTextV2
|
||||
type: "symbol"
|
||||
path: string
|
||||
range: RangeV2
|
||||
@@ -8294,6 +10236,15 @@ export type SymbolSourceV2 = {
|
||||
kind: number
|
||||
}
|
||||
|
||||
export type ResourceSourceV2 = {
|
||||
text: FilePartSourceTextV2
|
||||
type: "resource"
|
||||
clientName: string
|
||||
uri: string
|
||||
}
|
||||
|
||||
export type FilePartSourceV2 = FileSourceV2 | SymbolSourceV2 | ResourceSourceV2
|
||||
|
||||
export type FilePartV2 = {
|
||||
id: string
|
||||
sessionID: string
|
||||
@@ -8302,7 +10253,15 @@ export type FilePartV2 = {
|
||||
mime: string
|
||||
filename?: string | null
|
||||
url: string
|
||||
source?: FilePartSource | null
|
||||
source?: FilePartSourceV2 | null
|
||||
}
|
||||
|
||||
export type ToolStatePendingV2 = {
|
||||
status: "pending"
|
||||
input: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
raw: string
|
||||
}
|
||||
|
||||
export type ToolStateRunningV2 = {
|
||||
@@ -8352,6 +10311,8 @@ export type ToolStateErrorV2 = {
|
||||
}
|
||||
}
|
||||
|
||||
export type ToolStateV2 = ToolStatePendingV2 | ToolStateRunningV2 | ToolStateCompletedV2 | ToolStateErrorV2
|
||||
|
||||
export type ToolPartV2 = {
|
||||
id: string
|
||||
sessionID: string
|
||||
@@ -8359,7 +10320,7 @@ export type ToolPartV2 = {
|
||||
type: "tool"
|
||||
callID: string
|
||||
tool: string
|
||||
state: ToolState
|
||||
state: ToolStateV2
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
} | null
|
||||
@@ -8445,6 +10406,256 @@ export type CompactionPartV2 = {
|
||||
tail_start_id?: string | null
|
||||
}
|
||||
|
||||
export type PartV2 =
|
||||
| TextPartV2
|
||||
| SubtaskPartV2
|
||||
| ReasoningPartV2
|
||||
| FilePartV2
|
||||
| ToolPartV2
|
||||
| StepStartPartV2
|
||||
| StepFinishPartV2
|
||||
| SnapshotPartV2
|
||||
| PatchPartV2
|
||||
| AgentPartV2
|
||||
| RetryPartV2
|
||||
| CompactionPartV2
|
||||
|
||||
export type MessagePartUpdated2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "message.part.updated"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
part: PartV2
|
||||
time: number
|
||||
}
|
||||
}
|
||||
|
||||
export type MessagePartRemoved2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "message.part.removed"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
messageID: string
|
||||
partID: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionTextDelta2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.text.delta"
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
delta: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionReasoningDelta2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.reasoning.delta"
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
delta: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionToolInputDelta2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.tool.input.delta"
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
callID: string
|
||||
delta: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionCompactionDelta2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.compaction.delta"
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
text: string
|
||||
}
|
||||
}
|
||||
|
||||
export type FilesystemChanged2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "filesystem.changed"
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
file: string
|
||||
event: "add" | "change" | "unlink"
|
||||
}
|
||||
}
|
||||
|
||||
export type ReferenceUpdated2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "reference.updated"
|
||||
location?: LocationRef2
|
||||
data:
|
||||
| {
|
||||
[key: string]: unknown
|
||||
}
|
||||
| Array<unknown>
|
||||
}
|
||||
|
||||
export type PermissionV2Asked2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "permission.v2.asked"
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
id: string
|
||||
sessionID: string
|
||||
action: string
|
||||
resources: Array<string>
|
||||
save?: Array<string>
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
source?: PermissionV2Source2
|
||||
}
|
||||
}
|
||||
|
||||
export type PermissionV2Replied2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "permission.v2.replied"
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
requestID: string
|
||||
reply: PermissionV2Reply2
|
||||
}
|
||||
}
|
||||
|
||||
export type PluginAdded2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "plugin.added"
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
id: string
|
||||
}
|
||||
}
|
||||
|
||||
export type ProjectDirectoriesUpdated2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "project.directories.updated"
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
projectID: string
|
||||
}
|
||||
}
|
||||
|
||||
export type CommandUpdated2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "command.updated"
|
||||
location?: LocationRef2
|
||||
data:
|
||||
| {
|
||||
[key: string]: unknown
|
||||
}
|
||||
| Array<unknown>
|
||||
}
|
||||
|
||||
export type ConfigUpdated2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "config.updated"
|
||||
location?: LocationRef2
|
||||
data:
|
||||
| {
|
||||
[key: string]: unknown
|
||||
}
|
||||
| Array<unknown>
|
||||
}
|
||||
|
||||
export type SkillUpdated2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "skill.updated"
|
||||
location?: LocationRef2
|
||||
data:
|
||||
| {
|
||||
[key: string]: unknown
|
||||
}
|
||||
| Array<unknown>
|
||||
}
|
||||
|
||||
export type PtyV2 = {
|
||||
id: string
|
||||
title: string
|
||||
@@ -8456,6 +10667,353 @@ export type PtyV2 = {
|
||||
exitCode?: number
|
||||
}
|
||||
|
||||
export type PtyCreated2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "pty.created"
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
info: PtyV2
|
||||
}
|
||||
}
|
||||
|
||||
export type PtyUpdated2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "pty.updated"
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
info: PtyV2
|
||||
}
|
||||
}
|
||||
|
||||
export type PtyExited2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "pty.exited"
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
id: string
|
||||
exitCode: number
|
||||
}
|
||||
}
|
||||
|
||||
export type PtyDeleted2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "pty.deleted"
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
id: string
|
||||
}
|
||||
}
|
||||
|
||||
export type ShellCreated2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "shell.created"
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
info: Shell1V2
|
||||
}
|
||||
}
|
||||
|
||||
export type ShellExited2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "shell.exited"
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
id: string
|
||||
exit?: number | "NaN" | "Infinity" | "-Infinity"
|
||||
status: "running" | "exited" | "timeout" | "killed"
|
||||
}
|
||||
}
|
||||
|
||||
export type ShellDeleted2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "shell.deleted"
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
id: string
|
||||
}
|
||||
}
|
||||
|
||||
export type QuestionV2Option2 = {
|
||||
/**
|
||||
* Display text (1-5 words, concise)
|
||||
*/
|
||||
label: string
|
||||
/**
|
||||
* Explanation of choice
|
||||
*/
|
||||
description: string
|
||||
}
|
||||
|
||||
export type QuestionV2Info2 = {
|
||||
/**
|
||||
* Complete question
|
||||
*/
|
||||
question: string
|
||||
/**
|
||||
* Very short label (max 30 chars)
|
||||
*/
|
||||
header: string
|
||||
/**
|
||||
* Available choices
|
||||
*/
|
||||
options: Array<QuestionV2Option2>
|
||||
multiple?: boolean
|
||||
custom?: boolean
|
||||
}
|
||||
|
||||
export type QuestionV2Tool2 = {
|
||||
messageID: string
|
||||
callID: string
|
||||
}
|
||||
|
||||
export type QuestionV2Asked2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "question.v2.asked"
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
id: string
|
||||
sessionID: string
|
||||
/**
|
||||
* Questions to ask
|
||||
*/
|
||||
questions: Array<QuestionV2Info2>
|
||||
tool?: QuestionV2Tool2
|
||||
}
|
||||
}
|
||||
|
||||
export type QuestionV2Answer2 = Array<string>
|
||||
|
||||
export type QuestionV2Replied2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "question.v2.replied"
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
requestID: string
|
||||
answers: Array<QuestionV2Answer2>
|
||||
}
|
||||
}
|
||||
|
||||
export type QuestionV2Rejected2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "question.v2.rejected"
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
requestID: string
|
||||
}
|
||||
}
|
||||
|
||||
export type FormMetadata1 = {
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export type FormWhen12 = {
|
||||
key: string
|
||||
op: "eq" | "neq"
|
||||
value: string | number | "NaN" | "Infinity" | "-Infinity" | boolean
|
||||
}
|
||||
|
||||
export type FormStringField1 = {
|
||||
key: string
|
||||
title?: string
|
||||
description?: string
|
||||
required?: boolean
|
||||
when?: Array<FormWhen12>
|
||||
type: "string"
|
||||
format?: "email" | "uri" | "date" | "date-time"
|
||||
minLength?: number
|
||||
maxLength?: number
|
||||
pattern?: string
|
||||
placeholder?: string
|
||||
default?: string
|
||||
options?: Array<FormOption2>
|
||||
custom?: boolean
|
||||
}
|
||||
|
||||
export type FormNumberField12 = {
|
||||
key: string
|
||||
title?: string
|
||||
description?: string
|
||||
required?: boolean
|
||||
when?: Array<FormWhen12>
|
||||
type: "number"
|
||||
minimum?: number | "NaN" | "Infinity" | "-Infinity"
|
||||
maximum?: number | "NaN" | "Infinity" | "-Infinity"
|
||||
default?: number | "NaN" | "Infinity" | "-Infinity"
|
||||
}
|
||||
|
||||
export type FormIntegerField12 = {
|
||||
key: string
|
||||
title?: string
|
||||
description?: string
|
||||
required?: boolean
|
||||
when?: Array<FormWhen12>
|
||||
type: "integer"
|
||||
minimum?: number | "NaN" | "Infinity" | "-Infinity"
|
||||
maximum?: number | "NaN" | "Infinity" | "-Infinity"
|
||||
default?: number | "NaN" | "Infinity" | "-Infinity"
|
||||
}
|
||||
|
||||
export type FormBooleanField1 = {
|
||||
key: string
|
||||
title?: string
|
||||
description?: string
|
||||
required?: boolean
|
||||
when?: Array<FormWhen12>
|
||||
type: "boolean"
|
||||
default?: boolean
|
||||
}
|
||||
|
||||
export type FormMultiselectField1 = {
|
||||
key: string
|
||||
title?: string
|
||||
description?: string
|
||||
required?: boolean
|
||||
when?: Array<FormWhen12>
|
||||
type: "multiselect"
|
||||
options: Array<FormOption2>
|
||||
minItems?: number
|
||||
maxItems?: number
|
||||
custom?: boolean
|
||||
default?: Array<string>
|
||||
}
|
||||
|
||||
export type FormFormInfo1 = {
|
||||
id: string
|
||||
sessionID: string
|
||||
title?: string
|
||||
metadata?: FormMetadata1
|
||||
mode: "form"
|
||||
fields: Array<FormStringField1 | FormNumberField12 | FormIntegerField12 | FormBooleanField1 | FormMultiselectField1>
|
||||
}
|
||||
|
||||
export type FormUrlInfo1 = {
|
||||
id: string
|
||||
sessionID: string
|
||||
title?: string
|
||||
metadata?: FormMetadata1
|
||||
mode: "url"
|
||||
url: string
|
||||
}
|
||||
|
||||
export type FormCreated2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "form.created"
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
form: FormFormInfo1 | FormUrlInfo1
|
||||
}
|
||||
}
|
||||
|
||||
export type FormValue12 = string | number | "NaN" | "Infinity" | "-Infinity" | boolean | Array<string>
|
||||
|
||||
export type FormAnswer1 = {
|
||||
[key: string]: FormValue12
|
||||
}
|
||||
|
||||
export type FormReplied2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "form.replied"
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
id: string
|
||||
sessionID: string
|
||||
answer: FormAnswer1
|
||||
}
|
||||
}
|
||||
|
||||
export type FormCancelled2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "form.cancelled"
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
id: string
|
||||
sessionID: string
|
||||
}
|
||||
}
|
||||
|
||||
export type TodoV2 = {
|
||||
/**
|
||||
* Brief description of the task
|
||||
*/
|
||||
content: string
|
||||
/**
|
||||
* Current status of the task: pending, in_progress, completed, cancelled
|
||||
*/
|
||||
status: string
|
||||
/**
|
||||
* Priority level of the task: high, medium, low
|
||||
*/
|
||||
priority: string
|
||||
}
|
||||
|
||||
export type TodoUpdated2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "todo.updated"
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
todos: Array<TodoV2>
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionStatusV2 =
|
||||
| {
|
||||
type: "idle"
|
||||
@@ -8485,1994 +11043,47 @@ export type SessionStatusV22 = {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.status"
|
||||
location?: LocationRefV2
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
status: SessionStatusV2
|
||||
}
|
||||
}
|
||||
|
||||
export type QuestionInfoV2 = {
|
||||
/**
|
||||
* Complete question
|
||||
*/
|
||||
question: string
|
||||
/**
|
||||
* Very short label (max 30 chars)
|
||||
*/
|
||||
header: string
|
||||
/**
|
||||
* Available choices
|
||||
*/
|
||||
options: Array<QuestionOption>
|
||||
/**
|
||||
* Allow selecting multiple choices
|
||||
*/
|
||||
multiple?: boolean | null
|
||||
/**
|
||||
* Allow typing a custom answer (default: true)
|
||||
*/
|
||||
custom?: boolean | null
|
||||
}
|
||||
|
||||
export type QuestionToolV2 = {
|
||||
messageID: string
|
||||
callID: string
|
||||
}
|
||||
|
||||
export type V2EventV2 =
|
||||
| ModelsDevRefreshedV2
|
||||
| IntegrationUpdatedV2
|
||||
| IntegrationConnectionUpdatedV2
|
||||
| CatalogUpdatedV2
|
||||
| AgentUpdatedV2
|
||||
| SessionCreatedV2
|
||||
| SessionUpdatedV2
|
||||
| SessionDeletedV2
|
||||
| MessageUpdatedV2
|
||||
| MessageRemovedV2
|
||||
| MessagePartUpdatedV2
|
||||
| MessagePartRemovedV2
|
||||
| SessionAgentSelectedV2
|
||||
| SessionModelSelectedV2
|
||||
| SessionMovedV2
|
||||
| SessionRenamedV2
|
||||
| SessionForkedV2
|
||||
| SessionPromptPromotedV2
|
||||
| SessionPromptAdmittedV2
|
||||
| SessionExecutionStartedV2
|
||||
| SessionExecutionSucceededV2
|
||||
| SessionExecutionFailedV2
|
||||
| SessionExecutionInterruptedV2
|
||||
| SessionContextUpdatedV2
|
||||
| SessionSyntheticV2
|
||||
| SessionSkillActivatedV2
|
||||
| SessionShellStartedV2
|
||||
| SessionShellEndedV2
|
||||
| SessionStepStartedV2
|
||||
| SessionStepEndedV2
|
||||
| SessionStepFailedV2
|
||||
| SessionTextStartedV2
|
||||
| SessionTextDeltaV2
|
||||
| SessionTextEndedV2
|
||||
| SessionReasoningStartedV2
|
||||
| SessionReasoningDeltaV2
|
||||
| SessionReasoningEndedV2
|
||||
| SessionToolInputStartedV2
|
||||
| SessionToolInputDeltaV2
|
||||
| SessionToolInputEndedV2
|
||||
| SessionToolCalledV2
|
||||
| SessionToolProgressV2
|
||||
| SessionToolSuccessV2
|
||||
| SessionToolFailedV2
|
||||
| SessionRetryScheduledV2
|
||||
| SessionCompactionAdmittedV2
|
||||
| SessionCompactionStartedV2
|
||||
| SessionCompactionDeltaV2
|
||||
| SessionCompactionEndedV2
|
||||
| SessionCompactionFailedV2
|
||||
| SessionRevertStagedV2
|
||||
| SessionRevertClearedV2
|
||||
| SessionRevertCommittedV2
|
||||
| FilesystemChangedV2
|
||||
| ReferenceUpdatedV2
|
||||
| PermissionV2AskedV2
|
||||
| PermissionV2RepliedV2
|
||||
| PluginAddedV2
|
||||
| ProjectDirectoriesUpdatedV2
|
||||
| CommandUpdatedV2
|
||||
| ConfigUpdatedV2
|
||||
| SkillUpdatedV2
|
||||
| PtyCreatedV2
|
||||
| PtyUpdatedV2
|
||||
| PtyExitedV2
|
||||
| PtyDeletedV2
|
||||
| ShellCreatedV2
|
||||
| ShellExitedV2
|
||||
| ShellDeletedV2
|
||||
| QuestionV2AskedV2
|
||||
| QuestionV2RepliedV2
|
||||
| QuestionV2RejectedV2
|
||||
| FormCreatedV2
|
||||
| FormRepliedV2
|
||||
| FormCancelledV2
|
||||
| TodoUpdatedV2
|
||||
| SessionStatusV22
|
||||
| SessionIdleV2
|
||||
| TuiPromptAppendV2
|
||||
| TuiCommandExecuteV2
|
||||
| TuiToastShowV2
|
||||
| TuiSessionSelectV2
|
||||
| InstallationUpdatedV2
|
||||
| InstallationUpdateAvailableV2
|
||||
| VcsBranchUpdatedV2
|
||||
| McpStatusChangedV2
|
||||
| PermissionAskedV2
|
||||
| PermissionRepliedV2
|
||||
| QuestionAskedV2
|
||||
| QuestionRepliedV2
|
||||
| QuestionRejectedV2
|
||||
| SessionErrorV2
|
||||
| V2EventServerConnected
|
||||
|
||||
export type ProjectCopyErrorV2 = {
|
||||
name: "ProjectCopyError"
|
||||
data: {
|
||||
message: string
|
||||
forceRequired?: boolean | null
|
||||
}
|
||||
}
|
||||
|
||||
export type LocationInfoV2 = {
|
||||
directory: string
|
||||
workspaceID?: string
|
||||
project: {
|
||||
id: string
|
||||
directory: string
|
||||
}
|
||||
}
|
||||
|
||||
export type AgentColorV2 = string | "primary" | "secondary" | "accent" | "success" | "warning" | "error" | "info"
|
||||
|
||||
export type AgentV2InfoV2 = {
|
||||
id: string
|
||||
model?: ModelRef
|
||||
request: ProviderRequest
|
||||
system?: string
|
||||
description?: string
|
||||
mode: "subagent" | "primary" | "all"
|
||||
hidden: boolean
|
||||
color?: AgentColorV2
|
||||
steps?: number
|
||||
permissions: PermissionV2Ruleset
|
||||
}
|
||||
|
||||
export type LocationRefV2 = {
|
||||
directory: string
|
||||
workspaceID?: string
|
||||
}
|
||||
|
||||
export type FileDiffV2 = {
|
||||
path: string
|
||||
status: "added" | "modified" | "deleted"
|
||||
additions: number
|
||||
deletions: number
|
||||
patch: string
|
||||
}
|
||||
|
||||
export type RevertStateV2 = {
|
||||
messageID: string
|
||||
partID?: string
|
||||
snapshot?: string
|
||||
diff?: string
|
||||
files?: Array<FileDiffV2>
|
||||
}
|
||||
|
||||
export type SessionV2InfoV2 = {
|
||||
id: string
|
||||
parentID?: string
|
||||
projectID: string
|
||||
agent?: string
|
||||
model?: ModelRef
|
||||
cost: number
|
||||
tokens: {
|
||||
input: number
|
||||
output: number
|
||||
reasoning: number
|
||||
cache: {
|
||||
read: number
|
||||
write: number
|
||||
}
|
||||
}
|
||||
time: {
|
||||
created: number
|
||||
updated: number
|
||||
archived?: number
|
||||
}
|
||||
title: string
|
||||
location: LocationRefV2
|
||||
subpath?: string
|
||||
revert?: RevertStateV2
|
||||
}
|
||||
|
||||
export type SessionInputAdmittedV2 = {
|
||||
admittedSeq: number
|
||||
id: string
|
||||
sessionID: string
|
||||
prompt: Prompt
|
||||
delivery: "steer" | "queue"
|
||||
timeCreated: number
|
||||
promotedSeq?: number
|
||||
}
|
||||
|
||||
export type SessionInputCompactionV2 = {
|
||||
type: "compaction"
|
||||
admittedSeq: number
|
||||
id: string
|
||||
sessionID: string
|
||||
timeCreated: number
|
||||
handledSeq?: number
|
||||
}
|
||||
|
||||
export type SessionMessageAgentSelectedV2 = {
|
||||
id: string
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
time: {
|
||||
created: number
|
||||
}
|
||||
type: "agent-switched"
|
||||
agent: string
|
||||
}
|
||||
|
||||
export type SessionMessageModelSelectedV2 = {
|
||||
id: string
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
time: {
|
||||
created: number
|
||||
}
|
||||
type: "model-switched"
|
||||
model: ModelRef
|
||||
previous?: ModelRef
|
||||
}
|
||||
|
||||
export type SessionMessageUserV2 = {
|
||||
id: string
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
time: {
|
||||
created: number
|
||||
}
|
||||
text: string
|
||||
files?: Array<PromptFileAttachment>
|
||||
agents?: Array<PromptAgentAttachment>
|
||||
type: "user"
|
||||
}
|
||||
|
||||
export type SessionMessageSyntheticV2 = {
|
||||
id: string
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
time: {
|
||||
created: number
|
||||
}
|
||||
sessionID: string
|
||||
text: string
|
||||
description?: string
|
||||
type: "synthetic"
|
||||
}
|
||||
|
||||
export type SessionMessageSystemV2 = {
|
||||
id: string
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
time: {
|
||||
created: number
|
||||
}
|
||||
type: "system"
|
||||
text: string
|
||||
}
|
||||
|
||||
export type SessionMessageSkillV2 = {
|
||||
id: string
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
time: {
|
||||
created: number
|
||||
}
|
||||
type: "skill"
|
||||
name: string
|
||||
text: string
|
||||
}
|
||||
|
||||
export type SessionMessageShellV2 = {
|
||||
id: string
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
time: {
|
||||
created: number
|
||||
completed?: number
|
||||
}
|
||||
type: "shell"
|
||||
shell: ShellV2
|
||||
output?: {
|
||||
output: string
|
||||
cursor: number
|
||||
size: number
|
||||
truncated: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionMessageAssistantRetryV2 = {
|
||||
attempt: number
|
||||
at: number
|
||||
error: SessionStructuredError
|
||||
}
|
||||
|
||||
export type SessionMessageAssistantV2 = {
|
||||
id: string
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
time: {
|
||||
created: number
|
||||
completed?: number
|
||||
}
|
||||
type: "assistant"
|
||||
agent: string
|
||||
model: ModelRef
|
||||
content: Array<SessionMessageAssistantText | SessionMessageAssistantReasoning | SessionMessageAssistantTool>
|
||||
snapshot?: {
|
||||
start?: string
|
||||
end?: string
|
||||
files?: Array<string>
|
||||
}
|
||||
finish?: "stop" | "length" | "tool-calls" | "content-filter" | "error" | "unknown"
|
||||
cost?: number
|
||||
tokens?: {
|
||||
input: number
|
||||
output: number
|
||||
reasoning: number
|
||||
cache: {
|
||||
read: number
|
||||
write: number
|
||||
}
|
||||
}
|
||||
error?: SessionStructuredError
|
||||
retry?: SessionMessageAssistantRetryV2
|
||||
}
|
||||
|
||||
export type SessionMessageCompactionV2 = {
|
||||
type: "compaction"
|
||||
status: "queued" | "running" | "completed" | "failed"
|
||||
reason: "auto" | "manual"
|
||||
summary: string
|
||||
recent: string
|
||||
id: string
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
time: {
|
||||
created: number
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Context entry key (lowercase alphanumerics plus . _ -)
|
||||
*/
|
||||
export type SessionContextEntryKeyV2 = string
|
||||
|
||||
export type SessionAgentSelectedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.agent.selected"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
agent: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionModelSelectedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.model.selected"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
model: ModelRef
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionMovedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.moved"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
location: LocationRefV2
|
||||
subpath?: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionRenamedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.renamed"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
title: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionForkedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.forked"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
parentID: string
|
||||
from?: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionPromptPromotedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.prompt.promoted"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
inputID: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionPromptAdmittedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.prompt.admitted"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
inputID: string
|
||||
prompt: Prompt
|
||||
delivery: "steer" | "queue"
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionExecutionStartedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.execution.started"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionExecutionSucceededV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.execution.succeeded"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionExecutionFailedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.execution.failed"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
error: SessionStructuredError
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionExecutionInterruptedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.execution.interrupted"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
reason: "user" | "shutdown" | "superseded"
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionContextUpdatedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.context.updated"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
text: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionSyntheticV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.synthetic"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
text: string
|
||||
description?: string
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionSkillActivatedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.skill.activated"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
name: string
|
||||
text: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionShellStartedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.shell.started"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
shell: ShellV2
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionShellEndedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.shell.ended"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
shell: ShellV2
|
||||
output: {
|
||||
output: string
|
||||
cursor: number
|
||||
size: number
|
||||
truncated: boolean
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionStepStartedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.step.started"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
agent: string
|
||||
model: ModelRef
|
||||
snapshot?: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionStepEndedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.step.ended"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
finish: "stop" | "length" | "tool-calls" | "content-filter" | "error" | "unknown"
|
||||
cost: number
|
||||
tokens: {
|
||||
input: number
|
||||
output: number
|
||||
reasoning: number
|
||||
cache: {
|
||||
read: number
|
||||
write: number
|
||||
}
|
||||
}
|
||||
snapshot?: string
|
||||
files?: Array<string>
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionStepFailedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.step.failed"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
error: SessionStructuredError
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionTextStartedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.text.started"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
ordinal: number
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionTextEndedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.text.ended"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
ordinal: number
|
||||
text: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionMessageProviderState3 = {
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export type SessionReasoningStartedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.reasoning.started"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
ordinal: number
|
||||
state?: SessionMessageProviderState3
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionMessageProviderState4 = {
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export type SessionReasoningEndedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.reasoning.ended"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
ordinal: number
|
||||
text: string
|
||||
state?: SessionMessageProviderState4
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionToolInputStartedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.tool.input.started"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
callID: string
|
||||
name: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionToolInputEndedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.tool.input.ended"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
callID: string
|
||||
text: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionMessageProviderState5 = {
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export type SessionToolCalledV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.tool.called"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
callID: string
|
||||
input: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
executed: boolean
|
||||
state?: SessionMessageProviderState5
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionToolProgressV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.tool.progress"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
callID: string
|
||||
structured: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
content: Array<LlmToolContent>
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionMessageProviderState6 = {
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export type SessionToolSuccessV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.tool.success"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
callID: string
|
||||
structured: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
content: Array<LlmToolContent>
|
||||
outputPaths?: Array<string>
|
||||
result?: unknown
|
||||
executed: boolean
|
||||
resultState?: SessionMessageProviderState6
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionMessageProviderState7 = {
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export type SessionToolFailedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.tool.failed"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
callID: string
|
||||
error: SessionStructuredError
|
||||
result?: unknown
|
||||
executed: boolean
|
||||
resultState?: SessionMessageProviderState7
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionRetryScheduledV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.retry.scheduled"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
attempt: number
|
||||
at: number
|
||||
error: SessionStructuredError
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionCompactionAdmittedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.compaction.admitted"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
inputID: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionCompactionStartedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.compaction.started"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
reason: "auto" | "manual"
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionCompactionEndedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.compaction.ended"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
reason: "auto" | "manual"
|
||||
text: string
|
||||
recent: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionCompactionFailedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.compaction.failed"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionRevertStagedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.revert.staged"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
revert: RevertStateV2
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionRevertClearedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.revert.cleared"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionRevertCommittedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.revert.committed"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
to: string
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marker emitted once when a log read reaches its captured watermark. The reader holds every event committed at or below seq.
|
||||
*/
|
||||
export type EventLogSyncedV2 = {
|
||||
type: "log.synced"
|
||||
aggregateID: string
|
||||
seq?: number
|
||||
}
|
||||
|
||||
export type FormWhenV2 = {
|
||||
key: string
|
||||
op: "eq" | "neq"
|
||||
value: string | number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||
}
|
||||
|
||||
export type FormStringFieldV2 = {
|
||||
key: string
|
||||
title?: string
|
||||
description?: string
|
||||
required?: boolean
|
||||
when?: Array<FormWhenV2>
|
||||
type: "string"
|
||||
format?: "email" | "uri" | "date" | "date-time"
|
||||
minLength?: number
|
||||
maxLength?: number
|
||||
pattern?: string
|
||||
placeholder?: string
|
||||
default?: string
|
||||
options?: Array<FormOption>
|
||||
custom?: boolean
|
||||
}
|
||||
|
||||
export type FormMultiselectFieldV2 = {
|
||||
key: string
|
||||
title?: string
|
||||
description?: string
|
||||
required?: boolean
|
||||
when?: Array<FormWhenV2>
|
||||
type: "multiselect"
|
||||
options: Array<FormOption>
|
||||
minItems?: number
|
||||
maxItems?: number
|
||||
custom?: boolean
|
||||
default?: Array<string>
|
||||
}
|
||||
|
||||
export type FormFormInfoV2 = {
|
||||
id: string
|
||||
sessionID: string
|
||||
title?: string
|
||||
metadata?: FormMetadata
|
||||
mode: "form"
|
||||
fields: Array<FormStringFieldV2 | FormNumberField | FormIntegerField | FormBooleanField | FormMultiselectFieldV2>
|
||||
}
|
||||
|
||||
export type FormUrlInfoV2 = {
|
||||
id: string
|
||||
sessionID: string
|
||||
title?: string
|
||||
metadata?: FormMetadata
|
||||
mode: "url"
|
||||
url: string
|
||||
}
|
||||
|
||||
export type FormCreatePayloadV2 = {
|
||||
id?: string | null
|
||||
title?: string
|
||||
metadata?: FormMetadata
|
||||
mode: "form" | "url"
|
||||
fields?: Array<
|
||||
FormStringFieldV2 | FormNumberField | FormIntegerField | FormBooleanField | FormMultiselectFieldV2
|
||||
> | null
|
||||
url?: string | null
|
||||
}
|
||||
|
||||
export type FormValueV2 =
|
||||
| string
|
||||
| number
|
||||
| "NaN"
|
||||
| "Infinity"
|
||||
| "-Infinity"
|
||||
| "Infinity"
|
||||
| "-Infinity"
|
||||
| "NaN"
|
||||
| boolean
|
||||
| Array<string>
|
||||
|
||||
export type PermissionV2SourceV2 = {
|
||||
type: "tool"
|
||||
messageID: string
|
||||
callID: string
|
||||
}
|
||||
|
||||
export type PermissionV2RequestV2 = {
|
||||
id: string
|
||||
sessionID: string
|
||||
action: string
|
||||
resources: Array<string>
|
||||
save?: Array<string>
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
source?: PermissionV2SourceV2
|
||||
}
|
||||
|
||||
export type ModelsDevRefreshedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "models-dev.refreshed"
|
||||
location?: LocationRefV2
|
||||
data:
|
||||
| {
|
||||
[key: string]: unknown
|
||||
}
|
||||
| Array<unknown>
|
||||
}
|
||||
|
||||
export type IntegrationUpdatedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "integration.updated"
|
||||
location?: LocationRefV2
|
||||
data:
|
||||
| {
|
||||
[key: string]: unknown
|
||||
}
|
||||
| Array<unknown>
|
||||
}
|
||||
|
||||
export type IntegrationConnectionUpdatedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "integration.connection.updated"
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
integrationID: string
|
||||
}
|
||||
}
|
||||
|
||||
export type CatalogUpdatedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "catalog.updated"
|
||||
location?: LocationRefV2
|
||||
data:
|
||||
| {
|
||||
[key: string]: unknown
|
||||
}
|
||||
| Array<unknown>
|
||||
}
|
||||
|
||||
export type AgentUpdatedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "agent.updated"
|
||||
location?: LocationRefV2
|
||||
data:
|
||||
| {
|
||||
[key: string]: unknown
|
||||
}
|
||||
| Array<unknown>
|
||||
}
|
||||
|
||||
export type SessionCreatedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.created"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
info: SessionV2
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionUpdatedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.updated"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
info: SessionV2
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionDeletedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.deleted"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
info: SessionV2
|
||||
}
|
||||
}
|
||||
|
||||
export type MessageUpdatedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "message.updated"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
info: Message
|
||||
}
|
||||
}
|
||||
|
||||
export type MessageRemovedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "message.removed"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
messageID: string
|
||||
}
|
||||
}
|
||||
|
||||
export type MessagePartUpdatedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "message.part.updated"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
part: Part
|
||||
time: number
|
||||
}
|
||||
}
|
||||
|
||||
export type MessagePartRemovedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "message.part.removed"
|
||||
durable: {
|
||||
aggregateID: string
|
||||
seq: number
|
||||
version: number
|
||||
}
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
messageID: string
|
||||
partID: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionTextDeltaV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.text.delta"
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
ordinal: number
|
||||
delta: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionReasoningDeltaV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.reasoning.delta"
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
ordinal: number
|
||||
delta: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionToolInputDeltaV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.tool.input.delta"
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
assistantMessageID: string
|
||||
callID: string
|
||||
delta: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionCompactionDeltaV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.compaction.delta"
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
text: string
|
||||
}
|
||||
}
|
||||
|
||||
export type FilesystemChangedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "filesystem.changed"
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
file: string
|
||||
event: "add" | "change" | "unlink"
|
||||
}
|
||||
}
|
||||
|
||||
export type ReferenceUpdatedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "reference.updated"
|
||||
location?: LocationRefV2
|
||||
data:
|
||||
| {
|
||||
[key: string]: unknown
|
||||
}
|
||||
| Array<unknown>
|
||||
}
|
||||
|
||||
export type PermissionV2AskedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "permission.v2.asked"
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
id: string
|
||||
sessionID: string
|
||||
action: string
|
||||
resources: Array<string>
|
||||
save?: Array<string>
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
source?: PermissionV2SourceV2
|
||||
}
|
||||
}
|
||||
|
||||
export type PermissionV2RepliedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "permission.v2.replied"
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
requestID: string
|
||||
reply: PermissionV2Reply
|
||||
}
|
||||
}
|
||||
|
||||
export type PluginAddedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "plugin.added"
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
id: string
|
||||
}
|
||||
}
|
||||
|
||||
export type ProjectDirectoriesUpdatedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "project.directories.updated"
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
projectID: string
|
||||
}
|
||||
}
|
||||
|
||||
export type CommandUpdatedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "command.updated"
|
||||
location?: LocationRefV2
|
||||
data:
|
||||
| {
|
||||
[key: string]: unknown
|
||||
}
|
||||
| Array<unknown>
|
||||
}
|
||||
|
||||
export type ConfigUpdatedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "config.updated"
|
||||
location?: LocationRefV2
|
||||
data:
|
||||
| {
|
||||
[key: string]: unknown
|
||||
}
|
||||
| Array<unknown>
|
||||
}
|
||||
|
||||
export type SkillUpdatedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "skill.updated"
|
||||
location?: LocationRefV2
|
||||
data:
|
||||
| {
|
||||
[key: string]: unknown
|
||||
}
|
||||
| Array<unknown>
|
||||
}
|
||||
|
||||
export type PtyCreatedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "pty.created"
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
info: PtyV2
|
||||
}
|
||||
}
|
||||
|
||||
export type PtyUpdatedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "pty.updated"
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
info: PtyV2
|
||||
}
|
||||
}
|
||||
|
||||
export type PtyExitedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "pty.exited"
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
id: string
|
||||
exitCode: number
|
||||
}
|
||||
}
|
||||
|
||||
export type PtyDeletedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "pty.deleted"
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
id: string
|
||||
}
|
||||
}
|
||||
|
||||
export type ShellCreatedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "shell.created"
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
info: ShellV2
|
||||
}
|
||||
}
|
||||
|
||||
export type ShellExitedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "shell.exited"
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
id: string
|
||||
exit?: number | "NaN" | "Infinity" | "-Infinity"
|
||||
status: "running" | "exited" | "timeout" | "killed"
|
||||
}
|
||||
}
|
||||
|
||||
export type ShellDeletedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "shell.deleted"
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
id: string
|
||||
}
|
||||
}
|
||||
|
||||
export type QuestionV2AskedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "question.v2.asked"
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
id: string
|
||||
sessionID: string
|
||||
/**
|
||||
* Questions to ask
|
||||
*/
|
||||
questions: Array<QuestionV2Info>
|
||||
tool?: QuestionV2Tool
|
||||
}
|
||||
}
|
||||
|
||||
export type QuestionV2RepliedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "question.v2.replied"
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
requestID: string
|
||||
answers: Array<QuestionV2Answer>
|
||||
}
|
||||
}
|
||||
|
||||
export type QuestionV2RejectedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "question.v2.rejected"
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
requestID: string
|
||||
}
|
||||
}
|
||||
|
||||
export type FormMetadata1 = {
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export type FormStringField1 = {
|
||||
key: string
|
||||
title?: string
|
||||
description?: string
|
||||
required?: boolean
|
||||
when?: Array<FormWhen1>
|
||||
type: "string"
|
||||
format?: "email" | "uri" | "date" | "date-time"
|
||||
minLength?: number
|
||||
maxLength?: number
|
||||
pattern?: string
|
||||
placeholder?: string
|
||||
default?: string
|
||||
options?: Array<FormOption>
|
||||
custom?: boolean
|
||||
}
|
||||
|
||||
export type FormBooleanField1 = {
|
||||
key: string
|
||||
title?: string
|
||||
description?: string
|
||||
required?: boolean
|
||||
when?: Array<FormWhen1>
|
||||
type: "boolean"
|
||||
default?: boolean
|
||||
}
|
||||
|
||||
export type FormMultiselectField1 = {
|
||||
key: string
|
||||
title?: string
|
||||
description?: string
|
||||
required?: boolean
|
||||
when?: Array<FormWhen1>
|
||||
type: "multiselect"
|
||||
options: Array<FormOption>
|
||||
minItems?: number
|
||||
maxItems?: number
|
||||
custom?: boolean
|
||||
default?: Array<string>
|
||||
}
|
||||
|
||||
export type FormFormInfo1 = {
|
||||
id: string
|
||||
sessionID: string
|
||||
title?: string
|
||||
metadata?: FormMetadata1
|
||||
mode: "form"
|
||||
fields: Array<FormStringField1 | FormNumberField1 | FormIntegerField1 | FormBooleanField1 | FormMultiselectField1>
|
||||
}
|
||||
|
||||
export type FormUrlInfo1 = {
|
||||
id: string
|
||||
sessionID: string
|
||||
title?: string
|
||||
metadata?: FormMetadata1
|
||||
mode: "url"
|
||||
url: string
|
||||
}
|
||||
|
||||
export type FormCreatedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "form.created"
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
form: FormFormInfo1 | FormUrlInfo1
|
||||
}
|
||||
}
|
||||
|
||||
export type FormAnswer1 = {
|
||||
[key: string]: FormValue1
|
||||
}
|
||||
|
||||
export type FormRepliedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "form.replied"
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
id: string
|
||||
sessionID: string
|
||||
answer: FormAnswer1
|
||||
}
|
||||
}
|
||||
|
||||
export type FormCancelledV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "form.cancelled"
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
id: string
|
||||
sessionID: string
|
||||
}
|
||||
}
|
||||
|
||||
export type TodoUpdatedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "todo.updated"
|
||||
location?: LocationRefV2
|
||||
data: {
|
||||
sessionID: string
|
||||
todos: Array<Todo>
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionIdleV2 = {
|
||||
export type SessionIdle2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.idle"
|
||||
location?: LocationRefV2
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
}
|
||||
}
|
||||
|
||||
export type TuiPromptAppendV2 = {
|
||||
export type TuiPromptAppend2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "tui.prompt.append"
|
||||
location?: LocationRefV2
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
text: string
|
||||
}
|
||||
}
|
||||
|
||||
export type TuiCommandExecuteV2 = {
|
||||
export type TuiCommandExecute2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "tui.command.execute"
|
||||
location?: LocationRefV2
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
command:
|
||||
| "session.list"
|
||||
@@ -10496,14 +11107,14 @@ export type TuiCommandExecuteV2 = {
|
||||
}
|
||||
}
|
||||
|
||||
export type TuiToastShowV2 = {
|
||||
export type TuiToastShow2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "tui.toast.show"
|
||||
location?: LocationRefV2
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
title?: string
|
||||
message: string
|
||||
@@ -10512,14 +11123,14 @@ export type TuiToastShowV2 = {
|
||||
}
|
||||
}
|
||||
|
||||
export type TuiSessionSelectV2 = {
|
||||
export type TuiSessionSelect2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "tui.session.select"
|
||||
location?: LocationRefV2
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
/**
|
||||
* Session ID to navigate to
|
||||
@@ -10528,66 +11139,66 @@ export type TuiSessionSelectV2 = {
|
||||
}
|
||||
}
|
||||
|
||||
export type InstallationUpdatedV2 = {
|
||||
export type InstallationUpdated2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "installation.updated"
|
||||
location?: LocationRefV2
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
version: string
|
||||
}
|
||||
}
|
||||
|
||||
export type InstallationUpdateAvailableV2 = {
|
||||
export type InstallationUpdateAvailable2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "installation.update-available"
|
||||
location?: LocationRefV2
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
version: string
|
||||
}
|
||||
}
|
||||
|
||||
export type VcsBranchUpdatedV2 = {
|
||||
export type VcsBranchUpdated2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "vcs.branch.updated"
|
||||
location?: LocationRefV2
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
branch?: string
|
||||
}
|
||||
}
|
||||
|
||||
export type McpStatusChangedV2 = {
|
||||
export type McpStatusChanged2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "mcp.status.changed"
|
||||
location?: LocationRefV2
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
server: string
|
||||
}
|
||||
}
|
||||
|
||||
export type PermissionAskedV2 = {
|
||||
export type PermissionAsked2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "permission.asked"
|
||||
location?: LocationRefV2
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
id: string
|
||||
sessionID: string
|
||||
@@ -10604,14 +11215,14 @@ export type PermissionAskedV2 = {
|
||||
}
|
||||
}
|
||||
|
||||
export type PermissionRepliedV2 = {
|
||||
export type PermissionReplied2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "permission.replied"
|
||||
location?: LocationRefV2
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
requestID: string
|
||||
@@ -10619,14 +11230,53 @@ export type PermissionRepliedV2 = {
|
||||
}
|
||||
}
|
||||
|
||||
export type QuestionAskedV2 = {
|
||||
export type QuestionOptionV2 = {
|
||||
/**
|
||||
* Display text (1-5 words, concise)
|
||||
*/
|
||||
label: string
|
||||
/**
|
||||
* Explanation of choice
|
||||
*/
|
||||
description: string
|
||||
}
|
||||
|
||||
export type QuestionInfoV2 = {
|
||||
/**
|
||||
* Complete question
|
||||
*/
|
||||
question: string
|
||||
/**
|
||||
* Very short label (max 30 chars)
|
||||
*/
|
||||
header: string
|
||||
/**
|
||||
* Available choices
|
||||
*/
|
||||
options: Array<QuestionOptionV2>
|
||||
/**
|
||||
* Allow selecting multiple choices
|
||||
*/
|
||||
multiple?: boolean | null
|
||||
/**
|
||||
* Allow typing a custom answer (default: true)
|
||||
*/
|
||||
custom?: boolean | null
|
||||
}
|
||||
|
||||
export type QuestionToolV2 = {
|
||||
messageID: string
|
||||
callID: string
|
||||
}
|
||||
|
||||
export type QuestionAsked2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "question.asked"
|
||||
location?: LocationRefV2
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
id: string
|
||||
sessionID: string
|
||||
@@ -10638,6 +11288,8 @@ export type QuestionAskedV2 = {
|
||||
}
|
||||
}
|
||||
|
||||
export type QuestionAnswerV2 = Array<string>
|
||||
|
||||
export type QuestionRepliedV2 = {
|
||||
id: string
|
||||
created: number
|
||||
@@ -10645,11 +11297,11 @@ export type QuestionRepliedV2 = {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "question.replied"
|
||||
location?: LocationRefV2
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
requestID: string
|
||||
answers: Array<QuestionAnswer>
|
||||
answers: Array<QuestionAnswerV2>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10660,31 +11312,31 @@ export type QuestionRejectedV2 = {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "question.rejected"
|
||||
location?: LocationRefV2
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID: string
|
||||
requestID: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionErrorV2 = {
|
||||
export type SessionError2 = {
|
||||
id: string
|
||||
created: number
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
type: "session.error"
|
||||
location?: LocationRefV2
|
||||
location?: LocationRef2
|
||||
data: {
|
||||
sessionID?: string | null
|
||||
error?:
|
||||
| ProviderAuthError
|
||||
| ProviderAuthErrorV2
|
||||
| UnknownError1V2
|
||||
| MessageOutputLengthErrorV2
|
||||
| MessageAbortedError
|
||||
| MessageAbortedErrorV2
|
||||
| StructuredOutputErrorV2
|
||||
| ContextOverflowErrorV2
|
||||
| ContentFilterError
|
||||
| ContentFilterErrorV2
|
||||
| ApiErrorV2
|
||||
| null
|
||||
}
|
||||
@@ -10695,7 +11347,7 @@ export type V2EventServerConnected = {
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
} | null
|
||||
location?: LocationRefV2 | null
|
||||
location?: LocationRef2 | null
|
||||
type: "server.connected"
|
||||
data:
|
||||
| {
|
||||
@@ -10704,10 +11356,105 @@ export type V2EventServerConnected = {
|
||||
| Array<unknown>
|
||||
}
|
||||
|
||||
export type V2EventV2 =
|
||||
| ModelsDevRefreshed2
|
||||
| IntegrationUpdated2
|
||||
| IntegrationConnectionUpdated2
|
||||
| CatalogUpdated2
|
||||
| AgentUpdated2
|
||||
| SessionCreated2
|
||||
| SessionUpdated2
|
||||
| SessionDeleted2
|
||||
| MessageUpdated2
|
||||
| MessageRemoved2
|
||||
| MessagePartUpdated2
|
||||
| MessagePartRemoved2
|
||||
| SessionAgentSelected2
|
||||
| SessionModelSelected2
|
||||
| SessionMoved2
|
||||
| SessionRenamed2
|
||||
| SessionForked2
|
||||
| SessionPromptPromoted2
|
||||
| SessionPromptAdmitted2
|
||||
| SessionExecutionStarted2
|
||||
| SessionExecutionSucceeded2
|
||||
| SessionExecutionFailed2
|
||||
| SessionExecutionInterrupted2
|
||||
| SessionContextUpdated2
|
||||
| SessionSynthetic2
|
||||
| SessionSkillActivated2
|
||||
| SessionShellStarted2
|
||||
| SessionShellEnded2
|
||||
| SessionStepStarted2
|
||||
| SessionStepEnded2
|
||||
| SessionStepFailed2
|
||||
| SessionTextStarted2
|
||||
| SessionTextDelta2
|
||||
| SessionTextEnded2
|
||||
| SessionReasoningStarted2
|
||||
| SessionReasoningDelta2
|
||||
| SessionReasoningEnded2
|
||||
| SessionToolInputStarted2
|
||||
| SessionToolInputDelta2
|
||||
| SessionToolInputEnded2
|
||||
| SessionToolCalled2
|
||||
| SessionToolProgress2
|
||||
| SessionToolSuccess2
|
||||
| SessionToolFailed2
|
||||
| SessionRetryScheduled2
|
||||
| SessionCompactionStarted2
|
||||
| SessionCompactionDelta2
|
||||
| SessionCompactionEnded2
|
||||
| SessionRevertStaged2
|
||||
| SessionRevertCleared2
|
||||
| SessionRevertCommitted2
|
||||
| FilesystemChanged2
|
||||
| ReferenceUpdated2
|
||||
| PermissionV2Asked2
|
||||
| PermissionV2Replied2
|
||||
| PluginAdded2
|
||||
| ProjectDirectoriesUpdated2
|
||||
| CommandUpdated2
|
||||
| ConfigUpdated2
|
||||
| SkillUpdated2
|
||||
| PtyCreated2
|
||||
| PtyUpdated2
|
||||
| PtyExited2
|
||||
| PtyDeleted2
|
||||
| ShellCreated2
|
||||
| ShellExited2
|
||||
| ShellDeleted2
|
||||
| QuestionV2Asked2
|
||||
| QuestionV2Replied2
|
||||
| QuestionV2Rejected2
|
||||
| FormCreated2
|
||||
| FormReplied2
|
||||
| FormCancelled2
|
||||
| TodoUpdated2
|
||||
| SessionStatusV22
|
||||
| SessionIdle2
|
||||
| TuiPromptAppend2
|
||||
| TuiCommandExecute2
|
||||
| TuiToastShow2
|
||||
| TuiSessionSelect2
|
||||
| InstallationUpdated2
|
||||
| InstallationUpdateAvailable2
|
||||
| VcsBranchUpdated2
|
||||
| McpStatusChanged2
|
||||
| PermissionAsked2
|
||||
| PermissionReplied2
|
||||
| QuestionAsked2
|
||||
| QuestionRepliedV2
|
||||
| QuestionRejectedV2
|
||||
| SessionError2
|
||||
| V2EventServerConnected
|
||||
|
||||
export type V2EventStreamV2 = string
|
||||
|
||||
/**
|
||||
* Payload-free change hint: the aggregate's durable log advanced to at least seq. Hints coalesce under backpressure (latest per aggregate) and are never a delivery guarantee.
|
||||
*/
|
||||
export type EventLogHintV2 = {
|
||||
export type EventLogHint2 = {
|
||||
type: "log.hint"
|
||||
aggregateID: string
|
||||
seq: number
|
||||
@@ -10716,23 +11463,94 @@ export type EventLogHintV2 = {
|
||||
/**
|
||||
* Hints may have been lost; treat every aggregate as potentially dirty and recover via bounded sweep plus durable log reads. Emitted first on every (re)subscribe.
|
||||
*/
|
||||
export type EventLogSweepRequiredV2 = {
|
||||
export type EventLogSweepRequired2 = {
|
||||
type: "log.sweep_required"
|
||||
}
|
||||
|
||||
export type PtyTicketConnectTokenV2 = {
|
||||
export type EventLogChange2 = EventLogHint2 | EventLogSweepRequired2
|
||||
|
||||
export type EventLogChangeStream2 = string
|
||||
|
||||
export type PtyNotFoundErrorV2 = {
|
||||
_tag: "PtyNotFoundError"
|
||||
ptyID: string
|
||||
message: string
|
||||
}
|
||||
|
||||
export type PtyTicketConnectToken2 = {
|
||||
ticket: string
|
||||
expires_in: number
|
||||
}
|
||||
|
||||
export type QuestionV2RequestV2 = {
|
||||
export type ForbiddenErrorV2 = {
|
||||
_tag: "ForbiddenError"
|
||||
message: string
|
||||
}
|
||||
|
||||
export type ShellNotFoundErrorV2 = {
|
||||
_tag: "ShellNotFoundError"
|
||||
id: string
|
||||
message: string
|
||||
}
|
||||
|
||||
export type QuestionV2Request2 = {
|
||||
id: string
|
||||
sessionID: string
|
||||
/**
|
||||
* Questions to ask
|
||||
*/
|
||||
questions: Array<QuestionV2Info>
|
||||
tool?: QuestionV2Tool
|
||||
questions: Array<QuestionV2Info2>
|
||||
tool?: QuestionV2Tool2
|
||||
}
|
||||
|
||||
export type QuestionV2Reply2 = {
|
||||
/**
|
||||
* User answers in order of questions (each answer is an array of selected labels)
|
||||
*/
|
||||
answers: Array<QuestionV2Answer2>
|
||||
}
|
||||
|
||||
export type QuestionNotFoundErrorV2 = {
|
||||
_tag: "QuestionNotFoundError"
|
||||
requestID: string
|
||||
message: string
|
||||
}
|
||||
|
||||
export type ReferenceLocalSource2 = {
|
||||
type: "local"
|
||||
path: string
|
||||
description?: string
|
||||
hidden?: boolean
|
||||
}
|
||||
|
||||
export type ReferenceGitSource2 = {
|
||||
type: "git"
|
||||
repository: string
|
||||
branch?: string
|
||||
description?: string
|
||||
hidden?: boolean
|
||||
}
|
||||
|
||||
export type ReferenceSource2 = ReferenceLocalSource2 | ReferenceGitSource2
|
||||
|
||||
export type ReferenceInfo2 = {
|
||||
name: string
|
||||
path: string
|
||||
description?: string
|
||||
hidden?: boolean
|
||||
source: ReferenceSource2
|
||||
}
|
||||
|
||||
export type ProjectCopyCopy2 = {
|
||||
directory: string
|
||||
}
|
||||
|
||||
export type ProjectCopyErrorV2 = {
|
||||
name: "ProjectCopyError"
|
||||
data: {
|
||||
message: string
|
||||
forceRequired?: boolean | null
|
||||
}
|
||||
}
|
||||
|
||||
export type VcsFileStatusV2 = {
|
||||
@@ -10742,6 +11560,8 @@ export type VcsFileStatusV2 = {
|
||||
status: "added" | "deleted" | "modified"
|
||||
}
|
||||
|
||||
export type VcsMode2 = "working" | "branch"
|
||||
|
||||
export type AuthRemoveData = {
|
||||
body?: never
|
||||
path: {
|
||||
@@ -14890,7 +15710,7 @@ export type V2HealthGetErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2HealthGetError = V2HealthGetErrors[keyof V2HealthGetErrors]
|
||||
@@ -14926,7 +15746,7 @@ export type V2LocationGetErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2LocationGetError = V2LocationGetErrors[keyof V2LocationGetErrors]
|
||||
@@ -14935,7 +15755,7 @@ export type V2LocationGetResponses = {
|
||||
/**
|
||||
* Location.Info
|
||||
*/
|
||||
200: LocationInfoV2
|
||||
200: LocationInfo2
|
||||
}
|
||||
|
||||
export type V2LocationGetResponse = V2LocationGetResponses[keyof V2LocationGetResponses]
|
||||
@@ -14960,7 +15780,7 @@ export type V2AgentListErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2AgentListError = V2AgentListErrors[keyof V2AgentListErrors]
|
||||
@@ -14970,8 +15790,8 @@ export type V2AgentListResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
location: LocationInfoV2
|
||||
data: Array<AgentV2InfoV2>
|
||||
location: LocationInfo2
|
||||
data: Array<AgentV2Info2>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14997,7 +15817,7 @@ export type V2PluginListErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2PluginListError = V2PluginListErrors[keyof V2PluginListErrors]
|
||||
@@ -15007,8 +15827,8 @@ export type V2PluginListResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
location: LocationInfoV2
|
||||
data: Array<PluginInfo>
|
||||
location: LocationInfo2
|
||||
data: Array<PluginInfo2>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15041,11 +15861,11 @@ export type V2SessionListErrors = {
|
||||
/**
|
||||
* InvalidCursorError | InvalidRequestError
|
||||
*/
|
||||
400: InvalidCursorError | InvalidRequestError1 | InvalidRequestErrorV2
|
||||
400: InvalidCursorErrorV2 | InvalidRequestError1 | InvalidRequestErrorV2
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2SessionListError = V2SessionListErrors[keyof V2SessionListErrors]
|
||||
@@ -15063,8 +15883,8 @@ export type V2SessionCreateData = {
|
||||
body: {
|
||||
id?: string | null
|
||||
agent?: string | null
|
||||
model?: ModelRef | null
|
||||
location?: LocationRefV2 | null
|
||||
model?: ModelRef2 | null
|
||||
location?: LocationRef2 | null
|
||||
}
|
||||
path?: never
|
||||
query?: never
|
||||
@@ -15079,7 +15899,7 @@ export type V2SessionCreateErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2SessionCreateError = V2SessionCreateErrors[keyof V2SessionCreateErrors]
|
||||
@@ -15089,7 +15909,7 @@ export type V2SessionCreateResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
data: SessionV2InfoV2
|
||||
data: SessionV2Info2
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15110,7 +15930,7 @@ export type V2SessionActiveErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2SessionActiveError = V2SessionActiveErrors[keyof V2SessionActiveErrors]
|
||||
@@ -15121,7 +15941,7 @@ export type V2SessionActiveResponses = {
|
||||
*/
|
||||
200: {
|
||||
data: {
|
||||
[key: string]: unknown | SessionActive
|
||||
[key: string]: unknown | SessionActiveV2
|
||||
}
|
||||
watermarks: SessionWatermarksV2
|
||||
}
|
||||
@@ -15146,11 +15966,11 @@ export type V2SessionGetErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* SessionNotFoundError
|
||||
*/
|
||||
404: SessionNotFoundError
|
||||
404: SessionNotFoundErrorV2
|
||||
}
|
||||
|
||||
export type V2SessionGetError = V2SessionGetErrors[keyof V2SessionGetErrors]
|
||||
@@ -15160,7 +15980,7 @@ export type V2SessionGetResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
data: SessionV2InfoV2
|
||||
data: SessionV2Info2
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15185,11 +16005,11 @@ export type V2SessionForkErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* SessionNotFoundError | MessageNotFoundError
|
||||
*/
|
||||
404: MessageNotFoundError | SessionNotFoundError
|
||||
404: MessageNotFoundErrorV2 | SessionNotFoundErrorV2
|
||||
}
|
||||
|
||||
export type V2SessionForkError = V2SessionForkErrors[keyof V2SessionForkErrors]
|
||||
@@ -15199,7 +16019,7 @@ export type V2SessionForkResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
data: SessionV2InfoV2
|
||||
data: SessionV2Info2
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15224,11 +16044,11 @@ export type V2SessionSwitchAgentErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* SessionNotFoundError
|
||||
*/
|
||||
404: SessionNotFoundError
|
||||
404: SessionNotFoundErrorV2
|
||||
}
|
||||
|
||||
export type V2SessionSwitchAgentError = V2SessionSwitchAgentErrors[keyof V2SessionSwitchAgentErrors]
|
||||
@@ -15244,7 +16064,7 @@ export type V2SessionSwitchAgentResponse = V2SessionSwitchAgentResponses[keyof V
|
||||
|
||||
export type V2SessionSwitchModelData = {
|
||||
body: {
|
||||
model: ModelRef
|
||||
model: ModelRef2
|
||||
}
|
||||
path: {
|
||||
sessionID: string
|
||||
@@ -15261,11 +16081,11 @@ export type V2SessionSwitchModelErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* SessionNotFoundError
|
||||
*/
|
||||
404: SessionNotFoundError
|
||||
404: SessionNotFoundErrorV2
|
||||
}
|
||||
|
||||
export type V2SessionSwitchModelError = V2SessionSwitchModelErrors[keyof V2SessionSwitchModelErrors]
|
||||
@@ -15298,11 +16118,11 @@ export type V2SessionRenameErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* SessionNotFoundError
|
||||
*/
|
||||
404: SessionNotFoundError
|
||||
404: SessionNotFoundErrorV2
|
||||
}
|
||||
|
||||
export type V2SessionRenameError = V2SessionRenameErrors[keyof V2SessionRenameErrors]
|
||||
@@ -15319,7 +16139,7 @@ export type V2SessionRenameResponse = V2SessionRenameResponses[keyof V2SessionRe
|
||||
export type V2SessionPromptData = {
|
||||
body: {
|
||||
id?: string | null
|
||||
prompt: PromptInput
|
||||
prompt: PromptInputV2
|
||||
delivery?: "steer" | "queue" | null
|
||||
resume?: boolean | null
|
||||
}
|
||||
@@ -15338,11 +16158,11 @@ export type V2SessionPromptErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* SessionNotFoundError
|
||||
*/
|
||||
404: SessionNotFoundError
|
||||
404: SessionNotFoundErrorV2
|
||||
/**
|
||||
* ConflictError
|
||||
*/
|
||||
@@ -15356,7 +16176,7 @@ export type V2SessionPromptResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
data: SessionInputAdmittedV2
|
||||
data: SessionInputAdmitted2
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15368,9 +16188,9 @@ export type V2SessionCommandData = {
|
||||
command: string
|
||||
arguments?: string | null
|
||||
agent?: string | null
|
||||
model?: ModelRef | null
|
||||
files?: Array<PromptInputFileAttachment>
|
||||
agents?: Array<PromptAgentAttachment>
|
||||
model?: ModelRef2 | null
|
||||
files?: Array<PromptInputFileAttachment2>
|
||||
agents?: Array<PromptAgentAttachment2>
|
||||
delivery?: "steer" | "queue" | null
|
||||
resume?: boolean | null
|
||||
}
|
||||
@@ -15389,11 +16209,11 @@ export type V2SessionCommandErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* SessionNotFoundError | CommandNotFoundError
|
||||
*/
|
||||
404: CommandNotFoundError | SessionNotFoundError
|
||||
404: CommandNotFoundErrorV2 | SessionNotFoundErrorV2
|
||||
/**
|
||||
* ConflictError
|
||||
*/
|
||||
@@ -15401,7 +16221,7 @@ export type V2SessionCommandErrors = {
|
||||
/**
|
||||
* CommandEvaluationError
|
||||
*/
|
||||
500: CommandEvaluationError
|
||||
500: CommandEvaluationErrorV2
|
||||
}
|
||||
|
||||
export type V2SessionCommandError = V2SessionCommandErrors[keyof V2SessionCommandErrors]
|
||||
@@ -15411,7 +16231,7 @@ export type V2SessionCommandResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
data: SessionInputAdmittedV2
|
||||
data: SessionInputAdmitted2
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15438,11 +16258,11 @@ export type V2SessionSkillErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* SessionNotFoundError | SkillNotFoundError
|
||||
*/
|
||||
404: SkillNotFoundError | SessionNotFoundError
|
||||
404: SkillNotFoundErrorV2 | SessionNotFoundErrorV2
|
||||
}
|
||||
|
||||
export type V2SessionSkillError = V2SessionSkillErrors[keyof V2SessionSkillErrors]
|
||||
@@ -15479,11 +16299,11 @@ export type V2SessionSyntheticErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* SessionNotFoundError
|
||||
*/
|
||||
404: SessionNotFoundError
|
||||
404: SessionNotFoundErrorV2
|
||||
}
|
||||
|
||||
export type V2SessionSyntheticError = V2SessionSyntheticErrors[keyof V2SessionSyntheticErrors]
|
||||
@@ -15517,11 +16337,11 @@ export type V2SessionShellErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* SessionNotFoundError
|
||||
*/
|
||||
404: SessionNotFoundError
|
||||
404: SessionNotFoundErrorV2
|
||||
}
|
||||
|
||||
export type V2SessionShellError = V2SessionShellErrors[keyof V2SessionShellErrors]
|
||||
@@ -15536,9 +16356,7 @@ export type V2SessionShellResponses = {
|
||||
export type V2SessionShellResponse = V2SessionShellResponses[keyof V2SessionShellResponses]
|
||||
|
||||
export type V2SessionCompactData = {
|
||||
body: {
|
||||
id?: string | null
|
||||
}
|
||||
body?: never
|
||||
path: {
|
||||
sessionID: string
|
||||
}
|
||||
@@ -15554,26 +16372,32 @@ export type V2SessionCompactErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* SessionNotFoundError
|
||||
*/
|
||||
404: SessionNotFoundError
|
||||
404: SessionNotFoundErrorV2
|
||||
/**
|
||||
* ConflictError
|
||||
* SessionBusyError
|
||||
*/
|
||||
409: ConflictErrorV2
|
||||
409: SessionBusyErrorV2
|
||||
/**
|
||||
* UnknownError
|
||||
*/
|
||||
500: UnknownErrorV2
|
||||
/**
|
||||
* ServiceUnavailableError
|
||||
*/
|
||||
503: ServiceUnavailableErrorV2
|
||||
}
|
||||
|
||||
export type V2SessionCompactError = V2SessionCompactErrors[keyof V2SessionCompactErrors]
|
||||
|
||||
export type V2SessionCompactResponses = {
|
||||
/**
|
||||
* Success
|
||||
* <No Content>
|
||||
*/
|
||||
200: {
|
||||
data: SessionInputCompactionV2
|
||||
}
|
||||
204: void
|
||||
}
|
||||
|
||||
export type V2SessionCompactResponse = V2SessionCompactResponses[keyof V2SessionCompactResponses]
|
||||
@@ -15595,11 +16419,11 @@ export type V2SessionWaitErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* SessionNotFoundError
|
||||
*/
|
||||
404: SessionNotFoundError
|
||||
404: SessionNotFoundErrorV2
|
||||
/**
|
||||
* ServiceUnavailableError
|
||||
*/
|
||||
@@ -15637,15 +16461,15 @@ export type V2SessionRevertStageErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* MessageNotFoundError | SessionNotFoundError
|
||||
*/
|
||||
404: MessageNotFoundError | SessionNotFoundError
|
||||
404: MessageNotFoundErrorV2 | SessionNotFoundErrorV2
|
||||
/**
|
||||
* SessionBusyError
|
||||
*/
|
||||
409: SessionBusyError
|
||||
409: SessionBusyErrorV2
|
||||
/**
|
||||
* UnknownError
|
||||
*/
|
||||
@@ -15659,7 +16483,7 @@ export type V2SessionRevertStageResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
data: RevertStateV2
|
||||
data: RevertState2
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15682,15 +16506,15 @@ export type V2SessionRevertClearErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* SessionNotFoundError
|
||||
*/
|
||||
404: SessionNotFoundError
|
||||
404: SessionNotFoundErrorV2
|
||||
/**
|
||||
* SessionBusyError
|
||||
*/
|
||||
409: SessionBusyError
|
||||
409: SessionBusyErrorV2
|
||||
/**
|
||||
* UnknownError
|
||||
*/
|
||||
@@ -15725,15 +16549,15 @@ export type V2SessionRevertCommitErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* SessionNotFoundError
|
||||
*/
|
||||
404: SessionNotFoundError
|
||||
404: SessionNotFoundErrorV2
|
||||
/**
|
||||
* SessionBusyError
|
||||
*/
|
||||
409: SessionBusyError
|
||||
409: SessionBusyErrorV2
|
||||
}
|
||||
|
||||
export type V2SessionRevertCommitError = V2SessionRevertCommitErrors[keyof V2SessionRevertCommitErrors]
|
||||
@@ -15764,11 +16588,11 @@ export type V2SessionContextErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* SessionNotFoundError
|
||||
*/
|
||||
404: SessionNotFoundError
|
||||
404: SessionNotFoundErrorV2
|
||||
/**
|
||||
* UnknownError
|
||||
*/
|
||||
@@ -15782,7 +16606,7 @@ export type V2SessionContextResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
data: Array<SessionMessage>
|
||||
data: Array<SessionMessage2>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15805,11 +16629,11 @@ export type V2SessionContextEntryListErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* SessionNotFoundError
|
||||
*/
|
||||
404: SessionNotFoundError
|
||||
404: SessionNotFoundErrorV2
|
||||
}
|
||||
|
||||
export type V2SessionContextEntryListError = V2SessionContextEntryListErrors[keyof V2SessionContextEntryListErrors]
|
||||
@@ -15819,7 +16643,7 @@ export type V2SessionContextEntryListResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
data: Array<SessionContextEntryInfo>
|
||||
data: Array<SessionContextEntryInfo2>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15830,7 +16654,7 @@ export type V2SessionContextEntryRemoveData = {
|
||||
body?: never
|
||||
path: {
|
||||
sessionID: string
|
||||
key: SessionContextEntryKeyV2
|
||||
key: SessionContextEntryKey2
|
||||
}
|
||||
query?: never
|
||||
url: "/api/session/{sessionID}/context-entry/{key}"
|
||||
@@ -15844,11 +16668,11 @@ export type V2SessionContextEntryRemoveErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* SessionNotFoundError
|
||||
*/
|
||||
404: SessionNotFoundError
|
||||
404: SessionNotFoundErrorV2
|
||||
}
|
||||
|
||||
export type V2SessionContextEntryRemoveError =
|
||||
@@ -15870,7 +16694,7 @@ export type V2SessionContextEntryPutData = {
|
||||
}
|
||||
path: {
|
||||
sessionID: string
|
||||
key: SessionContextEntryKeyV2
|
||||
key: SessionContextEntryKey2
|
||||
}
|
||||
query?: never
|
||||
url: "/api/session/{sessionID}/context-entry/{key}"
|
||||
@@ -15884,11 +16708,11 @@ export type V2SessionContextEntryPutErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* SessionNotFoundError
|
||||
*/
|
||||
404: SessionNotFoundError
|
||||
404: SessionNotFoundErrorV2
|
||||
}
|
||||
|
||||
export type V2SessionContextEntryPutError = V2SessionContextEntryPutErrors[keyof V2SessionContextEntryPutErrors]
|
||||
@@ -15923,11 +16747,11 @@ export type V2SessionLogErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* SessionNotFoundError
|
||||
*/
|
||||
404: SessionNotFoundError
|
||||
404: SessionNotFoundErrorV2
|
||||
}
|
||||
|
||||
export type V2SessionLogError = V2SessionLogErrors[keyof V2SessionLogErrors]
|
||||
@@ -15939,7 +16763,7 @@ export type V2SessionLogResponses = {
|
||||
200: {
|
||||
id: string | null
|
||||
event: string
|
||||
data: SessionLogItemStream
|
||||
data: SessionLogItemStreamV2
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15962,11 +16786,11 @@ export type V2SessionInterruptErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* SessionNotFoundError
|
||||
*/
|
||||
404: SessionNotFoundError
|
||||
404: SessionNotFoundErrorV2
|
||||
}
|
||||
|
||||
export type V2SessionInterruptError = V2SessionInterruptErrors[keyof V2SessionInterruptErrors]
|
||||
@@ -15997,11 +16821,11 @@ export type V2SessionBackgroundErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* SessionNotFoundError
|
||||
*/
|
||||
404: SessionNotFoundError
|
||||
404: SessionNotFoundErrorV2
|
||||
}
|
||||
|
||||
export type V2SessionBackgroundError = V2SessionBackgroundErrors[keyof V2SessionBackgroundErrors]
|
||||
@@ -16033,11 +16857,11 @@ export type V2SessionMessageErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* SessionNotFoundError | MessageNotFoundError
|
||||
*/
|
||||
404: MessageNotFoundError | SessionNotFoundError
|
||||
404: MessageNotFoundErrorV2 | SessionNotFoundErrorV2
|
||||
}
|
||||
|
||||
export type V2SessionMessageError = V2SessionMessageErrors[keyof V2SessionMessageErrors]
|
||||
@@ -16047,7 +16871,7 @@ export type V2SessionMessageResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
data: SessionMessage
|
||||
data: SessionMessage2
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16076,15 +16900,15 @@ export type V2SessionMessagesErrors = {
|
||||
/**
|
||||
* InvalidCursorError | InvalidRequestError
|
||||
*/
|
||||
400: InvalidCursorError | InvalidRequestErrorV2
|
||||
400: InvalidCursorErrorV2 | InvalidRequestErrorV2
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* SessionNotFoundError
|
||||
*/
|
||||
404: SessionNotFoundError
|
||||
404: SessionNotFoundErrorV2
|
||||
/**
|
||||
* UnknownError
|
||||
*/
|
||||
@@ -16122,7 +16946,7 @@ export type V2ModelListErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* ServiceUnavailableError
|
||||
*/
|
||||
@@ -16136,8 +16960,8 @@ export type V2ModelListResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
location: LocationInfoV2
|
||||
data: Array<ModelV2Info>
|
||||
location: LocationInfo2
|
||||
data: Array<ModelV2Info2>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16163,7 +16987,7 @@ export type V2ModelDefaultErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* ServiceUnavailableError
|
||||
*/
|
||||
@@ -16177,8 +17001,8 @@ export type V2ModelDefaultResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
location: LocationInfoV2
|
||||
data: ModelV2Info | null
|
||||
location: LocationInfo2
|
||||
data: ModelV2Info2 | null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16187,7 +17011,7 @@ export type V2ModelDefaultResponse = V2ModelDefaultResponses[keyof V2ModelDefaul
|
||||
export type V2GenerateTextData = {
|
||||
body: {
|
||||
prompt: string
|
||||
model?: ModelRef | null
|
||||
model?: ModelRef2 | null
|
||||
}
|
||||
path?: never
|
||||
query?: {
|
||||
@@ -16207,7 +17031,7 @@ export type V2GenerateTextErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* ServiceUnavailableError
|
||||
*/
|
||||
@@ -16220,7 +17044,7 @@ export type V2GenerateTextResponses = {
|
||||
/**
|
||||
* GenerateTextResponse
|
||||
*/
|
||||
200: GenerateTextResponse
|
||||
200: GenerateTextResponseV2
|
||||
}
|
||||
|
||||
export type V2GenerateTextResponse = V2GenerateTextResponses[keyof V2GenerateTextResponses]
|
||||
@@ -16245,7 +17069,7 @@ export type V2ProviderListErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* ServiceUnavailableError
|
||||
*/
|
||||
@@ -16259,8 +17083,8 @@ export type V2ProviderListResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
location: LocationInfoV2
|
||||
data: Array<ProviderV2Info>
|
||||
location: LocationInfo2
|
||||
data: Array<ProviderV2Info2>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16288,11 +17112,11 @@ export type V2ProviderGetErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* ProviderNotFoundError
|
||||
*/
|
||||
404: ProviderNotFoundError
|
||||
404: ProviderNotFoundErrorV2
|
||||
/**
|
||||
* ServiceUnavailableError
|
||||
*/
|
||||
@@ -16306,8 +17130,8 @@ export type V2ProviderGetResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
location: LocationInfoV2
|
||||
data: ProviderV2Info
|
||||
location: LocationInfo2
|
||||
data: ProviderV2Info2
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16333,7 +17157,7 @@ export type V2IntegrationListErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2IntegrationListError = V2IntegrationListErrors[keyof V2IntegrationListErrors]
|
||||
@@ -16343,8 +17167,8 @@ export type V2IntegrationListResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
location: LocationInfoV2
|
||||
data: Array<IntegrationInfo>
|
||||
location: LocationInfo2
|
||||
data: Array<IntegrationInfo2>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16372,7 +17196,7 @@ export type V2IntegrationGetErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2IntegrationGetError = V2IntegrationGetErrors[keyof V2IntegrationGetErrors]
|
||||
@@ -16382,8 +17206,8 @@ export type V2IntegrationGetResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
location: LocationInfoV2
|
||||
data: IntegrationInfo | null
|
||||
location: LocationInfo2
|
||||
data: IntegrationInfo2 | null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16414,7 +17238,7 @@ export type V2IntegrationConnectKeyErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2IntegrationConnectKeyError = V2IntegrationConnectKeyErrors[keyof V2IntegrationConnectKeyErrors]
|
||||
@@ -16456,7 +17280,7 @@ export type V2IntegrationConnectOauthErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2IntegrationConnectOauthError = V2IntegrationConnectOauthErrors[keyof V2IntegrationConnectOauthErrors]
|
||||
@@ -16466,8 +17290,8 @@ export type V2IntegrationConnectOauthResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
location: LocationInfoV2
|
||||
data: IntegrationAttempt
|
||||
location: LocationInfo2
|
||||
data: IntegrationAttempt2
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16496,7 +17320,7 @@ export type V2IntegrationAttemptCancelErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2IntegrationAttemptCancelError = V2IntegrationAttemptCancelErrors[keyof V2IntegrationAttemptCancelErrors]
|
||||
@@ -16533,7 +17357,7 @@ export type V2IntegrationAttemptStatusErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2IntegrationAttemptStatusError = V2IntegrationAttemptStatusErrors[keyof V2IntegrationAttemptStatusErrors]
|
||||
@@ -16543,8 +17367,8 @@ export type V2IntegrationAttemptStatusResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
location: LocationInfoV2
|
||||
data: IntegrationAttemptStatus
|
||||
location: LocationInfo2
|
||||
data: IntegrationAttemptStatus2
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16575,7 +17399,7 @@ export type V2IntegrationAttemptCompleteErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2IntegrationAttemptCompleteError =
|
||||
@@ -16611,7 +17435,7 @@ export type V2McpListErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2McpListError = V2McpListErrors[keyof V2McpListErrors]
|
||||
@@ -16621,8 +17445,8 @@ export type V2McpListResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
location: LocationInfoV2
|
||||
data: Array<McpServer>
|
||||
location: LocationInfo2
|
||||
data: Array<McpServer2>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16650,7 +17474,7 @@ export type V2CredentialRemoveErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2CredentialRemoveError = V2CredentialRemoveErrors[keyof V2CredentialRemoveErrors]
|
||||
@@ -16688,7 +17512,7 @@ export type V2CredentialUpdateErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2CredentialUpdateError = V2CredentialUpdateErrors[keyof V2CredentialUpdateErrors]
|
||||
@@ -16722,7 +17546,7 @@ export type V2ProjectCurrentErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2ProjectCurrentError = V2ProjectCurrentErrors[keyof V2ProjectCurrentErrors]
|
||||
@@ -16731,7 +17555,7 @@ export type V2ProjectCurrentResponses = {
|
||||
/**
|
||||
* Project.Current
|
||||
*/
|
||||
200: ProjectCurrent
|
||||
200: ProjectCurrent2
|
||||
}
|
||||
|
||||
export type V2ProjectCurrentResponse = V2ProjectCurrentResponses[keyof V2ProjectCurrentResponses]
|
||||
@@ -16758,7 +17582,7 @@ export type V2ProjectDirectoriesErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2ProjectDirectoriesError = V2ProjectDirectoriesErrors[keyof V2ProjectDirectoriesErrors]
|
||||
@@ -16767,7 +17591,7 @@ export type V2ProjectDirectoriesResponses = {
|
||||
/**
|
||||
* Project.Directories
|
||||
*/
|
||||
200: ProjectDirectories
|
||||
200: ProjectDirectories2
|
||||
}
|
||||
|
||||
export type V2ProjectDirectoriesResponse = V2ProjectDirectoriesResponses[keyof V2ProjectDirectoriesResponses]
|
||||
@@ -16792,7 +17616,7 @@ export type V2FormRequestListErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2FormRequestListError = V2FormRequestListErrors[keyof V2FormRequestListErrors]
|
||||
@@ -16802,8 +17626,8 @@ export type V2FormRequestListResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
location: LocationInfoV2
|
||||
data: Array<FormFormInfoV2 | FormUrlInfoV2>
|
||||
location: LocationInfo2
|
||||
data: Array<FormFormInfo2 | FormUrlInfo2>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16826,11 +17650,11 @@ export type V2SessionFormListErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* SessionNotFoundError
|
||||
*/
|
||||
404: SessionNotFoundError
|
||||
404: SessionNotFoundErrorV2
|
||||
}
|
||||
|
||||
export type V2SessionFormListError = V2SessionFormListErrors[keyof V2SessionFormListErrors]
|
||||
@@ -16840,14 +17664,14 @@ export type V2SessionFormListResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
data: Array<FormFormInfoV2 | FormUrlInfoV2>
|
||||
data: Array<FormFormInfo2 | FormUrlInfo2>
|
||||
}
|
||||
}
|
||||
|
||||
export type V2SessionFormListResponse = V2SessionFormListResponses[keyof V2SessionFormListResponses]
|
||||
|
||||
export type V2SessionFormCreateData = {
|
||||
body: FormCreatePayloadV2
|
||||
body: FormCreatePayload2
|
||||
path: {
|
||||
sessionID: string
|
||||
}
|
||||
@@ -16863,11 +17687,11 @@ export type V2SessionFormCreateErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* SessionNotFoundError
|
||||
*/
|
||||
404: SessionNotFoundError
|
||||
404: SessionNotFoundErrorV2
|
||||
/**
|
||||
* ConflictError
|
||||
*/
|
||||
@@ -16881,7 +17705,7 @@ export type V2SessionFormCreateResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
data: FormFormInfoV2 | FormUrlInfoV2
|
||||
data: FormFormInfo2 | FormUrlInfo2
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16905,11 +17729,11 @@ export type V2SessionFormGetErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* SessionNotFoundError | FormNotFoundError
|
||||
*/
|
||||
404: FormNotFoundError | SessionNotFoundError
|
||||
404: FormNotFoundErrorV2 | SessionNotFoundErrorV2
|
||||
}
|
||||
|
||||
export type V2SessionFormGetError = V2SessionFormGetErrors[keyof V2SessionFormGetErrors]
|
||||
@@ -16919,7 +17743,7 @@ export type V2SessionFormGetResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
data: FormFormInfoV2 | FormUrlInfoV2
|
||||
data: FormFormInfo2 | FormUrlInfo2
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16943,11 +17767,11 @@ export type V2SessionFormStateErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* SessionNotFoundError | FormNotFoundError
|
||||
*/
|
||||
404: FormNotFoundError | SessionNotFoundError
|
||||
404: FormNotFoundErrorV2 | SessionNotFoundErrorV2
|
||||
}
|
||||
|
||||
export type V2SessionFormStateError = V2SessionFormStateErrors[keyof V2SessionFormStateErrors]
|
||||
@@ -16957,14 +17781,14 @@ export type V2SessionFormStateResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
data: FormState
|
||||
data: FormState2
|
||||
}
|
||||
}
|
||||
|
||||
export type V2SessionFormStateResponse = V2SessionFormStateResponses[keyof V2SessionFormStateResponses]
|
||||
|
||||
export type V2SessionFormReplyData = {
|
||||
body: FormReply
|
||||
body: FormReply2
|
||||
path: {
|
||||
sessionID: string
|
||||
formID: string
|
||||
@@ -16977,19 +17801,19 @@ export type V2SessionFormReplyErrors = {
|
||||
/**
|
||||
* FormInvalidAnswerError | InvalidRequestError
|
||||
*/
|
||||
400: FormInvalidAnswerError | InvalidRequestErrorV2
|
||||
400: FormInvalidAnswerErrorV2 | InvalidRequestErrorV2
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* SessionNotFoundError | FormNotFoundError
|
||||
*/
|
||||
404: FormNotFoundError | SessionNotFoundError
|
||||
404: FormNotFoundErrorV2 | SessionNotFoundErrorV2
|
||||
/**
|
||||
* FormAlreadySettledError
|
||||
*/
|
||||
409: FormAlreadySettledError
|
||||
409: FormAlreadySettledErrorV2
|
||||
}
|
||||
|
||||
export type V2SessionFormReplyError = V2SessionFormReplyErrors[keyof V2SessionFormReplyErrors]
|
||||
@@ -17021,15 +17845,15 @@ export type V2SessionFormCancelErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* SessionNotFoundError | FormNotFoundError
|
||||
*/
|
||||
404: FormNotFoundError | SessionNotFoundError
|
||||
404: FormNotFoundErrorV2 | SessionNotFoundErrorV2
|
||||
/**
|
||||
* FormAlreadySettledError
|
||||
*/
|
||||
409: FormAlreadySettledError
|
||||
409: FormAlreadySettledErrorV2
|
||||
}
|
||||
|
||||
export type V2SessionFormCancelError = V2SessionFormCancelErrors[keyof V2SessionFormCancelErrors]
|
||||
@@ -17063,7 +17887,7 @@ export type V2PermissionRequestListErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2PermissionRequestListError = V2PermissionRequestListErrors[keyof V2PermissionRequestListErrors]
|
||||
@@ -17073,8 +17897,8 @@ export type V2PermissionRequestListResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
location: LocationInfoV2
|
||||
data: Array<PermissionV2RequestV2>
|
||||
location: LocationInfo2
|
||||
data: Array<PermissionV2Request2>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17097,7 +17921,7 @@ export type V2PermissionSavedListErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2PermissionSavedListError = V2PermissionSavedListErrors[keyof V2PermissionSavedListErrors]
|
||||
@@ -17107,7 +17931,7 @@ export type V2PermissionSavedListResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
data: Array<PermissionSavedInfo>
|
||||
data: Array<PermissionSavedInfo2>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17130,7 +17954,7 @@ export type V2PermissionSavedRemoveErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2PermissionSavedRemoveError = V2PermissionSavedRemoveErrors[keyof V2PermissionSavedRemoveErrors]
|
||||
@@ -17161,11 +17985,11 @@ export type V2SessionPermissionListErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* SessionNotFoundError
|
||||
*/
|
||||
404: SessionNotFoundError
|
||||
404: SessionNotFoundErrorV2
|
||||
}
|
||||
|
||||
export type V2SessionPermissionListError = V2SessionPermissionListErrors[keyof V2SessionPermissionListErrors]
|
||||
@@ -17175,7 +17999,7 @@ export type V2SessionPermissionListResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
data: Array<PermissionV2RequestV2>
|
||||
data: Array<PermissionV2Request2>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17190,7 +18014,7 @@ export type V2SessionPermissionCreateData = {
|
||||
metadata?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
source?: PermissionV2SourceV2
|
||||
source?: PermissionV2Source2
|
||||
agent?: string | null
|
||||
}
|
||||
path: {
|
||||
@@ -17208,11 +18032,11 @@ export type V2SessionPermissionCreateErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* SessionNotFoundError
|
||||
*/
|
||||
404: SessionNotFoundError
|
||||
404: SessionNotFoundErrorV2
|
||||
}
|
||||
|
||||
export type V2SessionPermissionCreateError = V2SessionPermissionCreateErrors[keyof V2SessionPermissionCreateErrors]
|
||||
@@ -17224,7 +18048,7 @@ export type V2SessionPermissionCreateResponses = {
|
||||
200: {
|
||||
data: {
|
||||
id: string
|
||||
effect: PermissionV2Effect
|
||||
effect: PermissionV2Effect2
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17250,11 +18074,11 @@ export type V2SessionPermissionGetErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* SessionNotFoundError | PermissionNotFoundError
|
||||
*/
|
||||
404: PermissionNotFoundError | SessionNotFoundError
|
||||
404: PermissionNotFoundErrorV2 | SessionNotFoundErrorV2
|
||||
}
|
||||
|
||||
export type V2SessionPermissionGetError = V2SessionPermissionGetErrors[keyof V2SessionPermissionGetErrors]
|
||||
@@ -17264,7 +18088,7 @@ export type V2SessionPermissionGetResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
data: PermissionV2RequestV2
|
||||
data: PermissionV2Request2
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17272,7 +18096,7 @@ export type V2SessionPermissionGetResponse = V2SessionPermissionGetResponses[key
|
||||
|
||||
export type V2SessionPermissionReplyData = {
|
||||
body: {
|
||||
reply: PermissionV2Reply
|
||||
reply: PermissionV2Reply2
|
||||
message?: string | null
|
||||
}
|
||||
path: {
|
||||
@@ -17291,11 +18115,11 @@ export type V2SessionPermissionReplyErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* SessionNotFoundError | PermissionNotFoundError
|
||||
*/
|
||||
404: PermissionNotFoundError | SessionNotFoundError
|
||||
404: PermissionNotFoundErrorV2 | SessionNotFoundErrorV2
|
||||
}
|
||||
|
||||
export type V2SessionPermissionReplyError = V2SessionPermissionReplyErrors[keyof V2SessionPermissionReplyErrors]
|
||||
@@ -17330,7 +18154,7 @@ export type V2FsReadErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2FsReadError = V2FsReadErrors[keyof V2FsReadErrors]
|
||||
@@ -17365,7 +18189,7 @@ export type V2FsListErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2FsListError = V2FsListErrors[keyof V2FsListErrors]
|
||||
@@ -17375,8 +18199,8 @@ export type V2FsListResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
location: LocationInfoV2
|
||||
data: Array<FileSystemEntry>
|
||||
location: LocationInfo2
|
||||
data: Array<FileSystemEntry2>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17405,7 +18229,7 @@ export type V2FsFindErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2FsFindError = V2FsFindErrors[keyof V2FsFindErrors]
|
||||
@@ -17415,8 +18239,8 @@ export type V2FsFindResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
location: LocationInfoV2
|
||||
data: Array<FileSystemEntry>
|
||||
location: LocationInfo2
|
||||
data: Array<FileSystemEntry2>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17442,7 +18266,7 @@ export type V2CommandListErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2CommandListError = V2CommandListErrors[keyof V2CommandListErrors]
|
||||
@@ -17452,8 +18276,8 @@ export type V2CommandListResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
location: LocationInfoV2
|
||||
data: Array<CommandV2Info>
|
||||
location: LocationInfo2
|
||||
data: Array<CommandV2Info2>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17479,7 +18303,7 @@ export type V2SkillListErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2SkillListError = V2SkillListErrors[keyof V2SkillListErrors]
|
||||
@@ -17489,8 +18313,8 @@ export type V2SkillListResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
location: LocationInfoV2
|
||||
data: Array<SkillV2Info>
|
||||
location: LocationInfo2
|
||||
data: Array<SkillV2Info2>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17511,7 +18335,7 @@ export type V2EventSubscribeErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2EventSubscribeError = V2EventSubscribeErrors[keyof V2EventSubscribeErrors]
|
||||
@@ -17540,7 +18364,7 @@ export type V2EventChangesErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2EventChangesError = V2EventChangesErrors[keyof V2EventChangesErrors]
|
||||
@@ -17552,7 +18376,7 @@ export type V2EventChangesResponses = {
|
||||
200: {
|
||||
id: string | null
|
||||
event: string
|
||||
data: EventLogChangeStream
|
||||
data: EventLogChangeStream2
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17578,7 +18402,7 @@ export type V2PtyListErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2PtyListError = V2PtyListErrors[keyof V2PtyListErrors]
|
||||
@@ -17588,7 +18412,7 @@ export type V2PtyListResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
location: LocationInfoV2
|
||||
location: LocationInfo2
|
||||
data: Array<PtyV2>
|
||||
}
|
||||
}
|
||||
@@ -17623,7 +18447,7 @@ export type V2PtyCreateErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2PtyCreateError = V2PtyCreateErrors[keyof V2PtyCreateErrors]
|
||||
@@ -17633,7 +18457,7 @@ export type V2PtyCreateResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
location: LocationInfoV2
|
||||
location: LocationInfo2
|
||||
data: PtyV2
|
||||
}
|
||||
}
|
||||
@@ -17662,11 +18486,11 @@ export type V2PtyRemoveErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* PtyNotFoundError
|
||||
*/
|
||||
404: PtyNotFoundError
|
||||
404: PtyNotFoundErrorV2
|
||||
}
|
||||
|
||||
export type V2PtyRemoveError = V2PtyRemoveErrors[keyof V2PtyRemoveErrors]
|
||||
@@ -17702,11 +18526,11 @@ export type V2PtyGetErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* PtyNotFoundError
|
||||
*/
|
||||
404: PtyNotFoundError
|
||||
404: PtyNotFoundErrorV2
|
||||
}
|
||||
|
||||
export type V2PtyGetError = V2PtyGetErrors[keyof V2PtyGetErrors]
|
||||
@@ -17716,7 +18540,7 @@ export type V2PtyGetResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
location: LocationInfoV2
|
||||
location: LocationInfo2
|
||||
data: PtyV2
|
||||
}
|
||||
}
|
||||
@@ -17751,11 +18575,11 @@ export type V2PtyUpdateErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* PtyNotFoundError
|
||||
*/
|
||||
404: PtyNotFoundError
|
||||
404: PtyNotFoundErrorV2
|
||||
}
|
||||
|
||||
export type V2PtyUpdateError = V2PtyUpdateErrors[keyof V2PtyUpdateErrors]
|
||||
@@ -17765,7 +18589,7 @@ export type V2PtyUpdateResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
location: LocationInfoV2
|
||||
location: LocationInfo2
|
||||
data: PtyV2
|
||||
}
|
||||
}
|
||||
@@ -17794,15 +18618,15 @@ export type V2PtyConnectTokenErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* ForbiddenError
|
||||
*/
|
||||
403: ForbiddenError
|
||||
403: ForbiddenErrorV2
|
||||
/**
|
||||
* PtyNotFoundError
|
||||
*/
|
||||
404: PtyNotFoundError
|
||||
404: PtyNotFoundErrorV2
|
||||
}
|
||||
|
||||
export type V2PtyConnectTokenError = V2PtyConnectTokenErrors[keyof V2PtyConnectTokenErrors]
|
||||
@@ -17812,8 +18636,8 @@ export type V2PtyConnectTokenResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
location: LocationInfoV2
|
||||
data: PtyTicketConnectTokenV2
|
||||
location: LocationInfo2
|
||||
data: PtyTicketConnectToken2
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17841,15 +18665,15 @@ export type V2PtyConnectErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* ForbiddenError
|
||||
*/
|
||||
403: ForbiddenError
|
||||
403: ForbiddenErrorV2
|
||||
/**
|
||||
* PtyNotFoundError
|
||||
*/
|
||||
404: PtyNotFoundError
|
||||
404: PtyNotFoundErrorV2
|
||||
}
|
||||
|
||||
export type V2PtyConnectError = V2PtyConnectErrors[keyof V2PtyConnectErrors]
|
||||
@@ -17883,7 +18707,7 @@ export type V2ShellListErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2ShellListError = V2ShellListErrors[keyof V2ShellListErrors]
|
||||
@@ -17893,7 +18717,7 @@ export type V2ShellListResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
location: LocationInfoV2
|
||||
location: LocationInfo2
|
||||
data: Array<ShellV2>
|
||||
}
|
||||
}
|
||||
@@ -17927,7 +18751,7 @@ export type V2ShellCreateErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2ShellCreateError = V2ShellCreateErrors[keyof V2ShellCreateErrors]
|
||||
@@ -17937,7 +18761,7 @@ export type V2ShellCreateResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
location: LocationInfoV2
|
||||
location: LocationInfo2
|
||||
data: ShellV2
|
||||
}
|
||||
}
|
||||
@@ -17966,11 +18790,11 @@ export type V2ShellRemoveErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* ShellNotFoundError
|
||||
*/
|
||||
404: ShellNotFoundError
|
||||
404: ShellNotFoundErrorV2
|
||||
}
|
||||
|
||||
export type V2ShellRemoveError = V2ShellRemoveErrors[keyof V2ShellRemoveErrors]
|
||||
@@ -18006,11 +18830,11 @@ export type V2ShellGetErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* ShellNotFoundError
|
||||
*/
|
||||
404: ShellNotFoundError
|
||||
404: ShellNotFoundErrorV2
|
||||
}
|
||||
|
||||
export type V2ShellGetError = V2ShellGetErrors[keyof V2ShellGetErrors]
|
||||
@@ -18020,7 +18844,7 @@ export type V2ShellGetResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
location: LocationInfoV2
|
||||
location: LocationInfo2
|
||||
data: ShellV2
|
||||
}
|
||||
}
|
||||
@@ -18051,11 +18875,11 @@ export type V2ShellOutputErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* ShellNotFoundError
|
||||
*/
|
||||
404: ShellNotFoundError
|
||||
404: ShellNotFoundErrorV2
|
||||
}
|
||||
|
||||
export type V2ShellOutputError = V2ShellOutputErrors[keyof V2ShellOutputErrors]
|
||||
@@ -18065,7 +18889,7 @@ export type V2ShellOutputResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
location: LocationInfoV2
|
||||
location: LocationInfo2
|
||||
data: {
|
||||
output: string
|
||||
cursor: number
|
||||
@@ -18097,7 +18921,7 @@ export type V2QuestionRequestListErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2QuestionRequestListError = V2QuestionRequestListErrors[keyof V2QuestionRequestListErrors]
|
||||
@@ -18107,8 +18931,8 @@ export type V2QuestionRequestListResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
location: LocationInfoV2
|
||||
data: Array<QuestionV2RequestV2>
|
||||
location: LocationInfo2
|
||||
data: Array<QuestionV2Request2>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18131,11 +18955,11 @@ export type V2SessionQuestionListErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* SessionNotFoundError
|
||||
*/
|
||||
404: SessionNotFoundError
|
||||
404: SessionNotFoundErrorV2
|
||||
}
|
||||
|
||||
export type V2SessionQuestionListError = V2SessionQuestionListErrors[keyof V2SessionQuestionListErrors]
|
||||
@@ -18145,14 +18969,14 @@ export type V2SessionQuestionListResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
data: Array<QuestionV2RequestV2>
|
||||
data: Array<QuestionV2Request2>
|
||||
}
|
||||
}
|
||||
|
||||
export type V2SessionQuestionListResponse = V2SessionQuestionListResponses[keyof V2SessionQuestionListResponses]
|
||||
|
||||
export type V2SessionQuestionReplyData = {
|
||||
body: QuestionV2Reply
|
||||
body: QuestionV2Reply2
|
||||
path: {
|
||||
sessionID: string
|
||||
requestID: string
|
||||
@@ -18169,11 +18993,11 @@ export type V2SessionQuestionReplyErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* SessionNotFoundError | QuestionNotFoundError
|
||||
*/
|
||||
404: QuestionNotFoundError | SessionNotFoundError
|
||||
404: QuestionNotFoundErrorV2 | SessionNotFoundErrorV2
|
||||
}
|
||||
|
||||
export type V2SessionQuestionReplyError = V2SessionQuestionReplyErrors[keyof V2SessionQuestionReplyErrors]
|
||||
@@ -18205,11 +19029,11 @@ export type V2SessionQuestionRejectErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
/**
|
||||
* SessionNotFoundError | QuestionNotFoundError
|
||||
*/
|
||||
404: QuestionNotFoundError | SessionNotFoundError
|
||||
404: QuestionNotFoundErrorV2 | SessionNotFoundErrorV2
|
||||
}
|
||||
|
||||
export type V2SessionQuestionRejectError = V2SessionQuestionRejectErrors[keyof V2SessionQuestionRejectErrors]
|
||||
@@ -18243,7 +19067,7 @@ export type V2ReferenceListErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2ReferenceListError = V2ReferenceListErrors[keyof V2ReferenceListErrors]
|
||||
@@ -18253,8 +19077,8 @@ export type V2ReferenceListResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
location: LocationInfoV2
|
||||
data: Array<ReferenceInfo>
|
||||
location: LocationInfo2
|
||||
data: Array<ReferenceInfo2>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18285,7 +19109,7 @@ export type V2ProjectCopyRemoveErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2ProjectCopyRemoveError = V2ProjectCopyRemoveErrors[keyof V2ProjectCopyRemoveErrors]
|
||||
@@ -18325,7 +19149,7 @@ export type V2ProjectCopyCreateErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2ProjectCopyCreateError = V2ProjectCopyCreateErrors[keyof V2ProjectCopyCreateErrors]
|
||||
@@ -18334,7 +19158,7 @@ export type V2ProjectCopyCreateResponses = {
|
||||
/**
|
||||
* ProjectCopy.Copy
|
||||
*/
|
||||
200: ProjectCopyCopy
|
||||
200: ProjectCopyCopy2
|
||||
}
|
||||
|
||||
export type V2ProjectCopyCreateResponse = V2ProjectCopyCreateResponses[keyof V2ProjectCopyCreateResponses]
|
||||
@@ -18361,7 +19185,7 @@ export type V2ProjectCopyRefreshErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2ProjectCopyRefreshError = V2ProjectCopyRefreshErrors[keyof V2ProjectCopyRefreshErrors]
|
||||
@@ -18395,7 +19219,7 @@ export type V2VcsStatusErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2VcsStatusError = V2VcsStatusErrors[keyof V2VcsStatusErrors]
|
||||
@@ -18405,7 +19229,7 @@ export type V2VcsStatusResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
location: LocationInfoV2
|
||||
location: LocationInfo2
|
||||
data: Array<VcsFileStatusV2>
|
||||
}
|
||||
}
|
||||
@@ -18420,7 +19244,7 @@ export type V2VcsDiffData = {
|
||||
directory?: string | null
|
||||
workspace?: string | null
|
||||
} | null
|
||||
mode: VcsMode
|
||||
mode: VcsMode2
|
||||
context?: string | null
|
||||
}
|
||||
url: "/api/vcs/diff"
|
||||
@@ -18434,7 +19258,7 @@ export type V2VcsDiffErrors = {
|
||||
/**
|
||||
* UnauthorizedError
|
||||
*/
|
||||
401: UnauthorizedError
|
||||
401: UnauthorizedErrorV2
|
||||
}
|
||||
|
||||
export type V2VcsDiffError = V2VcsDiffErrors[keyof V2VcsDiffErrors]
|
||||
@@ -18444,8 +19268,8 @@ export type V2VcsDiffResponses = {
|
||||
* Success
|
||||
*/
|
||||
200: {
|
||||
location: LocationInfoV2
|
||||
data: Array<SnapshotFileDiff>
|
||||
location: LocationInfo2
|
||||
data: Array<SnapshotFileDiffV2>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -344,26 +344,44 @@ export const SessionHandler = HttpApiBuilder.group(Api, "server.session", (handl
|
||||
.handle(
|
||||
"session.compact",
|
||||
Effect.fn(function* (ctx) {
|
||||
return {
|
||||
data: yield* session.compact({ sessionID: ctx.params.sessionID, id: ctx.payload.id }).pipe(
|
||||
Effect.catchTag("Session.NotFoundError", (error) =>
|
||||
Effect.fail(
|
||||
new SessionNotFoundError({
|
||||
sessionID: error.sessionID,
|
||||
message: `Session not found: ${error.sessionID}`,
|
||||
}),
|
||||
),
|
||||
),
|
||||
Effect.catchTag("Session.CompactionConflictError", (error) =>
|
||||
Effect.fail(
|
||||
new ConflictError({
|
||||
message: `Compaction input ID conflicts with an existing durable record: ${error.inputID}`,
|
||||
resource: error.inputID,
|
||||
}),
|
||||
),
|
||||
yield* session.compact({ sessionID: ctx.params.sessionID }).pipe(
|
||||
Effect.catchTag("Session.NotFoundError", (error) =>
|
||||
Effect.fail(
|
||||
new SessionNotFoundError({
|
||||
sessionID: error.sessionID,
|
||||
message: `Session not found: ${error.sessionID}`,
|
||||
}),
|
||||
),
|
||||
),
|
||||
}
|
||||
Effect.catchTag("Session.OperationUnavailableError", (error) =>
|
||||
Effect.fail(
|
||||
new ServiceUnavailableError({
|
||||
message: `Session ${error.operation} is not available yet`,
|
||||
service: `session.${error.operation}`,
|
||||
}),
|
||||
),
|
||||
),
|
||||
Effect.catchTag(
|
||||
"Session.BusyError",
|
||||
(error) =>
|
||||
new SessionBusyError({
|
||||
sessionID: error.sessionID,
|
||||
message: `Session is busy: ${error.sessionID}`,
|
||||
}),
|
||||
),
|
||||
Effect.catchTag("Session.MessageDecodeError", (error) => {
|
||||
const ref = `err_${crypto.randomUUID().slice(0, 8)}`
|
||||
return Effect.logError("failed to decode session message during compaction").pipe(
|
||||
Effect.annotateLogs({ ref, sessionID: error.sessionID, messageID: error.messageID }),
|
||||
Effect.andThen(
|
||||
Effect.fail(
|
||||
new UnknownError({ message: "Unexpected server error. Check server logs for details.", ref }),
|
||||
),
|
||||
),
|
||||
)
|
||||
}),
|
||||
)
|
||||
return HttpApiSchema.NoContent.make()
|
||||
}),
|
||||
)
|
||||
.handle(
|
||||
|
||||
@@ -20,7 +20,7 @@ import type {
|
||||
SkillV2Info,
|
||||
V2Event,
|
||||
} from "@opencode-ai/sdk/v2"
|
||||
import { createStore, produce, reconcile } from "solid-js/store"
|
||||
import { createStore, produce } from "solid-js/store"
|
||||
import { createSimpleContext } from "./helper"
|
||||
import { useSDK } from "./sdk"
|
||||
import { createSignal, onCleanup } from "solid-js"
|
||||
@@ -52,7 +52,6 @@ type Data = {
|
||||
family: Record<string, string[]>
|
||||
status: Record<string, DataSessionStatus>
|
||||
compaction: Partial<Record<string, string>>
|
||||
compactionReason: Partial<Record<string, "auto" | "manual">>
|
||||
message: Record<string, SessionMessage[]>
|
||||
permission: Record<string, PermissionV2Request[]>
|
||||
question: Record<string, QuestionV2Request[]>
|
||||
@@ -71,6 +70,20 @@ function locationQuery(ref?: LocationRef) {
|
||||
return ref ? { directory: ref.directory, workspace: ref.workspaceID } : undefined
|
||||
}
|
||||
|
||||
export function mergeActiveSessionStatus(
|
||||
active: Readonly<Record<string, unknown>>,
|
||||
current: Readonly<Record<string, DataSessionStatus>>,
|
||||
changed: ReadonlyMap<string, number>,
|
||||
revision: number,
|
||||
) {
|
||||
const status: Record<string, DataSessionStatus> = Object.fromEntries(
|
||||
Object.keys(active).map((sessionID) => [sessionID, "running" as const]),
|
||||
)
|
||||
for (const [sessionID, value] of Object.entries(current))
|
||||
if ((changed.get(sessionID) ?? 0) > revision) status[sessionID] = value
|
||||
return status
|
||||
}
|
||||
|
||||
type Mutable<T> =
|
||||
T extends ReadonlyArray<infer U> ? Mutable<U>[] : T extends object ? { -readonly [K in keyof T]: Mutable<T[K]> } : T
|
||||
|
||||
@@ -88,7 +101,6 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
||||
family: {},
|
||||
status: {},
|
||||
compaction: {},
|
||||
compactionReason: {},
|
||||
message: {},
|
||||
permission: {},
|
||||
question: {},
|
||||
@@ -104,15 +116,10 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
||||
directory: process.cwd(),
|
||||
})
|
||||
const messageIndex = new Map<string, Map<string, number>>()
|
||||
let connectionGeneration = 0
|
||||
let statusChanges: Set<string> | undefined
|
||||
const statusChanged = new Map<string, number>()
|
||||
let statusRevision = 0
|
||||
let bootstrapping: Promise<void> | undefined
|
||||
|
||||
function setSessionStatus(sessionID: string, status: DataSessionStatus) {
|
||||
statusChanges?.add(sessionID)
|
||||
setStore("session", "status", sessionID, status)
|
||||
}
|
||||
|
||||
const message = {
|
||||
update(sessionID: string, fn: (messages: SessionMessage[], index: Map<string, number>) => void) {
|
||||
setStore(
|
||||
@@ -141,12 +148,6 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
||||
const item = messages.findLast((item) => item.type === "shell" && item.shell.id === shellID)
|
||||
return item?.type === "shell" ? item : undefined
|
||||
},
|
||||
compaction(messages: SessionMessage[]) {
|
||||
const item = messages.findLast(
|
||||
(item) => item.type === "compaction" && (item.status === "queued" || item.status === "running"),
|
||||
)
|
||||
return item?.type === "compaction" ? item : undefined
|
||||
},
|
||||
latestTool(assistant: SessionMessageAssistant | undefined, callID?: string) {
|
||||
return assistant?.content.findLast(
|
||||
(item): item is SessionMessageAssistantTool =>
|
||||
@@ -250,7 +251,6 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
||||
case "session.model.selected":
|
||||
if (store.session.info[event.data.sessionID])
|
||||
setStore("session", "info", event.data.sessionID, "model", event.data.model)
|
||||
if (!store.session.message[event.data.sessionID]) break
|
||||
message.update(event.data.sessionID, (draft, index) => {
|
||||
message.append(draft, index, {
|
||||
id: messageIDFromEvent(event.id),
|
||||
@@ -259,16 +259,6 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
||||
time: { created: event.created },
|
||||
})
|
||||
})
|
||||
void sdk.api.session
|
||||
.message({ sessionID: event.data.sessionID, messageID: messageIDFromEvent(event.id) })
|
||||
.then((item) => {
|
||||
message.update(event.data.sessionID, (draft, index) => {
|
||||
const position = index.get(item.id)
|
||||
if (position === undefined) return message.append(draft, index, mutable(item))
|
||||
draft[position] = mutable(item)
|
||||
})
|
||||
})
|
||||
.catch((error) => console.error("Failed to load projected model switch message", error))
|
||||
break
|
||||
case "session.renamed":
|
||||
if (store.session.info[event.data.sessionID])
|
||||
@@ -277,16 +267,13 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
||||
case "session.prompt.promoted": {
|
||||
message.update(event.data.sessionID, (draft, index) => {
|
||||
const position = index.get(event.data.inputID)
|
||||
if (position === undefined) return
|
||||
const existing = draft[position]
|
||||
if (existing?.type === "user" && existing.metadata?.queued === true) {
|
||||
const existing = position === undefined ? undefined : draft[position]
|
||||
if (existing?.type === "user") {
|
||||
existing.time.created = event.created
|
||||
delete existing.metadata.queued
|
||||
if (Object.keys(existing.metadata).length === 0) existing.metadata = undefined
|
||||
draft.splice(position, 1)
|
||||
draft.push(existing)
|
||||
index.clear()
|
||||
draft.forEach((message, indexValue) => index.set(message.id, indexValue))
|
||||
if (existing.metadata?.queued === true) {
|
||||
delete existing.metadata.queued
|
||||
if (Object.keys(existing.metadata).length === 0) existing.metadata = undefined
|
||||
}
|
||||
return
|
||||
}
|
||||
})
|
||||
@@ -548,39 +535,19 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
||||
})
|
||||
break
|
||||
case "session.execution.started":
|
||||
setSessionStatus(event.data.sessionID, "running")
|
||||
break
|
||||
case "session.compaction.admitted":
|
||||
message.update(event.data.sessionID, (draft, index) => {
|
||||
if (message.compaction(draft)) return
|
||||
message.append(draft, index, {
|
||||
id: event.data.inputID,
|
||||
type: "compaction",
|
||||
status: "queued",
|
||||
reason: "manual",
|
||||
summary: "",
|
||||
recent: "",
|
||||
time: { created: event.created },
|
||||
})
|
||||
})
|
||||
statusChanged.set(event.data.sessionID, ++statusRevision)
|
||||
setStore("session", "status", event.data.sessionID, "running")
|
||||
break
|
||||
case "session.compaction.started":
|
||||
setStore("session", "compaction", event.data.sessionID, "")
|
||||
setStore("session", "compactionReason", event.data.sessionID, event.data.reason)
|
||||
if (event.data.reason === "manual")
|
||||
message.update(event.data.sessionID, (draft) => {
|
||||
const current = message.compaction(draft)
|
||||
if (current) current.status = "running"
|
||||
})
|
||||
break
|
||||
case "session.execution.succeeded":
|
||||
case "session.execution.failed":
|
||||
case "session.execution.interrupted":
|
||||
setSessionStatus(event.data.sessionID, "idle")
|
||||
statusChanged.set(event.data.sessionID, ++statusRevision)
|
||||
setStore("session", "status", event.data.sessionID, "idle")
|
||||
if (store.session.compaction[event.data.sessionID] !== undefined)
|
||||
setStore("session", "compaction", event.data.sessionID, undefined)
|
||||
if (store.session.compactionReason[event.data.sessionID] !== undefined)
|
||||
setStore("session", "compactionReason", event.data.sessionID, undefined)
|
||||
message.update(event.data.sessionID, (draft) => {
|
||||
const currentAssistant = message.activeAssistant(draft)
|
||||
if (currentAssistant) currentAssistant.retry = undefined
|
||||
@@ -597,28 +564,13 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
||||
break
|
||||
case "session.compaction.delta":
|
||||
setStore("session", "compaction", event.data.sessionID, (text) => (text ?? "") + event.data.text)
|
||||
if (store.session.compactionReason[event.data.sessionID] === "manual")
|
||||
message.update(event.data.sessionID, (draft) => {
|
||||
const current = message.compaction(draft)
|
||||
if (current) current.summary += event.data.text
|
||||
})
|
||||
break
|
||||
case "session.compaction.ended":
|
||||
setStore("session", "compaction", event.data.sessionID, undefined)
|
||||
setStore("session", "compactionReason", event.data.sessionID, undefined)
|
||||
message.update(event.data.sessionID, (draft, index) => {
|
||||
const current = event.data.reason === "manual" ? message.compaction(draft) : undefined
|
||||
if (current) {
|
||||
current.status = "completed"
|
||||
current.reason = event.data.reason
|
||||
current.summary = event.data.text
|
||||
current.recent = event.data.recent
|
||||
return
|
||||
}
|
||||
message.append(draft, index, {
|
||||
id: messageIDFromEvent(event.id),
|
||||
type: "compaction",
|
||||
status: "completed",
|
||||
reason: event.data.reason,
|
||||
summary: event.data.text,
|
||||
recent: event.data.recent,
|
||||
@@ -626,14 +578,6 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
||||
})
|
||||
})
|
||||
break
|
||||
case "session.compaction.failed":
|
||||
setStore("session", "compaction", event.data.sessionID, undefined)
|
||||
setStore("session", "compactionReason", event.data.sessionID, undefined)
|
||||
message.update(event.data.sessionID, (draft) => {
|
||||
const current = message.compaction(draft)
|
||||
if (current) current.status = "failed"
|
||||
})
|
||||
break
|
||||
case "permission.v2.asked":
|
||||
if (store.session.permission[event.data.sessionID]?.some((request) => request.id === event.data.id)) break
|
||||
setStore("session", "permission", event.data.sessionID, [
|
||||
@@ -931,6 +875,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
||||
|
||||
async function bootstrap() {
|
||||
if (bootstrapping) return bootstrapping
|
||||
const activeRevision = statusRevision
|
||||
bootstrapping = Promise.allSettled([
|
||||
sdk.api.session
|
||||
.list({
|
||||
@@ -949,6 +894,13 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
||||
)
|
||||
for (const session of response.data) registerSession(session.id)
|
||||
}),
|
||||
sdk.api.session.active().then((active) => {
|
||||
setStore(
|
||||
"session",
|
||||
"status",
|
||||
mergeActiveSessionStatus(active.data, store.session.status, statusChanged, activeRevision),
|
||||
)
|
||||
}),
|
||||
result.location.refresh(),
|
||||
result.location.agent.refresh(),
|
||||
result.location.integration.refresh(),
|
||||
@@ -970,30 +922,9 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
||||
return bootstrapping
|
||||
}
|
||||
|
||||
function refreshActive() {
|
||||
const generation = ++connectionGeneration
|
||||
const changed = new Set<string>()
|
||||
statusChanges = changed
|
||||
void sdk.api.session
|
||||
.active()
|
||||
.then((active) => {
|
||||
if (generation !== connectionGeneration) return
|
||||
const status: Record<string, DataSessionStatus> = Object.fromEntries(
|
||||
Object.keys(active.data).map((sessionID) => [sessionID, "running" as const]),
|
||||
)
|
||||
for (const sessionID of changed) status[sessionID] = store.session.status[sessionID]
|
||||
setStore("session", "status", reconcile(status))
|
||||
})
|
||||
.catch(() => undefined)
|
||||
.finally(() => {
|
||||
if (statusChanges === changed) statusChanges = undefined
|
||||
})
|
||||
}
|
||||
|
||||
onCleanup(
|
||||
sdk.event.listen(({ details }) => {
|
||||
if (details.type === "server.connected") {
|
||||
refreshActive()
|
||||
void bootstrap()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ import { useProject } from "../../context/project"
|
||||
import { useData } from "../../context/data"
|
||||
import { SplitBorder } from "../../ui/border"
|
||||
import { useTuiPaths, useTuiTerminalEnvironment } from "../../context/runtime"
|
||||
import { Spinner, SPINNER_FRAMES } from "../../component/spinner"
|
||||
import { Spinner } from "../../component/spinner"
|
||||
import { createSyntaxStyleMemo, generateSubtleSyntax, selectedForeground, useTheme } from "../../context/theme"
|
||||
import { BoxRenderable, ScrollBoxRenderable, addDefaultParsers, TextAttributes, RGBA } from "@opentui/core"
|
||||
import { Prompt, type PromptRef } from "../../component/prompt"
|
||||
@@ -171,16 +171,6 @@ export function Session() {
|
||||
})
|
||||
onCleanup(() => setEpilogue())
|
||||
const messages = sessionMessages
|
||||
const transientCompaction = createMemo(() => {
|
||||
if (
|
||||
messages().some(
|
||||
(message) => message.type === "compaction" && (message.status === "queued" || message.status === "running"),
|
||||
)
|
||||
)
|
||||
return
|
||||
const text = data.session.compaction(route.sessionID)
|
||||
return text === undefined ? undefined : { text }
|
||||
})
|
||||
const descendantSessionIDs = createMemo(() => {
|
||||
if (session()?.parentID) return []
|
||||
return data.session.family(route.sessionID).filter((id) => id !== route.sessionID)
|
||||
@@ -925,8 +915,8 @@ export function Session() {
|
||||
/>
|
||||
)}
|
||||
</For>
|
||||
<Show when={transientCompaction()}>
|
||||
{(compaction) => <CompactionMessage status="running" text={compaction().text} />}
|
||||
<Show when={data.session.compaction(route.sessionID)}>
|
||||
{(text) => <CompactionMessage text={text()} />}
|
||||
</Show>
|
||||
<BackgroundToolHint messages={messages()} />
|
||||
<Show when={session()?.revert?.messageID}>
|
||||
@@ -1094,7 +1084,7 @@ function SessionMessageView(props: { message: SessionMessage }) {
|
||||
</Show>
|
||||
</Match>
|
||||
<Match when={props.message.type === "compaction"}>
|
||||
<CompactionMessage message={props.message as Extract<SessionMessage, { type: "compaction" }>} />
|
||||
<CompactionMessage />
|
||||
</Match>
|
||||
</Switch>
|
||||
)
|
||||
@@ -1224,7 +1214,15 @@ function AssistantFooter(props: { message: SessionMessageAssistant }) {
|
||||
<text fg={theme.textMuted}>{errorMessage(props.message.error)}</text>
|
||||
</box>
|
||||
</Show>
|
||||
<AssistantRetry retry={props.message.retry} />
|
||||
<Show when={props.message.retry}>
|
||||
{(retry) => (
|
||||
<box paddingLeft={3} marginTop={1}>
|
||||
<text fg={theme.textMuted}>
|
||||
Retry attempt {retry().attempt} scheduled: {retry().error.message} [{retry().error.type}]
|
||||
</text>
|
||||
</box>
|
||||
)}
|
||||
</Show>
|
||||
<box paddingLeft={3} marginTop={props.message.error ? 1 : 0}>
|
||||
<text>
|
||||
<span style={{ fg: props.message.error ? theme.textMuted : local.agent.color(props.message.agent) }}>
|
||||
@@ -1245,8 +1243,7 @@ function SessionSwitchMessageV2(props: { message: SessionMessage }) {
|
||||
const { theme } = useTheme()
|
||||
const text = () => {
|
||||
if (props.message.type === "agent-switched") return `Switched agent to ${props.message.agent}`
|
||||
if (props.message.type === "model-switched")
|
||||
return switchLabel(props.message.model, ctx.models(), props.message.previous)
|
||||
if (props.message.type === "model-switched") return switchLabel(props.message.model, ctx.models())
|
||||
return ""
|
||||
}
|
||||
return <text fg={theme.textMuted}>{text()}</text>
|
||||
@@ -1275,56 +1272,12 @@ function SessionSkillMessage(props: { message: Extract<SessionMessage, { type: "
|
||||
)
|
||||
}
|
||||
|
||||
function CompactionMessage(props: {
|
||||
message?: Extract<SessionMessage, { type: "compaction" }>
|
||||
status?: "running"
|
||||
text?: string
|
||||
}) {
|
||||
const ctx = use()
|
||||
const kv = useKV()
|
||||
const { theme, syntax } = useTheme()
|
||||
const status = () => props.message?.status ?? props.status
|
||||
const text = () => props.message?.summary ?? props.text ?? ""
|
||||
const color = () => (status() === "failed" ? theme.error : status() === "completed" ? theme.success : theme.textMuted)
|
||||
const border = () => (status() === "queued" ? theme.border : color())
|
||||
function CompactionMessage(props: { text?: string }) {
|
||||
const { theme } = useTheme()
|
||||
return (
|
||||
<box>
|
||||
<box flexDirection="row" alignItems="center">
|
||||
<box border={["top"]} borderColor={border()} flexGrow={1} />
|
||||
<box flexDirection="row" gap={1} paddingLeft={1} paddingRight={1}>
|
||||
<Switch>
|
||||
<Match when={status() === "running"}>
|
||||
<Show when={kv.get("animations_enabled", true)} fallback={<text fg={color()}>⋯</text>}>
|
||||
<spinner frames={SPINNER_FRAMES} interval={80} color={color()} />
|
||||
</Show>
|
||||
</Match>
|
||||
<Match when={status() === "completed"}>
|
||||
<text fg={color()}>✓</text>
|
||||
</Match>
|
||||
<Match when={status() === "failed"}>
|
||||
<text fg={color()}>✗</text>
|
||||
</Match>
|
||||
<Match when={status() === "queued"}>
|
||||
<text fg={color()}>◇</text>
|
||||
</Match>
|
||||
</Switch>
|
||||
<text fg={color()}>{status() === "queued" ? "Compaction queued" : "Compaction"}</text>
|
||||
</box>
|
||||
<box border={["top"]} borderColor={border()} flexGrow={1} />
|
||||
</box>
|
||||
<Show when={text().trim()}>
|
||||
<box paddingTop={1} paddingLeft={3}>
|
||||
<markdown
|
||||
syntaxStyle={syntax()}
|
||||
streaming={status() === "running"}
|
||||
internalBlockMode="top-level"
|
||||
content={text().trim()}
|
||||
tableOptions={{ style: "grid" }}
|
||||
conceal={ctx.conceal()}
|
||||
fg={theme.markdownText}
|
||||
bg={theme.background}
|
||||
/>
|
||||
</box>
|
||||
<box border={["top"]} title=" Compaction " titleAlignment="center" borderColor={theme.borderActive}>
|
||||
<Show when={props.text}>
|
||||
<text fg={theme.textMuted}>{props.text}</text>
|
||||
</Show>
|
||||
</box>
|
||||
)
|
||||
@@ -1608,7 +1561,15 @@ function AssistantMessage(props: { message: SessionMessageAssistant; last: boole
|
||||
<text fg={theme.textMuted}>{errorMessage(props.message.error)}</text>
|
||||
</box>
|
||||
</Show>
|
||||
<AssistantRetry retry={props.message.retry} />
|
||||
<Show when={props.message.retry}>
|
||||
{(retry) => (
|
||||
<box paddingLeft={3} marginTop={1}>
|
||||
<text fg={theme.textMuted}>
|
||||
Retry attempt {retry().attempt} scheduled: {retry().error.message} [{retry().error.type}]
|
||||
</text>
|
||||
</box>
|
||||
)}
|
||||
</Show>
|
||||
<Switch>
|
||||
<Match when={props.last || final() || props.message.error}>
|
||||
<box paddingLeft={3}>
|
||||
@@ -1628,21 +1589,6 @@ function AssistantMessage(props: { message: SessionMessageAssistant; last: boole
|
||||
)
|
||||
}
|
||||
|
||||
function AssistantRetry(props: { retry: SessionMessageAssistant["retry"] }) {
|
||||
const { theme } = useTheme()
|
||||
return (
|
||||
<Show when={props.retry}>
|
||||
{(retry) => (
|
||||
<box paddingLeft={3} marginTop={1}>
|
||||
<text fg={theme.textMuted}>
|
||||
Retry attempt {retry().attempt} scheduled: {retry().error.message} [{retry().error.type}]
|
||||
</text>
|
||||
</box>
|
||||
)}
|
||||
</Show>
|
||||
)
|
||||
}
|
||||
|
||||
function ExplorationSummary(props: { parts: SessionMessageAssistantTool[]; active: boolean }) {
|
||||
const { theme } = useTheme()
|
||||
const pathFormatter = usePathFormatter()
|
||||
@@ -2160,16 +2106,14 @@ function Shell(props: ToolProps) {
|
||||
return request?.source?.type === "tool" && request.source.callID === props.part.id
|
||||
})
|
||||
const color = createMemo(() => (permission() ? theme.warning : theme.text))
|
||||
const shellID = createMemo(() => stringValue(props.metadata.shellID))
|
||||
const backgroundRunning = createMemo(() => {
|
||||
const id = shellID()
|
||||
return Boolean(id && data.shell.get(id))
|
||||
const isRunning = createMemo(() => {
|
||||
if (props.part.state.status === "running") return true
|
||||
const shellID = stringValue(props.metadata.shellID)
|
||||
return Boolean(shellID && data.shell.get(shellID))
|
||||
})
|
||||
const isRunning = createMemo(() => props.part.state.status === "running" || backgroundRunning())
|
||||
const command = createMemo(() => stringValue(props.input.command))
|
||||
const output = createMemo(() => {
|
||||
if (props.part.state.status === "pending") return ""
|
||||
if (shellID()) return ""
|
||||
const content = props.part.state.content[0]
|
||||
return stripAnsi(content?.type === "text" ? content.text.trim() : "")
|
||||
})
|
||||
@@ -2212,11 +2156,6 @@ function Shell(props: ToolProps) {
|
||||
</Spinner>
|
||||
</Show>
|
||||
</Show>
|
||||
<Show when={shellID()}>
|
||||
<text>
|
||||
<span style={{ bg: theme.backgroundElement, fg: theme.textMuted }}> Backgrounded </span>
|
||||
</text>
|
||||
</Show>
|
||||
<Show when={collapsed().overflow}>
|
||||
<text fg={theme.textMuted}>{expanded() ? "Click to collapse" : "Click to expand"}</text>
|
||||
</Show>
|
||||
|
||||
@@ -28,24 +28,23 @@ export function createSessionRows(sessionID: Accessor<string>) {
|
||||
function reduce() {
|
||||
const messages = data.session.message.list(sessionID())
|
||||
const boundary = revertBoundary()
|
||||
const rows = reduceSessionRows(boundary ? messages.filter((message) => message.id < boundary) : messages)
|
||||
partitionPending(rows, pendingPermissions())
|
||||
return rows
|
||||
return reduceSessionRows(boundary ? messages.filter((message) => message.id < boundary) : messages)
|
||||
}
|
||||
|
||||
function pendingPermissions() {
|
||||
return new Set(
|
||||
createEffect(() => {
|
||||
const pending = new Set(
|
||||
(data.session.permission.list(sessionID()) ?? []).flatMap((request) =>
|
||||
request.source?.type === "tool" ? [request.source.callID] : [],
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
createEffect(() => {
|
||||
const pending = pendingPermissions()
|
||||
setRows(
|
||||
produce((draft) => {
|
||||
partitionPending(draft, pending)
|
||||
draft.forEach((row) => {
|
||||
if (row.type !== "group") return
|
||||
const refs = [...row.refs, ...row.pending]
|
||||
row.refs = refs.filter((ref) => !pending.has(ref.partID))
|
||||
row.pending = refs.filter((ref) => pending.has(ref.partID))
|
||||
})
|
||||
}),
|
||||
)
|
||||
})
|
||||
@@ -70,30 +69,13 @@ export function createSessionRows(sessionID: Accessor<string>) {
|
||||
}),
|
||||
)
|
||||
|
||||
createEffect(
|
||||
on(
|
||||
() =>
|
||||
data.session.message
|
||||
.list(sessionID())
|
||||
.flatMap((message) =>
|
||||
message.type === "user"
|
||||
? [{ id: message.id, created: message.time.created, state: message.metadata?.queued ? "queued" : "visible" }]
|
||||
: message.type === "compaction"
|
||||
? [{ id: message.id, created: message.time.created, state: message.status }]
|
||||
: [],
|
||||
),
|
||||
() => setRows(reconcile(reduce())),
|
||||
),
|
||||
)
|
||||
|
||||
const appendMessage = (messageID: string) =>
|
||||
setRows(
|
||||
produce((draft) => {
|
||||
if (draft.some((row) => row.type === "message" && row.messageID === messageID)) return
|
||||
const pending = isPending(messageID)
|
||||
const message = data.session.message.get(sessionID(), messageID)
|
||||
const index = message?.type === "compaction" && pending ? queuedStart(draft) : pending ? draft.length : queuedStart(draft)
|
||||
if (!pending) completePrevious(draft, index)
|
||||
const queued = isQueued(messageID)
|
||||
const index = queued ? draft.length : queuedStart(draft)
|
||||
if (!queued) completePrevious(draft, index)
|
||||
draft.splice(index, 0, { type: "message", messageID })
|
||||
}),
|
||||
)
|
||||
@@ -148,14 +130,13 @@ export function createSessionRows(sessionID: Accessor<string>) {
|
||||
return { messageID, partID: `${kind}:${Math.max(0, ordinal)}` }
|
||||
}
|
||||
|
||||
const isPending = (messageID: string) => {
|
||||
const isQueued = (messageID: string) => {
|
||||
const message = data.session.message.get(sessionID(), messageID)
|
||||
if (message?.type === "user") return message.metadata?.queued === true
|
||||
return message?.type === "compaction" && (message.status === "queued" || message.status === "running")
|
||||
return message?.type === "user" && message.metadata?.queued === true
|
||||
}
|
||||
|
||||
const queuedStart = (rows: SessionRow[]) => {
|
||||
const index = rows.findIndex((row) => row.type === "message" && isPending(row.messageID))
|
||||
const index = rows.findIndex((row) => row.type === "message" && isQueued(row.messageID))
|
||||
return index === -1 ? rows.length : index
|
||||
}
|
||||
|
||||
@@ -167,7 +148,7 @@ export function createSessionRows(sessionID: Accessor<string>) {
|
||||
}
|
||||
const subscriptions = [
|
||||
data.on("session.prompt.admitted", input),
|
||||
data.on("session.compaction.admitted", input),
|
||||
data.on("session.prompt.promoted", input),
|
||||
data.on("session.context.updated", message),
|
||||
data.on("session.synthetic", (event) => {
|
||||
if (event.data.sessionID === sessionID() && event.data.description?.trim())
|
||||
@@ -216,13 +197,9 @@ export function createSessionRows(sessionID: Accessor<string>) {
|
||||
}
|
||||
|
||||
export function reduceSessionRows(messages: SessionMessage[]) {
|
||||
const pendingCompactions = messages.filter(
|
||||
(message) => message.type === "compaction" && (message.status === "queued" || message.status === "running"),
|
||||
)
|
||||
const queuedUsers = messages.filter(isQueuedMessage)
|
||||
const pending = new Set([...pendingCompactions, ...queuedUsers].map((message) => message.id))
|
||||
return [...messages.filter((message) => !pending.has(message.id)), ...pendingCompactions, ...queuedUsers].reduce<SessionRow[]>(
|
||||
(rows, message) => {
|
||||
return [...messages.filter((message) => !isQueuedMessage(message)), ...messages.filter(isQueuedMessage)].reduce<
|
||||
SessionRow[]
|
||||
>((rows, message) => {
|
||||
if (message.type !== "assistant") {
|
||||
if (message.type === "synthetic" && !message.description?.trim()) return rows
|
||||
if (!isQueuedMessage(message)) completePrevious(rows)
|
||||
@@ -240,9 +217,7 @@ export function reduceSessionRows(messages: SessionMessage[]) {
|
||||
rows.push({ type: "assistant-footer", messageID: message.id })
|
||||
}
|
||||
return rows
|
||||
},
|
||||
[],
|
||||
)
|
||||
}, [])
|
||||
}
|
||||
|
||||
export function resolvePart(message: SessionMessageAssistant, partID: string) {
|
||||
@@ -280,15 +255,6 @@ function completePrevious(rows: SessionRow[], index = rows.length) {
|
||||
if (previous?.type === "group") previous.completed = true
|
||||
}
|
||||
|
||||
function partitionPending(rows: SessionRow[], pending: Set<string>) {
|
||||
rows.forEach((row) => {
|
||||
if (row.type !== "group") return
|
||||
const refs = [...row.refs, ...row.pending]
|
||||
row.refs = refs.filter((ref) => !pending.has(ref.partID))
|
||||
row.pending = refs.filter((ref) => pending.has(ref.partID))
|
||||
})
|
||||
}
|
||||
|
||||
function exploration(name: string) {
|
||||
return ["read", "glob", "grep"].includes(name.toLowerCase())
|
||||
}
|
||||
|
||||
@@ -34,12 +34,11 @@ export function formatRef(model: { providerID: string; id: string; variant?: str
|
||||
export function switchLabel(
|
||||
model: { providerID: string; id: string; variant?: string },
|
||||
models?: readonly { providerID: string; id: string; name: string }[],
|
||||
previous?: { providerID: string; id: string; variant?: string },
|
||||
) {
|
||||
if (previous?.providerID === model.providerID && previous.id === model.id)
|
||||
return `Switched variant to ${model.variant ?? "default"}`
|
||||
const display = models?.find((item) => item.providerID === model.providerID && item.id === model.id)?.name
|
||||
if (display === undefined) return `Switched model to ${formatRef(model)}`
|
||||
// Variant-only switches publish the same model id; without the variant the
|
||||
// notice would look like a redundant model switch.
|
||||
const variant = model.variant && model.variant !== "default" ? ` (${model.variant})` : ""
|
||||
return `Switched model to ${display}${variant}`
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import { EventV2 } from "@opencode-ai/core/event"
|
||||
import { onMount } from "solid-js"
|
||||
import { ProjectProvider } from "../../../src/context/project"
|
||||
import { SDKProvider } from "../../../src/context/sdk"
|
||||
import { DataProvider, useData } from "../../../src/context/data"
|
||||
import { DataProvider, mergeActiveSessionStatus, useData } from "../../../src/context/data"
|
||||
import { createSessionRows, type SessionRow } from "../../../src/routes/session/rows"
|
||||
import { createApi, createClient, createEventStream, createFetch, directory, json } from "../../fixture/tui-sdk"
|
||||
import { TestTuiContexts } from "../../fixture/tui-environment"
|
||||
@@ -28,6 +28,24 @@ function durable(sessionID: string, seq = 0, version = 1) {
|
||||
return { aggregateID: sessionID, seq, version }
|
||||
}
|
||||
|
||||
test("active bootstrap preserves newer lifecycle status", () => {
|
||||
expect(
|
||||
mergeActiveSessionStatus(
|
||||
{ "snapshot-active": {} },
|
||||
{ "started-during-bootstrap": "running", "stopped-during-bootstrap": "idle" },
|
||||
new Map([
|
||||
["started-during-bootstrap", 2],
|
||||
["stopped-during-bootstrap", 3],
|
||||
]),
|
||||
1,
|
||||
),
|
||||
).toEqual({
|
||||
"snapshot-active": "running",
|
||||
"started-during-bootstrap": "running",
|
||||
"stopped-during-bootstrap": "idle",
|
||||
})
|
||||
})
|
||||
|
||||
test("refreshes resources into reactive getters", async () => {
|
||||
const events = createEventStream()
|
||||
const location = {
|
||||
@@ -110,20 +128,12 @@ test("refreshes resources into reactive getters", async () => {
|
||||
|
||||
test("reconnects the event stream and bootstraps fresh data", async () => {
|
||||
const events = createEventStream()
|
||||
const requests = { active: 0, event: 0, model: 0 }
|
||||
let resolveActive!: (response: Response) => void
|
||||
const requests = { event: 0, model: 0 }
|
||||
const calls = createFetch((url) => {
|
||||
if (url.pathname === "/api/event") {
|
||||
requests.event++
|
||||
return events.v2()
|
||||
}
|
||||
if (url.pathname === "/api/session/active") {
|
||||
requests.active++
|
||||
if (requests.active === 1) return json({ data: { "session-stale": { type: "running" } }, watermarks: {} })
|
||||
return new Promise<Response>((resolve) => {
|
||||
resolveActive = resolve
|
||||
})
|
||||
}
|
||||
if (url.pathname !== "/api/model") return
|
||||
requests.model++
|
||||
return json({
|
||||
@@ -166,7 +176,6 @@ test("reconnects the event stream and bootstraps fresh data", async () => {
|
||||
|
||||
try {
|
||||
await wait(() => data.location.model.list()?.[0]?.id === "model-1")
|
||||
await wait(() => data.session.status("session-stale") === "running")
|
||||
expect(data.connection.status()).toBe("connected")
|
||||
expect(data.connection.attempt()).toBe(0)
|
||||
|
||||
@@ -175,20 +184,7 @@ test("reconnects the event stream and bootstraps fresh data", async () => {
|
||||
expect(data.connection.attempt()).toBe(1)
|
||||
expect(data.connection.error()).toBe("Event stream disconnected")
|
||||
|
||||
await wait(() => requests.active === 2 && data.connection.status() === "connected", 4000)
|
||||
emitEvent(events, {
|
||||
id: "evt_execution_started_after_reconnect",
|
||||
created: 1,
|
||||
type: "session.execution.started",
|
||||
durable: durable("session-new"),
|
||||
data: { sessionID: "session-new" },
|
||||
})
|
||||
await wait(() => data.session.status("session-new") === "running")
|
||||
resolveActive(json({ data: {}, watermarks: {} }))
|
||||
|
||||
await wait(() => data.location.model.list()?.[0]?.id === "model-2", 4000)
|
||||
await wait(() => data.session.status("session-stale") === "idle")
|
||||
expect(data.session.status("session-new")).toBe("running")
|
||||
expect(requests.event).toBe(2)
|
||||
expect(data.connection.status()).toBe("connected")
|
||||
expect(data.connection.attempt()).toBe(0)
|
||||
@@ -198,87 +194,6 @@ test("reconnects the event stream and bootstraps fresh data", async () => {
|
||||
}
|
||||
})
|
||||
|
||||
test("completes exploration when a queued prompt is promoted", async () => {
|
||||
const events = createEventStream()
|
||||
const sessionID = "session-promotion"
|
||||
const calls = createFetch((url) => {
|
||||
if (url.pathname === `/api/session/${sessionID}/message`) return json({ data: [], cursor: {} })
|
||||
}, events)
|
||||
let rows!: ReturnType<typeof createSessionRows>
|
||||
|
||||
function Probe() {
|
||||
rows = createSessionRows(() => sessionID)
|
||||
return <box />
|
||||
}
|
||||
|
||||
const app = await testRender(() => (
|
||||
<TestTuiContexts>
|
||||
<SDKProvider client={createClient(calls.fetch)} api={createApi(calls.fetch)}>
|
||||
<ProjectProvider>
|
||||
<DataProvider>
|
||||
<Probe />
|
||||
</DataProvider>
|
||||
</ProjectProvider>
|
||||
</SDKProvider>
|
||||
</TestTuiContexts>
|
||||
))
|
||||
|
||||
try {
|
||||
emitEvent(events, {
|
||||
id: "evt_step_started",
|
||||
created: 1,
|
||||
type: "session.step.started",
|
||||
durable: durable(sessionID),
|
||||
data: {
|
||||
sessionID,
|
||||
assistantMessageID: "message-assistant",
|
||||
agent: "build",
|
||||
model: { id: "model", providerID: "provider" },
|
||||
},
|
||||
})
|
||||
emitEvent(events, {
|
||||
id: "evt_tool_started",
|
||||
created: 2,
|
||||
type: "session.tool.input.started",
|
||||
durable: durable(sessionID, 1),
|
||||
data: {
|
||||
sessionID,
|
||||
assistantMessageID: "message-assistant",
|
||||
callID: "call-read",
|
||||
name: "read",
|
||||
},
|
||||
})
|
||||
await wait(() => rows.some((row) => row.type === "group" && !row.completed))
|
||||
|
||||
emitEvent(events, {
|
||||
id: "evt_prompt_admitted",
|
||||
created: 3,
|
||||
type: "session.prompt.admitted",
|
||||
durable: durable(sessionID, 2),
|
||||
data: {
|
||||
sessionID,
|
||||
inputID: "message-user",
|
||||
prompt: { text: "Continue" },
|
||||
delivery: "steer",
|
||||
},
|
||||
})
|
||||
await wait(() => rows.at(-1)?.type === "message")
|
||||
expect(rows.find((row) => row.type === "group")?.completed).toBe(false)
|
||||
|
||||
emitEvent(events, {
|
||||
id: "evt_prompt_promoted",
|
||||
created: 4,
|
||||
type: "session.prompt.promoted",
|
||||
durable: durable(sessionID, 3),
|
||||
data: { sessionID, inputID: "message-user" },
|
||||
})
|
||||
await wait(() => rows.find((row) => row.type === "group")?.completed === true)
|
||||
expect(rows.at(-1)).toEqual({ type: "message", messageID: "message-user" })
|
||||
} finally {
|
||||
app.renderer.destroy()
|
||||
}
|
||||
})
|
||||
|
||||
test("connectedOnce is false until first connect and persists across disconnect", async () => {
|
||||
const encoder = new TextEncoder()
|
||||
let stream: ReadableStreamDefaultController<Uint8Array> | undefined
|
||||
@@ -557,46 +472,6 @@ test("tracks session status from active sessions and execution events", async ()
|
||||
await wait(() => data.session.status("session-retry") === "idle")
|
||||
expect(data.session.message.get("session-retry", "message-retry")).not.toHaveProperty("retry")
|
||||
|
||||
emitEvent(events, {
|
||||
id: "evt_compaction_admitted",
|
||||
created: 0,
|
||||
type: "session.compaction.admitted",
|
||||
durable: durable("session-manual", 1),
|
||||
data: { sessionID: "session-manual", inputID: "message-compaction" },
|
||||
})
|
||||
await wait(() => {
|
||||
const message = data.session.message.get("session-manual", "message-compaction")
|
||||
return message?.type === "compaction" && message.status === "queued"
|
||||
})
|
||||
emitEvent(events, {
|
||||
id: "evt_manual_compaction_started",
|
||||
created: 1,
|
||||
type: "session.compaction.started",
|
||||
durable: durable("session-manual", 2),
|
||||
data: { sessionID: "session-manual", reason: "manual" },
|
||||
})
|
||||
emitEvent(events, {
|
||||
id: "evt_manual_compaction_delta",
|
||||
created: 2,
|
||||
type: "session.compaction.delta",
|
||||
data: { sessionID: "session-manual", text: "Streamed summary" },
|
||||
})
|
||||
await wait(() => {
|
||||
const message = data.session.message.get("session-manual", "message-compaction")
|
||||
return message?.type === "compaction" && message.summary === "Streamed summary"
|
||||
})
|
||||
emitEvent(events, {
|
||||
id: "evt_manual_compaction_ended",
|
||||
created: 3,
|
||||
type: "session.compaction.ended",
|
||||
durable: durable("session-manual", 3),
|
||||
data: { sessionID: "session-manual", reason: "manual", text: "Streamed summary", recent: "recent" },
|
||||
})
|
||||
await wait(() => {
|
||||
const message = data.session.message.get("session-manual", "message-compaction")
|
||||
return message?.type === "compaction" && message.status === "completed"
|
||||
})
|
||||
|
||||
emitEvent(events, {
|
||||
id: "evt_compaction_started",
|
||||
created: 0,
|
||||
@@ -1045,18 +920,7 @@ test("adds and dismisses question requests from live events", async () => {
|
||||
|
||||
test("settles pending tools when a live failure arrives", async () => {
|
||||
const events = createEventStream()
|
||||
const calls = createFetch((url) => {
|
||||
if (url.pathname === "/api/session/session-1/message/msg_model_1")
|
||||
return json({
|
||||
data: {
|
||||
id: "msg_model_1",
|
||||
type: "model-switched",
|
||||
previous: { id: "model-1", providerID: "provider-1", variant: "medium" },
|
||||
model: { id: "model-1", providerID: "provider-1", variant: "high" },
|
||||
time: { created: 0 },
|
||||
},
|
||||
})
|
||||
}, events)
|
||||
const calls = createFetch(undefined, events)
|
||||
let sync!: ReturnType<typeof useData>
|
||||
let ready!: () => void
|
||||
const mounted = new Promise<void>((resolve) => {
|
||||
@@ -1097,7 +961,7 @@ test("settles pending tools when a live failure arrives", async () => {
|
||||
durable: durable("session-1", 1),
|
||||
data: {
|
||||
sessionID: "session-1",
|
||||
model: { id: "model-1", providerID: "provider-1", variant: "high" },
|
||||
model: { id: "model-1", providerID: "provider-1" },
|
||||
},
|
||||
})
|
||||
emitEvent(events, {
|
||||
@@ -1183,11 +1047,6 @@ test("settles pending tools when a live failure arrives", async () => {
|
||||
"model-switched",
|
||||
"assistant",
|
||||
])
|
||||
expect(sync.session.message.get("session-1", "msg_model_1")).toMatchObject({
|
||||
type: "model-switched",
|
||||
previous: { id: "model-1", providerID: "provider-1", variant: "medium" },
|
||||
model: { id: "model-1", providerID: "provider-1", variant: "high" },
|
||||
})
|
||||
} finally {
|
||||
app.renderer.destroy()
|
||||
}
|
||||
|
||||
@@ -209,35 +209,6 @@ test("renders a footer for a pre-output retry assistant after replay", () => {
|
||||
expect(reduceSessionRows([message])).toEqual([{ type: "assistant-footer", messageID: "assistant-retry" }])
|
||||
})
|
||||
|
||||
test("places a pending compaction barrier before every queued user message", () => {
|
||||
const queued = (id: string, text: string, created: number): SessionMessage => ({
|
||||
type: "user",
|
||||
id,
|
||||
text,
|
||||
metadata: { queued: true },
|
||||
time: { created },
|
||||
})
|
||||
const messages: SessionMessage[] = [
|
||||
queued("user-before", "Before", 1),
|
||||
{
|
||||
type: "compaction",
|
||||
id: "compaction",
|
||||
status: "queued",
|
||||
reason: "manual",
|
||||
summary: "",
|
||||
recent: "",
|
||||
time: { created: 2 },
|
||||
},
|
||||
queued("user-after", "After", 3),
|
||||
]
|
||||
|
||||
expect(reduceSessionRows(messages)).toEqual([
|
||||
{ type: "message", messageID: "compaction" },
|
||||
{ type: "message", messageID: "user-before" },
|
||||
{ type: "message", messageID: "user-after" },
|
||||
])
|
||||
})
|
||||
|
||||
function assistant(id: string, content: SessionMessageAssistant["content"]): SessionMessageAssistant {
|
||||
return {
|
||||
type: "assistant",
|
||||
|
||||
@@ -34,16 +34,4 @@ describe("util.model", () => {
|
||||
"Switched model to removed/gone/high",
|
||||
)
|
||||
})
|
||||
|
||||
test("distinguishes variant-only switches from model switches", () => {
|
||||
const previous = { providerID: "openai", id: "gpt-5.5", variant: "medium" }
|
||||
|
||||
expect(switchLabel({ ...previous, variant: "high" }, undefined, previous)).toBe("Switched variant to high")
|
||||
expect(switchLabel({ providerID: "openai", id: "gpt-5.5" }, undefined, previous)).toBe(
|
||||
"Switched variant to default",
|
||||
)
|
||||
expect(switchLabel({ providerID: "anthropic", id: "sonnet", variant: "high" }, undefined, previous)).toBe(
|
||||
"Switched model to anthropic/sonnet/high",
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -749,12 +749,12 @@ You can configure file watcher ignore patterns through the `watcher` option.
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"watcher": {
|
||||
"ignore": ["**/generated/**"]
|
||||
"ignore": ["node_modules/**", "dist/**", ".git/**"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Patterns follow glob syntax. Common dependency, VCS, build, and cache directories are ignored automatically at any depth.
|
||||
Patterns follow glob syntax. Use this to exclude noisy directories from file watching.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,24 +1,15 @@
|
||||
# V2 Schema Changelog
|
||||
|
||||
## 2026-07-04: Canonicalize Generated Shell Type Name
|
||||
|
||||
- Collapse the legacy JavaScript SDK generator's equivalent `Shell1V2` component into the canonical `ShellV2` contract.
|
||||
|
||||
Compatibility:
|
||||
|
||||
- The Shell wire shape is unchanged. Generated event and endpoint types now consistently reference `ShellV2`.
|
||||
|
||||
## 2026-07-03: Add Execution Lifecycle, Retry, And Structured Session Errors
|
||||
|
||||
- Replace live-only `session.execution.settled` and unused `session.retried` with durable v1 `session.execution.started`, `session.execution.succeeded`, `session.execution.failed`, `session.execution.interrupted`, and `session.retry.scheduled` events.
|
||||
- Add an open `SessionError` wire envelope with dot-cased type values and the browser-safe `FinishReason` contract.
|
||||
- Add the closed, dot-cased `SessionError` wire union and browser-safe `FinishReason` contract.
|
||||
- Project retry state onto the current assistant and classify content-filter finishes as failed steps.
|
||||
- Reuse one projected assistant across pre-output retry steps; each provider call remains a distinct step and consumes agent allowance.
|
||||
|
||||
Compatibility:
|
||||
|
||||
- Experimental V2 event, sequence, input, and message-projection rows are reset. Durable event contracts restart at v1.
|
||||
- `SessionError.type` remains an open string so new error classifications do not require event-version or database migrations. Unknown fields are ignored by older decoders; richer public details require a separate compatibility design.
|
||||
- Execution lifecycle events are historical observations of one process-local coordinator busy period. Unmatched starts never establish current liveness or recovery work; `/api/session/active` remains the current-process liveness authority.
|
||||
- Scheduled retries are historical UI state after a crash and never trigger provider recovery.
|
||||
|
||||
@@ -964,7 +955,7 @@ Compatibility:
|
||||
|
||||
## 2026-07-03: Simplify Assistant Fragments And Provider State
|
||||
|
||||
- Remove provider block IDs from current Session text and reasoning event payloads and projected content. A Session assistant step allows at most one open fragment of each kind; events carry a Session-assigned kind-specific ordinal so live updates and hydrated projections share the stable `(assistantMessageID, kind, ordinal)` reference. Tool correlation continues to use `callID`.
|
||||
- Remove provider block IDs from current Session text and reasoning event payloads and projected content. A Session assistant step allows at most one open fragment of each kind; UI references use assistant message ID, kind, and ordinal. Tool correlation continues to use `callID`.
|
||||
- Replace nested `providerMetadata` with opaque, provider-un-nested `state` at the Session boundary. Reasoning uses `state`; tool calls use `state`, settlements use `resultState`, and projected tools expose `providerState` and `providerResultState`. Replay re-nests state under the selected provider only for the same successful model.
|
||||
- Flatten `executed` on tool events and projected tools, and remove the redundant tool name from `session.tool.called` because `session.tool.input.started` owns it.
|
||||
- Rename `session.revert.committed.messageID` to `to`, paired with `session.forked.from`.
|
||||
@@ -973,5 +964,5 @@ Compatibility:
|
||||
|
||||
Compatibility:
|
||||
|
||||
- All changed durable definitions remain version 1. `20260703200000_reset_v2_session_events` performs the single reset for this Session event contract update, wiping experimental V2 events, sequences, projected messages, and admitted inputs.
|
||||
- All changed durable definitions remain version 1. `20260703200000_reset_v2_event_fragments` wipes experimental V2 events, sequences, projected messages, and admitted inputs.
|
||||
- Promise, Effect, and legacy JavaScript SDK surfaces are regenerated from the simplified schemas.
|
||||
|
||||
+5
-8
@@ -32,7 +32,7 @@ sessions.active()
|
||||
-> absence means inactive; activity is not durable across process restarts
|
||||
```
|
||||
|
||||
`session_input` is the typed durable admission inbox for prompts and Session control operations. `PromptAdmitted` records accepted user input; `Compaction.Admitted` records one coalesced manual compaction barrier. Admitted prompts remain outside model-visible Session history until the serialized runner publishes `Prompted`. Its projector atomically writes the visible user message and marks the inbox row promoted in the same event transaction. A pending compaction blocks all unpromoted prompts, runs before the Session would otherwise become idle, and releases the backlog only after its durable ended or failed event settles the barrier. The V1-to-V2 shadow bridge publishes the same `Prompted` event for already-visible V1 prompts.
|
||||
`session_input` is the durable admission inbox. `PromptAdmitted` records and projects accepted input so pending queue state can be replayed, replicated, and observed by clients. Admitted inputs remain outside model-visible Session history until the serialized runner publishes `Prompted`. Its projector atomically writes the visible user message and marks the inbox row promoted in the same event transaction. The V1-to-V2 shadow bridge publishes the same `Prompted` event for already-visible V1 prompts.
|
||||
|
||||
`admittedSeq` is the durable Session event sequence of `PromptAdmitted`. Clients may use the admission event to represent queued input before `Prompted` makes it part of visible conversation history.
|
||||
|
||||
@@ -47,9 +47,7 @@ SessionExecution.resume(sessionID)
|
||||
|
||||
`SessionExecution` and the read-side `SessionStore` are process-global. `SessionRunner`, catalog, model resolver, tool registry, permission state, and filesystem are cached per Location. No layer takes a Session ID. An omitted `Location.workspaceID` means implicit-local placement; explicit workspace identity remains reserved for future placement semantics.
|
||||
|
||||
The local runner issues one explicit `llm.stream(request)` per step, projects each complete local tool call durably before eagerly starting its structured child execution, awaits every owned tool fiber after provider-stream closure, and reloads projected history once before continuation. For every in-process step, `session.step.started` precedes its tool calls, every local and hosted call settles as `session.tool.success` or `session.tool.failed`, and only then may the runner publish the single terminal `session.step.ended` or `session.step.failed`. Streamed provider-error evidence is retained until this closeout; thrown provider failures and interruption use the same settlement-first ordering. Promoting any new user input resets the selected agent's configured step allowance; multiple steers promoted at one boundary reset it once.
|
||||
|
||||
`callID` is unique only within its owning step, not across the Session. Tool events therefore carry `assistantMessageID`, and consumers correlate a call through the step that owns that assistant message rather than inventing a synthetic composite key. Before assembling a provider request, the runner's cross-drain `failInterruptedTools` recovery durably fails any tool still projected as pending or running from a previous process with `Tool execution interrupted`. This orphan-recovery sweep is the explicit nesting exception: it occurs in a later drain, but attributes every settlement to the original `assistantMessageID`; abandoned side effects are never silently replayed.
|
||||
The local runner issues one explicit `llm.stream(request)` per step, projects each complete local tool call durably before eagerly starting its structured child execution, awaits every started tool fiber after provider-stream closure, and reloads projected history once before continuation. Promoting any new user input resets the selected agent's configured step allowance; multiple steers promoted at one boundary reset it once. Tool settlement events carry the owning assistant message ID because provider-local call IDs may repeat across steps. Before assembling a provider request, the runner durably fails any local tool still projected as `running` from a previous process with `Tool execution interrupted`; abandoned side effects are never silently replayed.
|
||||
|
||||
`session.execution.started.1` and exactly one of `session.execution.succeeded.1`, `session.execution.failed.1`, or `session.execution.interrupted.1` observe one process-local coordinator busy period, including coalesced drains and joined resumes. These durable rows are history, not a durable execution identity: replay must never infer current liveness, recovery, grouping, or resumability from an unmatched start. A drain has no durable identity or transcript boundary. `/api/session/active` is the authority for current process-local liveness, and is empty after restart. User interruption records `reason: "user"`; owner-scope interruption defaults to `"shutdown"`; `"superseded"` is reserved for explicit replacement.
|
||||
|
||||
@@ -110,6 +108,7 @@ Current Context Epoch follow-ups:
|
||||
|
||||
- Add configured, remote, and nested instruction sources with explicit precedence and removal semantics.
|
||||
- Add durable post-crash continuation recovery for promoted or provider-dispatched work.
|
||||
- Add explicit manual compaction on top of automatic request-budget compaction.
|
||||
- Add operational metrics for observation latency, unavailable sources, contention, baseline size, and chronological-update growth.
|
||||
- Consider watcher-backed per-file caching only if measurements show direct safe-boundary observation is too expensive.
|
||||
- Expose plugin-defined Context Sources only after plugin reload and scoped cleanup semantics are designed.
|
||||
@@ -121,11 +120,9 @@ Before each step, the runner estimates the complete model-visible request and co
|
||||
|
||||
Compaction keeps the full transcript durable while replacing its active model representation with one hidden checkpoint containing a structured rolling summary and token-bounded serialized recent context. Provider-native assistant, reasoning, and tool messages never survive across the boundary, avoiding signature and encrypted-reasoning failures when the earlier prefix changes.
|
||||
|
||||
The rolling summary is a continuation checkpoint with this complete heading order: `Continuation Goal`, `Operating Constraints`, `Progress` (`Completed`, `In Flight`, `Blocked`), `Decisions To Preserve`, `Resume From Here`, `Context To Preserve`, and `Working Files`. Every heading remains present even when its value is `(none)`.
|
||||
`session.compaction.started.1` durably identifies the attempt. Compaction deltas are live-only progress. `session.compaction.ended.1` durably stores the final summary and serialized recent context; only this completed event projects a model-visible compaction message. On the next physical attempt, the runner observes that completed compaction and directly renders a fresh Context Epoch baseline. A failed or interrupted attempt therefore leaves the previous history boundary active.
|
||||
|
||||
`session.compaction.admitted.1` durably records a manual request and projects its queued transcript row. `session.compaction.started.1` identifies the attempt and transforms that row into a running divider. Compaction deltas are live-only progress rendered beneath it. `session.compaction.ended.1` durably stores the final summary and serialized recent context, completes the same row, and settles the manual barrier. `session.compaction.failed.1` settles an unsuccessful manual barrier without changing the previous history boundary. On the next physical attempt, the runner observes a completed compaction and directly renders a fresh Context Epoch baseline.
|
||||
|
||||
Assistant text and reasoning follow a strict `started` / live-only `delta` / durable full-value `ended` lifecycle. A publisher permits at most one open fragment of each kind in a step and fails on a second start before the matching end. Provider block IDs remain internal to LLM adapters; each fragment event carries a Session-assigned kind-specific ordinal, matching the ordinal derived from projected content. UI identity is therefore the assistant message ID plus content kind and ordinal. Tool calls retain step-scoped `callID` because settlements and provider replay correlate through it.
|
||||
Assistant text and reasoning follow a strict `started` / live-only `delta` / durable full-value `ended` lifecycle. A publisher permits at most one open fragment of each kind in a step and fails on a second start before the matching end. Provider block IDs remain internal to LLM adapters; projected UI identity is the assistant message ID plus content kind and ordinal. Tool calls retain `callID` because settlements and provider replay correlate through it.
|
||||
|
||||
Provider continuation state is opaque and un-nested at the Session boundary. The publisher selects only the active model provider's entry from LLM provider metadata. Same-model replay re-nests that state under the current provider; model switches and failed assistant steps continue to suppress provider-native continuation state.
|
||||
|
||||
|
||||
+3
-2
@@ -24,8 +24,6 @@ through legacy `SessionPrompt.loop(...)`:
|
||||
and issues one explicit `llm.stream(request)` step at a time
|
||||
- durable V2 projections record text, reasoning, provider failures, tool calls,
|
||||
tool results, and assistant output
|
||||
- owned local tool fibers and unresolved hosted calls settle before their step's
|
||||
single terminal event; cross-drain orphan recovery retains original assistant attribution
|
||||
- a scoped `ToolRegistry` advertises definitions and the first permission-checked
|
||||
`read` built-in
|
||||
- local continuation reloads projected history, and promoting new user input resets the selected agent's configured step allowance
|
||||
@@ -39,6 +37,9 @@ a FIFO until the Session would otherwise become idle and then promote one at a t
|
||||
|
||||
Next reviewed slices:
|
||||
|
||||
- preserve eager structured local-tool settlement: durably record each complete
|
||||
call, start its child execution immediately, await every settlement after the
|
||||
step closes, then reload projected history once
|
||||
- revisit per-step tool-call limits, output truncation, and operational
|
||||
backpressure before broadening exposure; eager local execution is deliberately
|
||||
unbounded in the current local slice while SQLite publication stays serialized
|
||||
|
||||
Reference in New Issue
Block a user