@clidey/dory 0.12.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/docs/features.mdx CHANGED
@@ -1,440 +1,217 @@
1
1
  ---
2
- title: 'Features'
3
- description: 'Overview of available components and features'
2
+ title: "Conversational AI: Chatting with Your Documents"
3
+ description: "Enable interactive Q&A over your uploaded documents using the Morphik Agent and Console chat. This step-by-step guide shows how to setup, invoke, and optimize conversational workflows for research and support scenarios."
4
4
  ---
5
5
 
6
- ## Headings Examples
6
+ # Conversational AI: Chatting with Your Documents
7
7
 
8
- ```mdx
9
- # Heading 1
10
- ```
11
- # Heading 1
12
-
13
- ```mdx
14
- ## Heading 2
15
- ```
16
- # Heading 2
17
-
18
- ```mdx
19
- ### Heading 3
20
- ```
21
- # Heading 3
22
- ```mdx
23
- #### Heading 4
24
- ```
25
- # Heading 4
26
- ```mdx
27
- ##### Heading 5
28
- ```
29
- # Heading 5
30
- ```mdx
31
- ###### Heading 6
32
- ```
33
- # Heading 6
34
-
35
- <br />
36
-
37
- ## Lists Examples
38
-
39
- ```mdx
40
- - List item 1
41
- - List item 2
42
- - List item 3
43
- ```
44
-
45
- - List item 1
46
- - List item 2
47
- - List item 3
48
-
49
- ```mdx
50
- 1. List item 1
51
- 2. List item 2
52
- 3. List item 3
53
- ```
54
-
55
- 1. List item 1
56
- 2. List item 2
57
- 3. List item 3
8
+ Enable interactive Q&A over your uploaded documents using the Morphik Agent and Console chat. This step-by-step guide shows you how to set up, invoke, and optimize conversational workflows for research and support scenarios, empowering you to get precise, context-aware answers directly from your document collections.
58
9
 
10
+ ---
59
11
 
12
+ ## 1. Introduction
60
13
 
61
- <br />
14
+ Conversational AI with Morphik lets you transform your document repositories into intelligent, interactive knowledge assistants. By leveraging Morphik's agent framework and chat interface, you can ask natural language questions about your documents and receive accurate, sourced responses combining search, analysis, and knowledge graph insights.
62
15
 
63
- ### Images
16
+ This guide focuses specifically on the **chatting experience** — how to activate and use the Morphik Agent alongside the Morphik Console or SDK to carry contextual conversations grounded in your document data.
64
17
 
65
- ```mdx
66
- <img src="./assets/dory.jpeg" alt="Example image" className="object-cover w-64 h-64" />
67
- ```
18
+ ---
68
19
 
69
- <img src="./assets/dory.jpeg" alt="Example image" className="object-cover w-64 h-64" />
20
+ ## 2. Prerequisites
70
21
 
22
+ Before starting, ensure you have:
71
23
 
72
- <br />
73
- <br />
74
- <br />
24
+ - A running Morphik server instance (hosted or self-hosted).
25
+ - Documents uploaded to Morphik via the Console or SDK.
26
+ - The Morphik Agent enabled and configured (part of Morphik Core).
27
+ - Access to the Morphik Console for interactive chat or access to the Python SDK for programmatic use.
75
28
 
76
- ## Code Components
29
+ > <Check>
30
+ > Make sure your user account has permissions to query documents and knowledge graphs.
31
+ >
32
+ ---
77
33
 
78
- ### Code Block
79
- ```typescript
80
- function example() {
81
- return "Hello World";
82
- }
83
- ```
34
+ ## 3. Workflow Overview
84
35
 
85
- ### Code Group Block
36
+ ### What You Will Accomplish
86
37
 
87
- <CodeGroup>
88
- ```typescript
89
- function example(): string {
90
- return "Hello World";
91
- }
92
- ```
93
- ```javascript
94
- function example() {
95
- return "Hello World";
96
- }
97
- ```
98
- </CodeGroup>
38
+ - Set up Morphik Agent to interpret user queries.
39
+ - Use natural language to query documents interactively.
40
+ - Receive well-organized answers with clear source attributions.
41
+ - Understand how the agent leverages multiple tools for retrieval and analysis.
99
42
 
43
+ ### Time Estimate
100
44
 
101
- <br />
102
- <br />
103
- <br />
45
+ ~15–30 minutes to get a working chat interface and basic conversational flow.
104
46
 
47
+ ### Difficulty Level
105
48
 
