refactor: hide the concrete agent loop

This commit is contained in:
Tianyi Cui
2026-07-14 02:32:35 +08:00
parent 31c29609d1
commit 225796c90d
40 changed files with 234 additions and 217 deletions
@@ -17,9 +17,9 @@ import { LlmAdapter } from '@deepseek-ai/dsh-llm'
import SessionStore, { SessionId } from '@deepseek-ai/dsh-session'
import SystemPrompt from '@deepseek-ai/dsh-system-prompt'
import ToolRegistry from '@deepseek-ai/dsh-tools'
import AgentRegistry from '@deepseek-ai/dsh-agent'
import AgentRegistry, { type Agent } from '@deepseek-ai/dsh-agent'
import AgentLoop, { type ReactLoopAgent } from '@deepseek-ai/dsh-agent-loop'
import AgentLoop from '@deepseek-ai/dsh-agent-loop'
import fc from 'fast-check'
/** A never-exhausting adapter: every model call returns the same short reply. */
@@ -48,7 +48,7 @@ async function harness() {
}
/** Resolve on the agent's next transition to idle (event-based, not polled). */
function nextIdle(ctx: Context, agent: ReactLoopAgent): Promise<void> {
function nextIdle(ctx: Context, agent: Agent): Promise<void> {
return new Promise((resolve) => {
const dispose = ctx.on('agent/status', (subject, status) => {
if (subject === agent && status === 'idle') {
@@ -61,7 +61,7 @@ function nextIdle(ctx: Context, agent: ReactLoopAgent): Promise<void> {
/** Record every status transition for the legal-machine assertion. Returns
* the seen list plus a disposer for the listener (per the registry convention). */
function recordStatus(ctx: Context, agent: ReactLoopAgent): { seen: string[]; dispose: () => void } {
function recordStatus(ctx: Context, agent: Agent): { seen: string[]; dispose: () => void } {
const seen: string[] = []
const dispose = ctx.on('agent/status', (subject, status) => {
if (subject === agent) seen.push(status)
@@ -69,13 +69,13 @@ function recordStatus(ctx: Context, agent: ReactLoopAgent): { seen: string[]; di
return { seen, dispose }
}
function userMessageTexts(agent: ReactLoopAgent): string[] {
function userMessageTexts(agent: Agent): string[] {
return agent.session.events
.filter(e => e.type === 'user/message')
.map(e => (e.data as { content: { type: string; text?: string }[] }).content.map(b => b.text ?? '').join(''))
}
function turnNumbers(agent: ReactLoopAgent): number[] {
function turnNumbers(agent: Agent): number[] {
return agent.session.events
.filter(e => e.type === 'turn/start')
.map(e => (e.data as { turn: number }).turn)