| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879 |
- import { describe, expect, it } from 'vitest'
- import { Context } from 'cordis'
- import Loader from '@cordisjs/plugin-loader'
- import * as agentCore from '../src/index.ts'
- import { AgentId } from '@deepseek-ai/dsh-agent'
- /**
- * Unit coverage for the @deepseek-ai/dsh-agent-core bundle: mounting it brings
- * up the whole providerless spine in one `ctx.plugin`, and the forwarded
- * `agents` config reaches the loop (default `[]`, or a pre-created agent).
- *
- * The bundle is exercised through `ctx.plugin(agentCore, …)` — the NAMESPACE
- * import, the same shape the Loader builds from `unwrapExports`. The real
- * Loader-path guard (export shape, `unwrapExports`) is the app packages' keyless
- * bin smokes; here we assert the composition + config forwarding.
- */
- async function mount(config?: agentCore.Config): Promise<Context> {
- const ctx = new Context()
- await ctx.plugin(agentCore, config)
- // The bundle mounts its children inside apply() (not awaited there); let their
- // fibers settle so the spine services and any pre-created agent are ready.
- await new Promise(resolve => setTimeout(resolve, 50))
- return ctx
- }
- describe('dsh-agent-core bundle', () => {
- it('brings up the full providerless spine', async () => {
- const ctx = await mount()
- // One service from each layer of the spine proves the children loaded.
- expect(ctx.get('timer')).toBeDefined()
- expect(ctx.get('llm')).toBeDefined()
- expect(ctx.get('sessions')).toBeDefined()
- expect(ctx.get('systemPrompt')).toBeDefined()
- expect(ctx.get('tools')).toBeDefined()
- expect(ctx.get('agents')).toBeDefined()
- expect(ctx.get('agentLoop')).toBeDefined()
- await ctx.fiber.dispose()
- })
- it('defaults the agents list to empty (no pre-created agents)', async () => {
- const ctx = await mount()
- expect(ctx.get('agents')?.get(AgentId('main'))).toBeUndefined()
- await ctx.fiber.dispose()
- })
- it('forwards a pre-created agent to the loop', async () => {
- const ctx = await mount({
- agents: [{ id: AgentId('main'), model: 'mock', systemPrompt: 'hi' }],
- })
- expect(ctx.get('agents')?.get(AgentId('main'))).toBeDefined()
- await ctx.fiber.dispose()
- })
- it('re-exports the loop config schema as its own', () => {
- expect(agentCore.Config).toBeDefined()
- expect(agentCore.name).toBe('agent-core')
- })
- it('has the namespace-plugin export shape (no stray default) so the Loader keeps name/Config/apply', () => {
- // Postmortem 0001 guard: a stray `export default apply` makes the Loader's
- // `unwrapExports` (`exports.default ?? exports`) collapse the module to the
- // bare `apply` function, DROPPING the named `name`/`Config`. This package has
- // no `inject` export (it mounts children that carry their own), so that
- // collapse would NOT crash at load — the plugin would boot but silently lose
- // its config schema. This bundle is also never Loader-unwrapped by any smoke
- // (the apps import it directly; the mount test namespace-mounts it), so this
- // is its ONLY export-shape guard. Assert directly AND through the real
- // `unwrapExports` so adding `export default` to src/index.ts fails here.
- expect('default' in agentCore).toBe(false)
- expect(typeof agentCore.apply).toBe('function')
- const loader = Object.create(Loader.prototype) as Loader
- const unwrapped = loader.unwrapExports(agentCore) as Record<string, unknown>
- expect(unwrapped).toBe(agentCore)
- expect(unwrapped.name).toBe('agent-core')
- expect(unwrapped.Config).toBeDefined()
- expect(typeof unwrapped.apply).toBe('function')
- })
- })
|