blob: 65cc9596514c410cb5a441329670e1baa84f399a [file]
import assert from 'node:assert/strict';
import { describe, test } from 'node:test';
import type { LlmConnection } from '@maka/core';
import {
modelMetadataIdsForProvider,
PROVIDER_REGISTRY,
thinkingVariantsForModel,
} from '@maka/core';
import { buildProviderOptions } from '@maka/runtime';
function conn(providerType: LlmConnection['providerType'], slug = 'test'): LlmConnection {
return {
slug,
name: slug,
providerType,
defaultModel: 'm',
enabled: true,
createdAt: 0,
updatedAt: 0,
};
}
// The metadata universe for each provider comes from the same alias rules
// `lookupModelMetadata` applies (generated snapshot + static overrides), so
// the sweep cannot silently shrink when the alias rules change.
function wiresAnything(options: Record<string, unknown>): boolean {
// The inner object must carry at least one field the SDK will translate;
// `{ openai: {} }` would send nothing while still being non-empty at the top.
return Object.values(options).some(
(value) => typeof value === 'object' && value !== null && Object.keys(value).length > 0,
);
}
function hasRealOffWire(options: Record<string, unknown>): boolean {
// A declared off choice must map to a wire the target SDK understands:
// reasoning_effort none, thinking disabled, budget zero, or template false.
for (const value of Object.values(options)) {
if (typeof value !== 'object' || value === null) continue;
const inner = value as Record<string, unknown>;
if (inner.reasoningEffort === 'none') return true;
if (
typeof inner.thinking === 'object' &&
inner.thinking !== null &&
(inner.thinking as Record<string, unknown>).type === 'disabled'
) {
return true;
}
if (
typeof inner.thinkingConfig === 'object' &&
inner.thinkingConfig !== null &&
(inner.thinkingConfig as Record<string, unknown>).thinkingBudget === 0
) {
return true;
}
if (
typeof inner.chat_template_kwargs === 'object' &&
inner.chat_template_kwargs !== null &&
(inner.chat_template_kwargs as Record<string, unknown>).thinking === false
) {
return true;
}
}
return false;
}
describe('thinking wire contract', () => {
test('issue #1858: opencode-go wires the declared effort for deepseek-v4-flash', () => {
assert.deepEqual(buildProviderOptions(conn('opencode-go'), 'deepseek-v4-flash', 'high'), {
'opencode-go': { reasoningEffort: 'high' },
});
assert.deepEqual(buildProviderOptions(conn('opencode-go'), 'deepseek-v4-flash', 'max'), {
'opencode-go': { reasoningEffort: 'max' },
});
});
test('every declared thinking variant on every provider path wires something real', () => {
const gaps: string[] = [];
for (const providerType of Object.keys(PROVIDER_REGISTRY) as LlmConnection['providerType'][]) {
// Providers without a runtime adapter (e.g. phase3-experimental
// gemini-cli) cannot start a request, so there is no wire to honor.
if (PROVIDER_REGISTRY[providerType].runtimeAdapter?.kind === 'unavailable') continue;
const modelIds = new Set([
...PROVIDER_REGISTRY[providerType].fallbackModels,
...modelMetadataIdsForProvider(providerType),
]);
for (const modelId of modelIds) {
for (const level of thinkingVariantsForModel(providerType, modelId)) {
const options = buildProviderOptions(conn(providerType), modelId, level);
if (!wiresAnything(options)) {
gaps.push(`${providerType}/${modelId} declares "${level}" but wires nothing`);
} else if (level === 'off' && !hasRealOffWire(options)) {
gaps.push(
`${providerType}/${modelId} declares "off" without a real off wire: ${JSON.stringify(options)}`,
);
}
}
}
}
assert.deepEqual(gaps, []);
});
test('kimi-coding-plan wires every declared variant over the openai-chat protocol too', () => {
// The sweep above only exercises conn() without a model apiProtocol, so
// kimi always takes its anthropic branch. Sweep the openai-chat branch
// explicitly so a future declared level cannot silently go unwired there.
const gaps: string[] = [];
const providerType = 'kimi-coding-plan' as const;
const modelIds = new Set([
...PROVIDER_REGISTRY[providerType].fallbackModels,
...modelMetadataIdsForProvider(providerType),
]);
for (const modelId of modelIds) {
const connection = {
...conn(providerType),
models: [{ id: modelId, apiProtocol: 'openai-chat' as const }],
};
for (const level of thinkingVariantsForModel(providerType, modelId)) {
const options = buildProviderOptions(connection, modelId, level);
if (!wiresAnything(options)) {
gaps.push(
`${providerType}/${modelId} (openai-chat) declares "${level}" but wires nothing`,
);
}
}
}
assert.deepEqual(gaps, []);
});
});