conversationalist 0.0.2 → 0.0.3

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/dist/index.js CHANGED
@@ -95,24 +95,103 @@ var conversationShape = {
95
95
  updatedAt: z.string()
96
96
  };
97
97
  var conversationSchema = z.object(conversationShape);
98
+ // src/utilities.ts
99
+ function pairToolCallsWithResults(messages) {
100
+ const pairs = [];
101
+ const resultsMap = new Map;
102
+ for (const msg of messages) {
103
+ if (msg.toolResult) {
104
+ resultsMap.set(msg.toolResult.callId, msg.toolResult);
105
+ }
106
+ }
107
+ for (const msg of messages) {
108
+ if (msg.toolCall) {
109
+ pairs.push({
110
+ call: msg.toolCall,
111
+ result: resultsMap.get(msg.toolCall.id)
112
+ });
113
+ }
114
+ }
115
+ return pairs;
116
+ }
117
+ function toReadonly(value) {
118
+ return value;
119
+ }
120
+ function createMessage(props) {
121
+ const content = Array.isArray(props.content) ? toReadonly([...props.content]) : props.content;
122
+ const message = {
123
+ id: props.id,
124
+ role: props.role,
125
+ content,
126
+ position: props.position,
127
+ createdAt: props.createdAt,
128
+ metadata: toReadonly({ ...props.metadata }),
129
+ hidden: props.hidden,
130
+ toolCall: props.toolCall ? toReadonly({ ...props.toolCall }) : undefined,
131
+ toolResult: props.toolResult ? toReadonly({ ...props.toolResult }) : undefined,
132
+ tokenUsage: props.tokenUsage ? toReadonly({ ...props.tokenUsage }) : undefined,
133
+ goalCompleted: props.goalCompleted
134
+ };
135
+ return toReadonly(message);
136
+ }
137
+ function toMultiModalArray(input) {
138
+ if (typeof input === "string")
139
+ return [{ type: "text", text: input }];
140
+ return Array.isArray(input) ? input : [input];
141
+ }
142
+ function normalizeContent(content) {
143
+ if (content === undefined)
144
+ return;
145
+ if (typeof content === "string")
146
+ return content;
147
+ return Array.isArray(content) ? content : [content];
148
+ }
149
+ function messageParts(message) {
150
+ if (typeof message.content === "string") {
151
+ return message.content ? [{ type: "text", text: message.content }] : [];
152
+ }
153
+ return message.content;
154
+ }
155
+ function messageText(message, joiner = `
156
+
157
+ `) {
158
+ if (typeof message.content === "string")
159
+ return message.content;
160
+ return messageParts(message).filter((p) => p.type === "text").map((p) => p.type === "text" ? p.text : "").join(joiner);
161
+ }
162
+ function messageHasImages(message) {
163
+ return messageParts(message).some((p) => p.type === "image");
164
+ }
165
+
98
166
  // src/environment.ts
167
+ function simpleTokenEstimator(message) {
168
+ const text = messageText(message);
169
+ return Math.ceil(text.length / 4);
170
+ }
99
171
  var defaultConversationEnvironment = {
100
172
  now: () => new Date().toISOString(),
101
- randomId: () => crypto.randomUUID()
173
+ randomId: () => crypto.randomUUID(),
174
+ estimateTokens: simpleTokenEstimator,
175
+ plugins: []
102
176
  };
103
177
  function resolveConversationEnvironment(environment) {
104
178
  return {
105
179
  now: environment?.now ?? defaultConversationEnvironment.now,
106
- randomId: environment?.randomId ?? defaultConversationEnvironment.randomId
180
+ randomId: environment?.randomId ?? defaultConversationEnvironment.randomId,
181
+ estimateTokens: environment?.estimateTokens ?? defaultConversationEnvironment.estimateTokens,
182
+ plugins: [...environment?.plugins ?? defaultConversationEnvironment.plugins]
107
183
  };
108
184
  }
