opsveritas-sdk 0.3.4 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +30 -1
- package/dist/index.d.ts +30 -1
- package/dist/index.js +87 -3
- package/dist/index.mjs +84 -2
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -13,6 +13,12 @@ interface TraceOptions {
|
|
|
13
13
|
}
|
|
14
14
|
declare function trace<T>(agentName: string, fn: () => Promise<T>, options?: TraceOptions): Promise<T>;
|
|
15
15
|
|
|
16
|
+
declare class OpsVeritasKilledError extends Error {
|
|
17
|
+
agentName: string;
|
|
18
|
+
reason?: string | undefined;
|
|
19
|
+
constructor(agentName: string, reason?: string | undefined);
|
|
20
|
+
}
|
|
21
|
+
|
|
16
22
|
interface WrapOptions {
|
|
17
23
|
agentName: string;
|
|
18
24
|
platform?: string;
|
|
@@ -39,6 +45,28 @@ interface LangChainOptions {
|
|
|
39
45
|
userId?: string;
|
|
40
46
|
}
|
|
41
47
|
declare function langchain(agentName: string, opts?: LangChainOptions): Record<string, unknown>;
|
|
48
|
+
interface LangChainModel {
|
|
49
|
+
invoke?: (...args: unknown[]) => unknown;
|
|
50
|
+
ainvoke?: (...args: unknown[]) => Promise<unknown>;
|
|
51
|
+
[key: string]: unknown;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Kill-switch enforcement for LangChain models — ADDITIVE, does not replace
|
|
55
|
+
* `langchain()` above. `langchain()` is telemetry-only (a callback handler;
|
|
56
|
+
* LangChain's callback manager swallows exceptions raised inside callbacks by
|
|
57
|
+
* default, so it can never actually block a call). This patches the model's
|
|
58
|
+
* own `invoke`/`ainvoke` directly — the same technique wrap() uses on raw
|
|
59
|
+
* provider clients — so a kill-switch check genuinely runs before the real
|
|
60
|
+
* API call happens.
|
|
61
|
+
*
|
|
62
|
+
* const model = new ChatOpenAI({ callbacks: [opsveritas.langchain('My Agent')] }); // telemetry
|
|
63
|
+
* opsveritas.wrapLangChain(model, { agentName: 'My Agent' }); // enforcement
|
|
64
|
+
*
|
|
65
|
+
* Scoped to invoke/ainvoke only — stream/astream/batch are out of scope for
|
|
66
|
+
* this pass (streaming needs mid-stream cancellation semantics; most LangChain
|
|
67
|
+
* usage goes through invoke/ainvoke).
|
|
68
|
+
*/
|
|
69
|
+
declare function wrapLangChain<T extends LangChainModel>(model: T, opts: WrapOptions): T;
|
|
42
70
|
|
|
43
71
|
interface ExecutionPayload {
|
|
44
72
|
platform: string;
|
|
@@ -66,6 +94,7 @@ declare const OpsVeritas: {
|
|
|
66
94
|
trace: typeof trace;
|
|
67
95
|
wrap: typeof wrap;
|
|
68
96
|
langchain: typeof langchain;
|
|
97
|
+
wrapLangChain: typeof wrapLangChain;
|
|
69
98
|
};
|
|
70
99
|
|
|
71
|
-
export { type ExecutionPayload, type LangChainOptions, OpsVeritas, type TraceOptions, type WrapOptions, OpsVeritas as default, init, langchain, run, trace, wrap };
|
|
100
|
+
export { type ExecutionPayload, type LangChainOptions, OpsVeritas, OpsVeritasKilledError, type TraceOptions, type WrapOptions, OpsVeritas as default, init, langchain, run, trace, wrap, wrapLangChain };
|
package/dist/index.d.ts
CHANGED
|
@@ -13,6 +13,12 @@ interface TraceOptions {
|
|
|
13
13
|
}
|
|
14
14
|
declare function trace<T>(agentName: string, fn: () => Promise<T>, options?: TraceOptions): Promise<T>;
|
|
15
15
|
|
|
16
|
+
declare class OpsVeritasKilledError extends Error {
|
|
17
|
+
agentName: string;
|
|
18
|
+
reason?: string | undefined;
|
|
19
|
+
constructor(agentName: string, reason?: string | undefined);
|
|
20
|
+
}
|
|
21
|
+
|
|
16
22
|
interface WrapOptions {
|
|
17
23
|
agentName: string;
|
|
18
24
|
platform?: string;
|
|
@@ -39,6 +45,28 @@ interface LangChainOptions {
|
|
|
39
45
|
userId?: string;
|
|
40
46
|
}
|
|
41
47
|
declare function langchain(agentName: string, opts?: LangChainOptions): Record<string, unknown>;
|
|
48
|
+
interface LangChainModel {
|
|
49
|
+
invoke?: (...args: unknown[]) => unknown;
|
|
50
|
+
ainvoke?: (...args: unknown[]) => Promise<unknown>;
|
|
51
|
+
[key: string]: unknown;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Kill-switch enforcement for LangChain models — ADDITIVE, does not replace
|
|
55
|
+
* `langchain()` above. `langchain()` is telemetry-only (a callback handler;
|
|
56
|
+
* LangChain's callback manager swallows exceptions raised inside callbacks by
|
|
57
|
+
* default, so it can never actually block a call). This patches the model's
|
|
58
|
+
* own `invoke`/`ainvoke` directly — the same technique wrap() uses on raw
|
|
59
|
+
* provider clients — so a kill-switch check genuinely runs before the real
|
|
60
|
+
* API call happens.
|
|
61
|
+
*
|
|
62
|
+
* const model = new ChatOpenAI({ callbacks: [opsveritas.langchain('My Agent')] }); // telemetry
|
|
63
|
+
* opsveritas.wrapLangChain(model, { agentName: 'My Agent' }); // enforcement
|
|
64
|
+
*
|
|
65
|
+
* Scoped to invoke/ainvoke only — stream/astream/batch are out of scope for
|
|
66
|
+
* this pass (streaming needs mid-stream cancellation semantics; most LangChain
|
|
67
|
+
* usage goes through invoke/ainvoke).
|
|
68
|
+
*/
|
|
69
|
+
declare function wrapLangChain<T extends LangChainModel>(model: T, opts: WrapOptions): T;
|
|
42
70
|
|
|
43
71
|
interface ExecutionPayload {
|
|
44
72
|
platform: string;
|
|
@@ -66,6 +94,7 @@ declare const OpsVeritas: {
|
|
|
66
94
|
trace: typeof trace;
|
|
67
95
|
wrap: typeof wrap;
|
|
68
96
|
langchain: typeof langchain;
|
|
97
|
+
wrapLangChain: typeof wrapLangChain;
|
|
69
98
|
};
|
|
70
99
|
|
|
71
|
-
export { type ExecutionPayload, type LangChainOptions, OpsVeritas, type TraceOptions, type WrapOptions, OpsVeritas as default, init, langchain, run, trace, wrap };
|
|
100
|
+
export { type ExecutionPayload, type LangChainOptions, OpsVeritas, OpsVeritasKilledError, type TraceOptions, type WrapOptions, OpsVeritas as default, init, langchain, run, trace, wrap, wrapLangChain };
|
package/dist/index.js
CHANGED
|
@@ -21,12 +21,14 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
OpsVeritas: () => OpsVeritas,
|
|
24
|
+
OpsVeritasKilledError: () => OpsVeritasKilledError,
|
|
24
25
|
default: () => index_default,
|
|
25
26
|
init: () => init,
|
|
26
27
|
langchain: () => langchain,
|
|
27
28
|
run: () => run,
|
|
28
29
|
trace: () => trace,
|
|
29
|
-
wrap: () => wrap
|
|
30
|
+
wrap: () => wrap,
|
|
31
|
+
wrapLangChain: () => wrapLangChain
|
|
30
32
|
});
|
|
31
33
|
module.exports = __toCommonJS(index_exports);
|
|
32
34
|
|
|
@@ -355,6 +357,53 @@ async function trace(agentName, fn, options) {
|
|
|
355
357
|
return result;
|
|
356
358
|
}
|
|
357
359
|
|
|
360
|
+
// src/killSwitch.ts
|
|
361
|
+
var POLL_INTERVAL_MS = 18e4;
|
|
362
|
+
var OpsVeritasKilledError = class extends Error {
|
|
363
|
+
constructor(agentName, reason) {
|
|
364
|
+
super(`[OpsVeritas] Agent "${agentName}" is paused (kill switch: ${reason ?? "budget exceeded"}). Call opsveritas restart from the dashboard to resume.`);
|
|
365
|
+
this.agentName = agentName;
|
|
366
|
+
this.reason = reason;
|
|
367
|
+
this.name = "OpsVeritasKilledError";
|
|
368
|
+
}
|
|
369
|
+
};
|
|
370
|
+
var cache = /* @__PURE__ */ new Map();
|
|
371
|
+
var polling = /* @__PURE__ */ new Set();
|
|
372
|
+
async function poll(agentName, framework) {
|
|
373
|
+
let cfg;
|
|
374
|
+
try {
|
|
375
|
+
cfg = getConfig();
|
|
376
|
+
} catch {
|
|
377
|
+
return void 0;
|
|
378
|
+
}
|
|
379
|
+
const params = new URLSearchParams({ agent_name: agentName });
|
|
380
|
+
if (framework) params.set("framework", framework);
|
|
381
|
+
try {
|
|
382
|
+
const res = await fetch(`${cfg.endpoint}/webhooks/agent-budget-status?${params}`, {
|
|
383
|
+
headers: { "x-opsveritas-key": cfg.apiKey }
|
|
384
|
+
});
|
|
385
|
+
if (!res.ok) return void 0;
|
|
386
|
+
const data = await res.json();
|
|
387
|
+
cache.set(agentName, { killed: !!data.killed, reason: data.reason });
|
|
388
|
+
return data.kill_switch_enabled;
|
|
389
|
+
} catch {
|
|
390
|
+
return void 0;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
function startPolling(agentName, framework) {
|
|
394
|
+
if (polling.has(agentName)) return;
|
|
395
|
+
polling.add(agentName);
|
|
396
|
+
void poll(agentName, framework).then((enabled) => {
|
|
397
|
+
if (enabled === false) return;
|
|
398
|
+
const timer = setInterval(() => void poll(agentName, framework), POLL_INTERVAL_MS);
|
|
399
|
+
const t = timer;
|
|
400
|
+
if (typeof t.unref === "function") t.unref();
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
function isKilled(agentName) {
|
|
404
|
+
return cache.get(agentName) ?? { killed: false };
|
|
405
|
+
}
|
|
406
|
+
|
|
358
407
|
// src/wrap.ts
|
|
359
408
|
var PATCHED = /* @__PURE__ */ Symbol("opsveritas.patched");
|
|
360
409
|
var OUTPUT_SUMMARY_MAX = 3e3;
|
|
@@ -395,7 +444,10 @@ function patchOpenAI(client, opts) {
|
|
|
395
444
|
const completions = client.chat?.completions;
|
|
396
445
|
if (!completions || completions[PATCHED]) return;
|
|
397
446
|
const orig = completions.create.bind(completions);
|
|
447
|
+
startPolling(opts.agentName, "sdk");
|
|
398
448
|
completions.create = async function(...args) {
|
|
449
|
+
const killState = isKilled(opts.agentName);
|
|
450
|
+
if (killState.killed) throw new OpsVeritasKilledError(opts.agentName, killState.reason);
|
|
399
451
|
const executedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
400
452
|
const t0 = Date.now();
|
|
401
453
|
let status = "success";
|
|
@@ -446,7 +498,10 @@ function patchAnthropic(client, opts) {
|
|
|
446
498
|
const messages = client.messages;
|
|
447
499
|
if (!messages || messages[PATCHED]) return;
|
|
448
500
|
const orig = messages.create.bind(messages);
|
|
501
|
+
startPolling(opts.agentName, "sdk");
|
|
449
502
|
messages.create = async function(...args) {
|
|
503
|
+
const killState = isKilled(opts.agentName);
|
|
504
|
+
if (killState.killed) throw new OpsVeritasKilledError(opts.agentName, killState.reason);
|
|
450
505
|
const executedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
451
506
|
const t0 = Date.now();
|
|
452
507
|
let status = "success";
|
|
@@ -495,7 +550,10 @@ function patchGemini(client, opts) {
|
|
|
495
550
|
if (client[PATCHED]) return;
|
|
496
551
|
const modelName = typeof client.model === "string" ? client.model.replace(/^models\//, "") : void 0;
|
|
497
552
|
const orig = client.generateContent.bind(client);
|
|
553
|
+
startPolling(opts.agentName, "sdk");
|
|
498
554
|
client.generateContent = async function(...args) {
|
|
555
|
+
const killState = isKilled(opts.agentName);
|
|
556
|
+
if (killState.killed) throw new OpsVeritasKilledError(opts.agentName, killState.reason);
|
|
499
557
|
const executedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
500
558
|
const t0 = Date.now();
|
|
501
559
|
let status = "success";
|
|
@@ -555,6 +613,7 @@ function wrap(client, opts) {
|
|
|
555
613
|
}
|
|
556
614
|
|
|
557
615
|
// src/langchain.ts
|
|
616
|
+
var LC_PATCHED = /* @__PURE__ */ Symbol("opsveritas.langchain.patched");
|
|
558
617
|
function extractUsage2(output) {
|
|
559
618
|
let model;
|
|
560
619
|
let inputTokens;
|
|
@@ -658,16 +717,41 @@ function langchain(agentName, opts = {}) {
|
|
|
658
717
|
}
|
|
659
718
|
};
|
|
660
719
|
}
|
|
720
|
+
function wrapLangChain(model, opts) {
|
|
721
|
+
const m = model;
|
|
722
|
+
if (m[LC_PATCHED]) return model;
|
|
723
|
+
startPolling(opts.agentName, "sdk");
|
|
724
|
+
if (typeof m.invoke === "function") {
|
|
725
|
+
const origInvoke = m.invoke.bind(model);
|
|
726
|
+
m.invoke = function(...args) {
|
|
727
|
+
const killState = isKilled(opts.agentName);
|
|
728
|
+
if (killState.killed) throw new OpsVeritasKilledError(opts.agentName, killState.reason);
|
|
729
|
+
return origInvoke(...args);
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
if (typeof m.ainvoke === "function") {
|
|
733
|
+
const origAinvoke = m.ainvoke.bind(model);
|
|
734
|
+
m.ainvoke = async function(...args) {
|
|
735
|
+
const killState = isKilled(opts.agentName);
|
|
736
|
+
if (killState.killed) throw new OpsVeritasKilledError(opts.agentName, killState.reason);
|
|
737
|
+
return origAinvoke(...args);
|
|
738
|
+
};
|
|
739
|
+
}
|
|
740
|
+
m[LC_PATCHED] = true;
|
|
741
|
+
return model;
|
|
742
|
+
}
|
|
661
743
|
|
|
662
744
|
// src/index.ts
|
|
663
|
-
var OpsVeritas = { init, run, trace, wrap, langchain };
|
|
745
|
+
var OpsVeritas = { init, run, trace, wrap, langchain, wrapLangChain };
|
|
664
746
|
var index_default = OpsVeritas;
|
|
665
747
|
// Annotate the CommonJS export names for ESM import in node:
|
|
666
748
|
0 && (module.exports = {
|
|
667
749
|
OpsVeritas,
|
|
750
|
+
OpsVeritasKilledError,
|
|
668
751
|
init,
|
|
669
752
|
langchain,
|
|
670
753
|
run,
|
|
671
754
|
trace,
|
|
672
|
-
wrap
|
|
755
|
+
wrap,
|
|
756
|
+
wrapLangChain
|
|
673
757
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -323,6 +323,53 @@ async function trace(agentName, fn, options) {
|
|
|
323
323
|
return result;
|
|
324
324
|
}
|
|
325
325
|
|
|
326
|
+
// src/killSwitch.ts
|
|
327
|
+
var POLL_INTERVAL_MS = 18e4;
|
|
328
|
+
var OpsVeritasKilledError = class extends Error {
|
|
329
|
+
constructor(agentName, reason) {
|
|
330
|
+
super(`[OpsVeritas] Agent "${agentName}" is paused (kill switch: ${reason ?? "budget exceeded"}). Call opsveritas restart from the dashboard to resume.`);
|
|
331
|
+
this.agentName = agentName;
|
|
332
|
+
this.reason = reason;
|
|
333
|
+
this.name = "OpsVeritasKilledError";
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
var cache = /* @__PURE__ */ new Map();
|
|
337
|
+
var polling = /* @__PURE__ */ new Set();
|
|
338
|
+
async function poll(agentName, framework) {
|
|
339
|
+
let cfg;
|
|
340
|
+
try {
|
|
341
|
+
cfg = getConfig();
|
|
342
|
+
} catch {
|
|
343
|
+
return void 0;
|
|
344
|
+
}
|
|
345
|
+
const params = new URLSearchParams({ agent_name: agentName });
|
|
346
|
+
if (framework) params.set("framework", framework);
|
|
347
|
+
try {
|
|
348
|
+
const res = await fetch(`${cfg.endpoint}/webhooks/agent-budget-status?${params}`, {
|
|
349
|
+
headers: { "x-opsveritas-key": cfg.apiKey }
|
|
350
|
+
});
|
|
351
|
+
if (!res.ok) return void 0;
|
|
352
|
+
const data = await res.json();
|
|
353
|
+
cache.set(agentName, { killed: !!data.killed, reason: data.reason });
|
|
354
|
+
return data.kill_switch_enabled;
|
|
355
|
+
} catch {
|
|
356
|
+
return void 0;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
function startPolling(agentName, framework) {
|
|
360
|
+
if (polling.has(agentName)) return;
|
|
361
|
+
polling.add(agentName);
|
|
362
|
+
void poll(agentName, framework).then((enabled) => {
|
|
363
|
+
if (enabled === false) return;
|
|
364
|
+
const timer = setInterval(() => void poll(agentName, framework), POLL_INTERVAL_MS);
|
|
365
|
+
const t = timer;
|
|
366
|
+
if (typeof t.unref === "function") t.unref();
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
function isKilled(agentName) {
|
|
370
|
+
return cache.get(agentName) ?? { killed: false };
|
|
371
|
+
}
|
|
372
|
+
|
|
326
373
|
// src/wrap.ts
|
|
327
374
|
var PATCHED = /* @__PURE__ */ Symbol("opsveritas.patched");
|
|
328
375
|
var OUTPUT_SUMMARY_MAX = 3e3;
|
|
@@ -363,7 +410,10 @@ function patchOpenAI(client, opts) {
|
|
|
363
410
|
const completions = client.chat?.completions;
|
|
364
411
|
if (!completions || completions[PATCHED]) return;
|
|
365
412
|
const orig = completions.create.bind(completions);
|
|
413
|
+
startPolling(opts.agentName, "sdk");
|
|
366
414
|
completions.create = async function(...args) {
|
|
415
|
+
const killState = isKilled(opts.agentName);
|
|
416
|
+
if (killState.killed) throw new OpsVeritasKilledError(opts.agentName, killState.reason);
|
|
367
417
|
const executedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
368
418
|
const t0 = Date.now();
|
|
369
419
|
let status = "success";
|
|
@@ -414,7 +464,10 @@ function patchAnthropic(client, opts) {
|
|
|
414
464
|
const messages = client.messages;
|
|
415
465
|
if (!messages || messages[PATCHED]) return;
|
|
416
466
|
const orig = messages.create.bind(messages);
|
|
467
|
+
startPolling(opts.agentName, "sdk");
|
|
417
468
|
messages.create = async function(...args) {
|
|
469
|
+
const killState = isKilled(opts.agentName);
|
|
470
|
+
if (killState.killed) throw new OpsVeritasKilledError(opts.agentName, killState.reason);
|
|
418
471
|
const executedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
419
472
|
const t0 = Date.now();
|
|
420
473
|
let status = "success";
|
|
@@ -463,7 +516,10 @@ function patchGemini(client, opts) {
|
|
|
463
516
|
if (client[PATCHED]) return;
|
|
464
517
|
const modelName = typeof client.model === "string" ? client.model.replace(/^models\//, "") : void 0;
|
|
465
518
|
const orig = client.generateContent.bind(client);
|
|
519
|
+
startPolling(opts.agentName, "sdk");
|
|
466
520
|
client.generateContent = async function(...args) {
|
|
521
|
+
const killState = isKilled(opts.agentName);
|
|
522
|
+
if (killState.killed) throw new OpsVeritasKilledError(opts.agentName, killState.reason);
|
|
467
523
|
const executedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
468
524
|
const t0 = Date.now();
|
|
469
525
|
let status = "success";
|
|
@@ -523,6 +579,7 @@ function wrap(client, opts) {
|
|
|
523
579
|
}
|
|
524
580
|
|
|
525
581
|
// src/langchain.ts
|
|
582
|
+
var LC_PATCHED = /* @__PURE__ */ Symbol("opsveritas.langchain.patched");
|
|
526
583
|
function extractUsage2(output) {
|
|
527
584
|
let model;
|
|
528
585
|
let inputTokens;
|
|
@@ -626,16 +683,41 @@ function langchain(agentName, opts = {}) {
|
|
|
626
683
|
}
|
|
627
684
|
};
|
|
628
685
|
}
|
|
686
|
+
function wrapLangChain(model, opts) {
|
|
687
|
+
const m = model;
|
|
688
|
+
if (m[LC_PATCHED]) return model;
|
|
689
|
+
startPolling(opts.agentName, "sdk");
|
|
690
|
+
if (typeof m.invoke === "function") {
|
|
691
|
+
const origInvoke = m.invoke.bind(model);
|
|
692
|
+
m.invoke = function(...args) {
|
|
693
|
+
const killState = isKilled(opts.agentName);
|
|
694
|
+
if (killState.killed) throw new OpsVeritasKilledError(opts.agentName, killState.reason);
|
|
695
|
+
return origInvoke(...args);
|
|
696
|
+
};
|
|
697
|
+
}
|
|
698
|
+
if (typeof m.ainvoke === "function") {
|
|
699
|
+
const origAinvoke = m.ainvoke.bind(model);
|
|
700
|
+
m.ainvoke = async function(...args) {
|
|
701
|
+
const killState = isKilled(opts.agentName);
|
|
702
|
+
if (killState.killed) throw new OpsVeritasKilledError(opts.agentName, killState.reason);
|
|
703
|
+
return origAinvoke(...args);
|
|
704
|
+
};
|
|
705
|
+
}
|
|
706
|
+
m[LC_PATCHED] = true;
|
|
707
|
+
return model;
|
|
708
|
+
}
|
|
629
709
|
|
|
630
710
|
// src/index.ts
|
|
631
|
-
var OpsVeritas = { init, run, trace, wrap, langchain };
|
|
711
|
+
var OpsVeritas = { init, run, trace, wrap, langchain, wrapLangChain };
|
|
632
712
|
var index_default = OpsVeritas;
|
|
633
713
|
export {
|
|
634
714
|
OpsVeritas,
|
|
715
|
+
OpsVeritasKilledError,
|
|
635
716
|
index_default as default,
|
|
636
717
|
init,
|
|
637
718
|
langchain,
|
|
638
719
|
run,
|
|
639
720
|
trace,
|
|
640
|
-
wrap
|
|
721
|
+
wrap,
|
|
722
|
+
wrapLangChain
|
|
641
723
|
};
|