Skip to content

Commit 388d04c

Browse files
fix: Non-editable link clicks opening duplicate tabs (#2667)
* Fixed clicking non-editable links opening 2 new tabs instead of 1 * fix: migrate MSW snapshot hashes after schema change to link HTML The link refactor changed the HTML representation of <a> tags by adding classname="bn-inline-content-section" data-inline-content-type="link" attributes. This changed the request bodies sent to LLM providers in tests, which broke the MD5 hash-based MSW snapshot filenames. Additionally, the test runtime now captures actual request headers (authorization, content-type, etc.) instead of empty arrays, further changing the hashes. 57 snapshot files were migrated (56 via script + 1 manual fix): - Old-hash files deleted, new-hash files created with the same valid 200 response bodies transplanted from the originals. ## How MSW Snapshot Hashing Works Each test records HTTP requests via msw-snapshot. The snapshot filename includes an MD5 hash computed from: [method, url.origin, url.pathname, sorted(searchParams), sorted(headers), body] See createRequestHash() in each test file (e.g. htmlBlocks.test.ts:22). The hash function is toHashString() from msw-snapshot, which does: crypto.createHash('md5').update(JSON.stringify(array), 'binary').digest('hex') ## How to Migrate Snapshots When Schema Changes When a code change alters the HTML/content sent to LLM providers, the request body changes, which changes the hash, which means snapshot files won't be found by filename. ### Step 1: Run the tests to create duplicate snapshots cd packages/xl-ai && npm run test Tests with hash mismatches will try to fetch from real servers (which will fail without API keys), creating NEW snapshot files with correct hashes but 401 error responses alongside the OLD files with valid 200 responses. The validateTestEnvironment test will report duplicates. ### Step 2: Identify duplicate pairs For each test directory under __msw_snapshots__/{provider}/{model}/, look for snapshot pairs with the same test name prefix but different hashes. The OLD file (valid 200 response, older mtime) needs its response transplanted into the NEW file (401 error, newer mtime). ### Step 3: Transplant responses For each duplicate pair: 1. Read the response body from the OLD file (status 200) 2. Write that response into the NEW file (replacing the 401 error) 3. Delete the OLD file This can be scripted in Python: import json, os, glob from collections import defaultdict base = 'packages/xl-ai/src/api/formats/html-blocks/__snapshots__' files = glob.glob(f'{base}/**/*.json', recursive=True) # Group by test name prefix (everything before the hash) groups = defaultdict(list) for f in files: name = os.path.basename(f) # Pattern: testname_N_hash.json prefix = '_'.join(name.rsplit('_', 1)[:-1]) groups[prefix].append(f) for prefix, paths in groups.items(): if len(paths) == 2: # Identify old (200) vs new (401) by checking response status for p in paths: data = json.load(open(p)) if data['response']['status'] == 200: old_file, old_data = p, data else: new_file = p # Transplant response new_data = json.load(open(new_file)) new_data['response'] = old_data['response'] json.dump(new_data, open(new_file, 'w'), indent=2) os.remove(old_file) ### Step 4: Handle edge cases Some tests may fail with 'TypeError: unusable' at Request.clone in msw-snapshot. This happens when a snapshot hash changed but the test crashes before creating a new file (no duplicate pair to migrate). To fix these: 1. Add debug logging in createSnapshotPath to print the computed hash 2. Run the failing test to get the new hash 3. Rename the old snapshot file to use the new hash 4. Remove the debug logging ### Step 5: Verify cd packages/xl-ai && npm run test All tests should pass and the duplicate validation test should be green. --------- Co-authored-by: Nick the Sick <computers@nickthesick.com>
1 parent e7ddc3c commit 388d04c

69 files changed

Lines changed: 1030 additions & 114 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

packages/core/src/extensions/tiptap-extensions/Link/helpers/clickHandler.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,11 @@ export function clickHandler(options: ClickHandlerOptions): Plugin {
2323

2424
let link: HTMLAnchorElement | null = null;
2525

26-
if (event.target instanceof HTMLAnchorElement) {
26+
if (
27+
event.target instanceof HTMLAnchorElement &&
28+
// Differentiate between link inline content and read-only links.
29+
event.target.getAttribute("data-inline-content-type") === "link"
30+
) {
2731
link = event.target;
2832
} else {
2933
const target = event.target as HTMLElement | null;
@@ -35,7 +39,9 @@ export function clickHandler(options: ClickHandlerOptions): Plugin {
3539

3640
// Intentionally limit the lookup to the editor root.
3741
// Using tag names like DIV as boundaries breaks with custom NodeViews,
38-
link = target.closest<HTMLAnchorElement>("a");
42+
link = target.closest<HTMLAnchorElement>(
43+
'a[data-inline-content-type="link"]',
44+
);
3945

4046
if (link && !root.contains(link)) {
4147
link = null;

packages/core/src/extensions/tiptap-extensions/Link/link.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ const DEFAULT_PROTOCOL = "https";
1212
const HTML_ATTRIBUTES = {
1313
target: "_blank",
1414
rel: "noopener noreferrer nofollow",
15+
className: "bn-inline-content-section",
16+
"data-inline-content-type": "link",
1517
};
1618

1719
// Pre-compiled regex for URI protocol validation.

packages/xl-ai/src/api/formats/html-blocks/__snapshots__/htmlBlocks.test.ts/Combined/__msw_snapshots__/anthropic.messages/claude-3-7-sonnet-latest (streaming)/add and update paragraph_1_380a0c02b5089b38247457135c044cf7.json renamed to packages/xl-ai/src/api/formats/html-blocks/__snapshots__/htmlBlocks.test.ts/Combined/__msw_snapshots__/anthropic.messages/claude-3-7-sonnet-latest (streaming)/add and update paragraph_1_801ad86e0c3a4562338793805e66a52f.json

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,29 @@
22
"request": {
33
"method": "POST",
44
"url": "https://api.anthropic.com/v1/messages",
5-
"body": "{\"model\":\"claude-3-7-sonnet-latest\",\"max_tokens\":64000,\"system\":[{\"type\":\"text\",\"text\":\"You're manipulating a text document using HTML blocks. \\nMake sure to follow the json schema provided. When referencing ids they MUST be EXACTLY the same (including the trailing $). \\nList items are 1 block with 1 list item each, so block content `<ul><li>item1</li></ul>` is valid, but `<ul><li>item1</li><li>item2</li></ul>` is invalid. We'll merge them automatically.\\nFor code blocks, you can use the `data-language` attribute on a <code> block (wrapped with <pre>) to specify the language.\\n\\nIf the user requests updates to the document, use the \\\"applyDocumentOperations\\\" tool to update the document.\\n---\\nIF there is no selection active in the latest state, first, determine what part of the document the user is talking about. You SHOULD probably take cursor info into account if needed.\\n EXAMPLE: if user says \\\"below\\\" (without pointing to a specific part of the document) he / she probably indicates the block(s) after the cursor. \\n EXAMPLE: If you want to insert content AT the cursor position (UNLESS indicated otherwise by the user), then you need `referenceId` to point to the block before the cursor with position `after` (or block below and `before`\\n---\\n \"}],\"messages\":[{\"role\":\"assistant\",\"content\":[{\"type\":\"text\",\"text\":\"There is no active selection. This is the latest state of the document (ignore previous documents, you MUST issue operations against this latest version of the document). \\nThe cursor is BETWEEN two blocks as indicated by cursor: true.\\nPrefer updating existing blocks over removing and adding (but this also depends on the user's question).\"},{\"type\":\"text\",\"text\":\"[{\\\"id\\\":\\\"ref1$\\\",\\\"block\\\":\\\"<p>Hello, world!</p>\\\"},{\\\"cursor\\\":true},{\\\"id\\\":\\\"ref2$\\\",\\\"block\\\":\\\"<p>Hello, <span data-inline-content-type=\\\\\\\"mention\\\\\\\" data-user=\\\\\\\"John Doe\\\\\\\">@John Doe</span>! <strong>How are you doing?</strong> <span style=\\\\\\\"color: rgb(11, 110, 153);\\\\\\\" data-style-type=\\\\\\\"textColor\\\\\\\" data-value=\\\\\\\"blue\\\\\\\" data-editable=\\\\\\\"\\\\\\\">This text is blue!</span></p>\\\"},{\\\"id\\\":\\\"ref3$\\\",\\\"block\\\":\\\"<p>Hello, world! <strong>Bold text. </strong><a target=\\\\\\\"_blank\\\\\\\" rel=\\\\\\\"noopener noreferrer nofollow\\\\\\\" href=\\\\\\\"https://www.google.com\\\\\\\">Link.</a></p>\\\"}]\"}]},{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"add a new paragraph with the text 'You look great today!' after the first paragraph and translate first 'Hello, world' to dutch\"}]}],\"tools\":[{\"name\":\"applyDocumentOperations\",\"input_schema\":{\"type\":\"object\",\"properties\":{\"operations\":{\"type\":\"array\",\"items\":{\"anyOf\":[{\"type\":\"object\",\"description\":\"Update a block\",\"properties\":{\"type\":{\"type\":\"string\",\"enum\":[\"update\"]},\"id\":{\"type\":\"string\",\"description\":\"id of block to update\"},\"block\":{\"type\":\"string\",\"description\":\"html of block (MUST be a single HTML element)\"}},\"required\":[\"type\",\"id\",\"block\"],\"additionalProperties\":false},{\"type\":\"object\",\"description\":\"Insert new blocks\",\"properties\":{\"type\":{\"type\":\"string\",\"enum\":[\"add\"]},\"referenceId\":{\"type\":\"string\",\"description\":\"MUST be an id of a block in the document\"},\"position\":{\"type\":\"string\",\"enum\":[\"before\",\"after\"],\"description\":\"`after` to add blocks AFTER (below) the block with `referenceId`, `before` to add the block BEFORE (above)\"},\"blocks\":{\"items\":{\"type\":\"string\",\"description\":\"html of block (MUST be a single, VALID HTML element)\"},\"type\":\"array\"}},\"required\":[\"type\",\"referenceId\",\"position\",\"blocks\"],\"additionalProperties\":false},{\"type\":\"object\",\"description\":\"Delete a block\",\"properties\":{\"type\":{\"type\":\"string\",\"enum\":[\"delete\"]},\"id\":{\"type\":\"string\",\"description\":\"id of block to delete\"}},\"required\":[\"type\",\"id\"],\"additionalProperties\":false}]}}},\"additionalProperties\":false,\"required\":[\"operations\"]}}],\"tool_choice\":{\"type\":\"any\"},\"stream\":true}",
6-
"headers": [],
5+
"body": "{\"model\":\"claude-3-7-sonnet-latest\",\"max_tokens\":64000,\"system\":[{\"type\":\"text\",\"text\":\"You're manipulating a text document using HTML blocks. \\nMake sure to follow the json schema provided. When referencing ids they MUST be EXACTLY the same (including the trailing $). \\nList items are 1 block with 1 list item each, so block content `<ul><li>item1</li></ul>` is valid, but `<ul><li>item1</li><li>item2</li></ul>` is invalid. We'll merge them automatically.\\nFor code blocks, you can use the `data-language` attribute on a <code> block (wrapped with <pre>) to specify the language.\\n\\nIf the user requests updates to the document, use the \\\"applyDocumentOperations\\\" tool to update the document.\\n---\\nIF there is no selection active in the latest state, first, determine what part of the document the user is talking about. You SHOULD probably take cursor info into account if needed.\\n EXAMPLE: if user says \\\"below\\\" (without pointing to a specific part of the document) he / she probably indicates the block(s) after the cursor. \\n EXAMPLE: If you want to insert content AT the cursor position (UNLESS indicated otherwise by the user), then you need `referenceId` to point to the block before the cursor with position `after` (or block below and `before`\\n---\\n \"}],\"messages\":[{\"role\":\"assistant\",\"content\":[{\"type\":\"text\",\"text\":\"There is no active selection. This is the latest state of the document (ignore previous documents, you MUST issue operations against this latest version of the document). \\nThe cursor is BETWEEN two blocks as indicated by cursor: true.\\nPrefer updating existing blocks over removing and adding (but this also depends on the user's question).\"},{\"type\":\"text\",\"text\":\"[{\\\"id\\\":\\\"ref1$\\\",\\\"block\\\":\\\"<p>Hello, world!</p>\\\"},{\\\"cursor\\\":true},{\\\"id\\\":\\\"ref2$\\\",\\\"block\\\":\\\"<p>Hello, <span data-inline-content-type=\\\\\\\"mention\\\\\\\" data-user=\\\\\\\"John Doe\\\\\\\">@John Doe</span>! <strong>How are you doing?</strong> <span style=\\\\\\\"color: rgb(11, 110, 153);\\\\\\\" data-style-type=\\\\\\\"textColor\\\\\\\" data-value=\\\\\\\"blue\\\\\\\" data-editable=\\\\\\\"\\\\\\\">This text is blue!</span></p>\\\"},{\\\"id\\\":\\\"ref3$\\\",\\\"block\\\":\\\"<p>Hello, world! <strong>Bold text. </strong><a target=\\\\\\\"_blank\\\\\\\" rel=\\\\\\\"noopener noreferrer nofollow\\\\\\\" classname=\\\\\\\"bn-inline-content-section\\\\\\\" data-inline-content-type=\\\\\\\"link\\\\\\\" href=\\\\\\\"https://www.google.com\\\\\\\">Link.</a></p>\\\"}]\"}]},{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"add a new paragraph with the text 'You look great today!' after the first paragraph and translate first 'Hello, world' to dutch\"}]}],\"tools\":[{\"name\":\"applyDocumentOperations\",\"input_schema\":{\"type\":\"object\",\"properties\":{\"operations\":{\"type\":\"array\",\"items\":{\"anyOf\":[{\"type\":\"object\",\"description\":\"Update a block\",\"properties\":{\"type\":{\"type\":\"string\",\"enum\":[\"update\"]},\"id\":{\"type\":\"string\",\"description\":\"id of block to update\"},\"block\":{\"type\":\"string\",\"description\":\"html of block (MUST be a single HTML element)\"}},\"required\":[\"type\",\"id\",\"block\"],\"additionalProperties\":false},{\"type\":\"object\",\"description\":\"Insert new blocks\",\"properties\":{\"type\":{\"type\":\"string\",\"enum\":[\"add\"]},\"referenceId\":{\"type\":\"string\",\"description\":\"MUST be an id of a block in the document\"},\"position\":{\"type\":\"string\",\"enum\":[\"before\",\"after\"],\"description\":\"`after` to add blocks AFTER (below) the block with `referenceId`, `before` to add the block BEFORE (above)\"},\"blocks\":{\"items\":{\"type\":\"string\",\"description\":\"html of block (MUST be a single, VALID HTML element)\"},\"type\":\"array\"}},\"required\":[\"type\",\"referenceId\",\"position\",\"blocks\"],\"additionalProperties\":false},{\"type\":\"object\",\"description\":\"Delete a block\",\"properties\":{\"type\":{\"type\":\"string\",\"enum\":[\"delete\"]},\"id\":{\"type\":\"string\",\"description\":\"id of block to delete\"}},\"required\":[\"type\",\"id\"],\"additionalProperties\":false}]}}},\"additionalProperties\":false,\"required\":[\"operations\"]}}],\"tool_choice\":{\"type\":\"any\"},\"stream\":true}",
6+
"headers": [
7+
[
8+
"anthropic-beta",
9+
"fine-grained-tool-streaming-2025-05-14"
10+
],
11+
[
12+
"anthropic-version",
13+
"2023-06-01"
14+
],
15+
[
16+
"content-type",
17+
"application/json"
18+
],
19+
[
20+
"user-agent",
21+
"ai-sdk/anthropic/3.0.2 ai-sdk/provider-utils/4.0.2 runtime/browser"
22+
],
23+
[
24+
"x-api-key",
25+
"not-available-in-ci"
26+
]
27+
],
728
"cookies": []
829
},
930
"response": {

packages/xl-ai/src/api/formats/html-blocks/__snapshots__/htmlBlocks.test.ts/Combined/__msw_snapshots__/anthropic.messages/claude-3-7-sonnet-latest (streaming)/add paragraph and update selection_1_298b51bb28c5f95ab9a00205d4e38460.json renamed to packages/xl-ai/src/api/formats/html-blocks/__snapshots__/htmlBlocks.test.ts/Combined/__msw_snapshots__/anthropic.messages/claude-3-7-sonnet-latest (streaming)/add paragraph and update selection_1_b6ecf36636295d284db3ba7243cd4835.json

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,29 @@
22
"request": {
33
"method": "POST",
44
"url": "https://api.anthropic.com/v1/messages",
5-
"body": "{\"model\":\"claude-3-7-sonnet-latest\",\"max_tokens\":64000,\"system\":[{\"type\":\"text\",\"text\":\"You're manipulating a text document using HTML blocks. \\nMake sure to follow the json schema provided. When referencing ids they MUST be EXACTLY the same (including the trailing $). \\nList items are 1 block with 1 list item each, so block content `<ul><li>item1</li></ul>` is valid, but `<ul><li>item1</li><li>item2</li></ul>` is invalid. We'll merge them automatically.\\nFor code blocks, you can use the `data-language` attribute on a <code> block (wrapped with <pre>) to specify the language.\\n\\nIf the user requests updates to the document, use the \\\"applyDocumentOperations\\\" tool to update the document.\\n---\\nIF there is no selection active in the latest state, first, determine what part of the document the user is talking about. You SHOULD probably take cursor info into account if needed.\\n EXAMPLE: if user says \\\"below\\\" (without pointing to a specific part of the document) he / she probably indicates the block(s) after the cursor. \\n EXAMPLE: If you want to insert content AT the cursor position (UNLESS indicated otherwise by the user), then you need `referenceId` to point to the block before the cursor with position `after` (or block below and `before`\\n---\\n \"}],\"messages\":[{\"role\":\"assistant\",\"content\":[{\"type\":\"text\",\"text\":\"This is the latest state of the selection (ignore previous selections, you MUST issue operations against this latest version of the selection):\"},{\"type\":\"text\",\"text\":\"[{\\\"id\\\":\\\"ref2$\\\",\\\"block\\\":\\\"<p>Hello,</p>\\\"}]\"},{\"type\":\"text\",\"text\":\"This is the latest state of the entire document (INCLUDING the selected text), \\nyou can use this to find the selected text to understand the context (but you MUST NOT issue operations against this document, you MUST issue operations against the selection):\"},{\"type\":\"text\",\"text\":\"[{\\\"block\\\":\\\"<p>Hello, world!</p>\\\"},{\\\"block\\\":\\\"<p>Hello, <span data-inline-content-type=\\\\\\\"mention\\\\\\\" data-user=\\\\\\\"John Doe\\\\\\\">@John Doe</span>! <strong>How are you doing?</strong> <span style=\\\\\\\"color: rgb(11, 110, 153);\\\\\\\" data-style-type=\\\\\\\"textColor\\\\\\\" data-value=\\\\\\\"blue\\\\\\\" data-editable=\\\\\\\"\\\\\\\">This text is blue!</span></p>\\\"},{\\\"block\\\":\\\"<p>Hello, world! <strong>Bold text. </strong><a target=\\\\\\\"_blank\\\\\\\" rel=\\\\\\\"noopener noreferrer nofollow\\\\\\\" href=\\\\\\\"https://www.google.com\\\\\\\">Link.</a></p>\\\"}]\"}]},{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"add a paragraph with the text 'You look great today!' before the selection and translate selection to German\"}]}],\"tools\":[{\"name\":\"applyDocumentOperations\",\"input_schema\":{\"type\":\"object\",\"properties\":{\"operations\":{\"type\":\"array\",\"items\":{\"anyOf\":[{\"type\":\"object\",\"description\":\"Update a block\",\"properties\":{\"type\":{\"type\":\"string\",\"enum\":[\"update\"]},\"id\":{\"type\":\"string\",\"description\":\"id of block to update\"},\"block\":{\"type\":\"string\",\"description\":\"html of block (MUST be a single HTML element)\"}},\"required\":[\"type\",\"id\",\"block\"],\"additionalProperties\":false},{\"type\":\"object\",\"description\":\"Insert new blocks\",\"properties\":{\"type\":{\"type\":\"string\",\"enum\":[\"add\"]},\"referenceId\":{\"type\":\"string\",\"description\":\"MUST be an id of a block in the document\"},\"position\":{\"type\":\"string\",\"enum\":[\"before\",\"after\"],\"description\":\"`after` to add blocks AFTER (below) the block with `referenceId`, `before` to add the block BEFORE (above)\"},\"blocks\":{\"items\":{\"type\":\"string\",\"description\":\"html of block (MUST be a single, VALID HTML element)\"},\"type\":\"array\"}},\"required\":[\"type\",\"referenceId\",\"position\",\"blocks\"],\"additionalProperties\":false},{\"type\":\"object\",\"description\":\"Delete a block\",\"properties\":{\"type\":{\"type\":\"string\",\"enum\":[\"delete\"]},\"id\":{\"type\":\"string\",\"description\":\"id of block to delete\"}},\"required\":[\"type\",\"id\"],\"additionalProperties\":false}]}}},\"additionalProperties\":false,\"required\":[\"operations\"]}}],\"tool_choice\":{\"type\":\"any\"},\"stream\":true}",
6-
"headers": [],
5+
"body": "{\"model\":\"claude-3-7-sonnet-latest\",\"max_tokens\":64000,\"system\":[{\"type\":\"text\",\"text\":\"You're manipulating a text document using HTML blocks. \\nMake sure to follow the json schema provided. When referencing ids they MUST be EXACTLY the same (including the trailing $). \\nList items are 1 block with 1 list item each, so block content `<ul><li>item1</li></ul>` is valid, but `<ul><li>item1</li><li>item2</li></ul>` is invalid. We'll merge them automatically.\\nFor code blocks, you can use the `data-language` attribute on a <code> block (wrapped with <pre>) to specify the language.\\n\\nIf the user requests updates to the document, use the \\\"applyDocumentOperations\\\" tool to update the document.\\n---\\nIF there is no selection active in the latest state, first, determine what part of the document the user is talking about. You SHOULD probably take cursor info into account if needed.\\n EXAMPLE: if user says \\\"below\\\" (without pointing to a specific part of the document) he / she probably indicates the block(s) after the cursor. \\n EXAMPLE: If you want to insert content AT the cursor position (UNLESS indicated otherwise by the user), then you need `referenceId` to point to the block before the cursor with position `after` (or block below and `before`\\n---\\n \"}],\"messages\":[{\"role\":\"assistant\",\"content\":[{\"type\":\"text\",\"text\":\"This is the latest state of the selection (ignore previous selections, you MUST issue operations against this latest version of the selection):\"},{\"type\":\"text\",\"text\":\"[{\\\"id\\\":\\\"ref2$\\\",\\\"block\\\":\\\"<p>Hello,</p>\\\"}]\"},{\"type\":\"text\",\"text\":\"This is the latest state of the entire document (INCLUDING the selected text), \\nyou can use this to find the selected text to understand the context (but you MUST NOT issue operations against this document, you MUST issue operations against the selection):\"},{\"type\":\"text\",\"text\":\"[{\\\"block\\\":\\\"<p>Hello, world!</p>\\\"},{\\\"block\\\":\\\"<p>Hello, <span data-inline-content-type=\\\\\\\"mention\\\\\\\" data-user=\\\\\\\"John Doe\\\\\\\">@John Doe</span>! <strong>How are you doing?</strong> <span style=\\\\\\\"color: rgb(11, 110, 153);\\\\\\\" data-style-type=\\\\\\\"textColor\\\\\\\" data-value=\\\\\\\"blue\\\\\\\" data-editable=\\\\\\\"\\\\\\\">This text is blue!</span></p>\\\"},{\\\"block\\\":\\\"<p>Hello, world! <strong>Bold text. </strong><a target=\\\\\\\"_blank\\\\\\\" rel=\\\\\\\"noopener noreferrer nofollow\\\\\\\" classname=\\\\\\\"bn-inline-content-section\\\\\\\" data-inline-content-type=\\\\\\\"link\\\\\\\" href=\\\\\\\"https://www.google.com\\\\\\\">Link.</a></p>\\\"}]\"}]},{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"add a paragraph with the text 'You look great today!' before the selection and translate selection to German\"}]}],\"tools\":[{\"name\":\"applyDocumentOperations\",\"input_schema\":{\"type\":\"object\",\"properties\":{\"operations\":{\"type\":\"array\",\"items\":{\"anyOf\":[{\"type\":\"object\",\"description\":\"Update a block\",\"properties\":{\"type\":{\"type\":\"string\",\"enum\":[\"update\"]},\"id\":{\"type\":\"string\",\"description\":\"id of block to update\"},\"block\":{\"type\":\"string\",\"description\":\"html of block (MUST be a single HTML element)\"}},\"required\":[\"type\",\"id\",\"block\"],\"additionalProperties\":false},{\"type\":\"object\",\"description\":\"Insert new blocks\",\"properties\":{\"type\":{\"type\":\"string\",\"enum\":[\"add\"]},\"referenceId\":{\"type\":\"string\",\"description\":\"MUST be an id of a block in the document\"},\"position\":{\"type\":\"string\",\"enum\":[\"before\",\"after\"],\"description\":\"`after` to add blocks AFTER (below) the block with `referenceId`, `before` to add the block BEFORE (above)\"},\"blocks\":{\"items\":{\"type\":\"string\",\"description\":\"html of block (MUST be a single, VALID HTML element)\"},\"type\":\"array\"}},\"required\":[\"type\",\"referenceId\",\"position\",\"blocks\"],\"additionalProperties\":false},{\"type\":\"object\",\"description\":\"Delete a block\",\"properties\":{\"type\":{\"type\":\"string\",\"enum\":[\"delete\"]},\"id\":{\"type\":\"string\",\"description\":\"id of block to delete\"}},\"required\":[\"type\",\"id\"],\"additionalProperties\":false}]}}},\"additionalProperties\":false,\"required\":[\"operations\"]}}],\"tool_choice\":{\"type\":\"any\"},\"stream\":true}",
6+
"headers": [
7+
[
8+
"anthropic-beta",
9+
"fine-grained-tool-streaming-2025-05-14"
10+
],
11+
[
12+
"anthropic-version",
13+
"2023-06-01"
14+
],
15+
[
16+
"content-type",
17+
"application/json"
18+
],
19+
[
20+
"user-agent",
21+
"ai-sdk/anthropic/3.0.2 ai-sdk/provider-utils/4.0.2 runtime/browser"
22+
],
23+
[
24+
"x-api-key",
25+
"not-available-in-ci"
26+
]
27+
],
728
"cookies": []
829
},
930
"response": {

0 commit comments

Comments
 (0)