109
185
  function isConversationEnvironmentParameter(value) {
110
- if (!value || typeof value !== "object")
186
+ if (!value || typeof value !== "object" || value === null)
111
187
  return false;
112
188
  if ("role" in value)
113
189
  return false;
114
190
  const candidate = value;
115
- return typeof candidate.now === "function" || typeof candidate.randomId === "function";
191
+ return typeof candidate["now"] === "function" || typeof candidate["randomId"] === "function" || typeof candidate["estimateTokens"] === "function" || Array.isArray(candidate["plugins"]) && candidate["plugins"].length > 0;
192
+ }
193
+ function withEnvironment(environment, fn) {
194
+ return (...args) => fn(...args, environment);
116
195
  }
117
196
 
118
197
  // src/errors.ts
@@ -169,74 +248,6 @@ function createValidationError(message, context, cause) {
169
248
  return new ConversationalistError("error:validation", message, { context, cause });
170
249
  }
171
250
 
172
- // src/utilities.ts
173
- function pairToolCallsWithResults(messages) {
174
- const pairs = [];
175
- const resultsMap = new Map;
176
- for (const msg of messages) {
177
- if (msg.toolResult) {
178
- resultsMap.set(msg.toolResult.callId, msg.toolResult);
179
- }
180
- }
181
- for (const msg of messages) {
182
- if (msg.toolCall) {
183
- pairs.push({
184
- call: msg.toolCall,
185
- result: resultsMap.get(msg.toolCall.id)
186
- });
187
- }
188
- }
189
- return pairs;
190
- }
191
- function toReadonly(value) {
192
- return value;
193
- }
194
- function createMessage(props) {
195
- const content = Array.isArray(props.content) ? toReadonly([...props.content]) : props.content;
196
- const message = {
197
- id: props.id,
198
- role: props.role,
199
- content,
200
- position: props.position,
201
- createdAt: props.createdAt,
202
- metadata: toReadonly({ ...props.metadata }),
203
- hidden: props.hidden,
204
- toolCall: props.toolCall ? toReadonly({ ...props.toolCall }) : undefined,
205
- toolResult: props.toolResult ? toReadonly({ ...props.toolResult }) : undefined,
206
- tokenUsage: props.tokenUsage ? toReadonly({ ...props.tokenUsage }) : undefined,
207
- goalCompleted: props.goalCompleted
208
- };
209
- return toReadonly(message);
210
- }
211
- function toMultiModalArray(input) {
212
- if (typeof input === "string")
213
- return [{ type: "text", text: input }];
214
- return Array.isArray(input) ? input : [input];
215
- }
216
- function normalizeContent(content) {
217
- if (content === undefined)
218
- return;
219
- if (typeof content === "string")
220
- return content;
221
- return Array.isArray(content) ? content : [content];
222
- }
223
- function messageParts(message) {
224
- if (typeof message.content === "string") {
225
- return message.content ? [{ type: "text", text: message.content }] : [];
226
- }
227
- return message.content;
228
- }
229
- function messageText(message, joiner = `
230
-
231
- `) {
232
- if (typeof message.content === "string")
233
- return message.content;
234
- return messageParts(message).filter((p) => p.type === "text").map((p) => p.type === "text" ? p.text : "").join(joiner);
235
- }
236
- function messageHasImages(message) {
237
- return messageParts(message).some((p) => p.type === "image");
238
- }
239
-
240
251
  // src/conversation.ts
