@maximem/synap-js-sdk 0.5.8 → 0.5.10
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 +5 -1
- package/dist/anticipation-cache-LPNKMRBH.cjs +20 -0
- package/dist/anticipation-cache-LPNKMRBH.cjs.map +1 -0
- package/dist/anticipation-cache-RWKF55J4.js +20 -0
- package/dist/{chunk-FXGLT6AT.js → chunk-I7TWR4S6.js} +59 -3
- package/dist/chunk-I7TWR4S6.js.map +1 -0
- package/dist/{chunk-T6U5PVAD.cjs → chunk-ICUFS3B5.cjs} +449 -12
- package/dist/chunk-ICUFS3B5.cjs.map +1 -0
- package/dist/{chunk-ODVOQOSO.js → chunk-R72YL6Q4.js} +445 -8
- package/dist/chunk-R72YL6Q4.js.map +1 -0
- package/dist/{chunk-HCULAVJC.cjs → chunk-RE4DDIWO.cjs} +66 -10
- package/dist/chunk-RE4DDIWO.cjs.map +1 -0
- package/dist/chunk-T372OL3Q.cjs.map +1 -1
- package/dist/chunk-ZKOJDUN4.cjs.map +1 -1
- package/dist/env-55ULHNJZ.cjs.map +1 -1
- package/dist/{errors-Bl3vY1eb.d.cts → errors-Bdayqlzy.d.cts} +88 -2
- package/dist/{errors-Bl3vY1eb.d.ts → errors-Bdayqlzy.d.ts} +88 -2
- package/dist/grpc/index.cjs +4 -4
- package/dist/grpc/index.cjs.map +1 -1
- package/dist/grpc/index.d.cts +8 -3
- package/dist/grpc/index.d.ts +8 -3
- package/dist/grpc/index.js +3 -3
- package/dist/index.cjs +1357 -128
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +277 -11
- package/dist/index.d.ts +277 -11
- package/dist/index.js +1309 -80
- package/dist/index.js.map +1 -1
- package/dist/onnx-encoder-4RSL6ID4.cjs +103 -0
- package/dist/onnx-encoder-4RSL6ID4.cjs.map +1 -0
- package/dist/onnx-encoder-NP35KH4H.js +103 -0
- package/dist/onnx-encoder-NP35KH4H.js.map +1 -0
- package/dist/{stream-client-VWKINE47.js → stream-client-3WHXGW4U.js} +2 -2
- package/dist/stream-client-L6OQPZN7.cjs +16 -0
- package/dist/stream-client-L6OQPZN7.cjs.map +1 -0
- package/package.json +4 -2
- package/dist/anticipation-cache-LRE3TLK4.cjs +0 -14
- package/dist/anticipation-cache-LRE3TLK4.cjs.map +0 -1
- package/dist/anticipation-cache-WLU4NMD5.js +0 -14
- package/dist/chunk-FXGLT6AT.js.map +0 -1
- package/dist/chunk-HCULAVJC.cjs.map +0 -1
- package/dist/chunk-ODVOQOSO.js.map +0 -1
- package/dist/chunk-T6U5PVAD.cjs.map +0 -1
- package/dist/stream-client-N46JBT5A.cjs +0 -16
- package/dist/stream-client-N46JBT5A.cjs.map +0 -1
- /package/dist/{anticipation-cache-WLU4NMD5.js.map → anticipation-cache-RWKF55J4.js.map} +0 -0
- /package/dist/{stream-client-VWKINE47.js.map → stream-client-3WHXGW4U.js.map} +0 -0
package/dist/index.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2;
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } async function _asyncNullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return await rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2; var _class3; var _class4;
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
|
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
var _chunkICUFS3B5cjs = require('./chunk-ICUFS3B5.cjs');
|
|
12
14
|
|
|
13
15
|
|
|
14
16
|
var _chunkZKOJDUN4cjs = require('./chunk-ZKOJDUN4.cjs');
|
|
@@ -55,6 +57,7 @@ var ENDPOINTS = {
|
|
|
55
57
|
context_fetch_client: { method: "POST", path: "/v1/context/client/fetch", idempotent: true },
|
|
56
58
|
context_fetch_conversation: { method: "POST", path: "/v1/context/conversation/fetch", idempotent: true },
|
|
57
59
|
context_for_prompt: { method: "GET", path: "/v1/conversations/{conversation_id}/context-for-prompt", idempotent: true },
|
|
60
|
+
conversation_turns: { method: "GET", path: "/v1/conversations/{conversation_id}/messages", idempotent: true },
|
|
58
61
|
conversations_ingest: { method: "POST", path: "/v1/conversations/ingest", idempotent: false },
|
|
59
62
|
conversations_messages: { method: "POST", path: "/v1/conversations/messages", idempotent: false },
|
|
60
63
|
conversations_messages_batch: { method: "POST", path: "/v1/conversations/messages/batch", idempotent: false },
|
|
@@ -132,7 +135,7 @@ var HEARTBEAT_INTERVAL_MS = 24e4;
|
|
|
132
135
|
var MAX_CONNECTIONS = 20;
|
|
133
136
|
var cached;
|
|
134
137
|
function supportsDispatcher() {
|
|
135
|
-
return typeof process !== "undefined" && _optionalChain([process, 'access',
|
|
138
|
+
return typeof process !== "undefined" && _optionalChain([process, 'access', _2 => _2.versions, 'optionalAccess', _3 => _3.node]) !== void 0 && // Edge builds of Next expose a partial `process` shim, but no real Node.
|
|
136
139
|
typeof globalThis.EdgeRuntime === "undefined";
|
|
137
140
|
}
|
|
138
141
|
async function getKeepAliveDispatcher(options = {}) {
|
|
@@ -173,7 +176,7 @@ var Heartbeat = (_class = class {
|
|
|
173
176
|
void Promise.resolve(this.ping()).catch(() => {
|
|
174
177
|
});
|
|
175
178
|
}, this.intervalMs);
|
|
176
|
-
_optionalChain([this, 'access',
|
|
179
|
+
_optionalChain([this, 'access', _4 => _4.timer, 'access', _5 => _5.unref, 'optionalCall', _6 => _6()]);
|
|
177
180
|
}
|
|
178
181
|
stop() {
|
|
179
182
|
if (this.timer !== null) {
|
|
@@ -216,7 +219,7 @@ var HttpTransport = (_class2 = class {
|
|
|
216
219
|
|
|
217
220
|
|
|
218
221
|
__init2() {this.closed = false}
|
|
219
|
-
constructor(options) {;_class2.prototype.__init2.call(this);_class2.prototype.__init3.call(this);
|
|
222
|
+
constructor(options) {;_class2.prototype.__init2.call(this);_class2.prototype.__init3.call(this);_class2.prototype.__init4.call(this);
|
|
220
223
|
this.#credentials = options.credentials;
|
|
221
224
|
this.baseUrl = (_nullishCoalesce(options.baseUrl, () => ( DEFAULT_BASE_URL))).replace(/\/+$/, "");
|
|
222
225
|
this.timeouts = { ...DEFAULT_TIMEOUTS, ...options.timeouts };
|
|
@@ -226,7 +229,7 @@ var HttpTransport = (_class2 = class {
|
|
|
226
229
|
this.keepAliveOptions = _nullishCoalesce(options.keepAlive, () => ( {}));
|
|
227
230
|
this.heartbeat = new Heartbeat(
|
|
228
231
|
() => this.pingHealth(),
|
|
229
|
-
_nullishCoalesce(_optionalChain([options, 'access',
|
|
232
|
+
_nullishCoalesce(_optionalChain([options, 'access', _7 => _7.keepAlive, 'optionalAccess', _8 => _8.heartbeatIntervalMs]), () => ( HEARTBEAT_INTERVAL_MS))
|
|
230
233
|
);
|
|
231
234
|
}
|
|
232
235
|
/** Start keeping the connection warm. Opt-in: it is pointless in serverless. */
|
|
@@ -264,6 +267,17 @@ var HttpTransport = (_class2 = class {
|
|
|
264
267
|
* deployment older than the field, and must mean "enforce nothing".
|
|
265
268
|
*/
|
|
266
269
|
__init3() {this.userContextIsolation = void 0}
|
|
270
|
+
/**
|
|
271
|
+
* Set by the client to its identity resolution (`initialize()`'s whoami).
|
|
272
|
+
* Python refuses every call before `initialize()`; here the first request
|
|
273
|
+
* runs it instead, so a caller who skips it gets the same identity-dependent
|
|
274
|
+
* behaviour (client-scope cache hits, the B2C check) rather than an error.
|
|
275
|
+
*/
|
|
276
|
+
__init4() {this.identityResolver = void 0}
|
|
277
|
+
/** Resolve identity once, before the first request. Never throws. */
|
|
278
|
+
async ready() {
|
|
279
|
+
if (this.identityResolver !== void 0) await this.identityResolver();
|
|
280
|
+
}
|
|
267
281
|
/** Refuse a customer_id on a B2C instance, at the call site. */
|
|
268
282
|
checkCustomerId(customerId, where) {
|
|
269
283
|
checkCustomerId(
|
|
@@ -295,6 +309,7 @@ var HttpTransport = (_class2 = class {
|
|
|
295
309
|
const spec = ENDPOINTS[name];
|
|
296
310
|
const correlationId = _nullishCoalesce(options.correlationId, () => ( _chunkT372OL3Qcjs.newCorrelationId.call(void 0, )));
|
|
297
311
|
const idempotent = _nullishCoalesce(options.idempotent, () => ( spec.idempotent));
|
|
312
|
+
if (name !== "whoami") await this.ready();
|
|
298
313
|
let attempt = 0;
|
|
299
314
|
let last = null;
|
|
300
315
|
while (attempt < this.retryPolicy.maxAttempts) {
|
|
@@ -315,7 +330,7 @@ var HttpTransport = (_class2 = class {
|
|
|
315
330
|
await sleep(decision.delaySeconds * 1e3, options.signal);
|
|
316
331
|
}
|
|
317
332
|
}
|
|
318
|
-
throw _nullishCoalesce(_optionalChain([last, 'optionalAccess',
|
|
333
|
+
throw _nullishCoalesce(_optionalChain([last, 'optionalAccess', _9 => _9.error]), () => ( new (0, _chunkT372OL3Qcjs.SynapError)("Request failed with no recorded error")));
|
|
319
334
|
}
|
|
320
335
|
async attempt(name, options, correlationId) {
|
|
321
336
|
const spec = ENDPOINTS[name];
|
|
@@ -394,17 +409,17 @@ function isOutcomeUnknown(error) {
|
|
|
394
409
|
return true;
|
|
395
410
|
}
|
|
396
411
|
function isConnectionRefusal(error) {
|
|
397
|
-
const code = _nullishCoalesce(_optionalChain([error, 'optionalAccess',
|
|
412
|
+
const code = _nullishCoalesce(_optionalChain([error, 'optionalAccess', _10 => _10.cause, 'optionalAccess', _11 => _11.code]), () => ( _optionalChain([error, 'optionalAccess', _12 => _12.code])));
|
|
398
413
|
return code === "ECONNREFUSED" || code === "ENOTFOUND" || code === "EAI_AGAIN" || code === "ECONNRESET" || code === "EHOSTUNREACH";
|
|
399
414
|
}
|
|
400
415
|
function toTransportError(error, correlationId) {
|
|
401
416
|
if (error instanceof _chunkT372OL3Qcjs.SynapError) return error;
|
|
402
|
-
const name = _optionalChain([error, 'optionalAccess',
|
|
417
|
+
const name = _optionalChain([error, 'optionalAccess', _13 => _13.name]);
|
|
403
418
|
if (name === "AbortError" || name === "TimeoutError") {
|
|
404
419
|
return new (0, _chunkT372OL3Qcjs.NetworkTimeoutError)("Request timed out", { correlationId, cause: error });
|
|
405
420
|
}
|
|
406
421
|
return new (0, _chunkT372OL3Qcjs.ServiceUnavailableError)(
|
|
407
|
-
`Network request failed: ${_nullishCoalesce(_optionalChain([error, 'optionalAccess',
|
|
422
|
+
`Network request failed: ${_nullishCoalesce(_optionalChain([error, 'optionalAccess', _14 => _14.message]), () => ( String(error)))}`,
|
|
408
423
|
{ correlationId, cause: error }
|
|
409
424
|
);
|
|
410
425
|
}
|
|
@@ -485,11 +500,11 @@ function stringOrNull(v) {
|
|
|
485
500
|
}
|
|
486
501
|
function withTimeout(ms, external) {
|
|
487
502
|
const controller = new AbortController();
|
|
488
|
-
const onExternalAbort = () => controller.abort(_optionalChain([external, 'optionalAccess',
|
|
503
|
+
const onExternalAbort = () => controller.abort(_optionalChain([external, 'optionalAccess', _15 => _15.reason]));
|
|
489
504
|
const timer = setTimeout(() => {
|
|
490
505
|
controller.abort(new (0, _chunkT372OL3Qcjs.NetworkTimeoutError)(`Timed out after ${ms}ms`));
|
|
491
506
|
}, ms);
|
|
492
|
-
_optionalChain([timer, 'access',
|
|
507
|
+
_optionalChain([timer, 'access', _16 => _16.unref, 'optionalCall', _17 => _17()]);
|
|
493
508
|
if (external) {
|
|
494
509
|
if (external.aborted) onExternalAbort();
|
|
495
510
|
else external.addEventListener("abort", onExternalAbort, { once: true });
|
|
@@ -498,7 +513,7 @@ function withTimeout(ms, external) {
|
|
|
498
513
|
signal: controller.signal,
|
|
499
514
|
dispose() {
|
|
500
515
|
clearTimeout(timer);
|
|
501
|
-
_optionalChain([external, 'optionalAccess',
|
|
516
|
+
_optionalChain([external, 'optionalAccess', _18 => _18.removeEventListener, 'call', _19 => _19("abort", onExternalAbort)]);
|
|
502
517
|
}
|
|
503
518
|
};
|
|
504
519
|
}
|
|
@@ -506,17 +521,97 @@ function sleep(ms, signal) {
|
|
|
506
521
|
if (ms <= 0) return Promise.resolve();
|
|
507
522
|
return new Promise((resolve, reject) => {
|
|
508
523
|
const timer = setTimeout(() => {
|
|
509
|
-
_optionalChain([signal, 'optionalAccess',
|
|
524
|
+
_optionalChain([signal, 'optionalAccess', _20 => _20.removeEventListener, 'call', _21 => _21("abort", onAbort)]);
|
|
510
525
|
resolve();
|
|
511
526
|
}, ms);
|
|
512
527
|
function onAbort() {
|
|
513
528
|
clearTimeout(timer);
|
|
514
|
-
reject(_nullishCoalesce(_optionalChain([signal, 'optionalAccess',
|
|
529
|
+
reject(_nullishCoalesce(_optionalChain([signal, 'optionalAccess', _22 => _22.reason]), () => ( new Error("Aborted"))));
|
|
515
530
|
}
|
|
516
|
-
_optionalChain([signal, 'optionalAccess',
|
|
531
|
+
_optionalChain([signal, 'optionalAccess', _23 => _23.addEventListener, 'call', _24 => _24("abort", onAbort, { once: true })]);
|
|
517
532
|
});
|
|
518
533
|
}
|
|
519
534
|
|
|
535
|
+
// src/context/ranked.ts
|
|
536
|
+
var RESPONSE_SHAPES = ["by_type", "ranked"];
|
|
537
|
+
var MEMORY_TYPES = [
|
|
538
|
+
"facts",
|
|
539
|
+
"preferences",
|
|
540
|
+
"episodes",
|
|
541
|
+
"emotions",
|
|
542
|
+
"temporal_events"
|
|
543
|
+
];
|
|
544
|
+
var EXCERPT_CATEGORY = "excerpts";
|
|
545
|
+
function wireRankScore(item) {
|
|
546
|
+
const md = item.metadata;
|
|
547
|
+
let raw = md !== null && typeof md === "object" ? md["rank_score"] : void 0;
|
|
548
|
+
if (raw === void 0 || raw === null) raw = item["rank_score"];
|
|
549
|
+
return typeof raw === "number" && Number.isFinite(raw) ? raw : null;
|
|
550
|
+
}
|
|
551
|
+
function wireCategory(item, fallback = "") {
|
|
552
|
+
if (item.source === "chunks") return EXCERPT_CATEGORY;
|
|
553
|
+
const category = item["category"];
|
|
554
|
+
if (typeof category === "string" && category !== "") return category;
|
|
555
|
+
const contextType = item["context_type"];
|
|
556
|
+
if (typeof contextType === "string" && contextType !== "") return contextType;
|
|
557
|
+
return fallback;
|
|
558
|
+
}
|
|
559
|
+
function byRankScore(a, b) {
|
|
560
|
+
const sa = wireRankScore(a);
|
|
561
|
+
const sb = wireRankScore(b);
|
|
562
|
+
if (sa === null && sb === null) return 0;
|
|
563
|
+
if (sa === null) return 1;
|
|
564
|
+
if (sb === null) return -1;
|
|
565
|
+
return sb - sa;
|
|
566
|
+
}
|
|
567
|
+
function rankItems(byType) {
|
|
568
|
+
const flat = [];
|
|
569
|
+
for (const type of MEMORY_TYPES) {
|
|
570
|
+
const list = byType[type];
|
|
571
|
+
if (!Array.isArray(list)) continue;
|
|
572
|
+
for (const it of list) {
|
|
573
|
+
if (it === null || typeof it !== "object") continue;
|
|
574
|
+
flat.push({
|
|
575
|
+
...it,
|
|
576
|
+
category: wireCategory(it, type),
|
|
577
|
+
id: it.id || it.item_id || ""
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
flat.sort(byRankScore);
|
|
582
|
+
return flat.map((it, n2) => ({ ...it, rank: n2 + 1 }));
|
|
583
|
+
}
|
|
584
|
+
function applyResponseShape(raw, shape = "by_type") {
|
|
585
|
+
const wire = raw["items"];
|
|
586
|
+
if (shape !== "ranked" && !Array.isArray(wire)) return raw;
|
|
587
|
+
const source = Array.isArray(wire) ? wire : rankItems(raw);
|
|
588
|
+
const items = source.map((it) => ({
|
|
589
|
+
...it,
|
|
590
|
+
id: it.id || it.item_id || "",
|
|
591
|
+
category: wireCategory(it)
|
|
592
|
+
}));
|
|
593
|
+
const out = { ...raw, items };
|
|
594
|
+
for (const type of MEMORY_TYPES) {
|
|
595
|
+
out[type] = items.filter((it) => it["category"] === type);
|
|
596
|
+
}
|
|
597
|
+
out["excerpts"] = items.filter((it) => it["category"] === EXCERPT_CATEGORY);
|
|
598
|
+
return out;
|
|
599
|
+
}
|
|
600
|
+
var RANKED_LABELS = {
|
|
601
|
+
facts: "fact",
|
|
602
|
+
preferences: "preference",
|
|
603
|
+
episodes: "episode",
|
|
604
|
+
emotions: "emotion",
|
|
605
|
+
temporal_events: "temporal event",
|
|
606
|
+
[EXCERPT_CATEGORY]: "excerpt"
|
|
607
|
+
};
|
|
608
|
+
function rankedLabel(category) {
|
|
609
|
+
return _nullishCoalesce(RANKED_LABELS[category], () => ( (category !== "" ? category : "item")));
|
|
610
|
+
}
|
|
611
|
+
function sortByRankScore(items) {
|
|
612
|
+
return [...items].sort(byRankScore);
|
|
613
|
+
}
|
|
614
|
+
|
|
520
615
|
// src/context/fetch.ts
|
|
521
616
|
var ENDPOINT_BY_SCOPE = {
|
|
522
617
|
user: "context_fetch_user",
|
|
@@ -536,10 +631,10 @@ function buildFetchRequest(scope, options) {
|
|
|
536
631
|
const conversationId = opt(options, "conversation_id", "conversationId");
|
|
537
632
|
const searchQuery = opt(options, "search_query", "searchQuery");
|
|
538
633
|
const maxResults = _nullishCoalesce(opt(options, "max_results", "maxResults"), () => ( 10));
|
|
539
|
-
const precisionLevel = _nullishCoalesce(opt(options, "precision_level", "precisionLevel"), () => ( "high"));
|
|
540
634
|
const queryDate = opt(options, "query_date", "queryDate");
|
|
541
635
|
const perQuery = opt(options, "max_results_per_query", "maxResultsPerQuery");
|
|
542
|
-
const
|
|
636
|
+
const responseShape = responseShapeOf(options);
|
|
637
|
+
const { mode, precisionLevel } = retrievalOptionsOf(options);
|
|
543
638
|
if (searchQuery !== void 0 && !Array.isArray(searchQuery)) {
|
|
544
639
|
throw new (0, _chunkT372OL3Qcjs.InvalidInputError)("search_query must be an array when provided");
|
|
545
640
|
}
|
|
@@ -556,16 +651,19 @@ function buildFetchRequest(scope, options) {
|
|
|
556
651
|
if (precisionLevel !== "high") body["precision_level"] = precisionLevel;
|
|
557
652
|
if (queryDate) body["query_date"] = queryDate;
|
|
558
653
|
if (perQuery) body["max_results_per_query"] = perQuery;
|
|
654
|
+
if (responseShape !== "by_type") body["response_shape"] = responseShape;
|
|
559
655
|
if (options.include_conversation_context === false) {
|
|
560
656
|
body["include_conversation_context"] = false;
|
|
561
657
|
}
|
|
658
|
+
const scopePath = opt(options, "scope_path", "scopePath");
|
|
659
|
+
if (scopePath !== void 0 && scopePath !== null && Object.keys(scopePath).length > 0) {
|
|
660
|
+
body["scope"] = scopePath;
|
|
661
|
+
}
|
|
562
662
|
switch (scope) {
|
|
563
663
|
case "user":
|
|
564
664
|
{
|
|
565
665
|
if (!userId) throw new (0, _chunkT372OL3Qcjs.InvalidInputError)("user_id is required");
|
|
566
666
|
body["user_id"] = userId;
|
|
567
|
-
const scopePath = opt(options, "scope_path", "scopePath");
|
|
568
|
-
if (scopePath !== void 0) body["scope"] = scopePath;
|
|
569
667
|
const contextMode = _nullishCoalesce(opt(options, "context_mode", "contextMode"), () => ( "in-conversation"));
|
|
570
668
|
if (!VALID_CONTEXT_MODES.includes(contextMode)) {
|
|
571
669
|
throw new (0, _chunkT372OL3Qcjs.InvalidInputError)(
|
|
@@ -603,22 +701,68 @@ function buildFetchRequest(scope, options) {
|
|
|
603
701
|
return { endpoint: ENDPOINT_BY_SCOPE[scope], body };
|
|
604
702
|
}
|
|
605
703
|
var VALID_CONTEXT_MODES = ["in-conversation", "conversation-summary"];
|
|
704
|
+
function responseShapeOf(options) {
|
|
705
|
+
const shape = _nullishCoalesce(opt(options, "response_shape", "responseShape"), () => ( "by_type"));
|
|
706
|
+
if (!RESPONSE_SHAPES.includes(shape)) {
|
|
707
|
+
throw new (0, _chunkT372OL3Qcjs.InvalidInputError)(
|
|
708
|
+
`Invalid response_shape '${shape}'. Must be one of: ${RESPONSE_SHAPES.join(", ")}`
|
|
709
|
+
);
|
|
710
|
+
}
|
|
711
|
+
return shape;
|
|
712
|
+
}
|
|
713
|
+
var VALID_MODES = ["fast", "accurate"];
|
|
714
|
+
var VALID_PRECISION = ["high", "medium"];
|
|
715
|
+
function retrievalOptionsOf(options) {
|
|
716
|
+
const mode = _nullishCoalesce(options.mode, () => ( "fast"));
|
|
717
|
+
if (!VALID_MODES.includes(mode)) {
|
|
718
|
+
throw new (0, _chunkT372OL3Qcjs.InvalidInputError)(
|
|
719
|
+
`Invalid mode '${mode}'. Must be one of: ${VALID_MODES.join(", ")}`
|
|
720
|
+
);
|
|
721
|
+
}
|
|
722
|
+
const precisionLevel = _nullishCoalesce(opt(options, "precision_level", "precisionLevel"), () => ( "high"));
|
|
723
|
+
if (!VALID_PRECISION.includes(precisionLevel)) {
|
|
724
|
+
throw new (0, _chunkT372OL3Qcjs.InvalidInputError)(
|
|
725
|
+
`Invalid precision_level '${precisionLevel}'. Must be one of: ${VALID_PRECISION.join(", ")}`
|
|
726
|
+
);
|
|
727
|
+
}
|
|
728
|
+
return { mode, precisionLevel };
|
|
729
|
+
}
|
|
606
730
|
async function fetchContext(transport, scope, options = {}, hooks = {}) {
|
|
607
731
|
const startedAt = Date.now();
|
|
732
|
+
await _optionalChain([transport, 'access', _25 => _25.ready, 'optionalCall', _26 => _26()]);
|
|
608
733
|
transport.checkCustomerId(
|
|
609
734
|
opt(options, "customer_id", "customerId"),
|
|
610
735
|
`${scope}.context.fetch`
|
|
611
736
|
);
|
|
612
|
-
const
|
|
737
|
+
const responseShape = responseShapeOf(options);
|
|
738
|
+
retrievalOptionsOf(options);
|
|
739
|
+
const network = async () => {
|
|
740
|
+
const { endpoint, body } = buildFetchRequest(scope, options);
|
|
741
|
+
const result = await transport.request(endpoint, { body });
|
|
742
|
+
return applyResponseShape(_nullishCoalesce(_optionalChain([result, 'optionalAccess', _27 => _27["context"]]), () => ( {})), responseShape);
|
|
743
|
+
};
|
|
744
|
+
const anticipated = await _asyncNullishCoalesce(await _optionalChain([hooks, 'access', _28 => _28.beforeFetch, 'optionalCall', _29 => _29(scope, options)]), async () => ( null));
|
|
745
|
+
if (anticipated !== null && anticipated.borderline) {
|
|
746
|
+
const pending = network();
|
|
747
|
+
pending.catch(() => void 0);
|
|
748
|
+
let timer;
|
|
749
|
+
const late = new Promise((resolve) => {
|
|
750
|
+
timer = setTimeout(() => resolve(null), _nullishCoalesce(anticipated.raceDeadlineMs, () => ( 250)));
|
|
751
|
+
});
|
|
752
|
+
const won = await Promise.race([pending.then((r) => r, () => null), late]);
|
|
753
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
754
|
+
if (won !== null) {
|
|
755
|
+
_optionalChain([hooks, 'access', _30 => _30.onAssembled, 'optionalCall', _31 => _31(scope, options, won, startedAt)]);
|
|
756
|
+
return won;
|
|
757
|
+
}
|
|
758
|
+
}
|
|
613
759
|
if (anticipated !== null) {
|
|
614
|
-
_optionalChain([hooks, 'access',
|
|
615
|
-
_optionalChain([hooks, 'access',
|
|
616
|
-
return anticipated.response;
|
|
617
|
-
}
|
|
618
|
-
const
|
|
619
|
-
|
|
620
|
-
const response = _nullishCoalesce(_optionalChain([result, 'optionalAccess', _30 => _30["context"]]), () => ( {}));
|
|
621
|
-
_optionalChain([hooks, 'access', _31 => _31.onAssembled, 'optionalCall', _32 => _32(scope, options, response, startedAt)]);
|
|
760
|
+
_optionalChain([hooks, 'access', _32 => _32.onServedFromCache, 'optionalCall', _33 => _33(scope, options, anticipated)]);
|
|
761
|
+
_optionalChain([hooks, 'access', _34 => _34.onAssembled, 'optionalCall', _35 => _35(scope, options, anticipated.response, startedAt)]);
|
|
762
|
+
return applyResponseShape(anticipated.response, responseShape);
|
|
763
|
+
}
|
|
764
|
+
const response = await network();
|
|
765
|
+
_optionalChain([hooks, 'access', _36 => _36.onAssembled, 'optionalCall', _37 => _37(scope, options, response, startedAt)]);
|
|
622
766
|
return response;
|
|
623
767
|
}
|
|
624
768
|
|
|
@@ -738,6 +882,17 @@ function normalizeConversationContext(value) {
|
|
|
738
882
|
conversationId: pick(value["conversationId"], value.conversation_id, null)
|
|
739
883
|
};
|
|
740
884
|
}
|
|
885
|
+
function normalizeRetrievalHealth(raw) {
|
|
886
|
+
if (!raw || typeof raw !== "object") return null;
|
|
887
|
+
const r = raw;
|
|
888
|
+
const warnings = r["warnings"];
|
|
889
|
+
return {
|
|
890
|
+
degraded: r["degraded"] === void 0 ? true : Boolean(r["degraded"]),
|
|
891
|
+
level: _nullishCoalesce(r["level"], () => ( null)),
|
|
892
|
+
code: _nullishCoalesce(r["code"], () => ( null)),
|
|
893
|
+
warnings: Array.isArray(warnings) ? warnings.map((w) => String(w)) : []
|
|
894
|
+
};
|
|
895
|
+
}
|
|
741
896
|
function normalizeContextResponse(result = {}) {
|
|
742
897
|
const context = _nullishCoalesce(result["context"], () => ( result));
|
|
743
898
|
return {
|
|
@@ -754,7 +909,15 @@ function normalizeContextResponse(result = {}) {
|
|
|
754
909
|
)
|
|
755
910
|
),
|
|
756
911
|
metadata: normalizeContextMetadata(obj(context.metadata)),
|
|
757
|
-
|
|
912
|
+
// `retrieval` is a SIBLING of `context` in the body, so it is read off the
|
|
913
|
+
// envelope first and only then off a bare context. Reading it from
|
|
914
|
+
// `context` alone is how the Python SDK dropped it.
|
|
915
|
+
retrieval: normalizeRetrievalHealth(
|
|
916
|
+
pick(result["retrieval"], context["retrieval"], null)
|
|
917
|
+
),
|
|
918
|
+
rawResponse: pick(context["rawResponse"], context["raw_response"], {}),
|
|
919
|
+
// Only for a ranked fetch, so a by-type result has exactly the keys it had.
|
|
920
|
+
...Array.isArray(context.items) ? { items: context.items, excerpts: Array.isArray(context.excerpts) ? context.excerpts : [] } : {}
|
|
758
921
|
};
|
|
759
922
|
}
|
|
760
923
|
|
|
@@ -1002,7 +1165,7 @@ function createMemoriesInterface(transport, onForgotten) {
|
|
|
1002
1165
|
transport.checkCustomerId(_nullishCoalesce(o2["customer_id"], () => ( o2["customerId"])), "memories.forget");
|
|
1003
1166
|
const body = buildForgetBody(options);
|
|
1004
1167
|
const result = await transport.request("memories_forget", { body });
|
|
1005
|
-
const removed = !!_optionalChain([result, 'optionalAccess',
|
|
1168
|
+
const removed = !!_optionalChain([result, 'optionalAccess', _38 => _38.deleted_ids, 'optionalAccess', _39 => _39.length]) || _optionalChain([result, 'optionalAccess', _40 => _40.status]) === "deleted" || _optionalChain([result, 'optionalAccess', _41 => _41.status]) === "partial";
|
|
1006
1169
|
if (removed && onForgotten) {
|
|
1007
1170
|
try {
|
|
1008
1171
|
onForgotten({
|
|
@@ -1042,14 +1205,14 @@ function sleep2(ms, signal) {
|
|
|
1042
1205
|
if (ms <= 0) return Promise.resolve();
|
|
1043
1206
|
return new Promise((resolve, reject) => {
|
|
1044
1207
|
const timer = setTimeout(() => {
|
|
1045
|
-
_optionalChain([signal, 'optionalAccess',
|
|
1208
|
+
_optionalChain([signal, 'optionalAccess', _42 => _42.removeEventListener, 'call', _43 => _43("abort", onAbort)]);
|
|
1046
1209
|
resolve();
|
|
1047
1210
|
}, ms);
|
|
1048
1211
|
function onAbort() {
|
|
1049
1212
|
clearTimeout(timer);
|
|
1050
|
-
reject(_nullishCoalesce(_optionalChain([signal, 'optionalAccess',
|
|
1213
|
+
reject(_nullishCoalesce(_optionalChain([signal, 'optionalAccess', _44 => _44.reason]), () => ( new Error("Aborted"))));
|
|
1051
1214
|
}
|
|
1052
|
-
_optionalChain([signal, 'optionalAccess',
|
|
1215
|
+
_optionalChain([signal, 'optionalAccess', _45 => _45.addEventListener, 'call', _46 => _46("abort", onAbort, { once: true })]);
|
|
1053
1216
|
});
|
|
1054
1217
|
}
|
|
1055
1218
|
|
|
@@ -1069,6 +1232,27 @@ function validateInstanceId(instanceId) {
|
|
|
1069
1232
|
}
|
|
1070
1233
|
}
|
|
1071
1234
|
|
|
1235
|
+
// src/agent-model.ts
|
|
1236
|
+
var AGENT_MODEL_KEY = "agent_model";
|
|
1237
|
+
var AGENT_CONTEXT_WINDOW_KEY = "agent_context_window";
|
|
1238
|
+
function agentModelOf(options) {
|
|
1239
|
+
const o2 = _nullishCoalesce(options, () => ( {}));
|
|
1240
|
+
const window = _nullishCoalesce(o2["context_window"], () => ( o2["contextWindow"]));
|
|
1241
|
+
return {
|
|
1242
|
+
model: typeof o2["model"] === "string" ? o2["model"] : void 0,
|
|
1243
|
+
contextWindow: typeof window === "number" ? window : void 0
|
|
1244
|
+
};
|
|
1245
|
+
}
|
|
1246
|
+
function withAgentModel(metadata, perCall, defaults, asStrings = false) {
|
|
1247
|
+
const model = perCall.model || defaults.model;
|
|
1248
|
+
const window = perCall.contextWindow || defaults.contextWindow;
|
|
1249
|
+
if (!model && !window) return metadata;
|
|
1250
|
+
const out = { ..._nullishCoalesce(metadata, () => ( {})) };
|
|
1251
|
+
if (model) out[AGENT_MODEL_KEY] = String(model);
|
|
1252
|
+
if (window) out[AGENT_CONTEXT_WINDOW_KEY] = asStrings ? String(Math.trunc(window)) : Math.trunc(window);
|
|
1253
|
+
return out;
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1072
1256
|
// src/conversation/interface.ts
|
|
1073
1257
|
var COMPACTION_LEVELS = [
|
|
1074
1258
|
"low",
|
|
@@ -1197,10 +1381,50 @@ var CompactionSubscribers = class {
|
|
|
1197
1381
|
}
|
|
1198
1382
|
}
|
|
1199
1383
|
};
|
|
1384
|
+
function storedBatchRows(bodies, result) {
|
|
1385
|
+
const r = _nullishCoalesce(result, () => ( {}));
|
|
1386
|
+
const results = Array.isArray(r["results"]) ? r["results"] : [];
|
|
1387
|
+
const errors = Array.isArray(r["errors"]) ? r["errors"] : [];
|
|
1388
|
+
const failed = new Set(errors.map((e) => _optionalChain([e, 'optionalAccess', _47 => _47["index"]])));
|
|
1389
|
+
const stored = bodies.filter((_, index) => !failed.has(index));
|
|
1390
|
+
if (stored.length !== results.length) return [];
|
|
1391
|
+
const pairs = [];
|
|
1392
|
+
stored.forEach((body, i) => {
|
|
1393
|
+
const row = results[i];
|
|
1394
|
+
if (row && typeof row === "object" && row["message_id"]) pairs.push([body, row]);
|
|
1395
|
+
});
|
|
1396
|
+
return pairs;
|
|
1397
|
+
}
|
|
1200
1398
|
function createConversationNamespace(transport, subscribers = new CompactionSubscribers(), onWrite = () => {
|
|
1201
1399
|
}, onTurn = () => {
|
|
1202
1400
|
}, onFetched = () => {
|
|
1203
|
-
}, localShortTerm = { prompt: () => null, compacted: () => null }) {
|
|
1401
|
+
}, localShortTerm = { prompt: () => null, compacted: () => null }, agentModel = () => ({})) {
|
|
1402
|
+
const writesInFlight = /* @__PURE__ */ new Map();
|
|
1403
|
+
const withTurnModel = (body, options) => {
|
|
1404
|
+
const metadata = withAgentModel(
|
|
1405
|
+
body["metadata"],
|
|
1406
|
+
agentModelOf(options),
|
|
1407
|
+
agentModel()
|
|
1408
|
+
);
|
|
1409
|
+
return metadata === void 0 ? body : { ...body, metadata };
|
|
1410
|
+
};
|
|
1411
|
+
const writeStarted = (conversationId) => {
|
|
1412
|
+
writesInFlight.set(conversationId, (_nullishCoalesce(writesInFlight.get(conversationId), () => ( 0))) + 1);
|
|
1413
|
+
};
|
|
1414
|
+
const writeLanded = (conversationId) => {
|
|
1415
|
+
const remaining = (_nullishCoalesce(writesInFlight.get(conversationId), () => ( 0))) - 1;
|
|
1416
|
+
if (remaining > 0) writesInFlight.set(conversationId, remaining);
|
|
1417
|
+
else writesInFlight.delete(conversationId);
|
|
1418
|
+
};
|
|
1419
|
+
const confirmation = (result, conversationId) => {
|
|
1420
|
+
const r = _nullishCoalesce(result, () => ( {}));
|
|
1421
|
+
const count = r["conversation_message_count"];
|
|
1422
|
+
return {
|
|
1423
|
+
...typeof r["message_id"] === "string" ? { messageId: r["message_id"] } : {},
|
|
1424
|
+
serverMessageCount: typeof count === "number" ? count : null,
|
|
1425
|
+
inFlight: _nullishCoalesce(writesInFlight.get(conversationId), () => ( 0))
|
|
1426
|
+
};
|
|
1427
|
+
};
|
|
1204
1428
|
const convId = (v) => {
|
|
1205
1429
|
const id = typeof v === "string" ? v : _nullishCoalesce(v.conversation_id, () => ( v.conversationId));
|
|
1206
1430
|
if (!id) throw new (0, _chunkT372OL3Qcjs.InvalidInputError)("conversation_id is required");
|
|
@@ -1213,13 +1437,21 @@ function createConversationNamespace(transport, subscribers = new CompactionSubs
|
|
|
1213
1437
|
_nullishCoalesce(options["customer_id"], () => ( options["customerId"])),
|
|
1214
1438
|
"conversation.record_message"
|
|
1215
1439
|
);
|
|
1216
|
-
const body = buildRecordMessageBody(options);
|
|
1217
|
-
const
|
|
1440
|
+
const body = withTurnModel(buildRecordMessageBody(options), options);
|
|
1441
|
+
const conversationId = String(_nullishCoalesce(body["conversation_id"], () => ( "")));
|
|
1442
|
+
writeStarted(conversationId);
|
|
1443
|
+
let result;
|
|
1444
|
+
try {
|
|
1445
|
+
result = await transport.request("conversations_messages", { body });
|
|
1446
|
+
} finally {
|
|
1447
|
+
writeLanded(conversationId);
|
|
1448
|
+
}
|
|
1218
1449
|
onTurn({
|
|
1219
|
-
conversationId
|
|
1450
|
+
conversationId,
|
|
1220
1451
|
role: String(_nullishCoalesce(body["role"], () => ( "user"))),
|
|
1221
1452
|
content: String(_nullishCoalesce(body["content"], () => ( ""))),
|
|
1222
|
-
timestamp: body["timestamp"]
|
|
1453
|
+
timestamp: body["timestamp"],
|
|
1454
|
+
...confirmation(result, conversationId)
|
|
1223
1455
|
});
|
|
1224
1456
|
onWrite({
|
|
1225
1457
|
userId: body["user_id"],
|
|
@@ -1238,16 +1470,18 @@ function createConversationNamespace(transport, subscribers = new CompactionSubs
|
|
|
1238
1470
|
"conversation.record_messages_batch"
|
|
1239
1471
|
);
|
|
1240
1472
|
}
|
|
1241
|
-
const bodies = messages.map(buildRecordMessageBody);
|
|
1473
|
+
const bodies = messages.map((m) => withTurnModel(buildRecordMessageBody(m), m));
|
|
1242
1474
|
const result = await transport.request("conversations_messages_batch", {
|
|
1243
1475
|
body: { messages: bodies }
|
|
1244
1476
|
});
|
|
1245
|
-
for (const body of bodies) {
|
|
1477
|
+
for (const [body, row] of storedBatchRows(bodies, result)) {
|
|
1478
|
+
const conversationId = String(_nullishCoalesce(body["conversation_id"], () => ( "")));
|
|
1246
1479
|
onTurn({
|
|
1247
|
-
conversationId
|
|
1480
|
+
conversationId,
|
|
1248
1481
|
role: String(_nullishCoalesce(body["role"], () => ( "user"))),
|
|
1249
1482
|
content: String(_nullishCoalesce(body["content"], () => ( ""))),
|
|
1250
|
-
timestamp: body["timestamp"]
|
|
1483
|
+
timestamp: body["timestamp"],
|
|
1484
|
+
...confirmation(row, conversationId)
|
|
1251
1485
|
});
|
|
1252
1486
|
}
|
|
1253
1487
|
for (const body of bodies) {
|
|
@@ -1282,13 +1516,24 @@ function createConversationNamespace(transport, subscribers = new CompactionSubs
|
|
|
1282
1516
|
},
|
|
1283
1517
|
get_context_for_prompt: async (options = {}) => {
|
|
1284
1518
|
const id = convId(options);
|
|
1519
|
+
const search = (_nullishCoalesce(_nullishCoalesce(options.search_history, () => ( options.searchHistory)), () => ( true))) && localShortTerm.historyExcerpts;
|
|
1520
|
+
const withHistory = async (response2) => {
|
|
1521
|
+
if (!search) return response2;
|
|
1522
|
+
try {
|
|
1523
|
+
return await localShortTerm.historyExcerpts(id, response2, options.query);
|
|
1524
|
+
} catch (e6) {
|
|
1525
|
+
return response2;
|
|
1526
|
+
}
|
|
1527
|
+
};
|
|
1285
1528
|
const local = localShortTerm.prompt(id, _nullishCoalesce(options.style, () => ( "structured")));
|
|
1286
|
-
if (local !== null) return local;
|
|
1529
|
+
if (local !== null) return withHistory(local);
|
|
1287
1530
|
const result = await transport.request("context_for_prompt", {
|
|
1288
1531
|
pathParams: { conversation_id: id },
|
|
1289
1532
|
query: { style: _nullishCoalesce(options.style, () => ( "structured")) }
|
|
1290
1533
|
});
|
|
1291
|
-
|
|
1534
|
+
const response = _nullishCoalesce(_nullishCoalesce(_optionalChain([result, 'optionalAccess', _48 => _48["context_for_prompt"]]), () => ( result)), () => ( {}));
|
|
1535
|
+
_optionalChain([localShortTerm, 'access', _49 => _49.reseed, 'optionalCall', _50 => _50(id, response)]);
|
|
1536
|
+
return withHistory(response);
|
|
1292
1537
|
},
|
|
1293
1538
|
async compact(options) {
|
|
1294
1539
|
return transport.request("conversations_compact", { body: buildCompactBody(options) });
|
|
@@ -1463,32 +1708,40 @@ function jsonOrText(value) {
|
|
|
1463
1708
|
(_k, v) => typeof v === "bigint" ? String(v) : v
|
|
1464
1709
|
);
|
|
1465
1710
|
return out === void 0 ? String(value) : out;
|
|
1466
|
-
} catch (
|
|
1711
|
+
} catch (e7) {
|
|
1467
1712
|
try {
|
|
1468
1713
|
return String(value);
|
|
1469
|
-
} catch (
|
|
1714
|
+
} catch (e8) {
|
|
1470
1715
|
return "";
|
|
1471
1716
|
}
|
|
1472
1717
|
}
|
|
1473
1718
|
}
|
|
1474
|
-
function createInstanceNamespace(credentials, cache, onTurn) {
|
|
1719
|
+
function createInstanceNamespace(credentials, cache, onTurn, agentModel = () => ({}), onToolResult) {
|
|
1475
1720
|
let client = null;
|
|
1476
1721
|
const openSessions = /* @__PURE__ */ new Map();
|
|
1477
1722
|
let dispatchCompaction = null;
|
|
1478
1723
|
let applyCompaction = null;
|
|
1724
|
+
let onListen = null;
|
|
1725
|
+
let onConversationState = null;
|
|
1479
1726
|
const internals = {
|
|
1480
1727
|
onCompactionUpdate(conversationId, bundle) {
|
|
1481
|
-
_optionalChain([applyCompaction, 'optionalCall',
|
|
1482
|
-
_optionalChain([dispatchCompaction, 'optionalCall',
|
|
1728
|
+
_optionalChain([applyCompaction, 'optionalCall', _51 => _51(bundle)]);
|
|
1729
|
+
_optionalChain([dispatchCompaction, 'optionalCall', _52 => _52(conversationId, bundle)]);
|
|
1483
1730
|
},
|
|
1484
1731
|
setCompactionApplier(apply) {
|
|
1485
1732
|
applyCompaction = apply;
|
|
1486
1733
|
},
|
|
1734
|
+
setOnListen(handle) {
|
|
1735
|
+
onListen = handle;
|
|
1736
|
+
},
|
|
1737
|
+
setConversationStateHandler(handle) {
|
|
1738
|
+
onConversationState = handle;
|
|
1739
|
+
},
|
|
1487
1740
|
sendContextUsed(event) {
|
|
1488
|
-
_optionalChain([client, 'optionalAccess',
|
|
1741
|
+
_optionalChain([client, 'optionalAccess', _53 => _53.sendContextUsed, 'call', _54 => _54(event)]);
|
|
1489
1742
|
},
|
|
1490
1743
|
sendContextAssembled(event) {
|
|
1491
|
-
_optionalChain([client, 'optionalAccess',
|
|
1744
|
+
_optionalChain([client, 'optionalAccess', _55 => _55.sendContextAssembled, 'call', _56 => _56(event)]);
|
|
1492
1745
|
},
|
|
1493
1746
|
setCompactionDispatcher(dispatch) {
|
|
1494
1747
|
dispatchCompaction = dispatch;
|
|
@@ -1510,7 +1763,7 @@ function createInstanceNamespace(credentials, cache, onTurn) {
|
|
|
1510
1763
|
...customerId ? { customer_id: customerId } : {}
|
|
1511
1764
|
});
|
|
1512
1765
|
openSessions.set(conversationId, sessionId);
|
|
1513
|
-
} catch (
|
|
1766
|
+
} catch (e9) {
|
|
1514
1767
|
}
|
|
1515
1768
|
}
|
|
1516
1769
|
const namespace = {
|
|
@@ -1518,7 +1771,11 @@ function createInstanceNamespace(credentials, cache, onTurn) {
|
|
|
1518
1771
|
if (client !== null) {
|
|
1519
1772
|
throw new (0, _chunkT372OL3Qcjs.ListeningAlreadyActiveError)("Listening is already active on this instance");
|
|
1520
1773
|
}
|
|
1521
|
-
|
|
1774
|
+
try {
|
|
1775
|
+
_optionalChain([onListen, 'optionalCall', _57 => _57()]);
|
|
1776
|
+
} catch (e10) {
|
|
1777
|
+
}
|
|
1778
|
+
const { GrpcStreamClient } = await Promise.resolve().then(() => _interopRequireWildcard(require("./stream-client-L6OQPZN7.cjs")));
|
|
1522
1779
|
const onContext = _nullishCoalesce(options.on_context, () => ( options.onContext));
|
|
1523
1780
|
const onDisconnect = _nullishCoalesce(options.on_disconnect, () => ( options.onDisconnect));
|
|
1524
1781
|
const onReconnect = _nullishCoalesce(options.on_reconnect, () => ( options.onReconnect));
|
|
@@ -1532,15 +1789,18 @@ function createInstanceNamespace(credentials, cache, onTurn) {
|
|
|
1532
1789
|
onCompactionUpdate: (conversationId, bundle) => {
|
|
1533
1790
|
internals.onCompactionUpdate(conversationId, bundle);
|
|
1534
1791
|
},
|
|
1792
|
+
onConversationState: (conversationId, messageCount) => {
|
|
1793
|
+
_optionalChain([onConversationState, 'optionalCall', _58 => _58(conversationId, messageCount)]);
|
|
1794
|
+
},
|
|
1535
1795
|
onStateChange: (state) => {
|
|
1536
1796
|
if (state !== "connected") openSessions.clear();
|
|
1537
1797
|
if (state === "reconnecting") {
|
|
1538
1798
|
reconnectAttempts += 1;
|
|
1539
|
-
_optionalChain([onReconnect, 'optionalCall',
|
|
1799
|
+
_optionalChain([onReconnect, 'optionalCall', _59 => _59(reconnectAttempts)]);
|
|
1540
1800
|
} else if (state === "disconnected") {
|
|
1541
|
-
const stopped = _nullishCoalesce(_optionalChain([stream, 'optionalAccess',
|
|
1801
|
+
const stopped = _nullishCoalesce(_optionalChain([stream, 'optionalAccess', _60 => _60.lastError]), () => ( null));
|
|
1542
1802
|
const reason = stopped === null ? "stream disconnected" : `credit_stop:${_nullishCoalesce(stopped.reason, () => ( "unknown"))}`;
|
|
1543
|
-
_optionalChain([onDisconnect, 'optionalCall',
|
|
1803
|
+
_optionalChain([onDisconnect, 'optionalCall', _61 => _61(reason)]);
|
|
1544
1804
|
}
|
|
1545
1805
|
}
|
|
1546
1806
|
});
|
|
@@ -1550,7 +1810,7 @@ function createInstanceNamespace(credentials, cache, onTurn) {
|
|
|
1550
1810
|
} catch (error) {
|
|
1551
1811
|
if (error instanceof _chunkT372OL3Qcjs.SynapError) throw error;
|
|
1552
1812
|
throw new (0, _chunkT372OL3Qcjs.SynapError)(
|
|
1553
|
-
`Could not open the Synap anticipation stream: ${_nullishCoalesce(_optionalChain([error, 'optionalAccess',
|
|
1813
|
+
`Could not open the Synap anticipation stream: ${_nullishCoalesce(_optionalChain([error, 'optionalAccess', _62 => _62.message]), () => ( String(error)))}`,
|
|
1554
1814
|
{ cause: error }
|
|
1555
1815
|
);
|
|
1556
1816
|
}
|
|
@@ -1575,7 +1835,7 @@ function createInstanceNamespace(credentials, cache, onTurn) {
|
|
|
1575
1835
|
session_id: sessionId,
|
|
1576
1836
|
conversation_id: conversationId
|
|
1577
1837
|
});
|
|
1578
|
-
} catch (
|
|
1838
|
+
} catch (e11) {
|
|
1579
1839
|
}
|
|
1580
1840
|
},
|
|
1581
1841
|
async send_message(options) {
|
|
@@ -1596,7 +1856,7 @@ function createInstanceNamespace(credentials, cache, onTurn) {
|
|
|
1596
1856
|
_nullishCoalesce(_nullishCoalesce(options.customer_id, () => ( options.customerId)), () => ( ""))
|
|
1597
1857
|
);
|
|
1598
1858
|
if (eventType === "user_message" || eventType === "assistant_message") {
|
|
1599
|
-
_optionalChain([onTurn, 'optionalCall',
|
|
1859
|
+
_optionalChain([onTurn, 'optionalCall', _63 => _63({
|
|
1600
1860
|
conversationId,
|
|
1601
1861
|
role: _nullishCoalesce(options.role, () => ( "user")),
|
|
1602
1862
|
content: options.content
|
|
@@ -1610,7 +1870,7 @@ function createInstanceNamespace(credentials, cache, onTurn) {
|
|
|
1610
1870
|
user_id: _nullishCoalesce(_nullishCoalesce(options.user_id, () => ( options.userId)), () => ( "")),
|
|
1611
1871
|
customer_id: _nullishCoalesce(_nullishCoalesce(options.customer_id, () => ( options.customerId)), () => ( "")),
|
|
1612
1872
|
session_id: _nullishCoalesce(_nullishCoalesce(_nullishCoalesce(options.session_id, () => ( options.sessionId)), () => ( openSessions.get(conversationId))), () => ( "")),
|
|
1613
|
-
metadata: _nullishCoalesce(options.metadata, () => ( {})),
|
|
1873
|
+
metadata: _nullishCoalesce(withAgentModel(options.metadata, agentModelOf(options), agentModel(), true), () => ( {})),
|
|
1614
1874
|
timestamp_ms: Date.now(),
|
|
1615
1875
|
tool_name: _nullishCoalesce(_nullishCoalesce(options.tool_name, () => ( options.toolName)), () => ( "")),
|
|
1616
1876
|
// Python serialises tool_args with json.dumps into tool_args_json.
|
|
@@ -1640,6 +1900,10 @@ function createInstanceNamespace(credentials, cache, onTurn) {
|
|
|
1640
1900
|
});
|
|
1641
1901
|
},
|
|
1642
1902
|
async record_tool_result(options) {
|
|
1903
|
+
const conversationId = _nullishCoalesce(_nullishCoalesce(options.conversation_id, () => ( options.conversationId)), () => ( ""));
|
|
1904
|
+
if (conversationId) {
|
|
1905
|
+
_optionalChain([onToolResult, 'optionalCall', _64 => _64({ conversationId, result: options.result, toolName: _nullishCoalesce(_nullishCoalesce(options.tool_name, () => ( options.toolName)), () => ( "")) })]);
|
|
1906
|
+
}
|
|
1643
1907
|
await namespace.send_message({
|
|
1644
1908
|
content: "",
|
|
1645
1909
|
role: "tool",
|
|
@@ -1690,7 +1954,7 @@ function createInstanceNamespace(credentials, cache, onTurn) {
|
|
|
1690
1954
|
}
|
|
1691
1955
|
|
|
1692
1956
|
// src/version.ts
|
|
1693
|
-
var SDK_VERSION = "0.5.
|
|
1957
|
+
var SDK_VERSION = "0.5.10";
|
|
1694
1958
|
|
|
1695
1959
|
// src/registry.ts
|
|
1696
1960
|
var instances = /* @__PURE__ */ new Map();
|
|
@@ -1731,6 +1995,34 @@ function unregisterIfOwner(key, client) {
|
|
|
1731
1995
|
// src/cache/short-term-store.ts
|
|
1732
1996
|
var DEFAULT_MAX_CONVERSATIONS = 100;
|
|
1733
1997
|
var DEFAULT_MAX_AGE_MS = 12 * 60 * 60 * 1e3;
|
|
1998
|
+
var CONTEXT_BLOCK_PREFIX = "## Conversation so far (compacted";
|
|
1999
|
+
function contextBlockOf(cc) {
|
|
2000
|
+
const block = cc["context_block"];
|
|
2001
|
+
if (typeof block === "string" && block) return block;
|
|
2002
|
+
const summary = cc["summary"];
|
|
2003
|
+
if (typeof summary === "string" && summary.startsWith(CONTEXT_BLOCK_PREFIX)) return summary;
|
|
2004
|
+
return null;
|
|
2005
|
+
}
|
|
2006
|
+
function localMessageCount(entry) {
|
|
2007
|
+
return entry.compactedMessageCount + entry.recentTurns.length;
|
|
2008
|
+
}
|
|
2009
|
+
function isComplete(entry) {
|
|
2010
|
+
return entry.participant && entry.synced && !entry.shared && entry.serverMessageCount !== null && entry.serverMessageCount <= localMessageCount(entry);
|
|
2011
|
+
}
|
|
2012
|
+
function heldIn(turn, turns) {
|
|
2013
|
+
return turns.some(
|
|
2014
|
+
(held) => turn.message_id && held.message_id ? held.message_id === turn.message_id : held.role === turn.role && held.content === turn.content
|
|
2015
|
+
);
|
|
2016
|
+
}
|
|
2017
|
+
function turnsAfter(localTurns, serverTurns) {
|
|
2018
|
+
const newer = [];
|
|
2019
|
+
for (let i = localTurns.length - 1; i >= 0; i -= 1) {
|
|
2020
|
+
const turn = localTurns[i];
|
|
2021
|
+
if (heldIn(turn, serverTurns)) break;
|
|
2022
|
+
newer.unshift(turn);
|
|
2023
|
+
}
|
|
2024
|
+
return newer;
|
|
2025
|
+
}
|
|
1734
2026
|
function parseIso(value) {
|
|
1735
2027
|
if (value === null || value === void 0 || value === "") return null;
|
|
1736
2028
|
if (value instanceof Date) return value.getTime();
|
|
@@ -1750,11 +2042,23 @@ var ShortTermStore = class {
|
|
|
1750
2042
|
#maxConversations;
|
|
1751
2043
|
#maxAgeMs;
|
|
1752
2044
|
#now;
|
|
2045
|
+
/**
|
|
2046
|
+
* Every turn appended here is also kept in the archive (a TurnStore), which
|
|
2047
|
+
* a compaction does not prune: the turns it covers stay searchable locally
|
|
2048
|
+
* (history-search.ts). Python: `ShortTermContextStore.attach_archive`.
|
|
2049
|
+
*/
|
|
2050
|
+
#archive = null;
|
|
1753
2051
|
constructor(options = {}) {
|
|
1754
2052
|
this.#maxConversations = _nullishCoalesce(options.maxConversations, () => ( DEFAULT_MAX_CONVERSATIONS));
|
|
1755
2053
|
this.#maxAgeMs = _nullishCoalesce(options.maxAgeMs, () => ( DEFAULT_MAX_AGE_MS));
|
|
1756
2054
|
this.#now = _nullishCoalesce(options.now, () => ( (() => Date.now())));
|
|
1757
2055
|
}
|
|
2056
|
+
attachArchive(archive) {
|
|
2057
|
+
this.#archive = archive;
|
|
2058
|
+
}
|
|
2059
|
+
get archive() {
|
|
2060
|
+
return this.#archive;
|
|
2061
|
+
}
|
|
1758
2062
|
/** The entry, or null. Age-evicts on read, as Python does. */
|
|
1759
2063
|
get(conversationId) {
|
|
1760
2064
|
if (!conversationId) return null;
|
|
@@ -1780,23 +2084,88 @@ var ShortTermStore = class {
|
|
|
1780
2084
|
* exists yet (the first turn, before any compaction has arrived) a fresh one
|
|
1781
2085
|
* is created with an empty summary; the next `compaction_update` fills the
|
|
1782
2086
|
* summary fields in and prunes the turns it covers.
|
|
2087
|
+
*
|
|
2088
|
+
* `confirmation` is what the write learned from the server. See
|
|
2089
|
+
* `TurnConfirmation` and `noteServerCount`.
|
|
1783
2090
|
*/
|
|
1784
|
-
appendTurn(conversationId, role, content, timestamp) {
|
|
2091
|
+
appendTurn(conversationId, role, content, timestamp, confirmation = {}) {
|
|
1785
2092
|
if (!conversationId) return;
|
|
1786
2093
|
const stamp = _nullishCoalesce(timestamp, () => ( new Date(this.#now()).toISOString()));
|
|
2094
|
+
if (this.#archive !== null) {
|
|
2095
|
+
try {
|
|
2096
|
+
this.#archive.add(conversationId, role, content, stamp, { messageId: _nullishCoalesce(confirmation.messageId, () => ( null)) });
|
|
2097
|
+
} catch (e12) {
|
|
2098
|
+
}
|
|
2099
|
+
}
|
|
1787
2100
|
const entry = _nullishCoalesce(this.#entries.get(conversationId), () => ( this.#blank(conversationId)));
|
|
1788
|
-
|
|
2101
|
+
const messageId = confirmation.messageId;
|
|
2102
|
+
const alreadyHeld = Boolean(messageId) && entry.recentTurns.some((t) => t.message_id === messageId);
|
|
2103
|
+
if (!alreadyHeld) {
|
|
2104
|
+
const turn = { role, content, timestamp: stamp };
|
|
2105
|
+
if (messageId) turn.message_id = messageId;
|
|
2106
|
+
entry.recentTurns.push(turn);
|
|
2107
|
+
}
|
|
2108
|
+
const count = confirmation.serverMessageCount;
|
|
2109
|
+
if (count !== null && count !== void 0) {
|
|
2110
|
+
this.#noteCount(entry, Number(count), _nullishCoalesce(confirmation.inFlight, () => ( 0)));
|
|
2111
|
+
}
|
|
1789
2112
|
entry.lastActivityAt = _nullishCoalesce(parseIso(stamp), () => ( this.#now()));
|
|
1790
2113
|
this.#touch(conversationId, entry);
|
|
1791
2114
|
this.#evict();
|
|
1792
2115
|
}
|
|
2116
|
+
/**
|
|
2117
|
+
* Record the server's message count for a conversation.
|
|
2118
|
+
*
|
|
2119
|
+
* The streamed write path's half of `appendTurn`'s confirmation: a streamed
|
|
2120
|
+
* turn is appended when it is sent, and the count arrives later, once the
|
|
2121
|
+
* server has written it. A count for a conversation this process holds
|
|
2122
|
+
* nothing for is ignored.
|
|
2123
|
+
*/
|
|
2124
|
+
noteServerCount(conversationId, count) {
|
|
2125
|
+
if (!conversationId) return;
|
|
2126
|
+
const entry = this.#entries.get(conversationId);
|
|
2127
|
+
if (entry !== void 0) this.#noteCount(entry, Number(count), 0);
|
|
2128
|
+
}
|
|
2129
|
+
/**
|
|
2130
|
+
* Compare the server's count with what the entry holds.
|
|
2131
|
+
*
|
|
2132
|
+
* The count is taken after one of this process's own writes, so it proves
|
|
2133
|
+
* the process takes part in the conversation.
|
|
2134
|
+
*
|
|
2135
|
+
* Server ahead of an entry that was in sync: something else wrote, and the
|
|
2136
|
+
* entry is marked shared for good. Server ahead of an entry that was never
|
|
2137
|
+
* in sync: this process joined late (a restart, an eviction), and `reseed`
|
|
2138
|
+
* will fix it. `inFlight` covers this process's own writes that the server
|
|
2139
|
+
* has counted and the entry has not appended yet, so two concurrent writes
|
|
2140
|
+
* do not look like a second writer.
|
|
2141
|
+
*/
|
|
2142
|
+
#noteCount(entry, count, inFlight) {
|
|
2143
|
+
entry.participant = true;
|
|
2144
|
+
if (count > localMessageCount(entry) + inFlight) {
|
|
2145
|
+
if (entry.synced) entry.shared = true;
|
|
2146
|
+
} else if (entry.serverMessageCount === null) {
|
|
2147
|
+
entry.synced = true;
|
|
2148
|
+
}
|
|
2149
|
+
entry.serverMessageCount = Math.max(_nullishCoalesce(entry.serverMessageCount, () => ( 0)), count);
|
|
2150
|
+
}
|
|
1793
2151
|
/**
|
|
1794
2152
|
* Apply a `compaction_update` bundle.
|
|
1795
2153
|
*
|
|
1796
2154
|
* Replaces the summary fields from the bundle's `conversation_context` and
|
|
1797
|
-
*
|
|
1798
|
-
*
|
|
1799
|
-
*
|
|
2155
|
+
* drops the buffered turns the new summary covers.
|
|
2156
|
+
*
|
|
2157
|
+
* Which turns those are is decided by count, not by clock. The bundle says
|
|
2158
|
+
* how many messages the summary covers and how many the conversation held
|
|
2159
|
+
* when the bundle was built, so the last `total - compacted` of its
|
|
2160
|
+
* `recent_turns` are exactly the uncovered messages. Turns this process
|
|
2161
|
+
* appended after the server took that count are kept behind them. Timestamps
|
|
2162
|
+
* cannot do this job: the REST write returns the time of the response and
|
|
2163
|
+
* not of the stored row, a caller may supply its own message time, and a
|
|
2164
|
+
* streamed turn is stamped when a background write runs.
|
|
2165
|
+
*
|
|
2166
|
+
* A bundle from a server that sends no counts falls back to the older
|
|
2167
|
+
* timestamp prune, and the entry is left out of sync so it is never used to
|
|
2168
|
+
* answer on its own.
|
|
1800
2169
|
*/
|
|
1801
2170
|
applyCompaction(bundle) {
|
|
1802
2171
|
if (typeof bundle !== "object" || bundle === null) return;
|
|
@@ -1806,22 +2175,84 @@ var ShortTermStore = class {
|
|
|
1806
2175
|
);
|
|
1807
2176
|
if (!conversationId) return;
|
|
1808
2177
|
const endTs = parseIso(_nullishCoalesce(cc["end_timestamp"], () => ( cc["compacted_at"])));
|
|
2178
|
+
const compactedAt = parseIso(cc["compacted_at"]);
|
|
2179
|
+
const compactedCount = Number(_nullishCoalesce(cc["compacted_message_count"], () => ( 0))) || 0;
|
|
2180
|
+
const totalCount = Number(_nullishCoalesce(cc["total_message_count"], () => ( 0))) || 0;
|
|
1809
2181
|
const entry = _nullishCoalesce(this.#entries.get(conversationId), () => ( this.#blank(conversationId)));
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
2182
|
+
const heldAt = parseIso(entry.compactedAt);
|
|
2183
|
+
if (compactedAt !== null && heldAt !== null && compactedAt < heldAt) return;
|
|
2184
|
+
const block = contextBlockOf(cc);
|
|
2185
|
+
if (block) {
|
|
2186
|
+
entry.contextBlock = block;
|
|
2187
|
+
entry.summary = cc["summary"] || block;
|
|
2188
|
+
entry.factualParagraph = null;
|
|
2189
|
+
entry.conversationalParagraph = null;
|
|
2190
|
+
} else {
|
|
2191
|
+
entry.summary = cc["summary"] || entry.summary;
|
|
2192
|
+
entry.factualParagraph = cc["factual_paragraph"] || entry.factualParagraph;
|
|
2193
|
+
entry.conversationalParagraph = cc["conversational_paragraph"] || entry.conversationalParagraph;
|
|
2194
|
+
}
|
|
1813
2195
|
entry.currentState = { ..._nullishCoalesce(cc["current_state"], () => ( {})) };
|
|
1814
2196
|
entry.keyExtractions = { ..._nullishCoalesce(cc["key_extractions"], () => ( {})) };
|
|
1815
2197
|
entry.compactionId = cc["compaction_id"] || entry.compactionId;
|
|
1816
2198
|
entry.compactedAt = cc["compacted_at"] || entry.compactedAt;
|
|
1817
2199
|
entry.endTimestamp = cc["end_timestamp"] || entry.endTimestamp;
|
|
1818
|
-
if (
|
|
1819
|
-
|
|
2200
|
+
if (compactedCount > 0 && compactedCount <= totalCount) {
|
|
2201
|
+
const uncovered = totalCount - compactedCount;
|
|
2202
|
+
const serverTurns = Array.isArray(cc["recent_turns"]) ? cc["recent_turns"] : [];
|
|
2203
|
+
const tail = uncovered > 0 ? serverTurns.slice(-uncovered).map((t) => ({ ...t })) : [];
|
|
2204
|
+
const ahead = localMessageCount(entry) - totalCount;
|
|
2205
|
+
const newer = entry.synced && ahead > 0 ? entry.recentTurns.slice(-ahead).filter((t) => !heldIn(t, tail)) : [];
|
|
2206
|
+
entry.recentTurns = [...tail, ...newer];
|
|
2207
|
+
entry.compactedMessageCount = compactedCount;
|
|
2208
|
+
entry.serverMessageCount = Math.max(_nullishCoalesce(entry.serverMessageCount, () => ( 0)), totalCount);
|
|
2209
|
+
entry.synced = tail.length === uncovered;
|
|
2210
|
+
} else {
|
|
2211
|
+
if (endTs !== null && entry.recentTurns.length > 0) {
|
|
2212
|
+
entry.recentTurns = entry.recentTurns.filter((t) => isAfter(t.timestamp, endTs));
|
|
2213
|
+
}
|
|
2214
|
+
entry.synced = false;
|
|
1820
2215
|
}
|
|
1821
2216
|
entry.lastActivityAt = this.#now();
|
|
1822
2217
|
this.#touch(conversationId, entry);
|
|
1823
2218
|
this.#evict();
|
|
1824
2219
|
}
|
|
2220
|
+
/**
|
|
2221
|
+
* Bring an entry back in step from a `/context-for-prompt` response.
|
|
2222
|
+
*
|
|
2223
|
+
* Called after the server was asked because the entry was not complete. The
|
|
2224
|
+
* response lists every message the server's summary does not cover, which is
|
|
2225
|
+
* what `recentTurns` is meant to hold.
|
|
2226
|
+
*
|
|
2227
|
+
* Only an entry that already exists is reseeded. Creating one here would let
|
|
2228
|
+
* a process that never writes to the conversation answer from a snapshot it
|
|
2229
|
+
* has no way to refresh.
|
|
2230
|
+
*
|
|
2231
|
+
* If the server's summary is not the one cached here, the entry cannot
|
|
2232
|
+
* render it, so it stays out of sync until the next bundle brings the
|
|
2233
|
+
* summary itself.
|
|
2234
|
+
*
|
|
2235
|
+
* Turns held locally and absent from the response are kept when they come
|
|
2236
|
+
* after everything the response has: they were written or sent after the
|
|
2237
|
+
* server read its messages.
|
|
2238
|
+
*/
|
|
2239
|
+
reseed(conversationId, state) {
|
|
2240
|
+
if (!conversationId) return;
|
|
2241
|
+
const entry = this.#entries.get(conversationId);
|
|
2242
|
+
if (entry === void 0 || entry.shared) return;
|
|
2243
|
+
entry.serverMessageCount = Math.max(
|
|
2244
|
+
_nullishCoalesce(entry.serverMessageCount, () => ( 0)),
|
|
2245
|
+
Number(state.totalMessageCount) || 0
|
|
2246
|
+
);
|
|
2247
|
+
if ((state.compactionId || null) !== entry.compactionId) {
|
|
2248
|
+
entry.synced = false;
|
|
2249
|
+
return;
|
|
2250
|
+
}
|
|
2251
|
+
const serverTurns = state.recentMessages.map((m) => ({ ...m }));
|
|
2252
|
+
entry.recentTurns = [...serverTurns, ...turnsAfter(entry.recentTurns, serverTurns)];
|
|
2253
|
+
entry.compactedMessageCount = Number(state.compactedMessageCount) || 0;
|
|
2254
|
+
entry.synced = true;
|
|
2255
|
+
}
|
|
1825
2256
|
invalidate(conversationId) {
|
|
1826
2257
|
this.#entries.delete(conversationId);
|
|
1827
2258
|
}
|
|
@@ -1832,6 +2263,7 @@ var ShortTermStore = class {
|
|
|
1832
2263
|
return {
|
|
1833
2264
|
conversationId,
|
|
1834
2265
|
summary: null,
|
|
2266
|
+
contextBlock: null,
|
|
1835
2267
|
factualParagraph: null,
|
|
1836
2268
|
conversationalParagraph: null,
|
|
1837
2269
|
currentState: {},
|
|
@@ -1840,7 +2272,12 @@ var ShortTermStore = class {
|
|
|
1840
2272
|
compactedAt: null,
|
|
1841
2273
|
endTimestamp: null,
|
|
1842
2274
|
recentTurns: [],
|
|
1843
|
-
lastActivityAt: this.#now()
|
|
2275
|
+
lastActivityAt: this.#now(),
|
|
2276
|
+
compactedMessageCount: 0,
|
|
2277
|
+
serverMessageCount: null,
|
|
2278
|
+
participant: false,
|
|
2279
|
+
synced: false,
|
|
2280
|
+
shared: false
|
|
1844
2281
|
};
|
|
1845
2282
|
}
|
|
1846
2283
|
/** Re-insert so this key becomes the most recently used. */
|
|
@@ -1857,6 +2294,520 @@ var ShortTermStore = class {
|
|
|
1857
2294
|
}
|
|
1858
2295
|
};
|
|
1859
2296
|
|
|
2297
|
+
// src/cache/turn-store.ts
|
|
2298
|
+
var SWEEP_EVERY_WRITES = 50;
|
|
2299
|
+
function bytesOf(text) {
|
|
2300
|
+
return new TextEncoder().encode(text).length;
|
|
2301
|
+
}
|
|
2302
|
+
var TurnStore = (_class3 = class {
|
|
2303
|
+
|
|
2304
|
+
__init5() {this.onDisk = false}
|
|
2305
|
+
#now;
|
|
2306
|
+
#seq = 0;
|
|
2307
|
+
#writes = 0;
|
|
2308
|
+
#conversations = /* @__PURE__ */ new Map();
|
|
2309
|
+
#vectors = /* @__PURE__ */ new Map();
|
|
2310
|
+
constructor(options = {}) {;_class3.prototype.__init5.call(this);
|
|
2311
|
+
this.limits = _nullishCoalesce(options.limits, () => ( { ..._chunkICUFS3B5cjs.HISTORY_SEARCH.store_limits }));
|
|
2312
|
+
this.#now = _nullishCoalesce(options.now, () => ( (() => Date.now() / 1e3)));
|
|
2313
|
+
}
|
|
2314
|
+
add(conversationId, role, content, timestamp, options = {}) {
|
|
2315
|
+
this.addMany(conversationId, [
|
|
2316
|
+
{ role, content, timestamp: _nullishCoalesce(timestamp, () => ( "")), message_id: _nullishCoalesce(options.messageId, () => ( null)), position: _nullishCoalesce(options.position, () => ( null)) }
|
|
2317
|
+
]);
|
|
2318
|
+
}
|
|
2319
|
+
/**
|
|
2320
|
+
* Insert turns not held yet; returns how many were new. A turn held without
|
|
2321
|
+
* an id or position (a streamed write) gets them when the same role and
|
|
2322
|
+
* text come back from the server.
|
|
2323
|
+
*/
|
|
2324
|
+
addMany(conversationId, turns) {
|
|
2325
|
+
if (!conversationId) return 0;
|
|
2326
|
+
const conv = _nullishCoalesce(this.#conversations.get(conversationId), () => ( { lastActivity: 0, turns: [] }));
|
|
2327
|
+
let added = 0;
|
|
2328
|
+
for (const turn of turns) {
|
|
2329
|
+
const role = String(turn.role || "user");
|
|
2330
|
+
const content = String(_nullishCoalesce(turn.content, () => ( "")));
|
|
2331
|
+
if (!content) continue;
|
|
2332
|
+
const messageId = turn.message_id ? String(turn.message_id) : null;
|
|
2333
|
+
const raw = turn.position;
|
|
2334
|
+
const position = typeof raw === "number" && Number.isInteger(raw) ? raw : /^\d+$/.test(String(_nullishCoalesce(raw, () => ( "")))) ? Number(raw) : null;
|
|
2335
|
+
const ts = turn.timestamp instanceof Date ? turn.timestamp.toISOString() : String(_nullishCoalesce(turn.timestamp, () => ( "")));
|
|
2336
|
+
if (messageId !== null) {
|
|
2337
|
+
const held = conv.turns.find((t) => t.message_id === messageId);
|
|
2338
|
+
if (held !== void 0) {
|
|
2339
|
+
if (position !== null) held.position = position;
|
|
2340
|
+
continue;
|
|
2341
|
+
}
|
|
2342
|
+
}
|
|
2343
|
+
const same = conv.turns.find(
|
|
2344
|
+
(t) => t.role === role && t.content === content && (t.message_id === null || t.position === null)
|
|
2345
|
+
);
|
|
2346
|
+
if (same !== void 0) {
|
|
2347
|
+
same.message_id = _nullishCoalesce(same.message_id, () => ( messageId));
|
|
2348
|
+
same.position = _nullishCoalesce(position, () => ( same.position));
|
|
2349
|
+
continue;
|
|
2350
|
+
}
|
|
2351
|
+
conv.turns.push({ seq: ++this.#seq, role, content, timestamp: ts, message_id: messageId, position });
|
|
2352
|
+
added += 1;
|
|
2353
|
+
}
|
|
2354
|
+
conv.lastActivity = this.#now();
|
|
2355
|
+
this.#conversations.set(conversationId, conv);
|
|
2356
|
+
this.#trim(conv);
|
|
2357
|
+
this.#writes += 1;
|
|
2358
|
+
if (this.#writes % SWEEP_EVERY_WRITES === 0) this.sweep();
|
|
2359
|
+
return added;
|
|
2360
|
+
}
|
|
2361
|
+
#trim(conv) {
|
|
2362
|
+
const limits = this.limits;
|
|
2363
|
+
let size = conv.turns.reduce((n2, t) => n2 + bytesOf(t.content), 0);
|
|
2364
|
+
while (conv.turns.length > limits.max_turns_per_conversation || size > limits.max_bytes_per_conversation) {
|
|
2365
|
+
const excess = Math.max(conv.turns.length - limits.max_turns_per_conversation, 1);
|
|
2366
|
+
const order = [...conv.turns].sort(
|
|
2367
|
+
(a, b) => (_nullishCoalesce(a.position, () => ( Number.MAX_SAFE_INTEGER))) - (_nullishCoalesce(b.position, () => ( Number.MAX_SAFE_INTEGER))) || a.seq - b.seq
|
|
2368
|
+
);
|
|
2369
|
+
const gone = new Set(order.slice(0, excess).map((t) => t.seq));
|
|
2370
|
+
if (gone.size === 0) break;
|
|
2371
|
+
for (const t of conv.turns) if (gone.has(t.seq)) size -= bytesOf(t.content);
|
|
2372
|
+
conv.turns = conv.turns.filter((t) => !gone.has(t.seq));
|
|
2373
|
+
for (const vectors of this.#vectors.values()) for (const seq of gone) vectors.delete(seq);
|
|
2374
|
+
}
|
|
2375
|
+
}
|
|
2376
|
+
/** Idle conversations, then the least recently used beyond the count, then more until the bytes fit. */
|
|
2377
|
+
sweep() {
|
|
2378
|
+
const limits = this.limits;
|
|
2379
|
+
const now = this.#now();
|
|
2380
|
+
for (const [id, conv] of this.#conversations) {
|
|
2381
|
+
if (conv.lastActivity < now - limits.idle_ttl_seconds) this.drop(id);
|
|
2382
|
+
}
|
|
2383
|
+
const byRecent = [...this.#conversations.entries()].sort((a, b) => b[1].lastActivity - a[1].lastActivity);
|
|
2384
|
+
for (const [id] of byRecent.slice(limits.max_conversations)) this.drop(id);
|
|
2385
|
+
while (this.sizeBytes() > limits.max_file_bytes) {
|
|
2386
|
+
const oldest = this.conversations()[0];
|
|
2387
|
+
if (oldest === void 0) break;
|
|
2388
|
+
this.drop(oldest);
|
|
2389
|
+
}
|
|
2390
|
+
}
|
|
2391
|
+
drop(conversationId) {
|
|
2392
|
+
const conv = this.#conversations.get(conversationId);
|
|
2393
|
+
if (conv === void 0) return;
|
|
2394
|
+
for (const vectors of this.#vectors.values()) for (const t of conv.turns) vectors.delete(t.seq);
|
|
2395
|
+
this.#conversations.delete(conversationId);
|
|
2396
|
+
}
|
|
2397
|
+
clear() {
|
|
2398
|
+
this.#conversations.clear();
|
|
2399
|
+
this.#vectors.clear();
|
|
2400
|
+
}
|
|
2401
|
+
close() {
|
|
2402
|
+
}
|
|
2403
|
+
/** In conversation order: by server position where known, else as written here. */
|
|
2404
|
+
turns(conversationId) {
|
|
2405
|
+
const conv = this.#conversations.get(conversationId);
|
|
2406
|
+
if (conv === void 0) return [];
|
|
2407
|
+
const bySeq = [...conv.turns].sort((a, b) => a.seq - b.seq);
|
|
2408
|
+
const key = /* @__PURE__ */ new Map();
|
|
2409
|
+
let top = 0;
|
|
2410
|
+
let step = 0;
|
|
2411
|
+
for (const t of bySeq) {
|
|
2412
|
+
if (t.position !== null) {
|
|
2413
|
+
key.set(t.seq, t.position);
|
|
2414
|
+
top = Math.max(top, t.position);
|
|
2415
|
+
step = 0;
|
|
2416
|
+
} else {
|
|
2417
|
+
step += 1;
|
|
2418
|
+
key.set(t.seq, top + step * 1e-6);
|
|
2419
|
+
}
|
|
2420
|
+
}
|
|
2421
|
+
return bySeq.sort((a, b) => (_nullishCoalesce(key.get(a.seq), () => ( 0))) - (_nullishCoalesce(key.get(b.seq), () => ( 0))) || a.seq - b.seq).map((t) => ({ ...t }));
|
|
2422
|
+
}
|
|
2423
|
+
/** Turns the server also holds: archived tool results are local only. Python: `count`. */
|
|
2424
|
+
count(conversationId) {
|
|
2425
|
+
return (_nullishCoalesce(_optionalChain([this, 'access', _65 => _65.#conversations, 'access', _66 => _66.get, 'call', _67 => _67(conversationId), 'optionalAccess', _68 => _68.turns]), () => ( []))).filter((t) => t.role !== "tool").length;
|
|
2426
|
+
}
|
|
2427
|
+
sizeBytes() {
|
|
2428
|
+
let n2 = 0;
|
|
2429
|
+
for (const conv of this.#conversations.values()) for (const t of conv.turns) n2 += bytesOf(t.content);
|
|
2430
|
+
return n2;
|
|
2431
|
+
}
|
|
2432
|
+
/** Conversation ids, least recently active first. */
|
|
2433
|
+
conversations() {
|
|
2434
|
+
return [...this.#conversations.entries()].sort((a, b) => a[1].lastActivity - b[1].lastActivity).map(([id]) => id);
|
|
2435
|
+
}
|
|
2436
|
+
vectors(seqs, model) {
|
|
2437
|
+
const held = this.#vectors.get(model);
|
|
2438
|
+
const out = /* @__PURE__ */ new Map();
|
|
2439
|
+
if (held === void 0) return out;
|
|
2440
|
+
for (const seq of seqs) {
|
|
2441
|
+
const v = held.get(seq);
|
|
2442
|
+
if (v !== void 0) out.set(seq, v);
|
|
2443
|
+
}
|
|
2444
|
+
return out;
|
|
2445
|
+
}
|
|
2446
|
+
putVectors(model, items) {
|
|
2447
|
+
const held = _nullishCoalesce(this.#vectors.get(model), () => ( /* @__PURE__ */ new Map()));
|
|
2448
|
+
for (const [seq, vec] of items) held.set(seq, vec);
|
|
2449
|
+
this.#vectors.set(model, held);
|
|
2450
|
+
}
|
|
2451
|
+
}, _class3);
|
|
2452
|
+
|
|
2453
|
+
// src/cache/history-search.ts
|
|
2454
|
+
var WORD_RE = /[\p{L}\p{N}\p{M}]+/gu;
|
|
2455
|
+
var FORMS = _nullishCoalesce(_chunkICUFS3B5cjs.HISTORY_SEARCH.irregular_forms, () => ( {}));
|
|
2456
|
+
function tokenize2(text) {
|
|
2457
|
+
const out = [];
|
|
2458
|
+
for (const word of _nullishCoalesce((text || "").toLowerCase().match(WORD_RE), () => ( []))) {
|
|
2459
|
+
if (/^[\x00-\x7f]+$/.test(word)) out.push(..._chunkICUFS3B5cjs.tokenize.call(void 0, _nullishCoalesce(FORMS[word], () => ( word))));
|
|
2460
|
+
else out.push(word);
|
|
2461
|
+
}
|
|
2462
|
+
return out;
|
|
2463
|
+
}
|
|
2464
|
+
var LITERAL_SOURCE = String.raw`"([^"]{3,})"|\b([A-Z0-9][A-Z0-9-]{3,})\b|(\d[\d,.:/-]*\d|\d)`;
|
|
2465
|
+
var SENTENCE_RE = /(?<=[.!?])\s+/;
|
|
2466
|
+
function literalsOf(query) {
|
|
2467
|
+
const out = [];
|
|
2468
|
+
for (const m of (query || "").matchAll(new RegExp(LITERAL_SOURCE, "g"))) {
|
|
2469
|
+
const quoted = m[1];
|
|
2470
|
+
const value = quoted || m[2] || m[3];
|
|
2471
|
+
if (value && (quoted || /\d/.test(value))) out.push(value.toLowerCase());
|
|
2472
|
+
}
|
|
2473
|
+
return out;
|
|
2474
|
+
}
|
|
2475
|
+
function cosine(a, b) {
|
|
2476
|
+
let dot = 0;
|
|
2477
|
+
let na = 0;
|
|
2478
|
+
let nb = 0;
|
|
2479
|
+
const n2 = Math.min(a.length, b.length);
|
|
2480
|
+
for (let i = 0; i < n2; i++) {
|
|
2481
|
+
dot += a[i] * b[i];
|
|
2482
|
+
na += a[i] * a[i];
|
|
2483
|
+
nb += b[i] * b[i];
|
|
2484
|
+
}
|
|
2485
|
+
return na && nb ? dot / (Math.sqrt(na) * Math.sqrt(nb)) : 0;
|
|
2486
|
+
}
|
|
2487
|
+
function words(text) {
|
|
2488
|
+
return text.split(/\s+/).filter(Boolean);
|
|
2489
|
+
}
|
|
2490
|
+
function excerptOf(content, terms, literals, maxWords) {
|
|
2491
|
+
let sentences = content.trim().split(SENTENCE_RE).filter((s2) => s2.trim());
|
|
2492
|
+
if (sentences.length === 0) sentences = [content.trim()];
|
|
2493
|
+
const score = (sentence) => {
|
|
2494
|
+
const low = sentence.toLowerCase();
|
|
2495
|
+
const held = new Set(tokenize2(sentence));
|
|
2496
|
+
let n2 = 0;
|
|
2497
|
+
for (const t of terms) if (held.has(t)) n2 += 1;
|
|
2498
|
+
for (const lit of literals) if (low.includes(lit)) n2 += 2;
|
|
2499
|
+
return n2;
|
|
2500
|
+
};
|
|
2501
|
+
let best = 0;
|
|
2502
|
+
for (let i = 1; i < sentences.length; i++) if (score(sentences[i]) > score(sentences[best])) best = i;
|
|
2503
|
+
let lo = best;
|
|
2504
|
+
let hi = best;
|
|
2505
|
+
let count = words(sentences[best]).length;
|
|
2506
|
+
for (; ; ) {
|
|
2507
|
+
let grew = false;
|
|
2508
|
+
for (const j of [hi + 1, lo - 1]) {
|
|
2509
|
+
if (j >= 0 && j < sentences.length && count + words(sentences[j]).length <= maxWords) {
|
|
2510
|
+
count += words(sentences[j]).length;
|
|
2511
|
+
lo = Math.min(lo, j);
|
|
2512
|
+
hi = Math.max(hi, j);
|
|
2513
|
+
grew = true;
|
|
2514
|
+
}
|
|
2515
|
+
}
|
|
2516
|
+
if (!grew) break;
|
|
2517
|
+
}
|
|
2518
|
+
let text = sentences.slice(lo, hi + 1).join(" ");
|
|
2519
|
+
if (words(text).length > maxWords) text = words(text).slice(0, maxWords).join(" ") + " ...";
|
|
2520
|
+
return (lo > 0 ? "... " : "") + text + (hi < sentences.length - 1 && !text.endsWith("...") ? " ..." : "");
|
|
2521
|
+
}
|
|
2522
|
+
var FENCE = /^\s*(?:```|~~~)/;
|
|
2523
|
+
var TABLE_RULE = /^\s*\|?\s*:?-{2,}/;
|
|
2524
|
+
var SENTENCE = /(?<=[.!?])\s+/;
|
|
2525
|
+
function splitPassages(content, maxWords) {
|
|
2526
|
+
const text = (_nullishCoalesce(content, () => ( ""))).trim();
|
|
2527
|
+
if (words(text).length <= maxWords) return text ? [text] : [];
|
|
2528
|
+
const out = [];
|
|
2529
|
+
const lines = text.split("\n");
|
|
2530
|
+
let i = 0;
|
|
2531
|
+
while (i < lines.length) {
|
|
2532
|
+
const line = lines[i];
|
|
2533
|
+
if (FENCE.test(line)) {
|
|
2534
|
+
let j2 = i + 1;
|
|
2535
|
+
while (j2 < lines.length && !FENCE.test(lines[j2])) j2 += 1;
|
|
2536
|
+
out.push(...windowsOf(lines.slice(i + 1, j2), maxWords));
|
|
2537
|
+
i = j2 + 1;
|
|
2538
|
+
continue;
|
|
2539
|
+
}
|
|
2540
|
+
if (line.trim().startsWith("|")) {
|
|
2541
|
+
let j2 = i;
|
|
2542
|
+
while (j2 < lines.length && lines[j2].trim().startsWith("|")) j2 += 1;
|
|
2543
|
+
const rows = lines.slice(i, j2).filter((r) => !TABLE_RULE.test(r)).map((r) => r.trim());
|
|
2544
|
+
const [header, body] = rows.length > 1 ? [rows[0], rows.slice(1)] : ["", rows];
|
|
2545
|
+
for (const row of body) {
|
|
2546
|
+
const both = `${header} ${row}`.trim();
|
|
2547
|
+
out.push(words(both).length <= Math.trunc(maxWords * 3 / 2) ? both : row);
|
|
2548
|
+
}
|
|
2549
|
+
i = j2;
|
|
2550
|
+
continue;
|
|
2551
|
+
}
|
|
2552
|
+
let j = i;
|
|
2553
|
+
while (j < lines.length && lines[j].trim() && !FENCE.test(lines[j]) && !lines[j].trim().startsWith("|")) j += 1;
|
|
2554
|
+
if (j === i) {
|
|
2555
|
+
i += 1;
|
|
2556
|
+
continue;
|
|
2557
|
+
}
|
|
2558
|
+
const block = lines.slice(i, j);
|
|
2559
|
+
if (block.length > 1 && block.every((b) => words(b).length <= 25)) {
|
|
2560
|
+
out.push(...windowsOf(block, maxWords));
|
|
2561
|
+
} else {
|
|
2562
|
+
const sentences = block.map((b) => b.trim()).join(" ").split(SENTENCE).filter((x) => x.trim());
|
|
2563
|
+
out.push(...windowsOf(sentences, maxWords));
|
|
2564
|
+
}
|
|
2565
|
+
i = j;
|
|
2566
|
+
}
|
|
2567
|
+
const kept = out.filter((x) => x.trim());
|
|
2568
|
+
return kept.length ? kept : [text];
|
|
2569
|
+
}
|
|
2570
|
+
function windowsOf(pieces, maxWords) {
|
|
2571
|
+
const out = [];
|
|
2572
|
+
let cur = [];
|
|
2573
|
+
let used = 0;
|
|
2574
|
+
for (const raw of pieces) {
|
|
2575
|
+
const piece = raw.trim();
|
|
2576
|
+
if (!piece) continue;
|
|
2577
|
+
const n2 = words(piece).length;
|
|
2578
|
+
if (cur.length && used + n2 > maxWords) {
|
|
2579
|
+
out.push(cur.join(" "));
|
|
2580
|
+
cur = [];
|
|
2581
|
+
used = 0;
|
|
2582
|
+
}
|
|
2583
|
+
if (n2 > maxWords) {
|
|
2584
|
+
const w = words(piece);
|
|
2585
|
+
for (let k = 0; k < w.length; k += maxWords) out.push(w.slice(k, k + maxWords).join(" "));
|
|
2586
|
+
continue;
|
|
2587
|
+
}
|
|
2588
|
+
cur.push(piece);
|
|
2589
|
+
used += n2;
|
|
2590
|
+
}
|
|
2591
|
+
if (cur.length) out.push(cur.join(" "));
|
|
2592
|
+
return out;
|
|
2593
|
+
}
|
|
2594
|
+
function askedKinds(query) {
|
|
2595
|
+
const out = [];
|
|
2596
|
+
for (const [name, spec] of Object.entries(_nullishCoalesce(_chunkICUFS3B5cjs.HISTORY_SEARCH.asked_kinds, () => ( {})))) {
|
|
2597
|
+
if (name.startsWith("$") || typeof spec !== "object") continue;
|
|
2598
|
+
if (new RegExp(spec.query, "i").test(_nullishCoalesce(query, () => ( "")))) out.push(new RegExp(spec.value));
|
|
2599
|
+
}
|
|
2600
|
+
return out;
|
|
2601
|
+
}
|
|
2602
|
+
function asksHowItStarted(query) {
|
|
2603
|
+
const spec = _chunkICUFS3B5cjs.HISTORY_SEARCH.early_query;
|
|
2604
|
+
if (!_optionalChain([spec, 'optionalAccess', _69 => _69.pattern])) return false;
|
|
2605
|
+
return new RegExp(spec.pattern, (_nullishCoalesce(spec.flags, () => ( ""))).includes("i") ? "i" : "").test(_nullishCoalesce(query, () => ( "")));
|
|
2606
|
+
}
|
|
2607
|
+
async function searchTurns(turns, query, options = {}) {
|
|
2608
|
+
const params = _chunkICUFS3B5cjs.HISTORY_SEARCH;
|
|
2609
|
+
const k = params.max_excerpts;
|
|
2610
|
+
const skip = new Set(_nullishCoalesce(options.exclude, () => ( [])));
|
|
2611
|
+
const pool = turns.filter((t) => t.content && !skip.has(t.content) && !skip.has(_nullishCoalesce(t.message_id, () => ( ""))));
|
|
2612
|
+
const terms = new Set(tokenize2(query || ""));
|
|
2613
|
+
const literals = literalsOf(query);
|
|
2614
|
+
if (pool.length === 0 || terms.size === 0 && literals.length === 0 && !options.encoder) return [];
|
|
2615
|
+
const maxWords = params.max_words_per_excerpt;
|
|
2616
|
+
const units = [];
|
|
2617
|
+
pool.forEach((t, ti) => {
|
|
2618
|
+
if (!params.passages) {
|
|
2619
|
+
units.push({ seq: t.seq, content: t.content, turn: ti, first: true, last: true, part: -1 });
|
|
2620
|
+
return;
|
|
2621
|
+
}
|
|
2622
|
+
const parts = splitPassages(t.content, maxWords);
|
|
2623
|
+
parts.forEach((part, pi) => {
|
|
2624
|
+
units.push({
|
|
2625
|
+
seq: t.seq,
|
|
2626
|
+
content: part,
|
|
2627
|
+
turn: ti,
|
|
2628
|
+
first: pi === 0,
|
|
2629
|
+
last: pi === parts.length - 1,
|
|
2630
|
+
part: parts.length > 1 ? pi : -1
|
|
2631
|
+
});
|
|
2632
|
+
});
|
|
2633
|
+
});
|
|
2634
|
+
const docs = units.map((u) => tokenize2(u.content));
|
|
2635
|
+
const bm = new (0, _chunkICUFS3B5cjs.BM25)(docs);
|
|
2636
|
+
const termList = [...terms];
|
|
2637
|
+
const rows = units.map((turn, i) => {
|
|
2638
|
+
const held = new Set(docs[i]);
|
|
2639
|
+
let matched = 0;
|
|
2640
|
+
for (const t of terms) if (held.has(t)) matched += 1;
|
|
2641
|
+
const low = turn.content.toLowerCase();
|
|
2642
|
+
let literal = 0;
|
|
2643
|
+
for (const lit of literals) if (low.includes(lit)) literal += 1;
|
|
2644
|
+
return { i, bm25: matched ? bm.score(termList, i) : 0, matched, literal };
|
|
2645
|
+
});
|
|
2646
|
+
const need = Math.min(params.min_matched_terms, Math.max(1, terms.size));
|
|
2647
|
+
const rareCap = Math.max(1, Math.trunc((_nullishCoalesce(params.rare_term_max_share, () => ( 0))) * units.length));
|
|
2648
|
+
const rare = /* @__PURE__ */ new Set();
|
|
2649
|
+
for (const t of terms) {
|
|
2650
|
+
let n3 = 0;
|
|
2651
|
+
for (const doc of docs) if (doc.includes(t)) n3 += 1;
|
|
2652
|
+
if (n3 > 0 && n3 <= rareCap) rare.add(t);
|
|
2653
|
+
}
|
|
2654
|
+
let eligible;
|
|
2655
|
+
if (params.passages) {
|
|
2656
|
+
const turnTerms = /* @__PURE__ */ new Map();
|
|
2657
|
+
for (const r of rows) {
|
|
2658
|
+
const held = _nullishCoalesce(turnTerms.get(units[r.i].turn), () => ( /* @__PURE__ */ new Set()));
|
|
2659
|
+
for (const t of docs[r.i]) if (terms.has(t)) held.add(t);
|
|
2660
|
+
turnTerms.set(units[r.i].turn, held);
|
|
2661
|
+
}
|
|
2662
|
+
eligible = rows.filter(
|
|
2663
|
+
(r) => r.literal > 0 || r.matched > 0 && (turnTerms.get(units[r.i].turn).size >= need || docs[r.i].some((t) => rare.has(t)))
|
|
2664
|
+
);
|
|
2665
|
+
} else {
|
|
2666
|
+
eligible = rows.filter(
|
|
2667
|
+
(r) => r.literal > 0 || r.matched >= need || r.matched > 0 && docs[r.i].some((t) => rare.has(t))
|
|
2668
|
+
);
|
|
2669
|
+
}
|
|
2670
|
+
const rrf = params.rrf_k;
|
|
2671
|
+
const fused = /* @__PURE__ */ new Map();
|
|
2672
|
+
const via = /* @__PURE__ */ new Map();
|
|
2673
|
+
for (const r of eligible) fused.set(r.i, 0);
|
|
2674
|
+
const add = (i, rank, how) => {
|
|
2675
|
+
fused.set(i, (_nullishCoalesce(fused.get(i), () => ( 0))) + 1 / (rrf + rank + 1));
|
|
2676
|
+
if (!via.has(i)) via.set(i, how);
|
|
2677
|
+
};
|
|
2678
|
+
eligible.filter((r) => r.literal > 0).sort((a, b) => b.literal - a.literal || a.i - b.i).forEach((r, rank) => add(r.i, rank, "literal"));
|
|
2679
|
+
eligible.filter((r) => r.bm25 > 0).sort((a, b) => b.bm25 - a.bm25 || a.i - b.i).forEach((r, rank) => add(r.i, rank, "bm25"));
|
|
2680
|
+
const kinds = askedKinds(query);
|
|
2681
|
+
if (kinds.length) {
|
|
2682
|
+
rows.filter((r) => r.matched > 0 && kinds.some((k2) => k2.test(units[r.i].content))).sort((a, b) => b.bm25 - a.bm25 || a.i - b.i).forEach((r, rank) => add(r.i, rank, "kind"));
|
|
2683
|
+
}
|
|
2684
|
+
if (options.encoder) {
|
|
2685
|
+
const ranked2 = await embeddingRanks(units, query, options.encoder, _nullishCoalesce(options.store, () => ( null)), _nullishCoalesce(params.min_cosine, () => ( 0.4)));
|
|
2686
|
+
ranked2.forEach(([i], rank) => add(i, rank, "embedding"));
|
|
2687
|
+
}
|
|
2688
|
+
if (fused.size === 0) return [];
|
|
2689
|
+
const n2 = Math.max(pool.length - 1, 1);
|
|
2690
|
+
const weight = asksHowItStarted(query) ? 0 : params.recency_weight;
|
|
2691
|
+
const top = /* @__PURE__ */ new Map();
|
|
2692
|
+
const ranked = /* @__PURE__ */ new Map();
|
|
2693
|
+
for (const [u, v] of fused) {
|
|
2694
|
+
const ti = units[u].turn;
|
|
2695
|
+
const score = v + weight * (ti / n2) / (rrf + 1);
|
|
2696
|
+
ranked.set(ti, [..._nullishCoalesce(ranked.get(ti), () => ( [])), [score, u]]);
|
|
2697
|
+
const held = top.get(ti);
|
|
2698
|
+
if (!held || score > held[0]) top.set(ti, [score, u]);
|
|
2699
|
+
}
|
|
2700
|
+
const best = [...top.keys()].sort((a, b) => top.get(b)[0] - top.get(a)[0] || a - b).slice(0, k);
|
|
2701
|
+
const perTurn = _nullishCoalesce(params.passages_per_turn, () => ( 1));
|
|
2702
|
+
const shown = (ti) => {
|
|
2703
|
+
const unit = units[top.get(ti)[1]];
|
|
2704
|
+
if (!params.passages || unit.first && unit.last) return excerptOf(pool[ti].content, terms, literals, maxWords);
|
|
2705
|
+
const picked = [...ranked.get(ti)].sort((a, b) => b[0] - a[0] || b[1] - a[1]).slice(0, perTurn).map(([, u]) => u).sort((a, b) => a - b);
|
|
2706
|
+
const parts = [];
|
|
2707
|
+
for (const u of picked) parts.push((units[u].first || parts.length ? "" : "... ") + units[u].content);
|
|
2708
|
+
return parts.join(" ... ") + (units[picked[picked.length - 1]].last ? "" : " ...");
|
|
2709
|
+
};
|
|
2710
|
+
const found = /* @__PURE__ */ new Map();
|
|
2711
|
+
for (const ti of best) {
|
|
2712
|
+
found.set(ti, {
|
|
2713
|
+
position: pool[ti].position,
|
|
2714
|
+
role: pool[ti].role,
|
|
2715
|
+
timestamp: pool[ti].timestamp,
|
|
2716
|
+
score: top.get(ti)[0],
|
|
2717
|
+
via: _nullishCoalesce(via.get(top.get(ti)[1]), () => ( "")),
|
|
2718
|
+
text: shown(ti)
|
|
2719
|
+
});
|
|
2720
|
+
}
|
|
2721
|
+
const before2 = _nullishCoalesce(params.previous_turns, () => ( 0));
|
|
2722
|
+
const tail = _nullishCoalesce(params.previous_turn_words, () => ( 40));
|
|
2723
|
+
for (const i of best) {
|
|
2724
|
+
for (let j = i - before2; j < i; j++) {
|
|
2725
|
+
if (j < 0 || found.has(j)) continue;
|
|
2726
|
+
const hit = pool[i].position;
|
|
2727
|
+
const prev = pool[j].position;
|
|
2728
|
+
if (hit && prev && hit - prev > before2) continue;
|
|
2729
|
+
const w = words(pool[j].content);
|
|
2730
|
+
found.set(j, {
|
|
2731
|
+
position: prev,
|
|
2732
|
+
role: pool[j].role,
|
|
2733
|
+
timestamp: pool[j].timestamp,
|
|
2734
|
+
score: 0,
|
|
2735
|
+
via: "previous",
|
|
2736
|
+
text: w.length <= tail ? w.join(" ") : "... " + w.slice(-tail).join(" ")
|
|
2737
|
+
});
|
|
2738
|
+
}
|
|
2739
|
+
}
|
|
2740
|
+
return [...found.keys()].sort((a, b) => a - b).map((i) => found.get(i));
|
|
2741
|
+
}
|
|
2742
|
+
async function embeddingRanks(pool, query, encoder, store, minCosine) {
|
|
2743
|
+
const keyOf = (u) => (_nullishCoalesce(u.part, () => ( -1))) < 0 ? encoder.model : `${encoder.model}#p${u.part}`;
|
|
2744
|
+
const vectors = /* @__PURE__ */ new Map();
|
|
2745
|
+
if (store !== null) {
|
|
2746
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
2747
|
+
pool.forEach((u, i) => byKey.set(keyOf(u), [..._nullishCoalesce(byKey.get(keyOf(u)), () => ( [])), i]));
|
|
2748
|
+
for (const [key, idx] of byKey) {
|
|
2749
|
+
const held = store.vectors(idx.map((i) => pool[i].seq), key);
|
|
2750
|
+
for (const i of idx) {
|
|
2751
|
+
const v = held.get(pool[i].seq);
|
|
2752
|
+
if (v) vectors.set(i, v);
|
|
2753
|
+
}
|
|
2754
|
+
}
|
|
2755
|
+
}
|
|
2756
|
+
const missing = pool.map((_, i) => i).filter((i) => !vectors.has(i));
|
|
2757
|
+
if (missing.length > 0) {
|
|
2758
|
+
const fresh = await encoder.encode(missing.map((i) => pool[i].content));
|
|
2759
|
+
const put = /* @__PURE__ */ new Map();
|
|
2760
|
+
missing.forEach((i, j) => {
|
|
2761
|
+
const v = Float32Array.from(_nullishCoalesce(fresh[j], () => ( [])));
|
|
2762
|
+
vectors.set(i, v);
|
|
2763
|
+
const key = keyOf(pool[i]);
|
|
2764
|
+
put.set(key, (_nullishCoalesce(put.get(key), () => ( /* @__PURE__ */ new Map()))).set(pool[i].seq, v));
|
|
2765
|
+
});
|
|
2766
|
+
if (store) for (const [key, items] of put) store.putVectors(key, items);
|
|
2767
|
+
}
|
|
2768
|
+
const q = await _asyncNullishCoalesce((await (_nullishCoalesce(encoder.encodeQuery, () => ( encoder.encode))).call(encoder, [query]))[0], async () => ( []));
|
|
2769
|
+
return pool.map((_, i) => [i, cosine(q, _nullishCoalesce(vectors.get(i), () => ( [])))]).filter(([, c]) => c >= minCosine).sort((a, b) => b[1] - a[1]);
|
|
2770
|
+
}
|
|
2771
|
+
function toolResultText(result, toolName) {
|
|
2772
|
+
let text = typeof result === "string" ? result : _nullishCoalesce(JSON.stringify(result), () => ( String(result)));
|
|
2773
|
+
const limit = _nullishCoalesce(_chunkICUFS3B5cjs.HISTORY_SEARCH.tool_result_max_chars, () => ( 16e3));
|
|
2774
|
+
if (text.length > limit) text = text.slice(0, limit) + " ...[cut]";
|
|
2775
|
+
return `[tool result: ${toolName || "tool"}] ${text}`;
|
|
2776
|
+
}
|
|
2777
|
+
function renderExcerpts(excerpts, latest = "") {
|
|
2778
|
+
if (excerpts.length === 0) return "";
|
|
2779
|
+
const lines = [_chunkICUFS3B5cjs.HISTORY_SEARCH.heading];
|
|
2780
|
+
for (const e of excerpts) {
|
|
2781
|
+
let where = e.position ? `turn ${e.position}, ${e.role}` : `${e.role}, earlier`;
|
|
2782
|
+
if (e.timestamp) {
|
|
2783
|
+
const ago = before(e.timestamp, latest);
|
|
2784
|
+
where += `, ${e.timestamp}` + (ago ? ` (${ago})` : "");
|
|
2785
|
+
}
|
|
2786
|
+
lines.push(`- ${where}: "${e.text}"`);
|
|
2787
|
+
}
|
|
2788
|
+
return lines.join("\n");
|
|
2789
|
+
}
|
|
2790
|
+
var ZONED = /(?:Z|[+-]\d{2}:\d{2})$/;
|
|
2791
|
+
function instant(stamp) {
|
|
2792
|
+
const text = (_nullishCoalesce(stamp, () => ( ""))).trim();
|
|
2793
|
+
if (!ZONED.test(text)) return null;
|
|
2794
|
+
const ms = Date.parse(text);
|
|
2795
|
+
return Number.isNaN(ms) ? null : ms / 1e3;
|
|
2796
|
+
}
|
|
2797
|
+
function before(stamp, latest) {
|
|
2798
|
+
const at = instant(stamp);
|
|
2799
|
+
const now = instant(latest);
|
|
2800
|
+
if (at === null || now === null || now < at) return "";
|
|
2801
|
+
const seconds = Math.trunc(now - at);
|
|
2802
|
+
for (const [unit, size] of [["day", 86400], ["hour", 3600], ["minute", 60]]) {
|
|
2803
|
+
if (seconds >= size) {
|
|
2804
|
+
const n2 = Math.trunc(seconds / size);
|
|
2805
|
+
return `${n2} ${unit}${n2 !== 1 ? "s" : ""} before the latest message`;
|
|
2806
|
+
}
|
|
2807
|
+
}
|
|
2808
|
+
return "less than a minute before the latest message";
|
|
2809
|
+
}
|
|
2810
|
+
|
|
1860
2811
|
// src/context/overlay.ts
|
|
1861
2812
|
var MAX_TURNS = 20;
|
|
1862
2813
|
var TOKEN_BUDGET = 2e3;
|
|
@@ -1885,7 +2836,23 @@ function overlayLocalRecentTurns(response, store, conversationId, configured) {
|
|
|
1885
2836
|
if (entry === null) return;
|
|
1886
2837
|
const existing = _nullishCoalesce(response.conversation_context, () => ( null));
|
|
1887
2838
|
if (existing !== null && !verbatimOverlayEnabled(configured)) return;
|
|
1888
|
-
const
|
|
2839
|
+
const serverCompaction = existing === null ? null : existing["compaction_id"];
|
|
2840
|
+
const localIsWhole = isComplete(entry) && (!serverCompaction || serverCompaction === entry.compactionId);
|
|
2841
|
+
let sourceTurns = entry.recentTurns;
|
|
2842
|
+
if (existing !== null && !localIsWhole) {
|
|
2843
|
+
const raw = Array.isArray(existing["recent_turns"]) ? existing["recent_turns"] : [];
|
|
2844
|
+
const serverTurns = raw.map((t) => ({
|
|
2845
|
+
role: String(_nullishCoalesce(t["role"], () => ( "user"))),
|
|
2846
|
+
content: String(_nullishCoalesce(t["content"], () => ( ""))),
|
|
2847
|
+
timestamp: String(_nullishCoalesce(t["timestamp"], () => ( "")))
|
|
2848
|
+
}));
|
|
2849
|
+
sourceTurns = [...serverTurns, ...turnsAfter(entry.recentTurns, serverTurns)];
|
|
2850
|
+
}
|
|
2851
|
+
const localTurns = budgetRecentTurns(sourceTurns).map((t) => ({
|
|
2852
|
+
role: t.role,
|
|
2853
|
+
content: t.content,
|
|
2854
|
+
timestamp: t.timestamp
|
|
2855
|
+
}));
|
|
1889
2856
|
const serverField = (name) => existing === null ? void 0 : existing[name];
|
|
1890
2857
|
const orLocal = (name, local) => {
|
|
1891
2858
|
const value = serverField(name);
|
|
@@ -1902,7 +2869,7 @@ function overlayLocalRecentTurns(response, store, conversationId, configured) {
|
|
|
1902
2869
|
compacted_at: orLocal("compacted_at", entry.compactedAt),
|
|
1903
2870
|
conversation_id: conversationId
|
|
1904
2871
|
};
|
|
1905
|
-
} catch (
|
|
2872
|
+
} catch (e13) {
|
|
1906
2873
|
}
|
|
1907
2874
|
}
|
|
1908
2875
|
|
|
@@ -1915,7 +2882,7 @@ function stringify(value) {
|
|
|
1915
2882
|
if (t === "string" || t === "number" || t === "boolean") return String(value);
|
|
1916
2883
|
try {
|
|
1917
2884
|
return _nullishCoalesce(JSON.stringify(value), () => ( ""));
|
|
1918
|
-
} catch (
|
|
2885
|
+
} catch (e14) {
|
|
1919
2886
|
return String(value);
|
|
1920
2887
|
}
|
|
1921
2888
|
}
|
|
@@ -1940,14 +2907,28 @@ function buildRecentMessages(turns) {
|
|
|
1940
2907
|
role: t.role || "user",
|
|
1941
2908
|
content: _nullishCoalesce(t.content, () => ( "")),
|
|
1942
2909
|
timestamp: t.timestamp,
|
|
1943
|
-
message_id: `local-${idx}`
|
|
2910
|
+
message_id: t.message_id || `local-${idx}`
|
|
1944
2911
|
}));
|
|
1945
2912
|
}
|
|
1946
2913
|
function compactedMessageCount(_entry) {
|
|
1947
2914
|
return 0;
|
|
1948
2915
|
}
|
|
2916
|
+
function blockOf(entry) {
|
|
2917
|
+
if (entry.contextBlock) return entry.contextBlock.trim();
|
|
2918
|
+
if (entry.summary && entry.summary.startsWith(CONTEXT_BLOCK_PREFIX)) return entry.summary.trim();
|
|
2919
|
+
return null;
|
|
2920
|
+
}
|
|
1949
2921
|
function formatStructured(entry, recent) {
|
|
1950
2922
|
const parts = [];
|
|
2923
|
+
const block = blockOf(entry);
|
|
2924
|
+
if (block) {
|
|
2925
|
+
parts.push(block);
|
|
2926
|
+
if (recent.length > 0) {
|
|
2927
|
+
parts.push(`## Recent Turns (${recent.length})`);
|
|
2928
|
+
for (const m of recent) parts.push(`**${m.role}**: ${m.content}`);
|
|
2929
|
+
}
|
|
2930
|
+
return parts.filter(Boolean).join("\n\n").trim();
|
|
2931
|
+
}
|
|
1951
2932
|
if (entry.summary) {
|
|
1952
2933
|
parts.push("## Summary");
|
|
1953
2934
|
parts.push(entry.summary.trim());
|
|
@@ -1982,9 +2963,11 @@ function formatStructured(entry, recent) {
|
|
|
1982
2963
|
}
|
|
1983
2964
|
function formatNarrative(entry, recent) {
|
|
1984
2965
|
const parts = [];
|
|
1985
|
-
|
|
1986
|
-
if (
|
|
1987
|
-
else if (entry.
|
|
2966
|
+
const block = blockOf(entry);
|
|
2967
|
+
if (block) parts.push(block);
|
|
2968
|
+
else if (entry.summary) parts.push(entry.summary.trim());
|
|
2969
|
+
if (!block && entry.conversationalParagraph) parts.push(entry.conversationalParagraph.trim());
|
|
2970
|
+
else if (!block && entry.factualParagraph) parts.push(entry.factualParagraph.trim());
|
|
1988
2971
|
if (recent.length > 0) {
|
|
1989
2972
|
const tail = recent.map((m) => `${m.role}: ${m.content}`).join("\n");
|
|
1990
2973
|
parts.push(`Recent exchanges:
|
|
@@ -1994,6 +2977,10 @@ ${tail}`);
|
|
|
1994
2977
|
}
|
|
1995
2978
|
function formatBullets(entry, recent) {
|
|
1996
2979
|
const parts = [];
|
|
2980
|
+
const block = blockOf(entry);
|
|
2981
|
+
if (block) {
|
|
2982
|
+
return [block, ...recent.map((m) => `- ${m.role}: ${m.content}`)].join("\n").trim();
|
|
2983
|
+
}
|
|
1997
2984
|
if (entry.summary) parts.push(`- Summary: ${entry.summary.trim()}`);
|
|
1998
2985
|
for (const [k, v] of Object.entries(_nullishCoalesce(entry.currentState, () => ( {})))) {
|
|
1999
2986
|
parts.push(`- ${k}: ${stringify(v)}`);
|
|
@@ -2031,7 +3018,9 @@ function renderForPrompt(entry, style = DEFAULT_STYLE, now = Date.now) {
|
|
|
2031
3018
|
recent_messages: recent,
|
|
2032
3019
|
recent_message_count: recent.length,
|
|
2033
3020
|
compacted_message_count: compacted,
|
|
2034
|
-
total_message_count: recent.length + compacted
|
|
3021
|
+
total_message_count: recent.length + compacted,
|
|
3022
|
+
context_block: blockOf(entry),
|
|
3023
|
+
compaction_id: entry.compactionId
|
|
2035
3024
|
};
|
|
2036
3025
|
}
|
|
2037
3026
|
function renderCompacted(entry, format = "structured", correlationId = "") {
|
|
@@ -2176,10 +3165,10 @@ function servedItemIds(hit) {
|
|
|
2176
3165
|
}
|
|
2177
3166
|
return ids;
|
|
2178
3167
|
}
|
|
2179
|
-
function tryServeFromCache(cache, scope, params, maxItems) {
|
|
3168
|
+
async function tryServeFromCache(cache, scope, params, maxItems) {
|
|
2180
3169
|
try {
|
|
2181
3170
|
const scoped = scopeLookupParams(scope, params);
|
|
2182
|
-
const hit = cache.
|
|
3171
|
+
const hit = await cache.lookupAsync({
|
|
2183
3172
|
searchQuery: _nullishCoalesce(scoped.searchQuery, () => ( null)),
|
|
2184
3173
|
entityId: _nullishCoalesce(scoped.entityId, () => ( null)),
|
|
2185
3174
|
customerId: _nullishCoalesce(scoped.customerId, () => ( null)),
|
|
@@ -2190,7 +3179,7 @@ function tryServeFromCache(cache, scope, params, maxItems) {
|
|
|
2190
3179
|
});
|
|
2191
3180
|
if (hit === null) return { response: null, hit: null };
|
|
2192
3181
|
return { response: buildAnticipationResponse(hit), hit };
|
|
2193
|
-
} catch (
|
|
3182
|
+
} catch (e15) {
|
|
2194
3183
|
return { response: null, hit: null };
|
|
2195
3184
|
}
|
|
2196
3185
|
}
|
|
@@ -2267,6 +3256,8 @@ function mergeScopeResults(scopeResults) {
|
|
|
2267
3256
|
episodes: [],
|
|
2268
3257
|
emotions: [],
|
|
2269
3258
|
temporal_events: [],
|
|
3259
|
+
items: [],
|
|
3260
|
+
excerpts: [],
|
|
2270
3261
|
scope_map: {},
|
|
2271
3262
|
conversation_context: null,
|
|
2272
3263
|
profile: null,
|
|
@@ -2276,6 +3267,8 @@ function mergeScopeResults(scopeResults) {
|
|
|
2276
3267
|
total_items: 0,
|
|
2277
3268
|
metadata: null
|
|
2278
3269
|
};
|
|
3270
|
+
const rankedSeen = /* @__PURE__ */ new Set();
|
|
3271
|
+
const rankedItems = [];
|
|
2279
3272
|
for (const [scopeName, response] of scopeResults) {
|
|
2280
3273
|
out.scopes_queried.push(scopeName);
|
|
2281
3274
|
if (out.metadata === null && response.metadata !== void 0) {
|
|
@@ -2300,8 +3293,32 @@ function mergeScopeResults(scopeResults) {
|
|
|
2300
3293
|
out[collection].push(item);
|
|
2301
3294
|
}
|
|
2302
3295
|
}
|
|
3296
|
+
const excerpts = response["excerpts"];
|
|
3297
|
+
if (Array.isArray(excerpts)) {
|
|
3298
|
+
for (const item of excerpts) {
|
|
3299
|
+
const id = itemId2(item);
|
|
3300
|
+
if (id !== void 0) {
|
|
3301
|
+
if (seen.has(id)) continue;
|
|
3302
|
+
seen.add(id);
|
|
3303
|
+
out.scope_map[id] = scopeName;
|
|
3304
|
+
}
|
|
3305
|
+
out.excerpts.push(item);
|
|
3306
|
+
}
|
|
3307
|
+
}
|
|
3308
|
+
const ranked = response["items"];
|
|
3309
|
+
if (Array.isArray(ranked)) {
|
|
3310
|
+
for (const item of ranked) {
|
|
3311
|
+
const id = itemId2(item);
|
|
3312
|
+
if (id !== void 0) {
|
|
3313
|
+
if (rankedSeen.has(id)) continue;
|
|
3314
|
+
rankedSeen.add(id);
|
|
3315
|
+
}
|
|
3316
|
+
rankedItems.push(item);
|
|
3317
|
+
}
|
|
3318
|
+
}
|
|
2303
3319
|
}
|
|
2304
|
-
out.
|
|
3320
|
+
out.items = sortByRankScore(rankedItems).map((item, n2) => ({ ...item, rank: n2 + 1 }));
|
|
3321
|
+
out.total_items = ITEM_COLLECTIONS.reduce((n2, c) => n2 + out[c].length, 0) + out.excerpts.length;
|
|
2305
3322
|
return out;
|
|
2306
3323
|
}
|
|
2307
3324
|
function oneDecimal(value) {
|
|
@@ -2327,7 +3344,18 @@ function formatForPrompt(ctx, options = {}) {
|
|
|
2327
3344
|
const includeScope = _nullishCoalesce(options.includeScope, () => ( false));
|
|
2328
3345
|
const includeConversationContext = _nullishCoalesce(options.includeConversationContext, () => ( true));
|
|
2329
3346
|
const sections = [];
|
|
2330
|
-
|
|
3347
|
+
const ranked = _nullishCoalesce(ctx.items, () => ( []));
|
|
3348
|
+
if (ranked.length > 0) {
|
|
3349
|
+
const lines = ranked.map((it, n2) => {
|
|
3350
|
+
let label = rankedLabel(String(_nullishCoalesce(it["category"], () => ( ""))));
|
|
3351
|
+
if (includeScope) label += `, scope: ${scopeOf(ctx, it)}`;
|
|
3352
|
+
return `${n2 + 1}. [${label}] ${String(_nullishCoalesce(it.content, () => ( "")))}`;
|
|
3353
|
+
});
|
|
3354
|
+
sections.push(`### Memories
|
|
3355
|
+
${lines.join("\n")}`);
|
|
3356
|
+
}
|
|
3357
|
+
const typed = ranked.length === 0;
|
|
3358
|
+
if (typed && ctx.facts.length > 0) {
|
|
2331
3359
|
const lines = ctx.facts.map((f) => {
|
|
2332
3360
|
let line = `- ${String(_nullishCoalesce(f.content, () => ( "")))}`;
|
|
2333
3361
|
if (includeScope) line += ` [scope: ${scopeOf(ctx, f)}]`;
|
|
@@ -2336,7 +3364,7 @@ function formatForPrompt(ctx, options = {}) {
|
|
|
2336
3364
|
sections.push(`### Facts
|
|
2337
3365
|
${lines.join("\n")}`);
|
|
2338
3366
|
}
|
|
2339
|
-
if (ctx.preferences.length > 0) {
|
|
3367
|
+
if (typed && ctx.preferences.length > 0) {
|
|
2340
3368
|
const lines = ctx.preferences.map((p) => {
|
|
2341
3369
|
const extras = [];
|
|
2342
3370
|
if (includeScope) extras.push(`scope: ${scopeOf(ctx, p)}`);
|
|
@@ -2349,7 +3377,7 @@ ${lines.join("\n")}`);
|
|
|
2349
3377
|
sections.push(`### Preferences
|
|
2350
3378
|
${lines.join("\n")}`);
|
|
2351
3379
|
}
|
|
2352
|
-
if (ctx.episodes.length > 0) {
|
|
3380
|
+
if (typed && ctx.episodes.length > 0) {
|
|
2353
3381
|
const lines = ctx.episodes.map((e) => {
|
|
2354
3382
|
let line = `- ${String(_nullishCoalesce(e["summary"], () => ( "")))}`;
|
|
2355
3383
|
if (includeScope) line += ` [scope: ${scopeOf(ctx, e)}]`;
|
|
@@ -2358,7 +3386,7 @@ ${lines.join("\n")}`);
|
|
|
2358
3386
|
sections.push(`### Episodes
|
|
2359
3387
|
${lines.join("\n")}`);
|
|
2360
3388
|
}
|
|
2361
|
-
if (ctx.emotions.length > 0) {
|
|
3389
|
+
if (typed && ctx.emotions.length > 0) {
|
|
2362
3390
|
const lines = ctx.emotions.map((em) => {
|
|
2363
3391
|
const extras = [];
|
|
2364
3392
|
if (includeScope) extras.push(`scope: ${scopeOf(ctx, em)}`);
|
|
@@ -2372,7 +3400,7 @@ ${lines.join("\n")}`);
|
|
|
2372
3400
|
sections.push(`### Emotions
|
|
2373
3401
|
${lines.join("\n")}`);
|
|
2374
3402
|
}
|
|
2375
|
-
if (ctx.temporal_events.length > 0) {
|
|
3403
|
+
if (typed && ctx.temporal_events.length > 0) {
|
|
2376
3404
|
const lines = ctx.temporal_events.map((te) => {
|
|
2377
3405
|
const extras = [];
|
|
2378
3406
|
if (includeScope) extras.push(`scope: ${scopeOf(ctx, te)}`);
|
|
@@ -2626,7 +3654,10 @@ function buildTool(target, options = {}, onWarning = () => {
|
|
|
2626
3654
|
}
|
|
2627
3655
|
|
|
2628
3656
|
// src/client.ts
|
|
2629
|
-
|
|
3657
|
+
function localModelOff() {
|
|
3658
|
+
return ["off", "0", "false", "no", "none"].includes((_nullishCoalesce(_chunkZKOJDUN4cjs.getEnv.call(void 0, "SYNAP_SDK_LOCAL_MODEL"), () => ( ""))).trim().toLowerCase());
|
|
3659
|
+
}
|
|
3660
|
+
var SynapClient = (_class4 = class _SynapClient {
|
|
2630
3661
|
// Native-private (`#`), not TypeScript `private`. TS `private` is erased at
|
|
2631
3662
|
// compile time, so the field stays enumerable at runtime and a JS consumer
|
|
2632
3663
|
// can still reach it. These two were public and made `client.transport
|
|
@@ -2649,10 +3680,20 @@ var SynapClient = class {
|
|
|
2649
3680
|
|
|
2650
3681
|
#closed = false;
|
|
2651
3682
|
#initialized = false;
|
|
3683
|
+
#identity;
|
|
2652
3684
|
#registryKeys;
|
|
2653
3685
|
#compactionSubscribers;
|
|
2654
3686
|
#shortTerm;
|
|
3687
|
+
/** Every raw turn, past compaction, for local history search. */
|
|
3688
|
+
#turnStore;
|
|
3689
|
+
/** A local embedding model for history search; null = keywords only. */
|
|
3690
|
+
#localEncoder = null;
|
|
3691
|
+
/** `history_search_model`: "auto", an "onnx:..." name, or null for none. */
|
|
3692
|
+
#localModelName = "auto";
|
|
3693
|
+
#localModelStarted = false;
|
|
3694
|
+
#backfillAfter = /* @__PURE__ */ new Map();
|
|
2655
3695
|
#stVerbatimOverlay;
|
|
3696
|
+
#agentModel = {};
|
|
2656
3697
|
#logger;
|
|
2657
3698
|
#stAuthoritative;
|
|
2658
3699
|
#turns;
|
|
@@ -2690,13 +3731,14 @@ var SynapClient = class {
|
|
|
2690
3731
|
userAgent: `@maximem/synap-js-sdk/${SDK_VERSION}`
|
|
2691
3732
|
});
|
|
2692
3733
|
if (options.heartbeat) this.#transport.startHeartbeat();
|
|
2693
|
-
this.#
|
|
3734
|
+
this.#transport.identityResolver = () => this.#resolveIdentity();
|
|
3735
|
+
this.#anticipationCache = new (0, _chunkICUFS3B5cjs.AnticipationCache)();
|
|
2694
3736
|
this.#fetchHooks = {
|
|
2695
|
-
beforeFetch: (scope, options2) => {
|
|
3737
|
+
beforeFetch: async (scope, options2) => {
|
|
2696
3738
|
const o2 = options2;
|
|
2697
3739
|
if (_nullishCoalesce(o2["query_date"], () => ( o2["queryDate"]))) return null;
|
|
2698
3740
|
if (_nullishCoalesce(o2["max_results_per_query"], () => ( o2["maxResultsPerQuery"]))) return null;
|
|
2699
|
-
const attempt = tryServeFromCache(
|
|
3741
|
+
const attempt = await tryServeFromCache(
|
|
2700
3742
|
this.#anticipationCache,
|
|
2701
3743
|
scope,
|
|
2702
3744
|
{
|
|
@@ -2710,7 +3752,7 @@ var SynapClient = class {
|
|
|
2710
3752
|
// on entity and conversation alone, so a bundle prefetched for one
|
|
2711
3753
|
// rung answered a caller standing at another, entirely inside this
|
|
2712
3754
|
// process and invisible to every server log.
|
|
2713
|
-
scopeRung:
|
|
3755
|
+
scopeRung: _chunkICUFS3B5cjs.rungKey.call(void 0,
|
|
2714
3756
|
_nullishCoalesce(o2["scope_path"], () => ( o2["scopePath"]))
|
|
2715
3757
|
)
|
|
2716
3758
|
},
|
|
@@ -2720,7 +3762,9 @@ var SynapClient = class {
|
|
|
2720
3762
|
return {
|
|
2721
3763
|
response: attempt.response,
|
|
2722
3764
|
servedItemIds: servedItemIds(attempt.hit),
|
|
2723
|
-
bundleId: _nullishCoalesce(attempt.hit.bundleIds[0], () => ( ""))
|
|
3765
|
+
bundleId: _nullishCoalesce(attempt.hit.bundleIds[0], () => ( "")),
|
|
3766
|
+
borderline: attempt.hit.band === "borderline",
|
|
3767
|
+
raceDeadlineMs: _chunkICUFS3B5cjs.SEMANTIC_MATCH.race_deadline_ms
|
|
2724
3768
|
};
|
|
2725
3769
|
},
|
|
2726
3770
|
onAssembled: (scope, options2, response, startedAt) => {
|
|
@@ -2735,9 +3779,19 @@ var SynapClient = class {
|
|
|
2735
3779
|
this.client = { context: { fetch: async (o2 = {}) => fetchContext(this.#transport, "client", o2, this.#fetchHooks) } };
|
|
2736
3780
|
this.#compactionSubscribers = new CompactionSubscribers();
|
|
2737
3781
|
this.#shortTerm = new ShortTermStore();
|
|
3782
|
+
this.#turnStore = new TurnStore();
|
|
3783
|
+
this.#shortTerm.attachArchive(this.#turnStore);
|
|
2738
3784
|
this.#stVerbatimOverlay = _nullishCoalesce(options.st_verbatim_overlay, () => ( options.stVerbatimOverlay));
|
|
3785
|
+
this.#agentModel = {
|
|
3786
|
+
model: _nullishCoalesce(options.agent_model, () => ( options.agentModel)),
|
|
3787
|
+
contextWindow: _nullishCoalesce(options.agent_context_window, () => ( options.agentContextWindow))
|
|
3788
|
+
};
|
|
2739
3789
|
this.#logger = options.logger;
|
|
2740
3790
|
this.#stAuthoritative = _nullishCoalesce(options.sdk_st_authoritative, () => ( options.sdkStAuthoritative));
|
|
3791
|
+
this.#localEncoder = _nullishCoalesce(_nullishCoalesce(options.history_search_encoder, () => ( options.historySearchEncoder)), () => ( null));
|
|
3792
|
+
const modelOption = options.history_search_model !== void 0 ? options.history_search_model : options.historySearchModel;
|
|
3793
|
+
this.#localModelName = modelOption === void 0 ? "auto" : modelOption;
|
|
3794
|
+
if (_optionalChain([this, 'access', _70 => _70.#localEncoder, 'optionalAccess', _71 => _71.model]) === _chunkICUFS3B5cjs.SEMANTIC_MATCH.model) this.#anticipationCache.setEncoder(this.#localEncoder);
|
|
2741
3795
|
this.#turns = new TurnCounter();
|
|
2742
3796
|
this.conversation = createConversationNamespace(
|
|
2743
3797
|
this.#transport,
|
|
@@ -2754,17 +3808,24 @@ var SynapClient = class {
|
|
|
2754
3808
|
},
|
|
2755
3809
|
// Buffer the turn locally so the next fetch sees it, ahead of the server
|
|
2756
3810
|
// having persisted and compacted it.
|
|
2757
|
-
({ conversationId, role, content, timestamp }) => {
|
|
2758
|
-
this.#shortTerm.appendTurn(conversationId, role, content, timestamp
|
|
3811
|
+
({ conversationId, role, content, timestamp, messageId, serverMessageCount, inFlight }) => {
|
|
3812
|
+
this.#shortTerm.appendTurn(conversationId, role, content, timestamp, {
|
|
3813
|
+
messageId,
|
|
3814
|
+
serverMessageCount,
|
|
3815
|
+
inFlight
|
|
3816
|
+
});
|
|
2759
3817
|
},
|
|
2760
3818
|
(response, conversationId, userId, scopePath) => {
|
|
2761
3819
|
overlayLocalRecentTurns(response, this.#shortTerm, conversationId, this.#stVerbatimOverlay);
|
|
2762
|
-
this.#injectUserSummary(response, conversationId, userId,
|
|
3820
|
+
this.#injectUserSummary(response, conversationId, userId, _chunkICUFS3B5cjs.rungKey.call(void 0, scopePath));
|
|
2763
3821
|
},
|
|
2764
3822
|
{
|
|
2765
3823
|
prompt: (conversationId, style) => this.#localPrompt(conversationId, style),
|
|
2766
|
-
compacted: (conversationId, format) => this.#localCompacted(conversationId, format)
|
|
2767
|
-
|
|
3824
|
+
compacted: (conversationId, format) => this.#localCompacted(conversationId, format),
|
|
3825
|
+
reseed: (conversationId, response) => this.#reseedShortTerm(conversationId, response),
|
|
3826
|
+
historyExcerpts: (conversationId, response, query) => this.#withHistoryExcerpts(conversationId, response, query)
|
|
3827
|
+
},
|
|
3828
|
+
() => this.#agentModel
|
|
2768
3829
|
);
|
|
2769
3830
|
this.memories = createMemoriesInterface(this.#transport, ({ userId, customerId }) => {
|
|
2770
3831
|
for (const id of /* @__PURE__ */ new Set([userId, customerId])) {
|
|
@@ -2778,11 +3839,17 @@ var SynapClient = class {
|
|
|
2778
3839
|
this.#anticipationCache,
|
|
2779
3840
|
({ conversationId, role, content }) => {
|
|
2780
3841
|
this.#shortTerm.appendTurn(conversationId, role, content);
|
|
2781
|
-
}
|
|
3842
|
+
},
|
|
3843
|
+
() => this.#agentModel,
|
|
3844
|
+
({ conversationId, result, toolName }) => this.archive_tool_result(conversationId, result, { tool_name: toolName })
|
|
2782
3845
|
);
|
|
3846
|
+
this.instance._internal.setOnListen(() => this.#startLocalModel());
|
|
2783
3847
|
this.instance._internal.setCompactionApplier((bundle) => {
|
|
2784
3848
|
this.#shortTerm.applyCompaction(bundle);
|
|
2785
3849
|
});
|
|
3850
|
+
this.instance._internal.setConversationStateHandler((conversationId, messageCount) => {
|
|
3851
|
+
this.#shortTerm.noteServerCount(conversationId, messageCount);
|
|
3852
|
+
});
|
|
2786
3853
|
if (options._force_new !== true) {
|
|
2787
3854
|
const incumbent = registerIfAbsent(registryKey, this);
|
|
2788
3855
|
if (incumbent !== void 0) return incumbent;
|
|
@@ -2870,19 +3937,30 @@ var SynapClient = class {
|
|
|
2870
3937
|
/**
|
|
2871
3938
|
* Resolve `client_id` and `instance_id` from the API key.
|
|
2872
3939
|
*
|
|
2873
|
-
* Mirrors Python's `initialize()`.
|
|
2874
|
-
*
|
|
2875
|
-
*
|
|
2876
|
-
*
|
|
2877
|
-
*
|
|
2878
|
-
*
|
|
3940
|
+
* Mirrors Python's `initialize()`. Python raises "SDK not initialized" on
|
|
3941
|
+
* any call made before it; here the first request runs the same resolution
|
|
3942
|
+
* instead (`identityResolver` on the transport), so skipping this call costs
|
|
3943
|
+
* nothing and breaks no existing caller. It matters for the anticipation
|
|
3944
|
+
* cache: a bundle shared at client scope is filtered on `client_id`, and an
|
|
3945
|
+
* empty one fails that filter for every bundle.
|
|
3946
|
+
*
|
|
3947
|
+
* Calling it explicitly still locks `configure()`, as in Python. Resolving
|
|
3948
|
+
* on first use does not, because a caller who never called it could always
|
|
3949
|
+
* configure after a request, and that keeps working.
|
|
2879
3950
|
*
|
|
2880
3951
|
* Best-effort and idempotent. A whoami failure leaves whatever the
|
|
2881
3952
|
* constructor resolved and is not fatal.
|
|
2882
3953
|
*/
|
|
2883
3954
|
async initialize() {
|
|
2884
|
-
if (this.#initialized) return;
|
|
2885
3955
|
this.#initialized = true;
|
|
3956
|
+
await this.#resolveIdentity();
|
|
3957
|
+
}
|
|
3958
|
+
/** Runs whoami at most once, however many calls arrive together. */
|
|
3959
|
+
#resolveIdentity() {
|
|
3960
|
+
this.#identity ??= this.#whoami();
|
|
3961
|
+
return this.#identity;
|
|
3962
|
+
}
|
|
3963
|
+
async #whoami() {
|
|
2886
3964
|
const credentials = this.#transport.currentCredentials();
|
|
2887
3965
|
if (credentials.clientId !== "" && credentials.instanceId !== "") return;
|
|
2888
3966
|
try {
|
|
@@ -2900,7 +3978,7 @@ var SynapClient = class {
|
|
|
2900
3978
|
this.#registryKeys.push(resolvedInstanceId);
|
|
2901
3979
|
}
|
|
2902
3980
|
}
|
|
2903
|
-
} catch (
|
|
3981
|
+
} catch (e16) {
|
|
2904
3982
|
}
|
|
2905
3983
|
}
|
|
2906
3984
|
/**
|
|
@@ -2942,6 +4020,14 @@ var SynapClient = class {
|
|
|
2942
4020
|
this.#transport.setRetryPolicy(_nullishCoalesce(_nullishCoalesce(options.retryPolicy, () => ( options.retry_policy)), () => ( null)));
|
|
2943
4021
|
}
|
|
2944
4022
|
if (options.logger !== void 0) this.#logger = options.logger;
|
|
4023
|
+
const model = _nullishCoalesce(options.agent_model, () => ( options.agentModel));
|
|
4024
|
+
const window = _nullishCoalesce(options.agent_context_window, () => ( options.agentContextWindow));
|
|
4025
|
+
if (model !== void 0 || window !== void 0) {
|
|
4026
|
+
this.#agentModel = {
|
|
4027
|
+
model: _nullishCoalesce(model, () => ( this.#agentModel.model)),
|
|
4028
|
+
contextWindow: _nullishCoalesce(window, () => ( this.#agentModel.contextWindow))
|
|
4029
|
+
};
|
|
4030
|
+
}
|
|
2945
4031
|
}
|
|
2946
4032
|
/**
|
|
2947
4033
|
* Fetch and merge context across every scope with an identifier, in one call.
|
|
@@ -2975,9 +4061,11 @@ var SynapClient = class {
|
|
|
2975
4061
|
include_scope_labels: includeScopeLabels = false,
|
|
2976
4062
|
context_mode: contextMode = "in-conversation",
|
|
2977
4063
|
include_profile: includeProfile = true,
|
|
2978
|
-
last_n_conversations: lastNConversations = 1
|
|
4064
|
+
last_n_conversations: lastNConversations = 1,
|
|
4065
|
+
response_shape: responseShape = "by_type"
|
|
2979
4066
|
} = options;
|
|
2980
4067
|
validateConversationId(conversationId);
|
|
4068
|
+
responseShapeOf({ response_shape: responseShape });
|
|
2981
4069
|
const wants = (scope) => scopes === void 0 || scopes.includes(scope);
|
|
2982
4070
|
const shared = {
|
|
2983
4071
|
search_query: searchQuery,
|
|
@@ -2989,7 +4077,8 @@ var SynapClient = class {
|
|
|
2989
4077
|
// threaded three call sites by hand and missed the client branch, which
|
|
2990
4078
|
// sits one indent deeper; spreading removes that whole class of miss.
|
|
2991
4079
|
query_date: queryDate,
|
|
2992
|
-
max_results_per_query: maxResultsPerQuery
|
|
4080
|
+
max_results_per_query: maxResultsPerQuery,
|
|
4081
|
+
response_shape: responseShape
|
|
2993
4082
|
};
|
|
2994
4083
|
const labels = [];
|
|
2995
4084
|
const tasks = [];
|
|
@@ -3054,7 +4143,7 @@ var SynapClient = class {
|
|
|
3054
4143
|
merged.conversation_context = await this.conversation.context.get_context_for_prompt({
|
|
3055
4144
|
conversation_id: conversationId
|
|
3056
4145
|
});
|
|
3057
|
-
} catch (
|
|
4146
|
+
} catch (e17) {
|
|
3058
4147
|
}
|
|
3059
4148
|
}
|
|
3060
4149
|
merged.formatted_context = formatForPrompt(merged, {
|
|
@@ -3106,7 +4195,7 @@ var SynapClient = class {
|
|
|
3106
4195
|
// not carry the caller's words.
|
|
3107
4196
|
query_count: distinctQueryCount(_nullishCoalesce(options["search_query"], () => ( options["searchQuery"])))
|
|
3108
4197
|
});
|
|
3109
|
-
} catch (
|
|
4198
|
+
} catch (e18) {
|
|
3110
4199
|
}
|
|
3111
4200
|
}
|
|
3112
4201
|
/**
|
|
@@ -3131,7 +4220,7 @@ var SynapClient = class {
|
|
|
3131
4220
|
}),
|
|
3132
4221
|
scope
|
|
3133
4222
|
});
|
|
3134
|
-
} catch (
|
|
4223
|
+
} catch (e19) {
|
|
3135
4224
|
}
|
|
3136
4225
|
}
|
|
3137
4226
|
/**
|
|
@@ -3152,25 +4241,139 @@ var SynapClient = class {
|
|
|
3152
4241
|
/**
|
|
3153
4242
|
* Whether the SDK is authoritative for short-term context.
|
|
3154
4243
|
*
|
|
3155
|
-
* Resolution order matches Python's `_is_st_authoritative`:
|
|
3156
|
-
*
|
|
3157
|
-
*
|
|
4244
|
+
* Resolution order matches Python's `_is_st_authoritative`:
|
|
4245
|
+
* `SYNAP_SDK_ST_AUTHORITATIVE` first, as an explicit override in either
|
|
4246
|
+
* direction, then the option. Off by default. Being enabled does not mean
|
|
4247
|
+
* the local store is used: that also takes an entry that holds the whole
|
|
4248
|
+
* conversation, see `isComplete`.
|
|
3158
4249
|
*/
|
|
3159
4250
|
#isStAuthoritative() {
|
|
3160
|
-
if (this.#stAuthoritative === true) return true;
|
|
3161
4251
|
const raw = (_nullishCoalesce(_chunkZKOJDUN4cjs.getEnv.call(void 0, "SYNAP_SDK_ST_AUTHORITATIVE"), () => ( ""))).trim().toLowerCase();
|
|
3162
|
-
|
|
4252
|
+
if (["0", "false", "no", "off"].includes(raw)) return false;
|
|
4253
|
+
if (["1", "true", "yes", "on"].includes(raw)) return true;
|
|
4254
|
+
return this.#stAuthoritative === true;
|
|
3163
4255
|
}
|
|
3164
4256
|
/**
|
|
3165
4257
|
* Render `get_context_for_prompt` from the local store, or null to fall
|
|
3166
|
-
* through to the network.
|
|
3167
|
-
*
|
|
3168
|
-
*
|
|
4258
|
+
* through to the network.
|
|
4259
|
+
*
|
|
4260
|
+
* The store answers only when it holds the whole conversation: the server
|
|
4261
|
+
* has confirmed a count the entry accounts for. An entry that is merely
|
|
4262
|
+
* present is not enough. After a restart or an eviction it holds one turn,
|
|
4263
|
+
* and rendering that as the conversation drops everything said before it.
|
|
3169
4264
|
*/
|
|
4265
|
+
/**
|
|
4266
|
+
* `response` with the earlier turns that best match `query` (by default the
|
|
4267
|
+
* latest user message) appended, when a compaction exists. The search runs
|
|
4268
|
+
* here, over the turn archive. Python: `_with_history_excerpts`.
|
|
4269
|
+
*/
|
|
4270
|
+
async #withHistoryExcerpts(conversationId, response, query) {
|
|
4271
|
+
const r = _nullishCoalesce(response, () => ( {}));
|
|
4272
|
+
const store = this.#turnStore;
|
|
4273
|
+
const recent = Array.isArray(r["recent_messages"]) ? r["recent_messages"] : [];
|
|
4274
|
+
store.addMany(
|
|
4275
|
+
conversationId,
|
|
4276
|
+
recent.map((m) => ({
|
|
4277
|
+
role: String(_nullishCoalesce(m["role"], () => ( "user"))),
|
|
4278
|
+
content: String(_nullishCoalesce(m["content"], () => ( ""))),
|
|
4279
|
+
timestamp: String(_nullishCoalesce(m["timestamp"], () => ( ""))),
|
|
4280
|
+
message_id: typeof m["message_id"] === "string" ? m["message_id"] : null
|
|
4281
|
+
}))
|
|
4282
|
+
);
|
|
4283
|
+
const entry = this.#shortTerm.get(conversationId);
|
|
4284
|
+
const total = Math.max(Number(_nullishCoalesce(r["total_message_count"], () => ( 0))) || 0, Number(_nullishCoalesce(_optionalChain([entry, 'optionalAccess', _72 => _72.serverMessageCount]), () => ( 0))) || 0);
|
|
4285
|
+
this.#maybeBackfillTurns(conversationId, total);
|
|
4286
|
+
if (!r["context_block"]) return response;
|
|
4287
|
+
const turns = store.turns(conversationId);
|
|
4288
|
+
let q = query;
|
|
4289
|
+
if (!q) {
|
|
4290
|
+
const latest = [...recent].reverse().find((m) => m["role"] === "user");
|
|
4291
|
+
q = latest ? String(_nullishCoalesce(latest["content"], () => ( ""))) : _nullishCoalesce(_optionalChain([[...turns], 'access', _73 => _73.reverse, 'call', _74 => _74(), 'access', _75 => _75.find, 'call', _76 => _76((t) => t.role === "user"), 'optionalAccess', _77 => _77.content]), () => ( ""));
|
|
4292
|
+
}
|
|
4293
|
+
if (!q) return response;
|
|
4294
|
+
const exclude = /* @__PURE__ */ new Set();
|
|
4295
|
+
for (const m of recent) {
|
|
4296
|
+
if (typeof m["message_id"] === "string" && m["message_id"]) exclude.add(m["message_id"]);
|
|
4297
|
+
exclude.add(String(_nullishCoalesce(m["content"], () => ( ""))));
|
|
4298
|
+
}
|
|
4299
|
+
this.#startLocalModel();
|
|
4300
|
+
const hits = await searchTurns(turns, q, { exclude, encoder: this.#localEncoder, store });
|
|
4301
|
+
if (hits.length === 0) return response;
|
|
4302
|
+
const block = renderExcerpts(hits, turns.length ? turns[turns.length - 1].timestamp : "");
|
|
4303
|
+
return {
|
|
4304
|
+
...r,
|
|
4305
|
+
history_excerpts: hits.map((h) => ({ position: h.position, role: h.role, text: h.text })),
|
|
4306
|
+
history_block: block,
|
|
4307
|
+
formatted_context: (String(_nullishCoalesce(r["formatted_context"], () => ( ""))).trimEnd() + "\n\n" + block).trim()
|
|
4308
|
+
};
|
|
4309
|
+
}
|
|
4310
|
+
/**
|
|
4311
|
+
* Keep what a tool returned in this process's turn archive, so history search
|
|
4312
|
+
* can find it after a compaction. Never sent anywhere: the server's
|
|
4313
|
+
* conversation holds what people said, and a compaction is made from that.
|
|
4314
|
+
* `instance.record_tool_result` calls this too. Python: `archive_tool_result`.
|
|
4315
|
+
*/
|
|
4316
|
+
archive_tool_result(conversationId, result, options = {}) {
|
|
4317
|
+
if (!conversationId || result === null || result === void 0) return;
|
|
4318
|
+
try {
|
|
4319
|
+
this.#turnStore.add(
|
|
4320
|
+
conversationId,
|
|
4321
|
+
"tool",
|
|
4322
|
+
toolResultText(result, _nullishCoalesce(options.tool_name, () => ( options.toolName))),
|
|
4323
|
+
_nullishCoalesce(options.timestamp, () => ( (/* @__PURE__ */ new Date()).toISOString()))
|
|
4324
|
+
);
|
|
4325
|
+
} catch (e20) {
|
|
4326
|
+
}
|
|
4327
|
+
}
|
|
4328
|
+
static __initStatic() {this.BACKFILL_COOLDOWN_MS = 6e4}
|
|
4329
|
+
static __initStatic2() {this.BACKFILL_PAGE = 500}
|
|
4330
|
+
/** Fetch, in the background, turns the server holds and the archive does not. */
|
|
4331
|
+
/**
|
|
4332
|
+
* Load the local embedding model in the background, once. Searches and
|
|
4333
|
+
* lookups before it is ready match by words. Python: `_start_history_encoder`.
|
|
4334
|
+
*/
|
|
4335
|
+
#startLocalModel() {
|
|
4336
|
+
if (this.#localModelStarted) return;
|
|
4337
|
+
this.#localModelStarted = true;
|
|
4338
|
+
if (localModelOff()) return;
|
|
4339
|
+
const name = this.#localModelName === "auto" ? _chunkICUFS3B5cjs.SEMANTIC_MATCH.model : this.#localModelName;
|
|
4340
|
+
if (!name) return;
|
|
4341
|
+
const callerEncoder = this.#localEncoder;
|
|
4342
|
+
void Promise.resolve().then(() => _interopRequireWildcard(require("./onnx-encoder-4RSL6ID4.cjs"))).then(({ canRunLocalModel, loadOnnxEncoder }) => canRunLocalModel() ? loadOnnxEncoder(name) : null).then((encoder) => {
|
|
4343
|
+
if (encoder === null) return;
|
|
4344
|
+
if (callerEncoder === null) this.#localEncoder = encoder;
|
|
4345
|
+
if (encoder.model === _chunkICUFS3B5cjs.SEMANTIC_MATCH.model) this.#anticipationCache.setEncoder(encoder);
|
|
4346
|
+
}).catch(() => {
|
|
4347
|
+
});
|
|
4348
|
+
}
|
|
4349
|
+
#maybeBackfillTurns(conversationId, total) {
|
|
4350
|
+
if (total <= this.#turnStore.count(conversationId)) return;
|
|
4351
|
+
const now = Date.now();
|
|
4352
|
+
if (now < (_nullishCoalesce(this.#backfillAfter.get(conversationId), () => ( 0)))) return;
|
|
4353
|
+
this.#backfillAfter.set(conversationId, now + _SynapClient.BACKFILL_COOLDOWN_MS);
|
|
4354
|
+
void this.#backfillTurns(conversationId, total);
|
|
4355
|
+
}
|
|
4356
|
+
async #backfillTurns(conversationId, total) {
|
|
4357
|
+
try {
|
|
4358
|
+
let start = 1;
|
|
4359
|
+
while (start <= total) {
|
|
4360
|
+
const result = await this.#transport.request("conversation_turns", {
|
|
4361
|
+
pathParams: { conversation_id: conversationId },
|
|
4362
|
+
query: { start, limit: _SynapClient.BACKFILL_PAGE }
|
|
4363
|
+
});
|
|
4364
|
+
const page = _nullishCoalesce((_nullishCoalesce(result, () => ( {})))["turns"], () => ( []));
|
|
4365
|
+
this.#turnStore.addMany(conversationId, page);
|
|
4366
|
+
if (page.length < _SynapClient.BACKFILL_PAGE) break;
|
|
4367
|
+
start += _SynapClient.BACKFILL_PAGE;
|
|
4368
|
+
}
|
|
4369
|
+
} catch (error) {
|
|
4370
|
+
this.#warn(`Turn backfill for ${conversationId} failed: ${String(error)}`);
|
|
4371
|
+
}
|
|
4372
|
+
}
|
|
3170
4373
|
#localPrompt(conversationId, style) {
|
|
3171
4374
|
if (!this.#isStAuthoritative()) return null;
|
|
3172
4375
|
const entry = this.#shortTerm.get(conversationId);
|
|
3173
|
-
if (entry === null) return null;
|
|
4376
|
+
if (entry === null || !isComplete(entry)) return null;
|
|
3174
4377
|
if (entry.compactionId === null && entry.recentTurns.length === 0) return null;
|
|
3175
4378
|
return renderForPrompt(entry, style);
|
|
3176
4379
|
}
|
|
@@ -3178,9 +4381,29 @@ var SynapClient = class {
|
|
|
3178
4381
|
#localCompacted(conversationId, format) {
|
|
3179
4382
|
if (!this.#isStAuthoritative()) return null;
|
|
3180
4383
|
const entry = this.#shortTerm.get(conversationId);
|
|
3181
|
-
if (entry === null || entry.compactionId === null) return null;
|
|
4384
|
+
if (entry === null || entry.compactionId === null || !isComplete(entry)) return null;
|
|
3182
4385
|
return renderCompacted(entry, format);
|
|
3183
4386
|
}
|
|
4387
|
+
/**
|
|
4388
|
+
* Bring the local store back in step from the server's answer.
|
|
4389
|
+
*
|
|
4390
|
+
* Only for a conversation this process writes to. The server's answer lists
|
|
4391
|
+
* every message its summary does not cover, which is exactly what the entry
|
|
4392
|
+
* was missing.
|
|
4393
|
+
*/
|
|
4394
|
+
#reseedShortTerm(conversationId, response) {
|
|
4395
|
+
if (!this.#isStAuthoritative()) return;
|
|
4396
|
+
const entry = this.#shortTerm.get(conversationId);
|
|
4397
|
+
if (entry === null || !entry.participant) return;
|
|
4398
|
+
const r = _nullishCoalesce(response, () => ( {}));
|
|
4399
|
+
const recent = Array.isArray(r["recent_messages"]) ? r["recent_messages"] : [];
|
|
4400
|
+
this.#shortTerm.reseed(conversationId, {
|
|
4401
|
+
compactionId: typeof r["compaction_id"] === "string" ? r["compaction_id"] : null,
|
|
4402
|
+
recentMessages: recent,
|
|
4403
|
+
compactedMessageCount: Number(_nullishCoalesce(r["compacted_message_count"], () => ( 0))) || 0,
|
|
4404
|
+
totalMessageCount: Number(_nullishCoalesce(r["total_message_count"], () => ( 0))) || 0
|
|
4405
|
+
});
|
|
4406
|
+
}
|
|
3184
4407
|
/** Every diagnostic the SDK emits passes through here. */
|
|
3185
4408
|
#warn(message) {
|
|
3186
4409
|
if (this.#logger !== void 0) {
|
|
@@ -3201,7 +4424,7 @@ var SynapClient = class {
|
|
|
3201
4424
|
this.#transport.close();
|
|
3202
4425
|
this.#anticipationCache.clear();
|
|
3203
4426
|
}
|
|
3204
|
-
};
|
|
4427
|
+
}, _class4.__initStatic(), _class4.__initStatic2(), _class4);
|
|
3205
4428
|
function pick3(o2, snake, camel) {
|
|
3206
4429
|
const a = o2[snake];
|
|
3207
4430
|
return a !== void 0 ? a : o2[camel];
|
|
@@ -3209,7 +4432,7 @@ function pick3(o2, snake, camel) {
|
|
|
3209
4432
|
function resolveBaseUrl(options) {
|
|
3210
4433
|
const explicit = _nullishCoalesce(options.baseUrl, () => ( options.api_base_url));
|
|
3211
4434
|
if (explicit !== void 0) return explicit;
|
|
3212
|
-
const fromEnv = _optionalChain([_chunkZKOJDUN4cjs.getEnv.call(void 0, "SYNAP_BASE_URL"), 'optionalAccess',
|
|
4435
|
+
const fromEnv = _optionalChain([_chunkZKOJDUN4cjs.getEnv.call(void 0, "SYNAP_BASE_URL"), 'optionalAccess', _78 => _78.trim, 'call', _79 => _79()]);
|
|
3213
4436
|
return fromEnv !== void 0 && fromEnv !== "" ? fromEnv : void 0;
|
|
3214
4437
|
}
|
|
3215
4438
|
function resolveCredentials(options) {
|
|
@@ -3277,5 +4500,11 @@ function resolveCredentials(options) {
|
|
|
3277
4500
|
|
|
3278
4501
|
|
|
3279
4502
|
|
|
3280
|
-
|
|
4503
|
+
|
|
4504
|
+
|
|
4505
|
+
|
|
4506
|
+
|
|
4507
|
+
|
|
4508
|
+
|
|
4509
|
+
exports.ANY_SCOPE = _chunkICUFS3B5cjs.ANY_SCOPE; exports.AgentUnavailableError = _chunkT372OL3Qcjs.AgentUnavailableError; exports.AnticipationCache = _chunkICUFS3B5cjs.AnticipationCache; exports.AuthenticationError = _chunkT372OL3Qcjs.AuthenticationError; exports.BM25 = _chunkICUFS3B5cjs.BM25; exports.COMPACTION_LEVELS = COMPACTION_LEVELS; exports.CONTRACT = _chunkICUFS3B5cjs.CONTRACT; exports.ConflictError = _chunkT372OL3Qcjs.ConflictError; exports.ConnectionError = _chunkT372OL3Qcjs.ConnectionError; exports.ContextNotFoundError = _chunkT372OL3Qcjs.ContextNotFoundError; exports.DEFAULT_BASE_URL = DEFAULT_BASE_URL; exports.DEFAULT_DOCUMENT_TYPE = DEFAULT_DOCUMENT_TYPE; exports.DEFAULT_INGEST_MODE = DEFAULT_INGEST_MODE; exports.DEFAULT_RETRY_POLICY = DEFAULT_RETRY_POLICY; exports.DEFAULT_TIMEOUTS = DEFAULT_TIMEOUTS; exports.DOCUMENT_TYPES = DOCUMENT_TYPES; exports.ENDPOINTS = ENDPOINTS; exports.EXCERPT_CATEGORY = EXCERPT_CATEGORY; exports.FORGET_MODES = FORGET_MODES; exports.HttpTransport = HttpTransport; exports.INGEST_MODES = INGEST_MODES; exports.ITEM_COLLECTIONS = ITEM_COLLECTIONS; exports.InsufficientCreditsError = _chunkT372OL3Qcjs.InsufficientCreditsError; exports.InvalidConversationIdError = _chunkT372OL3Qcjs.InvalidConversationIdError; exports.InvalidInputError = _chunkT372OL3Qcjs.InvalidInputError; exports.InvalidInstanceIdError = _chunkT372OL3Qcjs.InvalidInstanceIdError; exports.ListeningAlreadyActiveError = _chunkT372OL3Qcjs.ListeningAlreadyActiveError; exports.ListeningNotActiveError = _chunkT372OL3Qcjs.ListeningNotActiveError; exports.MEMORY_TYPES = MEMORY_TYPES; exports.NetworkTimeoutError = _chunkT372OL3Qcjs.NetworkTimeoutError; exports.PermanentError = _chunkT372OL3Qcjs.PermanentError; exports.RESPONSE_SHAPES = RESPONSE_SHAPES; exports.RateLimitError = _chunkT372OL3Qcjs.RateLimitError; exports.SDKError = _chunkT372OL3Qcjs.SDKError; exports.SDK_VERSION = SDK_VERSION; exports.ServiceUnavailableError = _chunkT372OL3Qcjs.ServiceUnavailableError; exports.SessionExpiredError = _chunkT372OL3Qcjs.SessionExpiredError; exports.SynapClient = SynapClient; exports.SynapError = _chunkT372OL3Qcjs.SynapError; exports.SynapPermanentError = _chunkT372OL3Qcjs.SynapPermanentError; exports.SynapTransientError = _chunkT372OL3Qcjs.SynapTransientError; exports.THRESHOLDS = _chunkICUFS3B5cjs.THRESHOLDS; exports.TranscriptConflictError = _chunkT372OL3Qcjs.TranscriptConflictError; exports.TransientError = _chunkT372OL3Qcjs.TransientError; exports.applyResponseShape = applyResponseShape; exports.flattenContextItems = flattenContextItems; exports.formatForPrompt = formatForPrompt; exports.isOutcomeUnknown = isOutcomeUnknown; exports.isRecallQuery = _chunkICUFS3B5cjs.isRecallQuery; exports.isSynapError = _chunkT372OL3Qcjs.isSynapError; exports.mergeScopeResults = mergeScopeResults; exports.rankItems = rankItems; exports.resolvePath = resolvePath; exports.shouldRetry = shouldRetry; exports.stem = _chunkICUFS3B5cjs.stem; exports.tokenize = _chunkICUFS3B5cjs.tokenize; exports.wireRankScore = wireRankScore;
|
|
3281
4510
|
//# sourceMappingURL=index.cjs.map
|