diff options
| author | Adam Malczewski <[email protected]> | 2026-06-22 14:58:40 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-06-22 14:58:40 +0900 |
| commit | e6e2d31b987043d0325a93d23295af0408b723ec (patch) | |
| tree | d3208766c1e8123b8ca81c7a7c5a91c2c269e536 /packages/transport-http/src | |
| parent | 519b79999d49156bbfaecc91a2d882fba2475fef (diff) | |
| download | dispatch-e6e2d31b987043d0325a93d23295af0408b723ec.tar.gz dispatch-e6e2d31b987043d0325a93d23295af0408b723ec.zip | |
feat: context window from model endpoints + percentage-based auto-compact
ModelInfo (kernel contract):
- Add contextWindow?: number field
OpenAI-stream listModels:
- Parse contextWindow from common field names (context_length,
context_window, max_context_length, max_tokens)
Transport-contract:
- ModelsResponse: add optional modelInfo map (model name → { contextWindow? })
- Add ModelMetadata type
- Rename CompactThresholdResponse → CompactPercentResponse
- Rename SetCompactThresholdRequest → SetCompactPercentRequest
Credential store:
- Add getModelInfo(modelName) method — resolves full ModelInfo
(including contextWindow) for a <credential>/<model> string
Transport-http:
- GET /models now includes modelInfo with contextWindow per model
- Rename compact-threshold endpoints → compact-percent
Session-orchestrator:
- Auto-compact now uses contextSize (not overcounted usage.inputTokens)
compared against contextWindow * (percent / 100)
- Default percent: 85 (was flat 350000)
- resolveModelInfo dep added to look up contextWindow
- Passes modelName from the settled turn to the compaction service
Conversation store:
- Rename getCompactThreshold/setCompactThreshold → getCompactPercent/setCompactPercent
- compactThresholdKey → compact-percent key
Diffstat (limited to 'packages/transport-http/src')
| -rw-r--r-- | packages/transport-http/src/app.test.ts | 26 | ||||
| -rw-r--r-- | packages/transport-http/src/app.ts | 32 | ||||
| -rw-r--r-- | packages/transport-http/src/extension.ts | 2 | ||||
| -rw-r--r-- | packages/transport-http/src/server.bun.test.ts | 7 |
4 files changed, 43 insertions, 24 deletions
diff --git a/packages/transport-http/src/app.test.ts b/packages/transport-http/src/app.test.ts index 674fd94..11f74f5 100644 --- a/packages/transport-http/src/app.test.ts +++ b/packages/transport-http/src/app.test.ts @@ -139,10 +139,10 @@ function createFakeConversationStore( }, async setConversationStatus() {}, async replaceHistory() {}, - async getCompactThreshold() { + async getCompactPercent() { return null; }, - async setCompactThreshold() {}, + async setCompactPercent() {}, async forkHistory() {}, async setCompactedFrom() {}, }; @@ -241,6 +241,9 @@ function createFakeCredentialStore(models: string[]): CredentialStore { resolve() { return undefined; }, + async getModelInfo() { + return undefined; + }, async listCatalog() { return models; }, @@ -252,6 +255,9 @@ function createThrowingCredentialStore(error: Error): CredentialStore { resolve() { return undefined; }, + async getModelInfo() { + return undefined; + }, async listCatalog() { throw error; }, @@ -876,10 +882,10 @@ describe("GET /conversations/:id", () => { }, async setConversationStatus() {}, async replaceHistory() {}, - async getCompactThreshold() { + async getCompactPercent() { return null; }, - async setCompactThreshold() {}, + async setCompactPercent() {}, async forkHistory() {}, async setCompactedFrom() {}, }; @@ -951,10 +957,10 @@ describe("GET /conversations/:id", () => { }, async setConversationStatus() {}, async replaceHistory() {}, - async getCompactThreshold() { + async getCompactPercent() { return null; }, - async setCompactThreshold() {}, + async setCompactPercent() {}, async forkHistory() {}, async setCompactedFrom() {}, }; @@ -1095,10 +1101,10 @@ describe("GET /conversations/:id/metrics", () => { }, async setConversationStatus() {}, async replaceHistory() {}, - async getCompactThreshold() { + async getCompactPercent() { return null; }, - async setCompactThreshold() {}, + async setCompactPercent() {}, async forkHistory() {}, async setCompactedFrom() {}, }; @@ -2072,10 +2078,10 @@ describe("PUT /conversations/:id/reasoning-effort", () => { }, async setConversationStatus() {}, async replaceHistory() {}, - async getCompactThreshold() { + async getCompactPercent() { return null; }, - async setCompactThreshold() {}, + async setCompactPercent() {}, async forkHistory() {}, async setCompactedFrom() {}, }; diff --git a/packages/transport-http/src/app.ts b/packages/transport-http/src/app.ts index a2ee18c..f917846 100644 --- a/packages/transport-http/src/app.ts +++ b/packages/transport-http/src/app.ts @@ -1,8 +1,8 @@ import type { AgentEvent, HostAPI, Logger } from "@dispatch/kernel"; import type { CloseConversationResponse, + CompactPercentResponse, CompactResponse, - CompactThresholdResponse, ConversationHistoryResponse, ConversationListResponse, ConversationMetricsResponse, @@ -14,7 +14,7 @@ import type { OpenConversationResponse, QueueResponse, ReasoningEffortResponse, - SetCompactThresholdRequest, + SetCompactPercentRequest, ThroughputResponse, TitleResponse, WarmResponse, @@ -233,7 +233,17 @@ export function createApp(opts: CreateServerOptions): Hono { app.get("/models", async (c) => { try { const models = await opts.credentialStore.listCatalog(); - const body: ModelsResponse = { models }; + const modelInfo: Record<string, { contextWindow?: number }> = {}; + for (const modelName of models) { + const info = await opts.credentialStore.getModelInfo(modelName); + if (info?.contextWindow !== undefined) { + modelInfo[modelName] = { contextWindow: info.contextWindow }; + } + } + const body: ModelsResponse = { + models, + ...(Object.keys(modelInfo).length > 0 ? { modelInfo } : {}), + }; return c.json(body, 200); } catch (err) { log.error("models: failed to retrieve catalog", { err }); @@ -739,14 +749,14 @@ export function createApp(opts: CreateServerOptions): Hono { return c.json(response, 200); }); - app.get("/conversations/:id/compact-threshold", async (c) => { + app.get("/conversations/:id/compact-percent", async (c) => { const conversationId = c.req.param("id"); - const threshold = (await opts.conversationStore.getCompactThreshold(conversationId)) ?? 0; - const response: CompactThresholdResponse = { conversationId, threshold }; + const threshold = (await opts.conversationStore.getCompactPercent(conversationId)) ?? 0; + const response: CompactPercentResponse = { conversationId, threshold }; return c.json(response, 200); }); - app.put("/conversations/:id/compact-threshold", async (c) => { + app.put("/conversations/:id/compact-percent", async (c) => { const conversationId = c.req.param("id"); let body: unknown; try { @@ -754,7 +764,7 @@ export function createApp(opts: CreateServerOptions): Hono { } catch { return c.json({ error: "Invalid JSON body" }, 400); } - const parsed = body as SetCompactThresholdRequest; + const parsed = body as SetCompactPercentRequest; if ( typeof parsed.threshold !== "number" || !Number.isFinite(parsed.threshold) || @@ -763,9 +773,9 @@ export function createApp(opts: CreateServerOptions): Hono { return c.json({ error: "threshold must be a non-negative number" }, 400); } const threshold = Math.floor(parsed.threshold); - await opts.conversationStore.setCompactThreshold(conversationId, threshold); - log.info("conversations: compact-threshold set", { conversationId, threshold }); - const response: CompactThresholdResponse = { conversationId, threshold }; + await opts.conversationStore.setCompactPercent(conversationId, threshold); + log.info("conversations: compact-percent set", { conversationId, threshold }); + const response: CompactPercentResponse = { conversationId, threshold }; return c.json(response, 200); }); diff --git a/packages/transport-http/src/extension.ts b/packages/transport-http/src/extension.ts index f7af615..36314e6 100644 --- a/packages/transport-http/src/extension.ts +++ b/packages/transport-http/src/extension.ts @@ -32,7 +32,7 @@ export const manifest: Manifest = { "/conversations/:id", "/conversations/:id/close", "/conversations/:id/compact", - "/conversations/:id/compact-threshold", + "/conversations/:id/compact-percent", "/conversations/:id/cwd", "/conversations/:id/last", "/conversations/:id/lsp", diff --git a/packages/transport-http/src/server.bun.test.ts b/packages/transport-http/src/server.bun.test.ts index fa519af..86ae6bc 100644 --- a/packages/transport-http/src/server.bun.test.ts +++ b/packages/transport-http/src/server.bun.test.ts @@ -66,10 +66,10 @@ function fakeConversationStore(): ConversationStore { }, async setConversationStatus() {}, async replaceHistory() {}, - async getCompactThreshold() { + async getCompactPercent() { return null; }, - async setCompactThreshold() {}, + async setCompactPercent() {}, async forkHistory() {}, async setCompactedFrom() {}, }; @@ -104,6 +104,9 @@ function fakeCredentialStore(): CredentialStore { resolve() { return undefined; }, + async getModelInfo() { + return undefined; + }, async listCatalog() { return []; }, |
