fix(agent): restore public send method
This commit is contained in:
@@ -43,6 +43,7 @@ function sessionAgent(session: Session, id = 'agent'): Agent {
|
||||
inbox: new Inbox(session),
|
||||
status: 'running',
|
||||
ctx: new Context(),
|
||||
send: () => {},
|
||||
followup: () => {},
|
||||
steer: () => {},
|
||||
inject: () => { throw new Error('time-context must append directly to the open step') },
|
||||
|
||||
@@ -99,6 +99,7 @@ function sessionAgent(session: Session, id = 'agent'): Agent {
|
||||
inbox: new Inbox(session),
|
||||
status: 'running',
|
||||
ctx: new Context(),
|
||||
send: () => {},
|
||||
followup: () => {},
|
||||
steer: () => {},
|
||||
inject: () => { throw new Error('tmux-context must append directly to the open step') },
|
||||
|
||||
@@ -178,6 +178,7 @@ function stubAgent(cwd?: string, seed: SessionEvent[] = []): Agent {
|
||||
session,
|
||||
inbox: new Inbox(session),
|
||||
status: 'idle',
|
||||
send: () => {},
|
||||
followup: () => {},
|
||||
steer: () => {},
|
||||
inject: () => { throw new Error('workspace-context must append directly to the open step') },
|
||||
|
||||
@@ -1419,7 +1419,7 @@ export const EVENT_API: readonly EventApiEntry[] = [
|
||||
export const TYPE_API: readonly TypeApiEntry[] = [
|
||||
{
|
||||
name: 'Agent',
|
||||
declaration: 'export interface Agent {\n readonly id: SessionId;\n readonly options: AgentOptions;\n readonly session: Session;\n readonly inbox: Inbox;\n readonly status: AgentStatus;\n readonly ctx: Context;\n cancel(cause: AgentCancelCause, options?: CancelOptions): void;\n whenIdle(): Promise<void>;\n followup(message: UserMessage): void;\n steer(message: UserMessage): void;\n inject(message: UserMessage): void;\n}',
|
||||
declaration: 'export interface Agent {\n readonly id: SessionId;\n readonly options: AgentOptions;\n readonly session: Session;\n readonly inbox: Inbox;\n readonly status: AgentStatus;\n readonly ctx: Context;\n cancel(cause: AgentCancelCause, options?: CancelOptions): void;\n whenIdle(): Promise<void>;\n send(message: UserMessage, target: InboxTarget, wakeup: boolean): void;\n followup(message: UserMessage): void;\n steer(message: UserMessage): void;\n inject(message: UserMessage): void;\n}',
|
||||
},
|
||||
{
|
||||
name: 'AgentCancelCause',
|
||||
|
||||
@@ -81,7 +81,7 @@ export class ReactLoopAgent implements Agent {
|
||||
}
|
||||
}
|
||||
|
||||
private send(message: UserMessage, target: InboxTarget, wakeup: boolean): void {
|
||||
send(message: UserMessage, target: InboxTarget, wakeup: boolean): void {
|
||||
// Waking input cannot join an aborted admission or turn, so it starts the next turn.
|
||||
const wakingAfterAbort = wakeup && this.phase.kind !== 'idle' && this.phase.abort.signal.aborted
|
||||
const resolvedTarget = wakingAfterAbort ? 'next-turn' : target
|
||||
@@ -180,7 +180,7 @@ export class ReactLoopAgent implements Agent {
|
||||
if (admission.kind !== 'admitted') return false
|
||||
signal.throwIfAborted()
|
||||
} catch (error: unknown) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- cancel may abort while admission awaits
|
||||
// oxlint-disable-next-line typescript/no-unnecessary-condition -- cancel may abort while admission awaits
|
||||
if (signal.aborted) return this.inbox.hasPending
|
||||
throw error
|
||||
}
|
||||
@@ -216,11 +216,11 @@ export class ReactLoopAgent implements Agent {
|
||||
if (admission.kind === 'empty' && turnEnds) break
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- cancel may abort during any awaited turn operation
|
||||
// oxlint-disable-next-line typescript/no-unnecessary-condition -- cancel may abort during any awaited turn operation
|
||||
if (signal.aborted) turnEnds = { kind: 'aborted', reason: signal.reason as AgentCancelCause }
|
||||
else turnEnds = { kind: 'error', error: errorChain(error) }
|
||||
} finally {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- the turn is always ended in this block
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion -- the turn is always ended in this block
|
||||
this.session.append('turn/end', { turn, reason: turnEnds! })
|
||||
}
|
||||
return this.inbox.hasPending
|
||||
@@ -317,7 +317,7 @@ export class ReactLoopAgent implements Agent {
|
||||
: undefined
|
||||
const maxTokens = this.options.maxTokens
|
||||
const seedConfig = this.requestHeaderLogged
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- the instance logged the frozen header it now folds
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion -- the instance logged the frozen header it now folds
|
||||
? persistedConfig!
|
||||
: deepFreeze({
|
||||
...route,
|
||||
|
||||
@@ -109,6 +109,15 @@ export interface Agent {
|
||||
*/
|
||||
whenIdle(): Promise<void>
|
||||
|
||||
/**
|
||||
* Route identified input to an inbox boundary and optionally wake the driver.
|
||||
* Waking input submitted after active cancellation is queued for the next turn.
|
||||
* @param message - identified content and its producer provenance.
|
||||
* @param target - the preferred next-turn or next-step inbox boundary.
|
||||
* @param wakeup - whether delivery may wake the driver.
|
||||
*/
|
||||
send(message: UserMessage, target: InboxTarget, wakeup: boolean): void
|
||||
|
||||
/**
|
||||
* Queue an ordinary follow-up turn and wake the driver. The item becomes the
|
||||
* sole ordinary message of its own turn.
|
||||
|
||||
@@ -24,6 +24,7 @@ function stubAgent(rawId: string, overrides: Partial<Agent> = {}): Agent {
|
||||
inbox: new Inbox(session),
|
||||
status: 'idle',
|
||||
ctx: new Context(),
|
||||
send: () => {},
|
||||
followup: () => {},
|
||||
steer: () => {},
|
||||
inject: () => {},
|
||||
|
||||
@@ -36,6 +36,7 @@ function agent(ctx: Context, cwd: string): Agent {
|
||||
inbox: new Inbox(session),
|
||||
status: 'idle',
|
||||
ctx: scope.ctx,
|
||||
send: () => {},
|
||||
followup: () => {},
|
||||
steer: () => {},
|
||||
inject: () => {},
|
||||
|
||||
@@ -37,6 +37,7 @@ function stubAgent(ctx: Context, id: string): { agent: Agent; session: Session }
|
||||
inbox: new Inbox(session),
|
||||
ctx: new Context(),
|
||||
get status() { return status },
|
||||
send: () => {},
|
||||
followup: () => {},
|
||||
steer: () => {},
|
||||
inject(input) { appendInjection(session, input) },
|
||||
|
||||
@@ -47,6 +47,7 @@ function stubAgentForSession(session: Session): StubAgent {
|
||||
inbox: new Inbox(session),
|
||||
ctx: new Context(),
|
||||
get status() { return status },
|
||||
send: () => {},
|
||||
followup: () => {},
|
||||
steer: () => {},
|
||||
inject(input) {
|
||||
|
||||
@@ -38,6 +38,7 @@ function liveAgent(ctx: Context, session: Session): Agent {
|
||||
inbox: new Inbox(session),
|
||||
ctx,
|
||||
get status() { return status },
|
||||
send: () => {},
|
||||
followup: () => {},
|
||||
steer: () => {},
|
||||
inject(input: UserMessage) {
|
||||
|
||||
@@ -32,6 +32,7 @@ function stubAgent(rawId: string, supplied?: Session): StubAgent {
|
||||
inbox: new Inbox(session),
|
||||
get status() { return status },
|
||||
ctx: new Context(),
|
||||
send: () => {},
|
||||
followup: () => {},
|
||||
steer: () => {},
|
||||
inject(input) {
|
||||
|
||||
@@ -47,6 +47,7 @@ function stubAgent(session: Session): Agent {
|
||||
inbox: new Inbox(session),
|
||||
status: 'idle',
|
||||
ctx: new Context(),
|
||||
send: () => {},
|
||||
followup: () => {},
|
||||
steer: () => {},
|
||||
inject: () => {},
|
||||
|
||||
@@ -43,7 +43,7 @@ function agent(ctx: Context): Agent {
|
||||
const session = new Session(id)
|
||||
return {
|
||||
id, options: {}, session, inbox: new Inbox(session), status: 'idle', ctx,
|
||||
followup: () => {}, steer: () => {}, inject: () => {}, cancel() {}, whenIdle: () => Promise.resolve(),
|
||||
send: () => {}, followup: () => {}, steer: () => {}, inject: () => {}, cancel() {}, whenIdle: () => Promise.resolve(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,7 +250,7 @@ describe('pty-local plugin shape', () => {
|
||||
const ownerFiber = await ctx.plugin(() => {})
|
||||
const owner: Agent = {
|
||||
id: session.id, options: {}, session, inbox: new Inbox(session), status: 'idle', ctx: ownerFiber.ctx,
|
||||
followup: () => {}, steer: () => {}, inject: () => {}, cancel() {}, whenIdle: () => Promise.resolve(),
|
||||
send: () => {}, followup: () => {}, steer: () => {}, inject: () => {}, cancel() {}, whenIdle: () => Promise.resolve(),
|
||||
}
|
||||
ctx.agents.register(owner)
|
||||
const providerFiber = await registerStubLocalBackend(ctx, () => stubLocalSession())
|
||||
@@ -293,7 +293,7 @@ describe('pty-local plugin shape', () => {
|
||||
const ownerFiber = await ctx.plugin(() => {})
|
||||
const owner: Agent = {
|
||||
id: session.id, options: {}, session, inbox: new Inbox(session), status: 'idle', ctx: ownerFiber.ctx,
|
||||
followup: () => {}, steer: () => {}, inject: () => {}, cancel() {}, whenIdle: () => Promise.resolve(),
|
||||
send: () => {}, followup: () => {}, steer: () => {}, inject: () => {}, cancel() {}, whenIdle: () => Promise.resolve(),
|
||||
}
|
||||
ctx.agents.register(owner)
|
||||
const gate = Promise.withResolvers<undefined>()
|
||||
|
||||
@@ -36,7 +36,7 @@ function stubAgent(ctx: Context, rawId: string): Agent {
|
||||
const session = new Session(id)
|
||||
return {
|
||||
id, options: {}, session, inbox: new Inbox(session), status: 'idle', ctx: scope.ctx,
|
||||
followup: () => {}, steer: () => {}, inject: () => {}, cancel() {}, whenIdle: () => Promise.resolve(),
|
||||
send: () => {}, followup: () => {}, steer: () => {}, inject: () => {}, cancel() {}, whenIdle: () => Promise.resolve(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ function stubAgent(ctx: Context, rawId: string): Agent {
|
||||
inbox: new Inbox(session),
|
||||
status: 'idle',
|
||||
ctx: scopeFiber.ctx,
|
||||
send: () => {},
|
||||
followup: () => {},
|
||||
steer: () => {},
|
||||
inject: () => {},
|
||||
|
||||
@@ -46,6 +46,7 @@ function agent(ctx: Context, cwd: string): Agent {
|
||||
inbox: new Inbox(session),
|
||||
status: 'idle',
|
||||
ctx: scope.ctx,
|
||||
send: () => {},
|
||||
followup: () => {},
|
||||
steer: () => {},
|
||||
inject: () => {},
|
||||
|
||||
@@ -42,6 +42,7 @@ function agent(ctx: Context, cwd: string | undefined): Agent {
|
||||
inbox: new Inbox(session),
|
||||
status: 'idle',
|
||||
ctx: scope.ctx,
|
||||
send: () => {},
|
||||
followup: () => {},
|
||||
steer: () => {},
|
||||
inject: () => {},
|
||||
|
||||
@@ -41,7 +41,7 @@ function agent(ctx: Context): Agent {
|
||||
const session = new Session(id)
|
||||
const value: Agent = {
|
||||
id, options: {}, session, inbox: new Inbox(session), status: 'idle', ctx: scope.ctx,
|
||||
followup: () => {}, steer: () => {}, inject: () => {}, cancel() {}, whenIdle: () => Promise.resolve(),
|
||||
send: () => {}, followup: () => {}, steer: () => {}, inject: () => {}, cancel() {}, whenIdle: () => Promise.resolve(),
|
||||
}
|
||||
ctx.agents.register(value)
|
||||
return value
|
||||
|
||||
@@ -19,7 +19,7 @@ function fakeAgent(ctx: Context, rawId: string): Agent {
|
||||
const session = new Session(id)
|
||||
const agent: Agent = {
|
||||
id, options: {}, session, inbox: new Inbox(session), status: 'idle', ctx: scope.ctx,
|
||||
followup: () => {}, steer: () => {}, inject: () => {}, cancel() {}, whenIdle: () => Promise.resolve(),
|
||||
send: () => {}, followup: () => {}, steer: () => {}, inject: () => {}, cancel() {}, whenIdle: () => Promise.resolve(),
|
||||
}
|
||||
ctx.agents.register(agent)
|
||||
return agent
|
||||
|
||||
@@ -46,6 +46,7 @@ function agentForCwd(cwd: string): Agent {
|
||||
session,
|
||||
inbox: new Inbox(session),
|
||||
status: 'idle',
|
||||
send: () => {},
|
||||
followup: () => {},
|
||||
steer: () => {},
|
||||
inject: () => { throw new Error('step-boundary catalog must not use agent.inject()') },
|
||||
@@ -62,6 +63,7 @@ function sessionAgent(session: Session, id = 'tool-skill-agent'): Agent {
|
||||
inbox: new Inbox(session),
|
||||
status: 'running',
|
||||
ctx: new Context(),
|
||||
send: () => {},
|
||||
followup: () => {},
|
||||
steer: () => {},
|
||||
inject: () => { throw new Error('step-boundary catalog must not use agent.inject()') },
|
||||
|
||||
@@ -26,6 +26,7 @@ function stubAgent(ctx: Context, rawId: string): Agent {
|
||||
inbox: new Inbox(session),
|
||||
status: 'idle' as const,
|
||||
ctx: scopeFiber.ctx,
|
||||
send: () => {},
|
||||
followup: () => {},
|
||||
steer: () => {},
|
||||
inject: () => {},
|
||||
|
||||
@@ -202,6 +202,7 @@ export async function createTuiTestHarness<TerminalType extends Terminal, Exit e
|
||||
injected,
|
||||
injectedOptions,
|
||||
cancelled,
|
||||
send() {},
|
||||
followup(input) {
|
||||
sent.push(input.content)
|
||||
sentMessages.push(input)
|
||||
|
||||
@@ -4905,7 +4905,7 @@ describe('terminal mounting', () => {
|
||||
const session = ctx.sessions.create(SessionId('main'))
|
||||
ctx.agents.register({
|
||||
id: session.id, options: {}, session, inbox: new Inbox(session), status: 'idle', ctx,
|
||||
followup: () => {}, steer: () => {}, inject: () => {}, cancel() {}, whenIdle: () => Promise.resolve(),
|
||||
send: () => {}, followup: () => {}, steer: () => {}, inject: () => {}, cancel() {}, whenIdle: () => Promise.resolve(),
|
||||
})
|
||||
const terminal = new FakeTerminal()
|
||||
mountTui(ctx, { theme: { color: false } }, { terminal, exit: vi.fn() })
|
||||
@@ -4930,7 +4930,7 @@ describe('terminal mounting', () => {
|
||||
const session = ctx.sessions.create(SessionId('main'))
|
||||
ctx.agents.register({
|
||||
id: session.id, options: {}, session, inbox: new Inbox(session), status: 'idle', ctx,
|
||||
followup: () => {}, steer: () => {}, inject: () => {}, cancel() {}, whenIdle: () => Promise.resolve(),
|
||||
send: () => {}, followup: () => {}, steer: () => {}, inject: () => {}, cancel() {}, whenIdle: () => Promise.resolve(),
|
||||
})
|
||||
const terminal = new FakeTerminal()
|
||||
// Mirror dsh-tui's own inject (minus loader, the absence under test).
|
||||
@@ -4965,14 +4965,14 @@ describe('terminal mounting', () => {
|
||||
const otherSession = ctx.sessions.create(SessionId('other-session'))
|
||||
ctx.agents.register({
|
||||
id: otherSession.id, options: {}, session: otherSession, inbox: new Inbox(otherSession), status: 'idle', ctx,
|
||||
followup: () => {}, steer: () => {}, inject: () => {}, cancel() {}, whenIdle: () => Promise.resolve(),
|
||||
send: () => {}, followup: () => {}, steer: () => {}, inject: () => {}, cancel() {}, whenIdle: () => Promise.resolve(),
|
||||
})
|
||||
expect(terminal.started).toBe(0)
|
||||
|
||||
const session = ctx.sessions.create(SessionId('late-session'))
|
||||
const agent = {
|
||||
id: session.id, options: {}, session, inbox: new Inbox(session), status: 'idle', ctx,
|
||||
followup: () => {}, steer: () => {}, inject: () => {}, cancel() {}, whenIdle: () => Promise.resolve(),
|
||||
send: () => {}, followup: () => {}, steer: () => {}, inject: () => {}, cancel() {}, whenIdle: () => Promise.resolve(),
|
||||
} as Agent
|
||||
ctx.agents.register(agent)
|
||||
await tick()
|
||||
@@ -5003,7 +5003,7 @@ describe('terminal mounting', () => {
|
||||
const session = ctx.sessions.create(SessionId('main-session'))
|
||||
ctx.agents.register({
|
||||
id: session.id, options: {}, session, inbox: new Inbox(session), status: 'idle', ctx,
|
||||
followup: () => {}, steer: () => {}, inject: () => {}, cancel() {}, whenIdle: () => Promise.resolve(),
|
||||
send: () => {}, followup: () => {}, steer: () => {}, inject: () => {}, cancel() {}, whenIdle: () => Promise.resolve(),
|
||||
})
|
||||
await tick()
|
||||
expect(terminal.started).toBe(0)
|
||||
@@ -5047,7 +5047,7 @@ describe('terminal mounting', () => {
|
||||
session.append('step/start', { turn: 1, step: 1 })
|
||||
ctx.agents.register({
|
||||
id: session.id, options: {}, session, inbox: new Inbox(session), status: 'running', ctx,
|
||||
followup: () => {}, steer: () => {}, inject: () => {}, cancel() {}, whenIdle: () => Promise.resolve(),
|
||||
send: () => {}, followup: () => {}, steer: () => {}, inject: () => {}, cancel() {}, whenIdle: () => Promise.resolve(),
|
||||
})
|
||||
const terminal = new FakeTerminal()
|
||||
terminal.start = () => { throw new Error('terminal startup failed') }
|
||||
|
||||
Reference in New Issue
Block a user