mirror of https://github.com/openclaw/openclaw.git
130 lines
3.8 KiB
TypeScript
130 lines
3.8 KiB
TypeScript
import { normalizeXaiModelId } from "openclaw/plugin-sdk/provider-models";
|
|
import { postTrustedWebToolsJson } from "openclaw/plugin-sdk/provider-web-search";
|
|
import { extractXaiWebSearchContent, type XaiWebSearchResponse } from "./web-search-shared.js";
|
|
|
|
export const XAI_CODE_EXECUTION_ENDPOINT = "https://api.x.ai/v1/responses";
|
|
export const XAI_DEFAULT_CODE_EXECUTION_MODEL = "grok-4-1-fast";
|
|
|
|
export type XaiCodeExecutionConfig = {
|
|
apiKey?: unknown;
|
|
model?: unknown;
|
|
maxTurns?: unknown;
|
|
};
|
|
|
|
export type XaiCodeExecutionResponse = XaiWebSearchResponse & {
|
|
output?: Array<{
|
|
type?: string;
|
|
}>;
|
|
};
|
|
|
|
export type XaiCodeExecutionResult = {
|
|
content: string;
|
|
citations: string[];
|
|
usedCodeExecution: boolean;
|
|
outputTypes: string[];
|
|
};
|
|
|
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
}
|
|
|
|
export function resolveXaiCodeExecutionConfig(
|
|
config?: Record<string, unknown>,
|
|
): XaiCodeExecutionConfig {
|
|
return isRecord(config) ? (config as XaiCodeExecutionConfig) : {};
|
|
}
|
|
|
|
export function resolveXaiCodeExecutionModel(config?: Record<string, unknown>): string {
|
|
const resolved = resolveXaiCodeExecutionConfig(config);
|
|
return typeof resolved.model === "string" && resolved.model.trim()
|
|
? normalizeXaiModelId(resolved.model.trim())
|
|
: XAI_DEFAULT_CODE_EXECUTION_MODEL;
|
|
}
|
|
|
|
export function resolveXaiCodeExecutionMaxTurns(
|
|
config?: Record<string, unknown>,
|
|
): number | undefined {
|
|
const raw = resolveXaiCodeExecutionConfig(config).maxTurns;
|
|
if (typeof raw !== "number" || !Number.isFinite(raw)) {
|
|
return undefined;
|
|
}
|
|
const normalized = Math.trunc(raw);
|
|
return normalized > 0 ? normalized : undefined;
|
|
}
|
|
|
|
export function buildXaiCodeExecutionPayload(params: {
|
|
task: string;
|
|
model: string;
|
|
tookMs: number;
|
|
content: string;
|
|
citations: string[];
|
|
usedCodeExecution: boolean;
|
|
outputTypes: string[];
|
|
}): Record<string, unknown> {
|
|
return {
|
|
task: params.task,
|
|
provider: "xai",
|
|
model: params.model,
|
|
tookMs: params.tookMs,
|
|
content: params.content,
|
|
citations: params.citations,
|
|
usedCodeExecution: params.usedCodeExecution,
|
|
outputTypes: params.outputTypes,
|
|
};
|
|
}
|
|
|
|
export async function requestXaiCodeExecution(params: {
|
|
apiKey: string;
|
|
model: string;
|
|
timeoutSeconds: number;
|
|
maxTurns?: number;
|
|
task: string;
|
|
}): Promise<XaiCodeExecutionResult> {
|
|
return await postTrustedWebToolsJson(
|
|
{
|
|
url: XAI_CODE_EXECUTION_ENDPOINT,
|
|
timeoutSeconds: params.timeoutSeconds,
|
|
apiKey: params.apiKey,
|
|
body: {
|
|
model: params.model,
|
|
input: [{ role: "user", content: params.task }],
|
|
tools: [{ type: "code_interpreter" }],
|
|
...(params.maxTurns ? { max_turns: params.maxTurns } : {}),
|
|
},
|
|
errorLabel: "xAI",
|
|
},
|
|
async (response) => {
|
|
const data = (await response.json()) as XaiCodeExecutionResponse;
|
|
const { text, annotationCitations } = extractXaiWebSearchContent(data);
|
|
const outputTypes = Array.isArray(data.output)
|
|
? [
|
|
...new Set(
|
|
data.output
|
|
.map((entry) => entry?.type)
|
|
.filter((value): value is string => Boolean(value)),
|
|
),
|
|
]
|
|
: [];
|
|
const citations =
|
|
Array.isArray(data.citations) && data.citations.length > 0
|
|
? data.citations
|
|
: annotationCitations;
|
|
return {
|
|
content: text ?? "No response",
|
|
citations,
|
|
usedCodeExecution: outputTypes.includes("code_interpreter_call"),
|
|
outputTypes,
|
|
};
|
|
},
|
|
);
|
|
}
|
|
|
|
export const __testing = {
|
|
buildXaiCodeExecutionPayload,
|
|
requestXaiCodeExecution,
|
|
resolveXaiCodeExecutionConfig,
|
|
resolveXaiCodeExecutionMaxTurns,
|
|
resolveXaiCodeExecutionModel,
|
|
XAI_DEFAULT_CODE_EXECUTION_MODEL,
|
|
} as const;
|