426e9eeabd
Voice Workbench / headless workbench (mocked backends) (push) Has been cancelled
Voice Workbench / real acoustic lane (nightly, provisioned only) (push) Has been cancelled
ci / test (push) Has been cancelled
ci / lint-and-format (push) Has been cancelled
ci / build (push) Has been cancelled
ci / dev-startup (push) Has been cancelled
gitleaks / gitleaks (push) Has been cancelled
Markdown Links / Relative Markdown Links (push) Has been cancelled
Quality (Extended) / Homepage Build (PR smoke) (push) Has been cancelled
Quality (Extended) / Comment-only diff guard (push) Has been cancelled
Quality (Extended) / Format + Type Safety Ratchet (push) Has been cancelled
Quality (Extended) / Develop Gate (secret scan + UI determinism) (push) Has been cancelled
Quality (Extended) / Develop Gate (lint) (push) Has been cancelled
Chat shell gestures / Chat shell gesture + parity e2e (push) Has been cancelled
Cloud Gateway Discord / Test (push) Has been cancelled
Benchmark Bridge Tests / benchmark (bunx @biomejs/biome check packages/lifeops-bench/src, benchmark-lint) (push) Has been cancelled
Benchmark Bridge Tests / benchmark (bunx vitest run --config packages/lifeops-bench/vitest.config.ts --root packages/lifeops-bench --passWithNoTests, benchmark-tests) (push) Has been cancelled
Build Agent Image / build-and-push (push) Has been cancelled
Dev Smoke / bun run dev onboarding chat (push) Has been cancelled
Dev Smoke / Vite HMR dependency-level smoke (push) Has been cancelled
Electrobun Submodule Guard / electrobun gitlink is fetchable (push) Has been cancelled
Publish @elizaos/example-code / check_npm (push) Has been cancelled
Publish @elizaos/example-code / publish_npm (push) Has been cancelled
Publish @elizaos/plugin-elizacloud / verify_version (push) Has been cancelled
Publish @elizaos/plugin-elizacloud / publish_npm (push) Has been cancelled
Sandbox Live Smoke / Sandbox live smoke (push) Has been cancelled
Snap Build & Test / Build Snap (amd64) (push) Has been cancelled
Snap Build & Test / Build Snap (arm64) (push) Has been cancelled
Test Packaging / elizaos CLI global-install smoke (node + bun) (push) Has been cancelled
Cloud Gateway Webhook / Test (push) Has been cancelled
Cloud Tests / lint-and-types (push) Has been cancelled
Cloud Tests / unit-tests (push) Has been cancelled
Cloud Tests / integration-tests (push) Has been cancelled
Cloud Tests / e2e-tests (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Apps Worker (Product 2) / Determine environment (push) Has been cancelled
Deploy Apps Worker (Product 2) / Deploy apps worker to apps-control host (${{ needs.determine-env.outputs.environment }}) (push) Has been cancelled
Deploy Eliza Provisioning Worker / Determine environment (push) Has been cancelled
Deploy Eliza Provisioning Worker / Deploy worker to Hetzner host (${{ needs.determine-env.outputs.environment }} @ ${{ needs.determine-env.outputs.deployment_sha }}) (push) Has been cancelled
Dev Smoke / Classify changed paths (push) Has been cancelled
supply-chain / sbom (push) Has been cancelled
supply-chain / vulnerability-scan (push) Has been cancelled
Build, Push & Deploy to Phala Cloud / build-and-push (push) Has been cancelled
Test Packaging / Validate Packaging Configs (push) Has been cancelled
Test Packaging / Build & Test PyPI Package (push) Has been cancelled
Test Packaging / PyPI on Python ${{ matrix.python }} (push) Has been cancelled
Test Packaging / Pack & Test JS Tarballs (push) Has been cancelled
UI Fixture E2E / ui-fixture-e2e (push) Has been cancelled
UI Fixture E2E / fixture-e2e (push) Has been cancelled
UI Story Gate / story-gate (push) Has been cancelled
vault-ci / test (macos-latest) (push) Has been cancelled
vault-ci / test (ubuntu-latest) (push) Has been cancelled
vault-ci / test (windows-latest) (push) Has been cancelled
vault-ci / app-core wiring tests (push) Has been cancelled
verify-patches / verify patches/CHECKSUMS.sha256 (push) Has been cancelled
Voice Benchmark Smoke / voice-emotion fixture smoke (push) Has been cancelled
Voice Benchmark Smoke / voiceagentbench fixture smoke (push) Has been cancelled
Voice Benchmark Smoke / voicebench-quality unit smoke (push) Has been cancelled
Voice Benchmark Smoke / voicebench TypeScript unit (no audio) (push) Has been cancelled
Voice Benchmark Smoke / voice bench smoke summary (push) Has been cancelled
Windows CI / windows ([bun run --cwd packages/app-core test bun run --cwd packages/elizaos test bun run --cwd packages/cloud/shared test], app-and-cli) (push) Has been cancelled
Windows CI / windows ([bun run --cwd packages/scenario-runner test bun run --cwd packages/vault test bun run --cwd packages/security test bun run --cwd plugins/plugin-coding-tools test], framework-packages) (push) Has been cancelled
Windows CI / windows ([bun run --cwd plugins/plugin-elizacloud test bun run --cwd plugins/plugin-discord test bun run --cwd plugins/plugin-anthropic test bun run --cwd plugins/plugin-openai test bun run --cwd plugins/plugin-app-control test bun run --cwd plugins/pl… (push) Has been cancelled
Windows CI / windows ([node packages/scripts/run-turbo.mjs run build --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/agent --concurrency=4 node packages/scripts/run-bash-linux-only.mjs scripts/verify-riscv64-buildpaths.sh node packages/scripts/run… (push) Has been cancelled
Windows CI / windows ([node packages/scripts/run-turbo.mjs run typecheck --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/cloud-shared --concurrency=4 bun run --cwd packages/core test bun run --cwd packages/shared test], core-runtime, 75) (push) Has been cancelled
269 lines
8.9 KiB
TypeScript
269 lines
8.9 KiB
TypeScript
/**
|
|
* Creative-draft tests pin the owner-voice artifact contract before live voice
|
|
* memo scenarios exercise it through the model loop.
|
|
*/
|
|
|
|
import { describe, expect, it } from "vitest";
|
|
import {
|
|
applyCreativeDraftRevision,
|
|
buildCreativeDraftPrompt,
|
|
buildOwnerVoiceStyleCard,
|
|
type CreativeMemoTranscript,
|
|
createCreativeDraftArtifact,
|
|
type OwnerVoiceSource,
|
|
scoreOwnerVoiceFidelity,
|
|
} from "../src/lifeops/creative-draft/index.js";
|
|
|
|
const ownerSources: OwnerVoiceSource[] = [
|
|
{
|
|
id: "essay-1",
|
|
source: "essay",
|
|
text: "Look, I think the point is simple. We should say the hard thing plainly because the audience can feel when we sand the edges off.",
|
|
},
|
|
{
|
|
id: "mail-1",
|
|
source: "sent_mail",
|
|
text: "I think the useful version is direct and specific. What matters is keeping the heat where the heat belongs.",
|
|
},
|
|
{
|
|
id: "thread-1",
|
|
source: "thread",
|
|
text: "Look, I want the piece to move fast. The point is not polish; the point is nerve.",
|
|
},
|
|
];
|
|
|
|
const memos: CreativeMemoTranscript[] = [
|
|
{
|
|
id: "memo-anger",
|
|
transcript:
|
|
"The second section needs to stay angry. They wasted six months and then asked everyone else to call it strategy.",
|
|
affect: "angry",
|
|
toneDirective: "Keep the anger in the second section.",
|
|
capturedAt: "2026-07-06T10:00:00.000Z",
|
|
},
|
|
{
|
|
id: "memo-hope",
|
|
transcript:
|
|
"End by saying we can still build the honest version if we stop hiding behind process.",
|
|
affect: "reflective",
|
|
capturedAt: "2026-07-06T10:04:00.000Z",
|
|
},
|
|
];
|
|
|
|
describe("creative draft owner-voice primitives", () => {
|
|
it("builds a style card from owner-authored examples", () => {
|
|
const card = buildOwnerVoiceStyleCard(ownerSources);
|
|
|
|
expect(card.sourceIds).toEqual(["essay-1", "mail-1", "thread-1"]);
|
|
expect(card.stanceMarkers).toEqual(
|
|
expect.arrayContaining(["I think", "look", "the point is"]),
|
|
);
|
|
expect(card.signaturePhrases).toContain("the point");
|
|
expect(card.avoidPhrases).toContain("leverage synergies");
|
|
});
|
|
|
|
it("maps memo affect into draft sections and prompt payload", () => {
|
|
const styleCard = buildOwnerVoiceStyleCard(ownerSources);
|
|
const request = {
|
|
title: "Honest Strategy Essay",
|
|
targetForm: "essay" as const,
|
|
ownerAsk: "Turn these memos into an essay in my voice.",
|
|
requestedVoice: "my voice, not consultant voice",
|
|
};
|
|
const draft = createCreativeDraftArtifact({
|
|
request,
|
|
memos,
|
|
styleCard,
|
|
nowIso: "2026-07-06T10:10:00.000Z",
|
|
});
|
|
const prompt = buildCreativeDraftPrompt({
|
|
request,
|
|
memos,
|
|
styleCard,
|
|
currentDraft: draft,
|
|
});
|
|
|
|
expect(draft.sourceMemoIds).toEqual(["memo-anger", "memo-hope"]);
|
|
expect(draft.sections[0]).toMatchObject({
|
|
memoId: "memo-anger",
|
|
affect: "angry",
|
|
directive: "Keep the anger in the second section.",
|
|
});
|
|
expect(prompt).toContain('"task": "creative_draft"');
|
|
expect(prompt).toContain("not like a consultant");
|
|
expect(prompt).toContain("Keep the anger in the second section.");
|
|
expect(prompt).toContain('"acceptedEdits": []');
|
|
});
|
|
|
|
it("scores owner-like copy above a generic consultant baseline", () => {
|
|
const styleCard = buildOwnerVoiceStyleCard(ownerSources);
|
|
const ownerLike =
|
|
"Look, I think the point is simple. What matters is keeping the heat where the heat belongs.";
|
|
const generic =
|
|
"This best-in-class framework will unlock value and leverage synergies across a robust operating model.";
|
|
|
|
expect(scoreOwnerVoiceFidelity(ownerLike, styleCard)).toBeGreaterThan(
|
|
scoreOwnerVoiceFidelity(generic, styleCard),
|
|
);
|
|
});
|
|
|
|
it("revisions preserve accepted edits and vetoed phrases across turns", () => {
|
|
const styleCard = buildOwnerVoiceStyleCard(ownerSources);
|
|
const request = {
|
|
title: "Launch Narrative",
|
|
targetForm: "launch_thread" as const,
|
|
ownerAsk: "Make this sound like me on a good day.",
|
|
};
|
|
const initial = createCreativeDraftArtifact({
|
|
request,
|
|
memos,
|
|
styleCard,
|
|
nowIso: "2026-07-06T10:10:00.000Z",
|
|
});
|
|
const revised = applyCreativeDraftRevision(initial, {
|
|
instruction: "Keep the sharper opening; never say best-in-class.",
|
|
acceptedEdit: "Sharper opening approved.",
|
|
vetoedPhrase: "best-in-class",
|
|
replacementText: "Look, the honest version starts by naming the waste.",
|
|
revisedAt: "2026-07-06T10:20:00.000Z",
|
|
});
|
|
|
|
expect(revised.id).toBe(initial.id);
|
|
expect(revised.acceptedEdits).toEqual(["Sharper opening approved."]);
|
|
expect(revised.vetoedPhrases).toEqual(["best-in-class"]);
|
|
expect(revised.sections[0]?.text).toBe(
|
|
"Look, the honest version starts by naming the waste.",
|
|
);
|
|
expect(revised.sections[1]).toEqual(initial.sections[1]);
|
|
});
|
|
|
|
it("revises a non-first section by sectionIndex", () => {
|
|
const styleCard = buildOwnerVoiceStyleCard(ownerSources);
|
|
const initial = createCreativeDraftArtifact({
|
|
request: {
|
|
title: "Two-part memo",
|
|
targetForm: "memo" as const,
|
|
ownerAsk: "Draft this.",
|
|
},
|
|
memos,
|
|
styleCard,
|
|
nowIso: "2026-07-06T10:10:00.000Z",
|
|
});
|
|
|
|
const revised = applyCreativeDraftRevision(initial, {
|
|
instruction: "Soften the closing.",
|
|
sectionIndex: 1,
|
|
replacementText: "We can still build the honest version.",
|
|
revisedAt: "2026-07-06T10:30:00.000Z",
|
|
});
|
|
|
|
// The first section is untouched; only the targeted second section changes.
|
|
expect(revised.sections[0]).toEqual(initial.sections[0]);
|
|
expect(revised.sections[1]?.text).toBe(
|
|
"We can still build the honest version.",
|
|
);
|
|
});
|
|
|
|
it("revises a non-first section by sectionId regardless of position", () => {
|
|
const styleCard = buildOwnerVoiceStyleCard(ownerSources);
|
|
const initial = createCreativeDraftArtifact({
|
|
request: {
|
|
title: "Two-part memo",
|
|
targetForm: "memo" as const,
|
|
ownerAsk: "Draft this.",
|
|
},
|
|
memos,
|
|
styleCard,
|
|
nowIso: "2026-07-06T10:10:00.000Z",
|
|
});
|
|
const targetSection = initial.sections[1];
|
|
if (!targetSection) throw new Error("expected a second section");
|
|
|
|
const revised = applyCreativeDraftRevision(initial, {
|
|
instruction: "Rewrite the hopeful close.",
|
|
sectionId: targetSection.id,
|
|
replacementText: "Stop hiding behind process and ship the honest one.",
|
|
revisedAt: "2026-07-06T10:35:00.000Z",
|
|
});
|
|
|
|
expect(revised.sections[0]).toEqual(initial.sections[0]);
|
|
expect(revised.sections[1]?.text).toBe(
|
|
"Stop hiding behind process and ship the honest one.",
|
|
);
|
|
});
|
|
|
|
it("rejects a revision whose target section does not exist", () => {
|
|
const styleCard = buildOwnerVoiceStyleCard(ownerSources);
|
|
const initial = createCreativeDraftArtifact({
|
|
request: {
|
|
title: "Two-part memo",
|
|
targetForm: "memo" as const,
|
|
ownerAsk: "Draft this.",
|
|
},
|
|
memos,
|
|
styleCard,
|
|
nowIso: "2026-07-06T10:10:00.000Z",
|
|
});
|
|
|
|
expect(() =>
|
|
applyCreativeDraftRevision(initial, {
|
|
instruction: "Edit a section that isn't there.",
|
|
sectionIndex: 9,
|
|
replacementText: "orphan text",
|
|
revisedAt: "2026-07-06T10:40:00.000Z",
|
|
}),
|
|
).toThrow(/unknown section/u);
|
|
expect(() =>
|
|
applyCreativeDraftRevision(initial, {
|
|
instruction: "Edit by a bogus id.",
|
|
sectionId: "section_does_not_exist",
|
|
replacementText: "orphan text",
|
|
revisedAt: "2026-07-06T10:41:00.000Z",
|
|
}),
|
|
).toThrow(/unknown section/u);
|
|
});
|
|
|
|
it("sources instructions through OptimizedPromptService when a runtime is supplied", () => {
|
|
const styleCard = buildOwnerVoiceStyleCard(ownerSources);
|
|
const request = {
|
|
title: "Optimized Draft",
|
|
targetForm: "essay" as const,
|
|
ownerAsk: "Draft in my voice.",
|
|
};
|
|
const optimizedInstructions =
|
|
"OPTIMIZED creative_draft instructions — write in the owner's voice.";
|
|
const runtime = {
|
|
getService(name: string) {
|
|
if (name !== "optimized_prompt") return null;
|
|
return {
|
|
getPrompt(task: string) {
|
|
return task === "creative_draft"
|
|
? { prompt: optimizedInstructions, optimizerSource: "gepa" }
|
|
: null;
|
|
},
|
|
};
|
|
},
|
|
};
|
|
|
|
const optimizedPrompt = buildCreativeDraftPrompt({
|
|
request,
|
|
memos,
|
|
styleCard,
|
|
runtime,
|
|
});
|
|
const baselinePrompt = buildCreativeDraftPrompt({
|
|
request,
|
|
memos,
|
|
styleCard,
|
|
});
|
|
|
|
expect(optimizedPrompt).toContain(optimizedInstructions);
|
|
expect(optimizedPrompt).not.toContain("not like a consultant");
|
|
// Absent a runtime, the inline baseline is used unchanged.
|
|
expect(baselinePrompt).toContain("not like a consultant");
|
|
// The structured data payload is composed around the resolved instructions
|
|
// in both cases.
|
|
expect(optimizedPrompt).toContain('"task": "creative_draft"');
|
|
});
|
|
});
|