mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-10-26 16:55:08 +00:00
refactor(session-controller): remove unused inspection facade
This commit is contained in:
1 parent
d6d51be4cb
commit
0c23ad233d
5 files changed
+8
-147
No files matched your search
@@ -9,7 +9,6 @@ import { installModelSelection } from '@deepseek-ai/dsh-agent'
|
||||
import type {} from '@deepseek-ai/dsh-agent-preset-registry'
|
||||
import { brandString } from '@deepseek-ai/dsh-brand'
|
||||
import type { Session, SessionId } from '@deepseek-ai/dsh-session'
|
||||
import type { SessionInspection } from '@deepseek-ai/dsh-session-persistence'
|
||||
import { SessionQueryError, type SessionObservation } from '@deepseek-ai/dsh-session-query'
|
||||
import { RemoteError, remoteErrorOf } from '@deepseek-ai/dsh-typert-protocol'
|
||||
import type {} from '@deepseek-ai/dsh-typert-registry'
|
||||
@@ -123,40 +122,6 @@ export function apiSessionSubagentOwnershipError(sessionId: SessionId): ApiSessi
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Inspect one cold Session without repairing, resuming, or publishing it.
|
||||
* @param ctx - Host context carrying Session persistence.
|
||||
* @param sessionId - durable Session identity.
|
||||
* @param signal - optional cancellation for persistence reads.
|
||||
* @returns the persisted header and complete event prefix.
|
||||
*/
|
||||
export async function inspectApiSession(
|
||||
ctx: Context,
|
||||
sessionId: SessionId,
|
||||
signal?: AbortSignal,
|
||||
): Promise<SessionInspection> {
|
||||
try {
|
||||
using observation = await ctx.sessionQuery.observeSession(sessionId, {
|
||||
...(signal === undefined ? {} : { signal }),
|
||||
projectionMode: 'none',
|
||||
})
|
||||
if (observation.header.cwd === undefined) {
|
||||
throw new ApiSessionNotFound(`session "${sessionId}" not found`)
|
||||
}
|
||||
return {
|
||||
meta: observation.header,
|
||||
inheritedEventCount: observation.inheritedEventCount,
|
||||
events: [...observation.events],
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof SessionQueryError
|
||||
&& error.code === 'SESSION_QUERY_SESSION_NOT_FOUND') {
|
||||
throw new ApiSessionNotFound(`session "${sessionId}" not found`)
|
||||
}
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/** Owns every operation that may create, resume, or configure a Web Agent. */
|
||||
export class ApiSessionAgentController {
|
||||
private readonly resumes = new Map<SessionId, Promise<Agent>>()
|
||||
|
||||
@@ -31,7 +31,6 @@ import {
|
||||
ApiSessionSubagentOwnership,
|
||||
apiSessionSubagentOwnershipError,
|
||||
hasApiSessionSubagentOwner,
|
||||
inspectApiSession,
|
||||
type ApiSessionCreated,
|
||||
} from './agent.ts'
|
||||
import type {
|
||||
@@ -54,12 +53,6 @@ import type {
|
||||
SessionRequestId,
|
||||
} from './types.ts'
|
||||
|
||||
interface SessionReadState {
|
||||
readonly id: SessionId
|
||||
readonly header: SessionHeader
|
||||
readonly events: readonly SessionEvent[]
|
||||
}
|
||||
|
||||
type PromptContentCandidate =
|
||||
| SessionPromptRequest['content'][number]
|
||||
| Extract<SessionUpdateQueueRequest['action'], { readonly kind: 'edit' }>['content'][number]
|
||||
@@ -371,11 +364,16 @@ export class SessionCommandController {
|
||||
* @returns the durable attachment reference and base64-encoded bytes.
|
||||
*/
|
||||
async attachment(request: SessionAttachmentRequest): Promise<SessionAttachmentValue> {
|
||||
let source: SessionReadState
|
||||
let ref: ImageAttachmentRef | undefined
|
||||
try {
|
||||
source = await this.readSessionState(request.sessionId)
|
||||
using observation = await this.ctx.sessionQuery.observeSession(request.sessionId, { projectionMode: 'none' })
|
||||
if (observation.source === 'prepared' && observation.header.cwd === undefined) {
|
||||
throw new ApiSessionNotFound(`session "${request.sessionId}" not found`)
|
||||
}
|
||||
ref = referencedImage(observation.events, String(request.attachmentId))
|
||||
} catch (error) {
|
||||
if (error instanceof ApiSessionNotFound) {
|
||||
if (error instanceof ApiSessionNotFound
|
||||
|| (error instanceof SessionQueryError && error.code === 'SESSION_QUERY_SESSION_NOT_FOUND')) {
|
||||
throw new RemoteError('session/not-found', error.message, { sessionId: request.sessionId })
|
||||
}
|
||||
throw new RemoteError(
|
||||
@@ -384,7 +382,6 @@ export class SessionCommandController {
|
||||
{},
|
||||
)
|
||||
}
|
||||
const ref = referencedImage(source.events, String(request.attachmentId))
|
||||
if (ref === undefined) {
|
||||
throw new RemoteError(
|
||||
'session/attachment-invalid',
|
||||
@@ -533,16 +530,6 @@ export class SessionCommandController {
|
||||
throw new RemoteError('gateway/internal', `failed to create session: ${String(error)}`, {})
|
||||
}
|
||||
|
||||
private async readSessionState(sessionId: SessionId): Promise<SessionReadState> {
|
||||
const attached = this.ctx.sessions.get(sessionId)
|
||||
if (attached !== undefined) {
|
||||
// oxlint-disable-next-line typescript/no-deprecated -- Existing Session history read; migration deferred.
|
||||
return { id: attached.id, header: attached.header, events: attached.snapshotEvents() }
|
||||
}
|
||||
const inspected = await inspectApiSession(this.ctx, sessionId)
|
||||
return { id: inspected.meta.id, header: inspected.meta, events: inspected.events }
|
||||
}
|
||||
|
||||
private async forkWorkspace(source: SessionHeader): Promise<Workspace | undefined> {
|
||||
const workspaces = this.ctx.workspaceRegistry.list()
|
||||
const direct = workspaces.find(workspace => workspace.sessionIds.includes(source.id))
|
||||
|
||||
@@ -10,7 +10,6 @@ import { errorChain, ReasoningEffortId, type MessageSource } from '@deepseek-ai/
|
||||
import type {} from '@deepseek-ai/dsh-client-file-upload'
|
||||
import { canOpenNativePath, nativeFileManager, nativeFileApplications, openNativeFileApplication, openNativeAssociatedPath, revealNativePath } from '@deepseek-ai/dsh-native-command'
|
||||
import type { SessionId } from '@deepseek-ai/dsh-session'
|
||||
import type { SessionInspection } from '@deepseek-ai/dsh-session-persistence'
|
||||
import type {} from '@deepseek-ai/dsh-session-projection-cache'
|
||||
import { SessionQueryError, type SessionObservation } from '@deepseek-ai/dsh-session-query'
|
||||
import { Remote, RemoteError, TypertRemoteService, principalOf } from '@deepseek-ai/dsh-typert-protocol'
|
||||
@@ -19,7 +18,6 @@ import { assertNever } from '@deepseek-ai/dsh-util-values'
|
||||
import type {} from '@deepseek-ai/dsh-api-remote-access'
|
||||
import {
|
||||
ApiSessionAgentController,
|
||||
inspectApiSession,
|
||||
type ApiSessionAgentResult,
|
||||
} from './agent.ts'
|
||||
import { SessionCommandController, hasPromptContent } from './commands.ts'
|
||||
@@ -240,28 +238,6 @@ export class SessionController extends TypertRemoteService {
|
||||
return this.agents.resolveAgent(sessionId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Inspect one attached or persisted Session without activating its Agent.
|
||||
* @param sessionId - durable Session identity.
|
||||
* @param signal - optional caller cancellation for persistence reads.
|
||||
* @returns the current attached state or persisted header and event prefix.
|
||||
*/
|
||||
inspect(
|
||||
sessionId: SessionId,
|
||||
signal?: AbortSignal,
|
||||
): Promise<SessionInspection> {
|
||||
const attached = this.ctx.sessions.get(sessionId)
|
||||
if (attached !== undefined) {
|
||||
return Promise.resolve({
|
||||
meta: attached.header,
|
||||
inheritedEventCount: attached.inheritedEventCount,
|
||||
// oxlint-disable-next-line typescript/no-deprecated -- Existing Session history read; migration deferred.
|
||||
events: attached.snapshotEvents(),
|
||||
})
|
||||
}
|
||||
return inspectApiSession(this.ctx, sessionId, signal)
|
||||
}
|
||||
|
||||
/**
|
||||
* Read all visible Session rows without resuming an Agent.
|
||||
* @param _request - reserved empty list request.
|
||||
@@ -614,5 +590,4 @@ export class SessionController extends TypertRemoteService {
|
||||
|
||||
}
|
||||
|
||||
export { buildModelCatalog }
|
||||
export default SessionController
|
||||
@@ -16,7 +16,6 @@ import {
|
||||
ApiSessionAgentController,
|
||||
ApiSessionCwdConflict,
|
||||
ApiSessionNotFound,
|
||||
inspectApiSession,
|
||||
} from '../src/agent.ts'
|
||||
import { installSessionReadTestServices, testSessionPersistence } from './test-remote.ts'
|
||||
|
||||
@@ -84,60 +83,7 @@ describe('ApiSession identity failures', () => {
|
||||
.toContain('belongs to "/existing"')
|
||||
})
|
||||
|
||||
it('maps absent and cwd-less point observations to not found', async () => {
|
||||
const ctx = new Context()
|
||||
roots.push(ctx)
|
||||
await ctx.plugin(SessionStore)
|
||||
installSessionReadTestServices(ctx)
|
||||
await expect(inspectApiSession(ctx, SessionId('missing')))
|
||||
.rejects.toBeInstanceOf(ApiSessionNotFound)
|
||||
|
||||
const inspect = vi.fn(() => Promise.resolve(undefined))
|
||||
const stat = vi.fn(() => Promise.resolve(undefined))
|
||||
const disposeMissing = providePersistence(ctx, {
|
||||
list: () => Promise.resolve([]),
|
||||
stat,
|
||||
inspect,
|
||||
})
|
||||
await expect(inspectApiSession(ctx, SessionId('missing'))).rejects.toBeInstanceOf(ApiSessionNotFound)
|
||||
// Absence is decided by the stat preflight; the log itself is never opened.
|
||||
expect(stat).toHaveBeenCalledOnce()
|
||||
expect(inspect).not.toHaveBeenCalled()
|
||||
disposeMissing()
|
||||
|
||||
const listed = header('cwd-less-catalog', null)
|
||||
const disposeListed = providePersistence(ctx, {
|
||||
list: () => Promise.resolve([listed]),
|
||||
inspect: () => Promise.resolve({ meta: listed, events: [] }),
|
||||
})
|
||||
await expect(inspectApiSession(ctx, listed.id)).rejects.toBeInstanceOf(ApiSessionNotFound)
|
||||
disposeListed()
|
||||
|
||||
const catalog = header('cwd-less-inspect')
|
||||
const inspected = header('cwd-less-inspect', null)
|
||||
providePersistence(ctx, {
|
||||
list: () => Promise.resolve([catalog]),
|
||||
inspect: () => Promise.resolve({ meta: inspected, events: [] }),
|
||||
})
|
||||
await expect(inspectApiSession(ctx, catalog.id)).rejects.toBeInstanceOf(ApiSessionNotFound)
|
||||
})
|
||||
|
||||
it('forwards an explicit inspection signal', async () => {
|
||||
const ctx = new Context()
|
||||
roots.push(ctx)
|
||||
await ctx.plugin(SessionStore)
|
||||
installSessionReadTestServices(ctx)
|
||||
const meta = header('signalled-inspection')
|
||||
const inspect = vi.fn(() => Promise.resolve({ meta, inheritedEventCount: SessionLogOffset(0), events: [] }))
|
||||
providePersistence(ctx, {
|
||||
list: () => Promise.resolve([meta]),
|
||||
inspect,
|
||||
})
|
||||
const signal = new AbortController().signal
|
||||
|
||||
await expect(inspectApiSession(ctx, meta.id, signal)).resolves.toEqual({ meta, inheritedEventCount: SessionLogOffset(0), events: [] })
|
||||
expect(inspect).toHaveBeenCalledWith(meta.id, signal)
|
||||
})
|
||||
})
|
||||
|
||||
describe('ApiSession Agent lookup and recovery', () => {
|
||||
|
||||
@@ -63,12 +63,6 @@ describe('SessionController facade', () => {
|
||||
ctx.on('api-session/error', failure)
|
||||
ctx.on('api-session/activity', activity)
|
||||
|
||||
await expect(controller.inspect(sessionId)).resolves.toEqual({
|
||||
meta: header,
|
||||
inheritedEventCount: SessionLogOffset(0),
|
||||
events,
|
||||
})
|
||||
expect(inspect).toHaveBeenCalledOnce()
|
||||
|
||||
const session = ctx.sessions.create(sessionId, { meta: header })
|
||||
const agent = {
|
||||
@@ -91,12 +85,6 @@ describe('SessionController facade', () => {
|
||||
await expect(resolveUploadAgent(sessionId)).rejects.toBe(activationError)
|
||||
|
||||
await expect(controller.resolveAgent(sessionId)).resolves.toEqual({ agent })
|
||||
await expect(controller.inspect(sessionId)).resolves.toEqual({
|
||||
meta: header,
|
||||
inheritedEventCount: SessionLogOffset(0),
|
||||
events,
|
||||
})
|
||||
expect(inspect).toHaveBeenCalledOnce()
|
||||
ctx.emit('agent/status', { agent, status: 'running' })
|
||||
ctx.emit('agent/error', { agent, turn: 1, step: 0, error: new Error('fixture failure') })
|
||||
session.append('user/message', createUserMessage({
|
||||
|
||||
Reference in new issue
Block a user