106
- ## Interactive Components
49
+ Intermediate — some familiarity with Morphik platform and basic querying.
107
50
 
108
- ### Mermaid
51
+ ---
109
52
 
110
- ```mdx
111
- mermaid
112
- graph TD
53
+ ## 4. Setting Up Conversational AI
113
54
 
114
- %% Main Start
115
- Start([Start Process]) --> Validate[Validate Input]
55
+ ### Step 1: Confirm Documents Are Ingested
116
56
 
117
- %% Decision Point
118
- Validate -->|Valid| ProcessData{Is Data Clean?}
119
- Validate -->|Invalid| Error[Show Error Message]
57
+ You must have documents ingested into Morphik.
120
58
 
121
- %% Clean Data Branch
122
- ProcessData -->|Yes| Clean[Clean Data]
123
- Clean --> Analyze[Analyze Data]
59
+ - Use the Console to upload or verify documents.
60
+ - Or use the Python SDK `ingest_text()` or `ingest_file()` functions.
124
61
 
125
- %% Dirty Data Branch
126
- ProcessData -->|No| Notify[Notify User]
127
- Notify --> Wait[Wait for Input]
128
- Wait --> Validate
62
+ ### Step 2: Configure the Morphik Agent
129
63
 
130
- %% Parallel Branches After Analysis
131
- Analyze --> Split1 & Split2
64
+ The Morphik Agent acts as the orchestrator between user queries and Morphik's internal tools.
132
65
 
133
- subgraph Parallel Tasks
134
- Split1[Generate Report] --> Merge
135
- Split2[Update Dashboard] --> Merge
136
- end
66
+ - The agent uses a system prompt describing available tools like chunk retrieval, document analysis, knowledge graph queries, and code execution.
67
+ - It converts user input into function calls to relevant Morphik APIs.
137
68
 
138
- Merge --> Decision2{Is More Input Needed?}
139
- Decision2 -->|Yes| WaitMore[Wait for More Input]
140
- WaitMore --> Validate
141
- Decision2 -->|No| End([End Process])
69
+ Typical agent setup (embedded in Morphik Core):
142
70
 
143
- %% Style and Class Definitions
144
- classDef decision fill:#f9f,stroke:#333,stroke-width:2px;
145
- class ProcessData,Decision2 decision;
71
+ ```python
72
+ from core.agent import MorphikAgent
146
73
 
74
+ # Assume document_service is your Morphik document API client
75
+ agent = MorphikAgent(document_service=document_service, model="gpt-4") # or any supported model
147
76
  ```
148
77
 
149
- <strong>
150
- <p>Note: Mermaid should be inside a code block with type "mermaid"</p>
151
- </strong>
152
-
153
- ```mermaid
154
- graph TD
78
+ ### Step 3: Build a Chat Interface
155
79
 
156
- %% Main Start
157
- Start([Start Process]) --> Validate[Validate Input]
80
+ You can interact with the agent through several clients:
158
81
 
159
- %% Decision Point
160
- Validate -->|Valid| ProcessData{Is Data Clean?}
161
- Validate -->|Invalid| Error[Show Error Message]
82
+ - **Morphik Console Chat**: Web-based chat UI within the Morphik Console.
83
+ - **Python SDK**: Run queries programmatically by sending conversational history and user queries.
162
84
 
163
- %% Clean Data Branch
164
- ProcessData -->|Yes| Clean[Clean Data]
165
- Clean --> Analyze[Analyze Data]
85
+ Example: Basic agent run call from Python
166
86
 
167
- %% Dirty Data Branch
168
- ProcessData -->|No| Notify[Notify User]
169
- Notify --> Wait[Wait for Input]
170
- Wait --> Validate
87
+ ```python
88
+ import asyncio
171
89
 
172
- %% Parallel Branches After Analysis
173
- Analyze --> Split1 & Split2
174
-
175
- subgraph Parallel Tasks
176
- Split1[Generate Report] --> Merge
177
- Split2[Update Dashboard] --> Merge
178
- end
179
-
180
- Merge --> Decision2{Is More Input Needed?}
181
- Decision2 -->|Yes| WaitMore[Wait for More Input]
182
- WaitMore --> Validate
183
- Decision2 -->|No| End([End Process])
184
-
185
- %% Style and Class Definitions
186
- classDef decision fill:#f9f,stroke:#333,stroke-width:2px;
187
- class ProcessData,Decision2 decision;
90
+ async def chat(agent, user_query):
91
+ auth_context = ... # your auth context
92
+ response = await agent.run(query=user_query, auth=auth_context)
93
+ print(response["response"])
188
94
 
95
+ asyncio.run(chat(agent, "What is reinforcement learning?"))
189
96
  ```
