mirror of
https://github.com/stablyai/orca.git
synced 2026-11-04 02:57:36 +00:00
feat(native-chat): read ZCode session transcripts through the OpenCode SQLite reader
ZCode's CLI persists an OpenCode-v1-shaped history in its own SQLite store (~/.zcode/cli/db/db.sqlite). The Agent Session History scan already lists those sessions, but opening one in the native chat found nothing: the chat transcript path had no ZCode awareness. Resolve a zcode transcript against the ZCode database (native home, then WSL homes) before any OpenCode install, tag every read (signal, page, subscribe) with the agent, and apply the same hidden-transcript filter the scan uses so ZCode's hidden bookkeeping rows stay out of chat renders.
This commit is contained in:
@@ -20,11 +20,16 @@ import { openCodeTranscriptPageLimit } from '../../shared/opencode-transcript-pa
|
||||
// OpenCode SQLite reads use the same bounded worker as AI Vault.
|
||||
|
||||
export type OpenCodeTranscriptDeps = {
|
||||
resolveDbPath?: (sessionId?: string, signal?: AbortSignal) => Promise<string | null>
|
||||
resolveDbPath?: (
|
||||
sessionId?: string,
|
||||
signal?: AbortSignal,
|
||||
agent?: 'zcode'
|
||||
) => Promise<string | null>
|
||||
readSignal?: (
|
||||
dbPath: string,
|
||||
sessionId: string,
|
||||
signal?: AbortSignal
|
||||
signal?: AbortSignal,
|
||||
agent?: 'zcode'
|
||||
) => Promise<OpenCodeTranscriptSignal | null>
|
||||
readPage?: (
|
||||
args: {
|
||||
@@ -32,6 +37,7 @@ export type OpenCodeTranscriptDeps = {
|
||||
sessionId: string
|
||||
limit: number
|
||||
beforeMessageRowId?: number
|
||||
agent?: 'zcode'
|
||||
},
|
||||
signal?: AbortSignal
|
||||
) => Promise<OpenCodeTranscriptPage | null>
|
||||
@@ -43,17 +49,51 @@ export function resolveOpenCodeTranscriptDbPath(sessionId?: string): Promise<str
|
||||
|
||||
export const openCodeTranscriptDefaultDeps: Required<OpenCodeTranscriptDeps> = {
|
||||
resolveDbPath: discoverOpenCodeTranscriptDatabase,
|
||||
readSignal: (dbPath, sessionId, signal) =>
|
||||
readOpenCodeTranscriptSignalViaWorker({ dbPath, sessionId }, signal),
|
||||
readSignal: (dbPath, sessionId, signal, agent) =>
|
||||
readOpenCodeTranscriptSignalViaWorker({ dbPath, sessionId, agent }, signal),
|
||||
readPage: (args, signal) => readOpenCodeTranscriptPageViaWorker(args, signal)
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a subscribe's read legs against its own abort signal, with the agent
|
||||
* tag (when any) already applied to every leg. Kept here so the poll loop stays
|
||||
* free of default-vs-override plumbing.
|
||||
*/
|
||||
export function bindOpenCodeTranscriptDeps(
|
||||
deps: OpenCodeTranscriptDeps,
|
||||
signal: AbortSignal,
|
||||
agent?: 'zcode'
|
||||
): {
|
||||
resolveDbPath: () => Promise<string | null>
|
||||
readSignal: (dbPath: string, sessionId: string) => Promise<OpenCodeTranscriptSignal | null>
|
||||
readPage: (
|
||||
page: Parameters<NonNullable<OpenCodeTranscriptDeps['readPage']>>[0]
|
||||
) => Promise<OpenCodeTranscriptPage | null>
|
||||
} {
|
||||
return {
|
||||
resolveDbPath: () =>
|
||||
(deps.resolveDbPath ?? openCodeTranscriptDefaultDeps.resolveDbPath)(undefined, signal, agent),
|
||||
readSignal: (dbPath, sessionId) =>
|
||||
(deps.readSignal ?? openCodeTranscriptDefaultDeps.readSignal)(
|
||||
dbPath,
|
||||
sessionId,
|
||||
signal,
|
||||
agent
|
||||
),
|
||||
readPage: (page) =>
|
||||
(deps.readPage ?? openCodeTranscriptDefaultDeps.readPage)(
|
||||
{ ...page, ...(agent ? { agent } : {}) },
|
||||
signal
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export type OpenCodeTailResult =
|
||||
| { messages: NativeChatMessage[]; hasMore: boolean; beforeOffset: number }
|
||||
| { error: string; notFound?: true }
|
||||
|
||||
export async function readOpenCodeNativeChatTranscriptTail(
|
||||
args: { sessionId: string; limit: number; beforeOffset?: number },
|
||||
args: { sessionId: string; limit: number; beforeOffset?: number; agent?: 'zcode' },
|
||||
deps: OpenCodeTranscriptDeps = {},
|
||||
signal?: AbortSignal
|
||||
): Promise<OpenCodeTailResult> {
|
||||
@@ -61,7 +101,8 @@ export async function readOpenCodeNativeChatTranscriptTail(
|
||||
try {
|
||||
const dbPath = await (deps.resolveDbPath ?? openCodeTranscriptDefaultDeps.resolveDbPath)(
|
||||
args.sessionId,
|
||||
signal
|
||||
signal,
|
||||
args.agent
|
||||
)
|
||||
if (!dbPath) {
|
||||
return { error: 'Transcript unavailable', notFound: true }
|
||||
@@ -71,7 +112,8 @@ export async function readOpenCodeNativeChatTranscriptTail(
|
||||
dbPath,
|
||||
sessionId: args.sessionId,
|
||||
limit,
|
||||
...(args.beforeOffset !== undefined ? { beforeMessageRowId: args.beforeOffset } : {})
|
||||
...(args.beforeOffset !== undefined ? { beforeMessageRowId: args.beforeOffset } : {}),
|
||||
...(args.agent ? { agent: args.agent } : {})
|
||||
},
|
||||
signal
|
||||
)
|
||||
@@ -91,7 +133,8 @@ export async function readOpenCodeNativeChatTranscriptTail(
|
||||
export async function readOpenCodeNativeChatTranscriptFull(
|
||||
sessionId: string,
|
||||
deps: OpenCodeTranscriptDeps = {},
|
||||
signal?: AbortSignal
|
||||
signal?: AbortSignal,
|
||||
agent?: 'zcode'
|
||||
): Promise<ReadTranscriptResult> {
|
||||
// Pages arrive newest-window first; reverse windows, preserving message order.
|
||||
const pages: NativeChatMessage[][] = []
|
||||
@@ -113,7 +156,8 @@ export async function readOpenCodeNativeChatTranscriptFull(
|
||||
dbPath,
|
||||
sessionId,
|
||||
limit: 500,
|
||||
...(cursor !== undefined ? { beforeMessageRowId: cursor } : {})
|
||||
...(cursor !== undefined ? { beforeMessageRowId: cursor } : {}),
|
||||
...(agent ? { agent } : {})
|
||||
},
|
||||
signal
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user