conversationalist 0.0.6 → 0.0.7

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 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
- [![Tests](https://github.com/stevekinney/conversationalist/actions/workflows/test.yml/badge.svg)](https://github.com/stevekinney/conversationalist/actions/workflows/test.yml)
5
+ [![CI](https://github.com/stevekinney/conversationalist/actions/workflows/ci.yml/badge.svg)](https://github.com/stevekinney/conversationalist/actions/workflows/ci.yml)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
7
 
8
8
  ## What is Conversationalist?
@@ -611,6 +611,112 @@ const restoredWithEnv = ConversationHistory.from(json, {
611
611
  });
612
612
  ```
613
613
 
614
+ ## Advanced Serialization
615
+
616
+ ### Schema Versioning
617
+
618
+ Conversations include a `schemaVersion` field for forward compatibility. When loading older data, use `migrateConversationJSON` to upgrade it to the current schema:
619
+
620
+ ```ts
621
+ import {
622
+ migrateConversationJSON,
623
+ deserializeConversation,
624
+ CURRENT_SCHEMA_VERSION,
625
+ } from 'conversationalist';
626
+
627
+ // Old data without schemaVersion
628
+ const legacyData = JSON.parse(oldStorage);
629
+ const migrated = migrateConversationJSON(legacyData);
630
+ // migrated.schemaVersion === CURRENT_SCHEMA_VERSION
631
+
632
+ const conversation = deserializeConversation(migrated);
633
+ ```
634
+
635
+ ### Serialization Options
636
+
637
+ `serializeConversation` accepts options for controlling the output:
638
+
639
+ ```ts
640
+ import { serializeConversation } from 'conversationalist';
641
+
642
+ const json = serializeConversation(conversation, {
643
+ // Sort keys and messages for stable, diff-friendly output
644
+ deterministic: true,
645
+
646
+ // Remove metadata keys starting with '_' (transient UI state)
647
+ stripTransient: true,
648
+
649
+ // Replace tool arguments with '[REDACTED]'
650
+ redactToolArguments: true,
651
+
652
+ // Replace tool result content with '[REDACTED]'
653
+ redactToolResults: true,
654
+ });
655
+ ```
656
+
657
+ ### Transient Metadata Convention
658
+
659
+ Keys prefixed with `_` are considered transient—temporary UI state that shouldn't be persisted:
660
+
661
+ ```ts
662
+ import {
663
+ isTransientKey,
664
+ stripTransientFromRecord,
665
+ stripTransientMetadata,
666
+ } from 'conversationalist';
667
+
668
+ // Check if a key is transient
669
+ isTransientKey('_tempId'); // true
670
+ isTransientKey('source'); // false
671
+
672
+ // Strip transient keys from a metadata object
673
+ stripTransientFromRecord({ _loading: true, source: 'web' });
674
+ // { source: 'web' }
675
+
676
+ // Strip transient metadata from an entire conversation
677
+ const cleaned = stripTransientMetadata(conversation);
678
+ ```
679
+
680
+ ### Deterministic Output
681
+
682
+ For reproducible snapshots or tests, use the deterministic utilities:
683
+
684
+ ```ts
685
+ import { sortObjectKeys, sortMessagesByPosition } from 'conversationalist';
686
+
687
+ // Sort object keys alphabetically (recursive)
688
+ const sorted = sortObjectKeys({ z: 1, a: 2, nested: { b: 3, a: 4 } });
689
+ // { a: 2, nested: { a: 4, b: 3 }, z: 1 }
690
+
691
+ // Sort messages by position, createdAt, then id
692
+ const orderedMessages = sortMessagesByPosition(messages);
693
+ ```
694
+
695
+ ### Role Labels
696
+
697
+ Export human-readable labels for message roles:
698
+
699
+ ```ts
700
+ import {
701
+ ROLE_LABELS,
702
+ LABEL_TO_ROLE,
703
+ getRoleLabel,
704
+ getRoleFromLabel,
705
+ } from 'conversationalist';
706
+
707
+ // Get display label for a role
708
+ getRoleLabel('tool-use'); // 'Tool Use'
709
+ getRoleLabel('assistant'); // 'Assistant'
710
+
711
+ // Get role from a label
712
+ getRoleFromLabel('Tool Result'); // 'tool-result'
713
+ getRoleFromLabel('Unknown'); // undefined
714
+
715
+ // Access the mappings directly
716
+ ROLE_LABELS['developer']; // 'Developer'
717
+ LABEL_TO_ROLE['System']; // 'system'
718
+ ```
719
+
614
720
  ### Markdown Serialization
615
721
 
616
722
  You can also convert a conversation to Markdown format for human-readable storage or export, and restore it later.
@@ -799,16 +905,19 @@ Svelte 5's runes pair perfectly with **Conversationalist**. You can use the `Con
799
905
 
800
906
  ## API Overview
801
907
 
802
- | Category | Key Functions |
803
- | :--------------- | :------------------------------------------------------------------------------------------------------- |
804
- | **Creation** | `createConversation`, `serializeConversation`, `deserializeConversation` |
805
- | **Appending** | `appendUserMessage`, `appendAssistantMessage`, `appendSystemMessage`, `appendMessages` |
806
- | **Streaming** | `appendStreamingMessage`, `updateStreamingMessage`, `finalizeStreamingMessage`, `cancelStreamingMessage` |
807
- | **Modification** | `redactMessageAtPosition`, `replaceSystemMessage`, `collapseSystemMessages` |
808
- | **Context** | `truncateToTokenLimit`, `getRecentMessages`, `estimateConversationTokens` |
809
- | **Querying** | `getConversationMessages`, `getMessageByIdentifier`, `computeConversationStatistics` |
810
- | **Conversion** | `toMarkdown`, `fromMarkdown`, `toChatMessages`, `pairToolCallsWithResults` |
811
- | **History** | `ConversationHistory`, `bindToConversationHistory` |
908
+ | Category | Key Functions |
909
+ | :---------------- | :------------------------------------------------------------------------------------------------------- |
910
+ | **Creation** | `createConversation`, `serializeConversation`, `deserializeConversation`, `migrateConversationJSON` |
911
+ | **Appending** | `appendUserMessage`, `appendAssistantMessage`, `appendSystemMessage`, `appendMessages` |
912
+ | **Streaming** | `appendStreamingMessage`, `updateStreamingMessage`, `finalizeStreamingMessage`, `cancelStreamingMessage` |
913
+ | **Modification** | `redactMessageAtPosition`, `replaceSystemMessage`, `collapseSystemMessages` |
914
+ | **Context** | `truncateToTokenLimit`, `getRecentMessages`, `estimateConversationTokens` |
915
+ | **Querying** | `getConversationMessages`, `getMessageByIdentifier`, `computeConversationStatistics` |
916
+ | **Conversion** | `toMarkdown`, `fromMarkdown`, `toChatMessages`, `pairToolCallsWithResults` |
917
+ | **Role Labels** | `ROLE_LABELS`, `LABEL_TO_ROLE`, `getRoleLabel`, `getRoleFromLabel` |
918
+ | **Transient** | `isTransientKey`, `stripTransientFromRecord`, `stripTransientMetadata` |
919
+ | **Deterministic** | `sortObjectKeys`, `sortMessagesByPosition` |
920
+ | **History** | `ConversationHistory`, `bindToConversationHistory` |
812
921
 
813
922
  ## Deterministic Environments (Testing)
814
923
 
@@ -4,6 +4,6 @@ export { appendAssistantMessage, appendMessages, appendSystemMessage, appendUser
4
4
  export { computeConversationStatistics, getConversationMessages, getMessageAtPosition, getMessageByIdentifier, searchConversationMessages, } from './query';
5
5
  export { collapseSystemMessages, getFirstSystemMessage, getSystemMessages, hasSystemMessage, prependSystemMessage, replaceSystemMessage, } from './system-messages';
6
6
  export { redactMessageAtPosition } from './modify';
7
- export { deserializeConversation, serializeConversation } from './serialization';
7
+ export { deserializeConversation, migrateConversationJSON, serializeConversation, } from './serialization';
8
8
  export { toChatMessages } from './transform';
9
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/conversation/index.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AAG9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAG9C,OAAO,EACL,sBAAsB,EACtB,cAAc,EACd,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,UAAU,CAAC;AAGlB,OAAO,EACL,6BAA6B,EAC7B,uBAAuB,EACvB,oBAAoB,EACpB,sBAAsB,EACtB,0BAA0B,GAC3B,MAAM,SAAS,CAAC;AAGjB,OAAO,EACL,sBAAsB,EACtB,qBAAqB,EACrB,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC;AAGnD,OAAO,EAAE,uBAAuB,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAGjF,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/conversation/index.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AAG9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAG9C,OAAO,EACL,sBAAsB,EACtB,cAAc,EACd,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,UAAU,CAAC;AAGlB,OAAO,EACL,6BAA6B,EAC7B,uBAAuB,EACvB,oBAAoB,EACpB,sBAAsB,EACtB,0BAA0B,GAC3B,MAAM,SAAS,CAAC;AAGjB,OAAO,EACL,sBAAsB,EACtB,qBAAqB,EACrB,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC;AAGnD,OAAO,EACL,uBAAuB,EACvB,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC"}
@@ -1,13 +1,51 @@
1
- import type { Conversation, ConversationJSON } from '../types';
1
+ import type { Conversation, ConversationJSON, SerializeOptions } from '../types';
2
+ /**
3
+ * Migrates a conversation JSON object to the current schema version.
4
+ * Handles data from older versions that may not have a schemaVersion field.
5
+ *
6
+ * @param json - The conversation JSON to migrate (may be from an older version)
7
+ * @returns A ConversationJSON with the current schema version
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * // Old data without schemaVersion
12
+ * const old = { id: 'conv-1', status: 'active', ... };
13
+ * const migrated = migrateConversationJSON(old);
14
+ * // migrated.schemaVersion === CURRENT_SCHEMA_VERSION
15
+ * ```
16
+ */
17
+ export declare function migrateConversationJSON(json: unknown): ConversationJSON;
2
18
  /**
3
19
  * Converts a conversation to a plain JSON-serializable object.
4
20
  * Creates deep copies of all nested objects to ensure immutability.
21
+ *
22
+ * @param conversation - The conversation to serialize
23
+ * @param options - Serialization options
24
+ * @returns A JSON-serializable conversation object
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * // Basic serialization
29
+ * const json = serializeConversation(conversation);
30
+ *
31
+ * // With options
32
+ * const json = serializeConversation(conversation, {
33
+ * deterministic: true,
34
+ * stripTransient: true,
35
+ * redactToolArguments: true,
36
+ * });
37
+ * ```
5
38
  */
6
- export declare function serializeConversation(conversation: Conversation): ConversationJSON;
39
+ export declare function serializeConversation(conversation: Conversation, options?: SerializeOptions): ConversationJSON;
7
40
  /**
8
41
  * Reconstructs a conversation from a JSON object.
42
+ * Automatically migrates data from older schema versions.
9
43
  * Validates message positions are contiguous and tool results reference valid calls.
10
44
  * Throws a serialization error if validation fails.
45
+ *
46
+ * @param json - The conversation JSON to deserialize (may be from an older version)
47
+ * @returns A Conversation object
48
+ * @throws {SerializationError} If validation fails
11
49
  */
12
- export declare function deserializeConversation(json: ConversationJSON): Conversation;
50
+ export declare function deserializeConversation(json: unknown): Conversation;
13
51
  //# sourceMappingURL=serialization.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"serialization.d.ts","sourceRoot":"","sources":["../../src/conversation/serialization.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAW,MAAM,UAAU,CAAC;AAIxE;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,YAAY,GAAG,gBAAgB,CAuBlF;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,gBAAgB,GAAG,YAAY,CA2C5E"}
1
+ {"version":3,"file":"serialization.d.ts","sourceRoot":"","sources":["../../src/conversation/serialization.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,YAAY,EACZ,gBAAgB,EAGhB,gBAAgB,EACjB,MAAM,UAAU,CAAC;AAUlB;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,OAAO,GAAG,gBAAgB,CA2BvE;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,qBAAqB,CACnC,YAAY,EAAE,YAAY,EAC1B,OAAO,GAAE,gBAAqB,GAC7B,gBAAgB,CAqElB;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,OAAO,GAAG,YAAY,CA8CnE"}
@@ -1,6 +1,6 @@
1
1
  import type { Message as ExternalMessage } from '@lasercat/homogenaize';
2
2
  import { type ConversationEnvironment } from './environment';
3
- import type { Conversation, ConversationJSON, ConversationStatus, Message, MessageInput } from './types';
3
+ import type { Conversation, ConversationJSON, ConversationStatus, Message, MessageInput, SerializeOptions } from './types';
4
4
  export type { ConversationEnvironment } from './environment';
5
5
  export declare function createConversation(options?: {
6
6
  id?: string;
@@ -33,7 +33,21 @@ export declare function prependSystemMessage(conversation: Conversation, content
33
33
  export declare function replaceSystemMessage(conversation: Conversation, content: string, metadata?: Record<string, unknown>, environment?: Partial<ConversationEnvironment>): Conversation;
34
34
  export declare function collapseSystemMessages(conversation: Conversation, environment?: Partial<ConversationEnvironment>): Conversation;
35
35
  export declare function redactMessageAtPosition(conversation: Conversation, position: number, placeholder?: string, environment?: Partial<ConversationEnvironment>): Conversation;
36
- export declare function serializeConversation(conversation: Conversation): ConversationJSON;
37
- export declare function deserializeConversation(json: ConversationJSON): Conversation;
36
+ /**
37
+ * Migrates a conversation JSON object to the current schema version.
38
+ * Handles data from older versions that may not have a schemaVersion field.
39
+ */
40
+ export declare function migrateConversationJSON(json: unknown): ConversationJSON;
41
+ /**
42
+ * Converts a conversation to a plain JSON-serializable object.
43
+ * Creates deep copies of all nested objects to ensure immutability.
44
+ */
45
+ export declare function serializeConversation(conversation: Conversation, options?: SerializeOptions): ConversationJSON;
46
+ /**
47
+ * Reconstructs a conversation from a JSON object.
48
+ * Automatically migrates data from older schema versions.
49
+ * Validates message positions are contiguous and tool results reference valid calls.
50
+ */
51
+ export declare function deserializeConversation(json: unknown): Conversation;
38
52
  export declare function toChatMessages(conversation: Conversation): ExternalMessage[];
39
53
  //# sourceMappingURL=conversation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"conversation.d.ts","sourceRoot":"","sources":["../src/conversation.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"conversation.d.ts","sourceRoot":"","sources":["../src/conversation.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,16 +1,17 @@
1
1
  export type { ImageContent, TextContent } from './multi-modal';
2
2
  export { copyContent, copyMultiModalContent } from './multi-modal';
3
3
  export type { Message as ExternalMessage, MultiModalContent, } from '@lasercat/homogenaize';
4
- export type { Conversation, ConversationJSON, ConversationStatus, Message, MessageInput, MessageJSON, MessageRole, TokenUsage, ToolCall, ToolResult, } from './types';
4
+ export type { Conversation, ConversationJSON, ConversationStatus, ExportOptions, Message, MessageInput, MessageJSON, MessageRole, SerializeOptions, TokenUsage, ToMarkdownOptions, ToolCall, ToolResult, } from './types';
5
+ export { CURRENT_SCHEMA_VERSION } from './types';
5
6
  export { conversationSchema, conversationShape, messageInputSchema, messageJSONSchema, messageRoleSchema, multiModalContentSchema, tokenUsageSchema, toolCallSchema, toolResultSchema, } from './schemas';
6
7
  export type { ConversationEnvironment } from './conversation';
7
- export { appendAssistantMessage, appendMessages, appendSystemMessage, appendUserMessage, collapseSystemMessages, computeConversationStatistics, createConversation, deserializeConversation, getConversationMessages, getFirstSystemMessage, getMessageAtPosition, getMessageByIdentifier, getSystemMessages, hasSystemMessage, prependSystemMessage, redactMessageAtPosition, replaceSystemMessage, searchConversationMessages, serializeConversation, toChatMessages, } from './conversation';
8
+ export { appendAssistantMessage, appendMessages, appendSystemMessage, appendUserMessage, collapseSystemMessages, computeConversationStatistics, createConversation, deserializeConversation, getConversationMessages, getFirstSystemMessage, getMessageAtPosition, getMessageByIdentifier, getSystemMessages, hasSystemMessage, migrateConversationJSON, prependSystemMessage, redactMessageAtPosition, replaceSystemMessage, searchConversationMessages, serializeConversation, toChatMessages, } from './conversation';
8
9
  export { withEnvironment } from './environment';
9
10
  export { createMessage } from './utilities';
10
11
  export type { ConversationalistErrorCode } from './errors';
11
12
  export { ConversationalistError, createDuplicateIdError, createInvalidInputError, createInvalidPositionError, createInvalidToolReferenceError, createLockedError, createNotFoundError, createSerializationError, createValidationError, } from './errors';
12
- export type { ToMarkdownOptions, ToolCallPair } from './utilities';
13
- export { fromMarkdown, MarkdownParseError, normalizeContent, pairToolCallsWithResults, toMarkdown, toMultiModalArray, } from './utilities';
13
+ export type { ToolCallPair } from './utilities';
14
+ export { fromMarkdown, getRoleFromLabel, getRoleLabel, isTransientKey, LABEL_TO_ROLE, MarkdownParseError, normalizeContent, pairToolCallsWithResults, ROLE_LABELS, sortMessagesByPosition, sortObjectKeys, stripTransientFromRecord, stripTransientMetadata, toMarkdown, toMultiModalArray, } from './utilities';
14
15
  export type { ConversationDraft } from './with-conversation';
15
16
  export { pipeConversation, withConversation } from './with-conversation';
16
17
  export { bindToConversationHistory, ConversationHistory } from './history';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACnE,YAAY,EACV,OAAO,IAAI,eAAe,EAC1B,iBAAiB,GAClB,MAAM,uBAAuB,CAAC;AAG/B,YAAY,EACV,YAAY,EACZ,gBAAgB,EAChB,kBAAkB,EAClB,OAAO,EACP,YAAY,EACZ,WAAW,EACX,WAAW,EACX,UAAU,EACV,QAAQ,EACR,UAAU,GACX,MAAM,SAAS,CAAC;AAGjB,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,uBAAuB,EACvB,gBAAgB,EAChB,cAAc,EACd,gBAAgB,GACjB,MAAM,WAAW,CAAC;AAGnB,YAAY,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EACL,sBAAsB,EACtB,cAAc,EACd,mBAAmB,EACnB,iBAAiB,EACjB,sBAAsB,EACtB,6BAA6B,EAC7B,kBAAkB,EAClB,uBAAuB,EACvB,uBAAuB,EACvB,qBAAqB,EACrB,oBAAoB,EACpB,sBAAsB,EACtB,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,uBAAuB,EACvB,oBAAoB,EACpB,0BAA0B,EAC1B,qBAAqB,EACrB,cAAc,GACf,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAGhD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG5C,YAAY,EAAE,0BAA0B,EAAE,MAAM,UAAU,CAAC;AAC3D,OAAO,EACL,sBAAsB,EACtB,sBAAsB,EACtB,uBAAuB,EACvB,0BAA0B,EAC1B,+BAA+B,EAC/B,iBAAiB,EACjB,mBAAmB,EACnB,wBAAwB,EACxB,qBAAqB,GACtB,MAAM,UAAU,CAAC;AAGlB,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,gBAAgB,EAChB,wBAAwB,EACxB,UAAU,EACV,iBAAiB,GAClB,MAAM,aAAa,CAAC;AAGrB,YAAY,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAGzE,OAAO,EAAE,yBAAyB,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAC3E,YAAY,EAAE,uBAAuB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAGxE,OAAO,EACL,sBAAsB,EACtB,sBAAsB,EACtB,wBAAwB,EACxB,mBAAmB,EACnB,kBAAkB,EAClB,sBAAsB,GACvB,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,0BAA0B,EAC1B,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACnE,YAAY,EACV,OAAO,IAAI,eAAe,EAC1B,iBAAiB,GAClB,MAAM,uBAAuB,CAAC;AAG/B,YAAY,EACV,YAAY,EACZ,gBAAgB,EAChB,kBAAkB,EAClB,aAAa,EACb,OAAO,EACP,YAAY,EACZ,WAAW,EACX,WAAW,EACX,gBAAgB,EAChB,UAAU,EACV,iBAAiB,EACjB,QAAQ,EACR,UAAU,GACX,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAGjD,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,uBAAuB,EACvB,gBAAgB,EAChB,cAAc,EACd,gBAAgB,GACjB,MAAM,WAAW,CAAC;AAGnB,YAAY,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EACL,sBAAsB,EACtB,cAAc,EACd,mBAAmB,EACnB,iBAAiB,EACjB,sBAAsB,EACtB,6BAA6B,EAC7B,kBAAkB,EAClB,uBAAuB,EACvB,uBAAuB,EACvB,qBAAqB,EACrB,oBAAoB,EACpB,sBAAsB,EACtB,iBAAiB,EACjB,gBAAgB,EAChB,uBAAuB,EACvB,oBAAoB,EACpB,uBAAuB,EACvB,oBAAoB,EACpB,0BAA0B,EAC1B,qBAAqB,EACrB,cAAc,GACf,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAGhD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG5C,YAAY,EAAE,0BAA0B,EAAE,MAAM,UAAU,CAAC;AAC3D,OAAO,EACL,sBAAsB,EACtB,sBAAsB,EACtB,uBAAuB,EACvB,0BAA0B,EAC1B,+BAA+B,EAC/B,iBAAiB,EACjB,mBAAmB,EACnB,wBAAwB,EACxB,qBAAqB,GACtB,MAAM,UAAU,CAAC;AAGlB,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,YAAY,EACZ,cAAc,EACd,aAAa,EACb,kBAAkB,EAClB,gBAAgB,EAChB,wBAAwB,EACxB,WAAW,EACX,sBAAsB,EACtB,cAAc,EACd,wBAAwB,EACxB,sBAAsB,EACtB,UAAU,EACV,iBAAiB,GAClB,MAAM,aAAa,CAAC;AAGrB,YAAY,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAGzE,OAAO,EAAE,yBAAyB,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAC3E,YAAY,EAAE,uBAAuB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAGxE,OAAO,EACL,sBAAsB,EACtB,sBAAsB,EACtB,wBAAwB,EACxB,mBAAmB,EACnB,kBAAkB,EAClB,sBAAsB,GACvB,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,0BAA0B,EAC1B,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,WAAW,CAAC"}
package/dist/index.js CHANGED
@@ -3514,6 +3514,8 @@ function copyContent(content) {
3514
3514
  }
3515
3515
  return content.map(copyMultiModalContent);
3516
3516
  }
3517
+ // src/types.ts
3518
+ var CURRENT_SCHEMA_VERSION = 1;
3517
3519
  // src/schemas.ts
3518
3520
  import { z } from "zod";
3519
3521
  var multiModalContentSchema = z.discriminatedUnion("type", [
@@ -3578,6 +3580,7 @@ var conversationStatusSchema = z.enum([
3578
3580
  "deleted"
3579
3581
  ]);
3580
3582
  var conversationShape = {
3583
+ schemaVersion: z.number().int().min(1),
3581
3584
  id: z.string(),
3582
3585
  title: z.string().optional(),
3583
3586
  status: conversationStatusSchema,
@@ -3601,6 +3604,32 @@ function normalizeContent(content) {
3601
3604
  return content;
3602
3605
  return Array.isArray(content) ? content : [content];
3603
3606
  }
3607
+ // src/utilities/deterministic.ts
3608
+ function sortObjectKeys(obj) {
3609
+ if (obj === null || typeof obj !== "object") {
3610
+ return obj;
3611
+ }
3612
+ if (Array.isArray(obj)) {
3613
+ return obj.map(sortObjectKeys);
3614
+ }
3615
+ const sorted = {};
3616
+ const keys = Object.keys(obj).sort();
3617
+ for (const key of keys) {
3618
+ sorted[key] = sortObjectKeys(obj[key]);
3619
+ }
3620
+ return sorted;
3621
+ }
3622
+ function sortMessagesByPosition(messages) {
3623
+ return [...messages].sort((a, b) => {
3624
+ if (a.position !== b.position) {
3625
+ return a.position - b.position;
3626
+ }
3627
+ if (a.createdAt !== b.createdAt) {
3628
+ return a.createdAt.localeCompare(b.createdAt);
3629
+ }
3630
+ return a.id.localeCompare(b.id);
3631
+ });
3632
+ }
3604
3633
  // src/utilities/markdown.ts
3605
3634
  var import_gray_matter = __toESM(require_gray_matter(), 1);
3606
3635
 
@@ -3645,7 +3674,7 @@ function messageHasImages(message) {
3645
3674
  }
3646
3675
 
3647
3676
  // src/utilities/markdown.ts
3648
- var ROLE_DISPLAY_NAMES = {
3677
+ var ROLE_LABELS = {
3649
3678
  user: "User",
3650
3679
  assistant: "Assistant",
3651
3680
  system: "System",
@@ -3654,7 +3683,8 @@ var ROLE_DISPLAY_NAMES = {
3654
3683
  "tool-result": "Tool Result",
3655
3684
  snapshot: "Snapshot"
3656
3685
  };
3657
- var DISPLAY_NAME_TO_ROLE = {
3686
+ var ROLE_DISPLAY_NAMES = ROLE_LABELS;
3687
+ var LABEL_TO_ROLE = {
3658
3688
  User: "user",
3659
3689
  Assistant: "assistant",
3660
3690
  System: "system",
@@ -3663,6 +3693,13 @@ var DISPLAY_NAME_TO_ROLE = {
3663
3693
  "Tool Result": "tool-result",
3664
3694
  Snapshot: "snapshot"
3665
3695
  };
3696
+ var DISPLAY_NAME_TO_ROLE = LABEL_TO_ROLE;
3697
+ function getRoleLabel(role) {
3698
+ return ROLE_LABELS[role];
3699
+ }
3700
+ function getRoleFromLabel(label) {
3701
+ return LABEL_TO_ROLE[label];
3702
+ }
3666
3703
  function formatMessageContent(message) {
3667
3704
  if (typeof message.content === "string")
3668
3705
  return message.content;
@@ -3884,6 +3921,44 @@ function pairToolCallsWithResults(messages) {
3884
3921
  }
3885
3922
  return pairs;
3886
3923
  }
3924
+ // src/utilities/transient.ts
3925
+ function isTransientKey(key) {
3926
+ return key.startsWith("_");
3927
+ }
3928
+ function stripTransientFromRecord(metadata) {
3929
+ const result = {};
3930
+ for (const [key, value] of Object.entries(metadata)) {
3931
+ if (!isTransientKey(key)) {
3932
+ result[key] = value;
3933
+ }
3934
+ }
3935
+ return result;
3936
+ }
3937
+ function stripTransientMetadata(conversation) {
3938
+ const strippedMessages = conversation.messages.map((message) => toReadonly({
3939
+ id: message.id,
3940
+ role: message.role,
3941
+ content: message.content,
3942
+ position: message.position,
3943
+ createdAt: message.createdAt,
3944
+ metadata: toReadonly(stripTransientFromRecord({ ...message.metadata })),
3945
+ hidden: message.hidden,
3946
+ toolCall: message.toolCall,
3947
+ toolResult: message.toolResult,
3948
+ tokenUsage: message.tokenUsage,
3949
+ goalCompleted: message.goalCompleted
3950
+ }));
3951
+ return toReadonly({
3952
+ id: conversation.id,
3953
+ title: conversation.title,
3954
+ status: conversation.status,
3955
+ metadata: toReadonly(stripTransientFromRecord({ ...conversation.metadata })),
3956
+ tags: conversation.tags,
3957
+ messages: strippedMessages,
3958
+ createdAt: conversation.createdAt,
3959
+ updatedAt: conversation.updatedAt
3960
+ });
3961
+ }
3887
3962
  // src/environment.ts
3888
3963
  function simpleTokenEstimator(message) {
3889
3964
  const text = messageText(message);
@@ -4237,33 +4312,88 @@ function redactMessageAtPosition(conversation, position, placeholder = "[REDACTE
4237
4312
  const next = { ...conversation, messages, updatedAt: now };
4238
4313
  return toReadonly(next);
4239
4314
  }
4240
- function serializeConversation(conversation) {
4241
- return {
4242
- id: conversation.id,
4243
- title: conversation.title,
4244
- status: conversation.status,
4245
- metadata: { ...conversation.metadata },
4246
- tags: [...conversation.tags],
4247
- messages: conversation.messages.map((m) => ({
4315
+ var REDACTED = "[REDACTED]";
4316
+ function migrateConversationJSON(json) {
4317
+ if (typeof json !== "object" || json === null || Array.isArray(json)) {
4318
+ return {
4319
+ schemaVersion: CURRENT_SCHEMA_VERSION,
4320
+ id: "",
4321
+ status: "active",
4322
+ metadata: {},
4323
+ tags: [],
4324
+ messages: [],
4325
+ createdAt: new Date().toISOString(),
4326
+ updatedAt: new Date().toISOString()
4327
+ };
4328
+ }
4329
+ const data = json;
4330
+ if (!("schemaVersion" in json)) {
4331
+ return {
4332
+ ...data,
4333
+ schemaVersion: CURRENT_SCHEMA_VERSION
4334
+ };
4335
+ }
4336
+ return data;
4337
+ }
4338
+ function serializeConversation(conversation, options2 = {}) {
4339
+ const {
4340
+ deterministic = false,
4341
+ stripTransient = false,
4342
+ redactToolArguments = false,
4343
+ redactToolResults = false
4344
+ } = options2;
4345
+ let metadata = { ...conversation.metadata };
4346
+ if (stripTransient) {
4347
+ metadata = stripTransientFromRecord(metadata);
4348
+ }
4349
+ let messages = conversation.messages.map((m) => {
4350
+ let msgMetadata = { ...m.metadata };
4351
+ if (stripTransient) {
4352
+ msgMetadata = stripTransientFromRecord(msgMetadata);
4353
+ }
4354
+ return {
4248
4355
  id: m.id,
4249
4356
  role: m.role,
4250
4357
  content: copyContent(m.content),
4251
4358
  position: m.position,
4252
4359
  createdAt: m.createdAt,
4253
- metadata: { ...m.metadata },
4360
+ metadata: msgMetadata,
4254
4361
  hidden: m.hidden,
4255
- toolCall: m.toolCall ? { ...m.toolCall } : undefined,
4256
- toolResult: m.toolResult ? { ...m.toolResult } : undefined,
4362
+ toolCall: m.toolCall ? {
4363
+ ...m.toolCall,
4364
+ arguments: redactToolArguments ? REDACTED : m.toolCall.arguments
4365
+ } : undefined,
4366
+ toolResult: m.toolResult ? {
4367
+ ...m.toolResult,
4368
+ content: redactToolResults ? REDACTED : m.toolResult.content
4369
+ } : undefined,
4257
4370
  tokenUsage: m.tokenUsage ? { ...m.tokenUsage } : undefined,
4258
4371
  goalCompleted: m.goalCompleted
4259
- })),
4372
+ };
4373
+ });
4374
+ if (deterministic) {
4375
+ messages = sortMessagesByPosition(messages);
4376
+ }
4377
+ let result = {
4378
+ schemaVersion: CURRENT_SCHEMA_VERSION,
4379
+ id: conversation.id,
4380
+ title: conversation.title,
4381
+ status: conversation.status,
4382
+ metadata,
4383
+ tags: [...conversation.tags],
4384
+ messages,
4260
4385
  createdAt: conversation.createdAt,
4261
4386
  updatedAt: conversation.updatedAt
4262
4387
  };
4388
+ if (deterministic) {
4389
+ result = sortObjectKeys(result);
4390
+ }
4391
+ return result;
4263
4392
  }
4264
4393
  function deserializeConversation(json) {
4394
+ const migrated = migrateConversationJSON(json);
4265
4395
  try {
4266
- json.messages.reduce((state, message, index) => {
4396
+ migrated.messages.reduce((state, message, index) => {
4267
4397
  if (message.position !== index) {
4268
4398
  throw createInvalidPositionError(index, message.position);
4269
4399
  }
@@ -4277,16 +4407,16 @@ function deserializeConversation(json) {
4277
4407
  }
4278
4408
  return state;
4279
4409
  }, { toolUses: new Map });
4280
- const messages = json.messages.map((m) => createMessage(m));
4410
+ const messages = migrated.messages.map((m) => createMessage(m));
4281
4411
  const conv = {
4282
- id: json.id,
4283
- title: json.title,
4284
- status: json.status,
4285
- metadata: { ...json.metadata },
4286
- tags: [...json.tags],
4412
+ id: migrated.id,
4413
+ title: migrated.title,
4414
+ status: migrated.status,
4415
+ metadata: { ...migrated.metadata },
4416
+ tags: [...migrated.tags],
4287
4417
  messages,
4288
- createdAt: json.createdAt,
4289
- updatedAt: json.updatedAt
4418
+ createdAt: migrated.createdAt,
4419
+ updatedAt: migrated.updatedAt
4290
4420
  };
4291
4421
  return toReadonly(conv);
4292
4422
  } catch (error) {
@@ -4950,6 +5080,10 @@ export {
4950
5080
  toMultiModalArray,
4951
5081
  toMarkdown,
4952
5082
  toChatMessages,
5083
+ stripTransientMetadata,
5084
+ stripTransientFromRecord,
5085
+ sortObjectKeys,
5086
+ sortMessagesByPosition,
4953
5087
  simpleTokenEstimator,
4954
5088
  serializeConversation,
4955
5089
  searchConversationMessages,
@@ -4960,13 +5094,17 @@ export {
4960
5094
  pairToolCallsWithResults,
4961
5095
  normalizeContent,
4962
5096
  multiModalContentSchema,
5097
+ migrateConversationJSON,
4963
5098
  messageRoleSchema,
4964
5099
  messageJSONSchema,
4965
5100
  messageInputSchema,
5101
+ isTransientKey,
4966
5102
  isStreamingMessage,
4967
5103
  hasSystemMessage,
4968
5104
  getSystemMessages,
4969
5105
  getStreamingMessage,
5106
+ getRoleLabel,
5107
+ getRoleFromLabel,
4970
5108
  getRecentMessages,
4971
5109
  getMessageByIdentifier,
4972
5110
  getMessageAtPosition,
@@ -4999,9 +5137,12 @@ export {
4999
5137
  appendStreamingMessage,
5000
5138
  appendMessages,
5001
5139
  appendAssistantMessage,
5140
+ ROLE_LABELS,
5002
5141
  MarkdownParseError,
5142
+ LABEL_TO_ROLE,
5003
5143
  ConversationalistError,
5004
- ConversationHistory
5144
+ ConversationHistory,
5145
+ CURRENT_SCHEMA_VERSION
5005
5146
  };
5006
5147
 
5007
- //# debugId=5ABC5C6EA1F008F764756E2164756E21
5148
+ //# debugId=5DC3B590F98C078D64756E2164756E21