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:
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* The concrete Agent implementation: LoopAgent plus its inbox. Everything
|
||||
* The concrete Agent implementation: ReactLoopAgent plus its inbox. Everything
|
||||
* observable happens through session events and the agent/* event taxonomy —
|
||||
* plugins never need this class.
|
||||
*
|
||||
@@ -21,7 +21,7 @@ import { isTurnOpen, lastTurnNumber, runLoop } from './loop.ts'
|
||||
* the loop driver. Everything observable happens through session events and
|
||||
* the agent/* event taxonomy — plugins never need this class.
|
||||
*/
|
||||
export class LoopAgent implements Agent {
|
||||
export class ReactLoopAgent implements Agent {
|
||||
readonly inbox = new Inbox()
|
||||
|
||||
private _status: AgentStatus = 'idle'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* THE concrete agent plugin: creates LoopAgents, runs their loops, and
|
||||
* THE concrete agent plugin: creates ReactLoopAgents, runs their loops, and
|
||||
* registers them in ctx.agents. Deliberately thin — every behavior beyond
|
||||
* "call the model, run the tools, repeat" belongs to plugins on the event
|
||||
* taxonomy.
|
||||
@@ -18,9 +18,9 @@ import type { Session } from '@deepseek-ai/dsh-session'
|
||||
import type {} from '@deepseek-ai/dsh-system-prompt'
|
||||
import type {} from '@deepseek-ai/dsh-tools'
|
||||
import type { SessionPersistence } from '@deepseek-ai/dsh-session-persistence'
|
||||
import { LoopAgent } from './agent.ts'
|
||||
import { ReactLoopAgent } from './agent.ts'
|
||||
|
||||
export { LoopAgent } from './agent.ts'
|
||||
export { ReactLoopAgent } from './agent.ts'
|
||||
export { Inbox, type InboxMessage } from './inbox.ts'
|
||||
export { runLoop } from './loop.ts'
|
||||
|
||||
@@ -48,7 +48,7 @@ export interface Config {
|
||||
}
|
||||
|
||||
/**
|
||||
* The agent-loop plugin (`ctx.agentLoop`): creates {@link LoopAgent}s, runs
|
||||
* The agent-loop plugin (`ctx.agentLoop`): creates {@link ReactLoopAgent}s, runs
|
||||
* their loops, and registers them in `ctx.agents`. Also implements the
|
||||
* {@link AgentFactory} seam, so plugins create/resume agents through
|
||||
* `ctx.agents` (the interface) without depending on this concrete package.
|
||||
@@ -118,7 +118,7 @@ export class AgentLoop extends Service implements AgentFactory {
|
||||
* fork seeds the new Session with the parent's event log, spawn starts
|
||||
* fresh; the child is returned as a regular Agent handle.
|
||||
*/
|
||||
create(id: string, options: AgentOptions = {}): LoopAgent {
|
||||
create(id: string, options: AgentOptions = {}): ReactLoopAgent {
|
||||
this.assertAgentIdFree(id)
|
||||
const session = this.ctx.sessions.create(`${id}-session-${randomUUID()}`, { meta: {} })
|
||||
return this.start(AgentId(id), options, session)
|
||||
@@ -219,9 +219,9 @@ export class AgentLoop extends Service implements AgentFactory {
|
||||
}
|
||||
}
|
||||
|
||||
/** Shared: construct a LoopAgent, register it, and start its loop (LIFO). */
|
||||
private start(id: AgentId, options: AgentOptions, session: Session): LoopAgent {
|
||||
const agent = new LoopAgent(this.ctx, id, options, session)
|
||||
/** Shared: construct a ReactLoopAgent, register it, and start its loop (LIFO). */
|
||||
private start(id: AgentId, options: AgentOptions, session: Session): ReactLoopAgent {
|
||||
const agent = new ReactLoopAgent(this.ctx, id, options, session)
|
||||
// Generator effect: stop and unregister are independent disposables
|
||||
// (LIFO), so a throwing stop() cannot leak the registry entry.
|
||||
this.ctx.effect(function* (this: AgentLoop) {
|
||||
|
||||
@@ -13,7 +13,7 @@ import { BlockAssembler, HarnessError } from '@deepseek-ai/dsh-llm'
|
||||
import type { Session, TurnEndReason, TurnTrigger } from '@deepseek-ai/dsh-session'
|
||||
import { renderPrompt } from '@deepseek-ai/dsh-system-prompt'
|
||||
import type {} from '@deepseek-ai/dsh-tools'
|
||||
import type { LoopAgent } from './agent.ts'
|
||||
import type { ReactLoopAgent } from './agent.ts'
|
||||
|
||||
/** An Error with an optional machine-readable code (e.g., from LlmError or a throwing plugin). */
|
||||
type CodedError = Error & { code?: string }
|
||||
@@ -98,7 +98,7 @@ function stepFinishReason(finish: FinishReason): TurnEndReason | undefined {
|
||||
|
||||
/**
|
||||
* Ambient handles the loop driver receives from the agent. Decouples the
|
||||
* pure function `runLoop` from the mutable LoopAgent fields, making the
|
||||
* pure function `runLoop` from the mutable ReactLoopAgent fields, making the
|
||||
* loop testable without a real agent.
|
||||
*/
|
||||
export interface LoopHandle {
|
||||
@@ -141,7 +141,7 @@ export interface LoopHandle {
|
||||
* idle (emit agent/status) unless more queued
|
||||
* ```
|
||||
*/
|
||||
export async function runLoop(ctx: Context, agent: LoopAgent, handle: LoopHandle): Promise<void> {
|
||||
export async function runLoop(ctx: Context, agent: ReactLoopAgent, handle: LoopHandle): Promise<void> {
|
||||
const { session } = agent
|
||||
|
||||
while (!handle.isDisposed()) {
|
||||
@@ -180,7 +180,7 @@ export async function runLoop(ctx: Context, agent: LoopAgent, handle: LoopHandle
|
||||
}
|
||||
}
|
||||
|
||||
async function runTurn(ctx: Context, agent: LoopAgent, handle: LoopHandle, turn: number): Promise<void> {
|
||||
async function runTurn(ctx: Context, agent: ReactLoopAgent, handle: LoopHandle, turn: number): Promise<void> {
|
||||
const { session } = agent
|
||||
|
||||
// --- Pre-turn. A throw here (the invariant guard) is owed NO turn/end —
|
||||
@@ -446,7 +446,7 @@ async function runTurn(ctx: Context, agent: LoopAgent, handle: LoopHandle, turn:
|
||||
}
|
||||
|
||||
/** Drain the steering queue into the session. Returns whether any arrived. */
|
||||
function drainSteering(ctx: Context, agent: LoopAgent, turn: number): boolean {
|
||||
function drainSteering(ctx: Context, agent: ReactLoopAgent, turn: number): boolean {
|
||||
const messages = agent.inbox.drainSteering()
|
||||
for (const message of messages) {
|
||||
agent.session.append('steering/message', { turn, content: message.content, source: message.source })
|
||||
@@ -458,7 +458,7 @@ function drainSteering(ctx: Context, agent: LoopAgent, turn: number): boolean {
|
||||
/** One step: assemble request → stream model → record → execute tools. */
|
||||
async function runStep(
|
||||
ctx: Context,
|
||||
agent: LoopAgent,
|
||||
agent: ReactLoopAgent,
|
||||
turn: number,
|
||||
step: number,
|
||||
signal: AbortSignal,
|
||||
|
||||
Reference in New Issue
Block a user