index.ts 3.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  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 — physical carriers 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 = [
  44. 'agents', 'directoryPicker', 'llm', 'sessions', 'subagents', 'sessionQuery',
  45. 'tools', 'userInteraction', 'workspace',
  46. ]
  47. static Config: z<Config> = z.object({
  48. provider: z.string().required(),
  49. model: z.string().required(),
  50. workspaceRoot: z.string(),
  51. })
  52. readonly sessions: ApiProxy['sessions']
  53. readonly subagents: ApiProxy['subagents']
  54. readonly workspace: ApiProxy['workspace']
  55. readonly host: ApiProxy['host']
  56. readonly commands: ApiProxy['commands']
  57. readonly goals: ApiProxy['goals']
  58. readonly skills: ApiProxy['skills']
  59. readonly settings: ApiProxy['settings']
  60. readonly credentials: ApiProxy['credentials']
  61. readonly llm: ApiProxy['llm']
  62. readonly events: ApiProxy['events']
  63. readonly respond: ApiProxy['respond']
  64. constructor(ctx: Context, config: Config) {
  65. super(ctx, 'apiProxy')
  66. const cwd = process.cwd()
  67. const api = createApiProxy(ctx, {
  68. provider: config.provider,
  69. model: config.model,
  70. cwd,
  71. workspaceRoot: resolve(config.workspaceRoot ?? cwd),
  72. })
  73. this.sessions = api.sessions
  74. this.subagents = api.subagents
  75. this.workspace = api.workspace
  76. this.host = api.host
  77. this.commands = api.commands
  78. this.goals = api.goals
  79. this.skills = api.skills
  80. this.settings = api.settings
  81. this.credentials = api.credentials
  82. this.llm = api.llm
  83. this.events = api.events
  84. // createApiProxy returns closures (no `this` capture); bind only satisfies
  85. // the unbound-method lint without changing behavior.
  86. this.respond = api.respond.bind(api)
  87. }
  88. }
  89. export default ApiProxyService