@lacneu/openclaw-knowledge 3.2.3 → 3.2.5

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/pgvector.js CHANGED
@@ -54,17 +54,26 @@ export async function searchCollection(pool, collection, vector, topK, scoreThre
54
54
  .filter((row) => row.score >= scoreThreshold);
55
55
  }
56
56
  /**
57
- * Format pgvector results for injection into the system prompt.
58
- * Respects a character budget so we never blow the context window with a
59
- * single oversized chunk — entries are appended whole until the budget is hit.
57
+ * Format pgvector results for injection into the system prompt AND report
58
+ * how many input entries were actually included.
60
59
  *
61
- * Returns `null` when there is nothing useful to inject so the caller can
62
- * easily skip empty sections.
60
+ * Internal sibling of the public `formatPgvectorResults`. The public
61
+ * variant returns only the prompt text and is kept backward-compatible;
62
+ * this one exposes `injectedCount` so the plugin's render path can size
63
+ * the provenance report to the injected subset (contract: "emit what
64
+ * was injected, not what was retrieved").
65
+ *
66
+ * Returns `null` when there is nothing useful to inject (empty input OR
67
+ * the budget cannot fit a single entry) so the caller can skip empty
68
+ * sections AND skip emitting a provenance report for zero injected items.
69
+ *
70
+ * @since 3.2.5
63
71
  */
