项目文件夹

文件
wehub-resource-sync 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
chore: import upstream snapshot with attribution
2026-07-13 12:43:05 +08:00

279 行
9.4 KiB
TypeScript

/**
* Asserts the canonical LifeOps action structure: retired source action names stay
* unregistered, the owner-operation parent umbrellas register, and each exposes `action` as
* its public discriminator. Pure plugin-shape asserts, no model.
*/
import { ShortcutRegistry } from "@elizaos/core";
import { describe, expect, it } from "vitest";
import { isDarwin } from "../src/platform/host.js";
import {
APPROVAL_REJECT_SHORTCUT_ID,
personalAssistantPlugin,
} from "../src/plugin.js";
// OWNER_SCREENTIME is only registered on darwin because the native activity
// tracker is macOS-only. See `platformGatedActionUmbrellas` in src/plugin.ts
// and `b56fb4edf6` (graceful Windows fallbacks for darwin-only features).
const DARWIN_ONLY_PARENTS = new Set(["OWNER_SCREENTIME"]);
const RETIRED_REGISTERED_NAMES = [
"LIFE",
"PROFILE",
"RELATIONSHIP",
"MONEY",
"PAYMENTS",
"SUBSCRIPTIONS",
"CHECKIN",
"SCHEDULE",
"BOOK_TRAVEL",
"SCHEDULING_NEGOTIATION",
"FIRST_RUN",
"TOGGLE_FEATURE",
"DEVICE_INTENT",
"MESSAGE_HANDOFF",
"APP_BLOCK",
"WEBSITE_BLOCK",
"AUTOFILL",
"PASSWORD_MANAGER",
"GOOGLE_CALENDAR",
"LIFEOPS",
"LIFEOPS_THREAD_CONTROL",
"SCHEDULED_TASK",
// Scheduling sub-handlers converted to plain functions in Task F teardown;
// dispatched from CALENDAR umbrella (action=propose_times|check_availability|update_preferences).
"PROPOSE_MEETING_TIMES",
"CHECK_AVAILABILITY",
"UPDATE_MEETING_PREFERENCES",
] as const;
const CANONICAL_OWNER_PARENTS = [
"OWNER_REMINDERS",
"OWNER_ALARMS",
"OWNER_GOALS",
"OWNER_TODOS",
"OWNER_ROUTINES",
"OWNER_HEALTH",
"OWNER_SCREENTIME",
"OWNER_FINANCES",
"PERSONAL_ASSISTANT",
"BLOCK",
"CREDENTIALS",
"CALENDAR",
"CONNECTOR",
"RESOLVE_REQUEST",
"VOICE_CALL",
"SCHEDULED_TASKS",
"WORK_THREAD",
] as const;
describe("LifeOps canonical action structure", () => {
it("does not register retired LifeOps source action names", () => {
const actionNames = new Set(
(personalAssistantPlugin.actions ?? []).map((a) => a.name),
);
for (const retired of RETIRED_REGISTERED_NAMES) {
expect(actionNames.has(retired), retired).toBe(false);
}
});
it("registers canonical owner-operation parents", () => {
const actionNames = new Set(
(personalAssistantPlugin.actions ?? []).map((a) => a.name),
);
const darwin = isDarwin();
for (const expected of CANONICAL_OWNER_PARENTS) {
if (!darwin && DARWIN_ONLY_PARENTS.has(expected)) continue;
expect(actionNames.has(expected), expected).toBe(true);
}
});
it("uses action as the public discriminator on canonical owner-operation parents", () => {
const actionNames = new Set(CANONICAL_OWNER_PARENTS);
const failures = (personalAssistantPlugin.actions ?? [])
.filter((action) =>
actionNames.has(
action.name as (typeof CANONICAL_OWNER_PARENTS)[number],
),
)
.filter((action) => {
const names = new Set(
(action.parameters ?? []).map((parameter) => parameter.name),
);
return names.has("subaction") && !names.has("action");
})
.map((action) => action.name);
expect(failures).toEqual([]);
});
it("routes work-thread Stage-1 behavior through threadOps field evaluator only", () => {
expect(
(personalAssistantPlugin.responseHandlerFieldEvaluators ?? []).map(
(evaluator) => evaluator.name,
),
).toContain("threadOps");
expect(
(personalAssistantPlugin.responseHandlerEvaluators ?? []).map(
(evaluator) => evaluator.name,
),
).not.toContain("lifeops.work_thread_router");
});
it("routes explicit pending-approval rejection phrasing to RESOLVE_REQUEST_REJECT", () => {
const registry = new ShortcutRegistry();
registry.registerMany(personalAssistantPlugin.shortcuts ?? []);
const actionNames = (personalAssistantPlugin.actions ?? []).map(
(action) => action.name,
);
const match = registry.match(
"Wait - which Chris? There are two. Don't send it, reject that for now until I confirm the right person.",
{
actions: actionNames,
allowNatural: true,
isElevated: true,
},
);
expect(match?.shortcut.id).toBe(APPROVAL_REJECT_SHORTCUT_ID);
expect(match?.shortcut.target).toEqual({
kind: "action",
name: "RESOLVE_REQUEST_REJECT",
});
const matchOwner = (text: string) =>
registry.match(text, {
actions: actionNames,
allowNatural: true,
isElevated: true,
});
for (const positive of [
"Don’t send it.",
"reject that for now",
"Decline the request.",
"deny the pending approval",
]) {
expect(matchOwner(positive)?.shortcut.id, positive).toBe(
APPROVAL_REJECT_SHORTCUT_ID,
);
}
// Rejection verbs aimed at other objects stay with the planner, which can
// weigh conversation context; a shortcut misfire terminally rejects a
// queued approval with zero inference.
for (const negative of [
"hold that for now",
"Decline the meeting request from Bob",
"Reject the draft and write a new one",
"deny his request for access",
]) {
expect(matchOwner(negative), negative).toBeNull();
}
expect(
registry.match("Don't send it, reject that request.", {
actions: actionNames,
allowNatural: true,
isElevated: false,
}),
).toBeNull();
});
});
// Live gemma-4-31b brush-teeth trajectory fences (#9950/#10722): the habit
// save flow only routes correctly when (1) each owner-life umbrella pins its
// backing kind (a planner-supplied kind:"goal" silently rerouted a habit into
// the goals store), (2) the umbrellas expose the `confirmed` preview->confirm
// handshake, and (3) SCHEDULED_TASKS de-claims new-habit creation so a
// habit-shaped ask reaches OWNER_ROUTINES/OWNER_REMINDERS instead of the raw
// scheduler surface. Evidence: test-results/evidence/
// 9950-gemma4-31b-live-trajectories/brush-teeth-basic-after-fix*.report.json.
describe("brush-teeth habit-save routing contract (#9950/#10722)", () => {
const findAction = (name: string) =>
(personalAssistantPlugin.actions ?? []).find(
(action) => action.name === name,
);
const PINNED_KINDS: Record<string, string> = {
OWNER_REMINDERS: "definition",
OWNER_ALARMS: "definition",
OWNER_TODOS: "definition",
OWNER_ROUTINES: "definition",
OWNER_GOALS: "goal",
};
it("pins each owner-life umbrella's kind parameter to its backing store", () => {
for (const [name, kind] of Object.entries(PINNED_KINDS)) {
const action = findAction(name);
expect(action, name).toBeDefined();
const kindParameter = (action?.parameters ?? []).find(
(parameter) => parameter.name === "kind",
);
expect(kindParameter, `${name} kind parameter`).toBeDefined();
const schema = kindParameter?.schema as {
enum?: string[];
default?: string;
};
expect(schema?.enum, `${name} kind enum`).toEqual([kind]);
expect(schema?.default, `${name} kind default`).toBe(kind);
}
});
it("exposes the create-only confirmed handshake on every owner-life umbrella", () => {
for (const name of Object.keys(PINNED_KINDS)) {
const action = findAction(name);
const confirmedParameter = (action?.parameters ?? []).find(
(parameter) => parameter.name === "confirmed",
);
expect(confirmedParameter, `${name} confirmed parameter`).toBeDefined();
expect(
(confirmedParameter?.schema as { type?: string })?.type,
`${name} confirmed type`,
).toBe("boolean");
}
});
it("claims habit phrasing on OWNER_ROUTINES and de-claims it on SCHEDULED_TASKS(+_CREATE)", () => {
const routines = findAction("OWNER_ROUTINES");
expect(routines?.description).toContain("habit");
expect(routines?.similes).toContain("CREATE_HABIT");
expect(routines?.similes).toContain("RECURRING_TASK");
const scheduledTasks = findAction("SCHEDULED_TASKS");
expect(scheduledTasks?.description).toContain("OWNER_ROUTINES");
expect(scheduledTasks?.routingHint).toContain("OWNER_ROUTINES");
const scheduledTasksCreate = findAction("SCHEDULED_TASKS_CREATE");
expect(
scheduledTasksCreate,
"SCHEDULED_TASKS_CREATE virtual",
).toBeDefined();
expect(scheduledTasksCreate?.description).toContain(
"OWNER_ROUTINES_CREATE",
);
});
it("claims one-off deadline reminders on OWNER_REMINDERS and de-claims them on SCHEDULED_TASKS", () => {
const reminders = findAction("OWNER_REMINDERS");
expect(reminders?.description).toContain("deadline");
expect(reminders?.description).toContain("by the 20th");
expect(reminders?.descriptionCompressed).toContain("deadlines");
const scheduledTasks = findAction("SCHEDULED_TASKS");
expect(scheduledTasks?.description).toContain(
"NOT the flow for saving a new owner reminder",
);
expect(scheduledTasks?.description).toContain("by the 20th");
expect(scheduledTasks?.routingHint).toContain(
"NEW owner reminders/deadlines",
);
expect(scheduledTasks?.routingHint).toContain(
"OWNER_REMINDERS action=create",
);
});
it("declares the productivity context on owner-life umbrellas (Stage-1 boost parity with SCHEDULED_TASKS)", () => {
for (const name of Object.keys(PINNED_KINDS)) {
const action = findAction(name);
expect(action?.contexts, `${name} contexts`).toContain("productivity");
}
});
});