mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-26 00:52:18 +03:00
Landed with the design call resolved per the owner's pick — **option 1**: the synced store is now endpoint-agnostic (persistDiscoveredModels and managedModelImport no longer drop non-chat models at write time), and chat selectability moved to read time (auto-pool expansion in autoStrategy applies filterChatSelectableModels; the models-route projection already had its chatOnly filter). Your discovery test now passes end-to-end (3/3): /api/show capabilities persist per connection and image/embedding requests route through the advertising host. Reconciliation notes: conflicted areas merged onto the current tip (adobe discovery import, requestedModel preflight signature, resolvedProvider fast-path coexists with the synced-route override — explicit resolution wins); carried base-red drains (#10055 memoization, #11071 test variants) dropped as already-landed; the managed-model-import exclusion test was propagated to the new contract (image/video models persist; the read filter still hides them from chat pickers — pinned by a new assertion). Full battery: 205/206 focused (the one red is a confirmed periodic-timer timing flake on the loaded devbox — 20/20 isolated), autoCombo vitest 30/30, combo suites 46/46, gates + typecheck clean. Thank you @yourspraveen — the capability probe + routing design was right; it just needed the store contract opened up. Fixes #11087.
95 lines
3.2 KiB
TypeScript
95 lines
3.2 KiB
TypeScript
import { TEXT_ENCODER } from "./kiro/eventstream.ts";
|
|
|
|
/**
|
|
* Validation + buffering helpers for Kiro's nested `tool_call` wrapper payloads.
|
|
*
|
|
* Extracted from kiro.ts (file-size gate, #9314) — pure functions, no dependency on
|
|
* KiroExecutor instance state.
|
|
*/
|
|
|
|
export type JsonRecord = Record<string, unknown>;
|
|
|
|
export const KIRO_TOOL_CALL_WRAPPER = "tool_call";
|
|
|
|
export type PendingKiroWrapperToolCall = {
|
|
toolCallId: string;
|
|
toolName: string;
|
|
inputKind?: "string" | "object";
|
|
inputText?: string;
|
|
inputObject?: Record<string, unknown>;
|
|
};
|
|
|
|
export function parseKiroToolInput(toolInput: unknown): unknown {
|
|
if (typeof toolInput !== "string") return toolInput;
|
|
try {
|
|
return JSON.parse(toolInput);
|
|
} catch (error) {
|
|
const message = error instanceof Error ? error.message : String(error);
|
|
throw new Error(`Invalid Kiro tool_call payload: input must be valid JSON (${message})`);
|
|
}
|
|
}
|
|
|
|
export function validateKiroToolName(toolUse: JsonRecord): string {
|
|
const toolName = typeof toolUse.name === "string" ? toolUse.name.trim() : "";
|
|
if (!toolName) throw new Error("Invalid Kiro toolUseEvent: missing tool name");
|
|
return toolName;
|
|
}
|
|
|
|
export function validateKiroToolCallWrapperInput(toolInput: unknown): void {
|
|
if (toolInput === undefined) {
|
|
throw new Error("Invalid Kiro tool_call payload: missing input");
|
|
}
|
|
const input = parseKiroToolInput(toolInput);
|
|
if (!input || typeof input !== "object" || Array.isArray(input)) {
|
|
throw new Error(
|
|
"Invalid Kiro tool_call payload: input must be an object with name and arguments"
|
|
);
|
|
}
|
|
const record = input as JsonRecord;
|
|
if (typeof record.name !== "string" || !record.name.trim()) {
|
|
throw new Error("Invalid Kiro tool_call payload: missing nested MCP tool name at input.name");
|
|
}
|
|
if (!Object.prototype.hasOwnProperty.call(record, "arguments")) {
|
|
throw new Error(
|
|
"Invalid Kiro tool_call payload: missing nested MCP tool arguments at input.arguments"
|
|
);
|
|
}
|
|
}
|
|
|
|
export function validateKiroToolUse(toolUse: JsonRecord): void {
|
|
const toolName = validateKiroToolName(toolUse);
|
|
if (toolName === KIRO_TOOL_CALL_WRAPPER) {
|
|
validateKiroToolCallWrapperInput(toolUse.input);
|
|
}
|
|
}
|
|
|
|
export function appendBufferedKiroToolInput(
|
|
toolCall: PendingKiroWrapperToolCall,
|
|
toolInput: unknown
|
|
): void {
|
|
if (toolInput === undefined) return;
|
|
if (typeof toolInput === "string") {
|
|
if (toolCall.inputKind && toolCall.inputKind !== "string") {
|
|
throw new Error("Invalid Kiro tool_call payload: mixed input fragment types");
|
|
}
|
|
toolCall.inputKind = "string";
|
|
toolCall.inputText = `${toolCall.inputText || ""}${toolInput}`;
|
|
return;
|
|
}
|
|
if (toolInput && typeof toolInput === "object" && !Array.isArray(toolInput)) {
|
|
if (toolCall.inputKind && toolCall.inputKind !== "object") {
|
|
throw new Error("Invalid Kiro tool_call payload: mixed input fragment types");
|
|
}
|
|
toolCall.inputKind = "object";
|
|
toolCall.inputObject = toolInput as Record<string, unknown>;
|
|
}
|
|
}
|
|
|
|
export function getBufferedKiroToolInput(toolCall: PendingKiroWrapperToolCall): unknown {
|
|
return toolCall.inputKind === "string" ? toolCall.inputText || "" : toolCall.inputObject;
|
|
}
|
|
|
|
export function encodeSse(value: string): Uint8Array {
|
|
return TEXT_ENCODER.encode(value);
|
|
}
|