feat(agent): add addressable queue operations

This commit is contained in:
kingwl
2026-07-30 00:05:00 +08:00
parent 87c9ab06b3
commit f893e2281d
108 changed files with 1785 additions and 608 deletions

View File

@@ -0,0 +1,23 @@
/**
* dsh-agent's owned branded ids for live inbox occurrences.
*
* @module @deepseek-ai/dsh-agent/brand
*/
import type { Branded } from '@deepseek-ai/dsh-brand'
/**
* Identifies one accepted occurrence in an agent inbox. Re-sending the same
* message creates a distinct item id, so pending work remains independently
* addressable.
*/
export type InboxItemId = Branded<'InboxItemId'>
/**
* Brand a string as an {@link InboxItemId}.
* @param id - the agent-loop-minted occurrence identifier.
* @returns the same string, branded; no validation is performed.
*/
export function InboxItemId(id: string): InboxItemId {
return id as InboxItemId
}

View File

@@ -15,6 +15,7 @@ import type { SessionEvent, SessionId } from '@deepseek-ai/dsh-session'
import type { Agent, AgentOptions } from './types.ts'
export * from './types.ts'
export * from './brand.ts'
export * from './llm-target.ts'
export { agentCarrier, agentEvents, assembleContextFor, emitAgentEvent } from './dispatch.ts'
export type { AgentEventDispatch, AgentSubjectEvent } from './dispatch.ts'

View File

@@ -9,6 +9,7 @@ import type { Context } from 'cordis'
import type { Scoped } from '@deepseek-ai/dsh-scope'
import type { ContentBlock, LlmCallConfig, LlmFailure, ResolvedRetryPolicy } from '@deepseek-ai/dsh-llm'
import type { Session, SessionId, UserMessage } from '@deepseek-ai/dsh-session'
import type { InboxItemId } from './brand.ts'
import type {} from '@deepseek-ai/dsh-system-prompt'
declare module '@deepseek-ai/dsh-system-prompt' {
interface AssembleContext {
@@ -39,6 +40,25 @@ export type SendTarget = 'next-turn' | 'next-step'
/** Resolved inbox placement reported when an accepted message is enqueued. */
export type InboxPlacement = 'queued' | 'steering'
/** One independently addressable accepted occurrence in an agent inbox. */
export interface InboxItem {
/** Agent-loop-minted occurrence identity. */
readonly id: InboxItemId
/** Identified message delivered by the caller. */
readonly message: UserMessage
/** Acceptance-time FIFO classification. */
readonly placement: InboxPlacement
}
/** A user-requested mutation of one still-pending inbox item. */
export type InboxAction =
| { readonly kind: 'edit'; readonly content: ContentBlock[] }
| { readonly kind: 'remove' }
| { readonly kind: 'promote' }
/** Result of applying an inbox action at the synchronous ownership boundary. */
export type InboxActionResult = 'applied' | 'not-found'
/**
* Options for the unified {@link Agent.send} primitive over the
* (`target` × `wakeup`) matrix. Named presets: {@link Agent.followup}
@@ -156,6 +176,18 @@ export interface Agent {
*/
send(message: UserMessage, options: SendOptions): void
/**
* Mutate one still-pending inbox occurrence synchronously. Editing preserves
* the message identity and queue position; removal publishes its terminal
* discard; promotion moves it to the front of its current FIFO and makes a
* queued item waking. A driver-claimed item is no longer pending and returns
* `not-found`.
* @param id - independently addressable inbox occurrence.
* @param action - edit, remove, or promote operation.
* @returns whether the pending occurrence was found and updated.
*/
updateInbox(id: InboxItemId, action: InboxAction): InboxActionResult
/**
* Clear queued and steering work — unless `keepInbox` — and abort the active
* turn. An effective call first emits `agent/cancel-requested` with the
@@ -239,29 +271,37 @@ declare module 'cordis' {
* acceptance-time routing result; listeners must not reconstruct it from
* later agent or session state.
* @param agent - the owning agent.
* @param message - accepted content, source, and correlation identity.
* @param placement - resolved queued or steering placement.
* @param item - accepted occurrence, message, and resolved placement.
* Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
* @mode emit
*/
'agent/inbox/enqueue'(this: Scoped<Agent>, agent: Agent, message: UserMessage, placement: InboxPlacement): void
'agent/inbox/enqueue'(this: Scoped<Agent>, agent: Agent, item: InboxItem): void
/**
* A still-pending inbox item changed content or position. The item id and
* placement remain stable; edit carries the replacement message, while
* promote makes this occurrence first in its current FIFO.
* @param agent - the owning agent.
* @param item - the complete post-update occurrence.
* @param action - the applied non-terminal operation.
* Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
* @mode emit
*/
'agent/inbox/update'(
this: Scoped<Agent>,
agent: Agent,
item: InboxItem,
action: 'edit' | 'promote',
): void
/**
* The driver claimed one item out of the inbox: a queued item at a turn
* boundary, or steering drained between steps. Fires after the item leaves
* its FIFO and before it becomes a durable message.
* @param agent - the agent whose inbox item was claimed.
* @param message - the claimed message.
* @param placement - the FIFO that claimed this occurrence; together with
* `message.id`, it matches the earliest outstanding enqueue in that FIFO.
* @param item - the exact claimed occurrence.
* Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
* @mode emit
*/
'agent/inbox/dequeue'(
this: Scoped<Agent>,
agent: Agent,
message: UserMessage,
placement: InboxPlacement,
): void
'agent/inbox/dequeue'(this: Scoped<Agent>, agent: Agent, item: InboxItem): void
/**
* Pending inbox items were dropped without delivering them, so every
* enqueue occurrence receives exactly one terminal `agent/inbox/dequeue` OR
@@ -269,11 +309,11 @@ declare module 'cordis' {
* emits this after `agent/cancel-requested` when applicable and before
* aborting the active work. Fires once per drop with every dropped item.
* @param agent - the agent whose inbox items were dropped.
* @param messages - the discarded messages in FIFO order (queued then steering); never empty.
* @param items - the discarded occurrences in FIFO order (queued then steering); never empty.
* Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
* @mode emit
*/
'agent/inbox/discard'(this: Scoped<Agent>, agent: Agent, messages: UserMessage[]): void
'agent/inbox/discard'(this: Scoped<Agent>, agent: Agent, items: InboxItem[]): void
/**
* Effective broad cancellation was requested, before queued/outbox work
* is cleared or the active turn is aborted. This observe-only notification