fix(canvas): 在线 Agent - 系统模型接入工具任务路由

This commit is contained in:
dlh
2026-08-20 09:59:27 +08:00
parent 298b5ebf1f
commit 31026a112d
6 changed files with 239 additions and 25 deletions

View File

@@ -10,6 +10,7 @@ import { modelOptionName, resolveModelChannel, resolveModelRequestConfig, type A
import { useLocalDreaminaModelStore } from "@/stores/use-local-dreamina-model-store";
import type { ReferenceImage } from "@/types/image";
import type { ReferenceAudio, ReferenceVideo } from "@/types/media";
import { buildBackendToolRequests, type ResponseFunctionTool, type ResponseInputMessage, type ToolChoice, type ToolResponseResult } from "@/services/api/image";
export type BackendGenerationMode = "text" | "image" | "video" | "audio";
@@ -19,6 +20,8 @@ export type BackendGenerationResult = {
video?: { dataUrl: string; storageKey?: string; width?: number; height?: number; durationMs?: number; bytes?: number; mimeType?: string };
audio?: { dataUrl: string; storageKey?: string; durationMs?: number; bytes?: number; mimeType?: string; format?: string };
text?: string;
toolCalls?: Array<{ id: string; type: "function"; function: { name: string; arguments: string }; thoughtSignature?: string }>;
reasoning?: string;
};
type BackendGenerationTaskOptions = {
@@ -105,6 +108,40 @@ export async function runBackendGenerationTask(
return createAndWaitGenerationTask({ projectId, mode, prompt, config, referenceImages, referenceVideos, referenceAudios, textHistory, signal, metadata, onTaskUpdate }, prepared, dependencies);
}
export async function runBackendToolGenerationTask(options: {
prompt: string;
config: AiConfig;
messages: ResponseInputMessage[];
tools: ResponseFunctionTool[];
toolChoice: ToolChoice;
signal?: AbortSignal;
}): Promise<ToolResponseResult> {
throwIfAborted(options.signal);
const logicalModelId = logicalModelIDForConfig(options.config);
if (!logicalModelId) throw new Error("当前模型不是平台系统模型");
const task = await createGenerationTask({
type: "canvas_text",
operation: "text",
prompt: options.prompt,
model: options.config.model,
logicalModelId,
input: {
mode: "text",
prompt: options.prompt,
config: backendProviderConfig(options.config),
agentRequests: buildBackendToolRequests(options.messages, options.tools, options.toolChoice),
metadata: { source: "canvas-online-agent" },
},
});
const completed = await waitForGenerationTask(task.id, { signal: options.signal, initialTask: task });
const result = parseBackendGenerationResult(completed);
return {
content: result.text || "",
toolCalls: result.toolCalls || [],
...(result.reasoning ? { reasoning: result.reasoning } : {}),
};
}
export async function runBackendGenerationTaskBatch(options: BackendGenerationTaskOptions & { count: number }, dependencies: GenerationTaskDependencies = defaultDependencies) {
const count = Math.max(1, Math.min(15, Math.floor(Number(options.count)) || 1));
throwIfAborted(options.signal);

View File

@@ -46,7 +46,11 @@ export type ToolResponseResult = {
reasoning?: string;
};
type ToolChoice = "auto" | "required" | { type: "function"; name: string };
export type ToolChoice = "auto" | "required" | { type: "function"; name: string };
export type BackendToolRequests = {
responses: Record<string, unknown>;
chatCompletion: Record<string, unknown>;
};
type ResponseMessageContent = AiTextMessage["content"] | string;
type ResponseInputContent = { type: "input_text"; text: string } | { type: "input_image"; image_url: string } | { type: "input_file"; filename: string; file_data?: string; file_url?: string };
type ResponseInputItem = { role: "system" | "user" | "assistant"; content: string | ResponseInputContent[] } | { type: "function_call"; call_id: string; name: string; arguments: string } | { type: "function_call_output"; call_id: string; output: string };
@@ -407,6 +411,23 @@ function toChatCompletionToolChoice(toolChoice: ToolChoice) {
return typeof toolChoice === "object" ? { type: "function", function: { name: toolChoice.name } } : toolChoice;
}
export function buildBackendToolRequests(messages: ResponseInputMessage[], tools: ResponseFunctionTool[], toolChoice: ToolChoice): BackendToolRequests {
return {
responses: {
input: toResponseInput(messages),
tools: tools.map(toResponseTool),
tool_choice: toolChoice,
parallel_tool_calls: false,
},
chatCompletion: {
messages: toChatCompletionMessages(messages),
tools,
tool_choice: toChatCompletionToolChoice(toolChoice),
parallel_tool_calls: false,
},
};
}
function isToolChoiceCompatibilityError(error: unknown) {
const message = error instanceof Error ? error.message : "";
return /tool[_\s-]?choice|thinking\s+mode/i.test(message);