Merge remote-tracking branch 'origin/master' into session-query-tool
# Conflicts: # docs/core-data-structures/persistence.i18n.yaml # packages/session-persistence/session-persistence-jsonl/src/index.ts
This commit is contained in:
@@ -188,15 +188,12 @@ describe('Agent', () => {
|
||||
const ctx = await harness(adapter)
|
||||
const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' })
|
||||
|
||||
// Simulate an OPEN turn in the log while the agent is idle (status is not a
|
||||
// reliable open-turn signal). inject must append into that open turn, NOT
|
||||
// wrap a new one.
|
||||
// Status is idle while the log has an open turn; enclosure must follow the log.
|
||||
agent.session.append('turn/start', { turn: 1, trigger: { kind: 'message', source: { kind: 'user' } } })
|
||||
agent.inject([{ type: 'text', text: 'mid' }], { source: { kind: 'plugin', plugin: 'p' } })
|
||||
expect(agent.session.events.filter(e => e.type === 'turn/start')).toHaveLength(1)
|
||||
expect(agent.session.events.at(-1)!.type).toBe('user/message')
|
||||
|
||||
// Close the turn; now inject must wrap its own one-shot injection turn.
|
||||
agent.session.append('turn/end', { turn: 1, reason: { kind: 'completed' } })
|
||||
agent.inject([{ type: 'text', text: 'after' }], { source: { kind: 'plugin', plugin: 'p' } })
|
||||
const starts = agent.session.events.filter(e => e.type === 'turn/start')
|
||||
@@ -342,11 +339,9 @@ describe('Agent', () => {
|
||||
const ctx = await harness(adapter)
|
||||
const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' })
|
||||
|
||||
// steer while idle delegates to send
|
||||
agent.steer([{ type: 'text', text: 'steer idle' }], { source: { kind: 'plugin', plugin: 'test' } })
|
||||
await waitForIdle(ctx, agent)
|
||||
|
||||
// The message was recorded as a user-level message (send path)
|
||||
expect(agent.session.events.some(e => e.type === 'user/message')).toBe(true)
|
||||
expect(adapter.requests).toHaveLength(1)
|
||||
})
|
||||
@@ -369,12 +364,10 @@ describe('Agent', () => {
|
||||
prepared.markPublished()
|
||||
const dispose = prepared.startDriver()
|
||||
|
||||
// First dispose
|
||||
const firstDisposal = dispose()
|
||||
expect(agent.status).toBe('disposed')
|
||||
await firstDisposal
|
||||
|
||||
// Second dispose — idempotent, no throw
|
||||
await expect(dispose()).resolves.toBeUndefined()
|
||||
expect(agent.status).toBe('disposed')
|
||||
})
|
||||
|
||||
@@ -142,8 +142,6 @@ describe('Agent.cancel()', () => {
|
||||
|
||||
agent.queue([{ type: 'text', text: 'quiet' }])
|
||||
const idle = agent.whenIdle()
|
||||
// Cancel reaches quiescence with no status transition and no waking send;
|
||||
// whenIdle must still resolve (previously it hung until the next send).
|
||||
agent.cancel({ kind: 'user' })
|
||||
await idle
|
||||
expect(agent.session.events.some(e => e.type === 'turn/start')).toBe(false)
|
||||
|
||||
@@ -1096,7 +1096,6 @@ describe('step boundary publication order', () => {
|
||||
const ctx = await harness(adapter)
|
||||
const agent = ctx.agentLoop.create(SessionId('a-step-order'), { provider: 'mock', model: 'mock' })
|
||||
|
||||
// Append commits before observers run.
|
||||
const observed: { turn: number; step: number; lastEventType: string | undefined; sawStepStart: boolean }[] = []
|
||||
ctx.on('session/event', (subject, event) => {
|
||||
if (subject !== agent.session || event.type !== 'step/start') return
|
||||
@@ -1704,7 +1703,6 @@ describe('disposal and cancellation during pre-step assembly', () => {
|
||||
send(agent, 'go')
|
||||
await new Promise(r => setTimeout(r, 50))
|
||||
|
||||
// Start disposal, then release the block, then await disposal.
|
||||
const disposalDone = fiber.dispose()
|
||||
releasePreStep()
|
||||
await disposalDone
|
||||
|
||||
@@ -283,20 +283,17 @@ describe('SurfaceManager', () => {
|
||||
|
||||
it('empty surface yields empty nodes', () => {
|
||||
const s = new Session(SessionId('empty'))
|
||||
// Only turn boundaries, no surface nodes.
|
||||
s.append('turn/start', { turn: 1, trigger: { kind: 'message', source: { kind: 'user' } } })
|
||||
s.append('step/start', { turn: 1, step: 1 })
|
||||
s.append('step/end', { turn: 1, step: 1 })
|
||||
s.append('turn/end', { turn: 1, reason: { kind: 'completed' } })
|
||||
expect(s.surface.nodes.length).toBe(0)
|
||||
// deriveMessages returns empty array
|
||||
expect(s.deriveMessages()).toEqual([])
|
||||
})
|
||||
|
||||
it('picks up new events incrementally (delta processing)', () => {
|
||||
const s = surfaceSession()
|
||||
expect(s.surface.nodes.length).toBe(2)
|
||||
// Append another surface node
|
||||
s.append('tool/result', { turn: 1, step: 1, callId: CallId('c1'), content: [{ type: 'text', text: 'ok' }], isError: false }, { surfaceOp: 'append' })
|
||||
expect(s.surface.nodes.length).toBe(3)
|
||||
expect(s.surface.nodes[2]!).toBe(4) // seq 4: after turn/end at seq 3
|
||||
@@ -306,7 +303,6 @@ describe('SurfaceManager', () => {
|
||||
const original = surfaceSession()
|
||||
original.append('tool/result', { turn: 1, step: 1, callId: CallId('c1'), content: [{ type: 'text', text: 'ok' }], isError: false }, { surfaceOp: 'append' })
|
||||
const replayed = new Session(SessionId('replay'), [...original.events])
|
||||
// Surface rebuilds from the seeded log's markers.
|
||||
expect(replayed.surface.nodes).toEqual([1, 2, 4])
|
||||
expect(replayed.deriveMessages()).toEqual(original.deriveMessages())
|
||||
})
|
||||
|
||||
@@ -1893,7 +1893,6 @@ describe('ToolRegistry', () => {
|
||||
const ctx = await setup()
|
||||
ctx.tools.register(echoTool)
|
||||
|
||||
// Register a second tool and call its returned disposer directly
|
||||
const dispose = ctx.tools.register({ ...echoTool, name: 'disposable' })
|
||||
expect(ctx.tools.schemas().map(t => t.name)).toEqual(['echo', 'disposable'])
|
||||
|
||||
@@ -2055,9 +2054,7 @@ describe('defineTool / schema DSL', () => {
|
||||
parameters: { a: { type: 'string' as const, required: true as const }, b: { type: 'number' as const } },
|
||||
output: { schema: { type: 'string' }, render: () => [] },
|
||||
async execute(args) {
|
||||
// Verify types at runtime via typeof
|
||||
expect(typeof args.a).toBe('string')
|
||||
// args.b should be undefined when not provided
|
||||
void args
|
||||
return args.a
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user