Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions config/scripts/journal-replay-retention-benchmark.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@ const identity = {
workspaceId: 'fixture',
hostId: 'local',
agent: 'codex',
providerHandle: { kind: 'codex', threadId: 'thread' }
providerHandle: { transport: 'codex-app-server', agent: 'codex', nativeId: 'thread' }
}
// The baseline predates the neutral handle and takes its journal identity in the typed form.
const baselineIdentity = { ...identity, providerHandle: { kind: 'codex', threadId: 'thread' } }
const fixture = await mkdtemp(join(tmpdir(), 'orca-journal-replay-bench-'))
// Released in `finally`, newest first: an open SQLite handle blocks the fixture's removal on Windows.
const releases = []
Expand Down Expand Up @@ -75,7 +77,10 @@ async function openArm(arm) {
let journal
let database
if (arm === 'baseline') {
journal = await implementation.openAgentSessionJournal({ identity, journalDir: stateDirectory })
journal = await implementation.openAgentSessionJournal({
identity: baselineIdentity,
journalDir: stateDirectory
})
} else {
database = implementation.JournalHostDatabase.open(stateDirectory)
releases.push(() => database.close())
Expand Down
10 changes: 9 additions & 1 deletion src/main/ai-vault/structured-session-ownership.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ import {
assertLegacyAiVaultResumeCommandAllowed,
projectStructuredAiVaultSessions
} from './structured-session-ownership'
import {
claudeProviderHandle,
codexProviderHandle
} from '../../shared/agent-session-provider-handle-encoding'

const PROVIDER_SESSION = '019fd532-7c11-7a90-b6de-4e1a2c3d5f60'

Expand Down Expand Up @@ -93,6 +97,7 @@ function installOwnership(overrides: Partial<StructuredProviderSessionOwnership>
...overrides
}
const record = agentSessionRecordFixture(ownership.lease)
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the ownership read touches only `deps.store.listRecords`; the rest of the host is never reached.
setStructuredAgentSessionHost({
deps: {
store: {
Expand All @@ -105,7 +110,10 @@ function installOwnership(overrides: Partial<StructuredProviderSessionOwnership>
providerHandleChain: [
{
...record.providerHandleChain[0]!,
handle: { provider: ownership.provider, threadId: ownership.providerSessionId }
handle:
ownership.provider === 'claude'
? claudeProviderHandle(ownership.providerSessionId, null)
: codexProviderHandle(ownership.providerSessionId)
}
],
lease: { ...ownership.lease, sessionId: ownership.sessionId }
Expand Down
3 changes: 2 additions & 1 deletion src/main/claude/claude-api-retry-idle-sweep.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
import { createClaudeJournalTranslator } from './claude-structured-journal-translation'
import { openTestJournalHostDatabase } from '../native-chat/agent-session-journal/journal-host-database-test-support'
import { createStructuredAgentSessionLogger } from '../native-chat/agent-session-wire/structured-agent-session-logger'
import { codexProviderHandle } from '../../shared/agent-session-provider-handle-encoding'

const SWEEP_MS = 5
const RETRY_GAP_MS = 10 * 60_000
Expand Down Expand Up @@ -63,7 +64,7 @@ beforeEach(async () => {
acquisitionGeneration: 'generation-1',
link: {
linkId: `link-${fence}`,
handle: { provider: 'codex', threadId: THREAD },
handle: codexProviderHandle(THREAD),
origin: 'created',
mintedAtFence: fence,
observedAt: NOW
Expand Down
3 changes: 2 additions & 1 deletion src/main/claude/claude-api-retry-row.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ import { unhandledProviderFrameJournalItem } from '../native-chat/agent-session-
import { createClaudeJournalTranslator } from './claude-structured-journal-translation'
import { openTestJournalHostDatabase } from '../native-chat/agent-session-journal/journal-host-database-test-support'
import { testEventSinkLogging } from '../native-chat/agent-session-wire/structured-agent-session-logger-test-support'
import { claudeProviderHandle } from '../../shared/agent-session-provider-handle-encoding'

const IDENTITY: AgentSessionJournalIdentity = {
sessionId: 'session-1',
workspaceId: 'workspace-1',
hostId: 'host-1',
agent: 'claude',
providerHandle: { kind: 'claude', sessionId: 'provider-1', leafUuid: 'leaf-1' }
providerHandle: claudeProviderHandle('provider-1', 'leaf-1')
}

/** A frame as Claude Code sends it while it retries a refused request. */
Expand Down
3 changes: 2 additions & 1 deletion src/main/claude/claude-context-usage-restart.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { readAgentJournalTurn } from '../../shared/agent-session-turn-record'
import { bindClaudeContextUsageCapture } from './claude-context-usage'
import { createClaudeJournalTranslator } from './claude-structured-journal-translation'
import { testEventSinkLogging } from '../native-chat/agent-session-wire/structured-agent-session-logger-test-support'
import { claudeProviderHandle } from '../../shared/agent-session-provider-handle-encoding'

const journals = createTrackedJournalOpener()
let root: string
Expand Down Expand Up @@ -104,7 +105,7 @@ async function openJournal(): Promise<AgentSessionJournal> {
workspaceId: 'workspace-1',
hostId: 'local',
agent: 'claude',
providerHandle: { kind: 'claude', sessionId: 'claude-session', leafUuid: null }
providerHandle: claudeProviderHandle('claude-session', null)
},
now: () => 9_000,
stateDirectory: join(root, 'orca-session')
Expand Down
3 changes: 2 additions & 1 deletion src/main/claude/claude-context-usage-unloaded-turn.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
} from './claude-context-usage-test-support'
import { createClaudeJournalTranslator } from './claude-structured-journal-translation'
import { testEventSinkLogging } from '../native-chat/agent-session-wire/structured-agent-session-logger-test-support'
import { claudeProviderHandle } from '../../shared/agent-session-provider-handle-encoding'

const SESSION = 'orca-session'
const journals = createTrackedJournalOpener()
Expand All @@ -49,7 +50,7 @@ async function openJournal(): Promise<AgentSessionJournal> {
workspaceId: 'workspace-1',
hostId: 'local',
agent: 'claude',
providerHandle: { kind: 'claude', sessionId: 'claude-session', leafUuid: null }
providerHandle: claudeProviderHandle('claude-session', null)
},
now: () => 9_000,
stateDirectory: join(root, SESSION)
Expand Down
3 changes: 2 additions & 1 deletion src/main/claude/claude-informational-row.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ import { createDeferredStructuredAgentSessionEventSink } from '../native-chat/ag
import { createClaudeJournalTranslator } from './claude-structured-journal-translation'
import { openTestJournalHostDatabase } from '../native-chat/agent-session-journal/journal-host-database-test-support'
import { testEventSinkLogging } from '../native-chat/agent-session-wire/structured-agent-session-logger-test-support'
import { claudeProviderHandle } from '../../shared/agent-session-provider-handle-encoding'

const IDENTITY: AgentSessionJournalIdentity = {
sessionId: 'session-1',
workspaceId: 'workspace-1',
hostId: 'host-1',
agent: 'claude',
providerHandle: { kind: 'claude', sessionId: 'provider-1', leafUuid: 'leaf-1' }
providerHandle: claudeProviderHandle('provider-1', 'leaf-1')
}

/** A frame as Claude Code 2.1.280 sends it: a transcript note at a render level. */
Expand Down
3 changes: 2 additions & 1 deletion src/main/claude/claude-stream-json-connection.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import type { ClaudeSession } from './claude-structured-session-state'
import { CLAUDE_STRUCTURED_BASE_OPTIONS } from './claude-structured-launch-resolution'
import { openTestJournalHostDatabase } from '../native-chat/agent-session-journal/journal-host-database-test-support'
import { testEventSinkLogging } from '../native-chat/agent-session-wire/structured-agent-session-logger-test-support'
import { claudeProviderHandle } from '../../shared/agent-session-provider-handle-encoding'

// These drive the real SDK against the scripted fake CLI, so every assertion is
// about the environment, argv and frames a real child actually saw.
Expand Down Expand Up @@ -380,7 +381,7 @@ describe('Claude stream-json connection', () => {
workspaceId: 'workspace-1',
hostId: 'host-1',
agent: 'claude',
providerHandle: { kind: 'claude', sessionId: SESSION_ID, leafUuid: 'leaf-1' }
providerHandle: claudeProviderHandle(SESSION_ID, 'leaf-1')
},
database: openTestJournalHostDatabase(join(scenario.cwd, 'journal')),
now: () => 1_700_000_000_000,
Expand Down
10 changes: 5 additions & 5 deletions src/main/claude/claude-structured-acquisition-launch.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { claudeProviderHandle } from '../../shared/agent-session-provider-handle-encoding'
import {
AgentSessionAcquisitionExitUnprovenError,
AgentSessionPreSpawnError,
Expand Down Expand Up @@ -72,11 +73,10 @@ export async function resolveClaudeAcquisitionLaunch(args: {
const launchIdentity = resumeSession
? {
...input.identity,
providerHandle: {
kind: 'claude' as const,
sessionId: resumeSession.providerSessionId,
leafUuid: resumeSession.turnEndLeafUuid
}
providerHandle: claudeProviderHandle(
resumeSession.providerSessionId,
resumeSession.turnEndLeafUuid
)
}
: input.identity
const launch = await deps
Expand Down
6 changes: 3 additions & 3 deletions src/main/claude/claude-structured-auth-parity.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
fakeClaude,
identityFor
} from './claude-structured-session-test-support'
import { claudeProviderHandle } from '../../shared/agent-session-provider-handle-encoding'

const SESSION_ID = 'orca-session-auth'
const IDENTITY = { sessionId: SESSION_ID } as Parameters<
Expand Down Expand Up @@ -60,11 +61,10 @@ function realResolverAdapter(
claude: ReturnType<typeof fakeClaude>,
authSwitchSettleTimeoutMs: number
): ClaudeStructuredSessionAdapter {
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the resolver reads only the chain head's handle from this partial record.
const resumable = {
...record(),
providerHandleChain: [
{ handle: { provider: 'claude', sessionId: PROVIDER_SESSION_ID, leafUuid: null } }
]
providerHandleChain: [{ handle: claudeProviderHandle(PROVIDER_SESSION_ID, null) }]
} as unknown as AgentSessionRecord
return new ClaudeStructuredSessionAdapter({
resolveLaunch: createClaudeStructuredLaunchResolver({
Expand Down
3 changes: 2 additions & 1 deletion src/main/claude/claude-structured-history-window.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
claudeProviderHistoryWindowFromJsonl,
resolveClaudeProviderHistoryWindow
} from './claude-structured-history-window'
import { claudeProviderHandle } from '../../shared/agent-session-provider-handle-encoding'

const PROVIDER_SESSION = 'provider-1'
const ORCA_SESSION = 'session-1'
Expand Down Expand Up @@ -82,7 +83,7 @@ describe('claudeProviderHistoryWindowFromJsonl', () => {
workspaceId: 'workspace-1',
hostId: 'host-1',
agent: 'claude',
providerHandle: { kind: 'claude', sessionId: PROVIDER_SESSION, leafUuid: 'anchor' }
providerHandle: claudeProviderHandle(PROVIDER_SESSION, 'anchor')
},
accountHomePath: accountHome,
hasLiveSession: false
Expand Down
16 changes: 12 additions & 4 deletions src/main/claude/claude-structured-history-window.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@

import { join } from 'node:path'
import type { AgentSessionJournalIdentity } from '../../shared/agent-session-journal-types'
import {
CLAUDE_STRUCTURED_HANDLE_NAMESPACE,
claudeProviderHandleLeafUuid,
isAgentSessionProviderHandleInNamespace
} from '../../shared/agent-session-provider-handle-encoding'
import { resolveSessionFilePath } from '../native-chat/session-file-resolver'
import type {
ProviderHistoryItem,
Expand Down Expand Up @@ -242,19 +247,22 @@ export async function resolveClaudeProviderHistoryWindow(input: {
hasLiveSession: boolean
}): Promise<ProviderHistoryWindow | null> {
const handle = input.identity.providerHandle
if (handle.kind !== 'claude') {
if (
!handle ||
!isAgentSessionProviderHandleInNamespace(handle, CLAUDE_STRUCTURED_HANDLE_NAMESPACE)
) {
return null
}
const transcriptPath = await resolveSessionFilePath('claude', handle.sessionId, {
const transcriptPath = await resolveSessionFilePath('claude', handle.nativeId, {
claudeProjectsDir: join(input.accountHomePath, 'projects')
})
if (!transcriptPath) {
return null
}
return readClaudeProviderHistoryWindow({
transcriptPath,
providerSessionId: handle.sessionId,
previousLeafUuid: handle.leafUuid,
providerSessionId: handle.nativeId,
previousLeafUuid: claudeProviderHandleLeafUuid(handle),
sessionId: input.identity.sessionId,
turnInFlight: input.hasLiveSession
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { readAgentJournalTurn } from '../../shared/agent-session-turn-record'
import { createClaudeJournalTranslator } from './claude-structured-journal-translation'
import { openTestJournalHostDatabase } from '../native-chat/agent-session-journal/journal-host-database-test-support'
import { testEventSinkLogging } from '../native-chat/agent-session-wire/structured-agent-session-logger-test-support'
import { claudeProviderHandle } from '../../shared/agent-session-provider-handle-encoding'

function sinkState() {
const items: { identity: AgentJournalItemIdentity; body: AgentJournalItemBody }[] = []
Expand Down Expand Up @@ -180,7 +181,7 @@ const JOURNAL_IDENTITY: AgentSessionJournalIdentity = {
workspaceId: 'workspace-1',
hostId: 'host-1',
agent: 'claude',
providerHandle: { kind: 'claude', sessionId: 'claude-session', leafUuid: 'leaf-1' }
providerHandle: claudeProviderHandle('claude-session', 'leaf-1')
}

let journalRoot = ''
Expand Down
26 changes: 11 additions & 15 deletions src/main/claude/claude-structured-launch-resolution.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
createClaudeStructuredLaunchResolver
} from './claude-structured-launch-resolution'
import { claudeStructuredPermissionModeForSettings } from './claude-structured-permission-mode'
import { claudeProviderHandle } from '../../shared/agent-session-provider-handle-encoding'

const SESSION_ID = 'orca-session-1'
const IDENTITY = { sessionId: SESSION_ID } as Parameters<
Expand All @@ -41,7 +42,7 @@ function record(overrides: Partial<AgentSessionRecord> = {}): AgentSessionRecord
function identityAt(leafUuid: string | null): typeof IDENTITY {
return {
...IDENTITY,
providerHandle: { kind: 'claude', sessionId: 'provider-current', leafUuid }
providerHandle: claudeProviderHandle('provider-current', leafUuid)
}
}

Expand Down Expand Up @@ -100,8 +101,9 @@ const WSL_ONLY_NORMALIZED: ClaudeManagedAccountGateSettings = {
}

const RESUMABLE = record({
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the resolver reads only each link's handle, so the link's other fields stay unset.
providerHandleChain: [
{ handle: { provider: 'claude', sessionId: 'provider-current', leafUuid: 'leaf-current' } }
{ handle: claudeProviderHandle('provider-current', 'leaf-current') }
] as AgentSessionRecord['providerHandleChain']
})

Expand Down Expand Up @@ -136,14 +138,11 @@ describe('claude structured launch resolution', () => {
it('resumes the durable chain head by session id and carries its leaf as bookkeeping', async () => {
const launch = await resolverFor(
record({
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the resolver reads only each link's handle, so the link's other fields stay unset.
providerHandleChain: [
{ handle: { provider: 'claude', sessionId: 'provider-old', leafUuid: 'leaf-old' } },
{ handle: claudeProviderHandle('provider-old', 'leaf-old') },
{
handle: {
provider: 'claude',
sessionId: 'provider-current',
leafUuid: 'leaf-current'
}
handle: claudeProviderHandle('provider-current', 'leaf-current')
}
] as AgentSessionRecord['providerHandleChain']
})
Expand Down Expand Up @@ -194,7 +193,7 @@ describe('claude structured launch resolution', () => {
resolve({
identity: {
...IDENTITY,
providerHandle: { kind: 'claude', sessionId: 'provider-other', leafUuid: 'leaf-current' }
providerHandle: claudeProviderHandle('provider-other', 'leaf-current')
}
})
).rejects.toThrow('durable resume identity changed before spawn')
Expand All @@ -203,13 +202,10 @@ describe('claude structured launch resolution', () => {
it('keeps session-only resume when the durable handle has no leaf', async () => {
const launch = await resolverFor(
record({
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the resolver reads only each link's handle, so the link's other fields stay unset.
providerHandleChain: [
{
handle: {
provider: 'claude',
sessionId: 'provider-current',
leafUuid: null
}
handle: claudeProviderHandle('provider-current', null)
}
] as AgentSessionRecord['providerHandleChain']
})
Expand All @@ -226,7 +222,7 @@ describe('claude structured launch resolution', () => {
record({
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the resolver reads only each link's handle.
providerHandleChain: [
{ handle: { provider: 'claude', sessionId: 'provider-current', leafUuid: null } }
{ handle: claudeProviderHandle('provider-current', null) }
] as AgentSessionRecord['providerHandleChain']
}),
undefined,
Expand Down
Loading
Loading