mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-09-09 04:02:35 +00:00
# Conflicts: # apps/cli/tests/fixtures/dsh-badge/snapshot.ts # docs/config-catalog.i18n.yaml # docs/config-catalog.md # docs/config-catalog.zh.md # docs/event-producer-consumer.i18n.yaml # docs/event-producer-consumer.md # docs/event-producer-consumer.zh.md # docs/module-graph.i18n.yaml # docs/module-graph.md # docs/module-graph.zh.md # docs/persistence-catalog.i18n.yaml # docs/persistence-catalog.md # docs/persistence-catalog.zh.md # packages/api/session-controller/tests/session-projections.host.spec.ts # packages/context/agent-instructions/tests/agent-instructions.e2e.ts # packages/context/agent-instructions/tests/agent-instructions.spec.ts # packages/context/tmux-context/tests/tmux-context.spec.ts # packages/core/agent-loop/package.json # packages/core/agent-loop/src/agent.ts # packages/core/agent-loop/src/index.ts # packages/core/agent/src/index.ts # packages/core/agent/src/types.ts # packages/goal/goal/tests/goal.spec.ts # packages/goal/tool-goal/package.json # packages/llm/llm-retry/tests/retry.spec.ts # packages/session-query/session-query/tests/observation.spec.ts # packages/shell/tool-pwsh-persistent/tests/loader-composition.spec.ts # packages/test-support/agent-loop-testkit/package.json # packages/workflow/workflow-worker-thread/tests/workflow-worker-thread.e2e.ts # pnpm-lock.yaml
109 lines
4.0 KiB
TypeScript
109 lines
4.0 KiB
TypeScript
/** The `agent-loop` settings section layered over the composition entry. */
|
|
|
|
import { describe, expect, it } from 'vitest'
|
|
import { Context } from '@deepseek-ai/cordis'
|
|
import type { Fiber } from '@deepseek-ai/cordis'
|
|
import LlmRuntime from '@deepseek-ai/dsh-llm'
|
|
import SessionStore from '@deepseek-ai/dsh-session'
|
|
import SystemPrompt from '@deepseek-ai/dsh-system-prompt'
|
|
import ToolRuntime from '@deepseek-ai/dsh-tools'
|
|
import AgentRegistry from '@deepseek-ai/dsh-agent'
|
|
import SessionProjectionRegistry from '@deepseek-ai/dsh-session-projection'
|
|
import { SettingsProvider } from '@deepseek-ai/dsh-settings'
|
|
import type { SettingsNamespace } from '@deepseek-ai/dsh-settings'
|
|
import AgentLoop, { AGENT_LOOP_SETTINGS_NAMESPACE } from '@deepseek-ai/dsh-agent-loop'
|
|
|
|
/** The smallest real provider: one in-memory document, always writable. */
|
|
class MemorySettings extends SettingsProvider {
|
|
doc: Record<string, unknown> = {}
|
|
|
|
get writable(): boolean {
|
|
return true
|
|
}
|
|
|
|
protected load(): Promise<Record<string, unknown>> {
|
|
return Promise.resolve(structuredClone(this.doc))
|
|
}
|
|
|
|
protected persist(ns: SettingsNamespace, section: Record<string, unknown>): Promise<void> {
|
|
this.doc = { ...this.doc, [ns]: structuredClone(section) }
|
|
return Promise.resolve()
|
|
}
|
|
}
|
|
|
|
async function boot(): Promise<{ ctx: Context; settingsFiber: Fiber; loopFiber: Fiber }> {
|
|
const ctx = new Context()
|
|
await ctx.plugin(LlmRuntime)
|
|
await ctx.plugin(SessionStore)
|
|
await ctx.plugin(SessionProjectionRegistry)
|
|
await ctx.plugin(SystemPrompt)
|
|
await ctx.plugin(ToolRuntime)
|
|
await ctx.plugin(AgentRegistry)
|
|
const settingsFiber = ctx.plugin(MemorySettings)
|
|
await settingsFiber.await()
|
|
const loopFiber = ctx.plugin(AgentLoop, { agents: [], maxParallelToolCalls: 4 })
|
|
await loopFiber.await()
|
|
return { ctx, settingsFiber, loopFiber }
|
|
}
|
|
|
|
describe('agent-loop settings section', () => {
|
|
it('layers the stored parallel cap over the composition entry', async () => {
|
|
const bench = await boot()
|
|
expect(bench.ctx.agentLoop.config.maxParallelToolCalls).toBe(4)
|
|
|
|
await bench.ctx.settings.update(AGENT_LOOP_SETTINGS_NAMESPACE, { maxParallelToolCalls: 1 })
|
|
|
|
expect(bench.ctx.agentLoop.config.maxParallelToolCalls).toBe(1)
|
|
await bench.ctx.fiber.dispose()
|
|
})
|
|
|
|
it('refuses a non-positive cap at the write', async () => {
|
|
const bench = await boot()
|
|
|
|
await expect(bench.ctx.settings.update(AGENT_LOOP_SETTINGS_NAMESPACE, { maxParallelToolCalls: 0 }))
|
|
.rejects.toThrow()
|
|
|
|
expect(bench.ctx.agentLoop.config.maxParallelToolCalls).toBe(4)
|
|
await bench.ctx.fiber.dispose()
|
|
})
|
|
|
|
it('never offers the composed agents array to the settings document', async () => {
|
|
const bench = await boot()
|
|
|
|
const descriptor = bench.ctx.settings.describe().find(row => String(row.ns) === 'agent-loop')
|
|
|
|
expect(Object.keys(descriptor?.value as object)).toEqual(['maxParallelToolCalls'])
|
|
await bench.ctx.fiber.dispose()
|
|
})
|
|
|
|
it('keeps serving the composed agents array to its own consumers', async () => {
|
|
const bench = await boot()
|
|
|
|
await bench.ctx.settings.update(AGENT_LOOP_SETTINGS_NAMESPACE, { maxParallelToolCalls: 2 })
|
|
|
|
expect(bench.ctx.agentLoop.config.agents).toEqual([])
|
|
await bench.ctx.fiber.dispose()
|
|
})
|
|
|
|
it('falls back to the composition entry when the settings provider detaches', async () => {
|
|
const bench = await boot()
|
|
await bench.ctx.settings.update(AGENT_LOOP_SETTINGS_NAMESPACE, { maxParallelToolCalls: 1 })
|
|
expect(bench.ctx.agentLoop.config.maxParallelToolCalls).toBe(1)
|
|
|
|
await bench.settingsFiber.dispose()
|
|
|
|
expect(bench.ctx.agentLoop.config.maxParallelToolCalls).toBe(4)
|
|
await bench.ctx.fiber.dispose()
|
|
})
|
|
|
|
it('releases the namespace when the service unloads', async () => {
|
|
const bench = await boot()
|
|
expect(bench.ctx.settings.describe().map(row => String(row.ns))).toContain('agent-loop')
|
|
|
|
await bench.loopFiber.dispose()
|
|
|
|
expect(bench.ctx.settings.describe().map(row => String(row.ns))).not.toContain('agent-loop')
|
|
await bench.ctx.fiber.dispose()
|
|
})
|
|
})
|