190
97
 
191
- ### Accordion
98
+ > <Tip>
99
+ > The agent requires an authenticated user context (`auth`) to respect data access control.
100
+ >
101
+ ### Step 4: Execute Conversational Queries
192
102
 
193
- ```mdx
194
- <AccordionGroup>
195
- <Accordion title="First Section" icon="DocumentIcon">
196
- This is the content of the first accordion section.
197
- </Accordion>
198
- <Accordion title="Second Section" icon="CodeBracketIcon">
199
- This is the content of the second accordion section.
200
- </Accordion>
201
- </AccordionGroup>
202
- ```
103
+ With the agent configured and interface in place, you can ask questions like:
203
104
 
204
- <AccordionGroup>
205
- <Accordion title="First Section" icon="DocumentIcon">
206
- This is the content of the first accordion section.
207
- </Accordion>
208
- <Accordion title="Second Section" icon="CodeBracketIcon">
209
- This is the content of the second accordion section.
210
- </Accordion>
211
- </AccordionGroup>
105
+ - "Summarize the key points in the document about AI."
106
+ - "Show me diagrams related to reinforcement learning."
107
+ - "What entities appear in the contract documents?"
212
108
 
213
- ### Callouts
109
+ The agent breaks these queries into tool calls behind the scenes and constructs rich, sourced responses.
214
110
 
215
- ```mdx
216
- <Note>
217
- This is a note callout with important information.
218
- </Note>
219
- ```
111
+ ---
220
112
 
221
- <Note>
222
- This is a note callout with important information.
223
- </Note>
113
+ ## 5. How the Morphik Agent Works Behind the Scenes
224
114
 
225
- ```mdx
226
- <Warning>
227
- This is a warning callout for critical information.
228
- </Warning>
229
- ```
115
+ The Morphik Agent integrates several internal tools to answer user questions effectively:
230
116
 
231
- <Warning>
232
- This is a warning callout for critical information.
233
- </Warning>
117
+ - **`retrieve_chunks`**: Finds the most relevant text and image fragments from indexed documents.
118
+ - **`retrieve_document`**: Accesses full documents or metadata by ID.
119
+ - **`document_analyzer`**: Extracts entities, facts, sentiment, and summaries.
120
+ - **`knowledge_graph_query`**: Navigates entities and relationships in knowledge graphs.
121
+ - **Other tools** like code execution and persistent memory saving.
234
122
 
235
- ```mdx
236
- <Info>
237
- This is an info callout for general information.
238
- </Info>
239
- ```
123
+ The agent dynamically decides which APIs to invoke based on the query context.
240
124
 
241
- <Info>
242
- This is an info callout for general information.
243
- </Info>
125
+ ---
244
126
 
245
- ```mdx
246
- <Tip>
247
- This is a tip callout for helpful suggestions.
248
- </Tip>
249
- ```
127
+ ## 6. Best Practices & Tips
250
128
 
251
- <Tip>
252
- This is a tip callout for helpful suggestions.
253
- </Tip>
129
+ - **Scope Your Queries**: Use filters like folder name or user ID to limit results and speed up responses.
130
+ - **Use Multi-Turn Conversations**: Provide context from earlier messages to get more precise answers.
131
+ - **Attribute Your Sources**: The agent returns source references for transparent answers.
132
+ - **Monitor Token Limits**: Be mindful of model token constraints; truncate or segment documents if needed.
133
+ - **Keep Your Documents Up to Date**: Re-ingest changed documents so retrieval returns current info.
254
134
 
255
- ```mdx
256
- <Check>
257
- This is a check callout for completed items.
258
- </Check>
259
- ```
135
+ ---
260
136
 
