Files
agent-radar 2ed3415fb7
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

201 lines
5.5 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { composerSettingsSupportFromOptions } from "./composerSettingsSupport";
import {
AGENT_CAPABILITY_KEYS,
type AgentActivityComposerOptions,
type AgentActivitySessionCapabilities
} from "@tutti-os/agent-activity-core";
function optionsFixture(input: {
model: boolean;
reasoning: boolean;
permission: boolean;
capabilities?: string[];
}): AgentActivityComposerOptions {
return {
provider: "test",
capabilities: Object.fromEntries(
AGENT_CAPABILITY_KEYS.map((key) => [
key,
(input.capabilities ?? []).includes(key)
])
) as unknown as AgentActivitySessionCapabilities,
models: [],
reasoningEfforts: [],
speeds: [],
modelConfigurable: input.model,
reasoningConfigurable: input.reasoning,
permissionConfig: {
configurable: input.permission,
defaultValue: null,
modes: []
},
capabilityCatalog: [],
skills: [],
behavior: {
collapseModelOptionsToLatest: false,
modelOptionsAuthoritative: false,
refreshModelOptionsAfterSettings: false,
prewarmDraftSession: false,
planModeExclusiveWithPermissionMode: false
},
loadedAtUnixMs: 0
};
}
describe("composerSettingsSupportFromOptions", () => {
it("keeps reasoning available when another model profile supports it", () => {
const options = optionsFixture({
model: true,
reasoning: false,
permission: false
});
options.reasoningOptionsByModel = {
"opencode/big-pickle": { defaultValue: null, options: [] },
"openai/gpt-5": {
defaultValue: "medium",
options: [{ value: "medium", label: "Medium" }]
}
};
expect(composerSettingsSupportFromOptions(options, null).reasoning).toBe(
true
);
});
// Equivalence truth table: must match the deleted composerSupportForProvider
// hardcoded table column by column (except plan, which intentionally moves
// from a hardcoded false to capability negotiation). The backend flag values
// per provider are pinned by Go's TestComposerConfigConfigurableTruthTable.
const providerFlags: Record<
string,
{
model: boolean;
reasoning: boolean;
permission: boolean;
capabilities: string[];
}
> = {
"claude-code": {
model: true,
reasoning: true,
permission: true,
capabilities: [
"imageInput",
"skills",
"compact",
"tokenUsage",
"rateLimits",
"planMode",
"interrupt",
"browserUse"
]
},
codex: {
model: true,
reasoning: true,
permission: true,
capabilities: [
"imageInput",
"skills",
"compact",
"tokenUsage",
"rateLimits",
"planMode",
"interrupt",
"browserUse"
]
},
opencode: {
model: true,
reasoning: false,
permission: false,
capabilities: ["interrupt", "planMode", "browserUse"]
},
cursor: {
model: true,
reasoning: false,
permission: true,
capabilities: ["interrupt", "planMode", "browserUse"]
},
hermes: {
model: false,
reasoning: false,
permission: false,
capabilities: ["interrupt"]
},
nexight: {
model: false,
reasoning: false,
permission: true,
capabilities: ["interrupt"]
},
openclaw: {
model: false,
reasoning: false,
permission: false,
capabilities: []
}
};
const legacyTable: Record<
string,
{ model: boolean; reasoning: boolean; permission: boolean }
> = {
"claude-code": { model: true, reasoning: true, permission: true },
codex: { model: true, reasoning: true, permission: true },
opencode: { model: true, reasoning: false, permission: false },
cursor: { model: true, reasoning: false, permission: true },
hermes: { model: false, reasoning: false, permission: false },
nexight: { model: false, reasoning: false, permission: true },
openclaw: { model: false, reasoning: false, permission: false }
};
for (const [provider, flags] of Object.entries(providerFlags)) {
it(`matches the legacy table for ${provider}`, () => {
const support = composerSettingsSupportFromOptions(
optionsFixture(flags),
null
);
expect(support.model).toBe(legacyTable[provider]!.model);
expect(support.reasoning).toBe(legacyTable[provider]!.reasoning);
expect(support.permission).toBe(legacyTable[provider]!.permission);
expect(support.plan).toBe(
provider === "claude-code" ||
provider === "codex" ||
provider === "cursor" ||
provider === "opencode"
);
expect(support.browser).toBe(flags.capabilities.includes("browserUse"));
});
}
it("returns all-false when composer options are absent", () => {
expect(composerSettingsSupportFromOptions(null, null)).toEqual({
model: false,
reasoning: false,
speed: false,
permission: false,
plan: false,
browser: false,
computer: false,
planImplementation: false,
permissionModeChangeDuringTurn: false,
permissionModeChangeDeferred: false,
modelSwitch: false
});
});
it("prefers session runtime capabilities for plan", () => {
const support = composerSettingsSupportFromOptions(
optionsFixture({
model: true,
reasoning: true,
permission: true,
capabilities: []
}),
{ planMode: true }
);
expect(support.plan).toBe(true);
});
});