refactor(app): route backend through adapters

This commit is contained in:
Brendan Allan 2026-07-16 06:24:08 +00:00
commit 08ea08e830
130 changed files with 5302 additions and 1953 deletions

View file

@ -1,4 +1,4 @@
import type { FileContent } from "@opencode-ai/sdk/v2"
import type { FileContent } from "../context/data-types"
import { createEffect, createMemo, Match, on, onCleanup, Show, Switch, untrack, type JSX } from "solid-js"
import { createStore } from "solid-js/store"
import { useI18n } from "@opencode-ai/ui/context/i18n"

View file

@ -1,5 +1,5 @@
import { describe, expect, test } from "bun:test"
import type { FilePart } from "@opencode-ai/sdk/v2"
import type { FilePart } from "../context/data-types"
import { attached, inline, kind } from "./message-file"
function file(part: Partial<FilePart> = {}): FilePart {

View file

@ -1,4 +1,4 @@
import type { FilePart } from "@opencode-ai/sdk/v2"
import type { FilePart } from "../context/data-types"
export function attached(part: FilePart) {
return part.url.startsWith("data:")

View file

@ -1,4 +1,4 @@
import { UserMessage } from "@opencode-ai/sdk/v2"
import type { UserMessage } from "../context/data-types"
import { HoverCard } from "@kobalte/core/hover-card"
import { ComponentProps, For, Match, Show, createSignal, splitProps, Switch } from "solid-js"
import { DiffChanges } from "@opencode-ai/ui/diff-changes"

View file

@ -29,7 +29,7 @@ import {
UserMessage,
QuestionAnswer,
QuestionInfo,
} from "@opencode-ai/sdk/v2"
} from "../context/data-types"
import { useData } from "../context"
import { useFileComponent } from "@opencode-ai/ui/context/file"
import { useDialog } from "@opencode-ai/ui/context/dialog"

View file

@ -1,6 +1,6 @@
import { parseDiffFromFile, parsePatchFiles, type FileDiffMetadata } from "@pierre/diffs"
import { parsePatch } from "diff"
import type { FileDiffInfo, VcsFileDiff } from "@opencode-ai/sdk/v2"
import type { SnapshotFileDiff as FileDiffInfo, VcsFileDiff } from "../context/data-types"
type LegacyDiff = {
file: string

View file

@ -1,5 +1,5 @@
import { createEffect, createMemo, createSignal, on, onCleanup, Show } from "solid-js"
import type { SessionStatus } from "@opencode-ai/sdk/v2/client"
import type { SessionStatus } from "../context/data-types"
import { useI18n } from "@opencode-ai/ui/context/i18n"
import { Card } from "@opencode-ai/ui/card"
import { Tooltip } from "@opencode-ai/ui/tooltip"

View file

@ -15,7 +15,7 @@ import { getDirectory, getFilename } from "@opencode-ai/core/util/path"
import { checksum } from "@opencode-ai/core/util/encode"
import { createEffect, createMemo, For, Match, onCleanup, Show, Switch, untrack, type JSX } from "solid-js"
import { createStore } from "solid-js/store"
import { type FileContent, type FileDiffInfo, type VcsFileDiff } from "@opencode-ai/sdk/v2"
import type { FileContent, SnapshotFileDiff as FileDiffInfo, VcsFileDiff } from "../context/data-types"
import { PreloadMultiFileDiffResult } from "@pierre/diffs/ssr"
import { type SelectedLineRange } from "@pierre/diffs"
import { Dynamic } from "solid-js/web"

View file

@ -1,11 +1,11 @@
import {
import type {
AssistantMessage,
type FileDiffInfo,
Message as MessageType,
Part as PartType,
type UserMessage,
} from "@opencode-ai/sdk/v2/client"
import type { SessionStatus } from "@opencode-ai/sdk/v2"
SessionStatus,
SnapshotFileDiff as FileDiffInfo,
UserMessage,
} from "../context/data-types"
import { useData } from "../context"
import { useFileComponent } from "@opencode-ai/ui/context/file"
@ -436,7 +436,7 @@ export function SessionTurn(
</Show>
</div>
</Show>
<SessionRetry status={status()} show={active()} />
<SessionRetry status={((value) => (value.type === "running" ? { type: "busy" as const } : value))(status())} show={active()} />
<Show when={edited() > 0 && !working()}>
<div
data-slot="session-turn-diffs"

View file

@ -11,7 +11,7 @@ import type {
ToolPart,
FilePart,
AgentPart,
} from "@opencode-ai/sdk/v2"
} from "../context/data-types"
import { DataProvider } from "../context/data"
import { FileComponentProvider } from "@opencode-ai/ui/context/file"
import { SessionTurn } from "./session-turn"

View file

@ -0,0 +1,212 @@
export type Session = {
id: string
slug: string
projectID: string
directory: string
title: string
version: string
parentID?: string
time: { created: number; updated: number; archived?: number }
revert?: { messageID: string }
}
export type SessionStatus =
| { type: "idle" }
| { type: "busy" }
| { type: "running" }
| {
type: "retry"
attempt: number
message: string
next: number
action?: { reason: string; provider: string; title: string; message: string; label: string; link?: string }
}
export type Todo = {
content: string
status: string
priority: string
}
export type QuestionInfo = {
question: string
header: string
options: Array<{ label: string; description: string }>
multiple?: boolean
custom?: boolean
}
export type QuestionAnswer = string[]
export type SnapshotFileDiff = {
file: string
patch?: string
additions: number
deletions: number
status?: "added" | "deleted" | "modified"
}
export type VcsFileDiff = SnapshotFileDiff & { file: string }
type SummaryFileDiff = Omit<SnapshotFileDiff, "file"> & { file?: string }
export type FileContent = {
readonly type: "text" | "binary"
readonly content: string
readonly diff?: string
readonly patch?: {
readonly oldFileName: string
readonly newFileName: string
readonly oldHeader?: string
readonly newHeader?: string
readonly hunks: readonly {
readonly oldStart: number
readonly oldLines: number
readonly newStart: number
readonly newLines: number
readonly lines: readonly string[]
}[]
readonly index?: string
}
readonly encoding?: "base64"
readonly mimeType?: string
}
export type MessageError =
| { name: "ProviderAuthError"; data: { providerID: string; message: string } }
| { name: "UnknownError"; data: { message: string; ref?: string } }
| { name: "MessageOutputLengthError"; data: Record<string, unknown> }
| { name: "MessageAbortedError"; data: { message: string } }
| { name: "StructuredOutputError"; data: { message: string; retries: number } }
| { name: "ContextOverflowError"; data: { message: string; responseBody?: string } }
| { name: "ContentFilterError"; data: { message: string } }
| {
name: "APIError"
data: {
message: string
statusCode?: number
isRetryable: boolean
responseHeaders?: Record<string, string>
responseBody?: string
metadata?: Record<string, string>
}
}
export type Message =
| {
id: string
sessionID: string
role: "user"
time: { created: number }
agent: string
model: { providerID: string; modelID: string; variant?: string }
system?: string
summary?: { title?: string; body?: string; diffs: SummaryFileDiff[] }
}
| {
id: string
sessionID: string
role: "assistant"
time: { created: number; completed?: number }
parentID: string
modelID: string
providerID: string
mode: string
agent: string
path: { cwd: string; root: string }
cost: number
tokens: { input: number; output: number; reasoning: number; cache: { read: number; write: number } }
error?: MessageError
finish?: string
}
export type UserMessage = Extract<Message, { role: "user" }>
export type AssistantMessage = Extract<Message, { role: "assistant" }>
type PartBase = { id: string; sessionID: string; messageID: string }
export type FilePart = PartBase & {
type: "file"
mime: string
filename?: string
url: string
source?:
| { type: "file"; path: string; text: { value: string; start: number; end: number } }
| {
type: "symbol"
path: string
range: {
start: { line: number; character: number }
end: { line: number; character: number }
}
name: string
kind: number
text: { value: string; start: number; end: number }
}
| { type: "resource"; clientName: string; uri: string; text: { value: string; start: number; end: number } }
}
type ToolState =
| { status: "pending"; input: Record<string, unknown>; raw: string }
| {
status: "running"
input: Record<string, unknown>
title?: string
metadata?: Record<string, unknown>
time: { start: number }
}
| {
status: "completed"
input: Record<string, unknown>
output: string
title: string
metadata: Record<string, unknown>
time: { start: number; end: number; compacted?: number }
attachments?: FilePart[]
}
| {
status: "error"
input: Record<string, unknown>
error: string
metadata?: Record<string, unknown>
time: { start: number; end: number }
}
export type Part =
| (PartBase & {
type: "text"
text: string
synthetic?: boolean
ignored?: boolean
time?: { start: number; end?: number }
metadata?: Record<string, unknown>
})
| (PartBase & {
type: "reasoning"
text: string
metadata?: Record<string, unknown>
time: { start: number; end?: number }
})
| FilePart
| (PartBase & { type: "agent"; name: string; source?: { value: string; start: number; end: number } })
| (PartBase & { type: "tool"; callID: string; tool: string; state: ToolState; metadata?: Record<string, unknown> })
| (PartBase & { type: "subtask"; prompt: string; description: string; agent: string })
| (PartBase & { type: "step-start"; snapshot?: string })
| (PartBase & {
type: "step-finish"
reason: string
snapshot?: string
cost: number
tokens: { input: number; output: number; reasoning: number; cache: { read: number; write: number } }
})
| (PartBase & { type: "snapshot"; snapshot: string })
| (PartBase & { type: "patch"; hash: string; files: string[] })
| (PartBase & {
type: "retry"
attempt: number
error: Extract<MessageError, { name: "APIError" }>
time: { created: number }
})
| (PartBase & { type: "compaction"; auto: boolean })
export type TextPart = Extract<Part, { type: "text" }>
export type ReasoningPart = Extract<Part, { type: "reasoning" }>
export type ToolPart = Extract<Part, { type: "tool" }>
export type AgentPart = Extract<Part, { type: "agent" }>

View file

@ -1,13 +1,13 @@
import type { FileDiffInfo, Message, Part, Provider, Session, SessionStatus } from "@opencode-ai/sdk/v2"
import type { Message, Part, Session, SessionStatus, SnapshotFileDiff as FileDiffInfo } from "./data-types"
import { createSimpleContext } from "@opencode-ai/ui/context"
import { PreloadMultiFileDiffResult } from "@pierre/diffs/ssr"
export type NormalizedProviderListResponse = {
all: Map<string, Provider>
all: ReadonlyMap<string, { name: string; models: Readonly<Record<string, { name: string }>> }>
default: {
[key: string]: string
}
connected: Array<string>
connected: readonly string[]
}
type Data = {

View file

@ -1,4 +1,4 @@
import type { FileContent } from "@opencode-ai/sdk/v2"
import type { FileContent } from "../context/data-types"
export type MediaKind = "image" | "audio" | "svg"

View file

@ -6,7 +6,7 @@ import { useFileComponent } from "@opencode-ai/ui/context/file"
import { useI18n } from "@opencode-ai/ui/context/i18n"
import { mediaKindFromPath } from "../../pierre/media"
import { cloneSelectedLineRange, previewSelectedLines } from "../../pierre/selection-bridge"
import type { FileContent, FileDiffInfo, VcsFileDiff } from "@opencode-ai/sdk/v2"
import type { FileContent, SnapshotFileDiff as FileDiffInfo, VcsFileDiff } from "../../context/data-types"
import { createEffect, createMemo, onCleanup, Show, untrack } from "solid-js"
import { createStore } from "solid-js/store"
import { Dynamic } from "solid-js/web"