diff options
| author | Adam Malczewski <[email protected]> | 2026-06-24 00:08:47 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-06-24 00:08:47 +0900 |
| commit | d225ea4bd5f95d39a910704fe45acdf847c953fa (patch) | |
| tree | ec0a33665087bb34844b19955ab6fa74c39e3656 /packages/transport-http/src/app.ts | |
| parent | 674853d87d54dba1cd83c4e51fce5411602f4d5d (diff) | |
| download | dispatch-d225ea4bd5f95d39a910704fe45acdf847c953fa.tar.gz dispatch-d225ea4bd5f95d39a910704fe45acdf847c953fa.zip | |
feat(system-prompt): wire into turn flow + compaction + API routes
session-orchestrator:
- Wire systemPromptService as optional dep (lazy via host.getService)
- Regular turn: construct on first turn (new conversation), get on subsequent
turns, set on providerOpts.systemPrompt (cache-safe)
- Compaction: construct (fresh resolve) + append COMPACTION_SYSTEM_PROMPT
- 12 new tests (construct/get/service-unavailable/compaction)
transport-http:
- GET /system-prompt (returns template or DEFAULT_TEMPLATE)
- PUT /system-prompt (validate + setTemplate, 503 when unavailable)
- GET /system-prompt/variables (static catalog, always available)
- 6 new tests
system-prompt service: added getTemplate/setTemplate to interface + impl.
1396 vitest pass. typecheck + biome clean.
Diffstat (limited to 'packages/transport-http/src/app.ts')
| -rw-r--r-- | packages/transport-http/src/app.ts | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/packages/transport-http/src/app.ts b/packages/transport-http/src/app.ts index eba5c1a..41b583c 100644 --- a/packages/transport-http/src/app.ts +++ b/packages/transport-http/src/app.ts @@ -1,4 +1,5 @@ import type { AgentEvent, HostAPI, Logger } from "@dispatch/kernel"; +import { DEFAULT_TEMPLATE, getVariableCatalog } from "@dispatch/system-prompt"; import type { CloseConversationResponse, CompactPercentResponse, @@ -17,6 +18,9 @@ import type { QueueResponse, ReasoningEffortResponse, SetCompactPercentRequest, + SetSystemPromptTemplateRequest, + SystemPromptTemplateResponse, + SystemPromptVariablesResponse, ThroughputResponse, TitleResponse, WarmResponse, @@ -51,6 +55,7 @@ import { type LspServerStatus, type LspService, type SessionOrchestrator, + type SystemPromptService, ThroughputQueryError, type ThroughputStore, type WarmService, @@ -63,6 +68,8 @@ export interface CreateServerOptions { readonly warmService?: WarmService; readonly compactionService?: CompactionService; readonly lspService?: LspService; + /** Optional — system prompt builder service (GET/PUT template). */ + readonly systemPromptService?: SystemPromptService; /** Optional — defaults to a no-op store (recording disabled, empty reports). */ readonly throughputStore?: ThroughputStore; readonly logger?: Logger; @@ -1018,6 +1025,55 @@ export function createApp(opts: CreateServerOptions): Hono { } }); + // ─── System prompt template ─────────────────────────────────────────────── + + app.get("/system-prompt/variables", (c) => { + // Static catalog — no service call needed. Always available. + const variables = getVariableCatalog(); + const body: SystemPromptVariablesResponse = { variables }; + return c.json(body, 200); + }); + + app.get("/system-prompt", async (c) => { + if (opts.systemPromptService === undefined) { + // FE always gets something useful — the built-in default template. + const body: SystemPromptTemplateResponse = { template: DEFAULT_TEMPLATE }; + return c.json(body, 200); + } + const template = await opts.systemPromptService.getTemplate(); + const body: SystemPromptTemplateResponse = { template }; + return c.json(body, 200); + }); + + app.put("/system-prompt", async (c) => { + if (opts.systemPromptService === undefined) { + return c.json({ error: "System prompt service not available" }, 503); + } + + let body: unknown; + try { + body = await c.req.json(); + } catch { + log.warn("system-prompt: invalid JSON body"); + return c.json({ error: "Invalid JSON body" }, 400); + } + + if (body === null || typeof body !== "object") { + return c.json({ error: "Request body must be a JSON object" }, 400); + } + const obj = body as Record<string, unknown>; + // `template` must be a string; empty string is valid ("no system prompt"). + if (typeof obj.template !== "string") { + return c.json({ error: "Field 'template' is required and must be a string" }, 400); + } + + const { template } = obj as unknown as SetSystemPromptTemplateRequest; + await opts.systemPromptService.setTemplate(template); + log.info("system-prompt: template set"); + const response: SystemPromptTemplateResponse = { template }; + return c.json(response, 200); + }); + // ─── Static frontend serving (catch-all, API routes take precedence) ────── if (opts.webDir !== undefined) { const webDir = opts.webDir; |
