mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
81 lines
3.5 KiB
TypeScript
81 lines
3.5 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import { Context, Service } from 'cordis'
|
|
import Loader from '@cordisjs/plugin-loader'
|
|
import { agentEvents } from '@deepseek-ai/dsh-agent'
|
|
import AgentLoop from '@deepseek-ai/dsh-agent-loop'
|
|
import { mountAgentLoopTestDependencies } from '@deepseek-ai/dsh-agent-loop-testkit'
|
|
import { CallId } from '@deepseek-ai/dsh-llm'
|
|
import { SessionId } from '@deepseek-ai/dsh-session'
|
|
import * as toolSchedule from '../src/index.ts'
|
|
|
|
class PersistenceProbe extends Service {
|
|
constructor(ctx: Context) {
|
|
super(ctx, 'sessionPersistence')
|
|
}
|
|
}
|
|
|
|
async function harness(): Promise<Context> {
|
|
const ctx = new Context()
|
|
await mountAgentLoopTestDependencies(ctx)
|
|
await ctx.plugin(PersistenceProbe)
|
|
ctx.on('session/flush', () => true)
|
|
await ctx.plugin(AgentLoop, { agents: [] })
|
|
return ctx
|
|
}
|
|
|
|
describe('Schedule plugin composition', () => {
|
|
it('has the Loader-safe function-plugin export shape', () => {
|
|
expect('default' in toolSchedule).toBe(false)
|
|
expect(toolSchedule.name).toBe('tool-schedule')
|
|
expect(toolSchedule.inject).toEqual(['agents', 'sessions', 'tools', 'sessionPersistence'])
|
|
const loader = Object.create(Loader.prototype) as Loader
|
|
expect(loader.unwrapExports(toolSchedule)).toBe(toolSchedule)
|
|
})
|
|
|
|
it('installs only on future root agents and unwinds on plugin disposal', async () => {
|
|
const ctx = await harness()
|
|
const existing = await ctx.agents.create({ sessionId: SessionId('schedule-existing') })
|
|
const plugin = await ctx.plugin(toolSchedule)
|
|
expect(ctx.tools.get('schedule_create', existing.agent)).toBeUndefined()
|
|
expect(ctx.tools.get('schedule_create')).toBeUndefined()
|
|
|
|
const root = await ctx.agents.create({ sessionId: SessionId('schedule-root') })
|
|
expect(ctx.tools.get('schedule_create', root.agent)?.name).toBe('schedule_create')
|
|
expect(ctx.tools.get('schedule_list', root.agent)?.name).toBe('schedule_list')
|
|
expect(ctx.tools.get('schedule_delete', root.agent)?.name).toBe('schedule_delete')
|
|
expect(ctx.tools.get('schedule_create')).toBeUndefined()
|
|
|
|
const created = await ctx.agents.withInitiator(root.agent, () => ctx.tools.execute({
|
|
signal: new AbortController().signal,
|
|
callId: CallId('schedule-plugin-create'),
|
|
name: 'schedule_create',
|
|
arguments: { prompt: 'future reminder', after_seconds: 3_600 },
|
|
agent: root.agent,
|
|
}))
|
|
expect(created.isError).toBe(false)
|
|
if (created.isError) throw new Error('expected Schedule create value')
|
|
expect(created.value).toMatchObject({ id: 'schedule-1', deliveryMode: 'session-local' })
|
|
agentEvents(ctx, root.agent).emit('agent/status', 'running')
|
|
agentEvents(ctx, root.agent).emit('agent/status', 'idle')
|
|
|
|
const child = await root.agent.ctx.agents.create({ sessionId: SessionId('schedule-child') })
|
|
expect(ctx.agents.roots()).toEqual([existing.agent, root.agent])
|
|
expect(ctx.tools.get('schedule_create', child.agent)).toBeUndefined()
|
|
|
|
const departing = await ctx.agents.create({ sessionId: SessionId('schedule-departing') })
|
|
expect(ctx.tools.get('schedule_create', departing.agent)).toBeDefined()
|
|
await departing.dispose()
|
|
expect(ctx.tools.get('schedule_create', departing.agent)).toBeUndefined()
|
|
|
|
await plugin.dispose()
|
|
expect(ctx.tools.get('schedule_create', root.agent)).toBeUndefined()
|
|
expect(ctx.tools.get('schedule_list', root.agent)).toBeUndefined()
|
|
expect(ctx.tools.get('schedule_delete', root.agent)).toBeUndefined()
|
|
|
|
await child.dispose()
|
|
await root.dispose()
|
|
await existing.dispose()
|
|
await ctx.fiber.dispose()
|
|
})
|
|
})
|