refactor: apply repository naming contract
Apply the accepted pre-release package, service, type, directory, and role renames as one repository-wide change.
This commit is contained in:
@@ -39,7 +39,7 @@ import type {
|
||||
ApiProxy, ConfigurableProviderView, CredentialView, GoalRef, HistoryEntry, HostFrame,
|
||||
ModelCatalogFailure, ModelProviderGroup,
|
||||
ModelReasoning, MuxFrame, PromptContentPart, QuestionResponsePayload, SessionProjectionsBlock, SessionSearchItem,
|
||||
QueuedInboxItem, SessionSummary, SettingsNamespaceView, SubagentAddress, TaskView, ToolEventView,
|
||||
QueuedInboxItem, SessionSummary, SettingsNamespaceView, SubagentAddress, JobView, ToolEventView,
|
||||
WorkspaceId, WorkspaceView,
|
||||
} from './api/index.ts'
|
||||
import {
|
||||
@@ -59,9 +59,9 @@ import {
|
||||
} from './api/session-search.ts'
|
||||
// Type-only: resolves `ctx.get('sessionProjections')` to the projection registry.
|
||||
import type {} from '@deepseek-ai/dsh-session-projection'
|
||||
// Type-only: resolves `ctx.get('tasks')` to the background task registry.
|
||||
import type {} from '@deepseek-ai/dsh-tasks'
|
||||
import type { TaskSnapshot } from '@deepseek-ai/dsh-tasks'
|
||||
// Type-only: resolves `ctx.get('tasks')` to the background job registry.
|
||||
import type {} from '@deepseek-ai/dsh-jobs'
|
||||
import type { JobSnapshot } from '@deepseek-ai/dsh-jobs'
|
||||
// Type-only: resolves `ctx.get('sessionProjectionCache')` (the cold listing column).
|
||||
import type {} from '@deepseek-ai/dsh-session-projection-cache'
|
||||
// GoalError narrows domain rejections to their stable codes at the wire boundary.
|
||||
@@ -91,8 +91,8 @@ import type { ClientResponse, RpcError, RpcReceipt, RpcRequest, RpcResponse } fr
|
||||
import { RpcId } from './api/rpc.ts'
|
||||
import type {
|
||||
AskUserQuestionAnswer, AskUserQuestionItem, AskUserQuestionRequest,
|
||||
} from '@deepseek-ai/dsh-user-interaction'
|
||||
import { UserInteractionError } from '@deepseek-ai/dsh-user-interaction'
|
||||
} from '@deepseek-ai/dsh-user-questions'
|
||||
import { UserQuestionError } from '@deepseek-ai/dsh-user-questions'
|
||||
import { DirectoryPickerError } from '@deepseek-ai/dsh-host-directory-picker'
|
||||
import {
|
||||
ApiRemoteSessionNotFound as SessionNotFound,
|
||||
@@ -119,7 +119,7 @@ const DEFAULT_MAX_MESSAGES = 50
|
||||
* is deferred work.
|
||||
*/
|
||||
const WEB_SETTINGS_NAMESPACES = [
|
||||
'agent-loop', 'bash', 'locale', 'permission', 'ui-conversation', 'ui-theme', 'web-search-deepseek',
|
||||
'agent-loop', 'shell', 'locale', 'permission', 'ui-conversation', 'ui-theme', 'web-search-deepseek',
|
||||
] as const
|
||||
|
||||
/** Provider work budget: at most 100 calls and 2,000 inspected hits. */
|
||||
@@ -277,7 +277,7 @@ function isAborted(signal: AbortSignal): boolean {
|
||||
* backwards from the window tail. Replacement copies never entered the
|
||||
* conversation a reader sees — they restate a shadowed range for the model
|
||||
* alone — so they consume no quota; the page stays one contiguous raw range,
|
||||
* which keeps a compaction's log-only `compact/summary` record on the same page as its
|
||||
* which keeps a compaction's log-only `compaction/summary` record on the same page as its
|
||||
* replacement. The cut is the starting seq of the oldest message group (chunks
|
||||
* group via sourceEventSeqs — never cut mid-message). The tail page naturally
|
||||
* includes the in-progress partial.
|
||||
@@ -476,17 +476,17 @@ function subscribeSession(queue: FrameQueue<RpcRequest<MuxFrame>>, session: Sess
|
||||
|
||||
/**
|
||||
* Project registry snapshots onto the wire view, dropping the three internal
|
||||
* fields {@link TaskView} documents as absent.
|
||||
* fields {@link JobView} documents as absent.
|
||||
*/
|
||||
function taskViews(snapshots: readonly TaskSnapshot[]): TaskView[] {
|
||||
return snapshots.map(task => ({
|
||||
id: task.id,
|
||||
kind: task.kind,
|
||||
label: task.label,
|
||||
status: task.status,
|
||||
...task.detail === undefined ? {} : { detail: task.detail },
|
||||
startedAt: task.startedAt,
|
||||
...task.finishedAt === undefined ? {} : { finishedAt: task.finishedAt },
|
||||
function jobViews(snapshots: readonly JobSnapshot[]): JobView[] {
|
||||
return snapshots.map(job => ({
|
||||
id: job.id,
|
||||
kind: job.kind,
|
||||
label: job.label,
|
||||
status: job.status,
|
||||
...job.detail === undefined ? {} : { detail: job.detail },
|
||||
startedAt: job.startedAt,
|
||||
...job.finishedAt === undefined ? {} : { finishedAt: job.finishedAt },
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -651,7 +651,7 @@ interface PendingQuestion {
|
||||
sessionId: SessionId
|
||||
questions: AskUserQuestionItem[]
|
||||
resolve: (answer: AskUserQuestionAnswer) => void
|
||||
reject: (error: UserInteractionError) => void
|
||||
reject: (error: UserQuestionError) => void
|
||||
signal?: AbortSignal
|
||||
onAbort?: () => void
|
||||
}
|
||||
@@ -1295,11 +1295,11 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro
|
||||
})
|
||||
}
|
||||
|
||||
const disposeProvider = ctx.userInteraction.registerProvider({
|
||||
const disposeProvider = ctx.userQuestions.registerProvider({
|
||||
ask(request: AskUserQuestionRequest): Promise<AskUserQuestionAnswer> {
|
||||
const sessionId = request.agent?.id
|
||||
if (sessionId === undefined) {
|
||||
return Promise.reject(new UserInteractionError(
|
||||
return Promise.reject(new UserQuestionError(
|
||||
'web user interaction requires an agent-owned session', 'ASK_MISSING_AGENT'))
|
||||
}
|
||||
return new Promise<AskUserQuestionAnswer>((resolve, reject) => {
|
||||
@@ -1310,7 +1310,7 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro
|
||||
}
|
||||
const onAbort = (): void => {
|
||||
claimQuestion(pending, 'cancelled')
|
||||
reject(new UserInteractionError(
|
||||
reject(new UserQuestionError(
|
||||
'ask_user_question was aborted before the user answered', 'ASK_ABORTED'))
|
||||
}
|
||||
pending.onAbort = onAbort
|
||||
@@ -1328,10 +1328,10 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro
|
||||
disposeProvider()
|
||||
for (const pending of [...pendingQuestions.values()]) {
|
||||
claimQuestion(pending, 'cancelled')
|
||||
pending.reject(new UserInteractionError(
|
||||
'web user-interaction provider was disposed', 'ASK_ABORTED'))
|
||||
pending.reject(new UserQuestionError(
|
||||
'web user-questions provider was disposed', 'ASK_ABORTED'))
|
||||
}
|
||||
}, 'api-proxy: user-interaction provider')
|
||||
}, 'api-proxy: user-questions provider')
|
||||
|
||||
// --- Approval pending registry ------------------------------------------
|
||||
// The proxy is the approval channel for every agent this host owns: an ask
|
||||
@@ -1439,7 +1439,7 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro
|
||||
|
||||
/** Resolve the Workspace inherited by a fork without making ordinary loose lineage grouped. */
|
||||
async function forkWorkspace(source: Pick<Session, 'id' | 'header'>): Promise<Workspace | undefined> {
|
||||
const workspaces = ctx.workspace.list()
|
||||
const workspaces = ctx.workspaceRegistry.list()
|
||||
const direct = workspaces.find(workspace => workspace.sessionIds.includes(source.id))
|
||||
if (direct !== undefined || source.header.origin !== 'subagent') return direct
|
||||
|
||||
@@ -1638,9 +1638,9 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro
|
||||
/** Resolve or create one path while holding the Host's workspace-create chain. */
|
||||
function ensureWorkspace(path: string): Promise<{ workspace: Workspace; created: boolean }> {
|
||||
const operation = workspaceCreationChain.then(async () => {
|
||||
const existing = await ctx.workspace.resolveByPath(path)
|
||||
const existing = await ctx.workspaceRegistry.resolveByPath(path)
|
||||
if (existing !== undefined) return { workspace: existing, created: false }
|
||||
return { workspace: await ctx.workspace.create(path), created: true }
|
||||
return { workspace: await ctx.workspaceRegistry.create(path), created: true }
|
||||
})
|
||||
workspaceCreationChain = operation.then(() => undefined, () => undefined)
|
||||
return operation
|
||||
@@ -1786,7 +1786,7 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro
|
||||
|
||||
/** Missing-service report shared by the settings domain (skills-domain stance). */
|
||||
function settingsAbsent(): RpcError {
|
||||
return { code: 'internal', message: 'settings service is absent: this deployment does not mount a settings provider (e.g. @deepseek-ai/dsh-settings-local) in its composition', details: {} }
|
||||
return { code: 'internal', message: 'settings service is absent: this deployment does not mount a settings provider (e.g. @deepseek-ai/dsh-settings-file) in its composition', details: {} }
|
||||
}
|
||||
|
||||
/** Open one Host-resolved target and map native failures onto the wire vocabulary. */
|
||||
@@ -2086,7 +2086,7 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro
|
||||
const sessionId = request.payload.sessionId ?? `session-${randomUUID()}` as SessionId
|
||||
let workspace: Workspace | undefined
|
||||
if (request.payload.workspaceId !== undefined) {
|
||||
workspace = ctx.workspace.get(brandWorkspaceId(request.payload.workspaceId))
|
||||
workspace = ctx.workspaceRegistry.get(brandWorkspaceId(request.payload.workspaceId))
|
||||
if (workspace === undefined) {
|
||||
return err(request, {
|
||||
code: 'workspace-not-found',
|
||||
@@ -2720,8 +2720,8 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro
|
||||
workspace: {
|
||||
list(request) {
|
||||
return Promise.resolve(ok(request, {
|
||||
items: ctx.workspace.list().map(workspaceView),
|
||||
archivedSessionIds: [...ctx.workspace.archivedSessionIds],
|
||||
items: ctx.workspaceRegistry.list().map(workspaceView),
|
||||
archivedSessionIds: [...ctx.workspaceRegistry.archivedSessionIds],
|
||||
}))
|
||||
},
|
||||
|
||||
@@ -2744,7 +2744,7 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro
|
||||
|
||||
async rename(request) {
|
||||
const { payload } = request
|
||||
const workspace = ctx.workspace.get(brandWorkspaceId(payload.workspaceId))
|
||||
const workspace = ctx.workspaceRegistry.get(brandWorkspaceId(payload.workspaceId))
|
||||
if (workspace === undefined) return workspaceNotFound(request, payload.workspaceId)
|
||||
const title = payload.title.trim()
|
||||
// Uniqueness AND the same-title no-op both ride the create chain so
|
||||
@@ -2753,7 +2753,7 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro
|
||||
// still lands afterwards.
|
||||
const operation = workspaceCreationChain.then(async () => {
|
||||
if (title === workspace.title) return
|
||||
if (ctx.workspace.list().some(other => other.id !== workspace.id && other.title === title)) {
|
||||
if (ctx.workspaceRegistry.list().some(other => other.id !== workspace.id && other.title === title)) {
|
||||
throw new WorkspaceNameConflictError(title)
|
||||
}
|
||||
await workspace.setTitle(title)
|
||||
@@ -2777,7 +2777,7 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro
|
||||
async delete(request) {
|
||||
const { workspaceId } = request.payload
|
||||
const operation = workspaceCreationChain.then(() =>
|
||||
ctx.workspace.delete(brandWorkspaceId(workspaceId)))
|
||||
ctx.workspaceRegistry.delete(brandWorkspaceId(workspaceId)))
|
||||
workspaceCreationChain = operation.then(() => undefined, () => undefined)
|
||||
if (!await operation) return workspaceNotFound(request, workspaceId)
|
||||
return ok(request, { deleted: true as const })
|
||||
@@ -2786,7 +2786,7 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro
|
||||
async insertBefore(request) {
|
||||
const { workspaceId, beforeWorkspaceId } = request.payload
|
||||
try {
|
||||
const workspaceIds = await ctx.workspace.insertBefore(
|
||||
const workspaceIds = await ctx.workspaceRegistry.insertBefore(
|
||||
brandWorkspaceId(workspaceId),
|
||||
beforeWorkspaceId === undefined ? undefined : brandWorkspaceId(beforeWorkspaceId),
|
||||
)
|
||||
@@ -2799,7 +2799,7 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro
|
||||
|
||||
async insertSessionBefore(request) {
|
||||
const { payload } = request
|
||||
const workspace = ctx.workspace.get(brandWorkspaceId(payload.workspaceId))
|
||||
const workspace = ctx.workspaceRegistry.get(brandWorkspaceId(payload.workspaceId))
|
||||
if (workspace === undefined) return workspaceNotFound(request, payload.workspaceId)
|
||||
try {
|
||||
await workspace.insertSessionBefore(payload.sessionId, payload.beforeSessionId)
|
||||
@@ -2823,7 +2823,7 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro
|
||||
async archiveSession(request) {
|
||||
const { sessionId } = request.payload
|
||||
try {
|
||||
await ctx.workspace.archiveSession(sessionId)
|
||||
await ctx.workspaceRegistry.archiveSession(sessionId)
|
||||
} catch (error: unknown) {
|
||||
// Only the registry's unknown-session rejection is the business
|
||||
// code; storage/durability failures propagate as internal errors.
|
||||
@@ -2834,7 +2834,7 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro
|
||||
details: { sessionId },
|
||||
})
|
||||
}
|
||||
return ok(request, { archivedSessionIds: [...ctx.workspace.archivedSessionIds] })
|
||||
return ok(request, { archivedSessionIds: [...ctx.workspaceRegistry.archivedSessionIds] })
|
||||
},
|
||||
},
|
||||
|
||||
@@ -3376,12 +3376,12 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro
|
||||
// a session with no live Agent owns no tasks, so it correctly sees only
|
||||
// the unowned ones, and listing never revives a cold session. An empty
|
||||
// set sends nothing — absence is how the client reads "no tasks".
|
||||
const tasks = ctx.get('tasks')
|
||||
if (tasks !== undefined) {
|
||||
const jobs = ctx.get('jobs')
|
||||
if (jobs !== undefined) {
|
||||
for (const session of ctx.sessions.list()) {
|
||||
const views = taskViews(tasks.list(ctx.agents.get(session.id)))
|
||||
const views = jobViews(jobs.list(ctx.agents.get(session.id)))
|
||||
if (views.length > 0) {
|
||||
queue.push(frame({ type: 'session/tasks', sessionId: session.id, tasks: views }))
|
||||
queue.push(frame({ type: 'session/jobs', sessionId: session.id, jobs: views }))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3416,29 +3416,29 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro
|
||||
// session born after the stream opened missed the baseline loop.
|
||||
// Unowned tasks are visible to it from birth, so without this it
|
||||
// would show none until the next registry change.
|
||||
const views = tasks === undefined ? [] : taskViews(tasks.list(ctx.agents.get(session.id)))
|
||||
const views = jobs === undefined ? [] : jobViews(jobs.list(ctx.agents.get(session.id)))
|
||||
if (views.length > 0) {
|
||||
queue.push(frame({ type: 'session/tasks', sessionId: session.id, tasks: views }))
|
||||
queue.push(frame({ type: 'session/jobs', sessionId: session.id, jobs: views }))
|
||||
}
|
||||
}),
|
||||
ctx.on('session/disposed', (session: Session) => {
|
||||
openCalls.delete(session.id)
|
||||
}),
|
||||
...tasks === undefined ? [] : [tasks.onTasksChanged((owner) => {
|
||||
...jobs === undefined ? [] : [jobs.onJobsChanged((owner) => {
|
||||
if (owner !== undefined) {
|
||||
// The exact owner instance the fence compares against, so the
|
||||
// push stays correct even while that Agent's scope is tearing
|
||||
// down and a lookup by id would already miss.
|
||||
queue.push(frame({ type: 'session/tasks', sessionId: owner.id, tasks: taskViews(tasks.list(owner)) }))
|
||||
queue.push(frame({ type: 'session/jobs', sessionId: owner.id, jobs: jobViews(jobs.list(owner)) }))
|
||||
return
|
||||
}
|
||||
// An unowned task is visible to every caller, so every subscribed
|
||||
// session's set changed with it.
|
||||
for (const session of ctx.sessions.list()) {
|
||||
queue.push(frame({
|
||||
type: 'session/tasks',
|
||||
type: 'session/jobs',
|
||||
sessionId: session.id,
|
||||
tasks: taskViews(tasks.list(ctx.agents.get(session.id))),
|
||||
jobs: jobViews(jobs.list(ctx.agents.get(session.id))),
|
||||
}))
|
||||
}
|
||||
})],
|
||||
@@ -3451,7 +3451,7 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro
|
||||
|
||||
host(_request, signal) {
|
||||
const queue = new FrameQueue<RpcRequest<HostFrame>>()
|
||||
const committedWorkspaces = ctx.workspace.list()
|
||||
const committedWorkspaces = ctx.workspaceRegistry.list()
|
||||
const committedWorkspaceIds = new Set(
|
||||
committedWorkspaces.map(workspace => String(workspace.id)),
|
||||
)
|
||||
@@ -3459,7 +3459,7 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro
|
||||
// Frame-dedup baseline, same posture as committedWorkspaceIds: the
|
||||
// stream opens against the current set; workspace.list re-baselines
|
||||
// reconnecting clients, so only later changes need frames.
|
||||
let archivedSessionIds = ctx.workspace.archivedSessionIds
|
||||
let archivedSessionIds = ctx.workspaceRegistry.archivedSessionIds
|
||||
const disposers = [
|
||||
ctx.on('session/created', (session: Session) => {
|
||||
queue.push(frame({
|
||||
@@ -3491,7 +3491,7 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro
|
||||
&& state.workspaceIds.some((workspaceId, index) => workspaceId !== committedWorkspaceOrder[index])
|
||||
for (const workspaceId of state.workspaceIds) {
|
||||
if (committedWorkspaceIds.has(workspaceId)) continue
|
||||
const workspace = ctx.workspace.get(workspaceId)
|
||||
const workspace = ctx.workspaceRegistry.get(workspaceId)
|
||||
if (workspace === undefined) {
|
||||
throw new Error(`committed workspace registry references missing workspace "${workspaceId}"`)
|
||||
}
|
||||
@@ -3633,7 +3633,7 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro
|
||||
return Promise.resolve({ accepted: false, reason: 'bad-response' })
|
||||
}
|
||||
claimQuestion(pending, 'cancelled')
|
||||
pending.reject(new UserInteractionError(
|
||||
pending.reject(new UserQuestionError(
|
||||
'the user cancelled ask_user_question', 'ASK_CANCELLED'))
|
||||
return Promise.resolve({ accepted: true })
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import { z } from 'zod'
|
||||
import type { AskUserQuestionItem } from '@deepseek-ai/dsh-user-interaction/types'
|
||||
import type { AskUserQuestionItem } from '@deepseek-ai/dsh-user-questions/types'
|
||||
import type { HostFrame, MuxFrame } from './events.ts'
|
||||
import type { Wire } from './rpc.schema.ts'
|
||||
import { rpcErrorSchema, rpcIdSchema } from './rpc.schema.ts'
|
||||
@@ -13,10 +13,10 @@ import { approvalRequestIdSchema } from './approvals.schema.ts'
|
||||
import {
|
||||
contentBlockSchema, messageIdSchema, sessionEventSchema, sessionIdSchema, toolEventViewSchema,
|
||||
} from './sessions.schema.ts'
|
||||
import { taskViewSchema } from './tasks.schema.ts'
|
||||
import { taskViewSchema } from './jobs.schema.ts'
|
||||
import { workspaceIdSchema, workspaceViewSchema } from './workspace.schema.ts'
|
||||
|
||||
/** Question fields validated strictly against core dsh-user-interaction. */
|
||||
/** Question fields validated strictly against core dsh-user-questions. */
|
||||
export const askUserQuestionItemSchema = z.object({
|
||||
id: z.string(),
|
||||
question: z.string(),
|
||||
@@ -45,7 +45,7 @@ export const muxFrameSchema = z.discriminatedUnion('type', [
|
||||
z.object({ type: z.literal('session/subscribed'), sessionId: sessionIdSchema, lastSeq: z.number().int() }),
|
||||
z.object({ type: z.literal('approval/requested'), sessionId: sessionIdSchema, approvalId: approvalRequestIdSchema, toolName: z.string(), callId: z.string().optional(), reason: z.string().optional() }),
|
||||
z.object({ type: z.literal('approval/resolved'), sessionId: sessionIdSchema, approvalId: approvalRequestIdSchema, outcome: z.union([z.literal('allowed-once'), z.literal('rejected'), z.literal('cancelled'), z.literal('unavailable')]) }),
|
||||
// Non-empty by wire contract: the user-interaction service rejects empty
|
||||
// Non-empty by wire contract: the user-questions service rejects empty
|
||||
// batches at ask() (EMPTY_QUESTIONS), so an empty frame is host breakage
|
||||
// and must fail loud here, not reach the composer.
|
||||
z.object({ type: z.literal('question/requested'), sessionId: sessionIdSchema, questions: z.array(askUserQuestionItemSchema).min(1) }),
|
||||
@@ -59,7 +59,7 @@ export const muxFrameSchema = z.discriminatedUnion('type', [
|
||||
message: messageSchema,
|
||||
})),
|
||||
}),
|
||||
z.object({ type: z.literal('session/tasks'), sessionId: sessionIdSchema, tasks: z.array(taskViewSchema) }),
|
||||
z.object({ type: z.literal('session/jobs'), sessionId: sessionIdSchema, jobs: z.array(taskViewSchema) }),
|
||||
// value stays wide: it already passed its unit's own schema on the host,
|
||||
// and deep-validating here would import every domain's schema into the carrier.
|
||||
z.object({ type: z.literal('session/projection'), sessionId: sessionIdSchema, key: z.string().min(1), value: z.unknown(), seq: z.number().int().nonnegative() }),
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* signal is a local stream-control parameter, independent of the request (never on the wire).
|
||||
*/
|
||||
|
||||
import type { AskUserQuestionItem } from '@deepseek-ai/dsh-user-interaction/types'
|
||||
import type { AskUserQuestionItem } from '@deepseek-ai/dsh-user-questions/types'
|
||||
import type { ApprovalOutcome, ApprovalRequestId } from '@deepseek-ai/dsh-user-approval/types'
|
||||
import type { Message } from '@deepseek-ai/dsh-llm/types'
|
||||
import type { MessageId } from '@deepseek-ai/dsh-llm/brand'
|
||||
@@ -14,7 +14,7 @@ import type { CallId } from '@deepseek-ai/dsh-llm/brand'
|
||||
import type { JsonValue, SessionEvent, SessionId } from '@deepseek-ai/dsh-session/types'
|
||||
import type { ToolCallView, ToolResultView } from '@deepseek-ai/dsh-tools/presentation'
|
||||
import type { RpcError, RpcId, RpcRequest } from './rpc.ts'
|
||||
import type { TaskView } from './tasks.ts'
|
||||
import type { JobView } from './jobs.ts'
|
||||
import type { WorkspaceView } from './workspace.ts'
|
||||
|
||||
// Client-side consumers take the render-intent vocabulary from the contract;
|
||||
@@ -83,7 +83,7 @@ export type MuxFrame =
|
||||
*/
|
||||
| { type: 'session/queue'; sessionId: SessionId; items: QueuedInboxItem[] }
|
||||
/**
|
||||
* Complete set of background tasks this session can see, after every registry
|
||||
* Complete set of background jobs this session can see, after every registry
|
||||
* commit that changes it: registration, the stopping transition, settlement,
|
||||
* and owner-disposal removal. The registry is process-local and holds no
|
||||
* durable event, so — exactly like `session/queue` — the whole snapshot is
|
||||
@@ -95,7 +95,7 @@ export type MuxFrame =
|
||||
* still sends `[]`, since that transition is the only one absence cannot
|
||||
* express.
|
||||
*/
|
||||
| { type: 'session/tasks'; sessionId: SessionId; tasks: TaskView[] }
|
||||
| { type: 'session/jobs'; sessionId: SessionId; jobs: JobView[] }
|
||||
/**
|
||||
* One projection unit's finished value changed (session-projection RFC).
|
||||
* Live push state, never logged — replay recomputes on the host (the
|
||||
|
||||
@@ -48,7 +48,7 @@ export type {
|
||||
SubagentAddress, SubagentCatalog, SubagentInterruptReceipt, SubagentListEntry,
|
||||
SubagentPromptReceipt, SubagentsApi,
|
||||
} from './subagents.ts'
|
||||
export type { TaskView } from './tasks.ts'
|
||||
export type { JobView } from './jobs.ts'
|
||||
export type { WorkspaceApi, WorkspaceId, WorkspaceView } from './workspace.ts'
|
||||
export type { SkillsApi, SkillEntry } from './skills.ts'
|
||||
export type { AgentPresetsApi, AgentPresetEntry } from './agent-presets.ts'
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
/**
|
||||
* tasks domain zod schemas: the branded task id and the wire view carried by
|
||||
* `session/tasks` frames.
|
||||
* tasks domain zod schemas: the branded job id and the wire view carried by
|
||||
* `session/jobs` frames.
|
||||
*/
|
||||
|
||||
import { z } from 'zod'
|
||||
import type { TaskId } from '@deepseek-ai/dsh-tasks/brand'
|
||||
import type { TaskView } from './tasks.ts'
|
||||
import type { JobId } from '@deepseek-ai/dsh-jobs/brand'
|
||||
import type { JobView } from './jobs.ts'
|
||||
import type { Wire } from './rpc.schema.ts'
|
||||
|
||||
/** TaskId: one brand cast after non-empty string validation. */
|
||||
export const taskIdSchema = z.string().min(1) as unknown as z.ZodType<TaskId>
|
||||
/** JobId: one brand cast after non-empty string validation. */
|
||||
export const taskIdSchema = z.string().min(1) as unknown as z.ZodType<JobId>
|
||||
|
||||
/**
|
||||
* One wire task view. `kind` stays an open string because producer plugins
|
||||
@@ -30,4 +30,4 @@ export const taskViewSchema = z.object({
|
||||
detail: z.string().optional(),
|
||||
startedAt: z.number().int().nonnegative(),
|
||||
finishedAt: z.number().int().nonnegative().optional(),
|
||||
}) satisfies z.ZodType<Wire<TaskView>>
|
||||
}) satisfies z.ZodType<Wire<JobView>>
|
||||
@@ -1,22 +1,22 @@
|
||||
/**
|
||||
* Browser-safe background-task domain contract. The registry's live records
|
||||
* Browser-safe background-job domain contract. The registry's live records
|
||||
* never cross the wire; a view is the subset a human list needs, minted fresh
|
||||
* per push.
|
||||
*/
|
||||
|
||||
import type { TaskId } from '@deepseek-ai/dsh-tasks/brand'
|
||||
import type { JobId } from '@deepseek-ai/dsh-jobs/brand'
|
||||
|
||||
/**
|
||||
* One background task as the client sees it.
|
||||
* One background job as the client sees it.
|
||||
*
|
||||
* Three registry fields are deliberately absent. `ownerSession` is redundant
|
||||
* beside the frame's own `sessionId`; `reported` is an internal notice-delivery
|
||||
* bit with no user meaning; `outputLimitBytes` is producer-owned model
|
||||
* presentation policy that never reaches a human surface.
|
||||
*/
|
||||
export interface TaskView {
|
||||
export interface JobView {
|
||||
/** Registry-issued `<kind>-N` identity, stable for the task's whole life. */
|
||||
id: TaskId
|
||||
id: JobId
|
||||
/**
|
||||
* Producer kind (`bash`, `pwsh`, `pty-send`, `subagent`, …). Kept as a bare
|
||||
* string because producer plugins extend the kind map by declaration merging,
|
||||
@@ -5,12 +5,12 @@
|
||||
*/
|
||||
|
||||
import { z } from 'zod'
|
||||
import type { AskUserQuestionAnswer } from '@deepseek-ai/dsh-user-interaction/types'
|
||||
import type { AskUserQuestionAnswer } from '@deepseek-ai/dsh-user-questions/types'
|
||||
import type { QuestionResponsePayload } from './questions.ts'
|
||||
import type { Wire } from './rpc.schema.ts'
|
||||
import { sessionIdSchema } from './sessions.schema.ts'
|
||||
|
||||
/** AskUserQuestionAnswer validated strictly against core dsh-user-interaction. */
|
||||
/** AskUserQuestionAnswer validated strictly against core dsh-user-questions. */
|
||||
export const askUserQuestionAnswerSchema = z.object({
|
||||
answers: z.array(z.object({
|
||||
id: z.string(),
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/**
|
||||
* questions domain contract. The question requested frame is a
|
||||
* server-request whose rpcId is the question's stable logical id (minted when the host accepts
|
||||
* ask(); core user-interaction has no request-level id); the answer is a client-response
|
||||
* ask(); core user-questions has no request-level id); the answer is a client-response
|
||||
* echoing that rpcId, with no resource id in the payload (rpcId suffices).
|
||||
*/
|
||||
|
||||
import type { AskUserQuestionAnswer } from '@deepseek-ai/dsh-user-interaction/types'
|
||||
import type { AskUserQuestionAnswer } from '@deepseek-ai/dsh-user-questions/types'
|
||||
import type { SessionId } from '@deepseek-ai/dsh-session/types'
|
||||
|
||||
/**
|
||||
|
||||
@@ -250,7 +250,7 @@ export interface SessionsApi {
|
||||
* Reads a window of history events; page boundaries align to append-origin message
|
||||
* boundaries: one page = all raw events owned by a whole number of such messages (including
|
||||
* their chunk / tool events), never cut mid-message. Model-only replacement copies consume no
|
||||
* `maxMessages`, so a compaction's `compact/summary` record stays on the page of its replacement. The tail
|
||||
* `maxMessages`, so a compaction's `compaction/summary` record stays on the page of its replacement. The tail
|
||||
* page (beforeSeq absent) additionally carries the in-flight
|
||||
* partial — chunk events already emitted for the last unfinalized message.
|
||||
* Each entry pairs the raw SessionEvent with the host-computed view (tool events whose
|
||||
|
||||
@@ -63,7 +63,7 @@ export interface Config {
|
||||
export class ApiProxyService extends Service implements ApiProxy {
|
||||
static inject = [
|
||||
'agentDefaultModel', 'agents', 'attachments', 'directoryPicker', 'llm', 'sessions', 'subagents', 'sessionQuery',
|
||||
'tools', 'userInteraction', 'workspace',
|
||||
'tools', 'userQuestions', 'workspaceRegistry',
|
||||
]
|
||||
|
||||
static Config: z<Config> = z.object({
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
import { Zip, ZipDeflate } from 'fflate'
|
||||
import type { Context } from '@deepseek-ai/cordis'
|
||||
import type { AttachmentStore, ImageAttachmentRef } from '@deepseek-ai/dsh-attachment'
|
||||
import type { SessionLineageNode, SessionQueryService } from '@deepseek-ai/dsh-session-query'
|
||||
import type { SessionLineageNode, SessionQueryEngine } from '@deepseek-ai/dsh-session-query'
|
||||
import type { SessionId, SessionStore } from '@deepseek-ai/dsh-session'
|
||||
import type { SessionPersistence, SessionRawArtifact } from '@deepseek-ai/dsh-session-persistence'
|
||||
|
||||
@@ -34,7 +34,7 @@ export const DEFAULT_SESSION_LOG_COMPRESSION_LEVEL: SessionLogCompressionLevel =
|
||||
|
||||
/** The services a session-log export needs (the live-session store is optional). */
|
||||
export interface SessionLogExportDeps {
|
||||
readonly sessionQuery: SessionQueryService | undefined
|
||||
readonly sessionQuery: SessionQueryEngine | undefined
|
||||
readonly sessionPersistence: SessionPersistence | undefined
|
||||
readonly attachments: AttachmentStore | undefined
|
||||
readonly sessions: SessionStore | undefined
|
||||
@@ -42,7 +42,7 @@ export interface SessionLogExportDeps {
|
||||
|
||||
/** The export services narrowed to the mounted ones streaming actually reads. */
|
||||
export interface SessionLogExportReady {
|
||||
readonly sessionQuery: SessionQueryService
|
||||
readonly sessionQuery: SessionQueryEngine
|
||||
readonly sessionPersistence: SessionPersistence
|
||||
readonly attachments: AttachmentStore
|
||||
readonly sessions: SessionStore | undefined
|
||||
|
||||
Reference in New Issue
Block a user