summaryrefslogtreecommitdiffhomepage
path: root/packages/transport-http/src/app.ts
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-06-24 00:08:47 +0900
committerAdam Malczewski <[email protected]>2026-06-24 00:08:47 +0900
commitd225ea4bd5f95d39a910704fe45acdf847c953fa (patch)
treeec0a33665087bb34844b19955ab6fa74c39e3656 /packages/transport-http/src/app.ts
parent674853d87d54dba1cd83c4e51fce5411602f4d5d (diff)
downloaddispatch-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.ts56
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;