Skip to content

Commit b0201fe

Browse files
authored
Merge branch 'main' into fix-auth-profiles-eperm-non-fatal
2 parents 4ccdd4a + 7c13004 commit b0201fe

10 files changed

Lines changed: 74 additions & 10 deletions

extensions/xai/api.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export {
2525
XAI_IMAGE_MODELS,
2626
} from "./model-definitions.js";
2727
export { isModernXaiModel, resolveXaiForwardCompatModel } from "./provider-models.js";
28+
export { applyXaiRuntimeModelCompat } from "./runtime-model-compat.js";
2829
export {
2930
applyXaiModelCompat,
3031
HTML_ENTITY_TOOL_CALL_ARGUMENTS_ENCODING,

extensions/xai/index.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ describe("xai provider plugin", () => {
221221
model: createProviderModel({ id: "grok-4-1-fast" }),
222222
} as never),
223223
).toMatchObject({
224+
thinkingLevelMap: { off: null },
224225
compat: {
225226
toolSchemaProfile: "xai",
226227
nativeWebSearchTool: true,

extensions/xai/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { defaultToolStreamExtraParams } from "openclaw/plugin-sdk/provider-strea
44
import { jsonResult, readProviderEnvValue } from "openclaw/plugin-sdk/provider-web-search";
55
import { Type } from "typebox";
66
import {
7-
applyXaiModelCompat,
7+
applyXaiRuntimeModelCompat,
88
buildXaiImageGenerationProvider,
99
normalizeXaiModelId,
1010
resolveXaiTransport,
@@ -194,7 +194,7 @@ export default defineSingleProviderPluginEntry({
194194
mode: "api-key" as const,
195195
};
196196
},
197-
normalizeResolvedModel: ({ model }) => applyXaiModelCompat(model),
197+
normalizeResolvedModel: ({ model }) => applyXaiRuntimeModelCompat(model),
198198
normalizeTransport: ({ provider, api, baseUrl }) =>
199199
resolveXaiTransport({ provider, api, baseUrl }),
200200
contributeResolvedModelCompat: ({ modelId, model }) =>

extensions/xai/provider-models.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ import type {
33
ProviderRuntimeModel,
44
} from "openclaw/plugin-sdk/plugin-entry";
55
import { normalizeModelCompat } from "openclaw/plugin-sdk/provider-model-shared";
6-
import { applyXaiModelCompat } from "openclaw/plugin-sdk/provider-tools";
76
import { normalizeOptionalLowercaseString } from "openclaw/plugin-sdk/text-runtime";
87
import { resolveXaiCatalogEntry, XAI_BASE_URL } from "./model-definitions.js";
8+
import { applyXaiRuntimeModelCompat } from "./runtime-model-compat.js";
99

1010
const XAI_MODERN_MODEL_PREFIXES = ["grok-3", "grok-4", "grok-code-fast"] as const;
1111

@@ -26,7 +26,7 @@ export function resolveXaiForwardCompatModel(params: {
2626
return undefined;
2727
}
2828

29-
return applyXaiModelCompat(
29+
return applyXaiRuntimeModelCompat(
3030
normalizeModelCompat({
3131
id: definition.id,
3232
name: definition.name,
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { applyXaiModelCompat } from "openclaw/plugin-sdk/provider-tools";
2+
3+
type XaiRuntimeModelCompat = {
4+
compat?: unknown;
5+
thinkingLevelMap?: Partial<
6+
Record<"off" | "minimal" | "low" | "medium" | "high" | "xhigh", string | null>
7+
>;
8+
};
9+
10+
export function applyXaiRuntimeModelCompat<T extends XaiRuntimeModelCompat>(model: T): T {
11+
const withCompat = applyXaiModelCompat(model);
12+
return {
13+
...withCompat,
14+
thinkingLevelMap: {
15+
...withCompat.thinkingLevelMap,
16+
off: null,
17+
},
18+
};
19+
}

extensions/xai/web-search.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,7 @@ describe("xai provider models", () => {
585585
api: "openai-responses",
586586
baseUrl: "https://api.x.ai/v1",
587587
reasoning: true,
588+
thinkingLevelMap: { off: null },
588589
input: ["text", "image"],
589590
contextWindow: 1_000_000,
590591
maxTokens: 64_000,

scripts/verify-docker-attestations.mjs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ import { execFileSync } from "node:child_process";
44
import process from "node:process";
55

66
const ATTESTATION_REFERENCE_TYPE = "attestation-manifest";
7+
const ATTESTATION_ARTIFACT_TYPE = "application/vnd.docker.attestation.manifest.v1+json";
8+
const ATTESTATION_MANIFEST_MEDIA_TYPES = new Set([
9+
"application/vnd.docker.distribution.manifest.v2+json",
10+
"application/vnd.oci.image.manifest.v1+json",
11+
]);
712
const REQUIRED_PREDICATES = ["https://spdx.dev/Document", "https://slsa.dev/provenance/v1"];
813

914
export function imageRefForDigest(imageRef, digest) {
@@ -39,6 +44,13 @@ function platformMatches(actual, expected) {
3944
);
4045
}
4146

47+
function isAttestationManifest(attestation) {
48+
if (attestation?.artifactType !== undefined) {
49+
return attestation.artifactType === ATTESTATION_ARTIFACT_TYPE;
50+
}
51+
return ATTESTATION_MANIFEST_MEDIA_TYPES.has(attestation?.mediaType);
52+
}
53+
4254
function parseJson(raw, label) {
4355
try {
4456
return JSON.parse(raw);
@@ -85,11 +97,11 @@ export function collectDockerAttestationErrors(params) {
8597
const predicates = new Set();
8698
for (const descriptor of attestationDescriptors) {
8799
const attestation = inspectAttestation(descriptor.digest);
88-
if (attestation?.artifactType !== "application/vnd.docker.attestation.manifest.v1+json") {
100+
if (!isAttestationManifest(attestation)) {
89101
errors.push(
90-
`${imageRef}: ${platformLabel} attestation ${descriptor.digest} has unexpected artifactType ${JSON.stringify(
102+
`${imageRef}: ${platformLabel} attestation ${descriptor.digest} has unexpected manifest shape artifactType=${JSON.stringify(
91103
attestation?.artifactType,
92-
)}`,
104+
)} mediaType=${JSON.stringify(attestation?.mediaType)}`,
93105
);
94106
}
95107
for (const layer of attestation?.layers ?? []) {

src/agents/models.profiles.live.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -741,7 +741,7 @@ describeLive("live models (profile keys)", () => {
741741
? {
742742
externalCli: externalCliDiscoveryForProviders({ cfg, providers: providerList }),
743743
skipExternalAuthProfiles: true,
744-
syntheticAuthProviderRefs: providerList,
744+
syntheticAuthProviderRefs: [],
745745
}
746746
: {}),
747747
});

src/agents/xai.live.test.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ describeLive("xai live", () => {
7474
{
7575
apiKey: XAI_KEY,
7676
maxTokens: 64,
77-
reasoning: "medium",
7877
},
7978
);
8079

@@ -107,7 +106,6 @@ describeLive("xai live", () => {
107106
{
108107
apiKey: XAI_KEY,
109108
maxTokens: 128,
110-
reasoning: "medium",
111109
onPayload: (payload) => {
112110
capturedPayload = payload as Record<string, unknown>;
113111
},

test/scripts/verify-docker-attestations.test.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ function createAttestation(
5151
};
5252
}
5353

54+
function createAttestationWithoutArtifactType() {
55+
const { artifactType: _artifactType, ...attestation } = createAttestation();
56+
return attestation;
57+
}
58+
5459
describe("verify-docker-attestations", () => {
5560
it("resolves digest refs from tagged image refs", () => {
5661
expect(imageRefForDigest("ghcr.io/openclaw/openclaw:2026.4.26", imageDigest)).toBe(
@@ -72,6 +77,17 @@ describe("verify-docker-attestations", () => {
7277
expect(errors).toEqual([]);
7378
});
7479

80+
it("accepts OCI attestation manifests without artifactType", () => {
81+
const errors = collectDockerAttestationErrors({
82+
imageRef: "ghcr.io/openclaw/openclaw:test",
83+
index: createIndex(),
84+
requiredPlatforms: [parsePlatform("linux/amd64")],
85+
inspectAttestation: () => createAttestationWithoutArtifactType(),
86+
});
87+
88+
expect(errors).toEqual([]);
89+
});
90+
7591
it("reports missing attestation manifests", () => {
7692
const index = createIndex();
7793
index.manifests = index.manifests.slice(0, 1);
@@ -100,4 +116,20 @@ describe("verify-docker-attestations", () => {
100116
"ghcr.io/openclaw/openclaw:test: linux/amd64 missing predicate https://slsa.dev/provenance/v1",
101117
]);
102118
});
119+
120+
it("reports an unexpected attestation manifest shape", () => {
121+
const errors = collectDockerAttestationErrors({
122+
imageRef: "ghcr.io/openclaw/openclaw:test",
123+
index: createIndex(),
124+
requiredPlatforms: [parsePlatform("linux/amd64")],
125+
inspectAttestation: () => ({
126+
...createAttestation(),
127+
artifactType: "application/vnd.example.invalid",
128+
}),
129+
});
130+
131+
expect(errors).toEqual([
132+
`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"`,
133+
]);
134+
});
103135
});

0 commit comments

Comments
 (0)