261
- <Check>
262
- This is a check callout for completed items.
263
- </Check>
264
-
265
-
266
- <br />
267
-
268
- ### Cards
269
- ```mdx
270
- <CardGroup cols={2}>
271
- <Card
272
- title="Example Card"
273
- description="This is an example card component with an icon and title."
274
- icon="FileText"
275
- href="#"
276
- />
277
- <Card
278
- title="Another Card"
279
- description="This is another example card with different content."
280
- icon="Code"
281
- href="#"
282
- />
283
- </CardGroup>
284
- ```
137
+ ## 7. Troubleshooting Common Issues
138
+
139
+ <AccordionGroup title="Troubleshooting Conversational AI">
140
+ <Accordion title="Agent Returns No or Irrelevant Results">
141
+ - Verify your documents are indexed and visible to your user.
142
+ - Check query filters and ensure they match existing document metadata.
143
+ - Increase the number of chunks retrieved to widen the search scope.
144
+ </Accordion>
145
+ <Accordion title="Agent Fails or Crashes During Execution">
146
+ - Confirm your Morphik service is running with adequate resources.
147
+ - Check logs for errors related to tool invocation or model loading.
148
+ - Validate your authentication token or context is correct.
149
+ - Check model supported in your configuration (e.g. GPT-4).
150
+ </Accordion>
151
+ <Accordion title="Sources or Citations Are Missing in Responses">
152
+ - Ensure your documents contain proper metadata with chunks.
153
+ - Confirm the agent is using the correct source map.
154
+ - Verify that retrieval calls return source IDs.
155
+ </Accordion>
156
+ </AccordionGroup>
285
157
 
286
- <CardGroup cols={2}>
287
- <Card
288
- title="Example Card"
289
- description="This is an example card component with an icon and title."
290
- icon="FileText"
291
- href="#"
292
- />
293
- <Card
294
- title="Another Card"
295
- description="This is another example card with different content."
296
- icon="Code"
297
- href="#"
298
- />
299
- </CardGroup>
300
-
301
- <br />
302
-
303
- ### Expandable
304
-
305
- ```mdx
306
- <Expandable title="Click to Expand">
307
- This is an expandable section that can be toggled.
308
- </Expandable>
309
- ```
158
+ ---
310
159
 
311
- <Expandable title="Click to Expand">
312
- This is an expandable section that can be toggled.
313
- </Expandable>
160
+ ## 8. Example: Interactive Chat with Morphik Console
314
161
 
315
- ### Source
162
+ 1. Open the Morphik Console in your browser.
163
+ 2. Navigate to the 'Chat' tab.
164
+ 3. Enter the query:
316
165
 
317
- ```mdx
318
- <Source url="https://github.com/clidey/dory" paths={[
319
- { path: "src/mdx/source.tsx", range: "1-46" },
320
- { path: "docs/features.mdx", range: "318-322" },
321
- ]} />
166
+ ```text
167
+ What does the document say about reinforcement learning?
322
168
  ```
323
169
 
324
- <Source url="https://github.com/clidey/dory" paths={[
325
- { path: "src/mdx/source.tsx", range: "1-46" },
326
- { path: "docs/features.mdx", range: "318-322" },
327
- ]} />
328
-
329
- <br />
330
- <br />
331
- <br />
332
-
170
+ 4. The chat will return a detailed answer with markdown formatting and source attributions.
171
+ 5. Explore linked entities or images directly within the chat where available.
333
172
 
334
- ## Special Components
335
-
336
- ### Grids
337
-
338
- #### Rows
339
- ```mdx
340
- <Row cols={2}>
341
- <Icon icon="FileText" />
342
- <Icon icon="CheckCircle" />
343
- </Row>
344
- ```
173
+ ---
345
174
 
346
- <Row cols={2}>
347
- <Icon icon="FileText" />
348
- <Icon icon="CheckCircle" />
349
- </Row>
175
+ ## 9. Example: Python SDK Conversational Query
350
176
 
351
- <br />
177
+ ```python
178
+ from morphik import Morphik
352
179
 
353
- #### Columns
180
+ morphik = Morphik("morphik://user:token@api.morphik.ai")
354
181
 
355
- ```mdx
356
- <Col>
357
- <Icon icon="FileText" />
358
- <Icon icon="FileText" />
359
- </Col>
182
+ response = morphik.query("Explain the advantage of Retrieval Augmented Generation.")
183
+ print(response.completion)
360
184
  ```
361
185
 
362
- <Col>
363
- <Icon icon="FileText" />
364
- <Icon icon="FileText" />
365
- </Col>
366
-
367
- <br />
368
- <br />
369
- <br />
370
-
371
- ### Latex
372
-
373
- ```mdx
374
- <Latex>
375
- E = mc^2
376
- </Latex>
377
- ```
186
+ This sends a natural language query routed to the Morphik Agent that returns composed answers referencing documents.
378
187
 
379
- <Latex>
380
- E = mc^2
381
- </Latex>
188
+ ---
382
189
 
