diff --git a/packages/api/session-controller/tests/fake-api.client.ts b/packages/api/session-controller/tests/fake-api.client.ts index c0a1b1b780..9415ef74eb 100644 --- a/packages/api/session-controller/tests/fake-api.client.ts +++ b/packages/api/session-controller/tests/fake-api.client.ts @@ -255,15 +255,6 @@ export class FakeApiClient implements IApiClient { list: (payload: unknown) => this.record('skill.list', payload, this.onSkillList(payload)), } - readonly goals: IApiClient['goals'] = { - create: payload => this.record('goal.create', payload, Promise.resolve(ok({ ref: { id: 'fake-goal' as never, revision: 1 } }))), - edit: payload => this.record('goal.edit', payload, Promise.resolve(ok({ ref: { id: 'fake-goal' as never, revision: 1 } }))), - pause: payload => this.record('goal.pause', payload, Promise.resolve(ok({ ref: { id: 'fake-goal' as never, revision: 1 } }))), - resume: payload => this.record('goal.resume', payload, Promise.resolve(ok({ ref: { id: 'fake-goal' as never, revision: 1 } }))), - complete: payload => this.record('goal.complete', payload, Promise.resolve(ok({ ref: { id: 'fake-goal' as never, revision: 1 } }))), - clear: payload => this.record('goal.clear', payload, Promise.resolve(ok({ cleared: true as const }))), - } - readonly settings: IApiClient['settings'] = { describe: payload => this.record('settings.describe', payload, Promise.resolve(ok({ writable: true, hasDocument: false, namespaces: [] }))), openDocument: payload => this.record('settings.openDocument', payload, Promise.resolve(ok({ opened: true as const }))), diff --git a/packages/client/connection/src/client/api.ts b/packages/client/connection/src/client/api.ts index 2d0170cb5f..a0ea093533 100644 --- a/packages/client/connection/src/client/api.ts +++ b/packages/client/connection/src/client/api.ts @@ -12,7 +12,6 @@ export type { SkillsApi, SkillEntry, ModelCatalog, ModelCatalogFailure, ModelCatalogModel, ModelProviderGroup, ModelReasoning, ModelReasoningEffort, ModelSelection, - GoalsApi, GoalRef, SettingsApi, SettingsNamespaceView, SettingsPathOpView, SettingsSecretView, CredentialsApi, CredentialView, ConfigurableProviderView, DiscoveredModelView, LlmApi, SubagentsApi, SubagentAddress, SubagentCatalog, SubagentListEntry, SubagentPromptReceipt, diff --git a/packages/client/connection/src/client/fixture.ts b/packages/client/connection/src/client/fixture.ts index c27a1cae4c..b569d26f7b 100644 --- a/packages/client/connection/src/client/fixture.ts +++ b/packages/client/connection/src/client/fixture.ts @@ -2235,18 +2235,6 @@ function createFixtureWorld(options: FixtureOptions): FixtureWorld { return { ok: true, value: goalView(projection) } } - const mapGoalResult = (result: RpcResult, map: (value: T) => U): RpcResult => ( - result.ok ? { ok: true, value: map(result.value) } : result - ) - - const goalRefResult = (result: RpcResult): RpcResult<{ ref: { id: never; revision: number } }> => ( - mapGoalResult(result, view => ({ ref: { id: view.id as never, revision: view.revision } })) - ) - - const legacyGoalResponse = (request: RpcRequest

, result: RpcResult): Promise> => ( - Promise.resolve({ rpcId: request.rpcId, result }) - ) - /** At most one in-flight replay per session; cancel clears it. */ const replays = new Map; finish(aborted: boolean): void }>() @@ -3301,46 +3289,6 @@ function createFixtureWorld(options: FixtureOptions): FixtureWorld { }) }, }, - goals: { - // Compatibility face only: old API Proxy payloads and acknowledgements - // adapt to the canonical fixture Remote implementation above. - create: request => legacyGoalResponse( - request, - mapGoalResult( - goalRemotes.create(request.payload.sessionId, { - objective: request.payload.objective, - ...request.payload.maxGoalRounds === undefined ? {} : { maxGoalRounds: request.payload.maxGoalRounds }, - }), - value => ({ ref: { id: value.ref.id as never, revision: value.ref.revision } }), - ), - ), - edit: request => legacyGoalResponse( - request, - goalRefResult(goalRemotes.edit(request.payload.sessionId, request.payload.ref, { - ...request.payload.objective === undefined ? {} : { objective: request.payload.objective }, - ...request.payload.maxGoalRounds === undefined ? {} : { maxGoalRounds: request.payload.maxGoalRounds }, - })), - ), - pause: request => legacyGoalResponse( - request, - goalRefResult(goalRemotes.pause(request.payload.sessionId, request.payload.ref)), - ), - resume: request => legacyGoalResponse( - request, - goalRefResult(goalRemotes.resume(request.payload.sessionId, request.payload.ref)), - ), - complete: request => legacyGoalResponse( - request, - goalRefResult(goalRemotes.complete(request.payload.sessionId, request.payload.ref)), - ), - clear: request => legacyGoalResponse( - request, - mapGoalResult( - goalRemotes.clear(request.payload.sessionId, request.payload.ref), - () => ({ cleared: true as const }), - ), - ), - }, settings: { // Only the resolved DeepSeek address needed by first-run readiness is // represented here. Fixture-backed journeys do not open its Models @@ -3600,12 +3548,6 @@ export class FixtureApiClient extends AbstractApiClient { case 'agentPreset.copy': return this.api.agentPresets.copy(request) case 'agentPreset.openDocument': return this.api.agentPresets.openDocument(request, new AbortController().signal) case 'agentPreset.remove': return this.api.agentPresets.remove(request) - case 'goal.create': return this.api.goals.create(request) - case 'goal.edit': return this.api.goals.edit(request) - case 'goal.pause': return this.api.goals.pause(request) - case 'goal.resume': return this.api.goals.resume(request) - case 'goal.complete': return this.api.goals.complete(request) - case 'goal.clear': return this.api.goals.clear(request) case 'settings.describe': return this.api.settings.describe(request) case 'settings.openDocument': return this.api.settings.openDocument(request, signal) case 'settings.update': return this.api.settings.update(request) diff --git a/packages/client/connection/src/client/index.ts b/packages/client/connection/src/client/index.ts index 0b01c1378a..d53c48d019 100644 --- a/packages/client/connection/src/client/index.ts +++ b/packages/client/connection/src/client/index.ts @@ -39,7 +39,6 @@ export type { RpcRequest, RpcResponse, RpcResult, RpcError, RpcErrorCode, ClientRequest, ServerResponse, RpcMessage, HostDescription, IApiClient, SessionId, SessionEvent, ContentBlock, StreamChunk, - GoalsApi, GoalRef, SettingsApi, SettingsNamespaceView, SettingsPathOpView, SettingsSecretView, CredentialsApi, CredentialView, ConfigurableProviderView, DiscoveredModelView, LlmApi, } from './api.ts' diff --git a/packages/client/connection/tests/fake-api.client.ts b/packages/client/connection/tests/fake-api.client.ts index 74e153f15c..1d0266b8d0 100644 --- a/packages/client/connection/tests/fake-api.client.ts +++ b/packages/client/connection/tests/fake-api.client.ts @@ -116,15 +116,6 @@ export class FakeApiClient implements IApiClient { list: (payload: unknown) => this.record('skill.list', payload, this.onSkillList(payload)), } - readonly goals: IApiClient['goals'] = { - create: payload => this.record('goal.create', payload, Promise.resolve(ok({ ref: { id: 'fake-goal' as never, revision: 1 } }))), - edit: payload => this.record('goal.edit', payload, Promise.resolve(ok({ ref: { id: 'fake-goal' as never, revision: 1 } }))), - pause: payload => this.record('goal.pause', payload, Promise.resolve(ok({ ref: { id: 'fake-goal' as never, revision: 1 } }))), - resume: payload => this.record('goal.resume', payload, Promise.resolve(ok({ ref: { id: 'fake-goal' as never, revision: 1 } }))), - complete: payload => this.record('goal.complete', payload, Promise.resolve(ok({ ref: { id: 'fake-goal' as never, revision: 1 } }))), - clear: payload => this.record('goal.clear', payload, Promise.resolve(ok({ cleared: true as const }))), - } - readonly settings: IApiClient['settings'] = { describe: payload => this.record('settings.describe', payload, Promise.resolve(ok({ writable: true, hasDocument: false, namespaces: [] }))), openDocument: payload => this.record('settings.openDocument', payload, Promise.resolve(ok({ opened: true as const }))), diff --git a/packages/client/connection/tests/fixture.client.spec.ts b/packages/client/connection/tests/fixture.client.spec.ts index 918b802aab..0bd00622bc 100644 --- a/packages/client/connection/tests/fixture.client.spec.ts +++ b/packages/client/connection/tests/fixture.client.spec.ts @@ -1567,29 +1567,33 @@ describe('FixtureApiClient (protocol-level fake carrier)', () => { const moved = await workspaces.insertSessionBefore({ workspaceId: wsid, sessionId: attached.result.value.sessionId }) if (!moved.result.ok) throw new Error('workspace move failed') expect(moved.result.value.workspace.sessionIds).toEqual([attached.result.value.sessionId]) - // Goal lifecycle over the fixture fold: create → edit → pause → resume → complete → clear; - // every mutation acknowledges with the NEW CAS ref (state rides the projection frames). - const goalCreated = await client.goals.create({ sessionId: id, objective: 'ship it' }) - if (!goalCreated.result.ok) throw new Error('goal create failed') - let ref = goalCreated.result.value.ref - expect(ref.revision).toBe(1) - const edited = await client.goals.edit({ sessionId: id, ref, objective: 'ship it v2' }) - if (!edited.result.ok) throw new Error('goal edit failed') - ref = edited.result.value.ref - const paused = await client.goals.pause({ sessionId: id, ref }) - if (!paused.result.ok) throw new Error('goal pause failed') - ref = paused.result.value.ref - const resumed = await client.goals.resume({ sessionId: id, ref }) - if (!resumed.result.ok) throw new Error('goal resume failed') - ref = resumed.result.value.ref + }) + + it('folds the goal lifecycle over the Goal Remotes', async () => { + const client = new FixtureApiClient() + const sessions = createSessionClient(client.rpc) + const created = await sessions.create({}) + if (!created.result.ok) throw new Error('create failed') + const id = created.result.value.sessionId + const goal = (endpoint: string, args: Record) => + client.rpc.call('/api', endpoint, { args: { agentId: id, ...args } }) + + // create → edit → pause → resume → complete → clear; each mutation advances the CAS + // revision by one (state rides the projection frames). + const goalCreated = await goal('goals/create', { request: { objective: 'ship it' } }) + if (!goalCreated.ok) throw new Error('goal create failed') + const { id: goalId, revision } = (goalCreated.value as { ref: { id: string; revision: number } }).ref + expect(revision).toBe(1) + const ref = (at: number) => ({ id: goalId, revision: at }) + expect((await goal('goals/edit', { ref: ref(1), request: { objective: 'ship it v2' } })).ok).toBe(true) + expect((await goal('goals/pause', { ref: ref(2) })).ok).toBe(true) + expect((await goal('goals/resume', { ref: ref(3) })).ok).toBe(true) // A stale ref loses the CAS check. - expect((await client.goals.pause({ sessionId: id, ref: { ...ref, revision: 1 } })).result.ok).toBe(false) - const completed = await client.goals.complete({ sessionId: id, ref }) - if (!completed.result.ok) throw new Error('goal complete failed') - ref = completed.result.value.ref + expect((await goal('goals/pause', { ref: ref(1) })).ok).toBe(false) + expect((await goal('goals/complete', { ref: ref(4) })).ok).toBe(true) // complete → complete is an invalid transition. - expect((await client.goals.complete({ sessionId: id, ref })).result.ok).toBe(false) - expect((await client.goals.clear({ sessionId: id, ref })).result).toEqual({ ok: true, value: { cleared: true } }) + expect((await goal('goals/complete', { ref: ref(5) })).ok).toBe(false) + expect(await goal('goals/clear', { ref: ref(5) })).toEqual({ ok: true, value: ref(6) }) const goalHistory = await sessions.history({ sessionId: id }) if (!goalHistory.result.ok) throw new Error('goal history failed') diff --git a/packages/client/ui-workspace/tests/workspaces-service.client.spec.ts b/packages/client/ui-workspace/tests/workspaces-service.client.spec.ts index 9c2dfd4fb8..ad9baff764 100644 --- a/packages/client/ui-workspace/tests/workspaces-service.client.spec.ts +++ b/packages/client/ui-workspace/tests/workspaces-service.client.spec.ts @@ -188,7 +188,6 @@ class FakeApiClient implements IApiClient { declare readonly subagents: IApiClient['subagents'] declare readonly skills: IApiClient['skills'] declare readonly agentPresets: IApiClient['agentPresets'] - declare readonly goals: IApiClient['goals'] declare readonly settings: IApiClient['settings'] declare readonly credentials: IApiClient['credentials'] declare readonly llm: IApiClient['llm'] diff --git a/packages/host/apiproxy/src/api-proxy.ts b/packages/host/apiproxy/src/api-proxy.ts index 1a8835383a..56b90e64f2 100644 --- a/packages/host/apiproxy/src/api-proxy.ts +++ b/packages/host/apiproxy/src/api-proxy.ts @@ -6,7 +6,7 @@ import { homedir } from 'node:os' import { dirname } from 'node:path' import type { Context } from '@deepseek-ai/cordis' -import type { Agent, ModelSelection } from '@deepseek-ai/dsh-agent' +import type { ModelSelection } from '@deepseek-ai/dsh-agent' import type {} from '@deepseek-ai/dsh-agent-presets/types' import type { Session, SessionId } from '@deepseek-ai/dsh-session' import { SubagentError } from '@deepseek-ai/dsh-subagent' @@ -16,7 +16,7 @@ import { PresetNotWritableError, UnknownPresetError, } from '@deepseek-ai/dsh-agent-presets' import type { - ApiProxy, ConfigurableProviderView, CredentialView, GoalRef, + ApiProxy, ConfigurableProviderView, CredentialView, SettingsNamespaceView, } from './api/index.ts' import type { SessionRequestId } from '@deepseek-ai/dsh-api-session-controller/types' @@ -32,9 +32,6 @@ import { type SessionLogCompressionLevel, } from './session-export.ts' import type { SessionRawArtifact } from '@deepseek-ai/dsh-session-persistence' -// GoalError narrows domain rejections to their stable codes at the wire boundary. -import { GoalError } from '@deepseek-ai/dsh-goal' -import type { GoalRef as CoreGoalRef } from '@deepseek-ai/dsh-goal' // Type-only edges: resolve the command-change stream and `ctx.get('skills')`. import type {} from '@deepseek-ai/dsh-commands' import type {} from '@deepseek-ai/dsh-skill' @@ -270,47 +267,6 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro } } - /** - * Resolve the goal service THIS agent runs. - * - * The service is per session: an agent preset mounts it behind an `isolate` - * realm, which no host context resolves. Reading it from the root would - * answer "absent" for a session whose composition mounts it — so the lookup - * is keyed by the agent, and only a deployment composing it nowhere is - * genuinely absent. - */ - function goalServiceFor(agent: Agent): NonNullable>> | { error: RpcError } { - const presets = ctx.get('agentPresets') - const goals = presets?.serviceFor(agent, 'goals') ?? ctx.get('goals') - if (goals === undefined) { - return { error: { code: 'internal', message: 'goal service is absent: neither this session\'s agent preset nor the host composition mounts @deepseek-ai/dsh-goal', details: {} } } - } - return goals - } - - /** Map one goal-domain rejection to the wire error (stable GoalError codes ride in details). */ - function goalError(request: RpcRequest, error: unknown): RpcResponse { - const details = error instanceof GoalError ? { goalCode: error.code } : {} - return err(request, { code: 'internal', message: String(error), details }) - } - - /** Resolve a session's agent, apply one goal mutation, and acknowledge with the new CAS ref. */ - async function mutateGoal( - request: RpcRequest<{ sessionId: SessionId }>, - mutation: (goals: NonNullable>>, agent: Agent) => CoreGoalRef, - ): Promise> { - const found = await agentFor(request.payload.sessionId) - if ('error' in found) return err(request, found.error) - const goals = goalServiceFor(found.agent) - if ('error' in goals) return err(request, goals.error) - try { - const ref = mutation(goals, found.agent) - return ok(request, { ref: { id: ref.id, revision: ref.revision } }) - } catch (error: unknown) { - return goalError(request, error) - } - } - /** 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-file) in its composition', details: {} } @@ -623,54 +579,6 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro }, }, - goals: { - // Mutations only — the read side is the 'goal' session projection. - // Every verb resolves the session's agent (agentFor: implicit cold - // resume, the command.* precedent) and acknowledges with the new CAS - // ref; the committed goal/change event carries the whole value to every - // client through the projection frames. - async create(request) { - const { objective, maxGoalRounds } = request.payload - return mutateGoal(request, (goals, agent) => goals.create(agent, { - objective, - ...(maxGoalRounds !== undefined ? { maxGoalRounds } : {}), - })) - }, - - async edit(request) { - const { ref, objective, maxGoalRounds } = request.payload - return mutateGoal(request, (goals, agent) => goals.edit(agent, ref, { - ...(objective !== undefined ? { objective } : {}), - ...(maxGoalRounds !== undefined ? { maxGoalRounds } : {}), - })) - }, - - async pause(request) { - return mutateGoal(request, (goals, agent) => goals.pause(agent, request.payload.ref)) - }, - - async resume(request) { - return mutateGoal(request, (goals, agent) => goals.resume(agent, request.payload.ref)) - }, - - async complete(request) { - return mutateGoal(request, (goals, agent) => goals.complete(agent, request.payload.ref)) - }, - - async clear(request) { - const found = await agentFor(request.payload.sessionId) - if ('error' in found) return err(request, found.error) - const goals = goalServiceFor(found.agent) - if ('error' in goals) return err(request, goals.error) - try { - goals.clear(found.agent, request.payload.ref) - return ok(request, { cleared: true as const }) - } catch (error: unknown) { - return goalError(request, error) - } - }, - }, - agentPresets: { // A deployment with no roster answers with an empty list rather than an // error: composing no presets is a valid deployment, and the browser diff --git a/packages/host/apiproxy/src/api/goals.schema.ts b/packages/host/apiproxy/src/api/goals.schema.ts deleted file mode 100644 index 24615502c3..0000000000 --- a/packages/host/apiproxy/src/api/goals.schema.ts +++ /dev/null @@ -1,79 +0,0 @@ -/** - * goals domain zod schemas. Mutation-only shapes: every value schema is a - * `{ ref }` acknowledgement (clear: `{ cleared }`) — the current goal state - * travels exclusively on the 'goal' session projection. - */ - -import { z } from 'zod' -import type { Wire } from './rpc.schema.ts' -import type { GoalRef, RequestPayload, ResponseValue } from './index.ts' - -/** GoalRef schema. */ -export const goalRefSchema = z.object({ - id: z.string(), - revision: z.number().int().positive(), -}) as unknown as z.ZodType> - -/** Shared `{ ref }` acknowledgement value of every non-clear mutation. */ -const goalRefValueSchema = z.object({ ref: goalRefSchema }) - -/** goal.create request payload. */ -export const goalCreateRequestSchema = z.object({ - sessionId: z.string(), - objective: z.string().min(1), - maxGoalRounds: z.number().int().positive().optional(), -}) as unknown as z.ZodType>> - -/** goal.create response value. */ -export const goalCreateValueSchema = goalRefValueSchema as unknown as z.ZodType>> - -/** goal.edit request payload. */ -export const goalEditRequestSchema = z.object({ - sessionId: z.string(), - ref: goalRefSchema, - objective: z.string().min(1).optional(), - maxGoalRounds: z.number().int().positive().optional(), -}).refine(value => value.objective !== undefined || value.maxGoalRounds !== undefined, { - message: 'goal.edit requires objective or maxGoalRounds', -}) as unknown as z.ZodType>> - -/** goal.edit response value. */ -export const goalEditValueSchema = goalRefValueSchema as unknown as z.ZodType>> - -/** goal.pause request payload. */ -export const goalPauseRequestSchema = z.object({ - sessionId: z.string(), - ref: goalRefSchema, -}) as unknown as z.ZodType>> - -/** goal.pause response value. */ -export const goalPauseValueSchema = goalRefValueSchema as unknown as z.ZodType>> - -/** goal.resume request payload. */ -export const goalResumeRequestSchema = z.object({ - sessionId: z.string(), - ref: goalRefSchema, -}) as unknown as z.ZodType>> - -/** goal.resume response value. */ -export const goalResumeValueSchema = goalRefValueSchema as unknown as z.ZodType>> - -/** goal.complete request payload. */ -export const goalCompleteRequestSchema = z.object({ - sessionId: z.string(), - ref: goalRefSchema, -}) as unknown as z.ZodType>> - -/** goal.complete response value. */ -export const goalCompleteValueSchema = goalRefValueSchema as unknown as z.ZodType>> - -/** goal.clear request payload. */ -export const goalClearRequestSchema = z.object({ - sessionId: z.string(), - ref: goalRefSchema, -}) as unknown as z.ZodType>> - -/** goal.clear response value. */ -export const goalClearValueSchema = z.object({ - cleared: z.literal(true), -}) as unknown as z.ZodType>> diff --git a/packages/host/apiproxy/src/api/goals.ts b/packages/host/apiproxy/src/api/goals.ts deleted file mode 100644 index abf6e53a07..0000000000 --- a/packages/host/apiproxy/src/api/goals.ts +++ /dev/null @@ -1,53 +0,0 @@ -/** - * goals domain contract. Method signatures are the source of truth: - * unary methods take the RpcRequest

narrow form and the impl echoes rpcId. - * - * Mutations only: the read side is the `goal` Session projection carried by - * Session Controller history and control streams. There is no goal.get or - * separate wire goal view; responses acknowledge with the new CAS ref, and - * committed goal/change events update the projection. - */ - -import type { Branded } from '@deepseek-ai/dsh-brand' -import type { SessionId } from '@deepseek-ai/dsh-session/types' -import type { RpcRequest, RpcResponse } from './rpc.ts' - -/** Identifies one goal across its durable revisions. */ -export type GoalId = Branded<'GoalId'> - -/** Compare-and-set identity for one exact goal revision. */ -export interface GoalRef { - readonly id: GoalId - readonly revision: number -} - -/** - * Goal-domain unary methods. Every mutation resolves an ordinary session's - * Agent and applies one CAS-guarded verb; session-backed subagents reject with - * `agent-busy`. - */ -export interface GoalsApi { - /** Create and arm a goal. */ - create(request: RpcRequest<{ sessionId: SessionId; objective: string; maxGoalRounds?: number }>): - Promise> - - /** Edit objective and/or round cap without changing phase. */ - edit(request: RpcRequest<{ sessionId: SessionId; ref: GoalRef; objective?: string; maxGoalRounds?: number }>): - Promise> - - /** Pause an active goal and disarm automatic continuation. */ - pause(request: RpcRequest<{ sessionId: SessionId; ref: GoalRef }>): - Promise> - - /** Resume and arm a stopped goal. */ - resume(request: RpcRequest<{ sessionId: SessionId; ref: GoalRef }>): - Promise> - - /** Mark a current non-complete goal complete and disarm it. */ - complete(request: RpcRequest<{ sessionId: SessionId; ref: GoalRef }>): - Promise> - - /** Clear the current goal while retaining a durable tombstone and history. */ - clear(request: RpcRequest<{ sessionId: SessionId; ref: GoalRef }>): - Promise> -} diff --git a/packages/host/apiproxy/src/api/index.ts b/packages/host/apiproxy/src/api/index.ts index 4cfcea6418..5ab6e52043 100644 --- a/packages/host/apiproxy/src/api/index.ts +++ b/packages/host/apiproxy/src/api/index.ts @@ -8,7 +8,6 @@ import type { HostApi } from './host.ts' import type { AgentPresetsApi } from './agent-presets.ts' import type { SkillsApi } from './skills.ts' import type { SubagentsApi } from './subagents.ts' -import type { GoalsApi } from './goals.ts' import type { SettingsApi } from './settings.ts' import type { CredentialsApi } from './credentials.ts' import type { LlmApi } from './llm.ts' @@ -20,7 +19,6 @@ export interface ApiProxy { host: HostApi skills: SkillsApi agentPresets: AgentPresetsApi - goals: GoalsApi settings: SettingsApi credentials: CredentialsApi llm: LlmApi @@ -40,7 +38,6 @@ export type { } from './subagents.ts' export type { SkillsApi, SkillEntry } from './skills.ts' export type { AgentPresetsApi, AgentPresetEntry } from './agent-presets.ts' -export type { GoalsApi, GoalId, GoalRef } from './goals.ts' export type { SettingsApi, SettingsNamespaceView, SettingsPathOpView, SettingsSecretView } from './settings.ts' export type { CredentialsApi, CredentialView } from './credentials.ts' export type { ConfigurableProviderView, DiscoveredModelView, LlmApi } from './llm.ts' diff --git a/packages/host/apiproxy/src/api/rpc-map.ts b/packages/host/apiproxy/src/api/rpc-map.ts index b24c5d9dfe..edeb2d10a8 100644 --- a/packages/host/apiproxy/src/api/rpc-map.ts +++ b/packages/host/apiproxy/src/api/rpc-map.ts @@ -6,7 +6,6 @@ import type { HostApi } from './host.ts' import type { AgentPresetsApi } from './agent-presets.ts' import type { SkillsApi } from './skills.ts' -import type { GoalsApi } from './goals.ts' import type { SettingsApi } from './settings.ts' import type { CredentialsApi } from './credentials.ts' import type { LlmApi } from './llm.ts' @@ -34,12 +33,6 @@ export interface RpcMethodMap { 'agentPreset.copy': AgentPresetsApi['copy'] 'agentPreset.openDocument': AgentPresetsApi['openDocument'] 'agentPreset.remove': AgentPresetsApi['remove'] - 'goal.create': GoalsApi['create'] - 'goal.edit': GoalsApi['edit'] - 'goal.pause': GoalsApi['pause'] - 'goal.resume': GoalsApi['resume'] - 'goal.complete': GoalsApi['complete'] - 'goal.clear': GoalsApi['clear'] 'settings.describe': SettingsApi['describe'] 'settings.openDocument': SettingsApi['openDocument'] 'settings.update': SettingsApi['update'] diff --git a/packages/host/apiproxy/src/fetch/client.ts b/packages/host/apiproxy/src/fetch/client.ts index 8cb839d20a..c68ca65410 100644 --- a/packages/host/apiproxy/src/fetch/client.ts +++ b/packages/host/apiproxy/src/fetch/client.ts @@ -21,14 +21,6 @@ import { agentPresetCopyValueSchema, agentPresetListValueSchema, agentPresetOpenDocumentValueSchema, agentPresetReadValueSchema, agentPresetRemoveValueSchema, agentPresetSelectValueSchema, } from '../api/agent-presets.schema.ts' -import { - goalCreateValueSchema, - goalEditValueSchema, - goalPauseValueSchema, - goalResumeValueSchema, - goalCompleteValueSchema, - goalClearValueSchema, -} from '../api/goals.schema.ts' import { settingsDescribeValueSchema, settingsMutateValueSchema, settingsOpenDocumentValueSchema, settingsReplaceValueSchema, settingsUpdateValueSchema, @@ -79,14 +71,6 @@ export interface IApiClient { openDocument(payload: RequestPayload<'agentPreset.openDocument'>, signal?: AbortSignal): Promise>> remove(payload: RequestPayload<'agentPreset.remove'>, signal?: AbortSignal): Promise>> } - goals: { - create(payload: RequestPayload<'goal.create'>, signal?: AbortSignal): Promise>> - edit(payload: RequestPayload<'goal.edit'>, signal?: AbortSignal): Promise>> - pause(payload: RequestPayload<'goal.pause'>, signal?: AbortSignal): Promise>> - resume(payload: RequestPayload<'goal.resume'>, signal?: AbortSignal): Promise>> - complete(payload: RequestPayload<'goal.complete'>, signal?: AbortSignal): Promise>> - clear(payload: RequestPayload<'goal.clear'>, signal?: AbortSignal): Promise>> - } settings: { describe(payload: RequestPayload<'settings.describe'>, signal?: AbortSignal): Promise>> openDocument(payload: RequestPayload<'settings.openDocument'>, signal?: AbortSignal): Promise>> @@ -126,12 +110,6 @@ const UNARY_VALUE_SCHEMAS: { [K in keyof RpcMethodMap]: z.ZodType this.callUnary('agentPreset.remove', payload, signal), } - readonly goals: IApiClient['goals'] = { - create: (payload, signal) => this.callUnary('goal.create', payload, signal), - edit: (payload, signal) => this.callUnary('goal.edit', payload, signal), - pause: (payload, signal) => this.callUnary('goal.pause', payload, signal), - resume: (payload, signal) => this.callUnary('goal.resume', payload, signal), - complete: (payload, signal) => this.callUnary('goal.complete', payload, signal), - clear: (payload, signal) => this.callUnary('goal.clear', payload, signal), - } - readonly settings: IApiClient['settings'] = { describe: (payload, signal) => this.callUnary('settings.describe', payload, signal), openDocument: (payload, signal) => this.callUnary('settings.openDocument', payload, signal), diff --git a/packages/host/apiproxy/src/fetch/handler.ts b/packages/host/apiproxy/src/fetch/handler.ts index 7e3a86cfe6..5ba7197cbb 100644 --- a/packages/host/apiproxy/src/fetch/handler.ts +++ b/packages/host/apiproxy/src/fetch/handler.ts @@ -24,14 +24,6 @@ import { agentPresetCopyRequestSchema, agentPresetListRequestSchema, agentPresetOpenDocumentRequestSchema, agentPresetReadRequestSchema, agentPresetRemoveRequestSchema, agentPresetSelectRequestSchema, } from '../api/agent-presets.schema.ts' -import { - goalCreateRequestSchema, - goalEditRequestSchema, - goalPauseRequestSchema, - goalResumeRequestSchema, - goalCompleteRequestSchema, - goalClearRequestSchema, -} from '../api/goals.schema.ts' import { settingsDescribeRequestSchema, settingsMutateRequestSchema, settingsOpenDocumentRequestSchema, settingsReplaceRequestSchema, settingsUpdateRequestSchema, @@ -78,12 +70,6 @@ const UNARY_ROUTES: UnaryRoutes = { 'agentPreset.copy': { schema: agentPresetCopyRequestSchema, invoke: (api, r) => api.agentPresets.copy(r) }, 'agentPreset.openDocument': { schema: agentPresetOpenDocumentRequestSchema, invoke: (api, r, signal) => api.agentPresets.openDocument(r, signal) }, 'agentPreset.remove': { schema: agentPresetRemoveRequestSchema, invoke: (api, r) => api.agentPresets.remove(r) }, - 'goal.create': { schema: goalCreateRequestSchema, invoke: (api, r) => api.goals.create(r) }, - 'goal.edit': { schema: goalEditRequestSchema, invoke: (api, r) => api.goals.edit(r) }, - 'goal.pause': { schema: goalPauseRequestSchema, invoke: (api, r) => api.goals.pause(r) }, - 'goal.resume': { schema: goalResumeRequestSchema, invoke: (api, r) => api.goals.resume(r) }, - 'goal.complete': { schema: goalCompleteRequestSchema, invoke: (api, r) => api.goals.complete(r) }, - 'goal.clear': { schema: goalClearRequestSchema, invoke: (api, r) => api.goals.clear(r) }, 'settings.describe': { schema: settingsDescribeRequestSchema, invoke: (api, r) => api.settings.describe(r) }, 'settings.openDocument': { schema: settingsOpenDocumentRequestSchema, invoke: (api, r, signal) => api.settings.openDocument(r, signal) }, 'settings.update': { schema: settingsUpdateRequestSchema, invoke: (api, r) => api.settings.update(r) }, diff --git a/packages/host/apiproxy/src/index.ts b/packages/host/apiproxy/src/index.ts index 546ad8d336..98ee7eca20 100644 --- a/packages/host/apiproxy/src/index.ts +++ b/packages/host/apiproxy/src/index.ts @@ -74,7 +74,6 @@ export class ApiProxyService extends Service implements ApiProxy { readonly subagents: ApiProxy['subagents'] readonly host: ApiProxy['host'] - readonly goals: ApiProxy['goals'] readonly skills: ApiProxy['skills'] readonly agentPresets: ApiProxy['agentPresets'] readonly settings: ApiProxy['settings'] @@ -94,7 +93,6 @@ export class ApiProxyService extends Service implements ApiProxy { }) this.subagents = api.subagents this.host = api.host - this.goals = api.goals this.skills = api.skills this.agentPresets = api.agentPresets this.settings = api.settings diff --git a/packages/host/apiproxy/tests/api-proxy-agent-preset.spec.ts b/packages/host/apiproxy/tests/api-proxy-agent-preset.spec.ts index ce7942cf38..990b658c9d 100644 --- a/packages/host/apiproxy/tests/api-proxy-agent-preset.spec.ts +++ b/packages/host/apiproxy/tests/api-proxy-agent-preset.spec.ts @@ -13,7 +13,6 @@ import { agentPresetProjectionDefinition, InvalidPresetIdError, PresetExistsError, UnknownPresetError, } from '@deepseek-ai/dsh-agent-presets' import type {} from '@deepseek-ai/dsh-agent-presets/types' -import { GoalId } from '@deepseek-ai/dsh-goal' import { createApiProxy } from '../src/api-proxy.ts' import { describe, expect, it } from 'vitest' import { SessionQueryError, type SessionObservation } from '@deepseek-ai/dsh-session-query' @@ -210,23 +209,6 @@ async function harness( * instance through the agent instead of reading a root-realm singleton. */ describe('a capability the session\'s preset mounts', () => { - it('serves the goal RPC from the session\'s own goal service', async () => { - const { api } = await harness(['standard']) - await createSession(api, { sessionId: SessionId('g1'), agentPreset: 'standard' }) - const ref = { id: GoalId('goal-1'), revision: 1 } - const paused: unknown[] = [] - services.set('g1', { - goals: { pause: (agent: { id: unknown }, r: unknown) => { paused.push([String(agent.id), r]); return ref } }, - }) - - const response = await api.goals.pause(request({ sessionId: SessionId('g1'), ref })) - - expect(response.result).toMatchObject({ ok: true, value: { ref } }) - // Reached the instance this session mounted, and was handed its own agent. - expect(paused).toEqual([['g1', ref]]) - services.delete('g1') - }) - it('serves the skill catalog from the session\'s own registry', async () => { const { api } = await harness(['standard']) await createSession(api, { sessionId: SessionId('k1'), agentPreset: 'standard' }) diff --git a/packages/host/apiproxy/tests/client-handler.spec.ts b/packages/host/apiproxy/tests/client-handler.spec.ts index 09509a0782..6f5fd528f0 100644 --- a/packages/host/apiproxy/tests/client-handler.spec.ts +++ b/packages/host/apiproxy/tests/client-handler.spec.ts @@ -7,7 +7,7 @@ import { describe, expect, it, vi } from 'vitest' import type { SessionId } from '@deepseek-ai/dsh-session' -import type { ApiProxy, GoalRef, RpcMessage, RpcRequest, RpcResponse } from '@deepseek-ai/dsh-host-apiproxy' +import type { ApiProxy, RpcMessage, RpcRequest, RpcResponse } from '@deepseek-ai/dsh-host-apiproxy' import { InProcessApiClient, RpcId, toFetchHandler } from '@deepseek-ai/dsh-host-apiproxy' const sid = (id: string): SessionId => id as SessionId @@ -22,7 +22,6 @@ function scriptedApi(overrides: { host?: Partial skills?: Partial agentPresets?: Partial - goals?: Partial settings?: Partial credentials?: Partial llm?: Partial @@ -56,15 +55,6 @@ function scriptedApi(overrides: { remove: r => ok(r, {}), ...overrides.agentPresets, }, - goals: { - create: err, - edit: err, - pause: err, - resume: err, - complete: err, - clear: err, - ...overrides.goals, - }, settings: { describe: r => ok(r, { writable: true, hasDocument: false, namespaces: [] }), openDocument: r => ok(r, { opened: true as const }), @@ -309,63 +299,6 @@ describe('unary round trip', () => { }) }) -describe('goals unary surface', () => { - const ref: GoalRef = { id: 'goal-1' as GoalRef['id'], revision: 1 } - /** The `{ ref }` acknowledgement every non-clear mutation answers (state travels on the projection). */ - const ack = { ref: { id: 'goal-1' as GoalRef['id'], revision: 2 } } - - it('round-trips every goal method with its own payload and value shape', async () => { - const seen: { method: string; payload: unknown }[] = [] - const record = recorderInto(seen) - const api = scriptedApi({ - goals: { - create: record('goal.create', r => ok(r, ack)), - edit: record('goal.edit', r => ok(r, { ref: { ...ack.ref, revision: 3 } })), - pause: record('goal.pause', r => ok(r, ack)), - resume: record('goal.resume', r => ok(r, ack)), - complete: record('goal.complete', r => ok(r, ack)), - clear: record('goal.clear', r => ok(r, { cleared: true as const })), - }, - }) - const c = client(api) - - const created = await c.goals.create({ sessionId: sid('s1'), objective: 'ship it', maxGoalRounds: 4 }) - expect(created.result).toEqual({ ok: true, value: ack }) - const edited = await c.goals.edit({ sessionId: sid('s1'), ref, objective: 'ship v2' }) - expect(edited.result).toEqual({ ok: true, value: { ref: { ...ack.ref, revision: 3 } } }) - expect((await c.goals.pause({ sessionId: sid('s1'), ref })).result).toEqual({ ok: true, value: ack }) - expect((await c.goals.resume({ sessionId: sid('s1'), ref })).result).toEqual({ ok: true, value: ack }) - expect((await c.goals.complete({ sessionId: sid('s1'), ref })).result).toEqual({ ok: true, value: ack }) - const cleared = await c.goals.clear({ sessionId: sid('s1'), ref }) - expect(cleared.result).toEqual({ ok: true, value: { cleared: true } }) - - // The handler dispatched each call through its own route row: payload parsed per method. - expect(seen.map(s => s.method)).toEqual(['goal.create', 'goal.edit', 'goal.pause', 'goal.resume', 'goal.complete', 'goal.clear']) - expect(seen[0]?.payload).toEqual({ sessionId: 's1', objective: 'ship it', maxGoalRounds: 4 }) - expect(seen[1]?.payload).toEqual({ sessionId: 's1', ref, objective: 'ship v2' }) - }) - - it('passes business errors through as results, not throws', async () => { - // Default scripted goals impl answers an err result: it must arrive as a result, not a throw. - const failed = await client(scriptedApi()).goals.pause({ sessionId: sid('s1'), ref }) - expect(failed.result.ok).toBe(false) - if (!failed.result.ok) expect(failed.result.error.code).toBe('internal') - }) - - it('rejects an invalid goal payload at the handler as bad-request', async () => { - const response = await client(scriptedApi()).goals.create({ sessionId: sid('s1'), objective: '' }) - expect(response.result.ok).toBe(false) - if (!response.result.ok) expect(response.result.error.code).toBe('bad-request') - - let editCalls = 0 - const api = scriptedApi({ goals: { edit: (r) => { editCalls++; return ok(r, ack) } } }) - const emptyEdit = await client(api).goals.edit({ sessionId: sid('s1'), ref }) - expect(emptyEdit.result.ok).toBe(false) - if (!emptyEdit.result.ok) expect(emptyEdit.result.error.code).toBe('bad-request') - expect(editCalls).toBe(0) - }) -}) - describe('envelope tap', () => { it('delivers one microtask batch of full forms per unary call', async () => { const api = scriptedApi() diff --git a/packages/host/apiproxy/tests/fetch-carrier.spec.ts b/packages/host/apiproxy/tests/fetch-carrier.spec.ts index f16136eeff..125d2a4171 100644 --- a/packages/host/apiproxy/tests/fetch-carrier.spec.ts +++ b/packages/host/apiproxy/tests/fetch-carrier.spec.ts @@ -87,26 +87,6 @@ function fakeApi(overrides: Partial<{ crashOn: string }> = {}): ApiProxy { return { rpcId: request.rpcId, result: { ok: true, value: { skills: [{ name: 'commit-helper', description: 'Git commits', modelInvocable: true }] } } } }, }, - goals: { - async create(request) { - return { rpcId: request.rpcId, result: { ok: false, error: { code: 'internal', message: 'stub', details: {} } } } - }, - async edit(request) { - return { rpcId: request.rpcId, result: { ok: false, error: { code: 'internal', message: 'stub', details: {} } } } - }, - async pause(request) { - return { rpcId: request.rpcId, result: { ok: false, error: { code: 'internal', message: 'stub', details: {} } } } - }, - async resume(request) { - return { rpcId: request.rpcId, result: { ok: false, error: { code: 'internal', message: 'stub', details: {} } } } - }, - async complete(request) { - return { rpcId: request.rpcId, result: { ok: false, error: { code: 'internal', message: 'stub', details: {} } } } - }, - async clear(request) { - return { rpcId: request.rpcId, result: { ok: false, error: { code: 'internal', message: 'stub', details: {} } } } - }, - }, settings: { async describe(request) { return { rpcId: request.rpcId, result: { ok: true, value: { writable: true, hasDocument: false, namespaces: [] } } } diff --git a/packages/host/apiproxy/tests/rpc-schemas.spec.ts b/packages/host/apiproxy/tests/rpc-schemas.spec.ts index 6213135c6b..3a821a8e3f 100644 --- a/packages/host/apiproxy/tests/rpc-schemas.spec.ts +++ b/packages/host/apiproxy/tests/rpc-schemas.spec.ts @@ -14,7 +14,6 @@ import { skillEntrySchema, skillListRequestSchema, skillListValueSchema } from ' import { agentPresetEntrySchema, agentPresetListValueSchema, agentPresetOpenDocumentValueSchema, } from '../src/api/agent-presets.schema.ts' -import { goalEditRequestSchema } from '../src/api/goals.schema.ts' import { subagentPromptRequestSchema } from '../src/api/subagents.schema.ts' describe('RpcId', () => { @@ -178,15 +177,6 @@ describe('skills domain schemas', () => { }) }) -describe('goals domain schemas', () => { - it('requires at least one replacement field for goal.edit', () => { - const ref = { id: 'g1', revision: 1 } - expect(goalEditRequestSchema.parse({ sessionId: 's1', ref, objective: 'updated' }).objective).toBe('updated') - expect(goalEditRequestSchema.parse({ sessionId: 's1', ref, maxGoalRounds: 3 }).maxGoalRounds).toBe(3) - expect(() => goalEditRequestSchema.parse({ sessionId: 's1', ref })).toThrow() - }) -}) - describe('agent-preset schemas', () => { it('accepts a roster row and rejects an unknown trust', () => { expect(agentPresetEntrySchema.parse({ id: 'standard', trust: 'system', isDefault: true }))