mirror of
https://github.com/stablyai/orca.git
synced 2026-11-13 17:37:40 +00:00
* refactor: import journal queue state from defining owners * refactor(shared): organize execution and automation owners * fix: retain type imports used by surviving test cases * refactor: finish work item owners and refresh validation metadata * test: infer reconnect status fixture type * test(claude): resolve source files beside same-named directories * test(runtime): group repository creation mock registrations
308 lines
10 KiB
TypeScript
308 lines
10 KiB
TypeScript
import type { AgentMessageSender } from './agent-session/agent-session-message-source'
|
|
import type { OrchestrationPartyLocationResult } from './orchestration/orchestration-caller-status'
|
|
import type { AgentSessionWorkspaceKind } from './agent-session/lifecycle/agent-session-record'
|
|
import { workspaceKindForWorktreeId } from './agent-launch/contracts/workspace-launch-kind'
|
|
|
|
export type StructuredSessionWorkspaceRemovedDetails = {
|
|
workspaceKind: AgentSessionWorkspaceKind
|
|
}
|
|
|
|
export function readStructuredSessionWorkspaceRemovedDetails(
|
|
value: unknown
|
|
): StructuredSessionWorkspaceRemovedDetails | undefined {
|
|
if (value !== null && typeof value === 'object' && 'workspaceKind' in value) {
|
|
const { workspaceKind } = value
|
|
if (workspaceKind === 'folder' || workspaceKind === 'git-worktree') {
|
|
return { workspaceKind }
|
|
}
|
|
}
|
|
return undefined
|
|
}
|
|
|
|
export type StructuredSessionOpenTarget = { sessionId: string; worktreeId: string; agent?: string }
|
|
export type StructuredSessionOpenSource =
|
|
| {
|
|
kind: 'history'
|
|
structuredSession: { sessionId: string; workspaceId: string }
|
|
agent?: string
|
|
}
|
|
| ({ kind: 'notification' } & StructuredSessionOpenTarget)
|
|
| {
|
|
kind: 'sender'
|
|
party: AgentMessageSender['party']
|
|
messageIds: readonly string[]
|
|
fallback?: StructuredSessionOpenTarget
|
|
displayName?: string
|
|
}
|
|
export type StructuredSessionOpenFailure = {
|
|
reason: 'gone' | 'workspace-missing' | 'unknown' | 'unsupported' | 'unreachable'
|
|
beforeEffects: boolean
|
|
code?: string
|
|
surface?: 'terminal'
|
|
workspaceKind?: AgentSessionWorkspaceKind
|
|
}
|
|
export type StructuredSessionOpenTab = { id: string; sessionId: string; agent?: string }
|
|
export type StructuredSessionOpenResult =
|
|
| { kind: 'opened'; target: StructuredSessionOpenTarget; tab: StructuredSessionOpenTab }
|
|
| { kind: 'terminal'; handle: string }
|
|
| { kind: 'failed'; failure: StructuredSessionOpenFailure }
|
|
| { kind: 'superseded' }
|
|
|
|
type Located = OrchestrationPartyLocationResult | StructuredSessionOpenFailure
|
|
export type StructuredSessionOpenDeps = {
|
|
locate: (address: string, messageIds: readonly string[]) => Promise<Located>
|
|
/** A sender's lookup that may also open a closed worker's conversation; older hosts lack it. */
|
|
open?: (address: string, messageIds: readonly string[]) => Promise<Located>
|
|
tabs: (target: StructuredSessionOpenTarget) => readonly StructuredSessionOpenTab[]
|
|
refresh: (target: StructuredSessionOpenTarget) => Promise<void>
|
|
activate: (
|
|
tab: StructuredSessionOpenTab,
|
|
target: StructuredSessionOpenTarget
|
|
) => boolean | Promise<boolean>
|
|
reveal: (
|
|
target: StructuredSessionOpenTarget
|
|
) => Promise<StructuredSessionOpenTarget | StructuredSessionOpenFailure>
|
|
current?: () => boolean
|
|
}
|
|
|
|
/** Only explicit unsupported responses prove that a fallback cannot duplicate an applied operation. */
|
|
export function structuredSessionOpenFailure(error: unknown): StructuredSessionOpenFailure {
|
|
const code = error !== null && typeof error === 'object' && 'code' in error ? error.code : null
|
|
if (
|
|
code === 'invalid_argument' ||
|
|
code === 'method_not_found' ||
|
|
code === 'forbidden' ||
|
|
code === 'structured_agent_session_unsupported' ||
|
|
code === 'runtime_compat_block'
|
|
) {
|
|
return { reason: 'unsupported', beforeEffects: true, code }
|
|
}
|
|
if (code === 'agent_session_workspace_removed') {
|
|
const details = readStructuredSessionWorkspaceRemovedDetails(
|
|
error !== null && typeof error === 'object' && 'details' in error ? error.details : undefined
|
|
)
|
|
return { reason: 'workspace-missing', beforeEffects: true, ...details }
|
|
}
|
|
if (code === 'agent_session_identity_required') {
|
|
return { reason: 'gone', beforeEffects: true }
|
|
}
|
|
return { reason: 'unreachable', beforeEffects: false }
|
|
}
|
|
|
|
export async function resolveStructuredSessionOpenSource(
|
|
source: StructuredSessionOpenSource,
|
|
locate: StructuredSessionOpenDeps['locate']
|
|
): Promise<StructuredSessionOpenTarget | StructuredSessionOpenResult> {
|
|
const seed =
|
|
source.kind === 'history'
|
|
? {
|
|
sessionId: source.structuredSession.sessionId,
|
|
worktreeId: source.structuredSession.workspaceId,
|
|
agent: source.agent
|
|
}
|
|
: source.kind === 'notification'
|
|
? source
|
|
: source.fallback
|
|
const address =
|
|
source.kind === 'sender' ? source.party.address : `orca_session_id:${seed?.sessionId}`
|
|
let found: Located
|
|
try {
|
|
found = await locate(address, source.kind === 'sender' ? source.messageIds : [])
|
|
} catch (error) {
|
|
found = structuredSessionOpenFailure(error)
|
|
}
|
|
if ('reason' in found) {
|
|
if (source.kind !== 'sender' && found.reason === 'unsupported' && seed) {
|
|
return seed
|
|
}
|
|
return { kind: 'failed', failure: found }
|
|
}
|
|
if (!found.location) {
|
|
return {
|
|
kind: 'failed',
|
|
failure: {
|
|
reason: found.lost ? 'gone' : 'unknown',
|
|
beforeEffects: true,
|
|
...(found.lost === 'terminal' ? { surface: 'terminal' as const } : {})
|
|
}
|
|
}
|
|
}
|
|
if (found.location.kind === 'terminal') {
|
|
return { kind: 'terminal', handle: found.location.handle }
|
|
}
|
|
if (found.location.kind !== 'chat') {
|
|
return { kind: 'failed', failure: { reason: 'unsupported', beforeEffects: true } }
|
|
}
|
|
return {
|
|
sessionId: found.location.sessionId,
|
|
worktreeId: found.location.worktreeId,
|
|
...(source.kind !== 'sender' ? { agent: source.agent } : {})
|
|
}
|
|
}
|
|
|
|
/** One policy for desktop and phone: refresh is advisory; reveal repairs missing publication. */
|
|
export async function openStructuredAgentSession(
|
|
source: StructuredSessionOpenSource,
|
|
deps: StructuredSessionOpenDeps
|
|
): Promise<StructuredSessionOpenResult> {
|
|
const current = () => deps.current?.() !== false
|
|
const seed =
|
|
source.kind === 'history'
|
|
? {
|
|
sessionId: source.structuredSession.sessionId,
|
|
worktreeId: source.structuredSession.workspaceId,
|
|
agent: source.agent
|
|
}
|
|
: null
|
|
const known = async (target: StructuredSessionOpenTarget) => {
|
|
if (!current()) {
|
|
return null
|
|
}
|
|
const tab = deps.tabs(target).find((row) => row.sessionId === target.sessionId)
|
|
if (!tab || !(await deps.activate(tab, target)) || !current()) {
|
|
return null
|
|
}
|
|
return { kind: 'opened' as const, target: { ...target, agent: tab.agent ?? target.agent }, tab }
|
|
}
|
|
const refreshKnown = async (target: StructuredSessionOpenTarget) => {
|
|
try {
|
|
await deps.refresh(target)
|
|
} catch {
|
|
/* Inventory reads are advisory. */
|
|
}
|
|
}
|
|
if (seed) {
|
|
try {
|
|
const direct = await known(seed)
|
|
if (direct) {
|
|
return direct
|
|
}
|
|
await refreshKnown(seed)
|
|
const refreshed = await known(seed)
|
|
if (refreshed) {
|
|
return refreshed
|
|
}
|
|
} catch (error) {
|
|
return { kind: 'failed', failure: structuredSessionOpenFailure(error) }
|
|
}
|
|
}
|
|
const resolved = await resolveStructuredSessionOpenSource(
|
|
source,
|
|
source.kind === 'sender' && deps.open ? openingOrLocating(deps.open, deps.locate) : deps.locate
|
|
)
|
|
if (!current()) {
|
|
return { kind: 'superseded' }
|
|
}
|
|
if ('kind' in resolved) {
|
|
if (
|
|
source.kind === 'sender' &&
|
|
resolved.kind === 'failed' &&
|
|
(resolved.failure.code === 'method_not_found' || resolved.failure.code === 'forbidden')
|
|
) {
|
|
const root = source.party.orcaSessionId
|
|
if (root) {
|
|
const fallback = source.fallback
|
|
if (fallback?.sessionId === root) {
|
|
try {
|
|
if (!deps.tabs(fallback).some((row) => row.sessionId === root)) {
|
|
await refreshKnown(fallback)
|
|
}
|
|
const opened = await known(fallback)
|
|
if (!current()) {
|
|
return { kind: 'superseded' }
|
|
}
|
|
if (opened) {
|
|
return opened
|
|
}
|
|
} catch (error) {
|
|
return { kind: 'failed', failure: structuredSessionOpenFailure(error) }
|
|
}
|
|
}
|
|
} else {
|
|
const handle = source.party.terminalHandle
|
|
if (handle && !handle.startsWith('dispatch:') && !handle.startsWith('run:')) {
|
|
return { kind: 'terminal', handle }
|
|
}
|
|
}
|
|
}
|
|
return resolved
|
|
}
|
|
let target: StructuredSessionOpenTarget = resolved
|
|
const activate = async () => {
|
|
if (!current()) {
|
|
return null
|
|
}
|
|
const tab = deps.tabs(target).find((row) => row.sessionId === target.sessionId)
|
|
return tab && (await deps.activate(tab, target)) ? tab : null
|
|
}
|
|
const refresh = async () => {
|
|
try {
|
|
await deps.refresh(target)
|
|
} catch {
|
|
/* Reveal can repair a failed inventory read. */
|
|
}
|
|
}
|
|
let revealed = false
|
|
const failure = (value: StructuredSessionOpenFailure): StructuredSessionOpenFailure => ({
|
|
...value,
|
|
...(value.reason === 'workspace-missing'
|
|
? {
|
|
workspaceKind:
|
|
value.workspaceKind ??
|
|
(workspaceKindForWorktreeId(target.worktreeId) === 'folder' ? 'folder' : 'git-worktree')
|
|
}
|
|
: {}),
|
|
beforeEffects: value.beforeEffects && !revealed
|
|
})
|
|
try {
|
|
let tab = await activate()
|
|
if (!tab) {
|
|
if (!seed || seed.sessionId !== target.sessionId || seed.worktreeId !== target.worktreeId) {
|
|
await refresh()
|
|
}
|
|
tab = await activate()
|
|
if (!tab && current()) {
|
|
const reply = await deps.reveal(target)
|
|
if (!current()) {
|
|
return { kind: 'superseded' }
|
|
}
|
|
if ('reason' in reply) {
|
|
return { kind: 'failed', failure: failure(reply) }
|
|
}
|
|
revealed = true
|
|
target = reply
|
|
await refresh()
|
|
tab = await activate()
|
|
}
|
|
}
|
|
if (!current()) {
|
|
return { kind: 'superseded' }
|
|
}
|
|
return tab
|
|
? { kind: 'opened', target: { ...target, agent: tab.agent ?? target.agent }, tab }
|
|
: { kind: 'failed', failure: { reason: 'unreachable', beforeEffects: false } }
|
|
} catch (error) {
|
|
return current()
|
|
? { kind: 'failed', failure: failure(structuredSessionOpenFailure(error)) }
|
|
: { kind: 'superseded' }
|
|
}
|
|
}
|
|
|
|
/** Older hosts refuse the opening call, so they keep answering the plain lookup. */
|
|
function openingOrLocating(
|
|
open: NonNullable<StructuredSessionOpenDeps['open']>,
|
|
locate: StructuredSessionOpenDeps['locate']
|
|
): StructuredSessionOpenDeps['locate'] {
|
|
return async (address, messageIds) => {
|
|
let opened: Located
|
|
try {
|
|
opened = await open(address, messageIds)
|
|
} catch (error) {
|
|
opened = structuredSessionOpenFailure(error)
|
|
}
|
|
return 'reason' in opened && (opened.code === 'method_not_found' || opened.code === 'forbidden')
|
|
? locate(address, messageIds)
|
|
: opened
|
|
}
|
|
}
|