// ── PAP Orchestrator ─────────────────────────────────────
@@ -223,7 +234,7 @@ fn GeneralTab() -> impl IntoView {
"STATUS"
- "ACTIVE"
+ {move || orch_status_text()}
"MANDATE TTL"
diff --git a/e2e/playwright.config.ts b/e2e/playwright.config.ts
index 68be6147..c62c5366 100644
--- a/e2e/playwright.config.ts
+++ b/e2e/playwright.config.ts
@@ -6,7 +6,10 @@ export default defineConfig({
testDir: "./tests",
// WASM compile+mount takes ~15ms; 60s covers slow CI runners.
timeout: 60_000,
- retries: 0,
+ retries: 1,
+ // Limit parallel workers in CI to reduce CPU contention from 8 concurrent
+ // WASM + Playwright instances (prevents typed-block render timeouts).
+ workers: isCI ? 4 : undefined,
expect: {
timeout: 30_000,
},
diff --git a/e2e/tests/agent-prompts.spec.ts b/e2e/tests/agent-prompts.spec.ts
index b8211bb7..a02b71dd 100644
--- a/e2e/tests/agent-prompts.spec.ts
+++ b/e2e/tests/agent-prompts.spec.ts
@@ -179,11 +179,11 @@ test.describe("LLM provider configuration", () => {
expect(saved.mandate_ttl_hours).toBe(24);
});
- test("settings UI General tab shows LLM provider select", async ({ page }) => {
+ test("settings UI General tab shows inference substrate select", async ({ page }) => {
await page.goto("/settings", { waitUntil: "commit" });
await waitForApp(page);
- await expect(page.locator("text=LLM Provider")).toBeVisible();
+ await expect(page.locator("text=INFERENCE_SUBSTRATE")).toBeVisible();
// First select on the page is the provider dropdown
await expect(page.locator("select").first()).toBeVisible();
});
@@ -209,7 +209,7 @@ async function submitAndAwaitTypedBlock(
page: import("@playwright/test").Page,
mockKeyword: string,
cssClass: string,
- timeout = 8000
+ timeout = 15000
): Promise {
// Navigate to canvas
await page.goto("/", { waitUntil: "commit" });
@@ -503,9 +503,9 @@ test.describe("Chrysalis federation commands", () => {
})
);
- // Local agents have explicit source fields (catalog, user_created)
+ // Local agents have explicit source fields (compiled, catalog, user_created)
for (const a of localAgents) {
- expect(["catalog", "user_created"]).toContain(a.source);
+ expect(["compiled", "catalog", "user_created"]).toContain(a.source);
}
// Remote agents from a registry are a separate list
@@ -690,7 +690,7 @@ test.describe("Canvas block lifecycle", () => {
await page.locator(".topbar-address-input").press("Enter");
// Eventually resolves (event fires after 200ms mock delay)
- await expect(page.locator(".typed-book").first()).toBeVisible({ timeout: 8000 });
+ await expect(page.locator(".typed-book").first()).toBeVisible({ timeout: 15000 });
// After resolution the block should NOT have the resolving class
const block = page.locator(".canvas-block").first();
@@ -702,7 +702,7 @@ test.describe("Canvas block lifecycle", () => {
await page.addInitScript(`
const origInvoke = window.__TAURI__.core.invoke;
window.__TAURI__.core.invoke = async function(cmd, args) {
- if (cmd === 'canvas_prompt') {
+ if (cmd === 'canvas_plan_prompt') {
const blockId = (args && (args.block_id || args.blockId)) || 'block-fail';
setTimeout(function() {
window.__TAURI__.event.emit('block_resolved', {
@@ -741,7 +741,7 @@ test.describe("Canvas block lifecycle", () => {
await page.addInitScript(`
const origInvoke = window.__TAURI__.core.invoke;
window.__TAURI__.core.invoke = async function(cmd, args) {
- if (cmd === 'canvas_prompt') {
+ if (cmd === 'canvas_plan_prompt') {
const blockId = (args && (args.block_id || args.blockId)) || 'block-ghost';
setTimeout(function() {
window.__TAURI__.event.emit('block_resolved', {
diff --git a/e2e/tests/agents.spec.ts b/e2e/tests/agents.spec.ts
index 433967f4..b745a15b 100644
--- a/e2e/tests/agents.spec.ts
+++ b/e2e/tests/agents.spec.ts
@@ -44,41 +44,41 @@ test.describe("Agent fleet page", () => {
test("active badge shows correct count", async ({ page }) => {
await page.goto("/fleet", { waitUntil: "commit" });
await waitForApp(page);
- // 2 catalog agents in mock → 2 ACTIVE
+ // 2 compiled agents in mock (Web Page Reader, On-Device AI) → 2 ACTIVE
const activeBadge = page.locator(".fleet-badge.active");
await expect(activeBadge).toBeVisible();
await expect(activeBadge).toContainText("2 ACTIVE");
});
- test("total badge shows all 3 agents", async ({ page }) => {
+ test("total badge shows all 5 agents", async ({ page }) => {
await page.goto("/fleet", { waitUntil: "commit" });
await waitForApp(page);
const totalBadge = page.locator(".fleet-badge.total");
await expect(totalBadge).toBeVisible();
- await expect(totalBadge).toContainText("3 TOTAL");
+ await expect(totalBadge).toContainText("5 TOTAL");
});
- test("renders 3 agent cards from list_local_agents", async ({ page }) => {
+ test("ACTIVE AGENTS section renders 2 compiled agent cards", async ({ page }) => {
await page.goto("/fleet", { waitUntil: "commit" });
await waitForApp(page);
- await expect(page.locator(".agent-card")).toHaveCount(3);
+ // Only compiled agents appear in the ACTIVE AGENTS grid
+ await expect(page.locator(".agent-card")).toHaveCount(2);
});
- test("first agent card shows DuckDuckGo Search", async ({ page }) => {
+ test("first agent card shows Web Page Reader (first compiled agent)", async ({ page }) => {
await page.goto("/fleet", { waitUntil: "commit" });
await waitForApp(page);
const firstCard = page.locator(".agent-card").first();
await expect(firstCard.locator(".agent-card-name")).toContainText(
- "DuckDuckGo Search"
+ "Web Page Reader"
);
});
- test("agent cards show source badges", async ({ page }) => {
+ test("agent cards show compiled source badges", async ({ page }) => {
await page.goto("/fleet", { waitUntil: "commit" });
await waitForApp(page);
- // Two catalog + one user_created
- await expect(page.locator(".agent-source-badge.catalog")).toHaveCount(2);
- await expect(page.locator(".agent-source-badge.user")).toHaveCount(1);
+ // Only compiled agents are shown in the ACTIVE AGENTS grid
+ await expect(page.locator(".agent-source-badge.compiled")).toHaveCount(2);
});
test("agent cards show truncated DID", async ({ page }) => {
@@ -98,7 +98,7 @@ test.describe("Agent fleet page", () => {
await waitForApp(page);
const firstCard = page.locator(".agent-card").first();
const actionStat = firstCard.locator(".agent-stat").nth(1);
- await expect(actionStat).toContainText("SearchAction");
+ await expect(actionStat).toContainText("ReadAction");
// Must NOT include raw "schema:" prefix
await expect(actionStat).not.toContainText("schema:");
});
@@ -119,7 +119,7 @@ test.describe("Agent fleet page", () => {
// ── Agent command round-trips ─────────────────────────────────
test.describe("Agent command round-trips", () => {
- test("list_local_agents returns 3 seeded agents with new fields", async ({
+ test("list_local_agents returns 5 seeded agents with new fields", async ({
page,
}) => {
await page.goto("/", { waitUntil: "commit" });
@@ -129,7 +129,8 @@ test.describe("Agent command round-trips", () => {
window.__TAURI__.core.invoke("list_local_agents")
);
- expect(agents).toHaveLength(3);
+ // 2 compiled + 2 catalog + 1 user_created = 5
+ expect(agents).toHaveLength(5);
// Every agent must have the new AgentInfo fields
for (const agent of agents) {
@@ -142,6 +143,7 @@ test.describe("Agent command round-trips", () => {
// Sources must be valid
const sources = agents.map((a: any) => a.source);
+ expect(sources).toContain("compiled");
expect(sources).toContain("catalog");
expect(sources).toContain("user_created");
});
@@ -176,7 +178,7 @@ test.describe("Agent command round-trips", () => {
const agents = await page.evaluate(() =>
window.__TAURI__.core.invoke("list_local_agents")
);
- expect(agents).toHaveLength(4);
+ expect(agents).toHaveLength(6); // 5 seeded + 1 new
expect(agents.find((a: any) => a.name === "Test Agent")).toBeDefined();
});
@@ -227,7 +229,7 @@ test.describe("Agent command round-trips", () => {
const after = await page.evaluate(() =>
window.__TAURI__.core.invoke("list_local_agents")
);
- expect(after).toHaveLength(2);
+ expect(after).toHaveLength(4); // 5 seeded - 1 deleted = 4
expect(after.find((a: any) => a.agent_did === custom.agent_did)).toBeUndefined();
});
diff --git a/e2e/tests/app.spec.ts b/e2e/tests/app.spec.ts
index 51888c90..3a09980a 100644
--- a/e2e/tests/app.spec.ts
+++ b/e2e/tests/app.spec.ts
@@ -49,15 +49,15 @@ test.describe("App shell", () => {
// ── Canvas Page (Home) ───────────────────────────────────────
test.describe("Canvas page", () => {
- test("shows empty state with inspiration lines on new canvas", async ({ page }) => {
+ test("shows empty state with agent tiles on new canvas", async ({ page }) => {
await page.goto("/", { waitUntil: "commit" });
await waitForApp(page);
- await expect(page.locator(".canvas-area")).toBeVisible();
+ await expect(page.locator(".canvas-stream")).toBeVisible();
// Seed canvas has blocks — create a new empty canvas via brand dropdown
await page.locator(".topbar-brand").click();
await page.locator("text=+ New Canvas").click();
- await expect(page.locator(".canvas-empty")).toBeVisible();
- await expect(page.locator(".inspiration-line").first()).toBeVisible();
+ await expect(page.locator(".canvas-empty-state")).toBeVisible();
+ await expect(page.locator(".agent-tile").first()).toBeVisible();
});
test("shows address bar prompt when orchestrator is ready", async ({ page }) => {
@@ -67,11 +67,12 @@ test.describe("Canvas page", () => {
await expect(page.locator(".topbar-address-input")).toBeVisible();
});
- test("address bar shows pap:// suggestion buttons", async ({ page }) => {
+ test("address bar shows pap:// suggestion buttons when typing pap://", async ({ page }) => {
await page.goto("/", { waitUntil: "commit" });
await waitForApp(page);
- await page.locator(".topbar-address-input").click();
- await expect(page.locator(".palette-suggestion").first()).toBeVisible();
+ // Suggestions appear only when user types "pap://" prefix
+ await page.locator(".topbar-address-input").fill("pap://");
+ await expect(page.locator(".palette-suggestion").first()).toBeVisible({ timeout: 10000 });
});
test("address bar input accepts text", async ({ page }) => {
@@ -79,11 +80,11 @@ test.describe("Canvas page", () => {
await waitForApp(page);
await page.locator(".topbar-address-input").fill("Search for flights");
await expect(page.locator(".topbar-address-input")).toHaveValue("Search for flights");
- // Suggestions should hide when input has text
+ // Suggestions should hide when input has non-pap:// text
await expect(page.locator(".palette-suggestion").first()).not.toBeVisible();
});
- test("shows setup prompt when orchestrator is disconnected", async ({ page }) => {
+ test("canvas renders normally when orchestrator is disconnected", async ({ page }) => {
// Override mock to return Disconnected status
await page.addInitScript(`
const origInvoke = window.__TAURI__.core.invoke;
@@ -94,12 +95,10 @@ test.describe("Canvas page", () => {
`);
await page.goto("/", { waitUntil: "commit" });
await waitForApp(page);
- // Seed canvas has blocks — create a new empty canvas to see the setup prompt
- await page.locator(".topbar-brand").click();
- await page.locator("text=+ New Canvas").click();
- await expect(page.locator(".canvas-prompt-setup")).toBeVisible();
- await expect(page.locator("text=Configure an LLM provider")).toBeVisible();
- await expect(page.locator("text=Open Settings")).toBeVisible();
+ // Canvas still renders — deterministic routing works without LLM
+ await expect(page.locator(".canvas-stream")).toBeVisible();
+ // Topbar address input is still available
+ await expect(page.locator(".topbar-address-input")).toBeVisible();
});
});
@@ -130,10 +129,10 @@ test.describe("Settings page", () => {
await expect(page.locator(".settings-tab").nth(5)).toHaveText("MANDATES");
});
- test("General tab shows LLM Provider config", async ({ page }) => {
+ test("General tab shows inference substrate config", async ({ page }) => {
await page.goto("/settings", { waitUntil: "commit" });
await waitForApp(page);
- await expect(page.locator("text=LLM Provider")).toBeVisible();
+ await expect(page.locator("text=INFERENCE_SUBSTRATE")).toBeVisible();
// Provider select is the first select on the page
await expect(page.locator("select").first()).toBeVisible();
});
@@ -218,7 +217,7 @@ test.describe("Settings page", () => {
await waitForApp(page);
// Start on General
- await expect(page.locator("text=LLM Provider")).toBeVisible();
+ await expect(page.locator("text=INFERENCE_SUBSTRATE")).toBeVisible();
// Switch to Identity
await page.locator(".settings-tab").nth(3).click();
diff --git a/e2e/tests/tauri-mock.ts b/e2e/tests/tauri-mock.ts
index 2ed0672c..7866966b 100644
--- a/e2e/tests/tauri-mock.ts
+++ b/e2e/tests/tauri-mock.ts
@@ -93,6 +93,34 @@ window.__TAURI__ = {
_mandates: {},
_orchestratorConfig: ${JSON.stringify(ORCHESTRATOR_CONFIG)},
_localAgents: [
+ {
+ name: 'Web Page Reader',
+ provider_name: 'Papillon',
+ provider_did: 'did:key:z6MkPap001',
+ capabilities: ['schema:ReadAction'],
+ object_types: ['WebPage'],
+ requires_disclosure: [],
+ returns: ['WebPage'],
+ endpoint: null,
+ content_hash: 'web-reader-hash',
+ agent_did: 'did:key:z6MkPapAgent001',
+ source: 'compiled',
+ published_to: [],
+ },
+ {
+ name: 'On-Device AI',
+ provider_name: 'Papillon',
+ provider_did: 'did:key:z6MkPap002',
+ capabilities: ['schema:AskAction'],
+ object_types: ['Answer'],
+ requires_disclosure: [],
+ returns: ['Answer'],
+ endpoint: null,
+ content_hash: 'on-device-ai-hash',
+ agent_did: 'did:key:z6MkPapAgent002',
+ source: 'compiled',
+ published_to: [],
+ },
{
name: 'DuckDuckGo Search',
provider_name: 'DuckDuckGo',
@@ -310,10 +338,11 @@ window.__TAURI__ = {
case 'list_agents':
// Registry browser — returns remote/federated agents
+ // live: true is required so build_catalog() indexes them for pap:// suggestions
return [
- { name: 'DuckDuckGo Search', provider_name: 'DuckDuckGo', provider_did: 'did:key:z6MkDDG', capabilities: ['schema:SearchAction'], object_types: ['SearchAction'], requires_disclosure: [], returns: ['results'], endpoint: null, content_hash: 'ddg-hash', agent_did: 'did:key:z6MkDDGFed', source: 'catalog', published_to: [] },
- { name: 'Wikipedia', provider_name: 'Wikimedia', provider_did: 'did:key:z6MkWiki', capabilities: ['schema:SearchAction'], object_types: ['SearchAction'], requires_disclosure: [], returns: ['article'], endpoint: null, content_hash: 'wiki-hash', agent_did: 'did:key:z6MkWikiFed', source: 'catalog', published_to: [] },
- { name: 'Mistral AI', provider_name: 'Mistral', provider_did: 'did:key:z6MkMistral', capabilities: ['schema:CreateAction'], object_types: ['InferenceAction'], requires_disclosure: [], returns: ['response'], endpoint: null, content_hash: 'mistral-hash', agent_did: 'did:key:z6MkMistralFed', source: 'catalog', published_to: [] },
+ { name: 'DuckDuckGo Search', provider_name: 'DuckDuckGo', provider_did: 'did:key:z6MkDDG', capabilities: ['schema:SearchAction'], object_types: ['SearchAction'], requires_disclosure: [], returns: ['results'], endpoint: null, content_hash: 'ddg-hash', agent_did: 'did:key:z6MkDDGFed', source: 'catalog', published_to: [], live: true },
+ { name: 'Wikipedia', provider_name: 'Wikimedia', provider_did: 'did:key:z6MkWiki', capabilities: ['schema:SearchAction'], object_types: ['SearchAction'], requires_disclosure: [], returns: ['article'], endpoint: null, content_hash: 'wiki-hash', agent_did: 'did:key:z6MkWikiFed', source: 'catalog', published_to: [], live: true },
+ { name: 'Mistral AI', provider_name: 'Mistral', provider_did: 'did:key:z6MkMistral', capabilities: ['schema:CreateAction'], object_types: ['InferenceAction'], requires_disclosure: [], returns: ['response'], endpoint: null, content_hash: 'mistral-hash', agent_did: 'did:key:z6MkMistralFed', source: 'catalog', published_to: [], live: true },
];
case 'list_local_agents':
@@ -432,7 +461,8 @@ window.__TAURI__ = {
prompt_id: (args && (args.prompt_id || args.promptId)) || 'p-mock',
state: 'Resolved',
schema_type: schemaType,
- content: { result: contentObj },
+ // Include receipt sentinel so render_typed_content unwraps 'result'
+ content: { result: contentObj, receipt: { status: 'ok', session: 'mock-session-001' } },
linked_block_ids: [],
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
@@ -814,6 +844,94 @@ window.__TAURI__ = {
return child;
}
+ // canvas_plan_prompt is the Tauri IPC entry point for the planning
+ // phase — same mock behaviour as canvas_prompt (emit block_resolved
+ // after a short delay so the Leptos UI can transition states).
+ case 'canvas_plan_prompt': {
+ const blockId = (args && (args.block_id || args.blockId)) || 'block-mock';
+ const promptText = ((args && args.text) || '').toLowerCase();
+ function typedBlock2(schemaType, contentObj) {
+ return {
+ id: blockId,
+ prompt_id: (args && (args.prompt_id || args.promptId)) || 'p-mock',
+ state: 'Resolved',
+ schema_type: schemaType,
+ // Include receipt sentinel so render_typed_content unwraps 'result'
+ content: { result: contentObj, receipt: { status: 'ok', session: 'mock-session-001' } },
+ linked_block_ids: [],
+ created_at: new Date().toISOString(),
+ updated_at: new Date().toISOString(),
+ };
+ }
+ var planBlock = null;
+ if (promptText.includes('mock:movie') || promptText.includes('__movie')) {
+ planBlock = typedBlock2('Movie', { name: 'Inception', datePublished: '2010', director: { name: 'Christopher Nolan' }, genre: 'Sci-Fi', aggregateRating: { ratingValue: '8.8' }, description: 'A mind-bending thriller.' });
+ } else if (promptText.includes('mock:tvseries') || promptText.includes('__tvseries')) {
+ planBlock = typedBlock2('TVSeries', { name: 'Breaking Bad', startDate: '2008', broadcastChannel: 'AMC', numberOfSeasons: '5', description: 'A chemistry teacher turns drug lord.' });
+ } else if (promptText.includes('mock:videogame') || promptText.includes('__videogame')) {
+ planBlock = typedBlock2('VideoGame', { name: 'The Legend of Zelda', genre: 'Adventure', gamePlatform: 'Nintendo Switch', author: { name: 'Nintendo' }, description: 'An epic adventure game.' });
+ } else if (promptText.includes('mock:musicrecording') || promptText.includes('__musicrecording')) {
+ planBlock = typedBlock2('MusicRecording', { name: 'Bohemian Rhapsody', byArtist: { name: 'Queen' }, inAlbum: { name: 'A Night at the Opera' }, duration: 'PT5M55S' });
+ } else if (promptText.includes('mock:musicgroup') || promptText.includes('__musicgroup')) {
+ planBlock = typedBlock2('MusicGroup', { name: 'The Beatles', genre: 'Rock', foundingDate: '1960', description: 'Legendary British rock band.' });
+ } else if (promptText.includes('mock:book') || promptText.includes('__book')) {
+ planBlock = typedBlock2('Book', { name: 'The Rust Programming Language', author: { name: 'Steve Klabnik' }, publisher: { name: 'No Starch Press' }, datePublished: '2019', isbn: '978-1593278281', description: 'The official Rust book.' });
+ } else if (promptText.includes('mock:newsarticle') || promptText.includes('__newsarticle')) {
+ planBlock = typedBlock2('NewsArticle', { headline: 'Rust Tops Developer Survey for 9th Year', publisher: { name: 'Stack Overflow' }, datePublished: '2024-06-01', description: 'Rust remains the most loved language.', url: 'https://survey.stackoverflow.co/2024' });
+ } else if (promptText.includes('mock:scholarlyarticle') || promptText.includes('__scholarlyarticle')) {
+ planBlock = typedBlock2('ScholarlyArticle', { name: 'Attention Is All You Need', author: [{ name: 'Vaswani et al.' }], isPartOf: 'NeurIPS 2017', datePublished: '2017', identifier: '10.5555/3295222.3295349', abstract: 'We propose the Transformer architecture.' });
+ } else if (promptText.includes('mock:person') || promptText.includes('__person')) {
+ planBlock = typedBlock2('Person', { name: 'Grace Hopper', jobTitle: 'Rear Admiral', affiliation: { name: 'US Navy' }, description: 'Pioneer of computer programming.', url: 'https://en.wikipedia.org/wiki/Grace_Hopper' });
+ } else if (promptText.includes('mock:organization') || promptText.includes('__organization')) {
+ planBlock = typedBlock2('Organization', { name: 'Mozilla Foundation', '@type': 'Organization', address: { addressLocality: 'San Francisco', addressCountry: 'US' }, description: 'Champions of the open web.', url: 'https://mozilla.org' });
+ } else if (promptText.includes('mock:weather') || promptText.includes('__weather')) {
+ planBlock = typedBlock2('WeatherForecast', { name: 'San Francisco', temperature: '65°F', description: 'Foggy with partial clearing', humidity: '78%', windSpeed: '15 mph' });
+ } else if (promptText.includes('mock:geocoords') || promptText.includes('__geocoords')) {
+ planBlock = typedBlock2('GeoCoordinates', { name: 'Eiffel Tower', latitude: 48.8584, longitude: 2.2945, elevation: '330m', address: 'Champ de Mars, Paris, France' });
+ } else if (promptText.includes('mock:product') || promptText.includes('__product')) {
+ planBlock = typedBlock2('Product', { name: 'Framework Laptop 16', brand: { name: 'Framework' }, offers: { price: '1049.00' }, aggregateRating: { ratingValue: '4.7' }, description: 'A modular, repairable laptop.' });
+ } else if (promptText.includes('mock:event') || promptText.includes('__event')) {
+ planBlock = typedBlock2('Event', { name: 'RustConf 2024', startDate: '2024-09-10', endDate: '2024-09-11', location: { name: 'Montreal, Canada' }, organizer: { name: 'Rust Foundation' }, description: 'Annual Rust programming conference.' });
+ } else if (promptText.includes('mock:sportsteam') || promptText.includes('__sportsteam')) {
+ planBlock = typedBlock2('SportsTeam', { name: 'World Cup Final 2026', homeTeam: { name: 'Spain' }, awayTeam: { name: 'Brazil' }, startDate: '2026-07-19', location: { name: 'MetLife Stadium, NJ' } });
+ } else if (promptText.includes('mock:course') || promptText.includes('__course')) {
+ planBlock = typedBlock2('Course', { name: 'CS50: Introduction to Computer Science', provider: { name: 'Harvard / edX' }, description: 'A broad introduction to computer science.', url: 'https://cs50.harvard.edu' });
+ } else if (promptText.includes('mock:nutrition') || promptText.includes('__nutrition')) {
+ planBlock = typedBlock2('NutritionInformation', { name: 'Avocado', servingSize: '100g', calories: '160', proteinContent: '2g', carbohydrateContent: '9g', fatContent: '15g' });
+ } else if (promptText.includes('mock:jobposting') || promptText.includes('__jobposting')) {
+ planBlock = typedBlock2('JobPosting', { title: 'Senior Rust Engineer', hiringOrganization: { name: 'Fastly' }, jobLocation: { address: { addressLocality: 'Remote' } }, datePosted: '2024-05-01', baseSalary: { value: { minValue: 180000, maxValue: 250000 } }, description: 'Build high-performance networking software.' });
+ } else if (promptText.includes('mock:visualartwork') || promptText.includes('__visualartwork')) {
+ planBlock = typedBlock2('VisualArtwork', { name: 'Starry Night', creator: { name: 'Vincent van Gogh' }, artMedium: 'Oil on canvas', dateCreated: '1889', locationCreated: { name: 'MoMA, New York' }, description: 'A swirling night sky over a village.' });
+ } else if (promptText.includes('mock:definedterm') || promptText.includes('__definedterm')) {
+ planBlock = typedBlock2('DefinedTerm', { name: 'monad', inDefinedTermSet: 'noun', description: 'A design pattern in functional programming representing computations as chains.' });
+ } else if (promptText.includes('mock:quotation') || promptText.includes('__quotation')) {
+ planBlock = typedBlock2('Quotation', { text: 'Programs must be written for people to read, and only incidentally for machines to execute.', spokenByCharacter: { name: 'Harold Abelson' }, citation: { name: 'SICP' } });
+ } else if (promptText.includes('mock:flightreservation') || promptText.includes('__flightreservation')) {
+ planBlock = typedBlock2('FlightReservation', { reservationNumber: 'PX-4892', underName: { name: 'Ada Lovelace' }, departureAirport: 'SFO', arrivalAirport: 'JFK', departureDate: '2026-06-01', departureTime: '09:15', arrivalTime: '17:45', airline: 'United', totalPrice: 382.00 });
+ } else if (promptText.includes('mock:hotel') || promptText.includes('__hotel')) {
+ planBlock = typedBlock2('LodgingReservation', { reservationNumber: 'H-78321', underName: { name: 'Grace Hopper' }, name: 'The Grand Pacific', checkinDate: '2026-07-10', checkoutDate: '2026-07-13', totalPrice: 540.00 });
+ } else {
+ planBlock = {
+ id: blockId,
+ prompt_id: (args && (args.prompt_id || args.promptId)) || 'p-mock',
+ state: 'Resolved',
+ schema_type: null,
+ content: { result: 'Here is your answer.' },
+ linked_block_ids: [],
+ created_at: new Date().toISOString(),
+ updated_at: new Date().toISOString(),
+ };
+ }
+ var resolvedPlanBlock = planBlock;
+ setTimeout(function() {
+ window.__TAURI__.event.emit('block_resolved', { block: resolvedPlanBlock });
+ }, 200);
+ return null;
+ }
+
+ case 'get_recovery_status':
+ return { has_recovery: false, guardian_count: 0, threshold: 0 };
+
default:
console.warn('[tauri-mock] unhandled command:', cmd);
return null;
diff --git a/e2e/tests/templates.spec.ts b/e2e/tests/templates.spec.ts
index fdf8cbd7..d91240d9 100644
--- a/e2e/tests/templates.spec.ts
+++ b/e2e/tests/templates.spec.ts
@@ -44,7 +44,8 @@ async function createTemplate(
config: string = VALID_CONFIG,
) {
await page.locator('input[placeholder*="Name"]').fill(name);
- await page.locator('input[placeholder*="Schema"]').fill(schemaType);
+ // SchemaTypeInput placeholder is "e.g. FlightReservation"
+ await page.locator('input[placeholder*="FlightReservation"]').fill(schemaType);
await page.locator("textarea").first().fill(config);
await page.locator('button:has-text("Create Template")').click();
// Wait for success message
@@ -180,7 +181,7 @@ test.describe("Templates", () => {
// Try to create with malformed JSON
const templateName = `BadJSON-${Date.now()}`;
await page.locator('input[placeholder*="Name"]').fill(templateName);
- await page.locator('input[placeholder*="Schema"]').fill("Recipe");
+ await page.locator('input[placeholder*="FlightReservation"]').fill("Recipe");
await page.locator("textarea").first().fill("{invalid json");
await page.locator('button:has-text("Create Template")').click();
@@ -195,7 +196,7 @@ test.describe("Templates", () => {
await goToTemplatesTab(page);
// Try to create with empty name — just fill schema and config
- await page.locator('input[placeholder*="Schema"]').fill("Recipe");
+ await page.locator('input[placeholder*="FlightReservation"]').fill("Recipe");
await page.locator("textarea").first().fill(VALID_CONFIG);
// Click Create and expect error