383
- <br />
384
- <br />
385
- <br />
190
+ ## 10. Next Steps & Further Reading
386
191
 
387
- ### Tables
192
+ - Explore [Multimodal Search & Retrieval guide](/guides/core-workflows/multimodal-search) to understand how retrieval integrates with chat.
193
+ - Learn about [Building Knowledge Graphs](/guides/knowledge-graphs/build-knowledge-graph) to enhance entity-level understanding.
194
+ - Review [Cache-Augmented Generation](/guides/integrations-and-caching/cache-augmentation) to accelerate response times via document caching.
195
+ - Deep dive into Morphik Console features in [Using the Morphik Console](/getting-started/first-steps-and-validation/using-the-morphik-console).
196
+ - Consult the [Agent code & tools description](/core/agent.py) for advanced customization.
388
197
 
389
- ```mdx
390
- | Property | Description |
391
- | -------- | ------------------------------------- |
392
- | Name | Full name of user |
393
- | Age | Reported age |
394
- | Joined | Whether the user joined the community |
395
- ```
198
+ ---
396
199
 
397
- | Property | Description |
398
- | -------- | ------------------------------------- |
399
- | Name | Full name of user |
400
- | Age | Reported age |
401
- | Joined | Whether the user joined the community |
200
+ ## 11. Summary
402
201
 
202
+ By following this guide, you will have enabled a robust conversational AI interface backed by Morphik’s multimodal document understanding and knowledge graph capabilities. This conversational workflow transforms your static documents into interactive assistants that can support research, customer support, and knowledge discovery efficiently.
403
203
 
404
- ### Steps
204
+ ---
405
205
 
406
- ```mdx
407
- <Steps>
408
- <Step title="First Step">
409
- This is the first step in the process.
410
- </Step>
411
- <Step title="Second Step">
412
- This is the second step in the process.
413
- </Step>
414
- </Steps>
415
- ```
206
+ ## References and Links
416
207
 
