| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118 |
- /**
- * @deepseek-ai/dsh-host-apiproxy — the API gateway every client shape shares:
- * the ApiProxy contract (api/: types + zod schemas, browser-safe), the fetch
- * carrier pair (fetch/: toFetchHandler on the host side, AbstractApiClient +
- * platform subclasses on the client side), and the host-side implementation
- * (api-proxy.ts: createApiProxy + the ApiProxyService gateway plugin providing
- * `ctx.apiProxy`). Transport-agnostic by design: this package registers no
- * routes — physical carriers wrap `ctx.apiProxy` themselves.
- *
- * The gateway consumes `ctx.agentDefaultModel`, the transport-independent default
- * shared with direct entry points. Switching models persists through that
- * service; sessions that have already logged a selection remain unchanged.
- */
- import { Context, Service } from '@deepseek-ai/cordis'
- import z from '@deepseek-ai/schemastery'
- import type {} from '@deepseek-ai/dsh-agent-default-model'
- import type { ApiProxy } from './api/index.ts'
- import { createApiProxy } from './api-proxy.ts'
- import {
- DEFAULT_SESSION_LOG_COMPRESSION_LEVEL,
- type SessionLogCompressionLevel,
- } from './session-export.ts'
- export type * from './api/index.ts'
- export { RpcId } from './api/rpc.ts'
- export { toFetchHandler } from './fetch/handler.ts'
- export { AbstractApiClient, InProcessApiClient } from './fetch/client.ts'
- export type { IApiClient } from './fetch/client.ts'
- export { createApiProxy } from './api-proxy.ts'
- export type { ApiProxyDefaults } from './api-proxy.ts'
- declare module '@deepseek-ai/cordis' {
- interface Context {
- /** The host-side ApiProxy implementation (the transport-agnostic gateway face). */
- apiProxy: ApiProxy
- }
- }
- /** Gateway plugin configuration. */
- export interface Config {
- /**
- * Whether this deployment can hand paths to a native desktop opener —
- * the `hasDocument` capability the agent-preset roster reports. Absent,
- * the platform is asked (macOS/Windows/WSL yes; Linux only with a display
- * server); set it explicitly where detection misleads, e.g. `false` in a
- * container whose DISPLAY points nowhere a user can see.
- */
- nativeOpen?: boolean
- /**
- * DEFLATE level for every session-log ZIP entry: `0` stores without
- * compression, `1` favors CPU/latency, and `9` favors archive size.
- * @default 6
- */
- sessionExportCompressionLevel?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
- }
- /**
- * The API gateway service: implements the ApiProxy contract over the composed
- * host context and provides it as `ctx.apiProxy`. The Host cwd is the default
- * project directory.
- */
- export class ApiProxyService extends Service implements ApiProxy {
- static inject = [
- 'agentDefaultModel', 'agents', 'attachments', 'directoryPicker', 'llm', 'sessions', 'subagents', 'sessionQuery',
- 'tools', 'userQuestions', 'workspaceRegistry',
- ]
- static Config: z<Config> = z.object({
- nativeOpen: z.boolean(),
- sessionExportCompressionLevel: z.number().step(1).min(0).max(9)
- .default(DEFAULT_SESSION_LOG_COMPRESSION_LEVEL) as z<SessionLogCompressionLevel>,
- })
- readonly sessions: ApiProxy['sessions']
- readonly subagents: ApiProxy['subagents']
- readonly workspace: ApiProxy['workspace']
- readonly host: ApiProxy['host']
- readonly goals: ApiProxy['goals']
- readonly skills: ApiProxy['skills']
- readonly agentPresets: ApiProxy['agentPresets']
- readonly settings: ApiProxy['settings']
- readonly credentials: ApiProxy['credentials']
- readonly llm: ApiProxy['llm']
- readonly events: ApiProxy['events']
- readonly downloads: ApiProxy['downloads']
- readonly respond: ApiProxy['respond']
- constructor(ctx: Context, config: Config) {
- super(ctx, 'apiProxy')
- const api = createApiProxy(ctx, {
- defaultModelSelection: () => ctx.agentDefaultModel.currentSelection(),
- saveDefaultModelSelection: selection => ctx.agentDefaultModel.saveSelection(selection),
- cwd: process.cwd(),
- ...config.nativeOpen === undefined ? {} : { canOpenPath: () => config.nativeOpen as boolean },
- ...(config.sessionExportCompressionLevel === undefined
- ? {}
- : { sessionExportCompressionLevel: config.sessionExportCompressionLevel }),
- })
- this.sessions = api.sessions
- this.subagents = api.subagents
- this.workspace = api.workspace
- this.host = api.host
- this.goals = api.goals
- this.skills = api.skills
- this.agentPresets = api.agentPresets
- this.settings = api.settings
- this.credentials = api.credentials
- this.llm = api.llm
- this.events = api.events
- this.downloads = api.downloads
- // createApiProxy returns closures (no `this` capture), so the bind is
- // behavior-neutral.
- this.respond = api.respond.bind(api)
- }
- }
- export default ApiProxyService
|