refactor(agent): trim obsolete loop surfaces
This commit is contained in:
@@ -146,17 +146,17 @@ export type AgentCancelCause =
|
||||
export type AgentInterruptReason = AgentCancelCause | { readonly kind: 'disposed' }
|
||||
|
||||
/** Public live-agent handle with aliases over the unified delivery primitive. */
|
||||
export abstract class Agent {
|
||||
export interface Agent {
|
||||
/** The single identity shared with {@link session}. */
|
||||
abstract readonly id: SessionId
|
||||
readonly id: SessionId
|
||||
/** The provider route and model this agent's requests use. */
|
||||
abstract readonly options: AgentOptions
|
||||
readonly options: AgentOptions
|
||||
/** The live session this agent drives; its log is the durable source of truth. */
|
||||
abstract readonly session: Session
|
||||
readonly session: Session
|
||||
/** The current lifecycle state, mirrored on every `agent/status` transition. */
|
||||
abstract readonly status: AgentStatus
|
||||
readonly status: AgentStatus
|
||||
/** Agent-scoped context; its contributions are agent-local, unwind on disposal, and reject registration afterward. */
|
||||
abstract readonly ctx: Context
|
||||
readonly ctx: Context
|
||||
|
||||
/**
|
||||
* The unified delivery primitive over the (`target` × `wakeup`) matrix.
|
||||
@@ -175,7 +175,7 @@ export abstract class Agent {
|
||||
* @param options - target queue, wakeup decision, and source.
|
||||
* @returns the accepted message's {@link AgentMessageId}, stable across its `agent/inbox/*` events.
|
||||
*/
|
||||
abstract send(content: ContentBlock[], options: SendOptions): AgentMessageId
|
||||
send(content: ContentBlock[], options: SendOptions): AgentMessageId
|
||||
|
||||
/**
|
||||
* Clear queued and steering work — unless `keepInbox` — and abort the active
|
||||
@@ -186,10 +186,10 @@ export abstract class Agent {
|
||||
* @param cause - the stable caller intent carried by the current turn signal.
|
||||
* @param options - cancellation options; `keepInbox` preserves pending work.
|
||||
*/
|
||||
abstract cancel(cause: AgentCancelCause, options?: CancelOptions): void
|
||||
cancel(cause: AgentCancelCause, options?: CancelOptions): void
|
||||
|
||||
/** Resolve at idle quiescence; disposal waits for driver exit rather than only the status transition. */
|
||||
abstract whenIdle(): Promise<void>
|
||||
whenIdle(): Promise<void>
|
||||
|
||||
/**
|
||||
* Queue an ordinary follow-up turn and wake the driver — the
|
||||
@@ -199,13 +199,7 @@ export abstract class Agent {
|
||||
* @param options - message source.
|
||||
* @returns the accepted message's {@link AgentMessageId}.
|
||||
*/
|
||||
followup(content: ContentBlock[], options?: AliasSendOptions): AgentMessageId {
|
||||
return this.send(content, {
|
||||
target: 'next-turn',
|
||||
wakeup: true,
|
||||
source: options?.source ?? { kind: 'user' },
|
||||
})
|
||||
}
|
||||
followup(content: ContentBlock[], options?: AliasSendOptions): AgentMessageId
|
||||
|
||||
/**
|
||||
* Submit steering into the running turn — the `next-step`/wakeup preset of
|
||||
@@ -218,13 +212,7 @@ export abstract class Agent {
|
||||
* @param options - message source.
|
||||
* @returns the accepted message's {@link AgentMessageId}.
|
||||
*/
|
||||
steer(content: ContentBlock[], options?: AliasSendOptions): AgentMessageId {
|
||||
return this.send(content, {
|
||||
target: 'next-step',
|
||||
wakeup: true,
|
||||
source: options?.source ?? { kind: 'user' },
|
||||
})
|
||||
}
|
||||
steer(content: ContentBlock[], options?: AliasSendOptions): AgentMessageId
|
||||
|
||||
/**
|
||||
* Append model-facing context without running the model — the
|
||||
@@ -236,13 +224,7 @@ export abstract class Agent {
|
||||
* @param options - context source.
|
||||
* @returns the accepted message's {@link AgentMessageId}.
|
||||
*/
|
||||
inject(content: ContentBlock[], options?: AliasSendOptions): AgentMessageId {
|
||||
return this.send(content, {
|
||||
target: 'next-step',
|
||||
wakeup: false,
|
||||
source: options?.source ?? { kind: 'plugin', plugin: '' },
|
||||
})
|
||||
}
|
||||
inject(content: ContentBlock[], options?: AliasSendOptions): AgentMessageId
|
||||
|
||||
/**
|
||||
* Re-open a turn on the current session log without a new prompt — the
|
||||
@@ -251,7 +233,7 @@ export abstract class Agent {
|
||||
* immediately. Repeated calls before the scheduled retry coalesce.
|
||||
* @throws while other agent work is running.
|
||||
*/
|
||||
abstract retry(): void
|
||||
retry(): void
|
||||
}
|
||||
|
||||
declare module 'cordis' {
|
||||
|
||||
@@ -3,60 +3,38 @@ import { Context, Service, symbols } from 'cordis'
|
||||
import type { Events } from 'cordis'
|
||||
import { Session, SessionId } from '@deepseek-ai/dsh-session'
|
||||
import AgentRegistry, {
|
||||
Agent,
|
||||
AgentMessageId,
|
||||
agentEvents,
|
||||
agentInterruptReasonOf,
|
||||
} from '@deepseek-ai/dsh-agent'
|
||||
|
||||
import type {
|
||||
Agent,
|
||||
AgentCancelCause,
|
||||
AgentFactory,
|
||||
CreateAgentOptions,
|
||||
ResumeAgentOptions,
|
||||
SendOptions,
|
||||
} from '@deepseek-ai/dsh-agent'
|
||||
|
||||
function stubAgent(rawId: string, overrides: Partial<Agent> = {}): Agent {
|
||||
const id = SessionId(rawId)
|
||||
// Agent is an abstract class, so its alias methods live on the prototype and
|
||||
// object spread would drop them; build the full literal and merge overrides.
|
||||
return Object.assign(Object.create(Agent.prototype) as Agent, {
|
||||
return {
|
||||
id,
|
||||
options: {},
|
||||
session: new Session(id),
|
||||
status: 'idle',
|
||||
ctx: new Context(),
|
||||
send: () => AgentMessageId('stub'),
|
||||
followup: () => AgentMessageId('stub'),
|
||||
steer: () => AgentMessageId('stub'),
|
||||
inject: () => AgentMessageId('stub'),
|
||||
cancel() {},
|
||||
retry() {},
|
||||
whenIdle() { return Promise.resolve() },
|
||||
...overrides,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
describe('Agent delivery aliases', () => {
|
||||
it('materializes complete SendOptions for every preset', () => {
|
||||
const calls: SendOptions[] = []
|
||||
const agent = stubAgent('aliases', {
|
||||
send(_content, options) {
|
||||
if (options !== undefined) calls.push(options)
|
||||
return AgentMessageId('stub')
|
||||
},
|
||||
})
|
||||
|
||||
agent.followup([])
|
||||
agent.steer([])
|
||||
agent.inject([])
|
||||
|
||||
expect(calls).toEqual([
|
||||
{ target: 'next-turn', wakeup: true, source: { kind: 'user' } },
|
||||
{ target: 'next-step', wakeup: true, source: { kind: 'user' } },
|
||||
{ target: 'next-step', wakeup: false, source: { kind: 'plugin', plugin: '' } },
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe('AgentRegistry', () => {
|
||||
it('registers exact entries, emits lifecycle events, and unregisters on owner disposal', async () => {
|
||||
const ctx = new Context()
|
||||
|
||||
Reference in New Issue
Block a user