Skip to content

Commit dfe14fb

Browse files
committed
Fix builtin provider save — remove stray type field rejected by strict schema
`useSaveBuiltinProviderMutation` sends `type: 'builtin'` on the `PUT /api/providers/:id` body, but `ProviderUpdateSchema` in `src/lib/validation/schemas.ts` is `.strict()` and does not accept a `type` key. Every save of a builtin provider (Anthropic, OpenAI, Hermes, etc.) via the Provider Sheet therefore returns 400. The server already derives `type` server-side (`'builtin'` when the id is present in the `PROVIDERS` map, `existing.type` on update), so the client never needed to send it. - Drop `type: 'builtin'` from the PUT body. - Add a regression test asserting `PUT /providers/:id` with an unknown field returns 400. - Wire `src/app/api/providers/[id]/route.test.ts` into `test:runtime` (it was present but not executed by any npm script). Repro: open any builtin provider in the Provider Sheet, change the base URL or enablement, click Save — fails with a Zod validation error. After this change, save succeeds.
1 parent da64497 commit dfe14fb

3 files changed

Lines changed: 21 additions & 2 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@
8787
"test:cli": "node --test src/cli/*.test.js bin/*.test.js scripts/postinstall.test.mjs scripts/run-next-build.test.mjs scripts/run-next-typegen.test.mjs",
8888
"test:setup": "tsx --test src/app/api/setup/check-provider/route.test.ts src/lib/server/provider-model-discovery.test.ts src/components/auth/setup-wizard/utils.test.ts src/components/auth/setup-wizard/types.test.ts src/hooks/setup-done-detection.test.ts src/lib/setup-defaults.test.ts src/lib/server/storage-auth.test.ts src/lib/server/storage-auth-docker.test.ts",
8989
"test:openclaw": "tsx --test src/lib/openclaw/openclaw-agent-id.test.ts src/lib/openclaw/openclaw-endpoint.test.ts src/lib/server/agents/agent-runtime-config.test.ts src/lib/server/build-llm.test.ts src/lib/server/connectors/connector-routing.test.ts src/lib/server/connectors/openclaw.test.ts src/lib/server/connectors/swarmdock.test.ts src/lib/server/gateway/protocol.test.ts src/lib/server/llm-response-cache.test.ts src/lib/server/mcp-conformance.test.ts src/lib/server/openclaw/agent-resolver.test.ts src/lib/server/openclaw/deploy.test.ts src/lib/server/openclaw/skills-normalize.test.ts src/lib/server/session-tools/openclaw-nodes.test.ts src/lib/server/session-tools/swarmdock.test.ts src/lib/server/tasks/task-quality-gate.test.ts src/lib/server/tasks/task-validation.test.ts src/lib/server/tool-capability-policy.test.ts src/lib/providers/openclaw-exports.test.ts src/app/api/openclaw/dashboard-url/route.test.ts",
90-
"test:runtime": "tsx --test src/lib/server/mcp-gateway-runtime.test.ts src/lib/server/mcp-connection-pool.test.ts src/lib/server/knowledge-sources.test.ts src/lib/server/chat-execution/chat-execution-grounding.test.ts src/lib/server/chat-execution/chat-turn-preparation.test.ts src/lib/server/chat-execution/iteration-timers.test.ts src/lib/server/chat-execution/post-stream-finalization.test.ts src/lib/server/chats/clear-undo-snapshots.test.ts src/lib/server/connectors/email.test.ts src/lib/server/protocols/protocol-service.test.ts src/lib/server/runtime/run-ledger.test.ts src/lib/server/observability/otel-config.test.ts src/lib/server/safe-parse-body.test.ts src/app/api/approvals/route.test.ts src/app/api/agents/agents-route.test.ts src/app/api/tasks/tasks-route.test.ts src/app/api/chats/chat-route.test.ts src/app/api/chats/clear-route.test.ts src/app/api/chats/compact-route.test.ts src/app/api/chats/context-status-route.test.ts src/app/api/connectors/connector-doctor-route.test.ts src/app/api/healthz/route.test.ts src/app/api/logs/route.test.ts src/app/api/tts/route.test.ts",
90+
"test:runtime": "tsx --test src/lib/server/mcp-gateway-runtime.test.ts src/lib/server/mcp-connection-pool.test.ts src/lib/server/knowledge-sources.test.ts src/lib/server/chat-execution/chat-execution-grounding.test.ts src/lib/server/chat-execution/chat-turn-preparation.test.ts src/lib/server/chat-execution/iteration-timers.test.ts src/lib/server/chat-execution/post-stream-finalization.test.ts src/lib/server/chats/clear-undo-snapshots.test.ts src/lib/server/connectors/email.test.ts src/lib/server/protocols/protocol-service.test.ts src/lib/server/runtime/run-ledger.test.ts src/lib/server/observability/otel-config.test.ts src/lib/server/safe-parse-body.test.ts src/app/api/approvals/route.test.ts src/app/api/agents/agents-route.test.ts src/app/api/tasks/tasks-route.test.ts src/app/api/chats/chat-route.test.ts src/app/api/chats/clear-route.test.ts src/app/api/chats/compact-route.test.ts src/app/api/chats/context-status-route.test.ts src/app/api/connectors/connector-doctor-route.test.ts src/app/api/healthz/route.test.ts src/app/api/logs/route.test.ts src/app/api/providers/[id]/route.test.ts src/app/api/tts/route.test.ts",
9191
"test:builder": "tsx --test src/features/protocols/builder/utils/nodes-to-template.test.ts src/features/protocols/builder/utils/template-to-nodes.test.ts src/features/protocols/builder/validators/dag-validator.test.ts",
9292
"test:e2e": "tsx .workbench/browser-e2e/run.ts",
9393
"test:mcp:conformance": "node --import tsx ./scripts/mcp-conformance-check.ts",

src/app/api/providers/[id]/route.test.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,23 @@ test('provider route upserts builtin override records for enablement changes', (
4747
assert.equal(output.responsePayload.type, 'builtin')
4848
assert.equal(output.responsePayload.isEnabled, false)
4949
})
50+
51+
test('provider route rejects unknown fields per ProviderUpdateSchema.strict()', () => {
52+
const output = runWithTempDataDir<{ status: number }>(`
53+
const routeMod = await import('./src/app/api/providers/[id]/route')
54+
const route = routeMod.default || routeMod
55+
56+
const response = await route.PUT(
57+
new Request('http://local/api/providers/openai', {
58+
method: 'PUT',
59+
headers: { 'content-type': 'application/json' },
60+
body: JSON.stringify({ type: 'builtin', isEnabled: true }),
61+
}),
62+
{ params: Promise.resolve({ id: 'openai' }) },
63+
)
64+
65+
console.log(JSON.stringify({ status: response.status }))
66+
`, { prefix: 'swarmclaw-provider-route-strict-test-' })
67+
68+
assert.equal(output.status, 400)
69+
})

src/features/providers/queries.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@ export function useSaveBuiltinProviderMutation() {
8585
mutationFn: async ({ id, models, isEnabled, baseUrl }: SaveBuiltinProviderInput) => {
8686
await api('PUT', `/providers/${id}/models`, { models })
8787
return api('PUT', `/providers/${id}`, {
88-
type: 'builtin',
8988
isEnabled,
9089
...(baseUrl ? { baseUrl } : {}),
9190
})

0 commit comments

Comments
 (0)