417
- <Steps>
418
- <Step title="First Step">
419
- This is the first step in the process.
420
- </Step>
421
- <Step title="Second Step">
422
- This is the second step in the process.
423
- </Step>
424
- </Steps>
425
-
426
- ### Icons
427
-
428
- ```mdx
429
- <Col rows={2}>
430
- <Icon icon="Code" />
431
- <Icon icon="FileText" />
432
- <Icon icon="CheckCircle" />
433
- </Col>
434
- ```
208
+ - [Morphik Console Guide](https://morphik.ai/docs/getting-started/first-steps-and-validation/using-the-morphik-console)
209
+ - [Morphik Python SDK](https://morphik.ai/docs/sdks/python/README)
210
+ - [Multimodal Search Guide](https://morphik.ai/docs/guides/core-workflows/multimodal-search)
211
+ - [Knowledge Graph Guide](https://morphik.ai/docs/guides/knowledge-graphs/build-knowledge-graph)
212
+ - [Cache Augmented Generation Guide](https://morphik.ai/docs/guides/integrations-and-caching/cache-augmentation)
213
+ - [Morphik Agent Source Code](https://github.com/morphik-org/morphik-core/blob/main/core/agent.py)
435
214
 
436
- <Row cols={3}>
437
- <Icon icon="Code" />
438
- <Icon icon="FileText" />
439
- <Icon icon="CheckCircle" />
440
- </Row>
215
+ <Tip>
216
+ Engage with the Morphik Discord community for live support and tips on using conversational AI effectively.
217
+ </Tip>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@clidey/dory",
3
3
  "private": false,
4
- "version": "0.12.0",
4
+ "version": "0.14.0",
5
5
  "type": "module",
6
6
  "description": "A CLI tool for building and previewing documentation sites",
7
7
  "keywords": [
@@ -1,10 +1,10 @@
1
1
  import { visit } from 'unist-util-visit';
2
2
 
3
+ // This plugin replaces mdxTextExpression nodes with inlineCode for safety.
3
4
  export const remarkSafeVars = () => {
4
5
  return (tree: any) => {
5
6
  visit(tree, 'mdxTextExpression', (node: any, index: number | undefined, parent: any) => {
6
7
  if (parent && typeof index === 'number') {
7
- // Replace mdxTextExpression with inlineCode node for code formatting
8
8
  parent.children[index] = {
9
9
  type: 'inlineCode',
10
10
  value: node.value
@@ -33,6 +33,46 @@ const KNOWN_COMPONENTS = [
33
33
  'address', 'cite', 'q', 'dfn'
34
34
  ];
35
35
 
36
+ // Helper: returns true if the given code string is inside a code block (```)
37
+ function isInsideCodeBlock(code: string, idx: number): boolean {
38
+ // Count the number of ``` before idx
39
+ const before = code.slice(0, idx);
40
+ const codeBlockMatches = before.match(/```/g);
41
+ // Odd number of ``` means inside a code block
42
+ return codeBlockMatches ? codeBlockMatches.length % 2 === 1 : false;
43
+ }
44
+
45
+ // Helper: checks if a known component tag has a matching closing tag
46
+ function hasMatchingClosingTag(code: string, tagName: string, openingTagOffset: number): boolean {
47
+ // Simple approach: look for the next occurrence of either an opening or closing tag of the same type
48
+ const afterOpening = code.slice(openingTagOffset + `<${tagName}>`.length);
49
+
50
+ // Find the first occurrence of either opening or closing tag
51
+ const nextOpeningMatch = afterOpening.match(new RegExp(`<${tagName}>`, 'i'));
52
+ const nextClosingMatch = afterOpening.match(new RegExp(`</${tagName}>`, 'i'));
53
+
54
+ // If no closing tag found at all
55
+ if (!nextClosingMatch) {
56
+ return false;
57
+ }
58
+
59
+ const nextOpeningIndex = nextOpeningMatch ? nextOpeningMatch.index! : Infinity;
60
+ const nextClosingIndex = nextClosingMatch ? nextClosingMatch.index! : Infinity;
61
+
62
+ // If the closing tag comes before any other opening tag, this tag is properly closed
63
+ if (nextClosingIndex < nextOpeningIndex) {
64
+ // Check if the closing tag is inside a code block
65
+ const closingTagOffset = openingTagOffset + `<${tagName}>`.length + nextClosingIndex;
66
+ if (isInsideCodeBlock(code, closingTagOffset)) {
67
+ return false;
68
+ }
69
+ return true;
70
+ }
71
+
72
+ return false; // Another opening tag comes before the closing tag, so this one is not properly closed
73
+ }
74
+
75
+ // Allow any <[a-z][a-z0-9]*> tag inside code blocks to be left as-is (not parsed as JSX).
36
76
  export function preprocessMdxTags() {
37
77
  return {
38
78
  name: 'preprocess-mdx-tags',
@@ -43,10 +83,36 @@ export function preprocessMdxTags() {
43
83
  // Remove leading whitespace from code fence blocks
44
84
  let processed = code.replace(/^(\s+)(```\w*)/gm, '$2');
45
85
 
46
- // Replace unrecognized <someTag> with `"<someTag>"`
47
- processed = processed.replace(/<([a-z][a-z0-9]+)>/gi, (match, tag) => {
48
- const known = KNOWN_COMPONENTS.includes(tag);
49
- return known ? match : `\`<${tag}>\``; // wrap in backticks to keep as code
86
+ // Only replace unrecognized <someTag> with `"<someTag>"` if NOT inside a code block
87
+ // This regex finds all <tag> occurrences
88
+ processed = processed.replace(/<([a-z][a-z0-9]*)>/gi, (match, tag, offset) => {
89
+ // If inside a code block, do not touch
90
+ if (isInsideCodeBlock(processed, offset)) {
91
+ return match;
92
+ }
93
+
94
+ // If known component, check if it has a closing tag
95
+ if (KNOWN_COMPONENTS.includes(tag)) {
96
+ // If it doesn't have a matching closing tag, treat it as text
97
+ if (!hasMatchingClosingTag(processed, tag, offset)) {
98
+ return `\`<${tag}>\``;
99
+ }
100
+ // Otherwise, leave as-is for proper JSX parsing
101
+ return match;
102
+ }
103
+
104
+ // If already inside backticks, do not wrap again
105
+ // Find the start of the line up to the match
106
+ const before = processed.slice(0, offset);
107
+ // Count the number of backticks before this tag
108
+ const backtickMatches = before.match(/`+/g);
109
+ // If the number of backticks is odd, we're inside a backtick span
110
+ const insideBackticks = backtickMatches ? backtickMatches.reduce((acc, s) => acc + s.length, 0) % 2 === 1 : false;
111
+ if (insideBackticks) {
112
+ return match;
113
+ }
114
+ // Otherwise, wrap in backticks to prevent JSX parsing
115
+ return `\`<${tag}>\``;
50
116
  });
51
117
 
52
118
  return {