index.ts 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. /**
  2. * @deepseek-ai/dsh-host-apiproxy — the API gateway every client shape shares:
  3. * the ApiProxy contract (api/: types + zod schemas, browser-safe), the fetch
  4. * carrier pair (fetch/: toFetchHandler on the host side, AbstractApiClient +
  5. * platform subclasses on the client side), and the host-side implementation
  6. * (api-proxy.ts: createApiProxy + the ApiProxyService gateway plugin providing
  7. * `ctx.apiProxy`). Transport-agnostic by design: this package registers no
  8. * routes — carriers (HTTP today, IPC later) wrap `ctx.apiProxy` themselves.
  9. */
  10. import { resolve } from 'node:path'
  11. import { Context, Service } from 'cordis'
  12. import z from 'schemastery'
  13. import type { ApiProxy } from './api/index.ts'
  14. import { createApiProxy } from './api-proxy.ts'
  15. export type * from './api/index.ts'
  16. export { RpcId } from './api/rpc.ts'
  17. export { toFetchHandler } from './fetch/handler.ts'
  18. export { AbstractApiClient, InProcessApiClient } from './fetch/client.ts'
  19. export type { IApiClient } from './fetch/client.ts'
  20. export { createApiProxy } from './api-proxy.ts'
  21. export type { ApiProxyDefaults } from './api-proxy.ts'
  22. declare module 'cordis' {
  23. interface Context {
  24. /** The host-side ApiProxy implementation (the transport-agnostic gateway face). */
  25. apiProxy: ApiProxy
  26. }
  27. }
  28. /** Gateway plugin config: host-level agent routing and Workspace creation root. */
  29. export interface Config {
  30. /** Default provider route for created/resumed agents. */
  31. provider: string
  32. /** Default model id. */
  33. model: string
  34. /** Parent directory for name-created Workspaces; defaults to the Host cwd. */
  35. workspaceRoot?: string
  36. }
  37. /**
  38. * The API gateway service: implements the ApiProxy contract over the composed
  39. * host context and provides it as `ctx.apiProxy`. The Host cwd is the default
  40. * project directory and the fallback parent for name-created Workspaces.
  41. */
  42. export class ApiProxyService extends Service implements ApiProxy {
  43. static inject = ['agents', 'directoryPicker', 'llm', 'sessions', 'tools', 'userInteraction', 'workspace']
  44. static Config: z<Config> = z.object({
  45. provider: z.string().required(),
  46. model: z.string().required(),
  47. workspaceRoot: z.string(),
  48. })
  49. readonly sessions: ApiProxy['sessions']
  50. readonly workspace: ApiProxy['workspace']
  51. readonly host: ApiProxy['host']
  52. readonly commands: ApiProxy['commands']
  53. readonly goals: ApiProxy['goals']
  54. readonly skills: ApiProxy['skills']
  55. readonly events: ApiProxy['events']
  56. readonly respond: ApiProxy['respond']
  57. constructor(ctx: Context, config: Config) {
  58. super(ctx, 'apiProxy')
  59. const cwd = process.cwd()
  60. const api = createApiProxy(ctx, {
  61. provider: config.provider,
  62. model: config.model,
  63. cwd,
  64. workspaceRoot: resolve(config.workspaceRoot ?? cwd),
  65. })
  66. this.sessions = api.sessions
  67. this.workspace = api.workspace
  68. this.host = api.host
  69. this.commands = api.commands
  70. this.goals = api.goals
  71. this.skills = api.skills
  72. this.events = api.events
  73. // createApiProxy returns closures (no `this` capture); bind only satisfies
  74. // the unbound-method lint without changing behavior.
  75. this.respond = api.respond.bind(api)
  76. }
  77. }
  78. export default ApiProxyService