mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
refactor(commands): move the command service to Remote
`CommandService.list` and `execute` carry the wire contract directly through `@Remote`, and the Client assembly mounts the generated commands contribution. The legacy API Proxy route, its schemas, the map rows, the generated client methods and the fixture's command domain are removed, so the catalog and the admission call have one owner again. `Session.command()` keeps a result-shaped public face for parity with the prompt, cancel and attachment neighbours it sits beside, and reads the generated namespace through one `SessionRemotes` parameter. The Session cluster declares that face against the owning business package rather than the generated contribution: the Host compiler aggregate builds this package, and it runs before any contribution is emitted. Migrated calls lose the `title-invalid` class of protocol-only error codes and report `internal`; no production caller branched on them.
This commit is contained in:
@@ -17,7 +17,7 @@
|
||||
*/
|
||||
import { Context as CordisContext } from '@deepseek-ai/cordis'
|
||||
import type { Context, Fiber } from '@deepseek-ai/cordis'
|
||||
import type { SessionId } from '@deepseek-ai/dsh-client-connection/client'
|
||||
import type { SessionId } from '@deepseek-ai/dsh-api-remotes/client'
|
||||
import type { TypeRTClientRemote, TypeRTRemoteScopeApi } from '@deepseek-ai/dsh-type-meta'
|
||||
|
||||
/** Client Cordis Context carrying one Agent identity and its scoped Remote namespaces. */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { SessionEvent } from '@deepseek-ai/dsh-session/types'
|
||||
import type { ToolEventView } from '@deepseek-ai/dsh-client-connection/client'
|
||||
import type { ToolEventView } from '@deepseek-ai/dsh-api-remotes/client'
|
||||
|
||||
/* oxlint-disable typescript/no-duplicate-type-constituents, typescript/no-redundant-type-constituents --
|
||||
* The unaugmented declaration-merge maps intentionally resolve to never in the Runtime program;
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
import type { AttachmentIdType, ImageAttachmentRef } from '@deepseek-ai/dsh-attachment'
|
||||
import type {
|
||||
MessageId, PromptContentPart, QueueAction, RpcResult, SessionId,
|
||||
} from '@deepseek-ai/dsh-client-connection/client'
|
||||
} from '@deepseek-ai/dsh-api-remotes/client'
|
||||
import type { RemoteResult } from '@deepseek-ai/dsh-type-meta'
|
||||
import type { ConversationSnapshot } from '../sessions/conversation.ts'
|
||||
import type { ObservableSnapshot } from './store.ts'
|
||||
|
||||
@@ -75,9 +76,9 @@ export interface ISession {
|
||||
* Execute one slash-command line against this session's agent — pure
|
||||
* admission semantics (the host executor durably logs the lifecycle).
|
||||
* @param line - the full command line, leading slash included.
|
||||
* @returns the admission result, or the error branch on transport failure.
|
||||
* @returns the admission result, or the Remote face's error branch.
|
||||
*/
|
||||
command(line: string): Promise<RpcResult<{ matched: boolean }>>
|
||||
command(line: string): Promise<RemoteResult<{ matched: boolean }>>
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* dependency.
|
||||
*/
|
||||
|
||||
import type { SessionId, WorkspaceId } from '@deepseek-ai/dsh-client-connection/client'
|
||||
import type { SessionId, WorkspaceId } from '@deepseek-ai/dsh-api-remotes/client'
|
||||
import type { ObservableSnapshot } from './store.ts'
|
||||
|
||||
/** Session-list row facts sibling domains read: recency, blank-reuse eligibility, and its cwd canon. */
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
import type { Context } from '@deepseek-ai/cordis'
|
||||
import type {
|
||||
RpcResult, SessionId, SubagentAddress,
|
||||
} from '@deepseek-ai/dsh-client-connection/client'
|
||||
} from '@deepseek-ai/dsh-api-remotes/client'
|
||||
import type { HostObservable, SessionMaybeProvideInfo } from '@deepseek-ai/dsh-client-ui-slots'
|
||||
import type { AgentContext } from '../agents/scope.ts'
|
||||
import type { SessionSearchResultItem } from '../sessions/manager.ts'
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* the concrete class. Widening this interface is the explicit act of
|
||||
* widening what features may do to the workspaces domain.
|
||||
*/
|
||||
import type { DirectoryListing, SessionId, WorkspaceId, WorkspaceView } from '@deepseek-ai/dsh-client-connection/client'
|
||||
import type { DirectoryListing, SessionId, WorkspaceId, WorkspaceView } from '@deepseek-ai/dsh-api-remotes/client'
|
||||
import type { WorkspaceListState } from '../workspaces/service.ts'
|
||||
import type { ObservableSnapshot } from './store.ts'
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/** Browser runtime services for slots, sessions, workspaces, and connection-stream delivery. */
|
||||
import type { Context } from '@deepseek-ai/cordis'
|
||||
import type { ConnectionHandle, SessionId } from '@deepseek-ai/dsh-client-connection/client'
|
||||
import type { ConnectionHandle, SessionId } from '@deepseek-ai/dsh-api-remotes/client'
|
||||
// Type-only: the ctx.remote merge. Deliberately the gateway's Client half rather
|
||||
// than api-remotes': that face imports a Host-tsdown-generated artifact, and this
|
||||
// project sits in the Host build graph.
|
||||
import type {} from '@deepseek-ai/dsh-api-gateway/client'
|
||||
import type {} from '@deepseek-ai/dsh-api-remotes/client'
|
||||
import type { TypeRTContext } from '@deepseek-ai/dsh-type-meta'
|
||||
import type { MaybeSnapshotSelectorHook, SnapshotSelectorHook } from '@deepseek-ai/dsh-client-ui-slots'
|
||||
import { SlotsService } from './slots.ts'
|
||||
@@ -179,7 +179,7 @@ declare module '@deepseek-ai/cordis' {
|
||||
}
|
||||
|
||||
/** Required services: the wire handle and Client TypeRT registry. */
|
||||
export const inject = ['connection', 'typert', 'remote']
|
||||
export const inject = ['connection', 'typert', 'remote', 'remote.commands']
|
||||
|
||||
/** Mounts the browser runtime services and connection stream.
|
||||
* @param ctx - Client Cordis context.
|
||||
@@ -191,7 +191,7 @@ export function apply(ctx: Context): void {
|
||||
views: new ConversationViewRegistry(ctx),
|
||||
}
|
||||
const connection = ctx.get('connection') as ConnectionHandle
|
||||
const sessions = new SessionsService(ctx, connection.api, conversation)
|
||||
const sessions = new SessionsService(ctx, connection.api, ctx.remote, conversation)
|
||||
ctx.typert.contexts.registerClient('agent', {
|
||||
identity: candidate => sessions.scopeOf(candidate),
|
||||
})
|
||||
|
||||
@@ -13,7 +13,7 @@ import type { LlmRetryEventData } from '@deepseek-ai/dsh-llm-retry/types'
|
||||
import type { TodoItem } from '@deepseek-ai/dsh-session/types'
|
||||
import type {
|
||||
RpcError, SessionId, SubagentAddress, ToolCallView, ToolResultView,
|
||||
} from '@deepseek-ai/dsh-client-connection/client'
|
||||
} from '@deepseek-ai/dsh-api-remotes/client'
|
||||
import type { PendingInteraction } from './pending.ts'
|
||||
import type { ContextProvenanceView, KnownContextForm } from './context-provenance.ts'
|
||||
import type {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// The input order is authoritative; lineage only makes each child adjacent to its parent.
|
||||
// Orphaned lineage degrades to root level; cycles fail soft and emit as roots.
|
||||
|
||||
import type { SessionId, SessionSummary } from '@deepseek-ai/dsh-client-connection/client'
|
||||
import type { SessionId, SessionSummary } from '@deepseek-ai/dsh-api-remotes/client'
|
||||
import type { SessionProjectionMap } from '@deepseek-ai/dsh-session-projection/types'
|
||||
import type { PendingInteractionStatus } from './pending.ts'
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import type {
|
||||
IApiClient, HostFrame, MuxFrame, RpcError, RpcRequest, RpcResult, SessionId,
|
||||
SessionSummary, SubagentAddress, SubagentCatalog, TaskView, WorkspaceId,
|
||||
} from '@deepseek-ai/dsh-client-connection/client'
|
||||
} from '@deepseek-ai/dsh-api-remotes/client'
|
||||
// Value import from the inline-safe wire layer (not the connection plugin):
|
||||
// plugin-to-plugin value imports are a bundle purity error.
|
||||
import { transportError } from '@deepseek-ai/dsh-host-apiproxy/api'
|
||||
@@ -21,6 +21,7 @@ import type {} from '@deepseek-ai/dsh-session-title/client'
|
||||
import { Notifier } from './notifier.ts'
|
||||
import { ProjectionValueStore } from './projection-store.ts'
|
||||
import { Session } from './session.ts'
|
||||
import type { SessionRemotes } from './remotes.ts'
|
||||
|
||||
/**
|
||||
* List arrival lifecycle, orthogonal to the pull-activity `state` axis:
|
||||
@@ -164,6 +165,7 @@ export class SessionManager {
|
||||
*/
|
||||
constructor(
|
||||
private readonly api: IApiClient,
|
||||
private readonly remote: SessionRemotes,
|
||||
restoredSelection?: SessionId,
|
||||
restoredAddress?: SubagentAddress,
|
||||
private readonly conversation?: ConversationRuntime,
|
||||
@@ -304,7 +306,7 @@ export class SessionManager {
|
||||
|
||||
private createSession(sessionId: SessionId): Session {
|
||||
const address = this.addresses.get(sessionId)
|
||||
return new Session(sessionId, this.api, {
|
||||
return new Session(sessionId, this.api, this.remote, {
|
||||
...(address === undefined ? {} : {
|
||||
address,
|
||||
parentAvailable: this.catalogs.get(address.parentSessionId)?.parentAvailable ?? false,
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
import type {
|
||||
ClientResponse, MuxFrame, RpcId, RpcReceipt, SessionId,
|
||||
} from '@deepseek-ai/dsh-client-connection/client'
|
||||
} from '@deepseek-ai/dsh-api-remotes/client'
|
||||
|
||||
/** Kind-keyed payload map: the requested frame's domain fields (envelope fields stripped). */
|
||||
export interface PendingPayloads {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { ContentBlock } from '@deepseek-ai/dsh-llm/types'
|
||||
import type { MuxFrame } from '@deepseek-ai/dsh-client-connection/client'
|
||||
import type { MuxFrame } from '@deepseek-ai/dsh-api-remotes/client'
|
||||
import type { SessionEvent } from '@deepseek-ai/dsh-session/types'
|
||||
import type { QueuedMessage } from './conversation.ts'
|
||||
|
||||
|
||||
12
packages/client/runtime/src/client/sessions/remotes.ts
Normal file
12
packages/client/runtime/src/client/sessions/remotes.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Remote namespaces the Session cluster calls. One parameter for one concept:
|
||||
* the generated surface a Session and its manager reach the Host through.
|
||||
*
|
||||
* @module @deepseek-ai/dsh-client-runtime/client/sessions/remotes
|
||||
*/
|
||||
|
||||
import type { Context } from '@deepseek-ai/cordis'
|
||||
import type {} from '@deepseek-ai/dsh-api-remotes/client'
|
||||
|
||||
/** The generated Remote namespaces a Session and its manager call. */
|
||||
export type SessionRemotes = Pick<Context['remote'], 'commands'>
|
||||
@@ -17,7 +17,7 @@
|
||||
import type { Context, Fiber } from '@deepseek-ai/cordis'
|
||||
import type {
|
||||
IApiClient, RpcError, RpcResult, SessionId, SubagentAddress, TaskView, WorkspaceId,
|
||||
} from '@deepseek-ai/dsh-client-connection/client'
|
||||
} from '@deepseek-ai/dsh-api-remotes/client'
|
||||
// Value import from the inline-safe wire layer (not the connection plugin):
|
||||
// plugin-to-plugin value imports are a bundle purity error.
|
||||
import { SESSION_SEARCH_RESULT_LIMIT } from '@deepseek-ai/dsh-host-apiproxy/api'
|
||||
@@ -32,6 +32,7 @@ import type { AgentContext, ISessions } from '../contract/sessions.ts'
|
||||
import { createScope, scopeOf as scopeTagOf } from '../agents/scope.ts'
|
||||
import type { ConversationRuntime } from './conversation-assembler.ts'
|
||||
import { SessionManager } from './manager.ts'
|
||||
import type { SessionRemotes } from './remotes.ts'
|
||||
import type { SessionListPhase, SessionSearchResultItem, SubagentCatalogSnapshot } from './manager.ts'
|
||||
import type { PendingInteractionStatus } from './pending.ts'
|
||||
import { SessionProvideChannel } from './provide.ts'
|
||||
@@ -271,11 +272,13 @@ export class SessionsService implements ISessions {
|
||||
/**
|
||||
* @param ctx - client root context (scope fibers mount under it).
|
||||
* @param api - wire client shared with every Session.
|
||||
* @param remote - generated Remote namespaces shared with every Session.
|
||||
* @param conversationRuntime - same-pass registry instances, when runtime apply owns them.
|
||||
*/
|
||||
constructor(
|
||||
private readonly rootCtx: Context,
|
||||
api: IApiClient,
|
||||
remote: SessionRemotes,
|
||||
conversationRuntime?: ConversationRuntime,
|
||||
) {
|
||||
this.selection = createSnapshotStore<SessionSelection>(
|
||||
@@ -291,6 +294,7 @@ export class SessionsService implements ISessions {
|
||||
)
|
||||
this.manager = new SessionManager(
|
||||
api,
|
||||
remote,
|
||||
restored.sessionId,
|
||||
restored.subagentAddress,
|
||||
conversation,
|
||||
|
||||
@@ -6,7 +6,7 @@ import type { SessionEvent } from '@deepseek-ai/dsh-session/types'
|
||||
import type {
|
||||
HistoryEntry, IApiClient, MessageId, MuxFrame, PromptContentPart, QueueAction, RpcError,
|
||||
RpcId, RpcResponse, RpcResult, SessionId, SubagentAddress, ToolEventView,
|
||||
} from '@deepseek-ai/dsh-client-connection/client'
|
||||
} from '@deepseek-ai/dsh-api-remotes/client'
|
||||
// Value import from the inline-safe wire layer (not the connection plugin):
|
||||
// plugin-to-plugin value imports are a bundle purity error.
|
||||
import { transportError } from '@deepseek-ai/dsh-host-apiproxy/api'
|
||||
@@ -21,6 +21,8 @@ import { EMPTY_CHAT_SNAPSHOT } from './conversation.ts'
|
||||
import type { PendingInteraction } from './pending.ts'
|
||||
import { PendingWait } from './pending.ts'
|
||||
import { Notifier } from './notifier.ts'
|
||||
import type { RemoteResult } from '@deepseek-ai/dsh-type-meta'
|
||||
import type { SessionRemotes } from './remotes.ts'
|
||||
import { ProjectionValueStore } from './projection-store.ts'
|
||||
import type { ProjectionsBaseline } from './projection-store.ts'
|
||||
import { resolvedClientTimeZone } from '../time-zone.ts'
|
||||
@@ -134,11 +136,13 @@ export class Session implements SessionFace {
|
||||
/**
|
||||
* @param sessionId - Host session identity (client sessions are always Host-born).
|
||||
* @param api - shared wire client.
|
||||
* @param remote - generated Remote namespaces this session calls.
|
||||
* @param options - optional manager-owned state observers.
|
||||
*/
|
||||
constructor(
|
||||
readonly sessionId: SessionId,
|
||||
private readonly api: IApiClient,
|
||||
private readonly remote: SessionRemotes,
|
||||
private readonly options: SessionOptions = {},
|
||||
) {
|
||||
this.projections = options.projections ?? new ProjectionValueStore()
|
||||
@@ -351,12 +355,10 @@ export class Session implements SessionFace {
|
||||
* @param line - the full command line, leading slash included.
|
||||
* @returns the admission result, or the error branch on transport failure.
|
||||
*/
|
||||
async command(line: string): Promise<RpcResult<{ matched: boolean }>> {
|
||||
try {
|
||||
return (await this.api.commands.execute({ sessionId: this.sessionId, line })).result
|
||||
} catch (error) {
|
||||
return transportError(error)
|
||||
}
|
||||
async command(line: string): Promise<RemoteResult<{ matched: boolean }>> {
|
||||
const result = await this.remote.commands.execute(this.sessionId, line)
|
||||
if (!result.ok) return result
|
||||
return { ok: true, value: { matched: result.value !== undefined } }
|
||||
}
|
||||
|
||||
/** First open: pull the tail page (idempotent — in-flight/already-open returns the existing promise). */
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* uninterrupted subagent subtree.
|
||||
* @module @deepseek-ai/dsh-client-runtime/client/sessions/subagent-lineage
|
||||
*/
|
||||
import type { SessionId } from '@deepseek-ai/dsh-client-connection/client'
|
||||
import type { SessionId } from '@deepseek-ai/dsh-api-remotes/client'
|
||||
import type { SessionSummary } from './service.ts'
|
||||
|
||||
/** Descendant counts projected for one possible parent session. */
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import type {
|
||||
HostFrame, IApiClient, RpcError, RpcRequest, RpcResult, SessionId, WorkspaceId, WorkspaceView,
|
||||
} from '@deepseek-ai/dsh-client-connection/client'
|
||||
} from '@deepseek-ai/dsh-api-remotes/client'
|
||||
import { transportError } from '@deepseek-ai/dsh-host-apiproxy/api'
|
||||
import { mergeOrderedBaseline } from '../ordered-baseline.ts'
|
||||
import { Notifier } from '../sessions/notifier.ts'
|
||||
|
||||
@@ -4,7 +4,7 @@ import type { Context } from '@deepseek-ai/cordis'
|
||||
import type {
|
||||
DirectoryListing, IApiClient, RpcError,
|
||||
SessionId, WorkspaceId, WorkspaceView,
|
||||
} from '@deepseek-ai/dsh-client-connection/client'
|
||||
} from '@deepseek-ai/dsh-api-remotes/client'
|
||||
import type { SnapshotStore } from '../contract/store.ts'
|
||||
import { createSnapshotStore } from '../contract/store.ts'
|
||||
import type { SessionsPort, SessionsPortList } from '../contract/sessions-port.ts'
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import type {
|
||||
IApiClient, RpcResult, WorkspaceView,
|
||||
} from '@deepseek-ai/dsh-client-connection/client'
|
||||
} from '@deepseek-ai/dsh-api-remotes/client'
|
||||
import { transportError } from '@deepseek-ai/dsh-host-apiproxy/api'
|
||||
import type { ObservableSnapshot } from '../contract/store.ts'
|
||||
import { Notifier } from '../sessions/notifier.ts'
|
||||
|
||||
Reference in New Issue
Block a user