feat(gui): goal wire domain, client goal state, and docked goal bar
- apiproxy goals RPC domain (get/create/edit/pause/resume/complete/clear) with CAS refs, zod schemas, and fetch client/handler wiring - client runtime session goal state: live goal/change meta triggers a coalesced refetch; mutations fold transport errors into RpcResult - web GoalBar: docked strip above the composer (sparkle, phase label, truncated objective, inline edit, clear; resume when paused); creation stays on the /goal command - GoalBarActions in the ui-conversation contract layer; IconSparkle16 moves to ui-primitives icons
This commit is contained in:
88
packages/host/apiproxy/src/api/goals.ts
Normal file
88
packages/host/apiproxy/src/api/goals.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* goals domain contract. Method signatures are the source of truth:
|
||||
* unary methods take the RpcRequest<P> narrow form and the impl echoes rpcId.
|
||||
*/
|
||||
|
||||
import type { Branded } from '@deepseek-ai/dsh-brand'
|
||||
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
|
||||
}
|
||||
|
||||
/** Durable continuation phase. */
|
||||
export type GoalPhase =
|
||||
| 'active'
|
||||
| 'paused'
|
||||
| 'blocked'
|
||||
| 'complete'
|
||||
|
||||
/** Machine-routable and human-readable explanation for a blocked goal. */
|
||||
export interface GoalBlockReason {
|
||||
readonly code: string
|
||||
readonly message: string
|
||||
}
|
||||
|
||||
/** Whether this live process may automatically continue an active goal. */
|
||||
export type GoalActivation = 'armed' | 'disarmed'
|
||||
|
||||
/** Current goal projection, including values derived from the session log. */
|
||||
export interface GoalView {
|
||||
readonly id: GoalId
|
||||
readonly revision: number
|
||||
readonly objective: string
|
||||
readonly phase: GoalPhase
|
||||
readonly blockedReason?: GoalBlockReason
|
||||
readonly maxGoalRounds: number
|
||||
readonly roundsStarted: number
|
||||
readonly createdAt: number
|
||||
readonly updatedAt: number
|
||||
readonly activation: GoalActivation
|
||||
}
|
||||
|
||||
/** Input whose omitted round cap is resolved by the service configuration. */
|
||||
export interface CreateGoalRequest {
|
||||
readonly objective: string
|
||||
readonly maxGoalRounds?: number
|
||||
}
|
||||
|
||||
/** Fields changed by an edit; at least one must be present. */
|
||||
export interface EditGoalRequest {
|
||||
readonly objective?: string
|
||||
readonly maxGoalRounds?: number
|
||||
}
|
||||
|
||||
/** Goal-domain unary methods. */
|
||||
export interface GoalsApi {
|
||||
/** Read the current goal for one session. Returns null when no goal is current. */
|
||||
get(request: RpcRequest<{ sessionId: string }>): Promise<RpcResponse<{ goal: GoalView | null }>>
|
||||
|
||||
/** Create and arm a goal. */
|
||||
create(request: RpcRequest<{ sessionId: string; objective: string; maxGoalRounds?: number }>):
|
||||
Promise<RpcResponse<{ goal: GoalView }>>
|
||||
|
||||
/** Edit objective and/or round cap without changing phase. */
|
||||
edit(request: RpcRequest<{ sessionId: string; ref: GoalRef; objective?: string; maxGoalRounds?: number }>):
|
||||
Promise<RpcResponse<{ goal: GoalView }>>
|
||||
|
||||
/** Pause an active goal and disarm automatic continuation. */
|
||||
pause(request: RpcRequest<{ sessionId: string; ref: GoalRef }>):
|
||||
Promise<RpcResponse<{ goal: GoalView }>>
|
||||
|
||||
/** Resume and arm a stopped goal. */
|
||||
resume(request: RpcRequest<{ sessionId: string; ref: GoalRef }>):
|
||||
Promise<RpcResponse<{ goal: GoalView }>>
|
||||
|
||||
/** Mark a current non-complete goal complete and disarm it. */
|
||||
complete(request: RpcRequest<{ sessionId: string; ref: GoalRef }>):
|
||||
Promise<RpcResponse<{ goal: GoalView }>>
|
||||
|
||||
/** Clear the current goal while retaining a durable tombstone and history. */
|
||||
clear(request: RpcRequest<{ sessionId: string; ref: GoalRef }>):
|
||||
Promise<RpcResponse<{ cleared: true }>>
|
||||
}
|
||||
Reference in New Issue
Block a user