conversationalist 0.0.10 → 0.0.11
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 +89 -15
- package/dist/adapters/anthropic/index.d.ts.map +1 -1
- package/dist/adapters/anthropic/index.js +255 -2
- package/dist/adapters/anthropic/index.js.map +8 -4
- package/dist/adapters/gemini/index.d.ts.map +1 -1
- package/dist/adapters/gemini/index.js +255 -3
- package/dist/adapters/gemini/index.js.map +8 -4
- package/dist/adapters/openai/index.d.ts.map +1 -1
- package/dist/adapters/openai/index.js +247 -3
- package/dist/adapters/openai/index.js.map +8 -4
- package/dist/context.d.ts +6 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/conversation/append.d.ts +5 -0
- package/dist/conversation/append.d.ts.map +1 -1
- package/dist/conversation/create.d.ts +9 -0
- package/dist/conversation/create.d.ts.map +1 -1
- package/dist/conversation/index.d.ts +8 -3
- package/dist/conversation/index.d.ts.map +1 -1
- package/dist/conversation/integrity.d.ts +16 -0
- package/dist/conversation/integrity.d.ts.map +1 -0
- package/dist/conversation/modify.d.ts +8 -2
- package/dist/conversation/modify.d.ts.map +1 -1
- package/dist/conversation/serialization.d.ts +0 -17
- package/dist/conversation/serialization.d.ts.map +1 -1
- package/dist/conversation/system-messages.d.ts.map +1 -1
- package/dist/conversation/tool-interactions.d.ts +45 -0
- package/dist/conversation/tool-interactions.d.ts.map +1 -0
- package/dist/conversation/transform.d.ts.map +1 -1
- package/dist/conversation/validation.d.ts +8 -0
- package/dist/conversation/validation.d.ts.map +1 -0
- package/dist/errors.d.ts +6 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/export/index.js +249 -12
- package/dist/export/index.js.map +10 -6
- package/dist/history.d.ts +4 -1
- package/dist/history.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +604 -231
- package/dist/index.js.map +24 -13
- package/dist/markdown/index.js +595 -215
- package/dist/markdown/index.js.map +22 -12
- package/dist/schemas/index.js +35 -19
- package/dist/schemas/index.js.map +3 -3
- package/dist/schemas.d.ts +15 -35
- package/dist/schemas.d.ts.map +1 -1
- package/dist/streaming.d.ts.map +1 -1
- package/dist/types.d.ts +0 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/utilities/index.d.ts +0 -1
- package/dist/utilities/index.d.ts.map +1 -1
- package/dist/utilities/markdown.d.ts.map +1 -1
- package/dist/utilities/tool-calls.d.ts +2 -6
- package/dist/utilities/tool-calls.d.ts.map +1 -1
- package/dist/utilities/tool-results.d.ts.map +1 -1
- package/dist/utilities/transient.d.ts.map +1 -1
- package/dist/utilities.d.ts +0 -1
- package/dist/utilities.d.ts.map +1 -1
- package/dist/versioning/index.d.ts +0 -1
- package/dist/versioning/index.d.ts.map +1 -1
- package/dist/versioning/index.js +1 -52
- package/dist/versioning/index.js.map +4 -5
- package/dist/with-conversation.d.ts +4 -1
- package/dist/with-conversation.d.ts.map +1 -1
- package/package.json +6 -4
- package/dist/conversation.d.ts +0 -109
- package/dist/conversation.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -23,6 +23,12 @@ function copyContent(content) {
|
|
|
23
23
|
}
|
|
24
24
|
// src/schemas.ts
|
|
25
25
|
import { z } from "zod";
|
|
26
|
+
var isPlainObject = (value) => {
|
|
27
|
+
if (!value || typeof value !== "object")
|
|
28
|
+
return false;
|
|
29
|
+
const prototype = Reflect.getPrototypeOf(value);
|
|
30
|
+
return prototype === Object.prototype || prototype === null;
|
|
31
|
+
};
|
|
26
32
|
function toMultiModalContent(value) {
|
|
27
33
|
const result = { type: value.type };
|
|
28
34
|
if (value.text !== undefined)
|
|
@@ -33,14 +39,28 @@ function toMultiModalContent(value) {
|
|
|
33
39
|
result.mimeType = value.mimeType;
|
|
34
40
|
return result;
|
|
35
41
|
}
|
|
36
|
-
var jsonValueSchema = z.lazy(() =>
|
|
37
|
-
z.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
var jsonValueSchema = z.lazy(() => {
|
|
43
|
+
const jsonObjectSchema = z.preprocess((value, ctx) => {
|
|
44
|
+
if (!isPlainObject(value)) {
|
|
45
|
+
ctx.addIssue({
|
|
46
|
+
code: z.ZodIssueCode.custom,
|
|
47
|
+
message: "expected a plain object"
|
|
48
|
+
});
|
|
49
|
+
return z.NEVER;
|
|
50
|
+
}
|
|
51
|
+
return value;
|
|
52
|
+
}, z.record(z.string(), jsonValueSchema));
|
|
53
|
+
return z.union([
|
|
54
|
+
z.string(),
|
|
55
|
+
z.number().refine((value) => Number.isFinite(value), {
|
|
56
|
+
message: "expected a finite number"
|
|
57
|
+
}),
|
|
58
|
+
z.boolean(),
|
|
59
|
+
z.null(),
|
|
60
|
+
z.array(jsonValueSchema),
|
|
61
|
+
jsonObjectSchema
|
|
62
|
+
]);
|
|
63
|
+
});
|
|
44
64
|
var multiModalContentSchema = z.discriminatedUnion("type", [
|
|
45
65
|
z.object({
|
|
46
66
|
type: z.literal("text"),
|
|
@@ -66,16 +86,12 @@ var toolCallSchema = z.object({
|
|
|
66
86
|
id: z.string(),
|
|
67
87
|
name: z.string(),
|
|
68
88
|
arguments: jsonValueSchema
|
|
69
|
-
});
|
|
89
|
+
}).strict();
|
|
70
90
|
var toolResultSchema = z.object({
|
|
71
91
|
callId: z.string(),
|
|
72
92
|
outcome: z.enum(["success", "error"]),
|
|
73
|
-
content: jsonValueSchema
|
|
74
|
-
|
|
75
|
-
toolName: z.string().optional(),
|
|
76
|
-
result: jsonValueSchema.optional(),
|
|
77
|
-
error: z.string().optional()
|
|
78
|
-
});
|
|
93
|
+
content: jsonValueSchema
|
|
94
|
+
}).strict();
|
|
79
95
|
var tokenUsageSchema = z.object({
|
|
80
96
|
prompt: z.number().int().min(0),
|
|
81
97
|
completion: z.number().int().min(0),
|
|
@@ -90,7 +106,7 @@ var messageInputSchema = z.object({
|
|
|
90
106
|
toolResult: toolResultSchema.optional(),
|
|
91
107
|
tokenUsage: tokenUsageSchema.optional(),
|
|
92
108
|
goalCompleted: z.boolean().optional()
|
|
93
|
-
});
|
|
109
|
+
}).strict();
|
|
94
110
|
var messageSchema = z.object({
|
|
95
111
|
id: z.string(),
|
|
96
112
|
role: messageRoleSchema,
|
|
@@ -103,7 +119,7 @@ var messageSchema = z.object({
|
|
|
103
119
|
toolResult: toolResultSchema.optional(),
|
|
104
120
|
tokenUsage: tokenUsageSchema.optional(),
|
|
105
121
|
goalCompleted: z.boolean().optional()
|
|
106
|
-
}).
|
|
122
|
+
}).strict();
|
|
107
123
|
var conversationStatusSchema = z.enum([
|
|
108
124
|
"active",
|
|
109
125
|
"archived",
|
|
@@ -120,7 +136,7 @@ var conversationShape = {
|
|
|
120
136
|
createdAt: z.string(),
|
|
121
137
|
updatedAt: z.string()
|
|
122
138
|
};
|
|
123
|
-
var conversationSchema = z.object(conversationShape);
|
|
139
|
+
var conversationSchema = z.object(conversationShape).strict();
|
|
124
140
|
// src/utilities/content.ts
|
|
125
141
|
function toMultiModalArray(input) {
|
|
126
142
|
if (typeof input === "string")
|
|
@@ -203,6 +219,160 @@ function pairToolCallsWithResults(messages) {
|
|
|
203
219
|
}
|
|
204
220
|
return pairs;
|
|
205
221
|
}
|
|
222
|
+
// src/errors.ts
|
|
223
|
+
class ConversationalistError extends Error {
|
|
224
|
+
code;
|
|
225
|
+
context;
|
|
226
|
+
cause;
|
|
227
|
+
constructor(code, message, options) {
|
|
228
|
+
super(message);
|
|
229
|
+
this.name = "ConversationalistError";
|
|
230
|
+
this.code = code;
|
|
231
|
+
this.context = options?.context;
|
|
232
|
+
this.cause = options?.cause;
|
|
233
|
+
if (Error.captureStackTrace) {
|
|
234
|
+
Error.captureStackTrace(this, ConversationalistError);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
toDetailedString() {
|
|
238
|
+
const parts = [`[${this.code}] ${this.message}`];
|
|
239
|
+
if (this.context && Object.keys(this.context).length > 0) {
|
|
240
|
+
parts.push(`Context: ${JSON.stringify(this.context, null, 2)}`);
|
|
241
|
+
}
|
|
242
|
+
if (this.cause) {
|
|
243
|
+
parts.push(`Caused by: ${this.cause.message}`);
|
|
244
|
+
}
|
|
245
|
+
return parts.join(`
|
|
246
|
+
`);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
function createLockedError(conversationId) {
|
|
250
|
+
return new ConversationalistError("error:locked", `conversation ${conversationId} is locked (concurrent modification detected)`, { context: { conversationId } });
|
|
251
|
+
}
|
|
252
|
+
function createInvalidInputError(message, context) {
|
|
253
|
+
return new ConversationalistError("error:invalid-input", message, { context });
|
|
254
|
+
}
|
|
255
|
+
function createInvalidPositionError(expected, actual) {
|
|
256
|
+
return new ConversationalistError("error:invalid-position", `invalid position: expected ${expected}, got ${actual}`, { context: { expected, actual } });
|
|
257
|
+
}
|
|
258
|
+
function createInvalidToolReferenceError(callId) {
|
|
259
|
+
return new ConversationalistError("error:invalid-tool-reference", `tool result references non-existent tool-use: ${callId}`, { context: { callId } });
|
|
260
|
+
}
|
|
261
|
+
function createDuplicateIdError(id) {
|
|
262
|
+
return new ConversationalistError("error:duplicate-id", `conversation with id ${id} already exists`, { context: { id } });
|
|
263
|
+
}
|
|
264
|
+
function createNotFoundError(id) {
|
|
265
|
+
return new ConversationalistError("error:not-found", `conversation with id ${id} not found`, {
|
|
266
|
+
context: { id }
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
function createSerializationError(message, cause) {
|
|
270
|
+
return new ConversationalistError("error:serialization", message, { cause });
|
|
271
|
+
}
|
|
272
|
+
function createValidationError(message, context, cause) {
|
|
273
|
+
return new ConversationalistError("error:validation", message, { context, cause });
|
|
274
|
+
}
|
|
275
|
+
function createIntegrityError(message, context) {
|
|
276
|
+
return new ConversationalistError("error:integrity", message, { context });
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// src/conversation/integrity.ts
|
|
280
|
+
function validateConversationIntegrity(conversation) {
|
|
281
|
+
const issues = [];
|
|
282
|
+
const seenIds = new Set;
|
|
283
|
+
conversation.ids.forEach((id, index) => {
|
|
284
|
+
if (seenIds.has(id)) {
|
|
285
|
+
issues.push({
|
|
286
|
+
code: "integrity:duplicate-message-id",
|
|
287
|
+
message: `duplicate message id in ids: ${id}`,
|
|
288
|
+
data: { id, position: index }
|
|
289
|
+
});
|
|
290
|
+
} else {
|
|
291
|
+
seenIds.add(id);
|
|
292
|
+
}
|
|
293
|
+
if (!conversation.messages[id]) {
|
|
294
|
+
issues.push({
|
|
295
|
+
code: "integrity:missing-message",
|
|
296
|
+
message: `missing message for id ${id}`,
|
|
297
|
+
data: { id, position: index }
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
for (const id of Object.keys(conversation.messages)) {
|
|
302
|
+
if (!seenIds.has(id)) {
|
|
303
|
+
issues.push({
|
|
304
|
+
code: "integrity:unlisted-message",
|
|
305
|
+
message: `message ${id} is not listed in ids`,
|
|
306
|
+
data: { id }
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
const toolUses = new Map;
|
|
311
|
+
conversation.ids.forEach((id, index) => {
|
|
312
|
+
const message = conversation.messages[id];
|
|
313
|
+
if (!message)
|
|
314
|
+
return;
|
|
315
|
+
if (message.role === "tool-use" && message.toolCall) {
|
|
316
|
+
if (toolUses.has(message.toolCall.id)) {
|
|
317
|
+
issues.push({
|
|
318
|
+
code: "integrity:duplicate-tool-call",
|
|
319
|
+
message: `duplicate toolCall.id ${message.toolCall.id}`,
|
|
320
|
+
data: { toolCallId: message.toolCall.id, messageId: message.id }
|
|
321
|
+
});
|
|
322
|
+
} else {
|
|
323
|
+
toolUses.set(message.toolCall.id, { position: index, messageId: message.id });
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
conversation.ids.forEach((id, index) => {
|
|
328
|
+
const message = conversation.messages[id];
|
|
329
|
+
if (!message)
|
|
330
|
+
return;
|
|
331
|
+
if (message.role === "tool-result" && message.toolResult) {
|
|
332
|
+
const toolUse = toolUses.get(message.toolResult.callId);
|
|
333
|
+
if (!toolUse) {
|
|
334
|
+
issues.push({
|
|
335
|
+
code: "integrity:orphan-tool-result",
|
|
336
|
+
message: `tool-result references missing tool-use ${message.toolResult.callId}`,
|
|
337
|
+
data: { callId: message.toolResult.callId, messageId: message.id }
|
|
338
|
+
});
|
|
339
|
+
} else if (toolUse.position >= index) {
|
|
340
|
+
issues.push({
|
|
341
|
+
code: "integrity:tool-result-before-call",
|
|
342
|
+
message: `tool-result ${message.toolResult.callId} occurs before tool-use`,
|
|
343
|
+
data: {
|
|
344
|
+
callId: message.toolResult.callId,
|
|
345
|
+
messageId: message.id,
|
|
346
|
+
toolUseMessageId: toolUse.messageId
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
return issues;
|
|
353
|
+
}
|
|
354
|
+
function assertConversationIntegrity(conversation) {
|
|
355
|
+
const issues = validateConversationIntegrity(conversation);
|
|
356
|
+
if (issues.length === 0)
|
|
357
|
+
return;
|
|
358
|
+
throw createIntegrityError("conversation integrity check failed", { issues });
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// src/conversation/validation.ts
|
|
362
|
+
function assertConversationSafe(conversation) {
|
|
363
|
+
const parsed = conversationSchema.safeParse(conversation);
|
|
364
|
+
if (!parsed.success) {
|
|
365
|
+
throw createValidationError("conversation failed schema validation", {
|
|
366
|
+
issues: parsed.error.issues
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
assertConversationIntegrity(conversation);
|
|
370
|
+
}
|
|
371
|
+
function ensureConversationSafe(conversation) {
|
|
372
|
+
assertConversationSafe(conversation);
|
|
373
|
+
return conversation;
|
|
374
|
+
}
|
|
375
|
+
|
|
206
376
|
// src/utilities/message-store.ts
|
|
207
377
|
function getOrderedMessages(conversation) {
|
|
208
378
|
const ordered = [];
|
|
@@ -259,7 +429,7 @@ function stripTransientMetadata(conversation) {
|
|
|
259
429
|
}
|
|
260
430
|
return toReadonly(baseMessage);
|
|
261
431
|
});
|
|
262
|
-
return toReadonly({
|
|
432
|
+
return ensureConversationSafe(toReadonly({
|
|
263
433
|
schemaVersion: conversation.schemaVersion,
|
|
264
434
|
id: conversation.id,
|
|
265
435
|
title: conversation.title,
|
|
@@ -269,7 +439,7 @@ function stripTransientMetadata(conversation) {
|
|
|
269
439
|
messages: toIdRecord(strippedMessages),
|
|
270
440
|
createdAt: conversation.createdAt,
|
|
271
441
|
updatedAt: conversation.updatedAt
|
|
272
|
-
});
|
|
442
|
+
}));
|
|
273
443
|
}
|
|
274
444
|
// src/environment.ts
|
|
275
445
|
function simpleTokenEstimator(message) {
|
|
@@ -302,64 +472,43 @@ function withEnvironment(environment, fn) {
|
|
|
302
472
|
return (...args) => fn(...args, environment);
|
|
303
473
|
}
|
|
304
474
|
|
|
305
|
-
// src/errors.ts
|
|
306
|
-
class ConversationalistError extends Error {
|
|
307
|
-
code;
|
|
308
|
-
context;
|
|
309
|
-
cause;
|
|
310
|
-
constructor(code, message, options) {
|
|
311
|
-
super(message);
|
|
312
|
-
this.name = "ConversationalistError";
|
|
313
|
-
this.code = code;
|
|
314
|
-
this.context = options?.context;
|
|
315
|
-
this.cause = options?.cause;
|
|
316
|
-
if (Error.captureStackTrace) {
|
|
317
|
-
Error.captureStackTrace(this, ConversationalistError);
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
toDetailedString() {
|
|
321
|
-
const parts = [`[${this.code}] ${this.message}`];
|
|
322
|
-
if (this.context && Object.keys(this.context).length > 0) {
|
|
323
|
-
parts.push(`Context: ${JSON.stringify(this.context, null, 2)}`);
|
|
324
|
-
}
|
|
325
|
-
if (this.cause) {
|
|
326
|
-
parts.push(`Caused by: ${this.cause.message}`);
|
|
327
|
-
}
|
|
328
|
-
return parts.join(`
|
|
329
|
-
`);
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
function createLockedError(conversationId) {
|
|
333
|
-
return new ConversationalistError("error:locked", `conversation ${conversationId} is locked (concurrent modification detected)`, { context: { conversationId } });
|
|
334
|
-
}
|
|
335
|
-
function createInvalidInputError(message, context) {
|
|
336
|
-
return new ConversationalistError("error:invalid-input", message, { context });
|
|
337
|
-
}
|
|
338
|
-
function createInvalidPositionError(expected, actual) {
|
|
339
|
-
return new ConversationalistError("error:invalid-position", `invalid position: expected ${expected}, got ${actual}`, { context: { expected, actual } });
|
|
340
|
-
}
|
|
341
|
-
function createInvalidToolReferenceError(callId) {
|
|
342
|
-
return new ConversationalistError("error:invalid-tool-reference", `tool result references non-existent tool-use: ${callId}`, { context: { callId } });
|
|
343
|
-
}
|
|
344
|
-
function createDuplicateIdError(id) {
|
|
345
|
-
return new ConversationalistError("error:duplicate-id", `conversation with id ${id} already exists`, { context: { id } });
|
|
346
|
-
}
|
|
347
|
-
function createNotFoundError(id) {
|
|
348
|
-
return new ConversationalistError("error:not-found", `conversation with id ${id} not found`, {
|
|
349
|
-
context: { id }
|
|
350
|
-
});
|
|
351
|
-
}
|
|
352
|
-
function createSerializationError(message, cause) {
|
|
353
|
-
return new ConversationalistError("error:serialization", message, { cause });
|
|
354
|
-
}
|
|
355
|
-
function createValidationError(message, context, cause) {
|
|
356
|
-
return new ConversationalistError("error:validation", message, { context, cause });
|
|
357
|
-
}
|
|
358
|
-
|
|
359
475
|
// src/types.ts
|
|
360
476
|
var CURRENT_SCHEMA_VERSION = 3;
|
|
361
477
|
|
|
362
|
-
// src/conversation.ts
|
|
478
|
+
// src/conversation/create.ts
|
|
479
|
+
function createConversation(options, environment) {
|
|
480
|
+
const resolvedEnvironment = resolveConversationEnvironment(environment);
|
|
481
|
+
const now = resolvedEnvironment.now();
|
|
482
|
+
const conv = {
|
|
483
|
+
schemaVersion: CURRENT_SCHEMA_VERSION,
|
|
484
|
+
id: options?.id ?? resolvedEnvironment.randomId(),
|
|
485
|
+
title: options?.title,
|
|
486
|
+
status: options?.status ?? "active",
|
|
487
|
+
metadata: { ...options?.metadata ?? {} },
|
|
488
|
+
ids: [],
|
|
489
|
+
messages: {},
|
|
490
|
+
createdAt: now,
|
|
491
|
+
updatedAt: now
|
|
492
|
+
};
|
|
493
|
+
return ensureConversationSafe(toReadonly(conv));
|
|
494
|
+
}
|
|
495
|
+
function createConversationUnsafe(options, environment) {
|
|
496
|
+
const resolvedEnvironment = resolveConversationEnvironment(environment);
|
|
497
|
+
const now = resolvedEnvironment.now();
|
|
498
|
+
const conv = {
|
|
499
|
+
schemaVersion: CURRENT_SCHEMA_VERSION,
|
|
500
|
+
id: options?.id ?? resolvedEnvironment.randomId(),
|
|
501
|
+
title: options?.title,
|
|
502
|
+
status: options?.status ?? "active",
|
|
503
|
+
metadata: { ...options?.metadata ?? {} },
|
|
504
|
+
ids: [],
|
|
505
|
+
messages: {},
|
|
506
|
+
createdAt: now,
|
|
507
|
+
updatedAt: now
|
|
508
|
+
};
|
|
509
|
+
return toReadonly(conv);
|
|
510
|
+
}
|
|
511
|
+
// src/conversation/tool-tracking.ts
|
|
363
512
|
var buildToolUseIndex = (messages) => messages.reduce((index, message) => {
|
|
364
513
|
if (message.role === "tool-use" && message.toolCall) {
|
|
365
514
|
index.set(message.toolCall.id, { name: message.toolCall.name });
|
|
@@ -376,44 +525,37 @@ var assertToolReference = (index, callId) => {
|
|
|
376
525
|
throw createInvalidToolReferenceError(callId);
|
|
377
526
|
}
|
|
378
527
|
};
|
|
528
|
+
|
|
529
|
+
// src/conversation/append.ts
|
|
379
530
|
function partitionAppendArgs(args) {
|
|
380
|
-
|
|
531
|
+
const filtered = args.filter((arg) => arg !== undefined);
|
|
532
|
+
if (filtered.length === 0) {
|
|
381
533
|
return { inputs: [] };
|
|
382
534
|
}
|
|
383
|
-
const last =
|
|
535
|
+
const last = filtered[filtered.length - 1];
|
|
384
536
|
if (isConversationEnvironmentParameter(last)) {
|
|
385
537
|
return {
|
|
386
|
-
inputs:
|
|
538
|
+
inputs: filtered.slice(0, -1),
|
|
387
539
|
environment: last
|
|
388
540
|
};
|
|
389
541
|
}
|
|
390
|
-
return { inputs:
|
|
391
|
-
}
|
|
392
|
-
function createConversation(options, environment) {
|
|
393
|
-
const resolvedEnvironment = resolveConversationEnvironment(environment);
|
|
394
|
-
const now = resolvedEnvironment.now();
|
|
395
|
-
const conv = {
|
|
396
|
-
schemaVersion: CURRENT_SCHEMA_VERSION,
|
|
397
|
-
id: options?.id ?? resolvedEnvironment.randomId(),
|
|
398
|
-
title: options?.title,
|
|
399
|
-
status: options?.status ?? "active",
|
|
400
|
-
metadata: { ...options?.metadata ?? {} },
|
|
401
|
-
ids: [],
|
|
402
|
-
messages: {},
|
|
403
|
-
createdAt: now,
|
|
404
|
-
updatedAt: now
|
|
405
|
-
};
|
|
406
|
-
return toReadonly(conv);
|
|
542
|
+
return { inputs: filtered };
|
|
407
543
|
}
|
|
408
544
|
function appendMessages(conversation, ...args) {
|
|
545
|
+
return appendMessagesInternal(conversation, args, true);
|
|
546
|
+
}
|
|
547
|
+
function appendUnsafeMessage(conversation, input, environment) {
|
|
548
|
+
return appendMessagesInternal(conversation, [input, environment], false);
|
|
549
|
+
}
|
|
550
|
+
var appendMessagesInternal = (conversation, args, validate) => {
|
|
409
551
|
const { inputs, environment } = partitionAppendArgs(args);
|
|
410
552
|
const resolvedEnvironment = resolveConversationEnvironment(environment);
|
|
411
553
|
const now = resolvedEnvironment.now();
|
|
412
554
|
const startPosition = conversation.ids.length;
|
|
413
|
-
const initialToolUses = buildToolUseIndex(getOrderedMessages(conversation));
|
|
555
|
+
const initialToolUses = validate ? buildToolUseIndex(getOrderedMessages(conversation)) : new Map;
|
|
414
556
|
const { messages } = inputs.reduce((state, input, index) => {
|
|
415
557
|
const processedInput = resolvedEnvironment.plugins.reduce((acc, plugin) => plugin(acc), input);
|
|
416
|
-
if (processedInput.role === "tool-result" && processedInput.toolResult) {
|
|
558
|
+
if (validate && processedInput.role === "tool-result" && processedInput.toolResult) {
|
|
417
559
|
assertToolReference(state.toolUses, processedInput.toolResult.callId);
|
|
418
560
|
}
|
|
419
561
|
const normalizedContent = normalizeContent(processedInput.content);
|
|
@@ -440,7 +582,16 @@ function appendMessages(conversation, ...args) {
|
|
|
440
582
|
} else {
|
|
441
583
|
message = createMessage(baseMessage);
|
|
442
584
|
}
|
|
443
|
-
|
|
585
|
+
let toolUses = state.toolUses;
|
|
586
|
+
if (processedInput.role === "tool-use" && processedInput.toolCall) {
|
|
587
|
+
if (validate && state.toolUses.has(processedInput.toolCall.id)) {
|
|
588
|
+
throw createIntegrityError("duplicate toolCall.id in conversation", {
|
|
589
|
+
toolCallId: processedInput.toolCall.id,
|
|
590
|
+
messageId: baseMessage.id
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
toolUses = validate ? registerToolUse(state.toolUses, processedInput.toolCall) : state.toolUses;
|
|
594
|
+
}
|
|
444
595
|
return {
|
|
445
596
|
toolUses,
|
|
446
597
|
messages: [...state.messages, message]
|
|
@@ -453,17 +604,25 @@ function appendMessages(conversation, ...args) {
|
|
|
453
604
|
messages: { ...conversation.messages, ...toIdRecord(messages) },
|
|
454
605
|
updatedAt: now
|
|
455
606
|
};
|
|
456
|
-
|
|
457
|
-
|
|
607
|
+
const readonly = toReadonly(next);
|
|
608
|
+
return validate ? ensureConversationSafe(readonly) : readonly;
|
|
609
|
+
};
|
|
458
610
|
function appendUserMessage(conversation, content, metadata, environment) {
|
|
459
|
-
|
|
611
|
+
const resolvedEnvironment = isConversationEnvironmentParameter(metadata) ? metadata : environment;
|
|
612
|
+
const resolvedMetadata = isConversationEnvironmentParameter(metadata) ? undefined : metadata;
|
|
613
|
+
return appendMessages(conversation, { role: "user", content, metadata: resolvedMetadata }, resolvedEnvironment);
|
|
460
614
|
}
|
|
461
615
|
function appendAssistantMessage(conversation, content, metadata, environment) {
|
|
462
|
-
|
|
616
|
+
const resolvedEnvironment = isConversationEnvironmentParameter(metadata) ? metadata : environment;
|
|
617
|
+
const resolvedMetadata = isConversationEnvironmentParameter(metadata) ? undefined : metadata;
|
|
618
|
+
return appendMessages(conversation, { role: "assistant", content, metadata: resolvedMetadata }, resolvedEnvironment);
|
|
463
619
|
}
|
|
464
620
|
function appendSystemMessage(conversation, content, metadata, environment) {
|
|
465
|
-
|
|
621
|
+
const resolvedEnvironment = isConversationEnvironmentParameter(metadata) ? metadata : environment;
|
|
622
|
+
const resolvedMetadata = isConversationEnvironmentParameter(metadata) ? undefined : metadata;
|
|
623
|
+
return appendMessages(conversation, { role: "system", content, metadata: resolvedMetadata }, resolvedEnvironment);
|
|
466
624
|
}
|
|
625
|
+
// src/conversation/query.ts
|
|
467
626
|
function getMessages(conversation, options) {
|
|
468
627
|
const includeHidden = options?.includeHidden ?? false;
|
|
469
628
|
const ordered = getOrderedMessages(conversation);
|
|
@@ -497,6 +656,7 @@ function getStatistics(conversation) {
|
|
|
497
656
|
}, { byRole: {}, hidden: 0, withImages: 0 });
|
|
498
657
|
return { total: ordered.length, ...stats };
|
|
499
658
|
}
|
|
659
|
+
// src/conversation/system-messages.ts
|
|
500
660
|
function hasSystemMessage(conversation) {
|
|
501
661
|
return getOrderedMessages(conversation).some((m) => m.role === "system");
|
|
502
662
|
}
|
|
@@ -507,7 +667,8 @@ function getSystemMessages(conversation) {
|
|
|
507
667
|
return getOrderedMessages(conversation).filter((m) => m.role === "system");
|
|
508
668
|
}
|
|
509
669
|
function prependSystemMessage(conversation, content, metadata, environment) {
|
|
510
|
-
const resolvedEnvironment = resolveConversationEnvironment(environment);
|
|
670
|
+
const resolvedEnvironment = resolveConversationEnvironment(isConversationEnvironmentParameter(metadata) ? metadata : environment);
|
|
671
|
+
const resolvedMetadata = isConversationEnvironmentParameter(metadata) ? undefined : metadata;
|
|
511
672
|
const now = resolvedEnvironment.now();
|
|
512
673
|
const newMessage = createMessage({
|
|
513
674
|
id: resolvedEnvironment.randomId(),
|
|
@@ -515,7 +676,7 @@ function prependSystemMessage(conversation, content, metadata, environment) {
|
|
|
515
676
|
content,
|
|
516
677
|
position: 0,
|
|
517
678
|
createdAt: now,
|
|
518
|
-
metadata: { ...
|
|
679
|
+
metadata: { ...resolvedMetadata ?? {} },
|
|
519
680
|
hidden: false,
|
|
520
681
|
toolCall: undefined,
|
|
521
682
|
toolResult: undefined,
|
|
@@ -534,20 +695,21 @@ function prependSystemMessage(conversation, content, metadata, environment) {
|
|
|
534
695
|
toolResult: message.toolResult,
|
|
535
696
|
tokenUsage: message.tokenUsage
|
|
536
697
|
}));
|
|
537
|
-
return toReadonly({
|
|
698
|
+
return ensureConversationSafe(toReadonly({
|
|
538
699
|
...conversation,
|
|
539
700
|
ids: [newMessage.id, ...ordered.map((message) => message.id)],
|
|
540
701
|
messages: toIdRecord([newMessage, ...renumberedMessages]),
|
|
541
702
|
updatedAt: now
|
|
542
|
-
});
|
|
703
|
+
}));
|
|
543
704
|
}
|
|
544
705
|
function replaceSystemMessage(conversation, content, metadata, environment) {
|
|
545
|
-
const resolvedEnvironment = resolveConversationEnvironment(environment);
|
|
706
|
+
const resolvedEnvironment = resolveConversationEnvironment(isConversationEnvironmentParameter(metadata) ? metadata : environment);
|
|
707
|
+
const resolvedMetadata = isConversationEnvironmentParameter(metadata) ? undefined : metadata;
|
|
546
708
|
const now = resolvedEnvironment.now();
|
|
547
709
|
const ordered = getOrderedMessages(conversation);
|
|
548
710
|
const firstSystemIndex = ordered.findIndex((m) => m.role === "system");
|
|
549
711
|
if (firstSystemIndex === -1) {
|
|
550
|
-
return prependSystemMessage(conversation, content,
|
|
712
|
+
return prependSystemMessage(conversation, content, resolvedMetadata, resolvedEnvironment);
|
|
551
713
|
}
|
|
552
714
|
const original = ordered[firstSystemIndex];
|
|
553
715
|
const replaced = createMessage({
|
|
@@ -556,7 +718,7 @@ function replaceSystemMessage(conversation, content, metadata, environment) {
|
|
|
556
718
|
content,
|
|
557
719
|
position: original.position,
|
|
558
720
|
createdAt: original.createdAt,
|
|
559
|
-
metadata: { ...
|
|
721
|
+
metadata: { ...resolvedMetadata ?? original.metadata },
|
|
560
722
|
hidden: original.hidden,
|
|
561
723
|
toolCall: undefined,
|
|
562
724
|
toolResult: undefined,
|
|
@@ -568,13 +730,13 @@ function replaceSystemMessage(conversation, content, metadata, environment) {
|
|
|
568
730
|
messages: { ...conversation.messages, [replaced.id]: replaced },
|
|
569
731
|
updatedAt: now
|
|
570
732
|
};
|
|
571
|
-
return toReadonly(next);
|
|
733
|
+
return ensureConversationSafe(toReadonly(next));
|
|
572
734
|
}
|
|
573
735
|
function collapseSystemMessages(conversation, environment) {
|
|
574
736
|
const ordered = getOrderedMessages(conversation);
|
|
575
737
|
const systemMessages = ordered.filter((m) => m.role === "system");
|
|
576
738
|
if (systemMessages.length <= 1) {
|
|
577
|
-
return conversation;
|
|
739
|
+
return ensureConversationSafe(conversation);
|
|
578
740
|
}
|
|
579
741
|
const resolvedEnvironment = resolveConversationEnvironment(environment);
|
|
580
742
|
const now = resolvedEnvironment.now();
|
|
@@ -630,9 +792,39 @@ function collapseSystemMessages(conversation, environment) {
|
|
|
630
792
|
messages: toIdRecord(renumbered),
|
|
631
793
|
updatedAt: now
|
|
632
794
|
};
|
|
633
|
-
return toReadonly(next);
|
|
795
|
+
return ensureConversationSafe(toReadonly(next));
|
|
634
796
|
}
|
|
635
|
-
|
|
797
|
+
// src/utilities/tool-results.ts
|
|
798
|
+
function redactToolResult(toolResult, placeholder) {
|
|
799
|
+
return { ...toolResult, content: placeholder };
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
// src/conversation/modify.ts
|
|
803
|
+
var isRedactMessageOptions = (value) => {
|
|
804
|
+
if (!value || typeof value !== "object")
|
|
805
|
+
return false;
|
|
806
|
+
const candidate = value;
|
|
807
|
+
return "placeholder" in candidate || "redactToolArguments" in candidate || "redactToolResults" in candidate || "clearToolMetadata" in candidate;
|
|
808
|
+
};
|
|
809
|
+
function redactMessageAtPosition(conversation, position, placeholderOrOptions, environment) {
|
|
810
|
+
let placeholder = "[REDACTED]";
|
|
811
|
+
let options = {};
|
|
812
|
+
let env = environment;
|
|
813
|
+
if (typeof placeholderOrOptions === "string") {
|
|
814
|
+
placeholder = placeholderOrOptions;
|
|
815
|
+
} else if (placeholderOrOptions) {
|
|
816
|
+
if (!environment && isConversationEnvironmentParameter(placeholderOrOptions)) {
|
|
817
|
+
env = placeholderOrOptions;
|
|
818
|
+
} else if (isRedactMessageOptions(placeholderOrOptions)) {
|
|
819
|
+
options = placeholderOrOptions;
|
|
820
|
+
if (options.placeholder) {
|
|
821
|
+
placeholder = options.placeholder;
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
const redactToolArguments = options.redactToolArguments ?? true;
|
|
826
|
+
const redactToolResults = options.redactToolResults ?? true;
|
|
827
|
+
const clearToolMetadata = options.clearToolMetadata ?? false;
|
|
636
828
|
if (position < 0 || position >= conversation.ids.length) {
|
|
637
829
|
throw createInvalidPositionError(conversation.ids.length - 1, position);
|
|
638
830
|
}
|
|
@@ -641,6 +833,22 @@ function redactMessageAtPosition(conversation, position, placeholder = "[REDACTE
|
|
|
641
833
|
if (!original) {
|
|
642
834
|
throw createInvalidPositionError(conversation.ids.length - 1, position);
|
|
643
835
|
}
|
|
836
|
+
let toolCall = original.toolCall ? { ...original.toolCall } : undefined;
|
|
837
|
+
let toolResult = original.toolResult ? { ...original.toolResult } : undefined;
|
|
838
|
+
if (clearToolMetadata) {
|
|
839
|
+
toolCall = undefined;
|
|
840
|
+
toolResult = undefined;
|
|
841
|
+
} else {
|
|
842
|
+
if (original.role === "tool-use" && toolCall) {
|
|
843
|
+
toolCall = {
|
|
844
|
+
...toolCall,
|
|
845
|
+
arguments: redactToolArguments ? placeholder : toolCall.arguments
|
|
846
|
+
};
|
|
847
|
+
}
|
|
848
|
+
if (original.role === "tool-result" && toolResult) {
|
|
849
|
+
toolResult = redactToolResults ? redactToolResult(toolResult, placeholder) : { ...toolResult };
|
|
850
|
+
}
|
|
851
|
+
}
|
|
644
852
|
const redacted = createMessage({
|
|
645
853
|
id: original.id,
|
|
646
854
|
role: original.role,
|
|
@@ -649,11 +857,11 @@ function redactMessageAtPosition(conversation, position, placeholder = "[REDACTE
|
|
|
649
857
|
createdAt: original.createdAt,
|
|
650
858
|
metadata: { ...original.metadata },
|
|
651
859
|
hidden: original.hidden,
|
|
652
|
-
toolCall
|
|
653
|
-
toolResult
|
|
654
|
-
tokenUsage: undefined
|
|
860
|
+
toolCall,
|
|
861
|
+
toolResult,
|
|
862
|
+
tokenUsage: original.tokenUsage ? { ...original.tokenUsage } : undefined
|
|
655
863
|
});
|
|
656
|
-
const resolvedEnvironment = resolveConversationEnvironment(
|
|
864
|
+
const resolvedEnvironment = resolveConversationEnvironment(env);
|
|
657
865
|
const now = resolvedEnvironment.now();
|
|
658
866
|
const next = {
|
|
659
867
|
...conversation,
|
|
@@ -661,70 +869,62 @@ function redactMessageAtPosition(conversation, position, placeholder = "[REDACTE
|
|
|
661
869
|
messages: { ...conversation.messages, [redacted.id]: redacted },
|
|
662
870
|
updatedAt: now
|
|
663
871
|
};
|
|
664
|
-
return toReadonly(next);
|
|
872
|
+
return ensureConversationSafe(toReadonly(next));
|
|
665
873
|
}
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
messages = { ...rawMessages };
|
|
691
|
-
if (isStringArray(rawIds) && rawIds.length > 0) {
|
|
692
|
-
ids = [...rawIds];
|
|
693
|
-
} else {
|
|
694
|
-
ids = Object.values(messages).sort((a, b) => a.position - b.position).map((message) => message.id);
|
|
695
|
-
}
|
|
696
|
-
}
|
|
697
|
-
if (ids.length > 0) {
|
|
698
|
-
ids = ids.filter((id) => (id in messages));
|
|
699
|
-
const missing = Object.keys(messages).filter((id) => !ids.includes(id));
|
|
700
|
-
if (missing.length > 0) {
|
|
701
|
-
const sortedMissing = missing.sort((a, b) => (messages[a]?.position ?? 0) - (messages[b]?.position ?? 0));
|
|
702
|
-
ids = [...ids, ...sortedMissing];
|
|
703
|
-
}
|
|
704
|
-
}
|
|
705
|
-
if (!("schemaVersion" in json)) {
|
|
874
|
+
// src/conversation/serialization.ts
|
|
875
|
+
function normalizeToolResult(toolResult) {
|
|
876
|
+
if (!toolResult)
|
|
877
|
+
return;
|
|
878
|
+
return {
|
|
879
|
+
callId: toolResult.callId,
|
|
880
|
+
outcome: toolResult.outcome,
|
|
881
|
+
content: toolResult.content
|
|
882
|
+
};
|
|
883
|
+
}
|
|
884
|
+
function normalizeMessage(message) {
|
|
885
|
+
const base = {
|
|
886
|
+
id: message.id,
|
|
887
|
+
role: message.role,
|
|
888
|
+
content: message.content,
|
|
889
|
+
position: message.position,
|
|
890
|
+
createdAt: message.createdAt,
|
|
891
|
+
metadata: message.metadata,
|
|
892
|
+
hidden: message.hidden,
|
|
893
|
+
toolCall: message.toolCall ? { ...message.toolCall } : undefined,
|
|
894
|
+
toolResult: normalizeToolResult(message.toolResult),
|
|
895
|
+
tokenUsage: message.tokenUsage ? { ...message.tokenUsage } : undefined
|
|
896
|
+
};
|
|
897
|
+
if (isAssistantMessage(message)) {
|
|
706
898
|
return {
|
|
707
|
-
...
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
messages
|
|
899
|
+
...base,
|
|
900
|
+
role: "assistant",
|
|
901
|
+
goalCompleted: message.goalCompleted
|
|
711
902
|
};
|
|
712
903
|
}
|
|
713
|
-
return
|
|
904
|
+
return base;
|
|
714
905
|
}
|
|
715
906
|
function deserializeConversation(json) {
|
|
716
|
-
const
|
|
907
|
+
const parsed = conversationSchema.safeParse(json);
|
|
908
|
+
if (!parsed.success) {
|
|
909
|
+
throw createSerializationError("failed to deserialize conversation: invalid data");
|
|
910
|
+
}
|
|
911
|
+
const data = parsed.data;
|
|
717
912
|
try {
|
|
718
|
-
const
|
|
719
|
-
|
|
913
|
+
const messageIds = new Set(Object.keys(data.messages));
|
|
914
|
+
const orderedMessages = data.ids.map((id, index) => {
|
|
915
|
+
const message = data.messages[id];
|
|
720
916
|
if (!message) {
|
|
721
917
|
throw createSerializationError(`missing message for id ${id}`);
|
|
722
918
|
}
|
|
723
919
|
if (message.position !== index) {
|
|
724
920
|
throw createInvalidPositionError(index, message.position);
|
|
725
921
|
}
|
|
726
|
-
|
|
922
|
+
messageIds.delete(id);
|
|
923
|
+
return normalizeMessage(message);
|
|
727
924
|
});
|
|
925
|
+
if (messageIds.size > 0) {
|
|
926
|
+
throw createSerializationError(`messages not listed in ids: ${[...messageIds].join(", ")}`);
|
|
927
|
+
}
|
|
728
928
|
orderedMessages.reduce((state, message) => {
|
|
729
929
|
if (message.role === "tool-use" && message.toolCall) {
|
|
730
930
|
return {
|
|
@@ -736,24 +936,28 @@ function deserializeConversation(json) {
|
|
|
736
936
|
}
|
|
737
937
|
return state;
|
|
738
938
|
}, { toolUses: new Map });
|
|
739
|
-
const messageInstances = orderedMessages.map((
|
|
939
|
+
const messageInstances = orderedMessages.map((message) => createMessage(message));
|
|
740
940
|
const conv = {
|
|
741
|
-
schemaVersion:
|
|
742
|
-
id:
|
|
743
|
-
title:
|
|
744
|
-
status:
|
|
745
|
-
metadata: { ...
|
|
941
|
+
schemaVersion: data.schemaVersion,
|
|
942
|
+
id: data.id,
|
|
943
|
+
title: data.title,
|
|
944
|
+
status: data.status,
|
|
945
|
+
metadata: { ...data.metadata },
|
|
746
946
|
ids: orderedMessages.map((message) => message.id),
|
|
747
947
|
messages: toIdRecord(messageInstances),
|
|
748
|
-
createdAt:
|
|
749
|
-
updatedAt:
|
|
948
|
+
createdAt: data.createdAt,
|
|
949
|
+
updatedAt: data.updatedAt
|
|
750
950
|
};
|
|
751
|
-
|
|
951
|
+
const readonly = toReadonly(conv);
|
|
952
|
+
assertConversationIntegrity(readonly);
|
|
953
|
+
return readonly;
|
|
752
954
|
} catch (error) {
|
|
753
955
|
throw createSerializationError(`failed to deserialize conversation: ${error instanceof Error ? error.message : String(error)}`, error);
|
|
754
956
|
}
|
|
755
957
|
}
|
|
958
|
+
// src/conversation/transform.ts
|
|
756
959
|
function toChatMessages(conversation) {
|
|
960
|
+
assertConversationSafe(conversation);
|
|
757
961
|
const roleMap = {
|
|
758
962
|
user: "user",
|
|
759
963
|
assistant: "assistant",
|
|
@@ -775,6 +979,62 @@ function toChatMessages(conversation) {
|
|
|
775
979
|
}
|
|
776
980
|
return result;
|
|
777
981
|
}
|
|
982
|
+
// src/conversation/tool-interactions.ts
|
|
983
|
+
function appendToolUse(conversation, toolCall, options, environment) {
|
|
984
|
+
const resolved = resolveConversationEnvironment(isConversationEnvironmentParameter(options) ? options : environment);
|
|
985
|
+
const resolvedOptions = isConversationEnvironmentParameter(options) ? undefined : options;
|
|
986
|
+
const callId = toolCall.callId ?? resolved.randomId();
|
|
987
|
+
const toolCallMeta = {
|
|
988
|
+
id: callId,
|
|
989
|
+
name: toolCall.toolId,
|
|
990
|
+
arguments: toolCall.args
|
|
991
|
+
};
|
|
992
|
+
return appendMessages(conversation, {
|
|
993
|
+
role: "tool-use",
|
|
994
|
+
content: resolvedOptions?.content ?? "",
|
|
995
|
+
metadata: resolvedOptions?.metadata,
|
|
996
|
+
hidden: resolvedOptions?.hidden,
|
|
997
|
+
toolCall: toolCallMeta,
|
|
998
|
+
tokenUsage: resolvedOptions?.tokenUsage
|
|
999
|
+
}, resolved);
|
|
1000
|
+
}
|
|
1001
|
+
function appendToolResult(conversation, toolResult, options, environment) {
|
|
1002
|
+
const resolvedOptions = isConversationEnvironmentParameter(options) ? undefined : options;
|
|
1003
|
+
const toolResultMeta = {
|
|
1004
|
+
callId: toolResult.callId,
|
|
1005
|
+
outcome: toolResult.outcome,
|
|
1006
|
+
content: toolResult.result
|
|
1007
|
+
};
|
|
1008
|
+
return appendMessages(conversation, {
|
|
1009
|
+
role: "tool-result",
|
|
1010
|
+
content: resolvedOptions?.content ?? "",
|
|
1011
|
+
metadata: resolvedOptions?.metadata,
|
|
1012
|
+
hidden: resolvedOptions?.hidden,
|
|
1013
|
+
toolResult: toolResultMeta,
|
|
1014
|
+
tokenUsage: resolvedOptions?.tokenUsage
|
|
1015
|
+
}, isConversationEnvironmentParameter(options) ? options : environment);
|
|
1016
|
+
}
|
|
1017
|
+
function getPendingToolCalls(conversation) {
|
|
1018
|
+
const ordered = getOrderedMessages(conversation);
|
|
1019
|
+
const completed = new Set;
|
|
1020
|
+
for (const message of ordered) {
|
|
1021
|
+
if (message.role === "tool-result" && message.toolResult) {
|
|
1022
|
+
completed.add(message.toolResult.callId);
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
const pending = [];
|
|
1026
|
+
for (const message of ordered) {
|
|
1027
|
+
if (message.role === "tool-use" && message.toolCall) {
|
|
1028
|
+
if (!completed.has(message.toolCall.id)) {
|
|
1029
|
+
pending.push(message.toolCall);
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
return pending;
|
|
1034
|
+
}
|
|
1035
|
+
function getToolInteractions(conversation) {
|
|
1036
|
+
return pairToolCallsWithResults(getOrderedMessages(conversation));
|
|
1037
|
+
}
|
|
778
1038
|
// src/guards.ts
|
|
779
1039
|
function isSchema(schema, value) {
|
|
780
1040
|
return schema.safeParse(value).success;
|
|
@@ -833,6 +1093,92 @@ var cloneMessageWithPosition = (message, position, content) => {
|
|
|
833
1093
|
}
|
|
834
1094
|
return createMessage(baseMessage);
|
|
835
1095
|
};
|
|
1096
|
+
var createMessageBlock = (message, estimator) => ({
|
|
1097
|
+
messages: [message],
|
|
1098
|
+
minPosition: message.position,
|
|
1099
|
+
maxPosition: message.position,
|
|
1100
|
+
tokenCount: estimator(message)
|
|
1101
|
+
});
|
|
1102
|
+
var buildMessageBlocks = (messages, estimator, preserveToolPairs) => {
|
|
1103
|
+
if (!preserveToolPairs) {
|
|
1104
|
+
const blocks2 = messages.map((message) => createMessageBlock(message, estimator));
|
|
1105
|
+
const messageToBlock2 = new Map;
|
|
1106
|
+
for (const block of blocks2) {
|
|
1107
|
+
const message = block.messages[0];
|
|
1108
|
+
if (message) {
|
|
1109
|
+
messageToBlock2.set(message.id, block);
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
return { blocks: blocks2, messageToBlock: messageToBlock2 };
|
|
1113
|
+
}
|
|
1114
|
+
const blocks = [];
|
|
1115
|
+
const toolUses = new Map;
|
|
1116
|
+
for (const message of messages) {
|
|
1117
|
+
if (message.role === "tool-use" && message.toolCall) {
|
|
1118
|
+
const block = createMessageBlock(message, estimator);
|
|
1119
|
+
toolUses.set(message.toolCall.id, block);
|
|
1120
|
+
blocks.push(block);
|
|
1121
|
+
continue;
|
|
1122
|
+
}
|
|
1123
|
+
if (message.role === "tool-result" && message.toolResult) {
|
|
1124
|
+
const existing = toolUses.get(message.toolResult.callId);
|
|
1125
|
+
if (existing) {
|
|
1126
|
+
existing.messages.push(message);
|
|
1127
|
+
existing.maxPosition = Math.max(existing.maxPosition, message.position);
|
|
1128
|
+
existing.tokenCount += estimator(message);
|
|
1129
|
+
continue;
|
|
1130
|
+
}
|
|
1131
|
+
const orphanBlock = createMessageBlock(message, estimator);
|
|
1132
|
+
orphanBlock.orphanToolResult = true;
|
|
1133
|
+
blocks.push(orphanBlock);
|
|
1134
|
+
continue;
|
|
1135
|
+
}
|
|
1136
|
+
blocks.push(createMessageBlock(message, estimator));
|
|
1137
|
+
}
|
|
1138
|
+
const filteredBlocks = blocks.filter((block) => !block.orphanToolResult);
|
|
1139
|
+
const messageToBlock = new Map;
|
|
1140
|
+
for (const block of filteredBlocks) {
|
|
1141
|
+
for (const message of block.messages) {
|
|
1142
|
+
messageToBlock.set(message.id, block);
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
return { blocks: filteredBlocks, messageToBlock };
|
|
1146
|
+
};
|
|
1147
|
+
var collectBlocksForMessages = (messages, messageToBlock) => {
|
|
1148
|
+
const blocks = [];
|
|
1149
|
+
const seen = new Set;
|
|
1150
|
+
for (const message of messages) {
|
|
1151
|
+
const block = messageToBlock.get(message.id);
|
|
1152
|
+
if (block && !seen.has(block)) {
|
|
1153
|
+
seen.add(block);
|
|
1154
|
+
blocks.push(block);
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
return blocks;
|
|
1158
|
+
};
|
|
1159
|
+
var collectMessagesFromBlocks = (blocks) => {
|
|
1160
|
+
const messages = [];
|
|
1161
|
+
const seen = new Set;
|
|
1162
|
+
for (const block of blocks) {
|
|
1163
|
+
for (const message of block.messages) {
|
|
1164
|
+
if (!seen.has(message.id)) {
|
|
1165
|
+
seen.add(message.id);
|
|
1166
|
+
messages.push(message);
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
messages.sort((a, b) => a.position - b.position);
|
|
1171
|
+
return messages;
|
|
1172
|
+
};
|
|
1173
|
+
var ensureTruncationSafe = (conversation, preserveToolPairs, operation) => {
|
|
1174
|
+
try {
|
|
1175
|
+
return ensureConversationSafe(conversation);
|
|
1176
|
+
} catch (error) {
|
|
1177
|
+
if (!preserveToolPairs && error instanceof ConversationalistError && error.code === "error:integrity")
|
|
1178
|
+
throw createIntegrityError(`${operation} produced invalid tool linkage; use preserveToolPairs: true to keep tool interactions intact`, { preserveToolPairs, issues: error.context?.["issues"] });
|
|
1179
|
+
throw error;
|
|
1180
|
+
}
|
|
1181
|
+
};
|
|
836
1182
|
function estimateConversationTokens(conversation, estimateTokens, environment) {
|
|
837
1183
|
let estimator = estimateTokens;
|
|
838
1184
|
let env = environment;
|
|
@@ -845,6 +1191,7 @@ function estimateConversationTokens(conversation, estimateTokens, environment) {
|
|
|
845
1191
|
return getOrderedMessages(conversation).reduce((total, message) => total + finalEstimator(message), 0);
|
|
846
1192
|
}
|
|
847
1193
|
function truncateToTokenLimit(conversation, maxTokens, optionsOrEstimator, environment) {
|
|
1194
|
+
assertConversationSafe(conversation);
|
|
848
1195
|
let options = {};
|
|
849
1196
|
let env = environment;
|
|
850
1197
|
if (typeof optionsOrEstimator === "function") {
|
|
@@ -866,54 +1213,56 @@ function truncateToTokenLimit(conversation, maxTokens, optionsOrEstimator, envir
|
|
|
866
1213
|
const estimator = options.estimateTokens ?? resolvedEnvironment.estimateTokens;
|
|
867
1214
|
const preserveSystem = options.preserveSystemMessages ?? true;
|
|
868
1215
|
const preserveLastN = options.preserveLastN ?? 0;
|
|
1216
|
+
const preserveToolPairs = options.preserveToolPairs ?? true;
|
|
869
1217
|
const currentTokens = estimateConversationTokens(conversation, estimator, resolvedEnvironment);
|
|
870
1218
|
if (currentTokens <= maxTokens) {
|
|
871
1219
|
return conversation;
|
|
872
1220
|
}
|
|
873
1221
|
const now = resolvedEnvironment.now();
|
|
874
1222
|
const orderedMessages = getOrderedMessages(conversation);
|
|
1223
|
+
const { blocks, messageToBlock } = buildMessageBlocks(orderedMessages, estimator, preserveToolPairs);
|
|
875
1224
|
const systemMessages = preserveSystem ? orderedMessages.filter((m) => m.role === "system") : [];
|
|
876
1225
|
const nonSystemMessages = orderedMessages.filter((m) => m.role !== "system");
|
|
877
1226
|
const protectedMessages = preserveLastN > 0 ? nonSystemMessages.slice(-preserveLastN) : [];
|
|
878
|
-
const
|
|
879
|
-
const
|
|
880
|
-
const
|
|
1227
|
+
const systemBlocks = collectBlocksForMessages(systemMessages, messageToBlock);
|
|
1228
|
+
const protectedBlocks = collectBlocksForMessages(protectedMessages, messageToBlock);
|
|
1229
|
+
const lockedBlocks = new Set([...systemBlocks, ...protectedBlocks]);
|
|
1230
|
+
const removableBlocks = blocks.filter((block) => !lockedBlocks.has(block));
|
|
1231
|
+
const systemTokens = systemBlocks.reduce((sum, block) => sum + block.tokenCount, 0);
|
|
1232
|
+
const protectedTokens = protectedBlocks.reduce((sum, block) => sum + block.tokenCount, 0);
|
|
881
1233
|
const availableTokens = maxTokens - systemTokens - protectedTokens;
|
|
1234
|
+
let selectedBlocks = [];
|
|
882
1235
|
if (availableTokens <= 0) {
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
const messageTokens = estimator(message);
|
|
897
|
-
if (usedTokens + messageTokens <= availableTokens) {
|
|
898
|
-
keptRemovable.unshift(message);
|
|
899
|
-
usedTokens += messageTokens;
|
|
900
|
-
} else {
|
|
901
|
-
break;
|
|
1236
|
+
selectedBlocks = [...systemBlocks, ...protectedBlocks];
|
|
1237
|
+
} else {
|
|
1238
|
+
const sortedRemovable = [...removableBlocks].sort((a, b) => a.maxPosition - b.maxPosition);
|
|
1239
|
+
const keptRemovable = [];
|
|
1240
|
+
let usedTokens = 0;
|
|
1241
|
+
for (let i = sortedRemovable.length - 1;i >= 0; i--) {
|
|
1242
|
+
const block = sortedRemovable[i];
|
|
1243
|
+
if (usedTokens + block.tokenCount <= availableTokens) {
|
|
1244
|
+
keptRemovable.unshift(block);
|
|
1245
|
+
usedTokens += block.tokenCount;
|
|
1246
|
+
} else {
|
|
1247
|
+
break;
|
|
1248
|
+
}
|
|
902
1249
|
}
|
|
1250
|
+
selectedBlocks = [...systemBlocks, ...keptRemovable, ...protectedBlocks];
|
|
903
1251
|
}
|
|
904
|
-
const allMessages =
|
|
905
|
-
allMessages.sort((a, b) => a.position - b.position);
|
|
1252
|
+
const allMessages = collectMessagesFromBlocks(selectedBlocks);
|
|
906
1253
|
const renumbered = allMessages.map((message, index) => cloneMessageWithPosition(message, index, copyContent(message.content)));
|
|
907
|
-
|
|
1254
|
+
const next = toReadonly({
|
|
908
1255
|
...conversation,
|
|
909
1256
|
ids: renumbered.map((message) => message.id),
|
|
910
1257
|
messages: toIdRecord(renumbered),
|
|
911
1258
|
updatedAt: now
|
|
912
1259
|
});
|
|
1260
|
+
return ensureTruncationSafe(next, preserveToolPairs, "truncateToTokenLimit");
|
|
913
1261
|
}
|
|
914
1262
|
function getRecentMessages(conversation, count, options) {
|
|
915
1263
|
const includeHidden = options?.includeHidden ?? false;
|
|
916
1264
|
const includeSystem = options?.includeSystem ?? false;
|
|
1265
|
+
const preserveToolPairs = options?.preserveToolPairs ?? true;
|
|
917
1266
|
const filtered = getOrderedMessages(conversation).filter((m) => {
|
|
918
1267
|
if (!includeHidden && m.hidden)
|
|
919
1268
|
return false;
|
|
@@ -921,23 +1270,35 @@ function getRecentMessages(conversation, count, options) {
|
|
|
921
1270
|
return false;
|
|
922
1271
|
return true;
|
|
923
1272
|
});
|
|
924
|
-
|
|
1273
|
+
if (!preserveToolPairs) {
|
|
1274
|
+
return filtered.slice(-count);
|
|
1275
|
+
}
|
|
1276
|
+
const { messageToBlock } = buildMessageBlocks(filtered, () => 0, preserveToolPairs);
|
|
1277
|
+
const tail = filtered.slice(-count);
|
|
1278
|
+
const blocks = collectBlocksForMessages(tail, messageToBlock);
|
|
1279
|
+
return collectMessagesFromBlocks(blocks);
|
|
925
1280
|
}
|
|
926
1281
|
function truncateFromPosition(conversation, position, options, environment) {
|
|
1282
|
+
assertConversationSafe(conversation);
|
|
927
1283
|
const preserveSystem = options?.preserveSystemMessages ?? true;
|
|
1284
|
+
const preserveToolPairs = options?.preserveToolPairs ?? true;
|
|
928
1285
|
const resolvedEnvironment = resolveConversationEnvironment(environment);
|
|
929
1286
|
const now = resolvedEnvironment.now();
|
|
930
1287
|
const ordered = getOrderedMessages(conversation);
|
|
1288
|
+
const { messageToBlock } = buildMessageBlocks(ordered, () => 0, preserveToolPairs);
|
|
931
1289
|
const systemMessages = preserveSystem ? ordered.filter((m) => m.role === "system" && m.position < position) : [];
|
|
932
1290
|
const keptMessages = ordered.filter((m) => m.position >= position);
|
|
933
|
-
const
|
|
1291
|
+
const systemBlocks = collectBlocksForMessages(systemMessages, messageToBlock);
|
|
1292
|
+
const keptBlocks = collectBlocksForMessages(keptMessages, messageToBlock);
|
|
1293
|
+
const allMessages = collectMessagesFromBlocks([...systemBlocks, ...keptBlocks]);
|
|
934
1294
|
const renumbered = allMessages.map((message, index) => cloneMessageWithPosition(message, index, copyContent(message.content)));
|
|
935
|
-
|
|
1295
|
+
const next = toReadonly({
|
|
936
1296
|
...conversation,
|
|
937
1297
|
ids: renumbered.map((message) => message.id),
|
|
938
1298
|
messages: toIdRecord(renumbered),
|
|
939
1299
|
updatedAt: now
|
|
940
1300
|
});
|
|
1301
|
+
return ensureTruncationSafe(next, preserveToolPairs, "truncateFromPosition");
|
|
941
1302
|
}
|
|
942
1303
|
|
|
943
1304
|
// src/streaming.ts
|
|
@@ -972,7 +1333,8 @@ function getStreamingMessage(conversation) {
|
|
|
972
1333
|
return getOrderedMessages(conversation).find(isStreamingMessage);
|
|
973
1334
|
}
|
|
974
1335
|
function appendStreamingMessage(conversation, role, metadata, environment) {
|
|
975
|
-
const resolvedEnvironment = resolveConversationEnvironment(environment);
|
|
1336
|
+
const resolvedEnvironment = resolveConversationEnvironment(isConversationEnvironmentParameter(metadata) ? metadata : environment);
|
|
1337
|
+
const resolvedMetadata = isConversationEnvironmentParameter(metadata) ? undefined : metadata;
|
|
976
1338
|
const now = resolvedEnvironment.now();
|
|
977
1339
|
const messageId = resolvedEnvironment.randomId();
|
|
978
1340
|
const newMessage = createMessage({
|
|
@@ -981,7 +1343,7 @@ function appendStreamingMessage(conversation, role, metadata, environment) {
|
|
|
981
1343
|
content: "",
|
|
982
1344
|
position: conversation.ids.length,
|
|
983
1345
|
createdAt: now,
|
|
984
|
-
metadata: { ...
|
|
1346
|
+
metadata: { ...resolvedMetadata ?? {}, [STREAMING_KEY]: true },
|
|
985
1347
|
hidden: false,
|
|
986
1348
|
toolCall: undefined,
|
|
987
1349
|
toolResult: undefined,
|
|
@@ -993,14 +1355,14 @@ function appendStreamingMessage(conversation, role, metadata, environment) {
|
|
|
993
1355
|
messages: { ...conversation.messages, [messageId]: newMessage },
|
|
994
1356
|
updatedAt: now
|
|
995
1357
|
});
|
|
996
|
-
return { conversation: updatedConversation, messageId };
|
|
1358
|
+
return { conversation: ensureConversationSafe(updatedConversation), messageId };
|
|
997
1359
|
}
|
|
998
1360
|
function updateStreamingMessage(conversation, messageId, content, environment) {
|
|
999
1361
|
const resolvedEnvironment = resolveConversationEnvironment(environment);
|
|
1000
1362
|
const now = resolvedEnvironment.now();
|
|
1001
1363
|
const original = conversation.messages[messageId];
|
|
1002
1364
|
if (!original) {
|
|
1003
|
-
return conversation;
|
|
1365
|
+
return ensureConversationSafe(conversation);
|
|
1004
1366
|
}
|
|
1005
1367
|
const overrides = {
|
|
1006
1368
|
content: typeof content === "string" ? content : [...content]
|
|
@@ -1009,44 +1371,45 @@ function updateStreamingMessage(conversation, messageId, content, environment) {
|
|
|
1009
1371
|
overrides.tokenUsage = { ...original.tokenUsage };
|
|
1010
1372
|
}
|
|
1011
1373
|
const updated = cloneMessage(original, overrides);
|
|
1012
|
-
return toReadonly({
|
|
1374
|
+
return ensureConversationSafe(toReadonly({
|
|
1013
1375
|
...conversation,
|
|
1014
1376
|
ids: [...conversation.ids],
|
|
1015
1377
|
messages: { ...conversation.messages, [updated.id]: updated },
|
|
1016
1378
|
updatedAt: now
|
|
1017
|
-
});
|
|
1379
|
+
}));
|
|
1018
1380
|
}
|
|
1019
1381
|
function finalizeStreamingMessage(conversation, messageId, options, environment) {
|
|
1020
|
-
const resolvedEnvironment = resolveConversationEnvironment(environment);
|
|
1382
|
+
const resolvedEnvironment = resolveConversationEnvironment(isConversationEnvironmentParameter(options) ? options : environment);
|
|
1383
|
+
const resolvedOptions = isConversationEnvironmentParameter(options) ? undefined : options;
|
|
1021
1384
|
const now = resolvedEnvironment.now();
|
|
1022
1385
|
const original = conversation.messages[messageId];
|
|
1023
1386
|
if (!original) {
|
|
1024
|
-
return conversation;
|
|
1387
|
+
return ensureConversationSafe(conversation);
|
|
1025
1388
|
}
|
|
1026
1389
|
const { [STREAMING_KEY]: _, ...restMetadata } = original.metadata;
|
|
1027
1390
|
const finalMetadata = {
|
|
1028
1391
|
...restMetadata,
|
|
1029
|
-
...
|
|
1392
|
+
...resolvedOptions?.metadata ?? {}
|
|
1030
1393
|
};
|
|
1031
1394
|
const finalizeOverrides = {
|
|
1032
1395
|
metadata: finalMetadata
|
|
1033
1396
|
};
|
|
1034
|
-
if (
|
|
1035
|
-
finalizeOverrides.tokenUsage = { ...
|
|
1397
|
+
if (resolvedOptions?.tokenUsage) {
|
|
1398
|
+
finalizeOverrides.tokenUsage = { ...resolvedOptions.tokenUsage };
|
|
1036
1399
|
}
|
|
1037
1400
|
const updated = cloneMessage(original, finalizeOverrides);
|
|
1038
|
-
return toReadonly({
|
|
1401
|
+
return ensureConversationSafe(toReadonly({
|
|
1039
1402
|
...conversation,
|
|
1040
1403
|
ids: [...conversation.ids],
|
|
1041
1404
|
messages: { ...conversation.messages, [updated.id]: updated },
|
|
1042
1405
|
updatedAt: now
|
|
1043
|
-
});
|
|
1406
|
+
}));
|
|
1044
1407
|
}
|
|
1045
1408
|
function cancelStreamingMessage(conversation, messageId, environment) {
|
|
1046
1409
|
const resolvedEnvironment = resolveConversationEnvironment(environment);
|
|
1047
1410
|
const now = resolvedEnvironment.now();
|
|
1048
1411
|
if (!conversation.messages[messageId]) {
|
|
1049
|
-
return conversation;
|
|
1412
|
+
return ensureConversationSafe(conversation);
|
|
1050
1413
|
}
|
|
1051
1414
|
const messages = getOrderedMessages(conversation).filter((m) => m.id !== messageId).map((message, index) => message.position === index ? message : (() => {
|
|
1052
1415
|
const overrides = {
|
|
@@ -1057,12 +1420,12 @@ function cancelStreamingMessage(conversation, messageId, environment) {
|
|
|
1057
1420
|
}
|
|
1058
1421
|
return cloneMessage(message, overrides);
|
|
1059
1422
|
})());
|
|
1060
|
-
return toReadonly({
|
|
1423
|
+
return ensureConversationSafe(toReadonly({
|
|
1061
1424
|
...conversation,
|
|
1062
1425
|
ids: messages.map((message) => message.id),
|
|
1063
1426
|
messages: toIdRecord(messages),
|
|
1064
1427
|
updatedAt: now
|
|
1065
|
-
});
|
|
1428
|
+
}));
|
|
1066
1429
|
}
|
|
1067
1430
|
|
|
1068
1431
|
// src/with-conversation.ts
|
|
@@ -1100,8 +1463,8 @@ function createDraft(initial) {
|
|
|
1100
1463
|
current = collapseSystemMessages(current);
|
|
1101
1464
|
return draft;
|
|
1102
1465
|
},
|
|
1103
|
-
redactMessageAtPosition: (position,
|
|
1104
|
-
current = redactMessageAtPosition(current, position,
|
|
1466
|
+
redactMessageAtPosition: (position, placeholderOrOptions) => {
|
|
1467
|
+
current = redactMessageAtPosition(current, position, placeholderOrOptions);
|
|
1105
1468
|
return draft;
|
|
1106
1469
|
},
|
|
1107
1470
|
appendStreamingMessage: (role, metadata) => {
|
|
@@ -1133,15 +1496,16 @@ function createDraft(initial) {
|
|
|
1133
1496
|
return draft;
|
|
1134
1497
|
}
|
|
1135
1498
|
function withConversation(conversation, fn) {
|
|
1136
|
-
const draft = createDraft(conversation);
|
|
1499
|
+
const draft = createDraft(ensureConversationSafe(conversation));
|
|
1137
1500
|
const maybePromise = fn(draft);
|
|
1138
1501
|
if (maybePromise && typeof maybePromise === "object" && typeof maybePromise.then === "function") {
|
|
1139
|
-
return maybePromise.then(() => draft.value);
|
|
1502
|
+
return maybePromise.then(() => ensureConversationSafe(draft.value));
|
|
1140
1503
|
}
|
|
1141
|
-
return draft.value;
|
|
1504
|
+
return ensureConversationSafe(draft.value);
|
|
1142
1505
|
}
|
|
1143
1506
|
function pipeConversation(conversation, ...fns) {
|
|
1144
|
-
|
|
1507
|
+
const result = fns.reduce((current, fn) => fn(current), conversation);
|
|
1508
|
+
return ensureConversationSafe(result);
|
|
1145
1509
|
}
|
|
1146
1510
|
// node_modules/event-emission/dist/index.js
|
|
1147
1511
|
var SymbolObservable = typeof Symbol === "function" && Symbol.observable || Symbol.for("@@observable");
|
|
@@ -2662,8 +3026,9 @@ class ConversationHistory extends EventTarget {
|
|
|
2662
3026
|
super();
|
|
2663
3027
|
this.environment = resolveConversationEnvironment(environment);
|
|
2664
3028
|
this.events = createEventTarget();
|
|
3029
|
+
const safeInitial = ensureConversationSafe(initial);
|
|
2665
3030
|
this.currentNode = {
|
|
2666
|
-
conversation:
|
|
3031
|
+
conversation: safeInitial,
|
|
2667
3032
|
parent: null,
|
|
2668
3033
|
children: []
|
|
2669
3034
|
};
|
|
@@ -2861,8 +3226,8 @@ class ConversationHistory extends EventTarget {
|
|
|
2861
3226
|
collapseSystemMessages() {
|
|
2862
3227
|
this.push(collapseSystemMessages(this.current, this.env));
|
|
2863
3228
|
}
|
|
2864
|
-
redactMessageAtPosition(position,
|
|
2865
|
-
this.push(redactMessageAtPosition(this.current, position,
|
|
3229
|
+
redactMessageAtPosition(position, placeholderOrOptions) {
|
|
3230
|
+
this.push(redactMessageAtPosition(this.current, position, placeholderOrOptions, this.env));
|
|
2866
3231
|
}
|
|
2867
3232
|
truncateFromPosition(position, options) {
|
|
2868
3233
|
this.push(truncateFromPosition(this.current, position, options, this.env));
|
|
@@ -2968,6 +3333,7 @@ function isConversation2(value) {
|
|
|
2968
3333
|
export {
|
|
2969
3334
|
withEnvironment,
|
|
2970
3335
|
withConversation,
|
|
3336
|
+
validateConversationIntegrity,
|
|
2971
3337
|
updateStreamingMessage,
|
|
2972
3338
|
truncateToTokenLimit,
|
|
2973
3339
|
truncateFromPosition,
|
|
@@ -3005,10 +3371,12 @@ export {
|
|
|
3005
3371
|
isConversation,
|
|
3006
3372
|
isAssistantMessage,
|
|
3007
3373
|
hasSystemMessage,
|
|
3374
|
+
getToolInteractions,
|
|
3008
3375
|
getSystemMessages,
|
|
3009
3376
|
getStreamingMessage,
|
|
3010
3377
|
getStatistics,
|
|
3011
3378
|
getRecentMessages,
|
|
3379
|
+
getPendingToolCalls,
|
|
3012
3380
|
getMessages,
|
|
3013
3381
|
getMessageIds,
|
|
3014
3382
|
getMessageById,
|
|
@@ -3026,6 +3394,7 @@ export {
|
|
|
3026
3394
|
createInvalidPositionError,
|
|
3027
3395
|
createInvalidInputError,
|
|
3028
3396
|
createDuplicateIdError,
|
|
3397
|
+
createConversationUnsafe,
|
|
3029
3398
|
createConversation,
|
|
3030
3399
|
copyMultiModalContent,
|
|
3031
3400
|
copyContent,
|
|
@@ -3033,7 +3402,11 @@ export {
|
|
|
3033
3402
|
conversationSchema,
|
|
3034
3403
|
collapseSystemMessages,
|
|
3035
3404
|
cancelStreamingMessage,
|
|
3405
|
+
assertConversationIntegrity,
|
|
3036
3406
|
appendUserMessage,
|
|
3407
|
+
appendUnsafeMessage,
|
|
3408
|
+
appendToolUse,
|
|
3409
|
+
appendToolResult,
|
|
3037
3410
|
appendSystemMessage,
|
|
3038
3411
|
appendStreamingMessage,
|
|
3039
3412
|
appendMessages,
|
|
@@ -3042,4 +3415,4 @@ export {
|
|
|
3042
3415
|
ConversationHistory
|
|
3043
3416
|
};
|
|
3044
3417
|
|
|
3045
|
-
//# debugId=
|
|
3418
|
+
//# debugId=F37C8EF457F39BC364756E2164756E21
|