Add abstract service interface packages
@deepseek-ai/dsh-llm: provider-neutral content-block vocabulary (merge-extensible maps), raw StreamChunk protocol, ToolSchema, abstract LlmAdapter, LlmService adapter registry, BlockAssembler. @deepseek-ai/dsh-session: event-sourced Session (append-only log, deriveMessages; context/steering render as tagged envelopes), SessionStore, session/event + awaited session/flush durability seam. @deepseek-ai/dsh-system-prompt: ordered sections + tool-schema providers; assemble() through the system-prompt/assemble waterfall. Tool schemas are part of the assembly by design. @deepseek-ai/dsh-tools: tool registry feeding schemas into the assembly; execute() through the tools/execute waterfall (the single sandbox/permission/hook seam). @deepseek-ai/dsh-agent: Agent interface (send/steer/inject/abort, spawn/fork TODO seams), AgentRegistry, and the full agent/* event taxonomy so plugins never depend on the concrete loop.
This commit is contained in:
54
packages/agent/tests/agent.spec.ts
Normal file
54
packages/agent/tests/agent.spec.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { Context } from 'cordis'
|
||||
import { Session } from '@deepseek-ai/dsh-session'
|
||||
import AgentRegistry, { Agent } from '@deepseek-ai/dsh-agent'
|
||||
|
||||
function stubAgent(id: string): Agent {
|
||||
return {
|
||||
id,
|
||||
options: {},
|
||||
session: new Session(`${id}-session`),
|
||||
status: 'idle',
|
||||
send() {},
|
||||
steer() {},
|
||||
inject() {},
|
||||
abort() {},
|
||||
}
|
||||
}
|
||||
|
||||
describe('AgentRegistry', () => {
|
||||
it('registers agents and emits created/disposed events', async () => {
|
||||
const ctx = new Context()
|
||||
await ctx.plugin(AgentRegistry)
|
||||
|
||||
const created: string[] = []
|
||||
const disposed: string[] = []
|
||||
ctx.on('agent/created', agent => void created.push(agent.id))
|
||||
ctx.on('agent/disposed', agent => void disposed.push(agent.id))
|
||||
|
||||
const agent = stubAgent('a1')
|
||||
const dispose = ctx.agents.register(agent)
|
||||
expect(created).toEqual(['a1'])
|
||||
expect(ctx.agents.get('a1')).toBe(agent)
|
||||
expect(ctx.agents.list()).toEqual([agent])
|
||||
|
||||
dispose()
|
||||
expect(disposed).toEqual(['a1'])
|
||||
expect(ctx.agents.get('a1')).toBeUndefined()
|
||||
})
|
||||
|
||||
it('rejects duplicate ids and unregisters on fiber dispose (HMR safety)', async () => {
|
||||
const ctx = new Context()
|
||||
await ctx.plugin(AgentRegistry)
|
||||
ctx.agents.register(stubAgent('main'))
|
||||
expect(() => ctx.agents.register(stubAgent('main'))).toThrow('already registered')
|
||||
|
||||
const fiber = await ctx.plugin(Object.assign((inner: Context) => {
|
||||
inner.agents.register(stubAgent('scoped'))
|
||||
}, { inject: ['agents'] }))
|
||||
expect(ctx.agents.list().map(a => a.id)).toEqual(['main', 'scoped'])
|
||||
|
||||
await fiber.dispose()
|
||||
expect(ctx.agents.list().map(a => a.id)).toEqual(['main'])
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user