refactor(agent-loop): rename LoopAgent to ReactLoopAgent

Rename the concrete Agent class to make its ReAct-style reasoning loop
explicit in the name. Package name, default-export plugin (`AgentLoop`),
and the `ctx.agentLoop` service key are unchanged.
This commit is contained in:
Tianyi Cui
2026-06-19 10:13:33 +08:00
parent c5049d1c3f
commit 224c6f029a
23 changed files with 91 additions and 91 deletions

View File

@@ -9,13 +9,13 @@ import SystemPrompt from '@deepseek-ai/dsh-system-prompt'
import ToolRegistry from '@deepseek-ai/dsh-tools'
import AgentRegistry from '@deepseek-ai/dsh-agent'
import SessionPersistenceJsonl from '@deepseek-ai/dsh-session-persistence-jsonl'
import AgentLoop, { LoopAgent } from '@deepseek-ai/dsh-agent-loop'
import AgentLoop, { ReactLoopAgent } from '@deepseek-ai/dsh-agent-loop'
import { MockAdapter, textResponse } from './mock-adapter.ts'
const dirs: string[] = []
afterEach(async () => { for (const d of dirs.splice(0)) await rm(d, { recursive: true, force: true }) })
function waitForIdle(ctx: Context, agent: LoopAgent): Promise<void> {
function waitForIdle(ctx: Context, agent: ReactLoopAgent): Promise<void> {
return new Promise((resolve) => {
const dispose = ctx.on('agent/status', (subject, status) => {
if (subject === agent && status === 'idle') { dispose(); resolve() }
@@ -38,7 +38,7 @@ describe('config-driven session id', () => {
await ctx1.plugin(AgentLoop, { agents: [{ id: 'cfg', model: 'mock', systemPrompt: '' }] })
await ctx1.plugin(SessionPersistenceJsonl, { root })
ctx1.llm.registerAdapter(['mock'], new MockAdapter([textResponse('cfg')]))
const a1 = ctx1.agents.get('cfg') as LoopAgent
const a1 = ctx1.agents.get('cfg') as ReactLoopAgent
expect(a1.session.id).toMatch(idPattern)
a1.send([{ type: 'text', text: 'q' }], { source: { kind: 'user' } })
await waitForIdle(ctx1, a1)
@@ -55,7 +55,7 @@ describe('config-driven session id', () => {
await ctx2.plugin(AgentLoop, { agents: [{ id: 'cfg', model: 'mock', systemPrompt: '' }] })
await ctx2.plugin(SessionPersistenceJsonl, { root })
ctx2.llm.registerAdapter(['mock'], new MockAdapter([textResponse('cfg2')]))
const a2 = ctx2.agents.get('cfg') as LoopAgent
const a2 = ctx2.agents.get('cfg') as ReactLoopAgent
expect(a2.session.id).toMatch(idPattern)
expect(a2.session.id).not.toBe(a1.session.id)
a2.send([{ type: 'text', text: 'q2' }], { source: { kind: 'user' } })
@@ -78,7 +78,7 @@ describe('config-driven session id', () => {
await ctx1.plugin(AgentLoop, { agents: [] })
await ctx1.plugin(SessionPersistenceJsonl, { root })
ctx1.llm.registerAdapter(['mock'], new MockAdapter([textResponse('first')]))
const a1 = ctx1.agents.create({ agentId: 'main', sessionId: 'sticky-1' }) as LoopAgent
const a1 = ctx1.agents.create({ agentId: 'main', sessionId: 'sticky-1' }) as ReactLoopAgent
a1.send([{ type: 'text', text: 'remember me' }], { source: { kind: 'user' } })
await waitForIdle(ctx1, a1)
await ctx1.fiber.dispose()
@@ -97,10 +97,10 @@ describe('config-driven session id', () => {
ctx2.llm.registerAdapter(['mock'], new MockAdapter([textResponse('second')]))
// The deferred resume runs on a microtask after the backend is available.
let resumed: LoopAgent | undefined
let resumed: ReactLoopAgent | undefined
for (let i = 0; i < 50 && !resumed; i++) {
await new Promise(r => setTimeout(r, 5))
resumed = ctx2.agents.get('main') as LoopAgent | undefined
resumed = ctx2.agents.get('main') as ReactLoopAgent | undefined
}
expect(resumed).toBeDefined()
// The live session id IS the resumed id (NOT a fresh ${id}-session-<uuid>),