index.ts 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. /**
  2. * Default executor-less, UI-less agent spine. It bundles the common services,
  3. * concrete loop, local skill provider, and model-facing bash/skill consumers;
  4. * deployments still choose the LLM adapter, bash executor, and presentation.
  5. * The plugin intentionally exposes named exports only because Loader default
  6. * unwrapping would discard its `Config` schema (see docs/postmortem/0001).
  7. * @module @deepseek-ai/dsh-agent-core
  8. */
  9. import type { Context } from 'cordis'
  10. import Timer from '@cordisjs/plugin-timer'
  11. import z from 'schemastery'
  12. import LlmService from '@deepseek-ai/dsh-llm'
  13. import SessionStore from '@deepseek-ai/dsh-session'
  14. import SystemPrompt, { type Config as SystemPromptConfig } from '@deepseek-ai/dsh-system-prompt'
  15. import ToolRegistry, { type Config as ToolsConfig } from '@deepseek-ai/dsh-tools'
  16. import SkillService, { type Config as SkillRegistryConfig } from '@deepseek-ai/dsh-skill'
  17. import * as SkillLocal from '@deepseek-ai/dsh-skill-local'
  18. import AgentRegistry from '@deepseek-ai/dsh-agent'
  19. import * as invariants from '@deepseek-ai/dsh-invariants'
  20. import * as toolBash from '@deepseek-ai/dsh-tool-bash'
  21. import * as toolSkill from '@deepseek-ai/dsh-tool-skill'
  22. import AgentLoop, { type Config as AgentLoopConfig } from '@deepseek-ai/dsh-agent-loop'
  23. export const name = 'agent-core'
  24. /** Skill bundle config forwarded to the registry, local provider, and model-facing consumer. */
  25. export interface SkillConfig {
  26. /** Registry-level discovery cache settings. */
  27. registry?: SkillRegistryConfig
  28. /** Local filesystem skill provider settings. */
  29. local?: SkillLocal.Config
  30. /** Model-facing skill catalog and tool settings. */
  31. tool?: toolSkill.Config
  32. }
  33. /**
  34. * Bundle config: each field forwarded verbatim to the child that owns it — `agents` to the
  35. * agent loop (an app that pre-creates no agents, like the ACP bridge, omits it),
  36. * `persona` and `toolOrder` to the system-prompt plugin (the deployment's persona section and
  37. * the explicit model-facing tool order), the `tools` object to the tool registry (its
  38. * presentation `mode`), and `skills` to the skill registry/local provider/tool consumer.
  39. * The schema intersects the owners' schemas, which supply defaults for every
  40. * optional input and keep validation from drifting.
  41. */
  42. export interface Config {
  43. /** The agent-loop `agents` list (see dsh-agent-loop's `Config`). */
  44. agents?: AgentLoopConfig['agents']
  45. /** The deployment persona (see dsh-system-prompt's `Config`). */
  46. persona?: SystemPromptConfig['persona']
  47. /** The explicit model-facing tool order (see dsh-system-prompt's `Config`). */
  48. toolOrder?: SystemPromptConfig['toolOrder']
  49. /** The tool registry's config — its presentation `mode` (see dsh-tools' `Config`). */
  50. tools?: ToolsConfig
  51. /** Skill registry, local provider, and model-facing consumer config. */
  52. skills?: SkillConfig
  53. }
  54. /** The skill config schema exported for app packages that forward `skills`. */
  55. export const SkillConfigSchema: z<SkillConfig> = z.object({
  56. registry: SkillService.Config,
  57. local: SkillLocal.Config,
  58. tool: toolSkill.Config,
  59. })
  60. /** Intersect the owners' schemas so validation + defaulting stay identical. */
  61. export const Config = z.intersect([
  62. AgentLoop.Config,
  63. SystemPrompt.Config,
  64. z.object({ tools: ToolRegistry.Config, skills: SkillConfigSchema }),
  65. ]) as unknown as z<Config>
  66. /**
  67. * Load the spine. Each `ctx.plugin(...)` mounts one child of the bundle fiber;
  68. * `agent-loop` receives the forwarded `agents` list and `system-prompt` the
  69. * forwarded `persona` and `toolOrder`. Load order is irrelevant (cordis pends
  70. * each fiber on its `inject` until the services it needs exist), but the
  71. * listing mirrors the dependency layering for readability: the LLM vocabulary
  72. * and core registries first, then the dev tripwire and the bash tool consumer,
  73. * then the loop that drives them.
  74. */
  75. export function apply(ctx: Context, config: Config): void {
  76. ctx.plugin(Timer)
  77. ctx.plugin(LlmService)
  78. ctx.plugin(SessionStore)
  79. // Owner schemas resolve defaults; forward toolOrder only when explicitly set.
  80. ctx.plugin(SystemPrompt, {
  81. persona: config.persona ?? '',
  82. ...config.toolOrder !== undefined ? { toolOrder: config.toolOrder } : {},
  83. })
  84. ctx.plugin(ToolRegistry, config.tools ?? {})
  85. ctx.plugin(SkillService, config.skills?.registry ?? {})
  86. ctx.plugin(SkillLocal, config.skills?.local ?? {})
  87. ctx.plugin(AgentRegistry)
  88. ctx.plugin(invariants)
  89. ctx.plugin(toolBash)
  90. ctx.plugin(toolSkill, config.skills?.tool ?? {})
  91. ctx.plugin(AgentLoop, { agents: config.agents ?? [] })
  92. }