@smartmemory/sdk-js 0.6.0 → 0.6.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -0
- package/dist/{core-CC81ya-7.js → core-CLtPrdbi.js} +279 -129
- package/dist/core.js +9 -9
- package/dist/fetch.js +19 -19
- package/dist/index.js +42 -34
- package/dist/progress.js +83 -82
- package/dist/react.js +1 -1
- package/package.json +21 -6
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
var
|
|
1
|
+
var I = (i) => {
|
|
2
2
|
throw TypeError(i);
|
|
3
3
|
};
|
|
4
|
-
var
|
|
5
|
-
var
|
|
6
|
-
const
|
|
4
|
+
var $ = (i, e, t) => e.has(i) || I("Cannot " + t);
|
|
5
|
+
var p = (i, e, t) => ($(i, e, "read from private field"), t ? t.call(i) : e.get(i)), k = (i, e, t) => e.has(i) ? I("Cannot add the same private member more than once") : e instanceof WeakSet ? e.add(i) : e.set(i, t), w = (i, e, t, r) => ($(i, e, "write to private field"), r ? r.call(i, t) : e.set(i, t), t), S = (i, e, t) => ($(i, e, "access private method"), t);
|
|
6
|
+
const R = {
|
|
7
7
|
access: "smart_memory_auth_token",
|
|
8
8
|
refresh: "smart_memory_refresh_token",
|
|
9
9
|
user: "smart_memory_user",
|
|
10
10
|
tenant: "smart_memory_tenant_id",
|
|
11
11
|
team: "smart_memory_team_id"
|
|
12
|
-
},
|
|
12
|
+
}, h = {
|
|
13
13
|
access: ["access_token", "sm_token"],
|
|
14
14
|
refresh: ["refresh_token", "sm_refresh_token"],
|
|
15
15
|
user: ["sm_user"],
|
|
16
16
|
tenant: ["tenant_id", "workspace_id", "sm_workspace_id"],
|
|
17
17
|
team: ["team_id", "sm_team_id"]
|
|
18
18
|
};
|
|
19
|
-
class
|
|
19
|
+
class U {
|
|
20
20
|
/**
|
|
21
21
|
* @param {Object} options
|
|
22
22
|
* @param {'localStorage' | 'sessionStorage' | 'memory'} [options.storage='localStorage']
|
|
23
23
|
* @param {Object} [options.keys] - Custom storage key names
|
|
24
24
|
*/
|
|
25
25
|
constructor({ storage: e = "localStorage", keys: t = {} } = {}) {
|
|
26
|
-
this.storageType = e, this.keys = { ...
|
|
26
|
+
this.storageType = e, this.keys = { ...R, ...t }, this._memory = { access: null, refresh: null, user: null, tenant: null, team: null };
|
|
27
27
|
}
|
|
28
28
|
getAccessToken() {
|
|
29
|
-
return this.storageType === "memory" ? this._memory.access : this._getFromStorage(this.keys.access,
|
|
29
|
+
return this.storageType === "memory" ? this._memory.access : this._getFromStorage(this.keys.access, h.access);
|
|
30
30
|
}
|
|
31
31
|
setAccessToken(e) {
|
|
32
32
|
if (this.storageType === "memory") {
|
|
@@ -36,7 +36,7 @@ class I {
|
|
|
36
36
|
this._setInStorage(this.keys.access, e);
|
|
37
37
|
}
|
|
38
38
|
getRefreshToken() {
|
|
39
|
-
return this.storageType === "memory" ? this._memory.refresh : this._getFromStorage(this.keys.refresh,
|
|
39
|
+
return this.storageType === "memory" ? this._memory.refresh : this._getFromStorage(this.keys.refresh, h.refresh);
|
|
40
40
|
}
|
|
41
41
|
setRefreshToken(e) {
|
|
42
42
|
if (this.storageType === "memory") {
|
|
@@ -47,7 +47,7 @@ class I {
|
|
|
47
47
|
}
|
|
48
48
|
getUser() {
|
|
49
49
|
if (this.storageType === "memory") return this._memory.user;
|
|
50
|
-
const e = this._getFromStorage(this.keys.user,
|
|
50
|
+
const e = this._getFromStorage(this.keys.user, h.user);
|
|
51
51
|
if (!e) return null;
|
|
52
52
|
try {
|
|
53
53
|
return JSON.parse(e);
|
|
@@ -63,7 +63,7 @@ class I {
|
|
|
63
63
|
this._setInStorage(this.keys.user, e ? JSON.stringify(e) : null);
|
|
64
64
|
}
|
|
65
65
|
getTenantId() {
|
|
66
|
-
return this.storageType === "memory" ? this._memory.tenant : this._normalizeId(this._getFromStorage(this.keys.tenant,
|
|
66
|
+
return this.storageType === "memory" ? this._memory.tenant : this._normalizeId(this._getFromStorage(this.keys.tenant, h.tenant));
|
|
67
67
|
}
|
|
68
68
|
setTenantId(e) {
|
|
69
69
|
const t = this._normalizeId(e);
|
|
@@ -74,7 +74,7 @@ class I {
|
|
|
74
74
|
this._setInStorage(this.keys.tenant, t);
|
|
75
75
|
}
|
|
76
76
|
getTeamId() {
|
|
77
|
-
return this.storageType === "memory" ? this._memory.team : this._normalizeId(this._getFromStorage(this.keys.team,
|
|
77
|
+
return this.storageType === "memory" ? this._memory.team : this._normalizeId(this._getFromStorage(this.keys.team, h.team));
|
|
78
78
|
}
|
|
79
79
|
setTeamId(e) {
|
|
80
80
|
const t = this._normalizeId(e);
|
|
@@ -94,27 +94,35 @@ class I {
|
|
|
94
94
|
localStorage.removeItem(e), sessionStorage.removeItem(e);
|
|
95
95
|
} catch {
|
|
96
96
|
}
|
|
97
|
-
for (const e of Object.values(
|
|
97
|
+
for (const e of Object.values(h))
|
|
98
98
|
for (const t of e)
|
|
99
99
|
try {
|
|
100
100
|
localStorage.removeItem(t), sessionStorage.removeItem(t);
|
|
101
101
|
} catch {
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
|
+
getImpersonationState() {
|
|
105
|
+
if (this.storageType === "memory") return null;
|
|
106
|
+
const e = sessionStorage.getItem("sm_impersonate_email");
|
|
107
|
+
return e ? { email: e } : null;
|
|
108
|
+
}
|
|
109
|
+
clearImpersonation() {
|
|
110
|
+
this.storageType !== "memory" && (sessionStorage.removeItem("sm_impersonate_token"), sessionStorage.removeItem("sm_impersonate_team"), sessionStorage.removeItem("sm_impersonate_tenant"), sessionStorage.removeItem("sm_impersonate_email"));
|
|
111
|
+
}
|
|
104
112
|
/** @private */
|
|
105
113
|
_getFromStorage(e, t = []) {
|
|
106
114
|
try {
|
|
107
115
|
const r = this.storageType === "localStorage" ? localStorage : sessionStorage, s = this.storageType === "localStorage" ? sessionStorage : localStorage, n = r.getItem(e) || s.getItem(e);
|
|
108
116
|
if (n != null) return n;
|
|
109
117
|
for (const a of t) {
|
|
110
|
-
const
|
|
111
|
-
if (
|
|
112
|
-
this._setInStorage(e,
|
|
118
|
+
const c = r.getItem(a) || s.getItem(a);
|
|
119
|
+
if (c != null) {
|
|
120
|
+
this._setInStorage(e, c);
|
|
113
121
|
try {
|
|
114
122
|
r.removeItem(a), s.removeItem(a);
|
|
115
123
|
} catch {
|
|
116
124
|
}
|
|
117
|
-
return
|
|
125
|
+
return c;
|
|
118
126
|
}
|
|
119
127
|
}
|
|
120
128
|
return null;
|
|
@@ -140,8 +148,8 @@ class I {
|
|
|
140
148
|
return r === "none" || r === "null" || r === "undefined" ? null : t;
|
|
141
149
|
}
|
|
142
150
|
}
|
|
143
|
-
var
|
|
144
|
-
class
|
|
151
|
+
var m, d, T;
|
|
152
|
+
class P {
|
|
145
153
|
/**
|
|
146
154
|
* @param {Object} options
|
|
147
155
|
* @param {string} options.apiBaseUrl
|
|
@@ -152,22 +160,22 @@ class T {
|
|
|
152
160
|
* @param {function(): void} options.onRefreshFailed
|
|
153
161
|
*/
|
|
154
162
|
constructor({ apiBaseUrl: e, refreshEndpoint: t, tokenManager: r, useCookieAuth: s = !1, onTokenRefreshed: n, onRefreshFailed: a }) {
|
|
155
|
-
|
|
156
|
-
|
|
163
|
+
k(this, d);
|
|
164
|
+
k(this, m, null);
|
|
157
165
|
this.apiBaseUrl = e, this.refreshEndpoint = t, this.tokenManager = r, this.useCookieAuth = s, this.onTokenRefreshed = n, this.onRefreshFailed = a;
|
|
158
166
|
}
|
|
159
167
|
async refresh() {
|
|
160
|
-
if (
|
|
161
|
-
return
|
|
162
|
-
|
|
168
|
+
if (p(this, m))
|
|
169
|
+
return p(this, m);
|
|
170
|
+
w(this, m, S(this, d, T).call(this));
|
|
163
171
|
try {
|
|
164
|
-
return await
|
|
172
|
+
return await p(this, m);
|
|
165
173
|
} finally {
|
|
166
|
-
|
|
174
|
+
w(this, m, null);
|
|
167
175
|
}
|
|
168
176
|
}
|
|
169
177
|
}
|
|
170
|
-
|
|
178
|
+
m = new WeakMap(), d = new WeakSet(), T = async function() {
|
|
171
179
|
const e = this.tokenManager.getRefreshToken();
|
|
172
180
|
if (!e && !this.useCookieAuth)
|
|
173
181
|
throw this.onRefreshFailed(), new Error("No refresh token");
|
|
@@ -182,8 +190,8 @@ l = new WeakMap(), y = new WeakSet(), k = async function() {
|
|
|
182
190
|
const s = await r.json();
|
|
183
191
|
return this.tokenManager.setAccessToken(s.access_token), s.refresh_token && this.tokenManager.setRefreshToken(s.refresh_token), this.onTokenRefreshed(s.access_token), s.access_token;
|
|
184
192
|
};
|
|
185
|
-
const
|
|
186
|
-
class
|
|
193
|
+
const b = "smart_memory_sso_redirect";
|
|
194
|
+
class C {
|
|
187
195
|
/**
|
|
188
196
|
* @param {Object} options
|
|
189
197
|
* @param {string} options.webAppUrl - Web app URL for login redirect
|
|
@@ -208,26 +216,26 @@ class S {
|
|
|
208
216
|
}
|
|
209
217
|
storeRedirect(e) {
|
|
210
218
|
try {
|
|
211
|
-
sessionStorage.setItem(
|
|
219
|
+
sessionStorage.setItem(b, e);
|
|
212
220
|
} catch (t) {
|
|
213
221
|
console.warn("Failed to store redirect URL:", t);
|
|
214
222
|
}
|
|
215
223
|
}
|
|
216
224
|
getAndClearRedirect() {
|
|
217
225
|
try {
|
|
218
|
-
const e = sessionStorage.getItem(
|
|
219
|
-
return sessionStorage.removeItem(
|
|
226
|
+
const e = sessionStorage.getItem(b);
|
|
227
|
+
return sessionStorage.removeItem(b), e;
|
|
220
228
|
} catch {
|
|
221
229
|
return null;
|
|
222
230
|
}
|
|
223
231
|
}
|
|
224
232
|
}
|
|
225
|
-
class
|
|
233
|
+
class L {
|
|
226
234
|
constructor(e) {
|
|
227
|
-
this.mode = e.mode, this.apiBaseUrl = e.apiBaseUrl, this.endpoints = e.endpoints || {}, this.listeners = /* @__PURE__ */ new Set(), this.useCookieAuth = e.useCookieAuth ?? this.mode === "sso", this.apiKey = e.apiKey || null, this.apiKey && (this.mode = "apiKey"), this.tokenManager = new
|
|
235
|
+
this.mode = e.mode, this.apiBaseUrl = e.apiBaseUrl, this.endpoints = e.endpoints || {}, this.listeners = /* @__PURE__ */ new Set(), this.useCookieAuth = e.useCookieAuth ?? this.mode === "sso", this.apiKey = e.apiKey || null, this.apiKey && (this.mode = "apiKey"), this.tokenManager = new U({
|
|
228
236
|
storage: e.storage || "localStorage",
|
|
229
237
|
keys: e.tokenKeys
|
|
230
|
-
}), this.mode !== "apiKey" ? this.refreshManager = new
|
|
238
|
+
}), this.mode !== "apiKey" ? this.refreshManager = new P({
|
|
231
239
|
apiBaseUrl: this.apiBaseUrl,
|
|
232
240
|
refreshEndpoint: this.endpoints.refresh || "/auth/refresh",
|
|
233
241
|
tokenManager: this.tokenManager,
|
|
@@ -239,7 +247,7 @@ class A {
|
|
|
239
247
|
onRefreshFailed: () => {
|
|
240
248
|
this.clearLocalAuth();
|
|
241
249
|
}
|
|
242
|
-
}) : this.refreshManager = null, this.mode === "sso" && (this.ssoManager = new
|
|
250
|
+
}) : this.refreshManager = null, this.mode === "sso" && (this.ssoManager = new C({
|
|
243
251
|
webAppUrl: e.webAppUrl,
|
|
244
252
|
allowedHosts: e.allowedRedirectHosts || [],
|
|
245
253
|
tokenManager: this.tokenManager
|
|
@@ -358,7 +366,7 @@ class A {
|
|
|
358
366
|
this.tokenManager.setTenantId(e), this.notifyListeners();
|
|
359
367
|
}
|
|
360
368
|
}
|
|
361
|
-
class
|
|
369
|
+
class g extends Error {
|
|
362
370
|
/**
|
|
363
371
|
* @param {string} message - Error message
|
|
364
372
|
* @param {number} [status=0] - HTTP status code (0 for network errors)
|
|
@@ -368,7 +376,7 @@ class h extends Error {
|
|
|
368
376
|
super(e), this.name = "APIError", this.status = t, this.detail = r;
|
|
369
377
|
}
|
|
370
378
|
}
|
|
371
|
-
class
|
|
379
|
+
class M {
|
|
372
380
|
/**
|
|
373
381
|
* @param {import('../auth/AuthCore.js').AuthCore} authCore
|
|
374
382
|
* @param {{ fetchFn?: typeof globalThis.fetch }} [options]
|
|
@@ -377,38 +385,38 @@ class v {
|
|
|
377
385
|
this.auth = e, this.baseURL = e.apiBaseUrl, this._customFetchFn = t || null;
|
|
378
386
|
}
|
|
379
387
|
get fetchFn() {
|
|
380
|
-
return this._customFetchFn || globalThis.fetch;
|
|
388
|
+
return this._customFetchFn || globalThis.fetch.bind(globalThis);
|
|
381
389
|
}
|
|
382
390
|
async request(e, t = {}) {
|
|
383
|
-
var a,
|
|
391
|
+
var a, c;
|
|
384
392
|
const r = `${this.baseURL}${e}`, s = {
|
|
385
393
|
"Content-Type": "application/json",
|
|
386
394
|
...this.auth.getAuthHeaders(t.headers)
|
|
387
395
|
}, n = this.auth.getRequestOptions({ ...t, headers: s });
|
|
388
396
|
try {
|
|
389
|
-
let
|
|
390
|
-
if (
|
|
397
|
+
let o = await this.fetchFn(r, n);
|
|
398
|
+
if (o.status === 401 && !t.__isRetry)
|
|
391
399
|
try {
|
|
392
400
|
await this.auth.refreshToken();
|
|
393
|
-
const
|
|
401
|
+
const u = {
|
|
394
402
|
"Content-Type": "application/json",
|
|
395
403
|
...this.auth.getAuthHeaders(t.headers)
|
|
396
404
|
};
|
|
397
|
-
|
|
405
|
+
o = await this.fetchFn(
|
|
398
406
|
r,
|
|
399
|
-
this.auth.getRequestOptions({ ...n, headers:
|
|
407
|
+
this.auth.getRequestOptions({ ...n, headers: u, __isRetry: !0 })
|
|
400
408
|
);
|
|
401
409
|
} catch {
|
|
402
410
|
}
|
|
403
|
-
if (
|
|
404
|
-
throw (
|
|
405
|
-
if (
|
|
411
|
+
if (o.status === 401)
|
|
412
|
+
throw (c = (a = this.auth).clearLocalAuth) == null || c.call(a), new g("Authentication required", 401, "auth_expired");
|
|
413
|
+
if (o.status === 204)
|
|
406
414
|
return null;
|
|
407
|
-
if (!
|
|
408
|
-
throw await this._handleError(
|
|
409
|
-
return await
|
|
410
|
-
} catch (
|
|
411
|
-
throw
|
|
415
|
+
if (!o.ok)
|
|
416
|
+
throw await this._handleError(o);
|
|
417
|
+
return await o.json();
|
|
418
|
+
} catch (o) {
|
|
419
|
+
throw o instanceof g ? o : new g(o.message, 0, "network_error");
|
|
412
420
|
}
|
|
413
421
|
}
|
|
414
422
|
async get(e, t = {}) {
|
|
@@ -448,14 +456,14 @@ class v {
|
|
|
448
456
|
} catch {
|
|
449
457
|
t = { message: `HTTP ${e.status}` };
|
|
450
458
|
}
|
|
451
|
-
return new
|
|
459
|
+
return new g(
|
|
452
460
|
t.detail || t.message || `HTTP ${e.status}`,
|
|
453
461
|
e.status,
|
|
454
462
|
t
|
|
455
463
|
);
|
|
456
464
|
}
|
|
457
465
|
}
|
|
458
|
-
class
|
|
466
|
+
class z {
|
|
459
467
|
constructor(e) {
|
|
460
468
|
this.api = e;
|
|
461
469
|
}
|
|
@@ -467,14 +475,14 @@ class R {
|
|
|
467
475
|
profileName: n = null,
|
|
468
476
|
conversationContext: a = null
|
|
469
477
|
}) {
|
|
470
|
-
const
|
|
478
|
+
const c = {
|
|
471
479
|
content: e,
|
|
472
480
|
memory_type: t,
|
|
473
481
|
metadata: r,
|
|
474
482
|
use_pipeline: s,
|
|
475
483
|
profile_name: n
|
|
476
484
|
};
|
|
477
|
-
return a != null && (
|
|
485
|
+
return a != null && (c.conversation_context = a), this.api.post("/memory/add", c);
|
|
478
486
|
}
|
|
479
487
|
async get(e) {
|
|
480
488
|
const t = await this.api.get(`/memory/${e}`);
|
|
@@ -503,9 +511,38 @@ class R {
|
|
|
503
511
|
let s = `/memory/list?limit=${e}&offset=${t}`;
|
|
504
512
|
return r && (s += `&memory_type=${r}`), this.api.get(s);
|
|
505
513
|
}
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
514
|
+
/**
|
|
515
|
+
* Search for memory items.
|
|
516
|
+
*
|
|
517
|
+
* @param {string} query - Search query string.
|
|
518
|
+
* @param {object} [options]
|
|
519
|
+
* @param {number} [options.topK=5]
|
|
520
|
+
* @param {boolean} [options.enableHybrid=true]
|
|
521
|
+
* @param {string|null} [options.memoryType=null]
|
|
522
|
+
* @param {boolean} [options.expertise=false] - When true (CORE-EXPERTISE-1 Phase 4a),
|
|
523
|
+
* the response shape changes from a flat list to `{results: {<expertise_type>: [items]}}`
|
|
524
|
+
* keyed by expertise type (decision, constraint, learned, opinion, reasoning, observation).
|
|
525
|
+
* Each bucket holds up to topK items.
|
|
526
|
+
* @param {boolean} [options.includeConsolidated=false] - When true (CORE-CONSOLIDATE-1),
|
|
527
|
+
* include consolidated source memories (normally hidden) in results.
|
|
528
|
+
* @param {boolean} [options.consolidationFirst=false] - When true (NEURO-1d), surface a
|
|
529
|
+
* consolidated summary above the scattered source memories it consolidates — best for
|
|
530
|
+
* synthesis queries. Opt-in; implies includeConsolidated.
|
|
531
|
+
* @param {boolean} [options.cite=false] - When true (RECALL-CITATIONS-1), the
|
|
532
|
+
* envelope gains a `citations` array of `{n, item_id, item_type, preview, score, footnote_marker}`.
|
|
533
|
+
* Empty `citations: []` when no results — distinguishes "no results" from "no citations requested".
|
|
534
|
+
* @returns {Promise<{results: Array|Object, group_roots: Object, citations?: Array}>}
|
|
535
|
+
* CORE-RECALL-LINEAGE-1: the response is ALWAYS a `SearchResponse` envelope —
|
|
536
|
+
* `results` is a flat array by default and a `{bucket: [...]}` map under
|
|
537
|
+
* `expertise: true`; `group_roots` is always present (possibly `{}`) and
|
|
538
|
+
* carries `GroupRootStub`s for any lineage root_id referenced by some
|
|
539
|
+
* result's `lineage_roots` but not itself in `results`; `citations` is
|
|
540
|
+
* present only under `cite: true`. Pre-LINEAGE-1 callers who indexed into a
|
|
541
|
+
* bare array must read `response.results` instead.
|
|
542
|
+
*/
|
|
543
|
+
async search(e, { topK: t = 5, enableHybrid: r = !0, memoryType: s = null, expertise: n = !1, cite: a = !1, decompose: c = !1, multiHop: o = !1, maxHops: u = 3, budgetMs: y = 1500, semanticHops: f = !1, includeReference: _ = !1, includeConsolidated: v = !1, consolidationFirst: A = !1 } = {}) {
|
|
544
|
+
const l = { query: e, top_k: t, enable_hybrid: r };
|
|
545
|
+
return s && (l.memory_type = s), n && (l.expertise = !0), a && (l.cite = !0), c && (l.decompose = !0), o && (l.multi_hop = !0), o && u !== 3 && (l.max_hops = u), o && y !== 1500 && (l.budget_ms = y), o && f && (l.semantic_hops = !0), _ && (l.include_reference = !0), v && (l.include_consolidated = !0), A && (l.consolidation_first = !0), this.api.post("/memory/search", l);
|
|
509
546
|
}
|
|
510
547
|
async getWorkingContext(e, t, { k: r = 20, maxTokens: s = null, strategy: n = null } = {}) {
|
|
511
548
|
const a = {
|
|
@@ -553,10 +590,10 @@ class R {
|
|
|
553
590
|
sessionDates: s = null,
|
|
554
591
|
turnsPerChunk: n = 15,
|
|
555
592
|
maxChunkChars: a = 12e3,
|
|
556
|
-
maxConcurrent:
|
|
593
|
+
maxConcurrent: c = 4
|
|
557
594
|
} = {}) {
|
|
558
|
-
const
|
|
559
|
-
return t && (
|
|
595
|
+
const o = { turns: e, turns_per_chunk: n, max_chunk_chars: a, max_concurrent: c };
|
|
596
|
+
return t && (o.session_boundaries = t), r && (o.conversation_id = r), s && (o.session_dates = s), this.api.post("/memory/ingest/conversation", o);
|
|
560
597
|
}
|
|
561
598
|
async ingestDocument(e, { title: t = null, source: r = null, chunkStrategy: s = null } = {}) {
|
|
562
599
|
const n = { content: e };
|
|
@@ -668,7 +705,7 @@ class R {
|
|
|
668
705
|
return this.api.get("/memory/clustering/stats");
|
|
669
706
|
}
|
|
670
707
|
}
|
|
671
|
-
class
|
|
708
|
+
class E {
|
|
672
709
|
constructor(e) {
|
|
673
710
|
this.api = e;
|
|
674
711
|
}
|
|
@@ -683,6 +720,9 @@ class U {
|
|
|
683
720
|
* @param {string[]} [params.evidenceIds]
|
|
684
721
|
* @param {string} [params.domain]
|
|
685
722
|
* @param {string[]} [params.tags]
|
|
723
|
+
* @param {string} [params.agentId] - Producing agent id (CORE-AGENT-ATTRIBUTION-1).
|
|
724
|
+
* When omitted, the backend auto-populates from scope.resolve_agent_id() —
|
|
725
|
+
* non-null only when the caller's user_type=='agent'.
|
|
686
726
|
*/
|
|
687
727
|
async create({
|
|
688
728
|
content: e,
|
|
@@ -691,8 +731,12 @@ class U {
|
|
|
691
731
|
sourceTraceId: s = null,
|
|
692
732
|
sourceSessionId: n = null,
|
|
693
733
|
evidenceIds: a = null,
|
|
694
|
-
domain:
|
|
695
|
-
tags:
|
|
734
|
+
domain: c = null,
|
|
735
|
+
tags: o = null,
|
|
736
|
+
rejectedAlternatives: u = null,
|
|
737
|
+
rationale: y = null,
|
|
738
|
+
constraints: f = null,
|
|
739
|
+
agentId: _ = null
|
|
696
740
|
}) {
|
|
697
741
|
return this.api.post("/memory/decisions/create", {
|
|
698
742
|
content: e,
|
|
@@ -701,13 +745,28 @@ class U {
|
|
|
701
745
|
source_trace_id: s,
|
|
702
746
|
source_session_id: n,
|
|
703
747
|
evidence_ids: a,
|
|
704
|
-
domain:
|
|
705
|
-
tags:
|
|
748
|
+
domain: c,
|
|
749
|
+
tags: o,
|
|
750
|
+
rejected_alternatives: u,
|
|
751
|
+
rationale: y,
|
|
752
|
+
constraints: f,
|
|
753
|
+
agent_id: _
|
|
706
754
|
});
|
|
707
755
|
}
|
|
708
756
|
/**
|
|
709
757
|
* List active decisions with optional filters.
|
|
710
|
-
* @param {Object} [params] - Query parameters
|
|
758
|
+
* @param {Object} [params] - Query parameters
|
|
759
|
+
* @param {string} [params.domain] - Filter by domain
|
|
760
|
+
* @param {string} [params.decision_type] - Filter by decision type
|
|
761
|
+
* @param {number} [params.min_confidence=0.0] - Minimum confidence (0..1)
|
|
762
|
+
* @param {number} [params.limit=50] - Maximum results
|
|
763
|
+
* @param {string} [params.agent_id] - Filter by producing agent id
|
|
764
|
+
* (CORE-AGENT-ATTRIBUTION-1). NULL-valued rows are excluded when set.
|
|
765
|
+
* @param {string} [params.provenance_memory_id] - Inverse-provenance filter
|
|
766
|
+
* (CORE-DECISION-PROVENANCE-LOOKUP-1). When set, returns only decisions whose
|
|
767
|
+
* provenance subgraph contains this memory id. Filters compose in-query so
|
|
768
|
+
* the response never silently truncates below `limit` when more matches exist.
|
|
769
|
+
* Unknown or out-of-scope memory ids return an empty list (never 404).
|
|
711
770
|
*/
|
|
712
771
|
async list(e = {}) {
|
|
713
772
|
const t = new URLSearchParams(e).toString();
|
|
@@ -823,7 +882,29 @@ class U {
|
|
|
823
882
|
});
|
|
824
883
|
}
|
|
825
884
|
}
|
|
826
|
-
class
|
|
885
|
+
class O {
|
|
886
|
+
constructor(e) {
|
|
887
|
+
this.api = e;
|
|
888
|
+
}
|
|
889
|
+
/**
|
|
890
|
+
* Create a new opinion with optional agent attribution.
|
|
891
|
+
* @param {string} content - Opinion content (required).
|
|
892
|
+
* @param {Object} [opts]
|
|
893
|
+
* @param {number} [opts.confidence] - Initial confidence (0..1).
|
|
894
|
+
* @param {string} [opts.subject] - What the opinion is about.
|
|
895
|
+
* @param {string} [opts.subjectType] - Type tag for the subject.
|
|
896
|
+
* @param {Object} [opts.disposition] - Disposition payload.
|
|
897
|
+
* @param {string[]} [opts.formedFrom] - Source memory ids that formed it.
|
|
898
|
+
* @param {string} [opts.domain] - Domain tag for filtered retrieval.
|
|
899
|
+
* @param {string} [opts.agentId] - Producing agent id; omit to let the
|
|
900
|
+
* server auto-populate from scope.resolve_agent_id().
|
|
901
|
+
*/
|
|
902
|
+
async createOpinion(e, t = {}) {
|
|
903
|
+
const r = { content: e };
|
|
904
|
+
return t.confidence !== void 0 && (r.confidence = t.confidence), t.subject !== void 0 && (r.subject = t.subject), t.subjectType !== void 0 && (r.subject_type = t.subjectType), t.disposition !== void 0 && (r.disposition = t.disposition), t.formedFrom !== void 0 && (r.formed_from = t.formedFrom), t.domain !== void 0 && (r.domain = t.domain), t.agentId !== void 0 && (r.agent_id = t.agentId), this.api.post("/memory/opinions/create", r);
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
class x {
|
|
827
908
|
constructor(e) {
|
|
828
909
|
this.api = e;
|
|
829
910
|
}
|
|
@@ -908,8 +989,45 @@ class P {
|
|
|
908
989
|
async getLinks(e) {
|
|
909
990
|
return this.api.get(`/memory/${encodeURIComponent(e)}/links`);
|
|
910
991
|
}
|
|
992
|
+
/**
|
|
993
|
+
* Merge unambiguous single-token entity aliases ("Hudson") into their
|
|
994
|
+
* multi-token canonical ("Rock Hudson") over the caller's workspace graph,
|
|
995
|
+
* abstaining on collisions (>=2 canonical candidates).
|
|
996
|
+
*
|
|
997
|
+
* `dry_run` is a query parameter (matching the /clustering/run precedent),
|
|
998
|
+
* not a JSON body — POST .../resolve-aliases?dry_run=true.
|
|
999
|
+
*
|
|
1000
|
+
* @param {Object} [options]
|
|
1001
|
+
* @param {boolean} [options.dryRun=false] - Compute the resolve/abstain plan and report counts without mutating the graph.
|
|
1002
|
+
* @param {boolean} [options.disambiguate=false] - Opt-in (CORE-GRAPH-ALIAS-DISAMBIG-1): additionally recover colliding surfaces by structural typed-neighbor overlap, merging only on a confident, clear winner (never mis-merge). Extractor-dependent; helps LLM-extracted graphs.
|
|
1003
|
+
* @returns {Promise<AliasResolveReport>}
|
|
1004
|
+
*/
|
|
1005
|
+
async resolveAliases({ dryRun: e = !1, disambiguate: t = !1 } = {}) {
|
|
1006
|
+
return this.api.post(`/memory/graph/resolve-aliases?dry_run=${e}&disambiguate=${t}`);
|
|
1007
|
+
}
|
|
1008
|
+
/**
|
|
1009
|
+
* Dedup cross-extractor fragmented entity nodes (CORE-GRAPH-CANONICAL-DEDUP-1).
|
|
1010
|
+
*
|
|
1011
|
+
* Collapses same-name entity-node fragments (the same entity split across >1 node because two
|
|
1012
|
+
* extractors disagreed on its type -> divergent canonical_key -> the write-time dedup missed them)
|
|
1013
|
+
* into one node, precision-first, over the caller's workspace graph. Unblocks ensemble alias
|
|
1014
|
+
* disambiguation. Opt-in, default-off. Recommended ensemble sequence: dedupEntities() then
|
|
1015
|
+
* resolveAliases({ disambiguate: true }).
|
|
1016
|
+
*
|
|
1017
|
+
* Both flags are query parameters, not a JSON body — POST .../dedup-entities?dry_run=true.
|
|
1018
|
+
*
|
|
1019
|
+
* @param {Object} [options]
|
|
1020
|
+
* @param {boolean} [options.dryRun=false] - Compute the dedup plan and report counts without mutating the graph.
|
|
1021
|
+
* @param {boolean} [options.requireStructuralConfirmation=true] - When true, a same-name pair merges only on T0 (same QID), T1 (same canonical_key), or T2 (>= tau_min shared typed entity-neighbors). When false, exact same-name clusters merge on name alone once T0/T1 fail (riskier disjoint-edge-tail recovery).
|
|
1022
|
+
* @returns {Promise<EntityDedupReport>}
|
|
1023
|
+
*/
|
|
1024
|
+
async dedupEntities({ dryRun: e = !1, requireStructuralConfirmation: t = !0 } = {}) {
|
|
1025
|
+
return this.api.post(
|
|
1026
|
+
`/memory/graph/dedup-entities?dry_run=${e}&require_structural_confirmation=${t}`
|
|
1027
|
+
);
|
|
1028
|
+
}
|
|
911
1029
|
}
|
|
912
|
-
class
|
|
1030
|
+
class q {
|
|
913
1031
|
constructor(e) {
|
|
914
1032
|
this.api = e;
|
|
915
1033
|
}
|
|
@@ -949,7 +1067,7 @@ class C {
|
|
|
949
1067
|
return this.api.delete(`/memory/teams/${e}/members/${t}`);
|
|
950
1068
|
}
|
|
951
1069
|
}
|
|
952
|
-
class
|
|
1070
|
+
class j {
|
|
953
1071
|
constructor(e) {
|
|
954
1072
|
this.api = e;
|
|
955
1073
|
}
|
|
@@ -966,7 +1084,7 @@ class M {
|
|
|
966
1084
|
return this.api.patch("/auth/llm-keys", e);
|
|
967
1085
|
}
|
|
968
1086
|
}
|
|
969
|
-
class
|
|
1087
|
+
class F {
|
|
970
1088
|
constructor(e) {
|
|
971
1089
|
this.api = e;
|
|
972
1090
|
}
|
|
@@ -992,7 +1110,7 @@ class L {
|
|
|
992
1110
|
});
|
|
993
1111
|
}
|
|
994
1112
|
}
|
|
995
|
-
class
|
|
1113
|
+
class K {
|
|
996
1114
|
constructor(e) {
|
|
997
1115
|
this.api = e;
|
|
998
1116
|
}
|
|
@@ -1013,7 +1131,7 @@ class z {
|
|
|
1013
1131
|
return this.api.delete(`/memory/api-keys/${e}`);
|
|
1014
1132
|
}
|
|
1015
1133
|
}
|
|
1016
|
-
class
|
|
1134
|
+
class H {
|
|
1017
1135
|
constructor(e) {
|
|
1018
1136
|
this.api = e;
|
|
1019
1137
|
}
|
|
@@ -1040,8 +1158,39 @@ class E {
|
|
|
1040
1158
|
async setRecallProfile(e, t) {
|
|
1041
1159
|
return this.api.put(`/memory/agents/${e}/recall-profile`, { recall_profile: t });
|
|
1042
1160
|
}
|
|
1161
|
+
/**
|
|
1162
|
+
* Get the current evaluation for an agent on a given (dimension, domain) slot.
|
|
1163
|
+
*
|
|
1164
|
+
* CORE-AGENT-2 S03-T11. Returns { evaluation: object | null }.
|
|
1165
|
+
* null means no evaluation has been written yet (cold-start) — not an error.
|
|
1166
|
+
*
|
|
1167
|
+
* @param {string} agentId - Agent identifier.
|
|
1168
|
+
* @param {string} dimension - Performance dimension (e.g. "decision_volume").
|
|
1169
|
+
* @param {string} domain - Domain string (e.g. "python").
|
|
1170
|
+
* @returns {Promise<{evaluation: object|null}>}
|
|
1171
|
+
*/
|
|
1172
|
+
async getEvaluation(e, t, r) {
|
|
1173
|
+
const s = new URLSearchParams({ dimension: t, domain: r }).toString();
|
|
1174
|
+
return this.api.get(`/memory/agents/${e}/evaluation${s ? "?" + s : ""}`);
|
|
1175
|
+
}
|
|
1176
|
+
/**
|
|
1177
|
+
* Get evaluation history for an agent on a given (dimension, domain) slot.
|
|
1178
|
+
*
|
|
1179
|
+
* CORE-AGENT-2 S03-T11. Returns { history: object[] } sorted most-recent-first.
|
|
1180
|
+
*
|
|
1181
|
+
* @param {string} agentId - Agent identifier.
|
|
1182
|
+
* @param {string} dimension - Performance dimension.
|
|
1183
|
+
* @param {string} domain - Domain string.
|
|
1184
|
+
* @param {object} [options]
|
|
1185
|
+
* @param {number} [options.limit=20] - Maximum records to return.
|
|
1186
|
+
* @returns {Promise<{history: object[]}>}
|
|
1187
|
+
*/
|
|
1188
|
+
async listEvaluationHistory(e, t, r, { limit: s = 20 } = {}) {
|
|
1189
|
+
const n = new URLSearchParams({ dimension: t, domain: r, limit: String(s) }).toString();
|
|
1190
|
+
return this.api.get(`/memory/agents/${e}/evaluation/history${n ? "?" + n : ""}`);
|
|
1191
|
+
}
|
|
1043
1192
|
}
|
|
1044
|
-
class
|
|
1193
|
+
class B {
|
|
1045
1194
|
constructor(e) {
|
|
1046
1195
|
this.api = e;
|
|
1047
1196
|
}
|
|
@@ -1055,7 +1204,7 @@ class x {
|
|
|
1055
1204
|
return this.api.get("/usage/tiers");
|
|
1056
1205
|
}
|
|
1057
1206
|
}
|
|
1058
|
-
class
|
|
1207
|
+
class D {
|
|
1059
1208
|
constructor(e) {
|
|
1060
1209
|
this.api = e;
|
|
1061
1210
|
}
|
|
@@ -1072,7 +1221,7 @@ class O {
|
|
|
1072
1221
|
return this.api.get("/memory/plugins");
|
|
1073
1222
|
}
|
|
1074
1223
|
}
|
|
1075
|
-
class
|
|
1224
|
+
class G {
|
|
1076
1225
|
constructor(e) {
|
|
1077
1226
|
this.api = e;
|
|
1078
1227
|
}
|
|
@@ -1095,7 +1244,7 @@ class q {
|
|
|
1095
1244
|
return this.api.get("/memory/token-usage/current");
|
|
1096
1245
|
}
|
|
1097
1246
|
}
|
|
1098
|
-
class
|
|
1247
|
+
class N {
|
|
1099
1248
|
constructor(e) {
|
|
1100
1249
|
this.api = e;
|
|
1101
1250
|
}
|
|
@@ -1181,8 +1330,8 @@ class F {
|
|
|
1181
1330
|
*/
|
|
1182
1331
|
async getAuditTrail(e, { changeType: t = null, userId: r = null, startTime: s = null, endTime: n = null } = {}) {
|
|
1183
1332
|
let a = `/memory/temporal/${e}/audit`;
|
|
1184
|
-
const
|
|
1185
|
-
return t &&
|
|
1333
|
+
const c = [];
|
|
1334
|
+
return t && c.push(`change_type=${t}`), r && c.push(`user_id=${r}`), s && c.push(`start_time=${s}`), n && c.push(`end_time=${n}`), c.length && (a += `?${c.join("&")}`), this.api.get(a);
|
|
1186
1335
|
}
|
|
1187
1336
|
// === TEMPORAL SEARCH ===
|
|
1188
1337
|
/**
|
|
@@ -1241,7 +1390,7 @@ class F {
|
|
|
1241
1390
|
return this.api.get(`/memory/temporal/relationships/${e}/valid-periods`);
|
|
1242
1391
|
}
|
|
1243
1392
|
}
|
|
1244
|
-
class
|
|
1393
|
+
class V {
|
|
1245
1394
|
constructor(e) {
|
|
1246
1395
|
this.api = e;
|
|
1247
1396
|
}
|
|
@@ -1310,7 +1459,7 @@ class H {
|
|
|
1310
1459
|
return this.api.get("/memory/governance/summary");
|
|
1311
1460
|
}
|
|
1312
1461
|
}
|
|
1313
|
-
class
|
|
1462
|
+
class J {
|
|
1314
1463
|
constructor(e) {
|
|
1315
1464
|
this.api = e;
|
|
1316
1465
|
}
|
|
@@ -1351,7 +1500,7 @@ class j {
|
|
|
1351
1500
|
return this.api.post("/memory/evolution/reinforce/opinions");
|
|
1352
1501
|
}
|
|
1353
1502
|
}
|
|
1354
|
-
class
|
|
1503
|
+
class W {
|
|
1355
1504
|
constructor(e) {
|
|
1356
1505
|
this.api = e;
|
|
1357
1506
|
}
|
|
@@ -1449,7 +1598,7 @@ class K {
|
|
|
1449
1598
|
});
|
|
1450
1599
|
}
|
|
1451
1600
|
}
|
|
1452
|
-
class
|
|
1601
|
+
class Y {
|
|
1453
1602
|
constructor(e) {
|
|
1454
1603
|
this.api = e;
|
|
1455
1604
|
}
|
|
@@ -1503,7 +1652,7 @@ class B {
|
|
|
1503
1652
|
return this.api.get(`/memory/reasoning/traces/${e}`);
|
|
1504
1653
|
}
|
|
1505
1654
|
}
|
|
1506
|
-
class
|
|
1655
|
+
class Z {
|
|
1507
1656
|
constructor(e) {
|
|
1508
1657
|
this.api = e;
|
|
1509
1658
|
}
|
|
@@ -1871,7 +2020,7 @@ class D {
|
|
|
1871
2020
|
return this.api.get(`/memory/ontology/updates/stats?history=${e}`);
|
|
1872
2021
|
}
|
|
1873
2022
|
}
|
|
1874
|
-
class
|
|
2023
|
+
class X {
|
|
1875
2024
|
constructor(e) {
|
|
1876
2025
|
this.api = e;
|
|
1877
2026
|
}
|
|
@@ -1900,7 +2049,7 @@ class G {
|
|
|
1900
2049
|
return e !== null && (s.protected_attributes = e), t !== null && (s.sentiment_analysis = t), r !== null && (s.topic_analysis = r), this.api.post("/memory/analytics/bias", s);
|
|
1901
2050
|
}
|
|
1902
2051
|
}
|
|
1903
|
-
class
|
|
2052
|
+
class Q {
|
|
1904
2053
|
constructor(e) {
|
|
1905
2054
|
this.api = e;
|
|
1906
2055
|
}
|
|
@@ -1936,7 +2085,7 @@ class N {
|
|
|
1936
2085
|
return this.api.get("/memory/validation/inference/rules");
|
|
1937
2086
|
}
|
|
1938
2087
|
}
|
|
1939
|
-
class
|
|
2088
|
+
class ee {
|
|
1940
2089
|
constructor(e) {
|
|
1941
2090
|
this.api = e;
|
|
1942
2091
|
}
|
|
@@ -2052,7 +2201,7 @@ class V {
|
|
|
2052
2201
|
return this.api.delete(`/memory/pipeline/configs/${e}`);
|
|
2053
2202
|
}
|
|
2054
2203
|
}
|
|
2055
|
-
class
|
|
2204
|
+
class te {
|
|
2056
2205
|
constructor(e) {
|
|
2057
2206
|
this.api = e;
|
|
2058
2207
|
}
|
|
@@ -2078,7 +2227,7 @@ class J {
|
|
|
2078
2227
|
return this.api.get(`/memory/archive/${e}`);
|
|
2079
2228
|
}
|
|
2080
2229
|
}
|
|
2081
|
-
class
|
|
2230
|
+
class re {
|
|
2082
2231
|
constructor(e) {
|
|
2083
2232
|
this.api = e;
|
|
2084
2233
|
}
|
|
@@ -2237,7 +2386,7 @@ class W {
|
|
|
2237
2386
|
return this.api.get(`/memory/zettel/by-relation/${e}/${t}?limit=${r}`);
|
|
2238
2387
|
}
|
|
2239
2388
|
}
|
|
2240
|
-
class
|
|
2389
|
+
class se {
|
|
2241
2390
|
constructor(e) {
|
|
2242
2391
|
this.api = e;
|
|
2243
2392
|
}
|
|
@@ -2273,7 +2422,7 @@ class Y {
|
|
|
2273
2422
|
return this.api.get("/memory/procedures/matches/stats");
|
|
2274
2423
|
}
|
|
2275
2424
|
}
|
|
2276
|
-
class
|
|
2425
|
+
class ne {
|
|
2277
2426
|
constructor(e) {
|
|
2278
2427
|
this.api = e;
|
|
2279
2428
|
}
|
|
@@ -2322,7 +2471,7 @@ class Z {
|
|
|
2322
2471
|
return this.api.delete(`/memory/procedures/candidates/${e}/dismiss`);
|
|
2323
2472
|
}
|
|
2324
2473
|
}
|
|
2325
|
-
class
|
|
2474
|
+
class ie {
|
|
2326
2475
|
constructor(e) {
|
|
2327
2476
|
this.api = e;
|
|
2328
2477
|
}
|
|
@@ -2377,7 +2526,7 @@ class X {
|
|
|
2377
2526
|
return this.api.get(`/memory/procedures/schemas/${e}`);
|
|
2378
2527
|
}
|
|
2379
2528
|
}
|
|
2380
|
-
class
|
|
2529
|
+
class ae {
|
|
2381
2530
|
constructor(e) {
|
|
2382
2531
|
this.api = e;
|
|
2383
2532
|
}
|
|
@@ -2449,11 +2598,11 @@ class Q {
|
|
|
2449
2598
|
return this.api.delete(`/memory/summary/${e}`);
|
|
2450
2599
|
}
|
|
2451
2600
|
}
|
|
2452
|
-
class
|
|
2601
|
+
class ce {
|
|
2453
2602
|
constructor(e) {
|
|
2454
|
-
this.auth = new
|
|
2455
|
-
const t = new
|
|
2456
|
-
this.memories = new
|
|
2603
|
+
this.auth = new L(e);
|
|
2604
|
+
const t = new M(this.auth, { fetchFn: e.fetchFn });
|
|
2605
|
+
this.memories = new z(t), this.decisions = new E(t), this.opinions = new O(t), this.graph = new x(t), this.teams = new q(t), this.profiles = new j(t), this.subscriptions = new F(t), this.authAPI = new K(t), this.agents = new H(t), this.usage = new B(t), this.insights = new D(t), this.tokenUsage = new G(t), this.temporal = new N(t), this.governance = new V(t), this.evolution = new J(t), this.reasoning = new W(t), this.reasoningTraces = new Y(t), this.ontology = new Z(t), this.analytics = new X(t), this.validation = new Q(t), this.pipeline = new ee(t), this.archive = new te(t), this.zettelkasten = new re(t), this.procedureMatches = new se(t), this.procedureCandidates = new ne(t), this.procedureDrift = new ie(t), this.summaries = new ae(t);
|
|
2457
2606
|
}
|
|
2458
2607
|
setTeamId(e) {
|
|
2459
2608
|
this.auth.tokenManager.setTeamId(e), this.auth.notifyListeners();
|
|
@@ -2463,35 +2612,36 @@ class te {
|
|
|
2463
2612
|
}
|
|
2464
2613
|
}
|
|
2465
2614
|
export {
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2615
|
+
g as A,
|
|
2616
|
+
M as B,
|
|
2617
|
+
E as D,
|
|
2618
|
+
J as E,
|
|
2619
|
+
V as G,
|
|
2620
|
+
D as I,
|
|
2621
|
+
z as M,
|
|
2622
|
+
Z as O,
|
|
2623
|
+
ee as P,
|
|
2624
|
+
W as R,
|
|
2625
|
+
ce as S,
|
|
2626
|
+
q as T,
|
|
2627
|
+
B as U,
|
|
2628
|
+
Q as V,
|
|
2629
|
+
re as Z,
|
|
2630
|
+
H as a,
|
|
2631
|
+
X as b,
|
|
2632
|
+
te as c,
|
|
2633
|
+
K as d,
|
|
2634
|
+
L as e,
|
|
2635
|
+
x as f,
|
|
2636
|
+
O as g,
|
|
2637
|
+
ne as h,
|
|
2638
|
+
se as i,
|
|
2639
|
+
j,
|
|
2640
|
+
Y as k,
|
|
2492
2641
|
F as l,
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2642
|
+
N as m,
|
|
2643
|
+
U as n,
|
|
2644
|
+
G as o,
|
|
2645
|
+
P as p,
|
|
2646
|
+
C as q
|
|
2497
2647
|
};
|