summaryrefslogtreecommitdiffhomepage
path: root/packages/session-orchestrator/src
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-06-27 20:06:47 +0900
committerAdam Malczewski <[email protected]>2026-06-27 20:06:47 +0900
commit2e741d1c1ac309327aff4fed0e248bc5baa342d4 (patch)
treefb84708f55e07572e4c69447884365d9b457755c /packages/session-orchestrator/src
parent2c91dc63802a386b1612ea0ed8c1e96b6f4421db (diff)
downloaddispatch-2e741d1c1ac309327aff4fed0e248bc5baa342d4.tar.gz
dispatch-2e741d1c1ac309327aff4fed0e248bc5baa342d4.zip
feat(vision): store images in tmp dir instead of SQLite — compact URLs + purge on compaction/close
Diffstat (limited to 'packages/session-orchestrator/src')
-rw-r--r--packages/session-orchestrator/src/orchestrator.ts30
1 files changed, 29 insertions, 1 deletions
diff --git a/packages/session-orchestrator/src/orchestrator.ts b/packages/session-orchestrator/src/orchestrator.ts
index c0493f3..045b88d 100644
--- a/packages/session-orchestrator/src/orchestrator.ts
+++ b/packages/session-orchestrator/src/orchestrator.ts
@@ -49,6 +49,20 @@ import type { ToolAssembly } from "./tools-filter.js";
* call `consult_vision`) and the images are registered for tool access.
*/
export interface VisionHandoffService {
+ /**
+ * Store images to tmp files and return compact URLs. Each input image's data
+ * URL is saved to a tmp file and replaced with a compact HTTP path so the
+ * persisted conversation store holds a tiny string, not megabytes of base64.
+ * When `saveImageToTmp` is not configured, data URLs pass through unchanged.
+ */
+ readonly storeImages: (
+ conversationId: string,
+ images: readonly ImageInput[],
+ ) => Promise<readonly ImageInput[]>;
+
+ /** Delete all tmp images for a conversation (on close). Best-effort. */
+ readonly purgeConversationImages: (conversationId: string) => Promise<void>;
+
readonly prepareForProvider: (
messages: readonly ChatMessage[],
currentModelName: string | undefined,
@@ -625,7 +639,18 @@ export function createSessionOrchestrator(
const effectiveModelName = resolveModelName(modelName, storedModel);
const history = await deps.conversationStore.load(conversationId);
- const userMsg = buildUserMessage(text, images);
+
+ // Store images to tmp files (compact URLs) BEFORE building the user
+ // message so the persisted chunks hold tiny URL references, not
+ // megabytes of base64 data URLs. When the vision-handoff service isn't
+ // loaded, images pass through unchanged (backward compatible).
+ const visionHandoffForStore = deps.resolveVisionHandoff?.();
+ const storedImages =
+ visionHandoffForStore !== undefined && images !== undefined
+ ? await visionHandoffForStore.storeImages(conversationId, images)
+ : images;
+
+ const userMsg = buildUserMessage(text, storedImages);
// Workspace assignment for new conversations happens BEFORE
// effective-cwd resolution (see workspaceSetupPromise above) so
@@ -988,6 +1013,9 @@ export function createSessionOrchestrator(
});
});
void deps.conversationStore.setConversationStatus(conversationId, "closed");
+ // Purge tmp images for this conversation (best-effort, fire-and-forget).
+ const vh = deps.resolveVisionHandoff?.();
+ if (vh !== undefined) void vh.purgeConversationImages(conversationId);
return { abortedTurn };
},