Files
tutti/packages/agent/gui/agent-gui/agentGuiNode/controller/agentGuiComposerDefaultsReconciliation.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

447 lines
12 KiB
TypeScript

import { describe, expect, it } from "vitest";
import {
acknowledgeAgentGUIComposerDefaultsMutation,
createAgentGUIComposerDefaultsLedger,
prepareAcknowledgedComposerDefaultsAuthorityRead,
preserveAcknowledgedComposerDefaultsForReconciliation,
registerAgentGUIComposerDefaultsMutation,
retireAcknowledgedComposerDefaultsForRead
} from "./agentGuiComposerDefaultsReconciliation";
const draftKey = "__agent_gui_node_defaults__:target:local:opencode";
describe("agentGuiComposerDefaultsReconciliation", () => {
it("does not let an older A read retire a later A generation", () => {
const ledger = createAgentGUIComposerDefaultsLedger();
const firstA = registerAgentGUIComposerDefaultsMutation(ledger, draftKey, {
permissionModeId: "ask"
});
acknowledgeAgentGUIComposerDefaultsMutation(ledger, firstA, {
acknowledgedFields: ["permissionModeId"],
supersededFields: []
});
const firstRead = prepareAcknowledgedComposerDefaultsAuthorityRead(
ledger,
draftKey,
{ permissionModeId: "ask" }
);
expect(firstRead.settings).toEqual({});
expect(firstRead.receipt).not.toBeNull();
const mutationB = registerAgentGUIComposerDefaultsMutation(
ledger,
draftKey,
{ permissionModeId: "full-access" }
);
acknowledgeAgentGUIComposerDefaultsMutation(ledger, mutationB, {
acknowledgedFields: ["permissionModeId"],
supersededFields: []
});
const latestA = registerAgentGUIComposerDefaultsMutation(ledger, draftKey, {
permissionModeId: "ask"
});
acknowledgeAgentGUIComposerDefaultsMutation(ledger, latestA, {
acknowledgedFields: ["permissionModeId"],
supersededFields: []
});
expect(
retireAcknowledgedComposerDefaultsForRead(
ledger,
firstRead.receipt!,
{
permissionModeId: "ask"
},
{
permissionModeId: "ask"
}
)
).toEqual([]);
const latestRead = prepareAcknowledgedComposerDefaultsAuthorityRead(
ledger,
draftKey,
{ permissionModeId: "ask" }
);
expect(latestRead.receipt).not.toBeNull();
expect(
retireAcknowledgedComposerDefaultsForRead(
ledger,
latestRead.receipt!,
{
permissionModeId: "ask"
},
{
permissionModeId: "ask"
}
)
).toEqual([{ field: "permissionModeId", value: "ask" }]);
});
it("does not let a read started before ack retire that later ack", () => {
const ledger = createAgentGUIComposerDefaultsLedger();
const mutation = registerAgentGUIComposerDefaultsMutation(
ledger,
draftKey,
{ model: "opencode/model-a" }
);
const preAckRead = prepareAcknowledgedComposerDefaultsAuthorityRead(
ledger,
draftKey,
{ model: "opencode/model-a" }
);
expect(preAckRead).toEqual({
force: false,
receipt: null,
settings: { model: "opencode/model-a" }
});
acknowledgeAgentGUIComposerDefaultsMutation(ledger, mutation, {
acknowledgedFields: ["model"],
supersededFields: []
});
const postAckRead = prepareAcknowledgedComposerDefaultsAuthorityRead(
ledger,
draftKey,
{ model: "opencode/model-a" }
);
expect(postAckRead).toMatchObject({
force: true,
receipt: {
draftKey,
fields: { model: { value: "opencode/model-a" } }
},
settings: {}
});
});
it("keeps authority receipts isolated by target draft key", () => {
const ledger = createAgentGUIComposerDefaultsLedger();
const otherDraftKey =
"__agent_gui_node_defaults__:target:local:claude-code";
const opencodeMutation = registerAgentGUIComposerDefaultsMutation(
ledger,
draftKey,
{ speed: "fast" }
);
const claudeMutation = registerAgentGUIComposerDefaultsMutation(
ledger,
otherDraftKey,
{ speed: "normal" }
);
acknowledgeAgentGUIComposerDefaultsMutation(ledger, opencodeMutation, {
acknowledgedFields: ["speed"],
supersededFields: []
});
acknowledgeAgentGUIComposerDefaultsMutation(ledger, claudeMutation, {
acknowledgedFields: ["speed"],
supersededFields: []
});
const opencodeRead = prepareAcknowledgedComposerDefaultsAuthorityRead(
ledger,
draftKey,
{ speed: "fast" }
);
expect(
retireAcknowledgedComposerDefaultsForRead(
ledger,
opencodeRead.receipt!,
{
speed: "fast"
},
{
speed: "fast"
}
)
).toEqual([{ field: "speed", value: "fast" }]);
expect(
prepareAcknowledgedComposerDefaultsAuthorityRead(ledger, otherDraftKey, {
speed: "normal"
}).receipt
).not.toBeNull();
});
it("keeps optimistic defaults when an authority read returns an older value", () => {
const ledger = createAgentGUIComposerDefaultsLedger();
const mutation = registerAgentGUIComposerDefaultsMutation(
ledger,
draftKey,
{ permissionModeId: "accept_edits" }
);
acknowledgeAgentGUIComposerDefaultsMutation(ledger, mutation, {
acknowledgedFields: ["permissionModeId"],
supersededFields: []
});
const read = prepareAcknowledgedComposerDefaultsAuthorityRead(
ledger,
draftKey,
{ permissionModeId: "accept_edits" }
);
expect(
retireAcknowledgedComposerDefaultsForRead(
ledger,
read.receipt!,
{ permissionModeId: "accept_edits" },
{ permissionModeId: "default" }
)
).toEqual([]);
expect(
prepareAcknowledgedComposerDefaultsAuthorityRead(ledger, draftKey, {
permissionModeId: "accept_edits"
}).receipt
).not.toBeNull();
});
it("stops forcing reads after bounded concrete authority conflicts", () => {
const ledger = createAgentGUIComposerDefaultsLedger();
const mutation = registerAgentGUIComposerDefaultsMutation(
ledger,
draftKey,
{ permissionModeId: "accept_edits" }
);
acknowledgeAgentGUIComposerDefaultsMutation(ledger, mutation, {
acknowledgedFields: ["permissionModeId"],
supersededFields: []
});
const settings = { permissionModeId: "accept_edits" };
for (let attempt = 0; attempt < 2; attempt += 1) {
const read = prepareAcknowledgedComposerDefaultsAuthorityRead(
ledger,
draftKey,
settings
);
expect(read.force).toBe(true);
retireAcknowledgedComposerDefaultsForRead(
ledger,
read.receipt!,
settings,
{ permissionModeId: "default" }
);
}
expect(
prepareAcknowledgedComposerDefaultsAuthorityRead(
ledger,
draftKey,
settings
)
).toEqual({
force: false,
receipt: null,
settings
});
});
it("protects acknowledged fields from sanitize only while confirmation remains bounded", () => {
const ledger = createAgentGUIComposerDefaultsLedger();
const settings = {
model: "opencode/model-b",
permissionModeId: "accept_edits",
reasoningEffort: "high",
speed: "fast"
};
const mutation = registerAgentGUIComposerDefaultsMutation(
ledger,
draftKey,
settings
);
acknowledgeAgentGUIComposerDefaultsMutation(ledger, mutation, {
acknowledgedFields: [
"model",
"permissionModeId",
"reasoningEffort",
"speed"
],
supersededFields: []
});
const sanitized = {
model: null,
permissionModeId: null,
reasoningEffort: null,
speed: null
};
expect(
preserveAcknowledgedComposerDefaultsForReconciliation(
ledger,
draftKey,
settings,
sanitized
)
).toEqual(settings);
for (let attempt = 0; attempt < 2; attempt += 1) {
const read = prepareAcknowledgedComposerDefaultsAuthorityRead(
ledger,
draftKey,
settings
);
retireAcknowledgedComposerDefaultsForRead(
ledger,
read.receipt!,
settings,
{
model: "opencode/model-a",
permissionModeId: "default",
reasoningEffort: "low",
speed: "normal"
}
);
}
expect(
preserveAcknowledgedComposerDefaultsForReconciliation(
ledger,
draftKey,
settings,
sanitized
)
).toBe(sanitized);
});
it("stops forcing reads but keeps optimistic intent when authority omits the field", () => {
const ledger = createAgentGUIComposerDefaultsLedger();
const mutation = registerAgentGUIComposerDefaultsMutation(
ledger,
draftKey,
{ permissionModeId: "accept_edits" }
);
acknowledgeAgentGUIComposerDefaultsMutation(ledger, mutation, {
acknowledgedFields: ["permissionModeId"],
supersededFields: []
});
const settings = { permissionModeId: "accept_edits" };
const read = prepareAcknowledgedComposerDefaultsAuthorityRead(
ledger,
draftKey,
settings
);
expect(
retireAcknowledgedComposerDefaultsForRead(
ledger,
read.receipt!,
settings,
{}
)
).toEqual([]);
expect(
prepareAcknowledgedComposerDefaultsAuthorityRead(
ledger,
draftKey,
settings
)
).toEqual({
force: false,
receipt: null,
settings
});
});
it("reconciles exact, absent, and conflicting fields independently", () => {
const ledger = createAgentGUIComposerDefaultsLedger();
const mutation = registerAgentGUIComposerDefaultsMutation(
ledger,
draftKey,
{
model: "opencode/model-a",
permissionModeId: "accept_edits",
speed: "fast"
}
);
acknowledgeAgentGUIComposerDefaultsMutation(ledger, mutation, {
acknowledgedFields: ["model", "permissionModeId", "speed"],
supersededFields: []
});
const settings = {
model: "opencode/model-a",
permissionModeId: "accept_edits",
speed: "fast"
};
const read = prepareAcknowledgedComposerDefaultsAuthorityRead(
ledger,
draftKey,
settings
);
expect(
retireAcknowledgedComposerDefaultsForRead(
ledger,
read.receipt!,
settings,
{
model: "opencode/model-a",
speed: "normal"
}
)
).toEqual([{ field: "model", value: "opencode/model-a" }]);
expect(
prepareAcknowledgedComposerDefaultsAuthorityRead(ledger, draftKey, {
permissionModeId: "accept_edits",
speed: "fast"
})
).toMatchObject({
force: true,
receipt: {
fields: {
speed: { value: "fast" }
}
},
settings: {
permissionModeId: "accept_edits"
}
});
});
it("does not let an omitted older read release a newer generation", () => {
const ledger = createAgentGUIComposerDefaultsLedger();
const firstMutation = registerAgentGUIComposerDefaultsMutation(
ledger,
draftKey,
{ permissionModeId: "accept_edits" }
);
acknowledgeAgentGUIComposerDefaultsMutation(ledger, firstMutation, {
acknowledgedFields: ["permissionModeId"],
supersededFields: []
});
const firstRead = prepareAcknowledgedComposerDefaultsAuthorityRead(
ledger,
draftKey,
{ permissionModeId: "accept_edits" }
);
const secondMutation = registerAgentGUIComposerDefaultsMutation(
ledger,
draftKey,
{ permissionModeId: "dont_ask" }
);
acknowledgeAgentGUIComposerDefaultsMutation(ledger, secondMutation, {
acknowledgedFields: ["permissionModeId"],
supersededFields: []
});
expect(
retireAcknowledgedComposerDefaultsForRead(
ledger,
firstRead.receipt!,
{ permissionModeId: "dont_ask" },
{}
)
).toEqual([]);
expect(
prepareAcknowledgedComposerDefaultsAuthorityRead(ledger, draftKey, {
permissionModeId: "dont_ask"
})
).toMatchObject({
force: true,
receipt: {
fields: {
permissionModeId: { value: "dont_ask" }
}
}
});
});
});