From 5f046fdfd8f685e3708b7570649787c9dcd27b18 Mon Sep 17 00:00:00 2001 From: Sawyer Date: Sun, 6 Sep 2026 09:05:38 -0700 Subject: [PATCH 1/3] Add tests for the Myra land path with no client-side title lookup Replace the by-title stub expectations in myra-workbench.test.ts and default-agent-workbench.test.ts with assertions that ensure() issues exactly the definition-keyed POST /workbenches create, with no kind=workbench or kind=chat list call in front of it. --- apps/web/src/myra-workbench.test.ts | 92 +------- .../src/default-agent-workbench.test.ts | 207 ++---------------- 2 files changed, 19 insertions(+), 280 deletions(-) diff --git a/apps/web/src/myra-workbench.test.ts b/apps/web/src/myra-workbench.test.ts index c42f4bdeb..c22a8b6f9 100644 --- a/apps/web/src/myra-workbench.test.ts +++ b/apps/web/src/myra-workbench.test.ts @@ -2,30 +2,13 @@ import { afterEach, describe, expect, test } from "bun:test"; import { ensureMyraWorkbench, - findMyraWorkbench, findMyraDefinition, isMyraWorkbenchId, - isMyraWorkbenchTitle, MYRA_WORKBENCH_TITLE, resetMyraWorkbenchCache, } from "./myra-workbench"; -import type { Workbench } from "@corbits/chat-ui"; import type { AgentDefinition } from "./agents-api"; -function workbench(partial: { - readonly id: string; - readonly title: string; - readonly kind?: string; -}): Workbench { - return { - id: partial.id, - title: partial.title, - kind: partial.kind ?? "workbench", - pinned: false, - participants: [], - }; -} - describe("myra-workbench helpers", () => { afterEach(() => { resetMyraWorkbenchCache(); @@ -39,29 +22,6 @@ describe("myra-workbench helpers", () => { test("MYRA_WORKBENCH_TITLE is Myra", () => { expect(MYRA_WORKBENCH_TITLE).toBe("Myra"); }); - - test("isMyraWorkbenchTitle is case-insensitive and trims", () => { - expect(isMyraWorkbenchTitle("Myra")).toBe(true); - expect(isMyraWorkbenchTitle(" myra ")).toBe(true); - expect(isMyraWorkbenchTitle("MYRA")).toBe(true); - expect(isMyraWorkbenchTitle("Myra chat")).toBe(false); - expect(isMyraWorkbenchTitle("Assistant")).toBe(false); - }); - - test("findMyraWorkbench returns the first Myra-titled row", () => { - const items = [ - workbench({ id: "a", title: "general" }), - workbench({ id: "b", title: "myra" }), - workbench({ id: "c", title: "Myra" }), - ]; - expect(findMyraWorkbench(items)?.id).toBe("b"); - }); - - test("findMyraWorkbench returns undefined when none match", () => { - expect( - findMyraWorkbench([workbench({ id: "a", title: "general" })]), - ).toBeUndefined(); - }); }); function definition(partial: { @@ -122,14 +82,8 @@ describe("ensureMyraWorkbench", () => { headers: { "content-type": "application/json" }, }); - test("creates a chat with Myra's definitionId when no Myra row exists", async () => { + test("lands on Myra by issuing exactly the definition-keyed create, with no list-by-title lookup", async () => { const calls = stubFetch((path) => { - if (path.endsWith("/chat/workbenches?kind=workbench")) { - return json({ items: [] }); - } - if (path.endsWith("/chat/workbenches?kind=chat")) { - return json({ items: [] }); - } if (path.includes("/workflows/definitions")) { return json({ data: [definition({ id: "def-assistant", name: "assistant" })], @@ -151,6 +105,10 @@ describe("ensureMyraWorkbench", () => { const result = await ensureMyraWorkbench("tnt_1"); expect(result).toEqual({ kind: "ready", workbenchId: "chat-1" }); + expect( + calls.some((call) => call.path.includes("kind=workbench")), + ).toBe(false); + expect(calls.some((call) => call.path.includes("kind=chat"))).toBe(false); const createCall = calls.find((call) => call.path.endsWith("/chat/workbenches"), ); @@ -164,48 +122,8 @@ describe("ensureMyraWorkbench", () => { expect(isMyraWorkbenchId("chat-1")).toBe(true); }); - test("converts a legacy workbench-kind Myra row carrying the agent into an auto-responding chat", async () => { - const legacyWire = { - id: "legacy-1", - title: "Myra", - kind: "workbench", - pinned: true, - participants: [{ address: "myra@wf_1.tnt_1", handle: "myra" }], - }; - const calls = stubFetch((path) => { - if (path.endsWith("/chat/workbenches?kind=workbench")) { - return json({ items: [legacyWire] }); - } - if (path.endsWith("/chat/workbenches?kind=chat")) { - return json({ items: [] }); - } - if (path.endsWith("/chat/workbenches/legacy-1/settings")) { - return json({ - ...legacyWire, - kind: "chat", - settings: { "chat/kind": "chat" }, - contextWindow: { value: 50, source: "inherit" }, - }); - } - throw new Error(`unexpected fetch: ${path}`); - }); - - const result = await ensureMyraWorkbench("tnt_1"); - - expect(result).toEqual({ kind: "ready", workbenchId: "legacy-1" }); - expect(isMyraWorkbenchId("legacy-1")).toBe(true); - const patchCall = calls.find((call) => call.init?.method === "PATCH"); - expect(JSON.parse(String(patchCall?.init?.body))).toEqual({ - "chat/kind": "chat", - }); - }); - test("errors when no Myra definition is deployed for the tenant", async () => { stubFetch((path) => { - if (path.endsWith("/chat/workbenches?kind=workbench")) - return json({ items: [] }); - if (path.endsWith("/chat/workbenches?kind=chat")) - return json({ items: [] }); if (path.includes("/workflows/definitions")) { return json({ data: [], nextCursor: null }); } diff --git a/packages/chat-ui/src/default-agent-workbench.test.ts b/packages/chat-ui/src/default-agent-workbench.test.ts index a2ebd8d90..bcacb1836 100644 --- a/packages/chat-ui/src/default-agent-workbench.test.ts +++ b/packages/chat-ui/src/default-agent-workbench.test.ts @@ -1,24 +1,6 @@ import { afterEach, describe, expect, test } from "bun:test"; -import { - createDefaultAgentWorkbench, - isWorkbenchTitleMatch, -} from "./default-agent-workbench"; -import type { Workbench } from "./api"; - -function workbench(partial: { - readonly id: string; - readonly title: string; - readonly kind?: string; -}): Workbench { - return { - id: partial.id, - title: partial.title, - kind: partial.kind ?? "workbench", - pinned: false, - participants: [], - }; -} +import { createDefaultAgentWorkbench } from "./default-agent-workbench"; type StubDefinition = { readonly id: string; readonly name: string }; @@ -26,16 +8,6 @@ function definition(id: string, name: string): StubDefinition { return { id, name }; } -describe("isWorkbenchTitleMatch", () => { - test("is case-insensitive and trims", () => { - expect(isWorkbenchTitleMatch("Myra", "Myra")).toBe(true); - expect(isWorkbenchTitleMatch(" myra ", "Myra")).toBe(true); - expect(isWorkbenchTitleMatch("MYRA", "Myra")).toBe(true); - expect(isWorkbenchTitleMatch("Myra chat", "Myra")).toBe(false); - expect(isWorkbenchTitleMatch("Assistant", "Myra")).toBe(false); - }); -}); - describe("createDefaultAgentWorkbench", () => { const realFetch = globalThis.fetch; @@ -71,32 +43,12 @@ describe("createDefaultAgentWorkbench", () => { expect(agent.isCachedWorkbenchId(null)).toBe(false); }); - test("findWorkbenchByTitle returns the first title match", () => { - const agent = createDefaultAgentWorkbench({ - title: "Myra", - assetName: "assistant", - }); - const items = [ - workbench({ id: "a", title: "general" }), - workbench({ id: "b", title: "myra" }), - workbench({ id: "c", title: "Myra" }), - ]; - expect(agent.findWorkbenchByTitle(items)?.id).toBe("b"); - expect( - agent.findWorkbenchByTitle([workbench({ id: "a", title: "general" })]), - ).toBeUndefined(); - }); - - test("creates a chat with the definitionId when no title match exists", async () => { + test("ensure issues exactly the definition-keyed create, with no list-by-title lookup", async () => { const agent = createDefaultAgentWorkbench({ title: "Myra", assetName: "assistant", }); const calls = stubFetch((path) => { - if (path.endsWith("/chat/workbenches?kind=workbench")) - return json({ items: [] }); - if (path.endsWith("/chat/workbenches?kind=chat")) - return json({ items: [] }); if (path.endsWith("/chat/workbenches")) { return json({ id: "chat-1", @@ -114,9 +66,9 @@ describe("createDefaultAgentWorkbench", () => { ]); expect(result).toEqual({ kind: "ready", workbenchId: "chat-1" }); - const createCall = calls.find((call) => - call.path.endsWith("/chat/workbenches"), - ); + expect(calls).toHaveLength(1); + const createCall = calls[0]; + expect(createCall?.path.endsWith("/chat/workbenches")).toBe(true); expect(createCall?.init?.method).toBe("POST"); expect(JSON.parse(String(createCall?.init?.body))).toEqual({ kind: "chat", @@ -127,131 +79,11 @@ describe("createDefaultAgentWorkbench", () => { expect(agent.isCachedWorkbenchId("chat-1")).toBe(true); }); - test("reuses an existing chat-kind title match without any settings write", async () => { - const agent = createDefaultAgentWorkbench({ - title: "Myra", - assetName: "assistant", - }); - const calls = stubFetch((path) => { - if (path.endsWith("/chat/workbenches?kind=workbench")) - return json({ items: [] }); - if (path.endsWith("/chat/workbenches?kind=chat")) { - return json({ - items: [ - { - id: "chat-1", - title: "Myra", - kind: "chat", - pinned: false, - participants: [{ address: "myra@wf_1.tnt_1", handle: "myra" }], - }, - ], - }); - } - throw new Error(`unexpected fetch: ${path}`); - }); - - const result = await agent.ensure("tnt_1", async () => []); - - expect(result).toEqual({ kind: "ready", workbenchId: "chat-1" }); - expect(agent.isCachedWorkbenchId("chat-1")).toBe(true); - expect(calls.some((call) => call.init?.method === "PATCH")).toBe(false); - }); - - test("converts a legacy workbench-kind match carrying the agent into a chat, so it auto-responds", async () => { - const agent = createDefaultAgentWorkbench({ - title: "Myra", - assetName: "assistant", - }); - const legacyWire = { - id: "legacy-1", - title: "Myra", - kind: "workbench", - pinned: true, - participants: [{ address: "myra@wf_1.tnt_1", handle: "myra" }], - }; - const calls = stubFetch((path) => { - if (path.endsWith("/chat/workbenches?kind=workbench")) - return json({ items: [legacyWire] }); - if (path.endsWith("/chat/workbenches?kind=chat")) - return json({ items: [] }); - if (path.endsWith("/chat/workbenches/legacy-1/settings")) { - return json({ - ...legacyWire, - kind: "chat", - settings: { "chat/kind": "chat" }, - contextWindow: { value: 50, source: "inherit" }, - }); - } - throw new Error(`unexpected fetch: ${path}`); - }); - - const result = await agent.ensure("tnt_1", async () => []); - - expect(result).toEqual({ kind: "ready", workbenchId: "legacy-1" }); - expect(agent.isCachedWorkbenchId("legacy-1")).toBe(true); - const patchCall = calls.find((call) => call.init?.method === "PATCH"); - expect( - patchCall?.path.endsWith("/chat/workbenches/legacy-1/settings"), - ).toBe(true); - expect(JSON.parse(String(patchCall?.init?.body))).toEqual({ - "chat/kind": "chat", - }); - }); - - test("ignores an agent-less legacy workbench-kind match and creates the real chat", async () => { - const agent = createDefaultAgentWorkbench({ - title: "Myra", - assetName: "assistant", - }); - const calls = stubFetch((path) => { - if (path.endsWith("/chat/workbenches?kind=workbench")) { - return json({ - items: [ - { - id: "husk-1", - title: "Myra", - kind: "workbench", - pinned: false, - participants: [{ address: "sawyer", handle: "sawyer" }], - }, - ], - }); - } - if (path.endsWith("/chat/workbenches?kind=chat")) - return json({ items: [] }); - if (path.endsWith("/chat/workbenches")) { - return json({ - id: "chat-2", - title: "Myra", - kind: "chat", - pinned: false, - participants: [], - }); - } - throw new Error(`unexpected fetch: ${path}`); - }); - - const result = await agent.ensure("tnt_1", async () => [ - definition("def-assistant", "assistant"), - ]); - - expect(result).toEqual({ kind: "ready", workbenchId: "chat-2" }); - expect(calls.some((call) => call.init?.method === "PATCH")).toBe(false); - }); - test("errors when no definition matches the configured asset name", async () => { const agent = createDefaultAgentWorkbench({ title: "Myra", assetName: "assistant", }); - stubFetch((path) => { - if (path.endsWith("/chat/workbenches?kind=workbench")) - return json({ items: [] }); - if (path.endsWith("/chat/workbenches?kind=chat")) - return json({ items: [] }); - throw new Error(`unexpected fetch: ${path}`); - }); const result = await agent.ensure("tnt_1", async () => [ definition("def-echo", "echo"), @@ -265,13 +97,6 @@ describe("createDefaultAgentWorkbench", () => { title: "Myra", assetName: undefined, }); - stubFetch((path) => { - if (path.endsWith("/chat/workbenches?kind=workbench")) - return json({ items: [] }); - if (path.endsWith("/chat/workbenches?kind=chat")) - return json({ items: [] }); - throw new Error(`unexpected fetch: ${path}`); - }); const result = await agent.ensure("tnt_1", async () => [ definition("def-echo", "echo"), @@ -286,25 +111,21 @@ describe("createDefaultAgentWorkbench", () => { assetName: "assistant", }); stubFetch((path) => { - if (path.endsWith("/chat/workbenches?kind=workbench")) - return json({ items: [] }); - if (path.endsWith("/chat/workbenches?kind=chat")) { + if (path.endsWith("/chat/workbenches")) { return json({ - items: [ - { - id: "chat-1", - title: "Myra", - kind: "chat", - pinned: false, - participants: [], - }, - ], + id: "chat-1", + title: "Myra", + kind: "chat", + pinned: false, + participants: [], }); } throw new Error(`unexpected fetch: ${path}`); }); - await agent.ensure("tnt_1", async () => []); + await agent.ensure("tnt_1", async () => [ + definition("def-assistant", "assistant"), + ]); expect(agent.isCachedWorkbenchId("chat-1")).toBe(true); agent.resetCache(); expect(agent.isCachedWorkbenchId("chat-1")).toBe(false); From 81c98324b539dd7c577ed78c4e880f274925953e Mon Sep 17 00:00:00 2001 From: Sawyer Date: Sun, 6 Sep 2026 09:05:44 -0700 Subject: [PATCH 2/3] Drop the client-side title pre-check in front of the Myra land create createDefaultAgentWorkbench used to list workbench and chat kinds and reuse a title match (plus convert a legacy workbench-kind row) before ever reaching the server's create. That duplicated the dedupe POST /workbenches already does by definitionId (findExistingAgentChat in packages/chat), and left two logics that could disagree. Delete the pre-check: the client always issues the definition-keyed create and trusts the server's find-or-reopen. Drops findWorkbenchByTitle, isWorkbenchTitleMatch, and apps/web's findMyraWorkbench/isMyraWorkbenchTitle, which existed only to serve that pre-check. --- apps/web/src/myra-workbench.ts | 21 +---- .../chat-ui/src/default-agent-workbench.ts | 93 +++---------------- packages/chat-ui/src/direct-workbench.ts | 7 +- packages/chat-ui/src/index.ts | 2 - 4 files changed, 20 insertions(+), 103 deletions(-) diff --git a/apps/web/src/myra-workbench.ts b/apps/web/src/myra-workbench.ts index 2e225b4df..608dacad9 100644 --- a/apps/web/src/myra-workbench.ts +++ b/apps/web/src/myra-workbench.ts @@ -5,10 +5,7 @@ import { createDefaultAgentWorkbench, - findWorkbenchByTitle, findDefinitionByAssetName, - isWorkbenchTitleMatch, - type Workbench, } from "@corbits/chat-ui"; import { WORKFLOW_CATALOG } from "@workbench/templates"; @@ -31,10 +28,6 @@ const myraWorkbench = createDefaultAgentWorkbench({ assetName: MYRA_ASSET_NAME, }); -export function isMyraWorkbenchTitle(title: string): boolean { - return isWorkbenchTitleMatch(title, MYRA_WORKBENCH_TITLE); -} - /** The last workbench id `ensureMyraWorkbench` resolved to, for the shell's * col2-wide derivation (CL-5936): "Myra is the active surface" reduces to * "the open workbench is the one Talk-to-Myra last landed us on". */ @@ -47,13 +40,6 @@ export function resetMyraWorkbenchCache(): void { myraWorkbench.resetCache(); } -/** Prefer an exact Myra title; first match wins across the given list. */ -export function findMyraWorkbench( - workbenches: readonly Workbench[], -): Workbench | undefined { - return findWorkbenchByTitle(workbenches, MYRA_WORKBENCH_TITLE); -} - /** Myra's deployed agent definition, matched by the seeded `assistant` * asset name — never by display name, which is a UI label, not a wire * identifier. */ @@ -64,10 +50,9 @@ export function findMyraDefinition( } /** - * List workbench + chat kinds, reuse a Myra-titled row if one exists — a - * legacy workbench-kind Myra from a bench seeded before CL-5985 included, so - * no bench ever ends up with two — otherwise create a 1:1 chat against - * Myra's deployed agent definition. + * Create (or reopen) the 1:1 chat against Myra's deployed agent definition — + * the server's `definitionId` dedupe on `POST /workbenches` is the one + * find-or-reopen path; this call always issues that create and trusts it. */ export function ensureMyraWorkbench(tenantId: string) { return myraWorkbench.ensure(tenantId, listAgentDefinitions); diff --git a/packages/chat-ui/src/default-agent-workbench.ts b/packages/chat-ui/src/default-agent-workbench.ts index 72d478f07..107ed7720 100644 --- a/packages/chat-ui/src/default-agent-workbench.ts +++ b/packages/chat-ui/src/default-agent-workbench.ts @@ -1,40 +1,20 @@ // Find-or-create a bench's 1:1 with a given deployed agent, generalizing -// `apps/web/src/myra-workbench.ts`'s original Myra-specific resolution: list -// workbench + chat kinds, reuse a chat-kind title match if one exists, -// otherwise create a chat against the agent's deployed definition. The -// agent's title and deployed asset name are config an app supplies — this -// module carries no product literal of its own. +// `apps/web/src/myra-workbench.ts`'s original Myra-specific resolution: this +// is the one deliberate find-or-create path in the product (CL-6089), the +// account's home-workbench land-hop (Myra), where landing twice must mean +// the same conversation, never two. Every other agent-chat creation — "+ New +// Workbench" picking an agent as a template, a freshly drafted agent's own +// launch — always mints a new workbench instead. // -// A legacy workbench-kind title match still carrying the agent is converted -// to a chat in place (one `chat/kind` settings patch): an agent chat must -// always auto-respond, and only `kind === "chat"` gets the unconditional -// fan-out in `sendWorkbenchMessage` — reusing the row as a workbench left the -// agent mention-gated and silent. A workbench-kind match with no agent -// participant is a husk that can't answer under either kind, so it is -// left alone and the real chat is created. -// -// This is the one deliberate find-or-create path in the product (CL-6089): -// the account's home-workbench land-hop (Myra), where landing twice must -// mean the same conversation, never two. Every other agent-chat creation -// — "+ New Workbench" picking an agent as a template, a freshly drafted -// agent's own launch — always mints a new workbench instead. The dedup -// here is `ensure`'s own title match above, not the server's -// `reuseExisting` flag on `POST /workbenches` (see `packages/chat/src/routes.ts` -// `findExistingAgentChat`): by the time `createWorkbench` below is reached, -// `ensure` has already exhausted its own by-title lookup and found no -// match, so a further server-side reuse pass here would only matter for -// a chat renamed away from the agent's title — an edge case this ticket -// leaves as-is rather than threading `reuseExisting` through here too. - -import { isAgentAddress } from "@corbits/chat/mentions"; +// The dedup is entirely the server's: `POST /workbenches` with `kind: "chat"` +// + `definitionId` find-or-reopens by definition (see +// `packages/chat/src/routes.ts` `findExistingAgentChat`), so this module +// issues that create unconditionally and trusts the response rather than +// pre-checking anything client-side. The agent's title and deployed asset +// name are config an app supplies — this module carries no product literal +// of its own. -import { - createWorkbench, - describeChatError, - listWorkbenches, - patchWorkbenchSettings, - type Workbench, -} from "./api"; +import { createWorkbench, describeChatError } from "./api"; export type DefaultAgentWorkbenchConfig = { readonly title: string; @@ -45,19 +25,6 @@ export type EnsureDefaultAgentWorkbenchResult = | { readonly kind: "ready"; readonly workbenchId: string } | { readonly kind: "error"; readonly message: string }; -export function isWorkbenchTitleMatch(title: string, target: string): boolean { - return title.trim().toLowerCase() === target.trim().toLowerCase(); -} - -export function findWorkbenchByTitle( - workbenches: readonly Workbench[], - title: string, -): Workbench | undefined { - return workbenches.find((workbench) => - isWorkbenchTitleMatch(workbench.title, title), - ); -} - /** An agent definition matched by its deployed asset name — never by * display name, which is a UI label, not a wire identifier. */ export function findDefinitionByAssetName( @@ -87,12 +54,6 @@ export function createDefaultAgentWorkbench( cachedWorkbenchId = null; } - function findByTitle( - workbenches: readonly Workbench[], - ): Workbench | undefined { - return findWorkbenchByTitle(workbenches, config.title); - } - async function ensure< D extends { readonly id: string; readonly name: string }, >( @@ -100,28 +61,6 @@ export function createDefaultAgentWorkbench( listDefinitions: (tenantId: string) => Promise, ): Promise { try { - const [workbenches, chats] = await Promise.all([ - listWorkbenches(tenantId, "workbench"), - listWorkbenches(tenantId, "chat"), - ]); - const existingChat = findByTitle(chats); - if (existingChat !== undefined) { - cachedWorkbenchId = existingChat.id; - return { kind: "ready", workbenchId: existingChat.id }; - } - const legacy = findByTitle(workbenches); - if ( - legacy !== undefined && - legacy.participants.some((participant) => - isAgentAddress(participant.address), - ) - ) { - await patchWorkbenchSettings(tenantId, legacy.id, { - "chat/kind": "chat", - }); - cachedWorkbenchId = legacy.id; - return { kind: "ready", workbenchId: legacy.id }; - } const definitions = await listDefinitions(tenantId); const definition = findDefinitionByAssetName( definitions, @@ -133,9 +72,6 @@ export function createDefaultAgentWorkbench( message: `No "${config.title}" agent found for this workbench.`, }; } - // The home workbench is the one deliberate reopen: the server's - // definitionId dedup catches it even after a rename, where this - // module's own title lookup above would miss and mint a second. const created = await createWorkbench(tenantId, { kind: "chat", definitionId: definition.id, @@ -156,7 +92,6 @@ export function createDefaultAgentWorkbench( ensure, isCachedWorkbenchId, resetCache, - findWorkbenchByTitle: findByTitle, }; } diff --git a/packages/chat-ui/src/direct-workbench.ts b/packages/chat-ui/src/direct-workbench.ts index b09a6417a..acd5ae067 100644 --- a/packages/chat-ui/src/direct-workbench.ts +++ b/packages/chat-ui/src/direct-workbench.ts @@ -1,8 +1,7 @@ // Finding an existing 1:1 by participant address — the read half of the -// "open-or-create" pattern the profile card's Message action needs (CL-5914), -// generalizing `apps/web/src/myra-workbench.ts`'s `findMyraWorkbench` from a -// title match to a participant match, since a profile subject is identified -// by address, not by a fixed workbench title. +// "open-or-create" pattern the profile card's Message action needs +// (CL-5914), matching by participant address since a profile subject is +// identified by address, not by a fixed workbench title. import type { Workbench } from "./api"; diff --git a/packages/chat-ui/src/index.ts b/packages/chat-ui/src/index.ts index 5d8426e03..8853a2eb3 100644 --- a/packages/chat-ui/src/index.ts +++ b/packages/chat-ui/src/index.ts @@ -242,9 +242,7 @@ export { findDirectWorkbenchWith } from "./direct-workbench"; export { createDefaultAgentWorkbench, - findWorkbenchByTitle, findDefinitionByAssetName, - isWorkbenchTitleMatch, } from "./default-agent-workbench"; export type { DefaultAgentWorkbench, From 305eaa12a020c54b030f3312486e6081cd880608 Mon Sep 17 00:00:00 2001 From: Sawyer Date: Sun, 6 Sep 2026 09:14:25 -0700 Subject: [PATCH 3/3] Format myra-workbench.test.ts to match prettier's line-wrap rules --- apps/web/src/myra-workbench.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/web/src/myra-workbench.test.ts b/apps/web/src/myra-workbench.test.ts index c22a8b6f9..2bbdfa53f 100644 --- a/apps/web/src/myra-workbench.test.ts +++ b/apps/web/src/myra-workbench.test.ts @@ -105,9 +105,9 @@ describe("ensureMyraWorkbench", () => { const result = await ensureMyraWorkbench("tnt_1"); expect(result).toEqual({ kind: "ready", workbenchId: "chat-1" }); - expect( - calls.some((call) => call.path.includes("kind=workbench")), - ).toBe(false); + expect(calls.some((call) => call.path.includes("kind=workbench"))).toBe( + false, + ); expect(calls.some((call) => call.path.includes("kind=chat"))).toBe(false); const createCall = calls.find((call) => call.path.endsWith("/chat/workbenches"),