64
- export function formatPgvectorResults(results, maxChars) {
72
+ export function formatPgvectorResultsDetailed(results, maxChars) {
65
73
  if (results.length === 0)
66
74
  return null;
67
75
  let output = "";
76
+ let injectedCount = 0;
68
77
  for (const r of results) {
69
78
  const lines = [
70
79
  `[${r.collection}] ${r.file_name ?? "unknown"} (score: ${r.score.toFixed(2)})`,
@@ -80,8 +89,29 @@ export function formatPgvectorResults(results, maxChars) {
80
89
  if (output.length + entry.length > maxChars)
81
90
  break;
82
91
  output += entry;
92
+ injectedCount += 1;
83
93
  }
84
- return output;
94
+ // No entry fit the budget — equivalent to "nothing to inject" so the
95
+ // caller skips the header AND the provenance report. Preserves the
96
+ // pre-3.2.5 `if (!formatted)` semantics when output was an empty string.
97
+ if (injectedCount === 0)
98
+ return null;
99
+ return { output, injectedCount };
100
+ }
101
+ /**
102
+ * Format pgvector results for injection into the system prompt.
103
+ * Respects a character budget so we never blow the context window with a
104
+ * single oversized chunk — entries are appended whole until the budget is hit.
105
+ *
106
+ * Returns `null` when there is nothing useful to inject so the caller can
107
+ * easily skip empty sections.
108
+ *
109
+ * Public API — signature kept stable across the v3.x line. Callers needing
110
+ * the count of entries actually injected should use
111
+ * `formatPgvectorResultsDetailed` (internal to this package).
112
+ */
113
+ export function formatPgvectorResults(results, maxChars) {
114
+ return formatPgvectorResultsDetailed(results, maxChars)?.output ?? null;
85
115
  }
86
116
  /**
87
117
  * Re-order `results` using the Jina cross-encoder reranker.
@@ -107,21 +137,44 @@ export async function rerankPgvectorResults(results, params) {
107
137
  // The reranker only sees the textual content. Empty/null texts cannot be
108
138
  // ranked, so we filter them out BEFORE the API call to avoid wasting
109
139
  // tokens on rows the cross-encoder can't score anyway.
110
- const indexed = results
140
+ let indexed = results
111
141
  .map((r, i) => ({ row: r, originalIndex: i, text: r.text ?? "" }))
112
142
  .filter((x) => x.text.trim().length > 0);
113
143
  if (indexed.length === 0)
114
144
  return results.slice(0, params.topN ?? results.length);
145
+ // 3.2.4 — payload-size guards. Both are no-ops when undefined so the
146
+ // legacy behavior is preserved for callers that haven't migrated.
147
+ if (typeof params.candidatePoolMax === "number" &&
148
+ params.candidatePoolMax > 0 &&
149
+ indexed.length > params.candidatePoolMax) {
150
+ // `results` is already cosine-sorted by the caller (runPgvectorSource).
151
+ // `indexed` preserves that order via the `originalIndex` mapping, so
152
+ // slicing to the first N keeps the best candidates and drops the tail.
153
+ indexed = indexed.slice(0, params.candidatePoolMax);
154
+ }
155
+ const documents = typeof params.maxCharsPerDoc === "number" && params.maxCharsPerDoc > 0
156
+ ? indexed.map((x) => x.text.slice(0, params.maxCharsPerDoc))
157
+ : indexed.map((x) => x.text);
158
+ const startedAt = Date.now();
115
159
  try {
116
160
  const reranked = await rerank({
117
161
  apiKey: params.apiKey,
118
162
  query: params.query,
119
- documents: indexed.map((x) => x.text),
163
+ documents,
120
164
  model: params.model,
121
165
  topN: params.topN,
122
166
  timeoutMs: params.timeoutMs,
123
167
  signal: params.signal,
168
+ rpmMonitor: params.rpmMonitor,
124
169
  });
170
+ if (params.onUsage) {
171
+ const totalChars = documents.reduce((sum, d) => sum + d.length, 0);
172
+ params.onUsage({
173
+ inputCount: documents.length,
174
+ totalChars,
175
+ durationMs: Date.now() - startedAt,
176
+ });
177
+ }
125
178
  if (reranked.length === 0) {
126
179
  // Defensive: reranker returned no usable items. Surface the original
127
180
  // cosine order rather than wiping the candidate list.
@@ -1 +1 @@
1
- {"version":3,"file":"pgvector.js","sourceRoot":"","sources":["../src/pgvector.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pgvector.js","sourceRoot":"","sources":["../src/pgvector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,105 @@
1
+ import type { PluginLogger } from "openclaw/plugin-sdk/plugin-entry";
2
+ import type { PgvectorResult } from "./types.js";
3
+ export type ProvenanceReportLevel = "off" | "metadata" | "full";
4
+ export declare const PROVENANCE_REPORT_LEVELS: readonly ProvenanceReportLevel[];
5
+ /** Gateway-scoped stream this plugin emits on (see contract §2). */
6
+ export declare const PROVENANCE_STREAM = "openclaw-knowledge.provenance";
7
+ /** Mirrors the consumer's per-item excerpt bound (contract §3). */
8
+ export declare const PROVENANCE_EXCERPT_MAX_CHARS = 2000;
9
+ /** Mirrors the consumer's per-report item cap (contract §3). */
10
+ export declare const PROVENANCE_MAX_ITEMS = 24;
11
+ export interface ProvenanceItemV1 {
12
+ id?: string;
13
+ type?: string;
14
+ date?: string;
15
+ score?: number;
16
+ text?: string;
17
+ file_name?: string;
18
+ collection?: string;
19
+ }
20
+ export interface ProvenanceReportV1 {
21
+ v: 1;
22
+ source: "knowledge";
23
+ kind: "documents";
24
+ injected?: {
25
+ chars?: number;
26
+ position?: string;
27
+ truncated?: boolean;
28
+ };
29
+ retrieval?: {
30
+ route?: string;
31
+ collections?: string[];
32
+ lightrag?: {
33
+ mode?: string;
34
+ };
35
+ };
36
+ items: ProvenanceItemV1[];
37
+ }
38
+ /** Structural emitAgentEvent surface (the installed SDK types may predate it). */
39
+ export type EmitAgentEventFn = (event: {
40
+ runId: string;
41
+ sessionKey?: string;
42
+ stream: string;
43
+ data: unknown;
44
+ }) => unknown;
45
+ /** Normalize the operator's config value; anything off-list means "off". */
46
+ export declare function resolveProvenanceLevel(raw: unknown): ProvenanceReportLevel;
47
+ /**
48
+ * Feature-detect emitAgentEvent on the (first-registration) plugin api.
49
+ *
50
+ * GATEWAY QUIRK (bench-verified 2026-06-12): the agent runtime RE-REGISTERS
51
+ * plugins per run, and emitting through a re-registration's api is rejected
52
+ * `"plugin is not loaded"` — callers MUST pass the FIRST registration's api
53
+ * (module-level singleton; see registerKnowledgePlugin).
54
+ */
55
+ export declare function resolveEmitAgentEvent(api: unknown): EmitAgentEventFn | undefined;
56
+ /**
57
+ * Report for an injected pgvector section. `data` is the FINAL injected list
58
+ * (post-rerank, post-topN — exactly what reached the LLM). Returns null when
59
+ * the level is "off" or there is nothing citable.
60
+ */
61
+ export declare function buildPgvectorProvenance(data: PgvectorResult[], collections: string[], level: ProvenanceReportLevel, injectedChars: number): ProvenanceReportV1 | null;
62
+ /**
63
+ * Report for an injected LightRAG section. The graph response is one opaque
64
+ * context blob (no per-document structure yet — the docstore initiative will
65
+ * enrich this), so the report carries ONE item describing the injected
66
+ * context; "full" includes its leading excerpt VERBATIM from what was
67
+ * actually injected (the post-truncation text).
68
+ *
69
+ * @param injectedText body of the section actually delivered to the LLM
70
+ * (post-truncation, header EXCLUDED). Used for the
71
+ * `full`-level excerpt.
72
+ * @param mode LightRAG query mode (`mix`, `hybrid`, …).
73
+ * @param level provenance gate (`off` / `metadata` / `full`).
74
+ * @param injectedChars total length of the system-prompt section actually
75
+ * delivered (header INCLUDED). Defaults to
76
+ * `injectedText.length` for callers that don't track
77
+ * the header separately; the plugin's render path
78
+ * passes the full section length so `injected.chars`
79
+ * reflects exactly what reached the LLM
80
+ * (codex pass #36 P3). Negative values fall back to
81
+ * `injectedText.length` to keep the report
82
+ * well-formed even on caller mistakes.
83
+ */
84
+ export declare function buildLightRAGProvenance(injectedText: string, mode: string, level: ProvenanceReportLevel, injectedChars?: number): ProvenanceReportV1 | null;
85
+ /**
86
+ * Stable categories logged when emission fails. Operators triage by code;
87
+ * the underlying gateway reason / Error message is intentionally NEVER
88
+ * passed to the logger because in `full` mode it may echo back the
89
+ * payload (excerpts of the injected documents) it was rejecting — and the
90
+ * tracing invariant of this module is that report content never reaches
91
+ * logs.
92
+ *
93
+ * @since 3.2.5 (codex pass #36 P2 — sanitize emission failure logs)
94
+ */
95
+ export type ProvenanceEmitFailureCode = "plugin_not_loaded" | "missing_run_context" | "invalid_stream" | "validation_error" | "rate_limited" | "rejected" | "throw";
96
+ /**
97
+ * Emit the turn's reports. Every guard degrades to SILENCE (a missing SDK
98
+ * function, a missing runId, a gateway rejection) — provenance must never
99
+ * break or delay a turn. Failures are logged as a STABLE CATEGORY CODE
100
+ * (never the raw gateway reason or Error message) because a silent
101
+ * `{emitted:false}` is undiagnosable in the field, but echoing the raw
102
+ * reason could leak fragments of the injected payload back into the log
103
+ * stream — violating the module's tracing invariant.
104
+ */
105
+ export declare function emitProvenanceReports(emit: EmitAgentEventFn | undefined, logger: PluginLogger, runId: string | undefined, sessionKey: string | undefined, reports: (ProvenanceReportV1 | null)[]): void;
@@ -0,0 +1,186 @@
1
+ // Provenance reporting (provenance/v1) — what this plugin ACTUALLY injected
2
+ // into the LLM, emitted on the gateway agent-event bus so a chat frontend
3
+ // (openclaw-webchat) can show the user "which documents fed this reply".
4
+ //
5
+ // Normative contract: openclaw-webchat docs/PROVENANCE_CONTRACT.md.
6
+ // Transport rules (gateway-enforced, bench-verified 2026-06-12):
7
+ // - stream MUST be scoped to this plugin: "openclaw-knowledge.provenance";
8
+ // - runId is REQUIRED (the before_prompt_build ctx carries it);
9
+ // - the gateway stamps pluginId/pluginName into `data` (authenticated
10
+ // emitter identity — we never claim it ourselves);
11
+ // - a violation returns `{emitted:false, reason}` WITHOUT throwing.
12
+ //
13
+ // PRIVACY: this channel is DISTINCT from the tracing events module — reports
14
+ // land in the chat frontend's store under the chat's own ACL. The level knob
15
+ // keeps content out unless the operator opts in:
16
+ // - "off" (default): no emission at all;
17
+ // - "metadata": items WITHOUT text (file names, collections, scores);
18
+ // - "full": plus the exact injected excerpts.
19
+ // The tracing invariant is untouched: NOTHING here goes through logs.
20
+ export const PROVENANCE_REPORT_LEVELS = [
21
+ "off",
22
+ "metadata",
23
+ "full",
24
+ ];
25
+ /** Gateway-scoped stream this plugin emits on (see contract §2). */
26
+ export const PROVENANCE_STREAM = "openclaw-knowledge.provenance";
27
+ /** Mirrors the consumer's per-item excerpt bound (contract §3). */
28
+ export const PROVENANCE_EXCERPT_MAX_CHARS = 2_000;
29
+ /** Mirrors the consumer's per-report item cap (contract §3). */
30
+ export const PROVENANCE_MAX_ITEMS = 24;
31
+ /** Normalize the operator's config value; anything off-list means "off". */
32
+ export function resolveProvenanceLevel(raw) {
33
+ return PROVENANCE_REPORT_LEVELS.includes(raw)
34
+ ? raw
35
+ : "off";
36
+ }
37
+ /**
38
+ * Feature-detect emitAgentEvent on the (first-registration) plugin api.
39
+ *
40
+ * GATEWAY QUIRK (bench-verified 2026-06-12): the agent runtime RE-REGISTERS
41
+ * plugins per run, and emitting through a re-registration's api is rejected
42
+ * `"plugin is not loaded"` — callers MUST pass the FIRST registration's api
43
+ * (module-level singleton; see registerKnowledgePlugin).
44
+ */
45
+ export function resolveEmitAgentEvent(api) {
46
+ const candidate = api?.emitAgentEvent;
47
+ if (typeof candidate !== "function")
48
+ return undefined;
49
+ return candidate.bind(api);
50
+ }
51
+ /**
52
+ * Report for an injected pgvector section. `data` is the FINAL injected list
53
+ * (post-rerank, post-topN — exactly what reached the LLM). Returns null when
54
+ * the level is "off" or there is nothing citable.
55
+ */
56
+ export function buildPgvectorProvenance(data, collections, level, injectedChars) {
57
+ if (level === "off" || data.length === 0)
58
+ return null;
59
+ const items = data
60
+ .slice(0, PROVENANCE_MAX_ITEMS)
61
+ .map((r) => {
62
+ const item = { collection: r.collection, score: r.score };
63
+ if (r.file_name)
64
+ item.file_name = r.file_name;
65
+ else if (r.file_id)
66
+ item.id = r.file_id;
67
+ if (level === "full" && r.text) {
68
+ item.text = r.text.slice(0, PROVENANCE_EXCERPT_MAX_CHARS);
69
+ }
70
+ return item;
71
+ });
72
+ return {
73
+ v: 1,
74
+ source: "knowledge",
75
+ kind: "documents",
76
+ injected: { chars: injectedChars, position: "system_append" },
77
+ retrieval: { route: "pgvector", collections },
78
+ items,
79
+ };
80
+ }
81
+ /**
82
+ * Report for an injected LightRAG section. The graph response is one opaque
83
+ * context blob (no per-document structure yet — the docstore initiative will
84
+ * enrich this), so the report carries ONE item describing the injected
85
+ * context; "full" includes its leading excerpt VERBATIM from what was
86
+ * actually injected (the post-truncation text).
87
+ *
88
+ * @param injectedText body of the section actually delivered to the LLM
89
+ * (post-truncation, header EXCLUDED). Used for the
90
+ * `full`-level excerpt.
91
+ * @param mode LightRAG query mode (`mix`, `hybrid`, …).
92
+ * @param level provenance gate (`off` / `metadata` / `full`).
93
+ * @param injectedChars total length of the system-prompt section actually
94
+ * delivered (header INCLUDED). Defaults to
95
+ * `injectedText.length` for callers that don't track
96
+ * the header separately; the plugin's render path
97
+ * passes the full section length so `injected.chars`
98
+ * reflects exactly what reached the LLM
99
+ * (codex pass #36 P3). Negative values fall back to
100
+ * `injectedText.length` to keep the report
101
+ * well-formed even on caller mistakes.
102
+ */
103
+ export function buildLightRAGProvenance(injectedText, mode, level, injectedChars) {
104
+ if (level === "off" || injectedText.length === 0)
105
+ return null;
106
+ const item = { id: "lightrag-context", type: mode };
107
+ if (level === "full") {
108
+ item.text = injectedText.slice(0, PROVENANCE_EXCERPT_MAX_CHARS);
109
+ }
110
+ const reportedChars = typeof injectedChars === "number" && injectedChars >= 0
111
+ ? injectedChars
112
+ : injectedText.length;
113
+ return {
114
+ v: 1,
115
+ source: "knowledge",
116
+ kind: "documents",
117
+ injected: { chars: reportedChars, position: "system_append" },
118
+ retrieval: { route: "lightrag", lightrag: { mode } },
119
+ items: [item],
120
+ };
121
+ }
122
+ /**
123
+ * Map a gateway-supplied `reason` to a stable category code. Matching is
124
+ * substring-based on the lower-cased reason — coarse on purpose so a
125
+ * future gateway wording change does not break the classifier silently.
126
+ * Unknown reasons collapse to `"rejected"` so the field always has a
127
+ * non-empty, content-free value.
128
+ */
129
+ function classifyRejectionReason(reason) {
130
+ if (!reason)
131
+ return "rejected";
132
+ const lower = reason.toLowerCase();
133
+ if (lower.includes("not loaded"))
134
+ return "plugin_not_loaded";
135
+ if (lower.includes("runid") || lower.includes("session")) {
136
+ return "missing_run_context";
137
+ }
138
+ if (lower.includes("stream"))
139
+ return "invalid_stream";
140
+ if (lower.includes("validation") || lower.includes("schema")) {
141
+ return "validation_error";
142
+ }
143
+ if (lower.includes("rate") || lower.includes("limit"))
144
+ return "rate_limited";
145
+ return "rejected";
146
+ }
147
+ /**
148
+ * Emit the turn's reports. Every guard degrades to SILENCE (a missing SDK
149
+ * function, a missing runId, a gateway rejection) — provenance must never
150
+ * break or delay a turn. Failures are logged as a STABLE CATEGORY CODE
151
+ * (never the raw gateway reason or Error message) because a silent
152
+ * `{emitted:false}` is undiagnosable in the field, but echoing the raw
153
+ * reason could leak fragments of the injected payload back into the log
154
+ * stream — violating the module's tracing invariant.
155
+ */
156
+ export function emitProvenanceReports(emit, logger, runId, sessionKey, reports) {
157
+ if (!emit)
158
+ return;
159
+ if (!runId)
160
+ return; // gateway-required; absent on some triggers
161
+ for (const report of reports) {
162
+ if (report === null)
163
+ continue;
164
+ try {
165
+ const res = emit({
166
+ runId,
167
+ ...(sessionKey ? { sessionKey } : {}),
168
+ stream: PROVENANCE_STREAM,
169
+ data: report,
170
+ });
171
+ if (res && res.emitted === false) {
172
+ const code = classifyRejectionReason(res.reason);
173
+ logger.warn(`openclaw-knowledge: provenance report rejected — ${code}`);
174
+ }
175
+ }
176
+ catch (err) {
177
+ // Log only the Error.name (`TypeError`, `RangeError`, ...) — NEVER the
178
+ // `.message`, which third-party libs commonly enrich with input data.
179
+ const name = err && typeof err === "object" && typeof err.name === "string"
180
+ ? err.name
181
+ : "Error";
182
+ logger.warn(`openclaw-knowledge: provenance emit failed — throw:${name}`);
183
+ }
184
+ }
185
+ }
186
+ //# sourceMappingURL=provenance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provenance.js","sourceRoot":"","sources":["../src/provenance.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import type { RpmMonitor } from "../jina/rate-limit.js";
1
2
  import type { RouterDecision } from "./types.js";
2
3
  export interface RouterConfig {
3
4
  /** Master switch. When false, every call returns `{route: "ALL"}`. */
@@ -32,6 +33,20 @@ export interface RouterConfig {
32
33
  * Trusting only confident scores keeps the gate fail-safe.
33
34
  */
34
35
  minConfidence?: number;
36
+ /**
37
+ * Optional callback fired AFTER a successful Jina `/v1/classify` call
38
+ * with payload-level numbers (duration, model). The plugin uses it to
39
+ * emit a `jina` usage event so dashboards can track classify spend
40
+ * per turn independently of the router decision.
41
+ *
42
+ * @since 3.2.4
43
+ */
44
+ onClassifierUsage?: (usage: {
45
+ durationMs: number;
46
+ model: "zero-shot" | "few-shot";
47
+ }) => void;
48
+ /** Optional RPM monitor (forwarded to the Jina client). @since 3.2.4 */
49
+ rpmMonitor?: RpmMonitor;
35
50
  }
36
51
  /**
37
52
  * Default applied by {@link decideRoute} when a caller omits
@@ -66,6 +66,7 @@ export async function decideRoute(cfg, ctx) {
66
66
  return { route: FALLBACK, reason: "classifier_fallback", score: null };
67
67
  }
68
68
  try {
69
+ const startedAt = Date.now();
69
70
  const outcome = cfg.classifierId
70
71
  ? await classifyFewShot({
71
72
  apiKey: cfg.jinaApiKey,
@@ -73,13 +74,21 @@ export async function decideRoute(cfg, ctx) {
73
74
  classifierId: cfg.classifierId,
74
75
  expectedLabels: ROUTER_LABEL_NAMES,
75
76
  signal: ctx.signal,
77
+ rpmMonitor: cfg.rpmMonitor,
76
78
  })
77
79
  : await classifyZeroShot({
78
80
  apiKey: cfg.jinaApiKey,
79
81
  text: ctx.query,
80
82
  labels: (cfg.labels ?? DEFAULT_ROUTER_LABELS),
81
83
  signal: ctx.signal,
84
+ rpmMonitor: cfg.rpmMonitor,
82
85
  });
86
+ if (cfg.onClassifierUsage) {
87
+ cfg.onClassifierUsage({
88
+ durationMs: Date.now() - startedAt,
89
+ model: cfg.classifierId ? "few-shot" : "zero-shot",
90
+ });
91
+ }
83
92
  if (!outcome) {
84
93
  return { route: FALLBACK, reason: "classifier_fallback", score: null };
85
94
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/router/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/router/index.ts"],"names":[],"mappings":"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"}
@@ -78,7 +78,19 @@ export interface CooldownEvent {
78
78
  scope: "global" | "router" | "pgvector_reranker";
79
79
  consecutiveErrors: number;
80
80
  }
81
- export type KnowledgeEvent = RouterEvent | PgvectorEvent | LightRAGEvent | JinaUsageEvent | CooldownEvent;
81
+ /**
82
+ * Emitted (at most once per 60-second window) when the plugin's
83
+ * Jina RPM soft monitor observes the configured budget being exceeded.
84
+ * Pure observability — does not block any call.
85
+ *
86
+ * @since 3.2.4
87
+ */
88
+ export interface JinaRpmExceededEvent {
89
+ type: "jina_rpm_exceeded";
90
+ count: number;
91
+ budget: number;
92
+ }
93
+ export type KnowledgeEvent = RouterEvent | PgvectorEvent | LightRAGEvent | JinaUsageEvent | CooldownEvent | JinaRpmExceededEvent;
82
94
  /**
83
95
  * Emit a structured event line through `logger.info`.
84
96
  *
@@ -1 +1 @@
1
- {"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/tracing/events.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,EAAE;AACF,2EAA2E;AAC3E,yEAAyE;AACzE,yDAAyD;AACzD,EAAE;AACF,wEAAwE;AACxE,+DAA+D;AAC/D,wEAAwE;AACxE,+BAA+B;AAC/B,EAAE;AACF,sEAAsE;AACtE,qEAAqE;AACrE,gEAAgE;AAChE,wEAAwE;AACxE,iCAAiC;AACjC,EAAE;AACF,oEAAoE;AACpE,uEAAuE;AACvE,qEAAqE;AACrE,sEAAsE;AACtE,uEAAuE;AACvE,8DAA8D;AAC9D,EAAE;AACF,2EAA2E;AAC3E,0EAA0E;AAC1E,mBAAmB;AAcnB;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,mBAAmB,CAAC;AAsDhD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,+BAA+B,GAAG,GAAG,CAAC;AAuBnD,8EAA8E;AAC9E,WAAW;AACX,8EAA8E;AAE9E;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CAAC,MAAqB,EAAE,KAAqB;IACpE,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACtC,MAAM,CAAC,IAAI,CAAC,GAAG,YAAY,IAAI,OAAO,EAAE,CAAC,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,4DAA4D;IAC9D,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,gBAAgB,CAC9B,MAAqB,EACrB,KAAyB,EACzB,WAAmB;IAEnB,IAAI,CAAC,MAAM,CAAC,KAAK;QAAE,OAAO;IAC1B,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;QACzD,MAAM,CAAC,KAAK,CAAC,GAAG,YAAY,wBAAwB,EAAE,SAAS,WAAW,EAAE,CAAC,CAAC;IAChF,CAAC;IAAC,MAAM,CAAC;QACP,gDAAgD;IAClD,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/tracing/events.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,EAAE;AACF,2EAA2E;AAC3E,yEAAyE;AACzE,yDAAyD;AACzD,EAAE;AACF,wEAAwE;AACxE,+DAA+D;AAC/D,wEAAwE;AACxE,+BAA+B;AAC/B,EAAE;AACF,sEAAsE;AACtE,qEAAqE;AACrE,gEAAgE;AAChE,wEAAwE;AACxE,iCAAiC;AACjC,EAAE;AACF,oEAAoE;AACpE,uEAAuE;AACvE,qEAAqE;AACrE,sEAAsE;AACtE,uEAAuE;AACvE,8DAA8D;AAC9D,EAAE;AACF,2EAA2E;AAC3E,0EAA0E;AAC1E,mBAAmB;AAcnB;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,mBAAmB,CAAC;AAsDhD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,+BAA+B,GAAG,GAAG,CAAC;AAqCnD,8EAA8E;AAC9E,WAAW;AACX,8EAA8E;AAE9E;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CAAC,MAAqB,EAAE,KAAqB;IACpE,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACtC,MAAM,CAAC,IAAI,CAAC,GAAG,YAAY,IAAI,OAAO,EAAE,CAAC,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,4DAA4D;IAC9D,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,gBAAgB,CAC9B,MAAqB,EACrB,KAAyB,EACzB,WAAmB;IAEnB,IAAI,CAAC,MAAM,CAAC,KAAK;QAAE,OAAO;IAC1B,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;QACzD,MAAM,CAAC,KAAK,CAAC,GAAG,YAAY,wBAAwB,EAAE,SAAS,WAAW,EAAE,CAAC,CAAC;IAChF,CAAC;IAAC,MAAM,CAAC;QACP,gDAAgD;IAClD,CAAC;AACH,CAAC"}
package/dist/types.d.ts CHANGED
@@ -39,12 +39,34 @@ export interface KnowledgePluginConfig {
39
39
  lightragMaxChars?: number;
40
40
  lightragEnabled?: boolean;
41
41
  jina?: JinaPluginConfig;
42
+ /**
43
+ * Provenance reporting toward chat frontends (provenance/v1 — see the
44
+ * openclaw-webchat PROVENANCE_CONTRACT): "off" (default, no emission),
45
+ * "metadata" (file names/collections/scores, no content), "full"
46
+ * (plus the exact injected excerpts).
47
+ *
48
+ * @since 3.3.0
49
+ */
50
+ provenanceReport?: string;
42
51
  }
43
52
  export interface JinaPluginConfig {
44
53
  /** Jina API key. Required for `router.mode=jina-classifier` or `pgvectorReranker.enabled`. Supports `${ENV_VAR}` substitution. */
45
54
  apiKey?: string;
46
55
  router?: RouterPluginConfig;
47
56
  pgvectorReranker?: PgvectorRerankerPluginConfig;
57
+ /**
58
+ * Soft RPM budget for ALL outbound Jina calls (router + reranker
59
+ * combined). When the sliding 60-second window exceeds this number,
60
+ * a `jina_rpm_exceeded` event is emitted (at most once per window)
61
+ * and a warning is logged. **The call is NEVER blocked** — the
62
+ * existing 429 cooldown breaker is the hard backstop.
63
+ *
64
+ * Default: 60. Set well below the Jina free-tier ceiling (100 RPM)
65
+ * to leave headroom for a shared key (e.g. plugin + Hindsight).
66
+ *
67
+ * @since 3.2.4
68
+ */
69
+ rpmBudget?: number;
48
70
  }
49
71
  export interface RouterPluginConfig {
50
72
  enabled?: boolean;
@@ -69,6 +91,25 @@ export interface PgvectorRerankerPluginConfig {
69
91
  model?: RerankerModel;
70
92
  /** Cap on results returned post-rerank. Default: `5`. */
71
93
  topN?: number;
94
+ /**
95
+ * Maximum number of candidate documents submitted to Jina per call.
96
+ * Pgvector recall is typically broad (20-50 hits) but only the top
97
+ * 10-15 are worth reranking. Trimming the tail saves Jina tokens
98
+ * linearly. Default: `20`. Set to `0` to disable the cap.
99
+ *
100
+ * @since 3.2.4
101
+ */
102
+ candidatePoolMax?: number;
103
+ /**
104
+ * Per-candidate text length cap (characters) before submission to
105
+ * Jina. The first ~2000 chars carry most of the relevance signal;
106
+ * longer chunks (transcripts, books) waste tokens on context the
107
+ * cross-encoder gets little additional signal from. Default: `2000`.
108
+ * Set to `0` to disable the truncation.
109
+ *
110
+ * @since 3.2.4
111
+ */
112
+ maxCharsPerDoc?: number;
72
113
  }
73
114
  export type LightRAGQueryMode = "naive" | "local" | "global" | "hybrid";
74
115
  /**
@@ -90,6 +131,13 @@ export interface ResolvedKnowledgeConfig {
90
131
  lightragMaxChars: number;
91
132
  lightragEnabled: boolean;
92
133
  jinaApiKey: string;
134
+ /**
135
+ * Soft RPM budget for ALL outbound Jina calls. Default: 60.
136
+ * `0` disables the monitor entirely.
137
+ *
138
+ * @since 3.2.4
139
+ */
140
+ jinaRpmBudget: number;
93
141
  routerEnabled: boolean;
94
142
  routerMode: "heuristic" | "jina-classifier";
95
143
  routerClassifierId: string;
@@ -102,6 +150,26 @@ export interface ResolvedKnowledgeConfig {
102
150
  pgvectorRerankerEnabled: boolean;
103
151
  pgvectorRerankerModel: RerankerModel;
104
152
  pgvectorRerankerTopN: number;
153
+ /**
154
+ * Cap on the number of candidates submitted to Jina /v1/rerank. `0`
155
+ * disables the cap (legacy v3.2.3 behavior). Default: `20`.
156
+ *
157
+ * @since 3.2.4
158
+ */
159
+ pgvectorRerankerCandidatePoolMax: number;
160
+ /**
161
+ * Per-candidate text truncation length in characters. `0` disables
162
+ * truncation. Default: `2000`.
163
+ *
164
+ * @since 3.2.4
165
+ */
166
+ pgvectorRerankerMaxCharsPerDoc: number;
167
+ /**
168
+ * Provenance reporting level (provenance/v1). Default "off".
169
+ *
170
+ * @since 3.3.0
171
+ */
172
+ provenanceReport: "off" | "metadata" | "full";
105
173
  }
106
174
  /**
107
175
  * One search hit from the PostgreSQL `knowledge_vectors` table, after score