@chatman-media/kb 1.3.0 → 1.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/answer-types.d.ts +9 -0
- package/dist/answer-types.d.ts.map +1 -1
- package/dist/answer.d.ts.map +1 -1
- package/dist/extract-user-facts.test.d.ts +2 -0
- package/dist/extract-user-facts.test.d.ts.map +1 -0
- package/dist/fact-checker.test.d.ts +2 -0
- package/dist/fact-checker.test.d.ts.map +1 -0
- package/dist/grade-skills.test.d.ts +2 -0
- package/dist/grade-skills.test.d.ts.map +1 -0
- package/dist/index.js +25 -18
- package/dist/ingest.d.ts.map +1 -1
- package/dist/prompt.d.ts.map +1 -1
- package/dist/prompt.test.d.ts +2 -0
- package/dist/prompt.test.d.ts.map +1 -0
- package/dist/reflect.test.d.ts +2 -0
- package/dist/reflect.test.d.ts.map +1 -0
- package/dist/rewrite-query.test.d.ts +2 -0
- package/dist/rewrite-query.test.d.ts.map +1 -0
- package/dist/styles.d.ts +9 -0
- package/dist/styles.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/answer-types.ts +6 -0
- package/src/answer.ts +2 -0
- package/src/chunk.ts +1 -1
- package/src/extract-user-facts.test.ts +44 -0
- package/src/fact-checker.test.ts +66 -0
- package/src/grade-skills.test.ts +39 -0
- package/src/ingest.ts +6 -1
- package/src/prompt.test.ts +44 -0
- package/src/prompt.ts +8 -4
- package/src/reflect.test.ts +44 -0
- package/src/reranker.ts +2 -2
- package/src/rewrite-query.test.ts +56 -0
- package/src/structured-output.ts +1 -1
- package/src/styles.ts +6 -0
- package/src/text-style-rules.ts +1 -1
- package/src/vision.ts +2 -2
package/dist/answer-types.d.ts
CHANGED
|
@@ -54,6 +54,15 @@ export interface AnswerInput {
|
|
|
54
54
|
* uses a calm FAQ-support block instead — answering questions without selling.
|
|
55
55
|
*/
|
|
56
56
|
supportPhase?: "docs" | "submitted";
|
|
57
|
+
/**
|
|
58
|
+
* Per-stage override (Phase 2 C-2): the lead's current funnel-stage goal/
|
|
59
|
+
* guidance from stage_definitions. Takes precedence over the Style's
|
|
60
|
+
* per-sales-stage config when composing the prompt.
|
|
61
|
+
*/
|
|
62
|
+
stageOverride?: {
|
|
63
|
+
goal: string;
|
|
64
|
+
guidance?: string;
|
|
65
|
+
};
|
|
57
66
|
/**
|
|
58
67
|
* Called after every `answerWithRag` or `answerWithRagStream` call with the
|
|
59
68
|
* final telemetry. Useful for logging, metrics, or A/B experiment recording
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"answer-types.d.ts","sourceRoot":"","sources":["../src/answer-types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"answer-types.d.ts","sourceRoot":"","sources":["../src/answer-types.ts"],"names":[],"mappings":"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"}
|
package/dist/answer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"answer.d.ts","sourceRoot":"","sources":["../src/answer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,YAAY,EAGjB,KAAK,OAAO,EACb,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AA8BzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAG9C,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,iBAAiB,EACjB,KAAK,OAAO,GACb,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,sBAAsB,EACtB,0BAA0B,EAC1B,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EACL,iBAAiB,EACjB,4BAA4B,EAC5B,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,oBAAoB,CAAC;AAI5B,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,WAAW,EAAE,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,oEAAoE;IACpE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,YAAY,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,CAAC,CAgG/E;
|
|
1
|
+
{"version":3,"file":"answer.d.ts","sourceRoot":"","sources":["../src/answer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,YAAY,EAGjB,KAAK,OAAO,EACb,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AA8BzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAG9C,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,iBAAiB,EACjB,KAAK,OAAO,GACb,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,sBAAsB,EACtB,0BAA0B,EAC1B,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EACL,iBAAiB,EACjB,4BAA4B,EAC5B,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,oBAAoB,CAAC;AAI5B,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,WAAW,EAAE,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,oEAAoE;IACpE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,YAAY,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,CAAC,CAgG/E;AA4OD;;;;;;;;GAQG;AACH,wBAAuB,mBAAmB,CAAC,KAAK,EAAE,WAAW,GAAG,aAAa,CAAC,MAAM,CAAC,CA2HpF;AAED,wBAAsB,aAAa,CAAC,CAAC,SAAS,CAAC,CAAC,UAAU,EACxD,KAAK,EAAE,WAAW,GAAG;IAAE,YAAY,EAAE,CAAC,CAAA;CAAE,GACvC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrC,wBAAsB,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;AAiG/E;;;;;;;;;GASG;AACH,wBAAsB,oBAAoB,CAAC,KAAK,EAAE;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,UAAU,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,WAAW,EAAE,CAAC;CACzB,GAAG,OAAO,CAAC,MAAM,CAAC,CA8BlB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extract-user-facts.test.d.ts","sourceRoot":"","sources":["../src/extract-user-facts.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fact-checker.test.d.ts","sourceRoot":"","sources":["../src/fact-checker.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grade-skills.test.d.ts","sourceRoot":"","sources":["../src/grade-skills.test.ts"],"names":[],"mappings":""}
|
package/dist/index.js
CHANGED
|
@@ -44647,7 +44647,7 @@ var NO_CONTEXT_MARKER = "__NO_CONTEXT__";
|
|
|
44647
44647
|
var replaceEmDash = {
|
|
44648
44648
|
name: "replace-em-dash",
|
|
44649
44649
|
description: "U+2014 \xAB\u2014\xBB \u2192 \xAB-\xBB (\u0441 \u043D\u043E\u0440\u043C\u0430\u043B\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u043F\u0440\u043E\u0431\u0435\u043B\u043E\u0432)",
|
|
44650
|
-
apply: (s) => s.replace(/\s
|
|
44650
|
+
apply: (s) => s.replace(/\s{0,200}\u2014\s{0,200}/g, " - ").replace(/ {2,}/g, " ")
|
|
44651
44651
|
};
|
|
44652
44652
|
var replaceEnDash = {
|
|
44653
44653
|
name: "replace-en-dash",
|
|
@@ -45100,9 +45100,11 @@ ${triggerLine}${h.body}`;
|
|
|
45100
45100
|
const skillsBlock = skillsForStage.length ? `\u041F\u0420\u0418\u0401\u041C\u042B (\u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0439 \u0443\u043C\u0435\u0441\u0442\u043D\u044B\u0435, \u043D\u0435 \u0432\u0441\u0435 \u0441\u0440\u0430\u0437\u0443 \u2014 \u0432\u044B\u0431\u0438\u0440\u0430\u0439 \u043F\u043E \u043A\u043E\u043D\u0442\u0435\u043A\u0441\u0442\u0443):
|
|
45101
45101
|
` + skillsForStage.map((s) => `- ${s.displayName} \u2014 ${s.promptFragment}`).join(`
|
|
45102
45102
|
`) : "";
|
|
45103
|
-
const
|
|
45104
|
-
|
|
45105
|
-
\u041A\u0410\
|
|
45103
|
+
const effGoal = options.stageOverride?.goal ?? stageCfg?.goal;
|
|
45104
|
+
const effGuidance = options.stageOverride?.guidance ?? stageCfg?.guidance;
|
|
45105
|
+
const stageBlock = effGoal ? `\u0422\u0415\u041A\u0423\u0429\u0418\u0419 \u042D\u0422\u0410\u041F: ${stage.toUpperCase()}.
|
|
45106
|
+
` + `\u0426\u0415\u041B\u042C \u042D\u0422\u0410\u041F\u0410: ${effGoal}.` + (effGuidance ? `
|
|
45107
|
+
\u041A\u0410\u041A: ${effGuidance}` : "") + (stageCfg?.groundingRequired ? `
|
|
45106
45108
|
GROUNDING: \u043D\u0430 \u044D\u0442\u043E\u043C \u044D\u0442\u0430\u043F\u0435 \u0432\u0441\u0435 \u043A\u043E\u043D\u043A\u0440\u0435\u0442\u043D\u044B\u0435 \u0444\u0430\u043A\u0442\u044B (\u0446\u0438\u0444\u0440\u044B, \u0441\u0443\u043C\u043C\u044B, \u0441\u0440\u043E\u043A\u0438) \u0431\u0435\u0440\u0438 \u0422\u041E\u041B\u042C\u041A\u041E \u0438\u0437 \u0441\u0435\u043A\u0446\u0438\u0438 KB CONTEXT \u043D\u0438\u0436\u0435. \u0415\u0441\u043B\u0438 \u0435\u0451 \u043D\u0435\u0442 \u0438\u043B\u0438 \u043D\u0443\u0436\u043D\u043E\u0433\u043E \u0444\u0430\u043A\u0442\u0430 \u0432 \u043D\u0435\u0439 \u043D\u0435\u0442 \u2014 \u043D\u0435 \u0432\u044B\u0434\u0443\u043C\u044B\u0432\u0430\u0439, \u0441\u043A\u0430\u0436\u0438 \u0447\u0442\u043E \u0443\u0442\u043E\u0447\u043D\u0438\u0448\u044C.` : "") : `\u0422\u0415\u041A\u0423\u0429\u0418\u0419 \u042D\u0422\u0410\u041F: ${stage}. (\u0421\u043F\u0435\u0446\u0438\u0444\u0438\u0447\u0435\u0441\u043A\u0438\u0445 \u043F\u0440\u0430\u0432\u0438\u043B \u0434\u043B\u044F \u044D\u0442\u0430\u043F\u0430 \u043D\u0435\u0442 \u2014 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0439 \u043E\u0431\u0449\u0438\u0439 \u0441\u0442\u0438\u043B\u044C.)`;
|
|
45107
45109
|
const minorRule = guardrails.noMinors ? "- \u0415\u0441\u043B\u0438 prospect <18 \u043B\u0435\u0442 \u2014 \u0432\u0435\u0436\u043B\u0438\u0432\u043E \u0437\u0430\u0432\u0435\u0440\u0448\u0438 \u0434\u0438\u0430\u043B\u043E\u0433." : "";
|
|
45108
45110
|
const topicsRule = guardrails.forbiddenTopics.length ? `- \u0417\u0430\u043F\u0440\u0435\u0449\u0451\u043D\u043D\u044B\u0435 \u0442\u0435\u043C\u044B: ${guardrails.forbiddenTopics.join(", ")}.` : "";
|
|
@@ -59649,7 +59651,7 @@ Schema:
|
|
|
59649
59651
|
${schemaStr}`;
|
|
59650
59652
|
}
|
|
59651
59653
|
function parseStructuredOutput(raw, schema) {
|
|
59652
|
-
const cleaned = raw.trim().replace(/^```(?:json)?\s*/i, "").replace(/\s
|
|
59654
|
+
const cleaned = raw.trim().replace(/^```(?:json)?\s*/i, "").replace(/\s{0,1000}```$/, "").trim();
|
|
59653
59655
|
let parsed;
|
|
59654
59656
|
try {
|
|
59655
59657
|
parsed = JSON.parse(cleaned);
|
|
@@ -59905,7 +59907,8 @@ ${kbContextStr}` : vacBlock : kbContextStr;
|
|
|
59905
59907
|
...input.conversationSummary ? { conversationSummary: input.conversationSummary } : {},
|
|
59906
59908
|
...input.skills && input.skills.length > 0 ? { skills: input.skills } : {},
|
|
59907
59909
|
...input.directorHooks && input.directorHooks.length > 0 ? { directorHooks: input.directorHooks } : {},
|
|
59908
|
-
...input.supportPhase ? { supportPhase: input.supportPhase } : {}
|
|
59910
|
+
...input.supportPhase ? { supportPhase: input.supportPhase } : {},
|
|
59911
|
+
...input.stageOverride ? { stageOverride: input.stageOverride } : {}
|
|
59909
59912
|
});
|
|
59910
59913
|
temperature = input.style.model.temperature;
|
|
59911
59914
|
} else {
|
|
@@ -60092,7 +60095,8 @@ ${kbContextStr}` : vacBlock : kbContextStr;
|
|
|
60092
60095
|
...input.conversationSummary ? { conversationSummary: input.conversationSummary } : {},
|
|
60093
60096
|
...input.skills && input.skills.length > 0 ? { skills: input.skills } : {},
|
|
60094
60097
|
...input.directorHooks && input.directorHooks.length > 0 ? { directorHooks: input.directorHooks } : {},
|
|
60095
|
-
...input.supportPhase ? { supportPhase: input.supportPhase } : {}
|
|
60098
|
+
...input.supportPhase ? { supportPhase: input.supportPhase } : {},
|
|
60099
|
+
...input.stageOverride ? { stageOverride: input.stageOverride } : {}
|
|
60096
60100
|
});
|
|
60097
60101
|
temperature = input.style.model.temperature;
|
|
60098
60102
|
} else {
|
|
@@ -60296,7 +60300,7 @@ class OllamaChatClient {
|
|
|
60296
60300
|
disableThinking;
|
|
60297
60301
|
timeoutMs;
|
|
60298
60302
|
constructor(opts) {
|
|
60299
|
-
this.host = opts.host.replace(
|
|
60303
|
+
this.host = opts.host.replace(/\/{1,512}$/, "");
|
|
60300
60304
|
this.model = opts.model;
|
|
60301
60305
|
this.fetchImpl = opts.fetch ?? globalThis.fetch.bind(globalThis);
|
|
60302
60306
|
this.disableThinking = opts.disableThinking ?? true;
|
|
@@ -60427,7 +60431,7 @@ class OllamaEmbeddingClient {
|
|
|
60427
60431
|
fetchImpl;
|
|
60428
60432
|
timeoutMs;
|
|
60429
60433
|
constructor(opts) {
|
|
60430
|
-
this.host = opts.host.replace(
|
|
60434
|
+
this.host = opts.host.replace(/\/{1,512}$/, "");
|
|
60431
60435
|
this.model = opts.model;
|
|
60432
60436
|
this.dim = opts.dim;
|
|
60433
60437
|
this.fetchImpl = opts.fetch ?? globalThis.fetch.bind(globalThis);
|
|
@@ -60478,7 +60482,7 @@ class OpenAIChatClient {
|
|
|
60478
60482
|
if (!opts.apiKey)
|
|
60479
60483
|
throw new Error("OpenAIChatClient: apiKey required");
|
|
60480
60484
|
this.apiKey = opts.apiKey;
|
|
60481
|
-
this.baseUrl = opts.baseUrl.replace(
|
|
60485
|
+
this.baseUrl = opts.baseUrl.replace(/\/{1,512}$/, "");
|
|
60482
60486
|
this.model = opts.model;
|
|
60483
60487
|
this.timeoutMs = opts.timeoutMs ?? 60000;
|
|
60484
60488
|
this.fetchImpl = opts.fetch ?? globalThis.fetch.bind(globalThis);
|
|
@@ -60624,7 +60628,7 @@ class OpenAIEmbeddingClient {
|
|
|
60624
60628
|
if (!opts.apiKey)
|
|
60625
60629
|
throw new Error("OpenAIEmbeddingClient: apiKey required");
|
|
60626
60630
|
this.apiKey = opts.apiKey;
|
|
60627
|
-
this.baseUrl = opts.baseUrl.replace(
|
|
60631
|
+
this.baseUrl = opts.baseUrl.replace(/\/{1,512}$/, "");
|
|
60628
60632
|
this.model = opts.model;
|
|
60629
60633
|
this.dim = opts.dim;
|
|
60630
60634
|
this.timeoutMs = opts.timeoutMs ?? 60000;
|
|
@@ -60701,7 +60705,7 @@ class OpenRouterChatClient {
|
|
|
60701
60705
|
throw new Error("OpenRouterChatClient: model required");
|
|
60702
60706
|
}
|
|
60703
60707
|
this.apiKey = opts.apiKey;
|
|
60704
|
-
this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(
|
|
60708
|
+
this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\/{1,512}$/, "");
|
|
60705
60709
|
this.model = opts.model;
|
|
60706
60710
|
this.siteUrl = opts.siteUrl;
|
|
60707
60711
|
this.appName = opts.appName;
|
|
@@ -61111,7 +61115,7 @@ function chunkBySections(text, opts = {}) {
|
|
|
61111
61115
|
bodyLines = [];
|
|
61112
61116
|
};
|
|
61113
61117
|
for (const line of lines) {
|
|
61114
|
-
const m = line.match(/^(#{1,6})\s+(
|
|
61118
|
+
const m = line.match(/^(#{1,6})\s+(\S.*)$/);
|
|
61115
61119
|
if (m) {
|
|
61116
61120
|
flush();
|
|
61117
61121
|
currentHeading = m[2] ?? null;
|
|
@@ -61719,7 +61723,10 @@ function* walk(dir) {
|
|
|
61719
61723
|
function stripNonContent(raw) {
|
|
61720
61724
|
let s = raw;
|
|
61721
61725
|
s = s.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/, "");
|
|
61722
|
-
|
|
61726
|
+
for (let prev = "";prev !== s; ) {
|
|
61727
|
+
prev = s;
|
|
61728
|
+
s = s.replace(/<!--[\s\S]{0,10000}?-->/g, "");
|
|
61729
|
+
}
|
|
61723
61730
|
s = s.replace(/\n{3,}/g, `
|
|
61724
61731
|
|
|
61725
61732
|
`).trim();
|
|
@@ -61806,7 +61813,7 @@ class CohereReranker {
|
|
|
61806
61813
|
throw new Error("CohereReranker: apiKey required");
|
|
61807
61814
|
this.apiKey = opts.apiKey;
|
|
61808
61815
|
this.model = opts.model ?? "rerank-v3.5";
|
|
61809
|
-
this.baseUrl = (opts.baseUrl ?? "https://api.cohere.com/v2").replace(
|
|
61816
|
+
this.baseUrl = (opts.baseUrl ?? "https://api.cohere.com/v2").replace(/\/{1,512}$/, "");
|
|
61810
61817
|
this.timeoutMs = opts.timeoutMs ?? 30000;
|
|
61811
61818
|
this.fetchImpl = opts.fetch ?? globalThis.fetch.bind(globalThis);
|
|
61812
61819
|
}
|
|
@@ -61852,7 +61859,7 @@ class JinaReranker {
|
|
|
61852
61859
|
throw new Error("JinaReranker: apiKey required");
|
|
61853
61860
|
this.apiKey = opts.apiKey;
|
|
61854
61861
|
this.model = opts.model ?? "jina-reranker-v2-base-multilingual";
|
|
61855
|
-
this.baseUrl = (opts.baseUrl ?? "https://api.jina.ai/v1").replace(
|
|
61862
|
+
this.baseUrl = (opts.baseUrl ?? "https://api.jina.ai/v1").replace(/\/{1,512}$/, "");
|
|
61856
61863
|
this.timeoutMs = opts.timeoutMs ?? 30000;
|
|
61857
61864
|
this.fetchImpl = opts.fetch ?? globalThis.fetch.bind(globalThis);
|
|
61858
61865
|
}
|
|
@@ -62424,7 +62431,7 @@ async function classifyPhoto(opts) {
|
|
|
62424
62431
|
if (!opts.apiKey || opts.apiKey.trim().length === 0) {
|
|
62425
62432
|
throw new Error("classifyPhoto: apiKey required");
|
|
62426
62433
|
}
|
|
62427
|
-
const baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL2).replace(
|
|
62434
|
+
const baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL2).replace(/\/{1,512}$/, "");
|
|
62428
62435
|
const fetchImpl = opts.fetch ?? globalThis.fetch.bind(globalThis);
|
|
62429
62436
|
const mime = opts.mimeType?.trim() ? opts.mimeType : "image/jpeg";
|
|
62430
62437
|
const base643 = Buffer.from(opts.bytes).toString("base64");
|
|
@@ -62519,7 +62526,7 @@ async function extractPassportIdentity(opts) {
|
|
|
62519
62526
|
if (!opts.apiKey || opts.apiKey.trim().length === 0) {
|
|
62520
62527
|
throw new Error("extractPassportIdentity: apiKey required");
|
|
62521
62528
|
}
|
|
62522
|
-
const baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL2).replace(
|
|
62529
|
+
const baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL2).replace(/\/{1,512}$/, "");
|
|
62523
62530
|
const fetchImpl = opts.fetch ?? globalThis.fetch.bind(globalThis);
|
|
62524
62531
|
const mime = opts.mimeType?.trim() ? opts.mimeType : "image/jpeg";
|
|
62525
62532
|
const base643 = Buffer.from(opts.bytes).toString("base64");
|
package/dist/ingest.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ingest.d.ts","sourceRoot":"","sources":["../src/ingest.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,YAAY,EAAa,MAAM,YAAY,CAAC;AAC1D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAEjE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAI3C,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,QAAQ,CAAC;IACb,QAAQ,EAAE,eAAe,CAAC;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB;;sEAEkE;IAClE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;iFAC6E;IAC7E,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA+C1F;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAC9B,KAAK,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EACtC,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,gBAAgB,CAAC,CA4C3B;AAED,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,eAAe,CACnC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,sBAAsB,CAAC,CAejC;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAK7E;AAaD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"ingest.d.ts","sourceRoot":"","sources":["../src/ingest.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,YAAY,EAAa,MAAM,YAAY,CAAC;AAC1D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAEjE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAI3C,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,QAAQ,CAAC;IACb,QAAQ,EAAE,eAAe,CAAC;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB;;sEAEkE;IAClE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;iFAC6E;IAC7E,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA+C1F;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAC9B,KAAK,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EACtC,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,gBAAgB,CAAC,CA4C3B;AAED,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,eAAe,CACnC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,sBAAsB,CAAC,CAejC;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAK7E;AAaD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAWnD"}
|
package/dist/prompt.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAQ,KAAK,EAAE,MAAM,aAAa,CAAC;AA6C5E;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,WAAW,EAClB,mBAAmB,GAAE,MAAM,GAAG,IAAW,EACzC,OAAO,GAAE,cAAmB,GAC3B,MAAM,
|
|
1
|
+
{"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAQ,KAAK,EAAE,MAAM,aAAa,CAAC;AA6C5E;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,WAAW,EAClB,mBAAmB,GAAE,MAAM,GAAG,IAAW,EACzC,OAAO,GAAE,cAAmB,GAC3B,MAAM,CAyIR"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.test.d.ts","sourceRoot":"","sources":["../src/prompt.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reflect.test.d.ts","sourceRoot":"","sources":["../src/reflect.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rewrite-query.test.d.ts","sourceRoot":"","sources":["../src/rewrite-query.test.ts"],"names":[],"mappings":""}
|
package/dist/styles.d.ts
CHANGED
|
@@ -182,5 +182,14 @@ export interface ComposeOptions {
|
|
|
182
182
|
* block instead. `docs` = collecting their documents, `submitted` = filed.
|
|
183
183
|
*/
|
|
184
184
|
supportPhase?: "docs" | "submitted";
|
|
185
|
+
/**
|
|
186
|
+
* Per-stage override (Phase 2): goal/guidance from the lead's current funnel
|
|
187
|
+
* stage_definition. Takes precedence over `style.stages[stage]` for the stage
|
|
188
|
+
* block. Lets AI-built funnels carry per-stage instructions.
|
|
189
|
+
*/
|
|
190
|
+
stageOverride?: {
|
|
191
|
+
goal: string;
|
|
192
|
+
guidance?: string;
|
|
193
|
+
};
|
|
185
194
|
}
|
|
186
195
|
//# sourceMappingURL=styles.d.ts.map
|
package/dist/styles.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,aAAa,+DAAgE,CAAC;AAC3F,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzD,eAAO,MAAM,gBAAgB,2DAA4D,CAAC;AAC1F,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE/D,eAAO,MAAM,UAAU,2FAOb,CAAC;AACX,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;AAEnD,eAAO,MAAM,UAAU;;;;;;;;;;iBAGrB,CAAC;AACH,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAE9C,eAAO,MAAM,iBAAiB;;;;;iBAK5B,CAAC;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D,eAAO,MAAM,aAAa;;;;;;;;iBAKxB,CAAC;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAEzD,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAsCtB,CAAC;AACH,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEhD;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,gBAAgB,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAED;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,kEAAkE;IAClE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,cAAc;IAC7B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,MAAM,CAAC,EAAE,SAAS,cAAc,EAAE,CAAC;IACnC;;;;OAIG;IACH,aAAa,CAAC,EAAE,SAAS,qBAAqB,EAAE,CAAC;IACjD;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,aAAa,+DAAgE,CAAC;AAC3F,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzD,eAAO,MAAM,gBAAgB,2DAA4D,CAAC;AAC1F,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE/D,eAAO,MAAM,UAAU,2FAOb,CAAC;AACX,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;AAEnD,eAAO,MAAM,UAAU;;;;;;;;;;iBAGrB,CAAC;AACH,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAE9C,eAAO,MAAM,iBAAiB;;;;;iBAK5B,CAAC;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D,eAAO,MAAM,aAAa;;;;;;;;iBAKxB,CAAC;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAEzD,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAsCtB,CAAC;AACH,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEhD;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,gBAAgB,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAED;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,kEAAkE;IAClE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,cAAc;IAC7B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,MAAM,CAAC,EAAE,SAAS,cAAc,EAAE,CAAC;IACnC;;;;OAIG;IACH,aAAa,CAAC,EAAE,SAAS,qBAAqB,EAAE,CAAC;IACjD;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,WAAW,CAAC;IACpC;;;;OAIG;IACH,aAAa,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACrD"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chatman-media/kb",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Tenant-scoped Knowledge Base: hybrid retrieval (pgvector + BM25), ingest, answer pipeline, persona/skill composition. LLM I/O живёт в @chatman-media/llm-router.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"url": "https://github.com/chatman-media/lead-engine/issues"
|
|
57
57
|
},
|
|
58
58
|
"dependencies": {
|
|
59
|
-
"@chatman-media/llm-router": "1.
|
|
59
|
+
"@chatman-media/llm-router": "1.1.1",
|
|
60
60
|
"unpdf": "^1.6.2",
|
|
61
61
|
"zod": "^4.4.1"
|
|
62
62
|
},
|
package/src/answer-types.ts
CHANGED
|
@@ -57,6 +57,12 @@ export interface AnswerInput {
|
|
|
57
57
|
* uses a calm FAQ-support block instead — answering questions without selling.
|
|
58
58
|
*/
|
|
59
59
|
supportPhase?: "docs" | "submitted";
|
|
60
|
+
/**
|
|
61
|
+
* Per-stage override (Phase 2 C-2): the lead's current funnel-stage goal/
|
|
62
|
+
* guidance from stage_definitions. Takes precedence over the Style's
|
|
63
|
+
* per-sales-stage config when composing the prompt.
|
|
64
|
+
*/
|
|
65
|
+
stageOverride?: { goal: string; guidance?: string };
|
|
60
66
|
/**
|
|
61
67
|
* Called after every `answerWithRag` or `answerWithRagStream` call with the
|
|
62
68
|
* final telemetry. Useful for logging, metrics, or A/B experiment recording
|
package/src/answer.ts
CHANGED
|
@@ -234,6 +234,7 @@ async function answerFromHits(opts: {
|
|
|
234
234
|
? { directorHooks: input.directorHooks }
|
|
235
235
|
: {}),
|
|
236
236
|
...(input.supportPhase ? { supportPhase: input.supportPhase } : {}),
|
|
237
|
+
...(input.stageOverride ? { stageOverride: input.stageOverride } : {}),
|
|
237
238
|
});
|
|
238
239
|
temperature = input.style.model.temperature;
|
|
239
240
|
} else {
|
|
@@ -503,6 +504,7 @@ export async function* answerWithRagStream(input: AnswerInput): AsyncIterable<st
|
|
|
503
504
|
? { directorHooks: input.directorHooks }
|
|
504
505
|
: {}),
|
|
505
506
|
...(input.supportPhase ? { supportPhase: input.supportPhase } : {}),
|
|
507
|
+
...(input.stageOverride ? { stageOverride: input.stageOverride } : {}),
|
|
506
508
|
});
|
|
507
509
|
temperature = input.style.model.temperature;
|
|
508
510
|
} else {
|
package/src/chunk.ts
CHANGED
|
@@ -137,7 +137,7 @@ export function chunkBySections(text: string, opts: Partial<ChunkOptions> = {}):
|
|
|
137
137
|
};
|
|
138
138
|
|
|
139
139
|
for (const line of lines) {
|
|
140
|
-
const m = line.match(/^(#{1,6})\s+(
|
|
140
|
+
const m = line.match(/^(#{1,6})\s+(\S.*)$/);
|
|
141
141
|
if (m) {
|
|
142
142
|
flush();
|
|
143
143
|
currentHeading = m[2] ?? null;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { ChatClient, ChatMessage } from "@chatman-media/llm-router";
|
|
2
|
+
import { describe, expect, it } from "bun:test";
|
|
3
|
+
import { extractUserFacts, parseFactsFromLlmOutput } from "./extract-user-facts.ts";
|
|
4
|
+
|
|
5
|
+
const chat = (text: string): ChatClient => ({ complete: async () => text }) as unknown as ChatClient;
|
|
6
|
+
const chatThrows = (): ChatClient =>
|
|
7
|
+
({ complete: async () => { throw new Error("x"); } }) as unknown as ChatClient;
|
|
8
|
+
|
|
9
|
+
describe("parseFactsFromLlmOutput", () => {
|
|
10
|
+
it("нет {} → {}", () => {
|
|
11
|
+
expect(parseFactsFromLlmOutput("no json")).toEqual({});
|
|
12
|
+
});
|
|
13
|
+
it("битый JSON → {}", () => {
|
|
14
|
+
expect(parseFactsFromLlmOutput("{broken")).toEqual({});
|
|
15
|
+
});
|
|
16
|
+
it("массив → {}", () => {
|
|
17
|
+
expect(parseFactsFromLlmOutput("[1,2]")).toEqual({});
|
|
18
|
+
});
|
|
19
|
+
it("валидный объект + coercion числовых значений", () => {
|
|
20
|
+
expect(parseFactsFromLlmOutput('{"name":"Аня","age":23}')).toEqual({ name: "Аня", age: "23" });
|
|
21
|
+
});
|
|
22
|
+
it("пустые / слишком длинные значения и длинные ключи отбрасываются", () => {
|
|
23
|
+
const longVal = "x".repeat(300);
|
|
24
|
+
const longKey = "k".repeat(50);
|
|
25
|
+
const out = parseFactsFromLlmOutput(`{"city":" ","name":"Аня","big":"${longVal}","${longKey}":"v"}`);
|
|
26
|
+
expect(out).toEqual({ name: "Аня" });
|
|
27
|
+
});
|
|
28
|
+
it("code-fence/think снимаются", () => {
|
|
29
|
+
expect(parseFactsFromLlmOutput('```json\n{"name":"Ира"}\n```')).toEqual({ name: "Ира" });
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe("extractUserFacts", () => {
|
|
34
|
+
const msgs: ChatMessage[] = [{ role: "user", content: "я Аня, мне 23" }];
|
|
35
|
+
it("нет user-сообщений → {} без LLM", async () => {
|
|
36
|
+
expect(await extractUserFacts({ messages: [{ role: "assistant", content: "hi" }], chat: chatThrows() })).toEqual({});
|
|
37
|
+
});
|
|
38
|
+
it("парсит факты из LLM", async () => {
|
|
39
|
+
expect(await extractUserFacts({ messages: msgs, chat: chat('{"name":"Аня","age":"23"}') })).toEqual({ name: "Аня", age: "23" });
|
|
40
|
+
});
|
|
41
|
+
it("LLM упал → {}", async () => {
|
|
42
|
+
expect(await extractUserFacts({ messages: msgs, chat: chatThrows() })).toEqual({});
|
|
43
|
+
});
|
|
44
|
+
});
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { ChatClient } from "@chatman-media/llm-router";
|
|
2
|
+
import { afterEach, describe, expect, it } from "bun:test";
|
|
3
|
+
import { checkFacts, parseFactCheckResult } from "./fact-checker.ts";
|
|
4
|
+
|
|
5
|
+
const chat = (text: string): ChatClient => ({ complete: async () => text }) as unknown as ChatClient;
|
|
6
|
+
const chatThrows = (): ChatClient =>
|
|
7
|
+
({ complete: async () => { throw new Error("down"); } }) as unknown as ChatClient;
|
|
8
|
+
|
|
9
|
+
const savedEnv = process.env.RAG_FACT_CHECKER_FAIL_OPEN;
|
|
10
|
+
afterEach(() => {
|
|
11
|
+
if (savedEnv === undefined) delete process.env.RAG_FACT_CHECKER_FAIL_OPEN;
|
|
12
|
+
else process.env.RAG_FACT_CHECKER_FAIL_OPEN = savedEnv;
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
describe("parseFactCheckResult", () => {
|
|
16
|
+
it("чистый JSON", () => {
|
|
17
|
+
expect(parseFactCheckResult('{"grounded":false,"vacancyOk":true,"reason":"x"}')).toEqual({
|
|
18
|
+
grounded: false,
|
|
19
|
+
vacancyOk: true,
|
|
20
|
+
reason: "x",
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
it("code-fence + think убираются", () => {
|
|
24
|
+
expect(parseFactCheckResult('<think>..</think>```json\n{"grounded":true,"vacancyOk":false}\n```')).toMatchObject({
|
|
25
|
+
grounded: true,
|
|
26
|
+
vacancyOk: false,
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
it("нет {} → OK (fail-open парсинга)", () => {
|
|
30
|
+
expect(parseFactCheckResult("no json")).toEqual({ grounded: true, vacancyOk: true });
|
|
31
|
+
});
|
|
32
|
+
it("битый JSON → OK", () => {
|
|
33
|
+
expect(parseFactCheckResult("{broken")).toEqual({ grounded: true, vacancyOk: true });
|
|
34
|
+
});
|
|
35
|
+
it("non-bool поля → дефолт true", () => {
|
|
36
|
+
expect(parseFactCheckResult('{"grounded":"yes"}')).toEqual({ grounded: true, vacancyOk: true });
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
describe("checkFacts", () => {
|
|
41
|
+
const base = { question: "q", answer: "Зарплата 1500$", context: "контекст 1500$" };
|
|
42
|
+
it("пустой ответ → OK без вызова LLM", async () => {
|
|
43
|
+
expect(await checkFacts({ ...base, answer: " ", chat: chatThrows() })).toEqual({ grounded: true, vacancyOk: true });
|
|
44
|
+
});
|
|
45
|
+
it("нет контекста и вакансий → OK", async () => {
|
|
46
|
+
expect(await checkFacts({ ...base, context: "", chat: chatThrows() })).toEqual({ grounded: true, vacancyOk: true });
|
|
47
|
+
});
|
|
48
|
+
it("есть контекст → парсит вердикт LLM", async () => {
|
|
49
|
+
const r = await checkFacts({ ...base, chat: chat('{"grounded":false,"vacancyOk":true,"reason":"выдумал"}') });
|
|
50
|
+
expect(r.grounded).toBe(false);
|
|
51
|
+
});
|
|
52
|
+
it("vacancies-ветка промпта", async () => {
|
|
53
|
+
const r = await checkFacts({ ...base, vacanciesBlock: "Вакансия: 2000$", chat: chat('{"grounded":true,"vacancyOk":false,"reason":"не совпало"}') });
|
|
54
|
+
expect(r.vacancyOk).toBe(false);
|
|
55
|
+
});
|
|
56
|
+
it("LLM упал → fail-closed по умолчанию", async () => {
|
|
57
|
+
delete process.env.RAG_FACT_CHECKER_FAIL_OPEN;
|
|
58
|
+
const r = await checkFacts({ ...base, chat: chatThrows() });
|
|
59
|
+
expect(r.grounded).toBe(false);
|
|
60
|
+
expect(r.reason).toContain("checker_error");
|
|
61
|
+
});
|
|
62
|
+
it("LLM упал + FAIL_OPEN=1 → пропускаем", async () => {
|
|
63
|
+
process.env.RAG_FACT_CHECKER_FAIL_OPEN = "1";
|
|
64
|
+
expect(await checkFacts({ ...base, chat: chatThrows() })).toEqual({ grounded: true, vacancyOk: true });
|
|
65
|
+
});
|
|
66
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { ChatClient } from "@chatman-media/llm-router";
|
|
2
|
+
import { describe, expect, it } from "bun:test";
|
|
3
|
+
import { gradeSkills, parseSlugList } from "./grade-skills.ts";
|
|
4
|
+
|
|
5
|
+
const chat = (text: string): ChatClient => ({ complete: async () => text }) as unknown as ChatClient;
|
|
6
|
+
const chatThrows = (): ChatClient =>
|
|
7
|
+
({ complete: async () => { throw new Error("x"); } }) as unknown as ChatClient;
|
|
8
|
+
const ALLOWED = ["mirroring", "scarcity-spots-left", "tactical-empathy"] as const;
|
|
9
|
+
|
|
10
|
+
describe("parseSlugList", () => {
|
|
11
|
+
it("пусто → []", () => {
|
|
12
|
+
expect(parseSlugList("", ALLOWED)).toEqual([]);
|
|
13
|
+
});
|
|
14
|
+
it("JSON-массив, фильтр по allowed", () => {
|
|
15
|
+
expect(parseSlugList('["mirroring","unknown-skill","tactical-empathy"]', ALLOWED)).toEqual(["mirroring", "tactical-empathy"]);
|
|
16
|
+
});
|
|
17
|
+
it("code-fenced JSON", () => {
|
|
18
|
+
expect(parseSlugList('```json\n["scarcity-spots-left"]\n```', ALLOWED)).toEqual(["scarcity-spots-left"]);
|
|
19
|
+
});
|
|
20
|
+
it("comma/newline текст → fallback-парсинг", () => {
|
|
21
|
+
expect(parseSlugList("mirroring, tactical-empathy", ALLOWED)).toEqual(["mirroring", "tactical-empathy"]);
|
|
22
|
+
});
|
|
23
|
+
it("всё неразрешённое → []", () => {
|
|
24
|
+
expect(parseSlugList('["foo","bar"]', ALLOWED)).toEqual([]);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
describe("gradeSkills", () => {
|
|
29
|
+
const base = { question: "q", reply: "r", availableSlugs: ALLOWED };
|
|
30
|
+
it("пустой availableSlugs → [] без LLM", async () => {
|
|
31
|
+
expect(await gradeSkills({ ...base, availableSlugs: [], chat: chatThrows() })).toEqual([]);
|
|
32
|
+
});
|
|
33
|
+
it("парсит и фильтрует ответ LLM", async () => {
|
|
34
|
+
expect(await gradeSkills({ ...base, chat: chat('["mirroring","x"]') })).toEqual(["mirroring"]);
|
|
35
|
+
});
|
|
36
|
+
it("LLM упал → [] (failure-soft)", async () => {
|
|
37
|
+
expect(await gradeSkills({ ...base, chat: chatThrows() })).toEqual([]);
|
|
38
|
+
});
|
|
39
|
+
});
|
package/src/ingest.ts
CHANGED
|
@@ -187,7 +187,12 @@ function* walk(dir: string): Generator<string> {
|
|
|
187
187
|
export function stripNonContent(raw: string): string {
|
|
188
188
|
let s = raw;
|
|
189
189
|
s = s.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/, "");
|
|
190
|
-
|
|
190
|
+
// Strip HTML comments. Bounded quantifier avoids polynomial backtracking;
|
|
191
|
+
// loop until stable so a leftover `<!--` can't survive a single pass.
|
|
192
|
+
for (let prev = ""; prev !== s; ) {
|
|
193
|
+
prev = s;
|
|
194
|
+
s = s.replace(/<!--[\s\S]{0,10000}?-->/g, "");
|
|
195
|
+
}
|
|
191
196
|
s = s.replace(/\n{3,}/g, "\n\n").trim();
|
|
192
197
|
return `${s}\n`;
|
|
193
198
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// Unit tests for kb composeSystemPrompt — the prompt builder used by the reply
|
|
2
|
+
// pipeline (answer.ts). Focus: Phase 2 C-2 `stageOverride` precedence (the
|
|
3
|
+
// lead's funnel-stage goal/guidance wins over the Style's per-sales-stage cfg).
|
|
4
|
+
|
|
5
|
+
import { describe, expect, it } from "bun:test";
|
|
6
|
+
import { composeSystemPrompt } from "./prompt.ts";
|
|
7
|
+
import type { Style } from "./styles.ts";
|
|
8
|
+
|
|
9
|
+
const baseStyle: Style = {
|
|
10
|
+
slug: "t",
|
|
11
|
+
displayName: "T",
|
|
12
|
+
persona: { name: "Алекс", role: "human" },
|
|
13
|
+
voice: { tone: "friendly", language: "ru", forbid: [] },
|
|
14
|
+
framework: "SPIN",
|
|
15
|
+
hooks: [],
|
|
16
|
+
stages: { qualify: { goal: "STYLE_GOAL", groundingRequired: false } },
|
|
17
|
+
fewShot: [],
|
|
18
|
+
guardrails: { noMinors: true, botDisclosureOnDirectQuestion: true, forbiddenTopics: [] },
|
|
19
|
+
model: { id: "x", temperature: 0.5, maxTokens: 100 },
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
describe("composeSystemPrompt — stageOverride (Phase 2 C-2)", () => {
|
|
23
|
+
it("без override → goal берётся из Style", () => {
|
|
24
|
+
const p = composeSystemPrompt(baseStyle, "qualify");
|
|
25
|
+
expect(p).toContain("STYLE_GOAL");
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("stageOverride имеет приоритет над Style для goal и guidance", () => {
|
|
29
|
+
const p = composeSystemPrompt(baseStyle, "qualify", null, {
|
|
30
|
+
stageOverride: { goal: "OVERRIDE_GOAL", guidance: "OVERRIDE_GUIDE" },
|
|
31
|
+
});
|
|
32
|
+
expect(p).toContain("OVERRIDE_GOAL");
|
|
33
|
+
expect(p).toContain("OVERRIDE_GUIDE");
|
|
34
|
+
expect(p).not.toContain("STYLE_GOAL");
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("stageOverride работает для стадии без конфига в Style", () => {
|
|
38
|
+
// "close" нет в baseStyle.stages → раньше был бы generic-блок; теперь override.
|
|
39
|
+
const p = composeSystemPrompt(baseStyle, "close", null, {
|
|
40
|
+
stageOverride: { goal: "CLOSE_GOAL" },
|
|
41
|
+
});
|
|
42
|
+
expect(p).toContain("CLOSE_GOAL");
|
|
43
|
+
});
|
|
44
|
+
});
|
package/src/prompt.ts
CHANGED
|
@@ -121,11 +121,15 @@ export function composeSystemPrompt(
|
|
|
121
121
|
skillsForStage.map((s) => `- ${s.displayName} — ${s.promptFragment}`).join("\n")
|
|
122
122
|
: "";
|
|
123
123
|
|
|
124
|
-
|
|
124
|
+
// Per-stage instructions: the lead's funnel-stage override (Phase 2) takes
|
|
125
|
+
// precedence over the Style's per-sales-stage config; grounding stays from style.
|
|
126
|
+
const effGoal = options.stageOverride?.goal ?? stageCfg?.goal;
|
|
127
|
+
const effGuidance = options.stageOverride?.guidance ?? stageCfg?.guidance;
|
|
128
|
+
const stageBlock = effGoal
|
|
125
129
|
? `ТЕКУЩИЙ ЭТАП: ${stage.toUpperCase()}.\n` +
|
|
126
|
-
`ЦЕЛЬ ЭТАПА: ${
|
|
127
|
-
(
|
|
128
|
-
(stageCfg
|
|
130
|
+
`ЦЕЛЬ ЭТАПА: ${effGoal}.` +
|
|
131
|
+
(effGuidance ? `\nКАК: ${effGuidance}` : "") +
|
|
132
|
+
(stageCfg?.groundingRequired
|
|
129
133
|
? `\nGROUNDING: на этом этапе все конкретные факты (цифры, суммы, сроки) бери ТОЛЬКО из секции KB CONTEXT ниже. Если её нет или нужного факта в ней нет — не выдумывай, скажи что уточнишь.`
|
|
130
134
|
: "")
|
|
131
135
|
: `ТЕКУЩИЙ ЭТАП: ${stage}. (Специфических правил для этапа нет — используй общий стиль.)`;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { ChatClient } from "@chatman-media/llm-router";
|
|
2
|
+
import { describe, expect, it } from "bun:test";
|
|
3
|
+
import { parseReflection, verifyAnswer } from "./reflect.ts";
|
|
4
|
+
|
|
5
|
+
const chat = (text: string): ChatClient => ({ complete: async () => text }) as unknown as ChatClient;
|
|
6
|
+
const chatThrows = (): ChatClient =>
|
|
7
|
+
({ complete: async () => { throw new Error("x"); } }) as unknown as ChatClient;
|
|
8
|
+
|
|
9
|
+
describe("parseReflection", () => {
|
|
10
|
+
it("нет {} → grounded:true", () => {
|
|
11
|
+
expect(parseReflection("plain")).toEqual({ grounded: true });
|
|
12
|
+
});
|
|
13
|
+
it("битый JSON → true", () => {
|
|
14
|
+
expect(parseReflection("{nope")).toEqual({ grounded: true });
|
|
15
|
+
});
|
|
16
|
+
it("grounded non-bool → true", () => {
|
|
17
|
+
expect(parseReflection('{"grounded":1}')).toEqual({ grounded: true });
|
|
18
|
+
});
|
|
19
|
+
it("grounded:true → {true}", () => {
|
|
20
|
+
expect(parseReflection('{"grounded":true}')).toEqual({ grounded: true });
|
|
21
|
+
});
|
|
22
|
+
it("grounded:false → {false, reason}", () => {
|
|
23
|
+
expect(parseReflection('{"grounded":false,"reason":"выдумал город"}')).toEqual({ grounded: false, reason: "выдумал город" });
|
|
24
|
+
});
|
|
25
|
+
it("grounded:false без reason → unknown", () => {
|
|
26
|
+
expect(parseReflection('{"grounded":false}')).toEqual({ grounded: false, reason: "unknown" });
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
describe("verifyAnswer", () => {
|
|
31
|
+
const base = { question: "q", answer: "Дубай 1500$", context: "Дубай 1500$" };
|
|
32
|
+
it("пустой ответ → grounded:true", async () => {
|
|
33
|
+
expect(await verifyAnswer({ ...base, answer: " ", chat: chatThrows() })).toEqual({ grounded: true });
|
|
34
|
+
});
|
|
35
|
+
it("нет контекста → grounded:true", async () => {
|
|
36
|
+
expect(await verifyAnswer({ ...base, context: "", chat: chatThrows() })).toEqual({ grounded: true });
|
|
37
|
+
});
|
|
38
|
+
it("LLM-вердикт false → {false,reason}", async () => {
|
|
39
|
+
expect(await verifyAnswer({ ...base, chat: chat('{"grounded":false,"reason":"r"}') })).toMatchObject({ grounded: false });
|
|
40
|
+
});
|
|
41
|
+
it("LLM упал → grounded:true (fail-open)", async () => {
|
|
42
|
+
expect(await verifyAnswer({ ...base, chat: chatThrows() })).toEqual({ grounded: true });
|
|
43
|
+
});
|
|
44
|
+
});
|
package/src/reranker.ts
CHANGED
|
@@ -49,7 +49,7 @@ export class CohereReranker implements Reranker {
|
|
|
49
49
|
if (!opts.apiKey) throw new Error("CohereReranker: apiKey required");
|
|
50
50
|
this.apiKey = opts.apiKey;
|
|
51
51
|
this.model = opts.model ?? "rerank-v3.5";
|
|
52
|
-
this.baseUrl = (opts.baseUrl ?? "https://api.cohere.com/v2").replace(
|
|
52
|
+
this.baseUrl = (opts.baseUrl ?? "https://api.cohere.com/v2").replace(/\/{1,512}$/, "");
|
|
53
53
|
this.timeoutMs = opts.timeoutMs ?? 30_000;
|
|
54
54
|
this.fetchImpl = opts.fetch ?? globalThis.fetch.bind(globalThis);
|
|
55
55
|
}
|
|
@@ -128,7 +128,7 @@ export class JinaReranker implements Reranker {
|
|
|
128
128
|
if (!opts.apiKey) throw new Error("JinaReranker: apiKey required");
|
|
129
129
|
this.apiKey = opts.apiKey;
|
|
130
130
|
this.model = opts.model ?? "jina-reranker-v2-base-multilingual";
|
|
131
|
-
this.baseUrl = (opts.baseUrl ?? "https://api.jina.ai/v1").replace(
|
|
131
|
+
this.baseUrl = (opts.baseUrl ?? "https://api.jina.ai/v1").replace(/\/{1,512}$/, "");
|
|
132
132
|
this.timeoutMs = opts.timeoutMs ?? 30_000;
|
|
133
133
|
this.fetchImpl = opts.fetch ?? globalThis.fetch.bind(globalThis);
|
|
134
134
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { ChatClient, ChatMessage } from "@chatman-media/llm-router";
|
|
2
|
+
import { describe, expect, it } from "bun:test";
|
|
3
|
+
import { questionNeedsRewrite, rewriteQuery, sanitizeRewritten } from "./rewrite-query.ts";
|
|
4
|
+
|
|
5
|
+
const chat = (text: string): ChatClient => ({ complete: async () => text }) as unknown as ChatClient;
|
|
6
|
+
const chatThrows = (): ChatClient =>
|
|
7
|
+
({ complete: async () => { throw new Error("x"); } }) as unknown as ChatClient;
|
|
8
|
+
const hist: ChatMessage[] = [{ role: "assistant", content: "в Дубае платят 1500" }];
|
|
9
|
+
|
|
10
|
+
describe("questionNeedsRewrite", () => {
|
|
11
|
+
it("пустой → false", () => {
|
|
12
|
+
expect(questionNeedsRewrite(" ", hist)).toBe(false);
|
|
13
|
+
});
|
|
14
|
+
it("нет истории → false", () => {
|
|
15
|
+
expect(questionNeedsRewrite("а там как?", [])).toBe(false);
|
|
16
|
+
});
|
|
17
|
+
it("короткий (<=4 слова) с историей → true", () => {
|
|
18
|
+
expect(questionNeedsRewrite("а виза как?", hist)).toBe(true);
|
|
19
|
+
});
|
|
20
|
+
it("дейктик-маркер → true", () => {
|
|
21
|
+
expect(questionNeedsRewrite("сколько стоит это оформление документов в итоге", hist)).toBe(true);
|
|
22
|
+
});
|
|
23
|
+
it("follow-up союз в начале → true", () => {
|
|
24
|
+
expect(questionNeedsRewrite("или есть другие варианты работы там сейчас", hist)).toBe(true);
|
|
25
|
+
});
|
|
26
|
+
it("длинный самостоятельный → false", () => {
|
|
27
|
+
expect(questionNeedsRewrite("сколько платят моделям в Дубае за месяц работы по контракту", hist)).toBe(false);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe("sanitizeRewritten", () => {
|
|
32
|
+
it("снимает think/fence/«ответ:» и берёт первую строку", () => {
|
|
33
|
+
expect(sanitizeRewritten('<think>..</think>ответ: какие условия в Дубае\nещё текст', "fb", 200)).toBe("какие условия в Дубае");
|
|
34
|
+
});
|
|
35
|
+
it("пусто/мусор → fallback", () => {
|
|
36
|
+
expect(sanitizeRewritten(" \n ", "ОРИГИНАЛ", 200)).toBe("ОРИГИНАЛ");
|
|
37
|
+
});
|
|
38
|
+
it("обрезка по maxLength", () => {
|
|
39
|
+
expect(sanitizeRewritten("абвгде", "fb", 3)).toBe("абв");
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
describe("rewriteQuery", () => {
|
|
44
|
+
it("пустой вопрос → как есть", async () => {
|
|
45
|
+
expect(await rewriteQuery({ question: " ", chat: chatThrows() })).toBe("");
|
|
46
|
+
});
|
|
47
|
+
it("не нужен рерайт (нет истории) → оригинал без вызова LLM", async () => {
|
|
48
|
+
expect(await rewriteQuery({ question: "а там?", chat: chatThrows() })).toBe("а там?");
|
|
49
|
+
});
|
|
50
|
+
it("нужен рерайт → sanitized из LLM", async () => {
|
|
51
|
+
expect(await rewriteQuery({ question: "а виза?", history: hist, chat: chat("как оформляется виза") })).toBe("как оформляется виза");
|
|
52
|
+
});
|
|
53
|
+
it("LLM упал → оригинал", async () => {
|
|
54
|
+
expect(await rewriteQuery({ question: "а виза?", history: hist, chat: chatThrows() })).toBe("а виза?");
|
|
55
|
+
});
|
|
56
|
+
});
|
package/src/structured-output.ts
CHANGED
package/src/styles.ts
CHANGED
|
@@ -135,4 +135,10 @@ export interface ComposeOptions {
|
|
|
135
135
|
* block instead. `docs` = collecting their documents, `submitted` = filed.
|
|
136
136
|
*/
|
|
137
137
|
supportPhase?: "docs" | "submitted";
|
|
138
|
+
/**
|
|
139
|
+
* Per-stage override (Phase 2): goal/guidance from the lead's current funnel
|
|
140
|
+
* stage_definition. Takes precedence over `style.stages[stage]` for the stage
|
|
141
|
+
* block. Lets AI-built funnels carry per-stage instructions.
|
|
142
|
+
*/
|
|
143
|
+
stageOverride?: { goal: string; guidance?: string };
|
|
138
144
|
}
|
package/src/text-style-rules.ts
CHANGED
|
@@ -37,7 +37,7 @@ export interface TextStyleRule {
|
|
|
37
37
|
export const replaceEmDash: TextStyleRule = {
|
|
38
38
|
name: "replace-em-dash",
|
|
39
39
|
description: "U+2014 «—» → «-» (с нормализацией пробелов)",
|
|
40
|
-
apply: (s) => s.replace(/\s
|
|
40
|
+
apply: (s) => s.replace(/\s{0,200}—\s{0,200}/g, " - ").replace(/ {2,}/g, " "),
|
|
41
41
|
};
|
|
42
42
|
|
|
43
43
|
/**
|
package/src/vision.ts
CHANGED
|
@@ -74,7 +74,7 @@ export async function classifyPhoto(opts: ClassifyPhotoOptions): Promise<PhotoCl
|
|
|
74
74
|
if (!opts.apiKey || opts.apiKey.trim().length === 0) {
|
|
75
75
|
throw new Error("classifyPhoto: apiKey required");
|
|
76
76
|
}
|
|
77
|
-
const baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(
|
|
77
|
+
const baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\/{1,512}$/, "");
|
|
78
78
|
const fetchImpl = opts.fetch ?? globalThis.fetch.bind(globalThis);
|
|
79
79
|
const mime = opts.mimeType?.trim() ? opts.mimeType : "image/jpeg";
|
|
80
80
|
const base64 = Buffer.from(opts.bytes).toString("base64");
|
|
@@ -210,7 +210,7 @@ export async function extractPassportIdentity(
|
|
|
210
210
|
if (!opts.apiKey || opts.apiKey.trim().length === 0) {
|
|
211
211
|
throw new Error("extractPassportIdentity: apiKey required");
|
|
212
212
|
}
|
|
213
|
-
const baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(
|
|
213
|
+
const baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\/{1,512}$/, "");
|
|
214
214
|
const fetchImpl = opts.fetch ?? globalThis.fetch.bind(globalThis);
|
|
215
215
|
const mime = opts.mimeType?.trim() ? opts.mimeType : "image/jpeg";
|
|
216
216
|
const base64 = Buffer.from(opts.bytes).toString("base64");
|