| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255 |
- /**
- * Caller identity, workspace authorization, and visible lineage projection.
- *
- * @module @deepseek-ai/dsh-tool-session-query/workspace-access
- */
- import type { Context } from 'cordis'
- import { HarnessError } from '@deepseek-ai/dsh-llm'
- import {
- SessionId,
- type SessionEvent,
- type SessionHeader,
- type SessionId as SessionIdValue,
- } from '@deepseek-ai/dsh-session'
- import type {
- SessionLineageNode,
- SessionRecord,
- } from '@deepseek-ai/dsh-session-query'
- import type { ToolRunContext } from '@deepseek-ai/dsh-tools'
- import { serviceBoundary } from './service-boundary.ts'
- interface Caller {
- readonly id: SessionIdValue
- readonly header: SessionHeader
- readonly events: readonly SessionEvent[]
- }
- interface TitleView {
- readonly text: string
- readonly unavailableCode?: string
- }
- interface CompleteTitleMap extends ReadonlyMap<SessionIdValue, TitleView> {
- get(id: SessionIdValue): TitleView
- }
- interface AuthorizedDescendant {
- readonly record: SessionRecord
- readonly descendants: Array<AuthorizedDescendant | null>
- }
- interface DescendantProjectionFrame {
- readonly node: SessionLineageNode
- readonly target: Array<AuthorizedDescendant | null>
- readonly next: DescendantProjectionFrame | undefined
- }
- interface DescendantVisit {
- readonly node: AuthorizedDescendant | null
- readonly depth: number
- readonly next: DescendantVisit | undefined
- }
- function callerOf(exec: ToolRunContext): Caller {
- const agent = exec.agent
- if (agent === undefined) {
- throw new HarnessError(
- 'session query tools require an agent-bound caller',
- 'SESSION_QUERY_TOOL_MISSING_AGENT',
- )
- }
- return {
- id: agent.session.id,
- header: agent.session.header,
- events: agent.session.events,
- }
- }
- function targetId(args: { readonly session_id?: string }, caller: Caller): SessionIdValue {
- return args.session_id === undefined ? caller.id : SessionId(args.session_id)
- }
- async function authorizeTarget(
- ctx: Context,
- caller: Caller,
- target: SessionIdValue,
- signal: AbortSignal,
- ): Promise<void> {
- if (target === caller.id) return
- const cwd = caller.header.cwd
- if (cwd === undefined) throw serviceBoundary.unauthorizedTarget()
- const records = await serviceBoundary.call(ctx, signal, 'target authorization', () =>
- ctx.sessionQuery.filterSessions([
- { kind: 'id', values: [target] },
- { kind: 'cwd', values: [cwd] },
- ], signal))
- if (records.length !== 1) throw serviceBoundary.unauthorizedTarget()
- }
- function recordAuthorized(record: SessionRecord, caller: Caller): boolean {
- return headerAuthorized(record.header, caller)
- }
- function headerAuthorized(header: SessionHeader, caller: Caller): boolean {
- if (header.id === caller.id) return header.cwd === caller.header.cwd
- return caller.header.cwd !== undefined && header.cwd === caller.header.cwd
- }
- function assertObservedTargetAuthorized(
- caller: Caller,
- target: SessionIdValue,
- observed: SessionHeader,
- ): void {
- if (observed.id !== target || !headerAuthorized(observed, caller)) {
- throw serviceBoundary.unauthorizedTarget()
- }
- }
- async function authorizeSessionIds(
- ctx: Context,
- caller: Caller,
- ids: readonly SessionIdValue[],
- signal: AbortSignal,
- ): Promise<ReadonlySet<SessionIdValue>> {
- const unique = [...new Set(ids)]
- const authorized = new Set<SessionIdValue>()
- if (unique.includes(caller.id)) authorized.add(caller.id)
- const cwd = caller.header.cwd
- const other = unique.filter(id => id !== caller.id)
- if (cwd === undefined || other.length === 0) return authorized
- const records = await serviceBoundary.call(ctx, signal, 'session-id authorization', () =>
- ctx.sessionQuery.filterSessions([
- { kind: 'id', values: other },
- { kind: 'cwd', values: [cwd] },
- ], signal))
- const requested = new Set(other)
- for (const record of records) {
- if (requested.has(record.header.id) && recordAuthorized(record, caller)) {
- authorized.add(record.header.id)
- }
- }
- return authorized
- }
- async function readTitles(
- ctx: Context,
- caller: Caller,
- ids: readonly SessionIdValue[],
- signal: AbortSignal,
- ): Promise<CompleteTitleMap> {
- const result = new Map<SessionIdValue, TitleView>()
- const observations = await serviceBoundary.call(ctx, signal, 'title observation', () =>
- ctx.sessionQuery.readTitleSnapshots(ids, signal))
- for (const observation of observations) {
- if (observation.status === 'rejected') {
- result.set(observation.sessionId, unavailableTitle(ctx, observation.reason))
- continue
- }
- assertObservedTargetAuthorized(caller, observation.sessionId, observation.value.session)
- result.set(observation.sessionId, { text: observation.value.title?.title ?? 'untitled' })
- }
- return result as CompleteTitleMap
- }
- async function readTitle(
- ctx: Context,
- caller: Caller,
- id: SessionIdValue,
- signal: AbortSignal,
- ): Promise<TitleView> {
- return (await readTitles(ctx, caller, [id], signal)).get(id)
- }
- function unavailableTitle(
- ctx: Context,
- error: unknown,
- ): TitleView {
- const sanitized = serviceBoundary.sanitizeError(ctx, 'title observation item', error)
- if (sanitized.code === 'SESSION_QUERY_TOOL_UNAUTHORIZED') throw sanitized
- return { text: 'untitled', unavailableCode: sanitized.code }
- }
- function authorizeDescendants(
- nodes: readonly SessionLineageNode[],
- caller: Caller,
- ): Array<AuthorizedDescendant | null> {
- const result: Array<AuthorizedDescendant | null> = []
- let pending: DescendantProjectionFrame | undefined
- for (const node of [...nodes].reverse()) {
- pending = { node, target: result, next: pending }
- }
- while (pending !== undefined) {
- const current = pending
- pending = current.next
- if (!recordAuthorized(current.node.session, caller)) {
- current.target.push(null)
- continue
- }
- const projected: AuthorizedDescendant = {
- record: current.node.session,
- descendants: [],
- }
- current.target.push(projected)
- for (const child of [...current.node.descendants].reverse()) {
- pending = {
- node: child,
- target: projected.descendants,
- next: pending,
- }
- }
- }
- return result
- }
- function * visitDescendants(
- nodes: readonly (AuthorizedDescendant | null)[],
- ): Generator<DescendantVisit> {
- let pending: DescendantVisit | undefined
- for (const node of [...nodes].reverse()) {
- pending = { node, depth: 0, next: pending }
- }
- while (pending !== undefined) {
- const current = pending
- pending = current.next
- yield current
- if (current.node === null) continue
- for (const child of [...current.node.descendants].reverse()) {
- pending = {
- node: child,
- depth: current.depth + 1,
- next: pending,
- }
- }
- }
- }
- function descendantIds(nodes: readonly (AuthorizedDescendant | null)[]): SessionIdValue[] {
- const ids: SessionIdValue[] = []
- for (const { node } of visitDescendants(nodes)) {
- if (node !== null) ids.push(node.record.header.id)
- }
- return ids
- }
- function titleText(view: TitleView): string {
- return view.unavailableCode === undefined
- ? view.text
- : `${view.text} (title unavailable: ${view.unavailableCode})`
- }
- /** Workspace-scoped caller authorization, title access, and lineage projection. */
- export const workspaceAccess = {
- callerOf,
- targetId,
- authorizeTarget,
- recordAuthorized,
- assertObservedTargetAuthorized,
- authorizeSessionIds,
- readTitles,
- readTitle,
- authorizeDescendants,
- visitDescendants,
- descendantIds,
- titleText,
- }
|