conversationalist 0.0.6 → 0.0.8
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/README.md +227 -58
- package/dist/adapters/anthropic/index.d.ts +11 -6
- package/dist/adapters/anthropic/index.d.ts.map +1 -1
- package/dist/adapters/anthropic/index.js +16 -3
- package/dist/adapters/anthropic/index.js.map +5 -4
- package/dist/adapters/gemini/index.d.ts +2 -2
- package/dist/adapters/gemini/index.d.ts.map +1 -1
- package/dist/adapters/gemini/index.js +52 -9
- package/dist/adapters/gemini/index.js.map +5 -4
- package/dist/adapters/openai/index.d.ts +32 -5
- package/dist/adapters/openai/index.d.ts.map +1 -1
- package/dist/adapters/openai/index.js +30 -8
- package/dist/adapters/openai/index.js.map +5 -4
- package/dist/context.d.ts.map +1 -1
- package/dist/conversation/append.d.ts +4 -4
- package/dist/conversation/append.d.ts.map +1 -1
- package/dist/conversation/create.d.ts +2 -3
- package/dist/conversation/create.d.ts.map +1 -1
- package/dist/conversation/index.d.ts +2 -2
- package/dist/conversation/index.d.ts.map +1 -1
- package/dist/conversation/modify.d.ts.map +1 -1
- package/dist/conversation/query.d.ts +9 -5
- package/dist/conversation/query.d.ts.map +1 -1
- package/dist/conversation/serialization.d.ts +21 -5
- package/dist/conversation/serialization.d.ts.map +1 -1
- package/dist/conversation/system-messages.d.ts +3 -3
- package/dist/conversation/system-messages.d.ts.map +1 -1
- package/dist/conversation/transform.d.ts.map +1 -1
- package/dist/conversation.d.ts +84 -14
- package/dist/conversation.d.ts.map +1 -1
- package/dist/export/index.d.ts +7 -0
- package/dist/export/index.d.ts.map +1 -0
- package/dist/export/index.js +3762 -0
- package/dist/export/index.js.map +62 -0
- package/dist/history.d.ts +102 -24
- package/dist/history.d.ts.map +1 -1
- package/dist/index.d.ts +8 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +440 -3982
- package/dist/index.js.map +15 -57
- package/dist/markdown/index.d.ts +15 -0
- package/dist/markdown/index.d.ts.map +1 -0
- package/dist/markdown/index.js +4969 -0
- package/dist/markdown/index.js.map +69 -0
- package/dist/message.d.ts +1 -1
- package/dist/message.d.ts.map +1 -1
- package/dist/multi-modal.d.ts +3 -0
- package/dist/multi-modal.d.ts.map +1 -1
- package/dist/plugins/index.d.ts +1 -1
- package/dist/plugins/index.d.ts.map +1 -1
- package/dist/plugins/index.js +59 -0
- package/dist/plugins/index.js.map +10 -0
- package/dist/plugins/pii-redaction.d.ts +10 -1
- package/dist/plugins/pii-redaction.d.ts.map +1 -1
- package/dist/redaction/index.d.ts +2 -0
- package/dist/redaction/index.d.ts.map +1 -0
- package/dist/redaction/index.js +59 -0
- package/dist/redaction/index.js.map +10 -0
- package/dist/schemas/index.d.ts +2 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +114 -0
- package/dist/schemas/index.js.map +10 -0
- package/dist/schemas.d.ts +325 -15
- package/dist/schemas.d.ts.map +1 -1
- package/dist/sort/index.d.ts +2 -0
- package/dist/sort/index.d.ts.map +1 -0
- package/dist/sort/index.js +32 -0
- package/dist/sort/index.js.map +10 -0
- package/dist/streaming.d.ts +3 -3
- package/dist/streaming.d.ts.map +1 -1
- package/dist/types.d.ts +107 -37
- package/dist/types.d.ts.map +1 -1
- package/dist/utilities/deterministic.d.ts +37 -0
- package/dist/utilities/deterministic.d.ts.map +1 -0
- package/dist/utilities/index.d.ts +3 -3
- package/dist/utilities/index.d.ts.map +1 -1
- package/dist/utilities/line-endings.d.ts +5 -0
- package/dist/utilities/line-endings.d.ts.map +1 -0
- package/dist/utilities/markdown.d.ts +47 -21
- package/dist/utilities/markdown.d.ts.map +1 -1
- package/dist/utilities/message-store.d.ts +6 -0
- package/dist/utilities/message-store.d.ts.map +1 -0
- package/dist/utilities/message.d.ts +9 -3
- package/dist/utilities/message.d.ts.map +1 -1
- package/dist/utilities/tool-calls.d.ts +4 -4
- package/dist/utilities/tool-calls.d.ts.map +1 -1
- package/dist/utilities/tool-results.d.ts +10 -0
- package/dist/utilities/tool-results.d.ts.map +1 -0
- package/dist/utilities/transient.d.ts +47 -0
- package/dist/utilities/transient.d.ts.map +1 -0
- package/dist/utilities.d.ts +6 -4
- package/dist/utilities.d.ts.map +1 -1
- package/dist/versioning/index.d.ts +3 -0
- package/dist/versioning/index.d.ts.map +1 -0
- package/dist/versioning/index.js +58 -0
- package/dist/versioning/index.js.map +11 -0
- package/dist/with-conversation.d.ts +8 -8
- package/dist/with-conversation.d.ts.map +1 -1
- package/package.json +26 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
A TypeScript-first library for managing LLM conversation state with **immutable updates**, **type-safe APIs**, and **provider-agnostic adapters**.
|
|
4
4
|
|
|
5
|
-
[](https://github.com/stevekinney/conversationalist/actions/workflows/ci.yml)
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
7
|
|
|
8
8
|
## What is Conversationalist?
|
|
@@ -13,7 +13,7 @@ In a modern AI application, a conversation is more than just a list of strings.
|
|
|
13
13
|
|
|
14
14
|
- **Tool Use**: Pairing function calls with their results and ensuring they stay in sync.
|
|
15
15
|
- **Hidden Logic**: Internal "thought" messages or snapshots that should be saved but never sent to the provider.
|
|
16
|
-
- **Metadata**: Tracking
|
|
16
|
+
- **Metadata**: Tracking custom IDs and tokens across different steps.
|
|
17
17
|
- **Streaming**: Gracefully handling partial messages in a UI without messy state transitions.
|
|
18
18
|
|
|
19
19
|
Conversationalist handles these complexities through a robust, type-safe API that treats your conversation as the "Single Source of Truth."
|
|
@@ -25,7 +25,7 @@ Managing LLM conversations manually often leads to "provider lock-in" or fragile
|
|
|
25
25
|
- **Decoupling Logic from Providers**: Write your business logic once using Conversationalist's message model, and use adapters to talk to OpenAI, Anthropic, or Gemini.
|
|
26
26
|
- **Built-in Context Management**: Automatically handle context window limits by truncating history while preserving critical system instructions or recent messages.
|
|
27
27
|
- **Type Safety Out-of-the-Box**: Built with Zod and TypeScript, ensuring that your conversation data is valid at runtime and compile-time.
|
|
28
|
-
- **Unified Serialization**: One standard format (`
|
|
28
|
+
- **Unified Serialization**: One standard format (`Conversation`) for your database, your frontend, and your backend.
|
|
29
29
|
|
|
30
30
|
## The Immutable Advantage
|
|
31
31
|
|
|
@@ -65,7 +65,6 @@ import {
|
|
|
65
65
|
appendAssistantMessage,
|
|
66
66
|
appendUserMessage,
|
|
67
67
|
createConversation,
|
|
68
|
-
serializeConversation,
|
|
69
68
|
} from 'conversationalist';
|
|
70
69
|
import { toOpenAIMessages } from 'conversationalist/openai';
|
|
71
70
|
|
|
@@ -82,17 +81,14 @@ conversation = appendAssistantMessage(conversation, 'Let me check that for you.'
|
|
|
82
81
|
// 3. Adapt for a provider
|
|
83
82
|
const openAIMessages = toOpenAIMessages(conversation);
|
|
84
83
|
// [{ role: 'user', content: 'Where is my order?' }, ...]
|
|
85
|
-
|
|
86
|
-
// 4. Save to your database
|
|
87
|
-
const data = serializeConversation(conversation);
|
|
88
|
-
// db.save(data.id, JSON.stringify(data));
|
|
89
84
|
```
|
|
90
85
|
|
|
91
86
|
## Core Concepts
|
|
92
87
|
|
|
93
88
|
### Conversations
|
|
94
89
|
|
|
95
|
-
A conversation is an immutable record with metadata,
|
|
90
|
+
A conversation is an immutable record with metadata, timestamps, a `messages` record keyed
|
|
91
|
+
by message ID, and an `ids` array that preserves order.
|
|
96
92
|
|
|
97
93
|
```ts
|
|
98
94
|
import { createConversation } from 'conversationalist';
|
|
@@ -101,14 +97,20 @@ const conversation = createConversation({
|
|
|
101
97
|
title: 'My Chat',
|
|
102
98
|
status: 'active',
|
|
103
99
|
metadata: { customerId: 'cus_123' },
|
|
104
|
-
tags: ['support', 'vip'],
|
|
105
100
|
});
|
|
106
101
|
```
|
|
107
102
|
|
|
103
|
+
Conversations track message order via `conversation.ids`. Every mutation keeps `ids` in sync
|
|
104
|
+
with `messages`. Use `getMessages(conversation)` for ordered arrays, or
|
|
105
|
+
`getMessageIds()` if you just need the IDs.
|
|
106
|
+
|
|
108
107
|
### Messages
|
|
109
108
|
|
|
110
109
|
Messages have roles and can contain text or multi-modal content. Optional fields include
|
|
111
|
-
`metadata`, `hidden`, `tokenUsage`, `toolCall`, `toolResult
|
|
110
|
+
`metadata`, `hidden`, `tokenUsage`, `toolCall`, and `toolResult`. Assistant messages can also
|
|
111
|
+
include `goalCompleted` (see `AssistantMessage`).
|
|
112
|
+
Use `isAssistantMessage` to narrow when you need `goalCompleted`.
|
|
113
|
+
Metadata and tool payloads are typed as `JSONValue` so conversations remain JSON-serializable.
|
|
112
114
|
|
|
113
115
|
**Roles**: `user`, `assistant`, `system`, `developer`, `tool-use`, `tool-result`, `snapshot`.
|
|
114
116
|
The `snapshot` role is for internal state and is skipped by adapters.
|
|
@@ -220,19 +222,15 @@ boundTruncate(4000); // Uses tiktokenEstimator automatically
|
|
|
220
222
|
|
|
221
223
|
### Markdown Conversion
|
|
222
224
|
|
|
223
|
-
Convert conversations to human-readable Markdown format, or parse Markdown back into a conversation object.
|
|
225
|
+
Convert conversations to human-readable Markdown format, or parse Markdown back into a conversation object. These helpers live in `conversationalist/markdown`.
|
|
224
226
|
|
|
225
227
|
#### Basic Usage (Clean Markdown)
|
|
226
228
|
|
|
227
229
|
By default, `toMarkdown` produces clean, readable Markdown without metadata:
|
|
228
230
|
|
|
229
231
|
```ts
|
|
230
|
-
import {
|
|
231
|
-
|
|
232
|
-
fromMarkdown,
|
|
233
|
-
createConversation,
|
|
234
|
-
appendMessages,
|
|
235
|
-
} from 'conversationalist';
|
|
232
|
+
import { appendMessages, createConversation } from 'conversationalist';
|
|
233
|
+
import { fromMarkdown, toMarkdown } from 'conversationalist/markdown';
|
|
236
234
|
|
|
237
235
|
let conversation = createConversation({ id: 'conv-1' });
|
|
238
236
|
conversation = appendMessages(
|
|
@@ -272,7 +270,6 @@ const markdown = toMarkdown(conversation, { includeMetadata: true });
|
|
|
272
270
|
// id: conv-1
|
|
273
271
|
// status: active
|
|
274
272
|
// metadata: {}
|
|
275
|
-
// tags: []
|
|
276
273
|
// createdAt: '2024-01-15T10:00:00.000Z'
|
|
277
274
|
// updatedAt: '2024-01-15T10:01:00.000Z'
|
|
278
275
|
// messages:
|
|
@@ -298,7 +295,7 @@ const markdown = toMarkdown(conversation, { includeMetadata: true });
|
|
|
298
295
|
// Parse back with all metadata preserved
|
|
299
296
|
const restored = fromMarkdown(markdown);
|
|
300
297
|
// restored.id === 'conv-1'
|
|
301
|
-
// restored.
|
|
298
|
+
// restored.ids[0] === 'msg-1'
|
|
302
299
|
```
|
|
303
300
|
|
|
304
301
|
#### Multi-Modal Content
|
|
@@ -326,18 +323,15 @@ const md = toMarkdown(conversation);
|
|
|
326
323
|
|
|
327
324
|
### PII Redaction Plugin
|
|
328
325
|
|
|
329
|
-
The library includes a built-in `
|
|
326
|
+
The library includes a built-in `redactPii` plugin that can automatically redact emails, phone numbers, and common API key patterns.
|
|
330
327
|
|
|
331
328
|
```ts
|
|
332
|
-
import {
|
|
333
|
-
|
|
334
|
-
createConversation,
|
|
335
|
-
piiRedactionPlugin,
|
|
336
|
-
} from 'conversationalist';
|
|
329
|
+
import { appendUserMessage, createConversation, getMessages } from 'conversationalist';
|
|
330
|
+
import { redactPii } from 'conversationalist/redaction';
|
|
337
331
|
|
|
338
332
|
// 1. Enable by adding to your environment
|
|
339
333
|
const env = {
|
|
340
|
-
plugins: [
|
|
334
|
+
plugins: [redactPii],
|
|
341
335
|
};
|
|
342
336
|
|
|
343
337
|
// 2. Use the environment when appending messages
|
|
@@ -349,7 +343,7 @@ conversation = appendUserMessage(
|
|
|
349
343
|
env,
|
|
350
344
|
);
|
|
351
345
|
|
|
352
|
-
console.log(conversation
|
|
346
|
+
console.log(getMessages(conversation)[0]?.content);
|
|
353
347
|
// "Contact me at [EMAIL_REDACTED]"
|
|
354
348
|
```
|
|
355
349
|
|
|
@@ -357,7 +351,7 @@ When using `ConversationHistory`, you only need to provide the plugin once durin
|
|
|
357
351
|
|
|
358
352
|
```ts
|
|
359
353
|
const history = new ConversationHistory(createConversation(), {
|
|
360
|
-
plugins: [
|
|
354
|
+
plugins: [redactPii],
|
|
361
355
|
});
|
|
362
356
|
|
|
363
357
|
const appendUser = history.bind(appendUserMessage);
|
|
@@ -374,6 +368,7 @@ import { toAnthropicMessages } from 'conversationalist/anthropic';
|
|
|
374
368
|
import { toGeminiMessages } from 'conversationalist/gemini';
|
|
375
369
|
```
|
|
376
370
|
|
|
371
|
+
- Adapter outputs are SDK-compatible (OpenAI `ChatCompletionMessageParam[]`, Anthropic `MessageParam[]`, Gemini `Content[]`).
|
|
377
372
|
- **OpenAI**: Supports `toOpenAIMessages` and `toOpenAIMessagesGrouped` (which groups consecutive tool calls).
|
|
378
373
|
- **Anthropic**: Maps system messages and tool blocks to Anthropic's specific format.
|
|
379
374
|
- **Gemini**: Handles Gemini's unique content/part structure.
|
|
@@ -533,6 +528,8 @@ history.truncateToTokenLimit(4000);
|
|
|
533
528
|
const messages = history.getMessages();
|
|
534
529
|
const stats = history.getStatistics();
|
|
535
530
|
const tokens = history.estimateTokens();
|
|
531
|
+
const ids = history.ids;
|
|
532
|
+
const firstMessage = history.get(ids[0]!);
|
|
536
533
|
```
|
|
537
534
|
|
|
538
535
|
### Event Subscription
|
|
@@ -587,10 +584,10 @@ history.undo();
|
|
|
587
584
|
history.appendUserMessage('Path B');
|
|
588
585
|
|
|
589
586
|
console.log(history.branchCount); // 2
|
|
590
|
-
console.log(history.
|
|
587
|
+
console.log(history.getMessages()[0]?.content); // "Path B"
|
|
591
588
|
|
|
592
589
|
history.switchToBranch(0);
|
|
593
|
-
console.log(history.
|
|
590
|
+
console.log(history.getMessages()[0]?.content); // "Path A"
|
|
594
591
|
```
|
|
595
592
|
|
|
596
593
|
### Serialization
|
|
@@ -598,26 +595,118 @@ console.log(history.current.messages[0].content); // "Path A"
|
|
|
598
595
|
You can serialize the entire history tree (including all branches) to JSON and reconstruct it later.
|
|
599
596
|
|
|
600
597
|
```ts
|
|
601
|
-
// 1.
|
|
602
|
-
const
|
|
603
|
-
// localStorage.setItem('chat_history', JSON.stringify(
|
|
598
|
+
// 1. Capture a snapshot
|
|
599
|
+
const snapshot = history.snapshot();
|
|
600
|
+
// localStorage.setItem('chat_history', JSON.stringify(snapshot));
|
|
604
601
|
|
|
605
|
-
// 2. Restore from
|
|
606
|
-
const restored = ConversationHistory.from(
|
|
602
|
+
// 2. Restore from a snapshot
|
|
603
|
+
const restored = ConversationHistory.from(snapshot);
|
|
607
604
|
|
|
608
605
|
// You can also provide a new environment (e.g. with fresh token counters)
|
|
609
|
-
const restoredWithEnv = ConversationHistory.from(
|
|
606
|
+
const restoredWithEnv = ConversationHistory.from(snapshot, {
|
|
610
607
|
estimateTokens: myNewEstimator,
|
|
611
608
|
});
|
|
612
609
|
```
|
|
613
610
|
|
|
611
|
+
## Advanced Serialization
|
|
612
|
+
|
|
613
|
+
### Schema Versioning
|
|
614
|
+
|
|
615
|
+
Conversations include a `schemaVersion` field for forward compatibility. When loading older data, use `migrateConversation` to upgrade it to the current schema:
|
|
616
|
+
|
|
617
|
+
```ts
|
|
618
|
+
import { deserializeConversation } from 'conversationalist';
|
|
619
|
+
import {
|
|
620
|
+
migrateConversation,
|
|
621
|
+
CURRENT_SCHEMA_VERSION,
|
|
622
|
+
} from 'conversationalist/versioning';
|
|
623
|
+
|
|
624
|
+
// Old data without schemaVersion
|
|
625
|
+
const legacyData = JSON.parse(oldStorage);
|
|
626
|
+
const migrated = migrateConversation(legacyData);
|
|
627
|
+
// migrated.schemaVersion === CURRENT_SCHEMA_VERSION
|
|
628
|
+
|
|
629
|
+
const conversation = deserializeConversation(migrated);
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
Conversations are already JSON-serializable; persist them directly and apply utilities
|
|
633
|
+
like `stripTransientMetadata` or `redactMessageAtPosition` when you need to sanitize data.
|
|
634
|
+
|
|
635
|
+
### Transient Metadata Convention
|
|
636
|
+
|
|
637
|
+
Keys prefixed with `_` are considered transient—temporary UI state that shouldn't be persisted:
|
|
638
|
+
|
|
639
|
+
```ts
|
|
640
|
+
import {
|
|
641
|
+
isTransientKey,
|
|
642
|
+
stripTransientFromRecord,
|
|
643
|
+
stripTransientMetadata,
|
|
644
|
+
} from 'conversationalist';
|
|
645
|
+
|
|
646
|
+
// Check if a key is transient
|
|
647
|
+
isTransientKey('_tempId'); // true
|
|
648
|
+
isTransientKey('source'); // false
|
|
649
|
+
|
|
650
|
+
// Strip transient keys from a metadata object
|
|
651
|
+
stripTransientFromRecord({ _loading: true, source: 'web' });
|
|
652
|
+
// { source: 'web' }
|
|
653
|
+
|
|
654
|
+
// Strip transient metadata from an entire conversation
|
|
655
|
+
const cleaned = stripTransientMetadata(conversation);
|
|
656
|
+
```
|
|
657
|
+
|
|
658
|
+
### Sort Utilities
|
|
659
|
+
|
|
660
|
+
For reproducible snapshots or tests, use the sort utilities:
|
|
661
|
+
|
|
662
|
+
```ts
|
|
663
|
+
import { sortObjectKeys, sortMessagesByPosition } from 'conversationalist/sort';
|
|
664
|
+
|
|
665
|
+
// Sort object keys alphabetically (recursive)
|
|
666
|
+
const sorted = sortObjectKeys({ z: 1, a: 2, nested: { b: 3, a: 4 } });
|
|
667
|
+
// { a: 2, nested: { a: 4, b: 3 }, z: 1 }
|
|
668
|
+
|
|
669
|
+
// Sort messages by position, createdAt, then id
|
|
670
|
+
const orderedMessages = sortMessagesByPosition(messages);
|
|
671
|
+
```
|
|
672
|
+
|
|
673
|
+
### Role Labels
|
|
674
|
+
|
|
675
|
+
Export human-readable labels for message roles:
|
|
676
|
+
|
|
677
|
+
```ts
|
|
678
|
+
import {
|
|
679
|
+
ROLE_LABELS,
|
|
680
|
+
LABEL_TO_ROLE,
|
|
681
|
+
getRoleLabel,
|
|
682
|
+
getRoleFromLabel,
|
|
683
|
+
} from 'conversationalist/markdown';
|
|
684
|
+
|
|
685
|
+
// Get display label for a role
|
|
686
|
+
getRoleLabel('tool-use'); // 'Tool Use'
|
|
687
|
+
getRoleLabel('assistant'); // 'Assistant'
|
|
688
|
+
|
|
689
|
+
// Get role from a label
|
|
690
|
+
getRoleFromLabel('Tool Result'); // 'tool-result'
|
|
691
|
+
getRoleFromLabel('Unknown'); // undefined
|
|
692
|
+
|
|
693
|
+
// Access the mappings directly
|
|
694
|
+
ROLE_LABELS['developer']; // 'Developer'
|
|
695
|
+
LABEL_TO_ROLE['System']; // 'system'
|
|
696
|
+
```
|
|
697
|
+
|
|
614
698
|
### Markdown Serialization
|
|
615
699
|
|
|
616
700
|
You can also convert a conversation to Markdown format for human-readable storage or export, and restore it later.
|
|
617
701
|
|
|
618
702
|
```ts
|
|
703
|
+
import { ConversationHistory } from 'conversationalist';
|
|
704
|
+
import { historyFromMarkdown, historyToMarkdown } from 'conversationalist/markdown';
|
|
705
|
+
|
|
706
|
+
const history = new ConversationHistory();
|
|
707
|
+
|
|
619
708
|
// Export to clean, readable Markdown
|
|
620
|
-
const markdown = history
|
|
709
|
+
const markdown = historyToMarkdown(history);
|
|
621
710
|
// ### User
|
|
622
711
|
//
|
|
623
712
|
// Hello!
|
|
@@ -627,10 +716,30 @@ const markdown = history.toMarkdown();
|
|
|
627
716
|
// Hi there!
|
|
628
717
|
|
|
629
718
|
// Export with full metadata (lossless round-trip)
|
|
630
|
-
const markdownWithMetadata = history
|
|
719
|
+
const markdownWithMetadata = historyToMarkdown(history, { includeMetadata: true });
|
|
720
|
+
|
|
721
|
+
// Export with additional controls (redaction, transient stripping, hidden handling)
|
|
722
|
+
const markdownSafe = historyToMarkdown(history, {
|
|
723
|
+
includeMetadata: true,
|
|
724
|
+
stripTransient: true,
|
|
725
|
+
redactToolArguments: true,
|
|
726
|
+
redactToolResults: true,
|
|
727
|
+
includeHidden: false,
|
|
728
|
+
});
|
|
631
729
|
|
|
632
730
|
// Restore from Markdown
|
|
633
|
-
const restored =
|
|
731
|
+
const restored = historyFromMarkdown(markdownWithMetadata);
|
|
732
|
+
```
|
|
733
|
+
|
|
734
|
+
### Export Helpers
|
|
735
|
+
|
|
736
|
+
For markdown export workflows, use the built-in helpers:
|
|
737
|
+
|
|
738
|
+
```ts
|
|
739
|
+
import { exportMarkdown, normalizeLineEndings } from 'conversationalist/export';
|
|
740
|
+
|
|
741
|
+
const normalizedMarkdown = exportMarkdown(conversation, { includeMetadata: true });
|
|
742
|
+
const normalized = normalizeLineEndings('line1\r\nline2');
|
|
634
743
|
```
|
|
635
744
|
|
|
636
745
|
## Integration
|
|
@@ -641,7 +750,7 @@ Because **Conversationalist** is immutable, it works perfectly with React's `use
|
|
|
641
750
|
|
|
642
751
|
```tsx
|
|
643
752
|
import { useState } from 'react';
|
|
644
|
-
import { createConversation,
|
|
753
|
+
import { appendUserMessage, createConversation, getMessages } from 'conversationalist';
|
|
645
754
|
|
|
646
755
|
export function ChatApp() {
|
|
647
756
|
const [conversation, setConversation] = useState(() => createConversation());
|
|
@@ -653,7 +762,7 @@ export function ChatApp() {
|
|
|
653
762
|
|
|
654
763
|
return (
|
|
655
764
|
<div>
|
|
656
|
-
{conversation.
|
|
765
|
+
{getMessages(conversation).map((m) => (
|
|
657
766
|
<div key={m.id}>{String(m.content)}</div>
|
|
658
767
|
))}
|
|
659
768
|
<button onClick={() => handleSend('Hello!')}>Send</button>
|
|
@@ -668,7 +777,7 @@ For more complex applications, you can wrap the logic into a custom hook. This e
|
|
|
668
777
|
|
|
669
778
|
```tsx
|
|
670
779
|
import { useState, useCallback, useEffect } from 'react';
|
|
671
|
-
import { createConversation,
|
|
780
|
+
import { ConversationHistory, createConversation, getMessages } from 'conversationalist';
|
|
672
781
|
|
|
673
782
|
export function useChat(initialTitle?: string) {
|
|
674
783
|
// 1. Initialize history (this could also come from context or props)
|
|
@@ -712,7 +821,7 @@ export function useChat(initialTitle?: string) {
|
|
|
712
821
|
|
|
713
822
|
return {
|
|
714
823
|
conversation,
|
|
715
|
-
messages: conversation
|
|
824
|
+
messages: getMessages(conversation),
|
|
716
825
|
loading,
|
|
717
826
|
sendMessage,
|
|
718
827
|
undo: () => history.undo(),
|
|
@@ -756,7 +865,11 @@ In Svelte 5, you can manage conversation state using the `$state` rune. Since **
|
|
|
756
865
|
|
|
757
866
|
```svelte
|
|
758
867
|
<script lang="ts">
|
|
759
|
-
import {
|
|
868
|
+
import {
|
|
869
|
+
appendUserMessage,
|
|
870
|
+
createConversation,
|
|
871
|
+
getMessages,
|
|
872
|
+
} from 'conversationalist';
|
|
760
873
|
|
|
761
874
|
let conversation = $state(createConversation());
|
|
762
875
|
|
|
@@ -766,7 +879,7 @@ In Svelte 5, you can manage conversation state using the `$state` rune. Since **
|
|
|
766
879
|
</script>
|
|
767
880
|
|
|
768
881
|
<div>
|
|
769
|
-
{#each conversation
|
|
882
|
+
{#each getMessages(conversation) as m (m.id)}
|
|
770
883
|
<div>{String(m.content)}</div>
|
|
771
884
|
{/each}
|
|
772
885
|
<button onclick={() => handleSend('Hello!')}>Send</button>
|
|
@@ -779,14 +892,14 @@ Svelte 5's runes pair perfectly with **Conversationalist**. You can use the `Con
|
|
|
779
892
|
|
|
780
893
|
```svelte
|
|
781
894
|
<script lang="ts">
|
|
782
|
-
import { ConversationHistory } from 'conversationalist';
|
|
895
|
+
import { ConversationHistory, getMessages } from 'conversationalist';
|
|
783
896
|
|
|
784
897
|
// history implements the Svelte store contract
|
|
785
898
|
const history = new ConversationHistory();
|
|
786
899
|
</script>
|
|
787
900
|
|
|
788
901
|
<div>
|
|
789
|
-
{#each $history
|
|
902
|
+
{#each getMessages($history) as m (m.id)}
|
|
790
903
|
<div>{String(m.content)}</div>
|
|
791
904
|
{/each}
|
|
792
905
|
<button onclick={() => history.appendUserMessage('Hello!')}>
|
|
@@ -799,16 +912,72 @@ Svelte 5's runes pair perfectly with **Conversationalist**. You can use the `Con
|
|
|
799
912
|
|
|
800
913
|
## API Overview
|
|
801
914
|
|
|
802
|
-
| Category | Key Functions
|
|
803
|
-
| :--------------- |
|
|
804
|
-
| **Creation** | `createConversation`, `
|
|
805
|
-
| **Appending** | `appendUserMessage`, `appendAssistantMessage`, `appendSystemMessage`, `appendMessages`
|
|
806
|
-
| **Streaming** | `appendStreamingMessage`, `updateStreamingMessage`, `finalizeStreamingMessage`, `cancelStreamingMessage`
|
|
807
|
-
| **Modification** | `redactMessageAtPosition`, `replaceSystemMessage`, `collapseSystemMessages`
|
|
808
|
-
| **Context** | `truncateToTokenLimit`, `getRecentMessages`, `estimateConversationTokens`
|
|
809
|
-
| **Querying** | `
|
|
810
|
-
| **Conversion** | `
|
|
811
|
-
| **
|
|
915
|
+
| Category | Key Functions |
|
|
916
|
+
| :--------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
917
|
+
| **Creation** | `createConversation`, `deserializeConversation` |
|
|
918
|
+
| **Appending** | `appendUserMessage`, `appendAssistantMessage`, `appendSystemMessage`, `appendMessages` |
|
|
919
|
+
| **Streaming** | `appendStreamingMessage`, `updateStreamingMessage`, `finalizeStreamingMessage`, `cancelStreamingMessage` |
|
|
920
|
+
| **Modification** | `redactMessageAtPosition`, `replaceSystemMessage`, `collapseSystemMessages` |
|
|
921
|
+
| **Context** | `truncateToTokenLimit`, `getRecentMessages`, `estimateConversationTokens` |
|
|
922
|
+
| **Querying** | `getMessages`, `getMessageIds`, `getMessageById`, `getStatistics` |
|
|
923
|
+
| **Conversion** | `toChatMessages`, `pairToolCallsWithResults` |
|
|
924
|
+
| **Markdown** | `toMarkdown`, `fromMarkdown`, `historyToMarkdown`, `historyFromMarkdown` (from `conversationalist/markdown`) |
|
|
925
|
+
| **Export** | `exportMarkdown`, `normalizeLineEndings` (from `conversationalist/export`) |
|
|
926
|
+
| **Schemas** | `conversationSchema`, `messageJSONSchema`, `messageInputSchema`, `messageRoleSchema`, `multiModalContentSchema`, `jsonValueSchema`, `toolCallSchema`, `toolResultSchema`, `tokenUsageSchema` (from `conversationalist/schemas`) |
|
|
927
|
+
| **Role Labels** | `ROLE_LABELS`, `LABEL_TO_ROLE`, `getRoleLabel`, `getRoleFromLabel` (from `conversationalist/markdown`) |
|
|
928
|
+
| **Transient** | `isTransientKey`, `stripTransientFromRecord`, `stripTransientMetadata` |
|
|
929
|
+
| **Redaction** | `redactPii`, `createPIIRedactionPlugin`, `createPIIRedaction`, `DEFAULT_PII_RULES` (from `conversationalist/redaction`) |
|
|
930
|
+
| **Versioning** | `migrateConversation`, `CURRENT_SCHEMA_VERSION` (from `conversationalist/versioning`) |
|
|
931
|
+
| **Sort** | `sortObjectKeys`, `sortMessagesByPosition` (from `conversationalist/sort`) |
|
|
932
|
+
| **History** | `ConversationHistory` |
|
|
933
|
+
|
|
934
|
+
## Standard Schema Compliance
|
|
935
|
+
|
|
936
|
+
All exported Zod schemas implement the [Standard Schema](https://standardschema.dev/) specification via Zod's built-in support. This means they can be used with any Standard Schema-compatible tool without library-specific adapters.
|
|
937
|
+
|
|
938
|
+
### Exported Schemas
|
|
939
|
+
|
|
940
|
+
| Schema | Purpose |
|
|
941
|
+
| :------------------------ | :---------------------------------- |
|
|
942
|
+
| `conversationSchema` | Complete conversation with metadata |
|
|
943
|
+
| `jsonValueSchema` | JSON-serializable values |
|
|
944
|
+
| `messageJSONSchema` | Serialized message format |
|
|
945
|
+
| `messageInputSchema` | Input for creating messages |
|
|
946
|
+
| `messageRoleSchema` | Valid message roles enum |
|
|
947
|
+
| `multiModalContentSchema` | Text or image content |
|
|
948
|
+
| `toolCallSchema` | Tool function calls |
|
|
949
|
+
| `toolResultSchema` | Tool execution results |
|
|
950
|
+
| `tokenUsageSchema` | Token usage statistics |
|
|
951
|
+
|
|
952
|
+
### Usage with Standard Schema Consumers
|
|
953
|
+
|
|
954
|
+
```ts
|
|
955
|
+
import { conversationSchema } from 'conversationalist/schemas';
|
|
956
|
+
|
|
957
|
+
// Access the Standard Schema interface
|
|
958
|
+
const standardSchema = conversationSchema['~standard'];
|
|
959
|
+
|
|
960
|
+
// Use with any Standard Schema consumer
|
|
961
|
+
const result = standardSchema.validate(unknownData);
|
|
962
|
+
if (result.issues) {
|
|
963
|
+
console.error('Validation failed:', result.issues);
|
|
964
|
+
} else {
|
|
965
|
+
console.log('Valid conversation:', result.value);
|
|
966
|
+
}
|
|
967
|
+
```
|
|
968
|
+
|
|
969
|
+
### Type Inference
|
|
970
|
+
|
|
971
|
+
Standard Schema preserves type information:
|
|
972
|
+
|
|
973
|
+
```ts
|
|
974
|
+
import type { StandardSchemaV1 } from '@standard-schema/spec';
|
|
975
|
+
import { conversationSchema } from 'conversationalist/schemas';
|
|
976
|
+
|
|
977
|
+
// Type is inferred correctly
|
|
978
|
+
type ConversationInput = StandardSchemaV1.InferInput<typeof conversationSchema>;
|
|
979
|
+
type ConversationOutput = StandardSchemaV1.InferOutput<typeof conversationSchema>;
|
|
980
|
+
```
|
|
812
981
|
|
|
813
982
|
## Deterministic Environments (Testing)
|
|
814
983
|
|
|
@@ -9,14 +9,19 @@ export interface AnthropicTextBlock {
|
|
|
9
9
|
/**
|
|
10
10
|
* Anthropic image content block.
|
|
11
11
|
*/
|
|
12
|
+
export interface AnthropicBase64ImageSource {
|
|
13
|
+
type: 'base64';
|
|
14
|
+
media_type: string;
|
|
15
|
+
data: string;
|
|
16
|
+
}
|
|
17
|
+
export interface AnthropicUrlImageSource {
|
|
18
|
+
type: 'url';
|
|
19
|
+
url: string;
|
|
20
|
+
}
|
|
21
|
+
export type AnthropicImageSource = AnthropicBase64ImageSource | AnthropicUrlImageSource;
|
|
12
22
|
export interface AnthropicImageBlock {
|
|
13
23
|
type: 'image';
|
|
14
|
-
source:
|
|
15
|
-
type: 'base64' | 'url';
|
|
16
|
-
media_type?: string;
|
|
17
|
-
data?: string;
|
|
18
|
-
url?: string;
|
|
19
|
-
};
|
|
24
|
+
source: AnthropicImageSource;
|
|
20
25
|
}
|
|
21
26
|
/**
|
|
22
27
|
* Anthropic tool use content block.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/anthropic/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAiC,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/anthropic/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAiC,MAAM,aAAa,CAAC;AAG/E;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC,IAAI,EAAE,QAAQ,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,KAAK,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,MAAM,oBAAoB,GAAG,0BAA0B,GAAG,uBAAuB,CAAC;AAExF,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,oBAAoB,CAAC;CAC9B;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,UAAU,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,aAAa,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAC7B,kBAAkB,GAClB,mBAAmB,GACnB,qBAAqB,GACrB,wBAAwB,CAAC;AAE7B;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAC3B,OAAO,EAAE,MAAM,GAAG,qBAAqB,EAAE,CAAC;CAC3C;AAED;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,gBAAgB,EAAE,CAAC;CAC9B;AA+GD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,YAAY,GAAG,qBAAqB,CAkFrF"}
|
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
// src/utilities/message-store.ts
|
|
2
|
+
function getOrderedMessages(conversation) {
|
|
3
|
+
const ordered = [];
|
|
4
|
+
for (const id of conversation.ids) {
|
|
5
|
+
const message = conversation.messages[id];
|
|
6
|
+
if (message) {
|
|
7
|
+
ordered.push(message);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
return ordered;
|
|
11
|
+
}
|
|
12
|
+
|
|
1
13
|
// src/adapters/anthropic/index.ts
|
|
2
14
|
function toAnthropicContent(content) {
|
|
3
15
|
if (typeof content === "string") {
|
|
@@ -75,7 +87,8 @@ function extractSystemContent(messages) {
|
|
|
75
87
|
`);
|
|
76
88
|
}
|
|
77
89
|
function toAnthropicMessages(conversation) {
|
|
78
|
-
const
|
|
90
|
+
const ordered = getOrderedMessages(conversation);
|
|
91
|
+
const system = extractSystemContent(ordered);
|
|
79
92
|
const messages = [];
|
|
80
93
|
let currentRole = null;
|
|
81
94
|
let currentBlocks = [];
|
|
@@ -89,7 +102,7 @@ function toAnthropicMessages(conversation) {
|
|
|
89
102
|
}
|
|
90
103
|
currentRole = null;
|
|
91
104
|
};
|
|
92
|
-
for (const message of
|
|
105
|
+
for (const message of ordered) {
|
|
93
106
|
if (message.hidden)
|
|
94
107
|
continue;
|
|
95
108
|
if (message.role === "system" || message.role === "developer") {
|
|
@@ -144,4 +157,4 @@ export {
|
|
|
144
157
|
toAnthropicMessages
|
|
145
158
|
};
|
|
146
159
|
|
|
147
|
-
//# debugId=
|
|
160
|
+
//# debugId=77199835081EDC2864756E2164756E21
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../../../src/adapters/anthropic/index.ts"],
|
|
3
|
+
"sources": ["../../../src/utilities/message-store.ts", "../../../src/adapters/anthropic/index.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import type {
|
|
5
|
+
"import type { Conversation, Message } from '../types';\n\nexport function getOrderedMessages(conversation: Conversation): Message[] {\n const ordered: Message[] = [];\n for (const id of conversation.ids) {\n const message = conversation.messages[id];\n if (message) {\n ordered.push(message);\n }\n }\n return ordered;\n}\n\nexport function toIdRecord<T extends { id: string }>(\n items: readonly T[],\n): Record<string, T> {\n const record: Record<string, T> = {};\n for (const item of items) {\n record[item.id] = item;\n }\n return record;\n}\n",
|
|
6
|
+
"import type { MultiModalContent } from '@lasercat/homogenaize';\n\nimport type { Conversation, Message, ToolCall, ToolResult } from '../../types';\nimport { getOrderedMessages } from '../../utilities/message-store';\n\n/**\n * Anthropic text content block.\n */\nexport interface AnthropicTextBlock {\n type: 'text';\n text: string;\n}\n\n/**\n * Anthropic image content block.\n */\nexport interface AnthropicBase64ImageSource {\n type: 'base64';\n media_type: string;\n data: string;\n}\n\nexport interface AnthropicUrlImageSource {\n type: 'url';\n url: string;\n}\n\nexport type AnthropicImageSource = AnthropicBase64ImageSource | AnthropicUrlImageSource;\n\nexport interface AnthropicImageBlock {\n type: 'image';\n source: AnthropicImageSource;\n}\n\n/**\n * Anthropic tool use content block.\n */\nexport interface AnthropicToolUseBlock {\n type: 'tool_use';\n id: string;\n name: string;\n input: unknown;\n}\n\n/**\n * Anthropic tool result content block.\n */\nexport interface AnthropicToolResultBlock {\n type: 'tool_result';\n tool_use_id: string;\n content: string;\n is_error?: boolean;\n}\n\n/**\n * Anthropic content block union type.\n */\nexport type AnthropicContentBlock =\n | AnthropicTextBlock\n | AnthropicImageBlock\n | AnthropicToolUseBlock\n | AnthropicToolResultBlock;\n\n/**\n * Anthropic message format for the Messages API.\n */\nexport interface AnthropicMessage {\n role: 'user' | 'assistant';\n content: string | AnthropicContentBlock[];\n}\n\n/**\n * Result of converting a conversation to Anthropic format.\n * System messages are extracted separately since Anthropic uses a top-level system parameter.\n */\nexport interface AnthropicConversation {\n system?: string;\n messages: AnthropicMessage[];\n}\n\n/**\n * Converts internal multi-modal content to Anthropic content blocks.\n */\nfunction toAnthropicContent(\n content: string | ReadonlyArray<MultiModalContent>,\n): string | AnthropicContentBlock[] {\n if (typeof content === 'string') {\n return content;\n }\n\n const blocks: AnthropicContentBlock[] = [];\n for (const part of content) {\n if (part.type === 'text') {\n blocks.push({ type: 'text', text: part.text ?? '' });\n } else if (part.type === 'image') {\n // Anthropic supports both URL and base64\n const url = part.url ?? '';\n if (url.startsWith('data:')) {\n // Base64 data URL\n const matches = url.match(/^data:([^;]+);base64,(.+)$/);\n if (matches && matches[1] && matches[2]) {\n blocks.push({\n type: 'image',\n source: {\n type: 'base64',\n media_type: matches[1],\n data: matches[2],\n },\n });\n }\n } else {\n // Regular URL\n blocks.push({\n type: 'image',\n source: {\n type: 'url',\n url,\n },\n });\n }\n }\n }\n\n return blocks.length === 1 && blocks[0]?.type === 'text' ? blocks[0].text : blocks;\n}\n\n/**\n * Converts an internal ToolCall to Anthropic tool_use block.\n */\nfunction toToolUseBlock(toolCall: ToolCall): AnthropicToolUseBlock {\n return {\n type: 'tool_use',\n id: toolCall.id,\n name: toolCall.name,\n input:\n typeof toolCall.arguments === 'string'\n ? JSON.parse(toolCall.arguments)\n : toolCall.arguments,\n };\n}\n\n/**\n * Converts an internal ToolResult to Anthropic tool_result block.\n */\nfunction toToolResultBlock(toolResult: ToolResult): AnthropicToolResultBlock {\n const result: AnthropicToolResultBlock = {\n type: 'tool_result',\n tool_use_id: toolResult.callId,\n content:\n typeof toolResult.content === 'string'\n ? toolResult.content\n : JSON.stringify(toolResult.content),\n };\n\n if (toolResult.outcome === 'error') {\n result.is_error = true;\n }\n\n return result;\n}\n\n/**\n * Collects system message content from a conversation.\n */\nfunction extractSystemContent(messages: ReadonlyArray<Message>): string | undefined {\n const systemMessages = messages.filter(\n (m) => (m.role === 'system' || m.role === 'developer') && !m.hidden,\n );\n\n if (systemMessages.length === 0) {\n return undefined;\n }\n\n const parts: string[] = [];\n for (const msg of systemMessages) {\n if (typeof msg.content === 'string') {\n parts.push(msg.content);\n } else {\n for (const part of msg.content) {\n if (part.type === 'text') {\n parts.push(part.text ?? '');\n }\n }\n }\n }\n\n return parts.join('\\n\\n');\n}\n\n/**\n * Converts a conversation to Anthropic Messages API format.\n * System messages are extracted to the top-level `system` field.\n * Tool calls become tool_use blocks, tool results become tool_result blocks.\n *\n * @example\n * ```ts\n * import { toAnthropicMessages } from 'conversationalist/anthropic';\n *\n * const { system, messages } = toAnthropicMessages(conversation);\n * const response = await anthropic.messages.create({\n * model: 'claude-3-opus-20240229',\n * system,\n * messages,\n * });\n * ```\n */\nexport function toAnthropicMessages(conversation: Conversation): AnthropicConversation {\n const ordered = getOrderedMessages(conversation);\n const system = extractSystemContent(ordered);\n const messages: AnthropicMessage[] = [];\n\n // Track pending content blocks to merge consecutive same-role messages\n let currentRole: 'user' | 'assistant' | null = null;\n let currentBlocks: AnthropicContentBlock[] = [];\n\n const flushCurrent = () => {\n if (currentRole && currentBlocks.length > 0) {\n messages.push({\n role: currentRole,\n content:\n currentBlocks.length === 1 && currentBlocks[0]?.type === 'text'\n ? currentBlocks[0].text\n : currentBlocks,\n });\n currentBlocks = [];\n }\n currentRole = null;\n };\n\n for (const message of ordered) {\n if (message.hidden) continue;\n\n // Skip system messages (already extracted)\n if (message.role === 'system' || message.role === 'developer') {\n continue;\n }\n\n // Skip snapshots\n if (message.role === 'snapshot') {\n continue;\n }\n\n let targetRole: 'user' | 'assistant';\n let blocks: AnthropicContentBlock[] = [];\n\n if (message.role === 'user') {\n targetRole = 'user';\n const content = toAnthropicContent(message.content);\n if (typeof content === 'string') {\n blocks = [{ type: 'text', text: content }];\n } else {\n blocks = content;\n }\n } else if (message.role === 'assistant') {\n targetRole = 'assistant';\n const content = toAnthropicContent(message.content);\n if (typeof content === 'string') {\n blocks = [{ type: 'text', text: content }];\n } else {\n blocks = content;\n }\n } else if (message.role === 'tool-use' && message.toolCall) {\n targetRole = 'assistant';\n blocks = [toToolUseBlock(message.toolCall)];\n } else if (message.role === 'tool-result' && message.toolResult) {\n targetRole = 'user';\n blocks = [toToolResultBlock(message.toolResult)];\n } else {\n continue;\n }\n\n // Merge with current or start new\n if (currentRole === targetRole) {\n currentBlocks.push(...blocks);\n } else {\n flushCurrent();\n currentRole = targetRole;\n currentBlocks = blocks;\n }\n }\n\n flushCurrent();\n\n const result: AnthropicConversation = { messages };\n if (system !== undefined) {\n result.system = system;\n }\n return result;\n}\n"
|
|
6
7
|
],
|
|
7
|
-
"mappings": ";
|
|
8
|
-
"debugId": "
|
|
8
|
+
"mappings": "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",
|
|
9
|
+
"debugId": "77199835081EDC2864756E2164756E21",
|
|
9
10
|
"names": []
|
|
10
11
|
}
|