Files
tutti/packages/agent/gui/agent-gui/agentGuiNode/controller/agentGuiController.composerHelpers.spec.ts
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

492 lines
13 KiB
TypeScript

import { afterEach, describe, expect, it } from "vitest";
import { setAgentGuiI18nTestLocale } from "../../../i18n/testUtils";
import type { AgentSessionPermissionConfig } from "../../../shared/agentSessionTypes";
import type { AgentGUINodeData } from "../../../types";
import {
buildNodeDefaultComposerSettings,
slashCommandPoliciesEqual,
nodeDataFromComposerSettings,
permissionModeOptions,
providerSkillsFromComposerOptions,
readNodeDefaultDraftSettings,
reasoningSelectionFromComposerOptions
} from "./agentGuiController.composerHelpers";
import type { AgentActivityComposerOptions } from "@tutti-os/agent-activity-core";
describe("slash command policy equality", () => {
const policy = {
fallbackCommands: ["compact", "goal"],
commandEffects: [
{ command: "compact", effect: "submitImmediate" as const },
{ command: "goal", effect: "activateGoalMode" as const }
]
};
it("compares cloned policy values structurally", () => {
expect(slashCommandPoliciesEqual(policy, structuredClone(policy))).toBe(
true
);
expect(
slashCommandPoliciesEqual(policy, {
...structuredClone(policy),
commandEffects: [
{ command: "compact", effect: "submitImmediate" },
{ command: "goal", effect: "showStatus" }
]
})
).toBe(false);
expect(
slashCommandPoliciesEqual(policy, {
...structuredClone(policy),
commandCatalogAuthoritative: true
})
).toBe(false);
});
});
describe("descriptor-backed skill invocation", () => {
it("does not apply invocation metadata from unavailable capabilities", () => {
const options = {
skills: [
{
name: "example",
trigger: "/example",
sourceKind: "plugin"
}
],
capabilityCatalog: [
{
name: "example",
label: "Example",
kind: "skill",
status: "unavailable",
trigger: "/example",
invocation: "promptItem"
}
]
} as unknown as AgentActivityComposerOptions;
expect(providerSkillsFromComposerOptions(options)).toEqual([
{
name: "example",
trigger: "/example",
sourceKind: "plugin"
}
]);
});
it("projects capability-only prompt-item skills for ordinary provider catalogs", () => {
const options = {
provider: "tutti-agent",
behavior: { nativePluginCatalogAuthoritative: false },
skills: [],
capabilityCatalog: [
{
id: "skill:review",
name: "review",
label: "Review",
kind: "skill",
status: "available",
trigger: "$review",
invocation: "promptItem",
path: "/skills/review/SKILL.md",
description: "Review code"
},
{
id: "skill:disabled",
name: "disabled",
label: "Disabled",
kind: "skill",
status: "disabled",
trigger: "$disabled",
invocation: "promptItem",
path: "/skills/disabled/SKILL.md"
}
]
} as unknown as AgentActivityComposerOptions;
expect(providerSkillsFromComposerOptions(options)).toEqual([
{
name: "review",
trigger: "$review",
invocation: "promptItem",
sourceKind: "plugin",
kind: "skill",
path: "/skills/review/SKILL.md",
description: "Review code"
}
]);
});
it("projects local connector capabilities with connection status", () => {
const options = {
provider: "tutti-agent",
behavior: {},
skills: [],
capabilityCatalog: [
{
id: "connector:github",
name: "github",
label: "GitHub",
kind: "connector",
status: "available",
trigger: "/github",
invocation: "textTrigger",
iconUrl: "data:image/png;base64,Z2l0aHVi",
description: "Repositories and pull requests",
source: "local-db"
},
{
id: "connector:notion",
name: "notion",
label: "Notion",
kind: "connector",
status: "authRequired",
trigger: "/notion",
invocation: "textTrigger",
source: "local-db"
}
]
} as unknown as AgentActivityComposerOptions;
expect(providerSkillsFromComposerOptions(options)).toEqual([
{
name: "GitHub",
connectorKey: "github",
trigger: "/github",
invocation: "textTrigger",
sourceKind: "connector",
kind: "connector",
status: "available",
iconUrl: "data:image/png;base64,Z2l0aHVi",
description: "Repositories and pull requests"
},
{
name: "Notion",
connectorKey: "notion",
trigger: "/notion",
invocation: "textTrigger",
sourceKind: "connector",
kind: "connector",
status: "authRequired"
}
]);
});
});
describe("permissionModeOptions", () => {
afterEach(() => {
setAgentGuiI18nTestLocale("en");
});
it("localizes codex auto permission through the zh-CN provider label", () => {
setAgentGuiI18nTestLocale("zh-CN");
const permissionConfig: AgentSessionPermissionConfig = {
configurable: true,
defaultValue: "auto",
modes: [
{
id: "auto",
label: "Approve for me",
description: "Ask only when risky actions are detected",
semantic: "auto"
}
]
};
expect(permissionModeOptions("codex", permissionConfig)).toEqual([
{
value: "auto",
label: "替我审批",
description: "仅对检测到的风险操作请求批准"
}
]);
});
it("presents OpenCode permissions independently from Plan mode", () => {
const permissionConfig: AgentSessionPermissionConfig = {
configurable: true,
defaultValue: "ask",
modes: [
{
id: "read-only",
label: "Read-only",
description: "Read-only",
semantic: "locked-down"
},
{
id: "ask",
label: "Ask",
description: "Ask",
semantic: "ask-before-write"
},
{
id: "full-access",
label: "Full access",
description: "Full access",
semantic: "full-access"
}
]
};
expect(permissionModeOptions("opencode", permissionConfig)).toEqual([
expect.objectContaining({ value: "read-only", label: "Read-only" }),
expect.objectContaining({ value: "ask", label: "Ask" }),
expect.objectContaining({
value: "full-access",
label: "Full access",
description: expect.stringContaining("separate Plan mode")
})
]);
});
});
describe("model reasoning options", () => {
afterEach(() => {
setAgentGuiI18nTestLocale("en");
});
const composerOptions = {
provider: "codex",
models: [
{ value: "gpt-5.6-sol", label: "GPT-5.6-Sol" },
{ value: "gpt-5.6-luna", label: "GPT-5.6-Luna" }
],
reasoningEfforts: [{ value: "high", label: "High" }],
speeds: [],
skills: [],
reasoningOptionsByModel: {
"gpt-5.6-sol": {
defaultValue: "low",
options: [
{ value: "low", label: "Low" },
{ value: "ultra", label: "ultra" }
]
},
"gpt-5.6-luna": {
defaultValue: "medium",
options: [
{ value: "low", label: "Low" },
{ value: "medium", label: "Medium" }
]
},
"no-reasoning": {
defaultValue: null,
options: []
}
},
loadedAtUnixMs: 1
} as unknown as AgentActivityComposerOptions;
it("switches the list by model without another catalog request", () => {
expect(
reasoningSelectionFromComposerOptions(
composerOptions,
"high",
"gpt-5.6-sol"
)
).toEqual({
currentValue: "low",
options: [
{ value: "low", label: "Low" },
{ value: "ultra", label: "ultra" }
]
});
expect(
reasoningSelectionFromComposerOptions(
composerOptions,
"ultra",
"gpt-5.6-luna"
)
).toEqual({
currentValue: "medium",
options: [
{ value: "low", label: "Low" },
{ value: "medium", label: "Medium" }
]
});
});
it("prefers the active ACP config options over the home catalog profile", () => {
expect(
reasoningSelectionFromComposerOptions(
composerOptions,
"xhigh",
"gpt-5.6-sol",
{
configOptions: [
{
id: "reasoning_effort",
currentValue: "xhigh",
options: [
{ value: "high", name: "High" },
{ value: "xhigh", name: "X High" }
]
}
]
}
)
).toEqual({
currentValue: "xhigh",
options: [
{ value: "high", label: "High" },
{ value: "xhigh", label: "X High" }
]
});
});
it("preserves an authoritative empty model reasoning list", () => {
expect(
reasoningSelectionFromComposerOptions(
composerOptions,
"high",
"no-reasoning"
)
).toEqual({ currentValue: null, options: [] });
});
it("rejects a stale live current value outside the advertised list", () => {
expect(
reasoningSelectionFromComposerOptions(
composerOptions,
"ultra",
"gpt-5.6-sol",
{
configOptions: [
{
id: "reasoning_effort",
currentValue: "ultra",
options: [
{ value: "high", name: "High" },
{ value: "xhigh", name: "X High" }
]
}
]
}
)
).toEqual({
currentValue: "high",
options: [
{ value: "high", label: "High" },
{ value: "xhigh", label: "X High" }
]
});
});
});
describe("target-keyed composer defaults", () => {
const baseNodeData: AgentGUINodeData = {
provider: "codex",
agentTargetId: "local:codex",
lastActiveAgentSessionId: null,
composerOverrides: null,
composerOverridesByAgentTargetId: {
"local:codex": { model: "target-model" }
},
composerOverridesByProvider: {
codex: { model: "provider-model" }
}
};
it("isolates target composer overrides from provider defaults", () => {
expect(buildNodeDefaultComposerSettings(baseNodeData).model).toBe(
"target-model"
);
expect(
buildNodeDefaultComposerSettings({
...baseNodeData,
agentTargetId: "other-target"
}).model
).toBeNull();
expect(
buildNodeDefaultComposerSettings({
...baseNodeData,
agentTargetId: null
}).model
).toBe("provider-model");
});
it("writes target composer overrides without mutating provider defaults", () => {
const next = nodeDataFromComposerSettings(baseNodeData, {
model: "target-new",
reasoningEffort: null,
speed: null,
planMode: false,
browserUse: true,
computerUse: true,
permissionModeId: null
});
expect(next.composerOverridesByAgentTargetId?.["local:codex"]?.model).toBe(
"target-new"
);
expect(next.composerOverridesByProvider?.codex?.model).toBe(
"provider-model"
);
expect(next.composerOverrides?.model ?? null).toBeNull();
});
it("reads target draft settings before provider legacy defaults", () => {
expect(
readNodeDefaultDraftSettings({
data: baseNodeData,
drafts: {
"__agent_gui_node_defaults__:codex": {
model: "provider-draft-model",
reasoningEffort: null,
speed: null,
planMode: false,
browserUse: true,
computerUse: true,
permissionModeId: null
},
"__agent_gui_node_defaults__:target:local:codex": {
model: "target-draft-model",
reasoningEffort: null,
speed: null,
planMode: false,
browserUse: true,
computerUse: true,
permissionModeId: null
}
}
}).model
).toBe("target-draft-model");
});
it("does not read provider or global draft settings for target-backed composers", () => {
expect(
readNodeDefaultDraftSettings({
data: {
...baseNodeData,
composerOverrides: {
model: "legacy-generic-model",
permissionModeId: "full-access"
}
},
drafts: {
"__agent_gui_node_defaults__:codex": {
model: "provider-draft-model",
reasoningEffort: null,
speed: null,
planMode: false,
browserUse: true,
computerUse: true,
permissionModeId: "auto"
},
__agent_gui_node_defaults__: {
model: "global-draft-model",
reasoningEffort: null,
speed: null,
planMode: false,
browserUse: true,
computerUse: true,
permissionModeId: "full-access"
}
}
})
).toEqual({});
});
});