index.ts 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. /**
  2. * Shared service mounting, real AgentLoop drivers, and structural Inbox stubs
  3. * for agent-loop tests. Callers retain ownership of their contexts, adapters,
  4. * optional plugins, agents, and teardown.
  5. * @module @deepseek-ai/dsh-agent-loop-testkit
  6. */
  7. import type { Context } from '@deepseek-ai/cordis'
  8. import AgentRegistry from '@deepseek-ai/dsh-agent'
  9. import type { Agent, AgentOptions, Inbox, InboxTarget } from '@deepseek-ai/dsh-agent'
  10. import AgentLoop from '@deepseek-ai/dsh-agent-loop'
  11. import LlmRuntime from '@deepseek-ai/dsh-llm'
  12. import SessionStore from '@deepseek-ai/dsh-session'
  13. import type { SessionHeader, SessionId, UserMessage } from '@deepseek-ai/dsh-session'
  14. import SessionProjectionRegistry from '@deepseek-ai/dsh-session-projection'
  15. import SystemPrompt from '@deepseek-ai/dsh-system-prompt'
  16. import type { Config as SystemPromptConfig } from '@deepseek-ai/dsh-system-prompt'
  17. import ToolRuntime from '@deepseek-ai/dsh-tools'
  18. import type { Config as ToolRuntimeConfig } from '@deepseek-ai/dsh-tools'
  19. export { createInboxStub, unsupportedInbox } from './inbox.ts'
  20. interface DriverInbox extends Inbox {
  21. claim(target: InboxTarget, turn: number): UserMessage[]
  22. }
  23. /** Test driver for production Agents created by a mounted AgentLoop. */
  24. export interface AgentLoopTestHarness {
  25. /**
  26. * Create a production Agent and fresh Session owned by the harness context.
  27. * @param id - shared Agent and Session identity.
  28. * @param options - concrete loop options.
  29. * @param meta - optional fresh-session workspace metadata.
  30. * @returns the published production Agent after creation completes.
  31. */
  32. create(id: SessionId, options?: AgentOptions, meta?: Pick<SessionHeader, 'cwd'>): Promise<Agent>
  33. /**
  34. * Admit pending messages through the production loop driver's claim operation.
  35. * @param agent - Agent returned by this harness's `create` method.
  36. * @param target - boundary whose pending input is admitted.
  37. * @param turn - turn that owns the admitted messages.
  38. * @returns next-step messages followed by one next-turn message when requested.
  39. */
  40. claim(agent: Agent, target: InboxTarget, turn: number): UserMessage[]
  41. }
  42. /** Configuration forwarded to the prerequisite service plugins. */
  43. export interface AgentLoopTestDependenciesOptions {
  44. /** Configuration for the system-prompt registry. */
  45. readonly systemPrompt?: SystemPromptConfig
  46. /** Configuration for the tool registry. */
  47. readonly tools?: ToolRuntimeConfig
  48. }
  49. /**
  50. * Mount the standard prerequisite services for an AgentLoop test.
  51. *
  52. * The function deliberately does not mount AgentLoop or register an adapter,
  53. * so tests retain control of load order and the topology under test. The
  54. * context owns every mounted service and remains responsible for disposal. A
  55. * plugin-load failure rejects the promise; services activated earlier in the
  56. * sequence remain context-owned and unwind with that context.
  57. * @param ctx - test context that owns the mounted services.
  58. * @param options - optional service configuration forwarded without mutation.
  59. * @returns after every prerequisite service has activated.
  60. */
  61. export async function mountAgentLoopTestDependencies(
  62. ctx: Context,
  63. options: AgentLoopTestDependenciesOptions = {},
  64. ): Promise<void> {
  65. await ctx.plugin(LlmRuntime)
  66. await ctx.plugin(SessionStore)
  67. await ctx.plugin(SessionProjectionRegistry)
  68. await ctx.plugin(SystemPrompt, options.systemPrompt ?? {})
  69. await ctx.plugin(ToolRuntime, options.tools ?? {})
  70. await ctx.plugin(AgentRegistry)
  71. }
  72. /**
  73. * Mount the production AgentLoop and expose its narrow test-driver operations.
  74. * Mount {@link mountAgentLoopTestDependencies} and any load-order-sensitive
  75. * consumers before calling this helper. The context owns the loop and every
  76. * Agent returned by the harness.
  77. * @param ctx - test context with the AgentLoop prerequisite services active.
  78. * @returns a driver that creates production Agents and claims their real Inbox.
  79. */
  80. export async function mountAgentLoopTestHarness(ctx: Context): Promise<AgentLoopTestHarness> {
  81. await ctx.plugin(AgentLoop, { agents: [] })
  82. return {
  83. create: async (id, options = {}, meta = {}) => ctx.agentLoop.create(id, options, meta),
  84. claim: (agent, target, turn) => (agent.inbox as DriverInbox).claim(target, turn),
  85. }
  86. }