fix(provider): satisfy Featherless release checks

This commit is contained in:
Vincent Koc 2026-07-06 12:49:02 -07:00 committed by Vincent Koc
parent 8970fa2e83
commit d09e2e738c
6 changed files with 64 additions and 5 deletions

View file

@ -6,7 +6,6 @@ Docs: https://docs.openclaw.ai
### Changes
- **Featherless AI provider:** add an official external provider plugin with API-key onboarding, a tool-capable Qwen3 default, and support for arbitrary Featherless model ids.
- **Gateway host status:** show the connected Gateway's host, network address, OS, runtime, uptime, CPU, memory, and disk details in Control UI Settings. (#100478)
- **iOS offline chat:** pre-paint recent sessions and canonical transcripts from a protected, bounded per-gateway cache, keep sending disabled offline, and purge cached conversation text when pairing is reset. (#100194)
- **Slack progress indicators:** use Slack's native assistant thread status and rotating loading messages by default while keeping acknowledgement reactions static; lifecycle reaction updates now require `messages.statusReactions.enabled: true`.

View file

@ -6062,6 +6062,15 @@ Do not edit it by hand; run `pnpm docs:map:gen`.
- H2: Surface
- H2: Related docs
## plugins/reference/featherless.md
- Route: /plugins/reference/featherless
- Headings:
- H1: Featherless plugin
- H2: Distribution
- H2: Surface
- H2: Related docs
## plugins/reference/feishu.md
- Route: /plugins/reference/feishu
@ -7436,6 +7445,16 @@ Do not edit it by hand; run `pnpm docs:map:gen`.
- H2: Music generation
- H2: Related
## providers/featherless.md
- Route: /providers/featherless
- Headings:
- H2: Setup
- H2: Default model
- H2: Other Featherless models
- H2: Troubleshooting
- H2: Related
## providers/fireworks.md
- Route: /providers/fireworks

View file

@ -115,6 +115,29 @@ describe("featherless provider plugin", () => {
});
});
it("applies provider compat to configured models without overriding explicit values", async () => {
const provider = await registerSingleProviderPlugin(featherlessPlugin);
const normalized = provider.normalizeResolvedModel?.({
provider: "featherless",
modelId: "google/gemma-3-27b-it",
model: {
...createDefaultRuntimeModel(),
id: "google/gemma-3-27b-it",
name: "Gemma 3 27B",
compat: {
supportsStore: true,
thinkingFormat: "deepseek",
},
},
});
expect(normalized?.compat).toMatchObject({
...FEATHERLESS_DYNAMIC_COMPAT,
supportsStore: true,
thinkingFormat: "deepseek",
});
});
it("defers the curated model to static catalog resolution", async () => {
const provider = await registerSingleProviderPlugin(featherlessPlugin);
const resolved = provider.resolveDynamicModel?.(

View file

@ -1,5 +1,8 @@
// Featherless plugin entrypoint registers its OpenClaw integration.
import type { ProviderResolveDynamicModelContext } from "openclaw/plugin-sdk/plugin-entry";
import type {
ProviderResolveDynamicModelContext,
ProviderRuntimeModel,
} from "openclaw/plugin-sdk/plugin-entry";
import { readConfiguredProviderCatalogEntries } from "openclaw/plugin-sdk/provider-catalog-shared";
import { defineSingleProviderPluginEntry } from "openclaw/plugin-sdk/provider-entry";
import {
@ -58,6 +61,16 @@ function resolveFeatherlessDynamicModel(ctx: ProviderResolveDynamicModelContext)
);
}
function normalizeFeatherlessResolvedModel(model: ProviderRuntimeModel): ProviderRuntimeModel {
return {
...model,
compat: {
...FEATHERLESS_DYNAMIC_COMPAT,
...model.compat,
},
};
}
export default defineSingleProviderPluginEntry({
id: PROVIDER_ID,
name: "Featherless AI Provider",
@ -94,6 +107,7 @@ export default defineSingleProviderPluginEntry({
config,
providerId: PROVIDER_ID,
}),
normalizeResolvedModel: ({ model }) => normalizeFeatherlessResolvedModel(model),
...buildProviderReplayFamilyHooks({
family: "openai-compatible",
dropReasoningFromHistory: false,

View file

@ -1,6 +1,9 @@
// Featherless model catalog helpers derive their values from the plugin manifest.
import { buildManifestModelProviderConfig } from "openclaw/plugin-sdk/provider-catalog-shared";
import type { ModelDefinitionConfig } from "openclaw/plugin-sdk/provider-model-shared";
import type {
ModelCompatConfig,
ModelDefinitionConfig,
} from "openclaw/plugin-sdk/provider-model-shared";
import manifest from "./openclaw.plugin.json" with { type: "json" };
const FEATHERLESS_MANIFEST_PROVIDER = buildManifestModelProviderConfig({
@ -26,10 +29,10 @@ const FEATHERLESS_DEFAULT_MODEL = requireFeatherlessManifestModel(FEATHERLESS_DE
export const FEATHERLESS_DEFAULT_CONTEXT_WINDOW = FEATHERLESS_DEFAULT_MODEL.contextWindow;
export const FEATHERLESS_DEFAULT_MAX_TOKENS = FEATHERLESS_DEFAULT_MODEL.maxTokens;
export const FEATHERLESS_DYNAMIC_COMPAT = {
export const FEATHERLESS_DYNAMIC_COMPAT: ModelCompatConfig = {
...FEATHERLESS_DEFAULT_MODEL.compat,
thinkingFormat: "openai",
} as const;
};
export function isFeatherlessCatalogModelId(modelId: string): boolean {
return FEATHERLESS_MANIFEST_PROVIDER.models.some((model) => model.id === modelId);

View file

@ -27,6 +27,7 @@
"provider": "featherless",
"method": "api-key",
"choiceId": "featherless-api-key",
"appGuidedSecret": true,
"choiceLabel": "Featherless AI API key",
"choiceHint": "OpenAI-compatible access to open models",
"groupId": "featherless",