index.ts 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. /**
  2. * Headless one-shot app composition: the default agent spine, JSONL session
  3. * persistence, and one fresh top-level agent. The CLI driver owns task
  4. * submission and output; the app deliberately mounts no interactive or logging
  5. * front door so stdout remains protocol-pure.
  6. * @module @deepseek-ai/dsh-cli-demo
  7. */
  8. import type { Context } from 'cordis'
  9. import z from 'schemastery'
  10. import { SessionId } from '@deepseek-ai/dsh-session'
  11. import ToolRegistry, { type Config as ToolsConfig } from '@deepseek-ai/dsh-tools'
  12. import * as agentCore from '@deepseek-ai/dsh-agent-spine-demo'
  13. import SessionPersistenceJsonl, {
  14. JsonlCompressionSchema,
  15. type JsonlCompression,
  16. } from '@deepseek-ai/dsh-session-persistence-jsonl'
  17. import * as sessionCheckpointPolicy from '@deepseek-ai/dsh-session-checkpoint-policy'
  18. import * as workspaceContext from '@deepseek-ai/dsh-workspace-context'
  19. const DEFAULT_PERSISTENCE_ROOT = './.sessions'
  20. export const name = 'cli-demo'
  21. /** App config forwarded to the spine, configured agent, and JSONL backend. */
  22. export interface Config {
  23. /** Provider route for the configured agent. */
  24. provider: string
  25. /** Model name for the configured agent; a matching adapter must be registered. */
  26. model: string
  27. /** Bundled agent-loop concurrency cap; `1` is serial and omission uses its default. */
  28. maxParallelToolCalls?: number
  29. /** Deployment persona forwarded to the system-prompt plugin. */
  30. persona?: string
  31. /** Explicit model-facing tool order forwarded to the system-prompt plugin. */
  32. toolOrder?: string[]
  33. /** Tool-registry presentation config forwarded through agent-spine-demo. */
  34. tools?: ToolsConfig
  35. /** DeepSeek Harness home directory exposed to bash and used for local skill discovery. */
  36. dshHome?: string
  37. /** Fallback session-title limits forwarded through agent-spine-demo. */
  38. sessionTitle?: NonNullable<agentCore.Config['sessionTitle']>
  39. /** Directory the JSONL session backend writes under. Defaults to `./.sessions`. */
  40. persistenceRoot?: string
  41. /** JSONL artifact encoding; defaults to checksummed Zstandard frames. */
  42. persistenceCompression?: JsonlCompression
  43. /** Skill registry, local-provider, and model-facing consumer config. */
  44. skills?: agentCore.SkillConfig
  45. /** Model-facing bash tool config forwarded through agent-spine-demo. */
  46. toolBash?: NonNullable<agentCore.Config['toolBash']>
  47. /** Generic background-task control-tool config forwarded through agent-spine-demo. */
  48. toolTasks?: NonNullable<agentCore.Config['toolTasks']>
  49. /** Controls automatic AGENTS.md/CLAUDE.md loading; configure a byte budget or set `false`. */
  50. workspaceContext: agentCore.Config['workspaceContext']
  51. }
  52. // Each front door keeps a complete Loader schema so its deployment contract is
  53. // readable without a cross-package config facade.
  54. /* jscpd:ignore-start */
  55. export const Config: z<Config> = z.object({
  56. provider: z.string().required(),
  57. model: z.string().required(),
  58. maxParallelToolCalls: z.number().step(1).min(1),
  59. persistenceRoot: z.string().default(DEFAULT_PERSISTENCE_ROOT),
  60. persistenceCompression: JsonlCompressionSchema,
  61. persona: z.string(),
  62. dshHome: z.string(),
  63. sessionTitle: agentCore.SessionTitleConfigSchema,
  64. skills: agentCore.SkillConfigSchema,
  65. // Absent means lexicographic order; schemastery's native array default is [].
  66. toolOrder: z.array(z.string()).default(undefined as unknown as string[]),
  67. tools: ToolRegistry.Config,
  68. toolBash: agentCore.ToolBashConfigSchema,
  69. toolTasks: z.union([z.const(false), agentCore.ToolTasksConfigSchema]),
  70. workspaceContext: z.union([z.const(false), workspaceContext.Config]).required(),
  71. })
  72. /* jscpd:ignore-end */
  73. /**
  74. * Compose the UI-less spine, a fresh top-level agent rooted at the process cwd,
  75. * and JSONL persistence. Swappable adapters, executors, and product tools stay
  76. * in the leaf `cordis.yml`.
  77. * @param ctx - app context that owns the composed child plugins.
  78. * @param config - validated app configuration.
  79. */
  80. export function apply(ctx: Context, config: Config): void {
  81. ctx.plugin(agentCore, {
  82. ...agentCore.pickSpineConfig(config),
  83. agents: [{ id: SessionId('main'), provider: config.provider, model: config.model, cwd: process.cwd() }],
  84. })
  85. ctx.plugin(SessionPersistenceJsonl, {
  86. root: config.persistenceRoot ?? DEFAULT_PERSISTENCE_ROOT,
  87. ...(config.persistenceCompression === undefined ? {} : { compression: config.persistenceCompression }),
  88. })
  89. ctx.plugin(sessionCheckpointPolicy)
  90. }