mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 05:50:43 +00:00
fix(plugins): share tool-stream defaults and align xai sdk imports
This commit is contained in:
@@ -3,11 +3,11 @@ import {
|
||||
normalizeNativeXaiModelId,
|
||||
normalizeProviderId,
|
||||
resolveProviderEndpoint,
|
||||
} from "@openclaw/plugin-sdk/provider-model-shared";
|
||||
} from "openclaw/plugin-sdk/provider-model-shared";
|
||||
import {
|
||||
applyXaiModelCompat,
|
||||
resolveXaiModelCompatPatch,
|
||||
} from "@openclaw/plugin-sdk/provider-tools";
|
||||
} from "openclaw/plugin-sdk/provider-tools";
|
||||
import { readStringValue } from "openclaw/plugin-sdk/text-runtime";
|
||||
|
||||
export { buildXaiProvider } from "./provider-catalog.js";
|
||||
@@ -28,7 +28,7 @@ export {
|
||||
HTML_ENTITY_TOOL_CALL_ARGUMENTS_ENCODING,
|
||||
XAI_TOOL_SCHEMA_PROFILE,
|
||||
resolveXaiModelCompatPatch,
|
||||
} from "@openclaw/plugin-sdk/provider-tools";
|
||||
} from "openclaw/plugin-sdk/provider-tools";
|
||||
|
||||
function isXaiNativeEndpoint(baseUrl: unknown): boolean {
|
||||
return (
|
||||
|
||||
@@ -88,4 +88,28 @@ describe("xai provider plugin", () => {
|
||||
(capturedPayload?.tools as Array<{ function?: Record<string, unknown> }>)[0]?.function,
|
||||
).not.toHaveProperty("strict");
|
||||
});
|
||||
|
||||
it("defaults tool_stream extra params but preserves explicit values", async () => {
|
||||
const provider = await registerSingleProviderPlugin(plugin);
|
||||
|
||||
expect(
|
||||
provider.prepareExtraParams?.({
|
||||
provider: "xai",
|
||||
modelId: "grok-4",
|
||||
extraParams: { fastMode: true },
|
||||
} as never),
|
||||
).toEqual({
|
||||
fastMode: true,
|
||||
tool_stream: true,
|
||||
});
|
||||
|
||||
const explicit = { fastMode: true, tool_stream: false };
|
||||
expect(
|
||||
provider.prepareExtraParams?.({
|
||||
provider: "xai",
|
||||
modelId: "grok-4",
|
||||
extraParams: explicit,
|
||||
} as never),
|
||||
).toBe(explicit);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Type } from "@sinclair/typebox";
|
||||
import { defineSingleProviderPluginEntry } from "openclaw/plugin-sdk/provider-entry";
|
||||
import { buildProviderReplayFamilyHooks } from "openclaw/plugin-sdk/provider-model-shared";
|
||||
import { defaultToolStreamExtraParams } from "openclaw/plugin-sdk/provider-stream-shared";
|
||||
import { jsonResult, readProviderEnvValue } from "openclaw/plugin-sdk/provider-web-search";
|
||||
import {
|
||||
applyXaiModelCompat,
|
||||
@@ -160,16 +161,7 @@ export default defineSingleProviderPluginEntry({
|
||||
buildProvider: buildXaiProvider,
|
||||
},
|
||||
...OPENAI_COMPATIBLE_REPLAY_HOOKS,
|
||||
prepareExtraParams: (ctx) => {
|
||||
const extraParams = ctx.extraParams;
|
||||
if (extraParams && extraParams.tool_stream !== undefined) {
|
||||
return extraParams;
|
||||
}
|
||||
return {
|
||||
...extraParams,
|
||||
tool_stream: true,
|
||||
};
|
||||
},
|
||||
prepareExtraParams: (ctx) => defaultToolStreamExtraParams(ctx.extraParams),
|
||||
wrapStreamFn: wrapXaiProviderStream,
|
||||
// Provider-specific fallback auth stays owned by the xAI plugin so core
|
||||
// auth/discovery code can consume it generically without parsing xAI's
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {
|
||||
createDefaultModelsPresetAppliers,
|
||||
type OpenClawConfig,
|
||||
} from "@openclaw/plugin-sdk/provider-onboard";
|
||||
} from "openclaw/plugin-sdk/provider-onboard";
|
||||
import { XAI_BASE_URL, XAI_DEFAULT_MODEL_ID } from "./model-definitions.js";
|
||||
import { buildXaiCatalogModels } from "./model-definitions.js";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { ModelProviderConfig } from "@openclaw/plugin-sdk/provider-model-shared";
|
||||
import type { ModelProviderConfig } from "openclaw/plugin-sdk/provider-model-shared";
|
||||
import { buildXaiCatalogModels, XAI_BASE_URL } from "./model-definitions.js";
|
||||
|
||||
export function buildXaiProvider(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { definePluginEntry } from "@openclaw/plugin-sdk/plugin-entry";
|
||||
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
|
||||
import { isRecord } from "./src/tool-config-shared.js";
|
||||
|
||||
export default definePluginEntry({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { postTrustedWebToolsJson } from "@openclaw/plugin-sdk/provider-web-search";
|
||||
import { postTrustedWebToolsJson } from "openclaw/plugin-sdk/provider-web-search";
|
||||
import {
|
||||
buildXaiResponsesToolBody,
|
||||
resolveXaiResponseTextAndCitations,
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import type { OpenClawConfig } from "@openclaw/plugin-sdk/config-runtime";
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
|
||||
import {
|
||||
coerceSecretRef,
|
||||
resolveNonEnvSecretRefApiKeyMarker,
|
||||
} from "@openclaw/plugin-sdk/provider-auth";
|
||||
} from "openclaw/plugin-sdk/provider-auth";
|
||||
import {
|
||||
readProviderEnvValue,
|
||||
readConfiguredSecretString,
|
||||
resolveProviderWebSearchPluginConfig,
|
||||
} from "@openclaw/plugin-sdk/provider-web-search";
|
||||
import { normalizeSecretInputString } from "@openclaw/plugin-sdk/secret-input";
|
||||
} from "openclaw/plugin-sdk/provider-web-search";
|
||||
import { normalizeSecretInputString } from "openclaw/plugin-sdk/secret-input";
|
||||
|
||||
export type XaiFallbackAuth = {
|
||||
apiKey: string;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { postTrustedWebToolsJson, wrapWebContent } from "@openclaw/plugin-sdk/provider-web-search";
|
||||
import { postTrustedWebToolsJson, wrapWebContent } from "openclaw/plugin-sdk/provider-web-search";
|
||||
import { normalizeXaiModelId } from "../model-id.js";
|
||||
import {
|
||||
buildXaiResponsesToolBody,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { OpenClawConfig } from "@openclaw/plugin-sdk/config-runtime";
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
|
||||
import { isRecord } from "./tool-config-shared.js";
|
||||
|
||||
type JsonRecord = Record<string, unknown>;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { postTrustedWebToolsJson, wrapWebContent } from "@openclaw/plugin-sdk/provider-web-search";
|
||||
import { postTrustedWebToolsJson, wrapWebContent } from "openclaw/plugin-sdk/provider-web-search";
|
||||
import {
|
||||
buildXaiResponsesToolBody,
|
||||
resolveXaiResponseTextCitationsAndInline,
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import type { StreamFn } from "@mariozechner/pi-agent-core";
|
||||
import { streamSimple } from "@mariozechner/pi-ai";
|
||||
import type { ProviderWrapStreamFnContext } from "@openclaw/plugin-sdk/plugin-entry";
|
||||
import type { ProviderWrapStreamFnContext } from "openclaw/plugin-sdk/plugin-entry";
|
||||
import {
|
||||
composeProviderStreamWrappers,
|
||||
createHtmlEntityToolCallArgumentDecodingWrapper,
|
||||
createToolStreamWrapper,
|
||||
} from "@openclaw/plugin-sdk/provider-stream-shared";
|
||||
} from "openclaw/plugin-sdk/provider-stream-shared";
|
||||
|
||||
const XAI_FAST_MODEL_IDS = new Map<string, string>([
|
||||
["grok-3", "grok-3-fast"],
|
||||
|
||||
@@ -215,4 +215,28 @@ describe("zai provider plugin", () => {
|
||||
|
||||
expect(capturedPayload).not.toHaveProperty("tool_stream");
|
||||
});
|
||||
|
||||
it("defaults tool_stream extra params but preserves explicit values", async () => {
|
||||
const provider = await registerSingleProviderPlugin(plugin);
|
||||
|
||||
expect(
|
||||
provider.prepareExtraParams?.({
|
||||
provider: "zai",
|
||||
modelId: "glm-4.7",
|
||||
extraParams: { endpoint: "global" },
|
||||
} as never),
|
||||
).toEqual({
|
||||
endpoint: "global",
|
||||
tool_stream: true,
|
||||
});
|
||||
|
||||
const explicit = { endpoint: "global", tool_stream: false };
|
||||
expect(
|
||||
provider.prepareExtraParams?.({
|
||||
provider: "zai",
|
||||
modelId: "glm-4.7",
|
||||
extraParams: explicit,
|
||||
} as never),
|
||||
).toBe(explicit);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
normalizeModelCompat,
|
||||
} from "openclaw/plugin-sdk/provider-model-shared";
|
||||
import { buildProviderStreamFamilyHooks } from "openclaw/plugin-sdk/provider-stream-family";
|
||||
import { defaultToolStreamExtraParams } from "openclaw/plugin-sdk/provider-stream-shared";
|
||||
import { fetchZaiUsage, resolveLegacyPiAgentAccessToken } from "openclaw/plugin-sdk/provider-usage";
|
||||
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
|
||||
import { detectZaiEndpoint, type ZaiEndpointId } from "./detect.js";
|
||||
@@ -281,15 +282,7 @@ export default definePluginEntry({
|
||||
],
|
||||
resolveDynamicModel: (ctx) => resolveGlm5ForwardCompatModel(ctx),
|
||||
...OPENAI_COMPATIBLE_REPLAY_HOOKS,
|
||||
prepareExtraParams: (ctx) => {
|
||||
if (ctx.extraParams?.tool_stream !== undefined) {
|
||||
return ctx.extraParams;
|
||||
}
|
||||
return {
|
||||
...ctx.extraParams,
|
||||
tool_stream: true,
|
||||
};
|
||||
},
|
||||
prepareExtraParams: (ctx) => defaultToolStreamExtraParams(ctx.extraParams),
|
||||
...ZAI_TOOL_STREAM_HOOKS,
|
||||
isBinaryThinking: () => true,
|
||||
isModernModelRef: ({ modelId }) => {
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { StreamFn } from "@mariozechner/pi-agent-core";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
createHtmlEntityToolCallArgumentDecodingWrapper,
|
||||
defaultToolStreamExtraParams,
|
||||
decodeHtmlEntitiesInObject,
|
||||
} from "./provider-stream-shared.js";
|
||||
|
||||
@@ -42,6 +43,24 @@ describe("decodeHtmlEntitiesInObject", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("defaultToolStreamExtraParams", () => {
|
||||
it("defaults tool_stream on when absent", () => {
|
||||
expect(defaultToolStreamExtraParams()).toEqual({ tool_stream: true });
|
||||
expect(defaultToolStreamExtraParams({ fastMode: true })).toEqual({
|
||||
fastMode: true,
|
||||
tool_stream: true,
|
||||
});
|
||||
});
|
||||
|
||||
it("preserves explicit tool_stream values", () => {
|
||||
const enabled = { tool_stream: true, fastMode: true };
|
||||
const disabled = { tool_stream: false, fastMode: true };
|
||||
|
||||
expect(defaultToolStreamExtraParams(enabled)).toBe(enabled);
|
||||
expect(defaultToolStreamExtraParams(disabled)).toBe(disabled);
|
||||
});
|
||||
});
|
||||
|
||||
describe("createHtmlEntityToolCallArgumentDecodingWrapper", () => {
|
||||
it("decodes tool call arguments in final and streaming messages", async () => {
|
||||
const resultMessage = {
|
||||
|
||||
@@ -17,6 +17,18 @@ export function composeProviderStreamWrappers(
|
||||
);
|
||||
}
|
||||
|
||||
export function defaultToolStreamExtraParams(
|
||||
extraParams?: Record<string, unknown>,
|
||||
): Record<string, unknown> {
|
||||
if (extraParams?.tool_stream !== undefined) {
|
||||
return extraParams;
|
||||
}
|
||||
return {
|
||||
...extraParams,
|
||||
tool_stream: true,
|
||||
};
|
||||
}
|
||||
|
||||
const HTML_ENTITY_RE = /&(?:amp|lt|gt|quot|apos|#39|#x[0-9a-f]+|#\d+);/i;
|
||||
|
||||
function decodeHtmlEntities(value: string): string {
|
||||
|
||||
@@ -37,6 +37,7 @@ export {
|
||||
createMoonshotThinkingWrapper,
|
||||
createToolStreamWrapper,
|
||||
createZaiToolStreamWrapper,
|
||||
defaultToolStreamExtraParams,
|
||||
hasCopilotVisionInput,
|
||||
isAnthropicBedrockModel,
|
||||
type ProviderStreamWrapperFactory,
|
||||
|
||||
Reference in New Issue
Block a user