源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
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
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
This commit is contained in:
+491
@@ -0,0 +1,491 @@
|
||||
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({});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user