docs: rebalance prose cleanup and add trimming skill

This commit is contained in:
Tianyi Cui
2026-07-13 23:27:00 +08:00
parent fcdc318dda
commit 148046b9c8
392 changed files with 2801 additions and 1754 deletions

View File

@@ -1,4 +1,9 @@
/** Agent-scoped subject dispatch and prompt assembly context helpers. @module @deepseek-ai/dsh-agent/dispatch */
/**
* Agent-scoped dispatch and prompt assembly helpers. Ordinary events use the
* fused dispatcher so subject and scope key cannot diverge; registry lifecycle
* code instead captures one stable carrier for both edges.
* @module @deepseek-ai/dsh-agent/dispatch
*/
import type { Context, Events } from 'cordis'
import { scopeTarget } from '@deepseek-ai/dsh-scope'
@@ -107,7 +112,8 @@ export function agentEvents(ctx: Context, agent: Agent): AgentEventDispatch {
}
/**
* Build the prompt assembly context with agent and scope set together.
* Build the prompt assembly context with agent and scope set together, so
* agent-scoped prompt and tool contributions cannot be silently omitted.
* @param agent - the agent the assembly is for.
* @returns the context to pass to `assemble()`.
*/

View File

@@ -65,14 +65,15 @@ export interface ResumeAgentOptions {
readonly agentOptions?: AgentOptions
/** Optional creation-only cancellation signal for persistence load/setup; detached before return. */
readonly signal?: AbortSignal
/** Compose the unpublished scoped context after persistence load. */
/** Compose after persistence load under the same unpublished rollback contract as create. */
readonly setup?: (agentCtx: Context) => Promise<void> | void
}
/**
* Holder-owned agent capability. Disposal stops and drains the loop and idle
* flushes before unregistering the agent, detaching its session, and unwinding
* its scoped context. Registry observers receive only the bare {@link Agent}.
* its scoped context. Provider unload reaches the same quiescence boundary;
* registry observers receive only the bare {@link Agent}.
*/
export interface AgentHandle {
agent: Agent
@@ -87,8 +88,9 @@ export interface AgentHandle {
*/
export interface AgentFactory {
/**
* Create, compose, publish, announce, and start an agent under the caller's
* ownership. Rollback pairs any creation announcement that began.
* Create and compose under caller ownership, publish and announce session then
* agent, emit session-start, and start the driver. Rollback pairs any creation
* announcement that began.
* @param ownerCtx - caller-bound context that owns the transaction and live handle.
* @param options - agent/session identity, configuration, and optional setup.
* @returns the owned handle after setup, both announcements, and loop start complete.
@@ -211,7 +213,8 @@ export class AgentRegistry extends Service {
/**
* Insert an unpublished agent for an ordered factory transaction.
* @param agent - the prepared, unpublished agent.
* @returns an idempotent detach closure; during creation dispatch it defers.
* @returns an idempotent closure that removes this exact entry and emits the
* paired disposal edge; detachment during creation dispatch is deferred.
*/
enter(agent: Agent): () => void {
const id = agent.id

View File

@@ -26,7 +26,7 @@ import type { Session } from '@deepseek-ai/dsh-session'
declare module '@deepseek-ai/dsh-system-prompt' {
interface AssembleContext {
/** Agent for this assembly; absent on unscoped diagnostic assemblies. */
/** Agent for this assembly; absent on diagnostics. When present, `scope` must identify the same agent. */
agent?: Agent
}
}
@@ -37,7 +37,7 @@ export interface AgentOptions {
model?: string
}
/** Message options; an omitted source resolves to `{ kind: 'user' }`. */
/** Message options; an omitted source resolves to `{ kind: 'user' }`, so plugins must label their own content. */
export interface SendOptions {
source?: MessageSource
}
@@ -86,10 +86,13 @@ export interface Agent {
readonly options: AgentOptions
readonly session: Session
readonly status: AgentStatus
/** Agent-scoped context; its contributions are agent-local and unwind on disposal. */
/** Agent-scoped context; its contributions are agent-local, unwind on disposal, and reject registration afterward. */
readonly ctx: Context
/** Queue detached, frozen lossless-JSON input; starts a turn when idle. */
/**
* Queue detached, frozen lossless-JSON input; starts a turn when idle.
* Invalid input throws synchronously before notification or enqueue.
*/
send(content: ContentBlock[], options?: SendOptions): void
/**
@@ -106,7 +109,10 @@ export interface Agent {
*/
inject(content: ContentBlock[], options?: SendOptions): void
/** Clear queued and steering work and abort the active step; idle cancellation is a no-op. */
/**
* Clear queued and steering work, including work waiting to start, and abort
* the active step. Idle cancellation is a no-op and does not arm a later cancel.
*/
cancel(reason?: string): void
/** Resolve at idle quiescence; disposal waits for driver exit rather than only the status transition. */
@@ -118,8 +124,11 @@ declare module 'cordis' {
interface Events {
// ---- lifecycle (emit) ----
/**
* A fully configured agent and its session were published. Synchronous
* listener failure vetoes publication; asynchronous failure is reported.
* A fully configured agent and live session were published. Setup is
* composition-only; `agent/session-start` is the first startup-driving seam.
* Synchronous listener failure vetoes publication, while returned-promise
* rejection is reported. Detach requested during dispatch waits until every
* creation listener has observed the stable entry.
* @param agent - the newly registered agent with its live session and completed setup.
* Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
* @mode emit
@@ -134,7 +143,8 @@ declare module 'cordis' {
*/
'agent/disposed'(this: Scoped<Agent>, agent: Agent): void
/**
* Agent status changed (`idle` ⇄ `running`, or → `disposed`).
* Agent status changed (`idle` ⇄ `running`, or → `disposed`). `send()` does
* not enter `running` synchronously; drive lifecycle from this event.
* @param agent - the agent whose status flipped.
* @param status - the status just entered (the transition's destination).
* Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
@@ -142,7 +152,8 @@ declare module 'cordis' {
*/
'agent/status'(this: Scoped<Agent>, agent: Agent, status: AgentStatus): void
/**
* Detached, frozen content entered the agent's inbox.
* Detached, frozen content entered the agent's inbox. Source defaults have
* already been applied, so these are the exact values retained for the log.
* @param agent - the agent whose inbox received the message.
* @param content - the accepted content blocks retained by the inbox.
* @param info - the accepted source plus whether it entered as steering.

View File

@@ -150,7 +150,7 @@ describe('verify-export-jsdoc export forms', () => {
))).toEqual([expect.stringMatching(/exported function 'f' .* has no JSDoc\./)])
})
it('does not treat a never-exported sibling declarator as surface (review round 2)', () => {
it('does not treat a never-exported sibling declarator as surface', () => {
// `export { publicValue }` resolves to the whole variable statement; only
// the named declarator is surface — the gate must not demand JSDoc for
// the private sibling sharing the statement.
@@ -159,7 +159,7 @@ describe('verify-export-jsdoc export forms', () => {
))).toEqual([])
})
it('unions declarators across multiple export lists over one statement (review round 2)', () => {
it('unions declarators across multiple export lists over one statement', () => {
// Two lists each name one declarator of the same undocumented statement:
// both are surface (deduplicating on first resolution would drop `b`),
// while the never-exported `c` stays out.
@@ -172,7 +172,7 @@ describe('verify-export-jsdoc export forms', () => {
])
})
it('scopes a default-export identifier to its own declarator (review round 2)', () => {
it('scopes a default-export identifier to its own declarator', () => {
// `export default` of an identifier reaches the statement through the
// same name lookup as an export list; the sibling stays private.
expect(collectExportJsdocViolations(make(
@@ -315,7 +315,7 @@ export namespace Loose {
})
})
describe('verify-export-jsdoc fail-closed forms (review round 1)', () => {
describe('verify-export-jsdoc fail-closed forms', () => {
it('checks the function contract on a non-identifier default export', () => {
expect(collectExportJsdocViolations(make(
'/** Doubles. */\nexport default (x: number): number => x * 2\n',
@@ -408,7 +408,7 @@ describe('verify-export-jsdoc fail-closed forms (review round 1)', () => {
})
})
describe('verify-export-jsdoc heritage refinement (review round 1)', () => {
describe('verify-export-jsdoc heritage refinement', () => {
it('requires @param for parameters the base member never names', () => {
const violations = collectExportJsdocViolations(make(`
/** Seam. */