diff --git a/extensions/xai/api.ts b/extensions/xai/api.ts index 91389f0ab55..039e66e9319 100644 --- a/extensions/xai/api.ts +++ b/extensions/xai/api.ts @@ -25,6 +25,7 @@ export { XAI_IMAGE_MODELS, } from "./model-definitions.js"; export { isModernXaiModel, resolveXaiForwardCompatModel } from "./provider-models.js"; +export { applyXaiRuntimeModelCompat } from "./runtime-model-compat.js"; export { applyXaiModelCompat, HTML_ENTITY_TOOL_CALL_ARGUMENTS_ENCODING, diff --git a/extensions/xai/index.test.ts b/extensions/xai/index.test.ts index 854da532311..347da642897 100644 --- a/extensions/xai/index.test.ts +++ b/extensions/xai/index.test.ts @@ -221,6 +221,7 @@ describe("xai provider plugin", () => { model: createProviderModel({ id: "grok-4-1-fast" }), } as never), ).toMatchObject({ + thinkingLevelMap: { off: null }, compat: { toolSchemaProfile: "xai", nativeWebSearchTool: true, diff --git a/extensions/xai/index.ts b/extensions/xai/index.ts index 9c9edf9c8b0..b850b59b0df 100644 --- a/extensions/xai/index.ts +++ b/extensions/xai/index.ts @@ -4,7 +4,7 @@ import { defaultToolStreamExtraParams } from "openclaw/plugin-sdk/provider-strea import { jsonResult, readProviderEnvValue } from "openclaw/plugin-sdk/provider-web-search"; import { Type } from "typebox"; import { - applyXaiModelCompat, + applyXaiRuntimeModelCompat, buildXaiImageGenerationProvider, normalizeXaiModelId, resolveXaiTransport, @@ -194,7 +194,7 @@ export default defineSingleProviderPluginEntry({ mode: "api-key" as const, }; }, - normalizeResolvedModel: ({ model }) => applyXaiModelCompat(model), + normalizeResolvedModel: ({ model }) => applyXaiRuntimeModelCompat(model), normalizeTransport: ({ provider, api, baseUrl }) => resolveXaiTransport({ provider, api, baseUrl }), contributeResolvedModelCompat: ({ modelId, model }) => diff --git a/extensions/xai/provider-models.ts b/extensions/xai/provider-models.ts index 8c02f4886a7..9aaccef61e4 100644 --- a/extensions/xai/provider-models.ts +++ b/extensions/xai/provider-models.ts @@ -3,9 +3,9 @@ import type { ProviderRuntimeModel, } from "openclaw/plugin-sdk/plugin-entry"; import { normalizeModelCompat } from "openclaw/plugin-sdk/provider-model-shared"; -import { applyXaiModelCompat } from "openclaw/plugin-sdk/provider-tools"; import { normalizeOptionalLowercaseString } from "openclaw/plugin-sdk/text-runtime"; import { resolveXaiCatalogEntry, XAI_BASE_URL } from "./model-definitions.js"; +import { applyXaiRuntimeModelCompat } from "./runtime-model-compat.js"; const XAI_MODERN_MODEL_PREFIXES = ["grok-3", "grok-4", "grok-code-fast"] as const; @@ -26,7 +26,7 @@ export function resolveXaiForwardCompatModel(params: { return undefined; } - return applyXaiModelCompat( + return applyXaiRuntimeModelCompat( normalizeModelCompat({ id: definition.id, name: definition.name, diff --git a/extensions/xai/runtime-model-compat.ts b/extensions/xai/runtime-model-compat.ts new file mode 100644 index 00000000000..c70b2cc57bf --- /dev/null +++ b/extensions/xai/runtime-model-compat.ts @@ -0,0 +1,19 @@ +import { applyXaiModelCompat } from "openclaw/plugin-sdk/provider-tools"; + +type XaiRuntimeModelCompat = { + compat?: unknown; + thinkingLevelMap?: Partial< + Record<"off" | "minimal" | "low" | "medium" | "high" | "xhigh", string | null> + >; +}; + +export function applyXaiRuntimeModelCompat(model: T): T { + const withCompat = applyXaiModelCompat(model); + return { + ...withCompat, + thinkingLevelMap: { + ...withCompat.thinkingLevelMap, + off: null, + }, + }; +} diff --git a/extensions/xai/web-search.test.ts b/extensions/xai/web-search.test.ts index 326cb0f04b3..12503d57b3b 100644 --- a/extensions/xai/web-search.test.ts +++ b/extensions/xai/web-search.test.ts @@ -585,6 +585,7 @@ describe("xai provider models", () => { api: "openai-responses", baseUrl: "https://api.x.ai/v1", reasoning: true, + thinkingLevelMap: { off: null }, input: ["text", "image"], contextWindow: 1_000_000, maxTokens: 64_000, diff --git a/scripts/verify-docker-attestations.mjs b/scripts/verify-docker-attestations.mjs index 5c2df08027b..3da6f0295cf 100644 --- a/scripts/verify-docker-attestations.mjs +++ b/scripts/verify-docker-attestations.mjs @@ -4,6 +4,11 @@ import { execFileSync } from "node:child_process"; import process from "node:process"; const ATTESTATION_REFERENCE_TYPE = "attestation-manifest"; +const ATTESTATION_ARTIFACT_TYPE = "application/vnd.docker.attestation.manifest.v1+json"; +const ATTESTATION_MANIFEST_MEDIA_TYPES = new Set([ + "application/vnd.docker.distribution.manifest.v2+json", + "application/vnd.oci.image.manifest.v1+json", +]); const REQUIRED_PREDICATES = ["https://spdx.dev/Document", "https://slsa.dev/provenance/v1"]; export function imageRefForDigest(imageRef, digest) { @@ -39,6 +44,13 @@ function platformMatches(actual, expected) { ); } +function isAttestationManifest(attestation) { + if (attestation?.artifactType !== undefined) { + return attestation.artifactType === ATTESTATION_ARTIFACT_TYPE; + } + return ATTESTATION_MANIFEST_MEDIA_TYPES.has(attestation?.mediaType); +} + function parseJson(raw, label) { try { return JSON.parse(raw); @@ -85,11 +97,11 @@ export function collectDockerAttestationErrors(params) { const predicates = new Set(); for (const descriptor of attestationDescriptors) { const attestation = inspectAttestation(descriptor.digest); - if (attestation?.artifactType !== "application/vnd.docker.attestation.manifest.v1+json") { + if (!isAttestationManifest(attestation)) { errors.push( - `${imageRef}: ${platformLabel} attestation ${descriptor.digest} has unexpected artifactType ${JSON.stringify( + `${imageRef}: ${platformLabel} attestation ${descriptor.digest} has unexpected manifest shape artifactType=${JSON.stringify( attestation?.artifactType, - )}`, + )} mediaType=${JSON.stringify(attestation?.mediaType)}`, ); } for (const layer of attestation?.layers ?? []) { diff --git a/src/agents/xai.live.test.ts b/src/agents/xai.live.test.ts index 723f1052872..f6ffd739762 100644 --- a/src/agents/xai.live.test.ts +++ b/src/agents/xai.live.test.ts @@ -74,7 +74,6 @@ describeLive("xai live", () => { { apiKey: XAI_KEY, maxTokens: 64, - reasoning: "medium", }, ); @@ -107,7 +106,6 @@ describeLive("xai live", () => { { apiKey: XAI_KEY, maxTokens: 128, - reasoning: "medium", onPayload: (payload) => { capturedPayload = payload as Record; }, diff --git a/test/scripts/verify-docker-attestations.test.ts b/test/scripts/verify-docker-attestations.test.ts index 181cf6ff8f8..dd14ee5ecde 100644 --- a/test/scripts/verify-docker-attestations.test.ts +++ b/test/scripts/verify-docker-attestations.test.ts @@ -51,6 +51,11 @@ function createAttestation( }; } +function createAttestationWithoutArtifactType() { + const { artifactType: _artifactType, ...attestation } = createAttestation(); + return attestation; +} + describe("verify-docker-attestations", () => { it("resolves digest refs from tagged image refs", () => { expect(imageRefForDigest("ghcr.io/openclaw/openclaw:2026.4.26", imageDigest)).toBe( @@ -72,6 +77,17 @@ describe("verify-docker-attestations", () => { expect(errors).toEqual([]); }); + it("accepts OCI attestation manifests without artifactType", () => { + const errors = collectDockerAttestationErrors({ + imageRef: "ghcr.io/openclaw/openclaw:test", + index: createIndex(), + requiredPlatforms: [parsePlatform("linux/amd64")], + inspectAttestation: () => createAttestationWithoutArtifactType(), + }); + + expect(errors).toEqual([]); + }); + it("reports missing attestation manifests", () => { const index = createIndex(); index.manifests = index.manifests.slice(0, 1); @@ -100,4 +116,20 @@ describe("verify-docker-attestations", () => { "ghcr.io/openclaw/openclaw:test: linux/amd64 missing predicate https://slsa.dev/provenance/v1", ]); }); + + it("reports an unexpected attestation manifest shape", () => { + const errors = collectDockerAttestationErrors({ + imageRef: "ghcr.io/openclaw/openclaw:test", + index: createIndex(), + requiredPlatforms: [parsePlatform("linux/amd64")], + inspectAttestation: () => ({ + ...createAttestation(), + artifactType: "application/vnd.example.invalid", + }), + }); + + expect(errors).toEqual([ + `ghcr.io/openclaw/openclaw:test: linux/amd64 attestation ${attestationDigest} has unexpected manifest shape artifactType="application/vnd.example.invalid" mediaType="application/vnd.oci.image.manifest.v1+json"`, + ]); + }); });