241
252
  var buildToolUseIndex = (messages) => messages.reduce((index, message) => {
242
253
  if (message.role === "tool-use" && message.toolCall) {
@@ -289,24 +300,25 @@ function appendMessages(conversation, ...args) {
289
300
  const startPosition = conversation.messages.length;
290
301
  const initialToolUses = buildToolUseIndex(conversation.messages);
291
302
  const { messages } = inputs.reduce((state, input, index) => {
292
- if (input.role === "tool-result" && input.toolResult) {
293
- assertToolReference(state.toolUses, input.toolResult.callId);
303
+ const processedInput = resolvedEnvironment.plugins.reduce((acc, plugin) => plugin(acc), input);
304
+ if (processedInput.role === "tool-result" && processedInput.toolResult) {
305
+ assertToolReference(state.toolUses, processedInput.toolResult.callId);
294
306
  }
295
- const normalizedContent = normalizeContent(input.content);
307
+ const normalizedContent = normalizeContent(processedInput.content);
296
308
  const message = createMessage({
297
309
  id: resolvedEnvironment.randomId(),
298
- role: input.role,
310
+ role: processedInput.role,
299
311
  content: normalizedContent,
300
312
  position: startPosition + index,
301
313
  createdAt: now,
302
- metadata: { ...input.metadata ?? {} },
303
- hidden: input.hidden ?? false,
304
- toolCall: input.toolCall,
305
- toolResult: input.toolResult,
306
- tokenUsage: input.tokenUsage,
307
- goalCompleted: input.goalCompleted
314
+ metadata: { ...processedInput.metadata ?? {} },
315
+ hidden: processedInput.hidden ?? false,
316
+ toolCall: processedInput.toolCall,
317
+ toolResult: processedInput.toolResult,
318
+ tokenUsage: processedInput.tokenUsage,
319
+ goalCompleted: processedInput.goalCompleted
308
320
  });
309
- const toolUses = input.role === "tool-use" && input.toolCall ? registerToolUse(state.toolUses, input.toolCall) : state.toolUses;
321
+ const toolUses = processedInput.role === "tool-use" && processedInput.toolCall ? registerToolUse(state.toolUses, processedInput.toolCall) : state.toolUses;
310
322
  return {
311
323
  toolUses,
312
324
  messages: [...state.messages, message]
@@ -583,73 +595,57 @@ function toChatMessages(conversation) {
583
595
  return result;
584
596
  }
585
597
  // src/context.ts
586
- function getRecentMessages(conversation, count, options) {
587
- const includeHidden = options?.includeHidden ?? false;
588
- const includeSystem = options?.includeSystem ?? false;
589
- const filtered = conversation.messages.filter((m) => {
590
- if (!includeHidden && m.hidden)
591
- return false;
592
- if (!includeSystem && m.role === "system")
593
- return false;
594
- return true;
595
- });
596
- return filtered.slice(-count);
597
- }
598
- function truncateFromPosition(conversation, position, options, environment) {
599
- const preserveSystem = options?.preserveSystemMessages ?? true;
600
- const resolvedEnvironment = resolveConversationEnvironment(environment);
601
- const now = resolvedEnvironment.now();
602
- const systemMessages = preserveSystem ? conversation.messages.filter((m) => m.role === "system" && m.position < position) : [];
603
- const keptMessages = conversation.messages.filter((m) => m.position >= position);
604
- const allMessages = [...systemMessages, ...keptMessages];
605
- const renumbered = allMessages.map((message, index) => createMessage({
606
- id: message.id,
607
- role: message.role,
608
- content: typeof message.content === "string" ? message.content : [...message.content],
609
- position: index,
610
- createdAt: message.createdAt,
611
- metadata: { ...message.metadata },
612
- hidden: message.hidden,
613
- toolCall: message.toolCall ? { ...message.toolCall } : undefined,
614
- toolResult: message.toolResult ? { ...message.toolResult } : undefined,
615
- tokenUsage: message.tokenUsage ? { ...message.tokenUsage } : undefined,
616
- goalCompleted: message.goalCompleted
617
- }));
618
- return toReadonly({
619
- ...conversation,
620
- messages: renumbered,
621
- updatedAt: now
622
- });
623
- }
624
- function estimateConversationTokens(conversation, estimateTokens) {
625
- return conversation.messages.reduce((total, message) => total + estimateTokens(message), 0);
626
- }
627
- function simpleTokenEstimator(message) {
628
- const text = messageText(message);
629
- return Math.ceil(text.length / 4);
598
+ function estimateConversationTokens(conversation, estimateTokens, environment) {
599
+ let estimator = estimateTokens;
600
+ let env = environment;
601
+ if (!environment && estimateTokens && isConversationEnvironmentParameter(estimateTokens)) {
602
+ env = estimateTokens;
603
+ estimator = undefined;
604
+ }
605
+ const resolvedEnvironment = resolveConversationEnvironment(env);
606
+ const finalEstimator = typeof estimator === "function" ? estimator : resolvedEnvironment.estimateTokens;
607
+ return conversation.messages.reduce((total, message) => total + finalEstimator(message), 0);
630
608
  }
631
- function truncateToTokenLimit(conversation, maxTokens, estimateTokens, options, environment) {
632
- const preserveSystem = options?.preserveSystemMessages ?? true;
633
- const preserveLastN = options?.preserveLastN ?? 0;
634
- const currentTokens = estimateConversationTokens(conversation, estimateTokens);
609
+ function truncateToTokenLimit(conversation, maxTokens, optionsOrEstimator, environment) {
610
+ let options = {};
611
+ let env = environment;
612
+ if (typeof optionsOrEstimator === "function") {
613
+ options = { estimateTokens: optionsOrEstimator };
614
+ } else if (optionsOrEstimator) {
615
+ if (!environment && isConversationEnvironmentParameter(optionsOrEstimator)) {
616
+ const candidate = optionsOrEstimator;
617
+ const hasEnvFields = !!(candidate["now"] || candidate["randomId"] || Array.isArray(candidate["plugins"]) && candidate["plugins"].length > 0);
618
+ if (hasEnvFields) {
619
+ env = optionsOrEstimator;
620
+ } else {
621
+ options = optionsOrEstimator;
622
+ }
623
+ } else {
624
+ options = optionsOrEstimator;
625
+ }
626
+ }
627
+ const resolvedEnvironment = resolveConversationEnvironment(env);
628
+ const estimator = options.estimateTokens ?? resolvedEnvironment.estimateTokens;
629
+ const preserveSystem = options.preserveSystemMessages ?? true;
630
+ const preserveLastN = options.preserveLastN ?? 0;
631
+ const currentTokens = estimateConversationTokens(conversation, estimator, resolvedEnvironment);
635
632
  if (currentTokens <= maxTokens) {
636
633
  return conversation;
637
634
  }
638
- const resolvedEnvironment = resolveConversationEnvironment(environment);
639
635
  const now = resolvedEnvironment.now();
640
636
  const systemMessages = preserveSystem ? conversation.messages.filter((m) => m.role === "system") : [];
641
637
  const nonSystemMessages = conversation.messages.filter((m) => m.role !== "system");
642
638
  const protectedMessages = preserveLastN > 0 ? nonSystemMessages.slice(-preserveLastN) : [];
643
639
  const removableMessages = preserveLastN > 0 ? nonSystemMessages.slice(0, -preserveLastN) : nonSystemMessages;
644
- const systemTokens = systemMessages.reduce((sum, m) => sum + estimateTokens(m), 0);
645
- const protectedTokens = protectedMessages.reduce((sum, m) => sum + estimateTokens(m), 0);
640
+ const systemTokens = systemMessages.reduce((sum, m) => sum + estimator(m), 0);
641
+ const protectedTokens = protectedMessages.reduce((sum, m) => sum + estimator(m), 0);
646
642
  const availableTokens = maxTokens - systemTokens - protectedTokens;
647
643
  if (availableTokens <= 0) {
648
644
  const allMessages2 = [...systemMessages, ...protectedMessages];
649
645
  const renumbered2 = allMessages2.map((message, index) => createMessage({
650
646
  id: message.id,
651
647
  role: message.role,
652
- content: typeof message.content === "string" ? message.content : [...message.content],
648
+ content: copyContent(message.content),
653
649
  position: index,
654
650
  createdAt: message.createdAt,
655
651
  metadata: { ...message.metadata },
@@ -669,7 +665,7 @@ function truncateToTokenLimit(conversation, maxTokens, estimateTokens, options,
669
665
  let usedTokens = 0;
670
666
  for (let i = removableMessages.length - 1;i >= 0; i--) {
671
667
  const message = removableMessages[i];
672
- const messageTokens = estimateTokens(message);
668
+ const messageTokens = estimator(message);
673
669
  if (usedTokens + messageTokens <= availableTokens) {
674
670
  keptRemovable.unshift(message);
675
671
  usedTokens += messageTokens;
@@ -682,7 +678,45 @@ function truncateToTokenLimit(conversation, maxTokens, estimateTokens, options,
682
678
  const renumbered = allMessages.map((message, index) => createMessage({
683
679
  id: message.id,
684
680
  role: message.role,
685
- content: typeof message.content === "string" ? message.content : [...message.content],
681
+ content: copyContent(message.content),
682
+ position: index,
683
+ createdAt: message.createdAt,
684
+ metadata: { ...message.metadata },
685
+ hidden: message.hidden,
686
+ toolCall: message.toolCall ? { ...message.toolCall } : undefined,
687
+ toolResult: message.toolResult ? { ...message.toolResult } : undefined,
688
+ tokenUsage: message.tokenUsage ? { ...message.tokenUsage } : undefined,
689
+ goalCompleted: message.goalCompleted
690
+ }));
691
+ return toReadonly({
692
+ ...conversation,
693
+ messages: renumbered,
694
+ updatedAt: now
695
+ });
696
+ }
697
+ function getRecentMessages(conversation, count, options) {
698
+ const includeHidden = options?.includeHidden ?? false;
699
+ const includeSystem = options?.includeSystem ?? false;
700
+ const filtered = conversation.messages.filter((m) => {
701
+ if (!includeHidden && m.hidden)
702
+ return false;
703
+ if (!includeSystem && m.role === "system")
704
+ return false;
705
+ return true;
706
+ });
707
+ return filtered.slice(-count);
708
+ }
709
+ function truncateFromPosition(conversation, position, options, environment) {
710
+ const preserveSystem = options?.preserveSystemMessages ?? true;
711
+ const resolvedEnvironment = resolveConversationEnvironment(environment);
712
+ const now = resolvedEnvironment.now();
713
+ const systemMessages = preserveSystem ? conversation.messages.filter((m) => m.role === "system" && m.position < position) : [];
714
+ const keptMessages = conversation.messages.filter((m) => m.position >= position);
715
+ const allMessages = [...systemMessages, ...keptMessages];
716
+ const renumbered = allMessages.map((message, index) => createMessage({
717
+ id: message.id,
718
+ role: message.role,
719
+ content: copyContent(message.content),
686
720
  position: index,
687
721
  createdAt: message.createdAt,
688
722
  metadata: { ...message.metadata },
@@ -875,8 +909,8 @@ function createDraft(initial) {
875
909
  current = truncateFromPosition(current, position, options);
876
910
  return draft;
877
911
  },
878
- truncateToTokenLimit: (maxTokens, estimateTokens, options) => {
879
- current = truncateToTokenLimit(current, maxTokens, estimateTokens, options);
912
+ truncateToTokenLimit: (maxTokens, options) => {
913
+ current = truncateToTokenLimit(current, maxTokens, options);
880
914
  return draft;
881
915
  }
882
916
  };
@@ -893,7 +927,291 @@ function withConversation(conversation, fn) {
893
927
  function pipeConversation(conversation, ...fns) {
894
928
  return fns.reduce((current, fn) => fn(current), conversation);
895
929
  }
930
+ // src/history.ts
931
+ class ConversationHistoryEvent extends CustomEvent {
932
+ constructor(type, detail) {
933
+ super(type, { detail });
934
+ }
935
+ }
936
+
937
+ class ConversationHistory extends EventTarget {
938
+ currentNode;
939
+ environment;
940
+ constructor(initial, environment) {
941
+ super();
942
+ this.environment = resolveConversationEnvironment(environment);
943
+ this.currentNode = {
944
+ conversation: initial,
945
+ parent: null,
946
+ children: []
947
+ };
948
+ }
949
+ notifyChange(type) {
950
+ const detail = {
951
+ type,
952
+ conversation: this.current
953
+ };
954
+ this.dispatchEvent(new ConversationHistoryEvent("change", detail));
955
+ this.dispatchEvent(new ConversationHistoryEvent(type, detail));
956
+ }
957
+ addEventListener(type, callback, options) {
958
+ if (!callback)
959
+ return;
960
+ super.addEventListener(type, callback, options);
961
+ const unsubscribe = () => this.removeEventListener(type, callback, options);
962
+ return unsubscribe;
963
+ }
964
+ subscribe(run) {
965
+ run(this.current);
966
+ const handler = (event) => {
967
+ if (event instanceof ConversationHistoryEvent) {
968
+ run(event.detail.conversation);
969
+ }
970
+ };
971
+ const unsubscribe = this.addEventListener("change", handler);
972
+ return unsubscribe || (() => {});
973
+ }
974
+ getSnapshot() {
975
+ return this.current;
976
+ }
977
+ get current() {
978
+ return this.currentNode.conversation;
979
+ }
980
+ get canUndo() {
981
+ return this.currentNode.parent !== null;
982
+ }
983
+ get canRedo() {
984
+ return this.currentNode.children.length > 0;
985
+ }
986
+ get env() {
987
+ return this.environment;
988
+ }
989
+ get branchCount() {
990
+ return this.currentNode.parent ? this.currentNode.parent.children.length : 1;
991
+ }
992
+ get branchIndex() {
993
+ if (!this.currentNode.parent)
994
+ return 0;
995
+ return this.currentNode.parent.children.indexOf(this.currentNode);
996
+ }
997
+ get redoCount() {
998
+ return this.currentNode.children.length;
999
+ }
1000
+ push(next) {
1001
+ const newNode = {
1002
+ conversation: next,
1003
+ parent: this.currentNode,
1004
+ children: []
1005
+ };
1006
+ this.currentNode.children.push(newNode);
1007
+ this.currentNode = newNode;
1008
+ this.notifyChange("push");
1009
+ }
1010
+ undo() {
1011
+ if (this.currentNode.parent) {
1012
+ this.currentNode = this.currentNode.parent;
1013
+ this.notifyChange("undo");
1014
+ return this.current;
1015
+ }
1016
+ return;
1017
+ }
1018
+ redo(childIndex = 0) {
1019
+ const next = this.currentNode.children[childIndex];
1020
+ if (next) {
1021
+ this.currentNode = next;
1022
+ this.notifyChange("redo");
1023
+ return this.current;
1024
+ }
1025
+ return;
1026
+ }
1027
+ switchToBranch(index) {
1028
+ if (this.currentNode.parent) {
1029
+ const target = this.currentNode.parent.children[index];
1030
+ if (target) {
1031
+ this.currentNode = target;
1032
+ this.notifyChange("switch");
1033
+ return this.current;
1034
+ }
1035
+ }
1036
+ return;
1037
+ }
1038
+ getPath() {
1039
+ const path = [];
1040
+ let curr = this.currentNode;
1041
+ while (curr) {
1042
+ path.unshift(curr.conversation);
1043
+ curr = curr.parent;
1044
+ }
1045
+ return path;
1046
+ }
1047
+ getMessages(options) {
1048
+ return getConversationMessages(this.current, options);
1049
+ }
1050
+ getMessageAtPosition(position) {
1051
+ return getMessageAtPosition(this.current, position);
1052
+ }
1053
+ getMessageByIdentifier(id) {
1054
+ return getMessageByIdentifier(this.current, id);
1055
+ }
1056
+ searchMessages(predicate) {
1057
+ return searchConversationMessages(this.current, predicate);
1058
+ }
1059
+ getStatistics() {
1060
+ return computeConversationStatistics(this.current);
1061
+ }
1062
+ hasSystemMessage() {
1063
+ return hasSystemMessage(this.current);
1064
+ }
1065
+ getFirstSystemMessage() {
1066
+ return getFirstSystemMessage(this.current);
1067
+ }
1068
+ getSystemMessages() {
1069
+ return getSystemMessages(this.current);
1070
+ }
1071
+ serialize() {
1072
+ return serializeConversation(this.current);
1073
+ }
1074
+ toChatMessages() {
1075
+ return toChatMessages(this.current);
1076
+ }
1077
+ estimateTokens(estimator) {
1078
+ return estimateConversationTokens(this.current, estimator, this.env);
1079
+ }
1080
+ getRecentMessages(count, options) {
1081
+ return getRecentMessages(this.current, count, options);
1082
+ }
1083
+ getStreamingMessage() {
1084
+ return getStreamingMessage(this.current);
1085
+ }
1086
+ appendMessages(...inputs) {
1087
+ this.push(appendMessages(this.current, ...inputs, this.env));
1088
+ }
1089
+ appendUserMessage(content, metadata) {
1090
+ this.push(appendUserMessage(this.current, content, metadata, this.env));
1091
+ }
1092
+ appendAssistantMessage(content, metadata) {
1093
+ this.push(appendAssistantMessage(this.current, content, metadata, this.env));
1094
+ }
1095
+ appendSystemMessage(content, metadata) {
1096
+ this.push(appendSystemMessage(this.current, content, metadata, this.env));
1097
+ }
1098
+ prependSystemMessage(content, metadata) {
1099
+ this.push(prependSystemMessage(this.current, content, metadata, this.env));
1100
+ }
1101
+ replaceSystemMessage(content, metadata) {
1102
+ this.push(replaceSystemMessage(this.current, content, metadata, this.env));
1103
+ }
1104
+ collapseSystemMessages() {
1105
+ this.push(collapseSystemMessages(this.current, this.env));
1106
+ }
1107
+ redactMessageAtPosition(position, placeholder) {
1108
+ this.push(redactMessageAtPosition(this.current, position, placeholder, this.env));
1109
+ }
1110
+ truncateFromPosition(position, options) {
1111
+ this.push(truncateFromPosition(this.current, position, options, this.env));
1112
+ }
1113
+ truncateToTokenLimit(maxTokens, options) {
1114
+ this.push(truncateToTokenLimit(this.current, maxTokens, options, this.env));
1115
+ }
1116
+ appendStreamingMessage(role, metadata) {
1117
+ const { conversation, messageId } = appendStreamingMessage(this.current, role, metadata, this.env);
1118
+ this.push(conversation);
1119
+ return messageId;
1120
+ }
1121
+ updateStreamingMessage(messageId, content) {
1122
+ this.push(updateStreamingMessage(this.current, messageId, content, this.env));
1123
+ }
1124
+ finalizeStreamingMessage(messageId, options) {
1125
+ this.push(finalizeStreamingMessage(this.current, messageId, options, this.env));
1126
+ }
1127
+ cancelStreamingMessage(messageId) {
1128
+ this.push(cancelStreamingMessage(this.current, messageId, this.env));
1129
+ }
1130
+ toJSON() {
1131
+ const getPath = (node) => {
1132
+ const path = [];
1133
+ let curr = node;
1134
+ while (curr.parent) {
1135
+ path.unshift(curr.parent.children.indexOf(curr));
1136
+ curr = curr.parent;
1137
+ }
1138
+ return path;
1139
+ };
1140
+ const serializeNode = (node) => ({
1141
+ conversation: serializeConversation(node.conversation),
1142
+ children: node.children.map(serializeNode)
1143
+ });
1144
+ let root = this.currentNode;
1145
+ while (root.parent) {
1146
+ root = root.parent;
1147
+ }
1148
+ return {
1149
+ root: serializeNode(root),
1150
+ currentPath: getPath(this.currentNode)
1151
+ };
1152
+ }
1153
+ static from(json, environment) {
1154
+ const rootConv = deserializeConversation(json.root.conversation);
1155
+ const history = new ConversationHistory(rootConv, environment);
1156
+ const buildTree = (nodeJSON, parentNode) => {
1157
+ const nodeConv = deserializeConversation(nodeJSON.conversation);
1158
+ const node = {
1159
+ conversation: nodeConv,
1160
+ parent: parentNode,
1161
+ children: []
1162
+ };
1163
+ node.children = nodeJSON.children.map((child) => buildTree(child, node));
1164
+ return node;
1165
+ };
1166
+ const h = history;
1167
+ const rootNode = h.currentNode;
1168
+ rootNode.children = json.root.children.map((child) => buildTree(child, rootNode));
1169
+ let current = rootNode;
1170
+ for (const index of json.currentPath) {
1171
+ const target = current.children[index];
1172
+ if (target) {
1173
+ current = target;
1174
+ }
1175
+ }
1176
+ h.currentNode = current;
1177
+ return history;
1178
+ }
1179
+ bind(fn) {
1180
+ return bindToConversationHistory(this, fn);
1181
+ }
1182
+ [Symbol.dispose]() {
1183
+ let root = this.currentNode;
1184
+ while (root?.parent) {
1185
+ root = root.parent;
1186
+ }
1187
+ const clearNode = (node) => {
1188
+ for (const child of node.children) {
1189
+ clearNode(child);
1190
+ }
1191
+ node.children = [];
1192
+ const n = node;
1193
+ n.parent = null;
1194
+ n.conversation = null;
1195
+ };
1196
+ if (root)
1197
+ clearNode(root);
1198
+ }
1199
+ }
1200
+ function bindToConversationHistory(history, fn) {
1201
+ return (...args) => {
1202
+ const boundFn = fn;
1203
+ const result = boundFn(history.current, ...args, history.env);
1204
+ if (isConversation(result)) {
1205
+ history.push(result);
1206
+ }
1207
+ return result;
1208
+ };
1209
+ }
1210
+ function isConversation(value) {
1211
+ return value !== null && typeof value === "object" && typeof value.id === "string" && typeof value.status === "string" && value.metadata !== null && typeof value.metadata === "object" && Array.isArray(value.tags) && Array.isArray(value.messages) && typeof value.createdAt === "string" && typeof value.updatedAt === "string";
1212
+ }
896
1213
  export {
1214
+ withEnvironment,
897
1215
  withConversation,
898
1216
  updateStreamingMessage,
899
1217
  truncateToTokenLimit,
@@ -945,12 +1263,14 @@ export {
945
1263
  computeConversationStatistics,
946
1264
  collapseSystemMessages,
947
1265
  cancelStreamingMessage,
1266
+ bindToConversationHistory,
948
1267
  appendUserMessage,
949
1268
  appendSystemMessage,
950
1269
  appendStreamingMessage,
951
1270
  appendMessages,
952
1271
  appendAssistantMessage,
953
- ConversationalistError
1272
+ ConversationalistError,
1273
+ ConversationHistory
954
1274
  };
955
1275
 
956
- //# debugId=A73ACE8C678CC64D64756E2164756E21
1276
+ //# debugId=A4607F063A1411CC64756E2164756E21