@oka-core/reason 0.2.12 → 0.2.14

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/client.d.ts CHANGED
@@ -115,6 +115,53 @@ export interface SemanticSearchResponse {
115
115
  results: SemanticSearchResult[];
116
116
  total: number;
117
117
  }
118
+ export interface HybridSearchOptions {
119
+ repo?: string;
120
+ limit?: number;
121
+ min_confidence?: number;
122
+ min_similarity?: number;
123
+ rerank?: boolean;
124
+ file_patterns?: string;
125
+ visibility?: "user_repo" | "account_wide" | "user_private";
126
+ mode?: "hybrid" | "bm25_only" | "vector_only";
127
+ }
128
+ export interface HybridResultScores {
129
+ final_score: number;
130
+ bm25_score: number | null;
131
+ vector_similarity: number | null;
132
+ rrf_score: number;
133
+ feature_score: number;
134
+ rerank_score: number | null;
135
+ }
136
+ export interface HybridResultItem {
137
+ id: string;
138
+ summary: string;
139
+ detailed_description?: string;
140
+ tags: string[];
141
+ file_patterns: string[];
142
+ category: string;
143
+ confidence: number;
144
+ evidence_count: number;
145
+ suggested_action?: string;
146
+ status: string;
147
+ scores: HybridResultScores;
148
+ matching_strategies: string[];
149
+ }
150
+ export interface HybridPipelineMeta {
151
+ bm25_candidates: number;
152
+ vector_candidates: number;
153
+ fused_candidates: number;
154
+ after_dedup: number;
155
+ pipeline_stages: string[];
156
+ elapsed_ms: number;
157
+ feedback_id?: string;
158
+ }
159
+ export interface HybridSearchResponse {
160
+ query: string;
161
+ results: HybridResultItem[];
162
+ total_candidates: number;
163
+ pipeline: HybridPipelineMeta;
164
+ }
118
165
  /**
119
166
  * Unified HTTP client for Oka Reason API.
120
167
  *
@@ -136,6 +183,10 @@ export declare class OkaClient {
136
183
  private readonly agentId;
137
184
  private readonly sessionId;
138
185
  private readonly timeout;
186
+ /** Maps learning_id → feedback_id for LTR attribution across tool calls. */
187
+ private readonly searchContext;
188
+ /** Reverse map: short ID prefix → full UUID */
189
+ private readonly idLookup;
139
190
  constructor(config?: OkaClientConfig);
140
191
  updateApiKey(key: string): void;
141
192
  ingest(event: IngestEvent): Promise<void>;
@@ -166,6 +217,26 @@ export declare class OkaClient {
166
217
  * GET /api/learnings/semantic/:query
167
218
  */
168
219
  semanticSearch(query: string, options?: SemanticSearchOptions): Promise<SemanticSearchResponse>;
220
+ /**
221
+ * Hybrid search combining BM25 + vector + RRF fusion.
222
+ * GET /api/learnings/query/:input
223
+ */
224
+ hybridSearch(query: string, options?: HybridSearchOptions): Promise<HybridSearchResponse>;
225
+ /**
226
+ * Submit explicit feedback on a learning (useful/not useful).
227
+ */
228
+ submitFeedback(params: {
229
+ learning_id?: string;
230
+ useful?: boolean;
231
+ reason?: string;
232
+ used_ids?: string[];
233
+ query_feedback_id?: string;
234
+ }): Promise<void>;
235
+ /**
236
+ * Report which learnings were actually used (implicit feedback).
237
+ * Groups by feedback_id from searchContext for correct attribution.
238
+ */
239
+ reportUsedLearnings(usedIds: string[]): void;
169
240
  /**
170
241
  * Trigger a consolidation run.
171
242
  * POST /api/reasoning/consolidate
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/dist/client.js CHANGED
@@ -21,6 +21,10 @@ export class OkaClient {
21
21
  agentId;
22
22
  sessionId;
23
23
  timeout;
24
+ /** Maps learning_id → feedback_id for LTR attribution across tool calls. */
25
+ searchContext = new Map();
26
+ /** Reverse map: short ID prefix → full UUID */
27
+ idLookup = new Map();
24
28
  constructor(config) {
25
29
  this.apiUrl = (config?.apiUrl ||
26
30
  process.env["OKA_API_URL"] ||
@@ -186,6 +190,102 @@ export class OkaClient {
186
190
  params.set("visibility", options.visibility);
187
191
  return this.get(`/api/learnings/semantic/${encodeURIComponent(query)}?${params}`).catch(() => ({ query, results: [], total: 0 }));
188
192
  }
193
+ // ─── Hybrid search (unified pipeline) ───────────────────────────
194
+ /**
195
+ * Hybrid search combining BM25 + vector + RRF fusion.
196
+ * GET /api/learnings/query/:input
197
+ */
198
+ async hybridSearch(query, options) {
199
+ const params = new URLSearchParams();
200
+ // repo scoping: same logic as semanticSearch
201
+ if (options?.repo)
202
+ params.set("repo", options.repo);
203
+ else if (!options?.visibility ||
204
+ options.visibility === "user_repo" ||
205
+ options.visibility === "user_private")
206
+ params.set("repo", this.repo);
207
+ if (options?.limit)
208
+ params.set("limit", String(options.limit));
209
+ if (options?.min_confidence)
210
+ params.set("min_confidence", String(options.min_confidence));
211
+ if (options?.min_similarity)
212
+ params.set("min_similarity", String(options.min_similarity));
213
+ if (options?.file_patterns)
214
+ params.set("file_patterns", options.file_patterns);
215
+ if (options?.visibility)
216
+ params.set("visibility", options.visibility);
217
+ if (options?.rerank)
218
+ params.set("rerank", "true");
219
+ if (options?.mode)
220
+ params.set("mode", options.mode);
221
+ const data = await this.get(`/api/learnings/query/${encodeURIComponent(query)}?${params}`).catch(() => ({
222
+ query,
223
+ results: [],
224
+ total_candidates: 0,
225
+ pipeline: {
226
+ bm25_candidates: 0,
227
+ vector_candidates: 0,
228
+ fused_candidates: 0,
229
+ after_dedup: 0,
230
+ pipeline_stages: [],
231
+ elapsed_ms: 0,
232
+ },
233
+ }));
234
+ // Track learning → feedback_id for LTR attribution.
235
+ // Index by both full UUID and 8-char prefix (agents see short IDs).
236
+ if (data.pipeline.feedback_id) {
237
+ const fbId = data.pipeline.feedback_id;
238
+ this.idLookup.set(fbId.slice(0, 8), fbId);
239
+ for (const r of data.results) {
240
+ this.searchContext.set(r.id, fbId);
241
+ this.searchContext.set(r.id.slice(0, 8), fbId);
242
+ this.idLookup.set(r.id.slice(0, 8), r.id);
243
+ }
244
+ }
245
+ return data;
246
+ }
247
+ // ─── Feedback (LTR training data) ────────────────────────────────
248
+ /**
249
+ * Submit explicit feedback on a learning (useful/not useful).
250
+ */
251
+ async submitFeedback(params) {
252
+ // Resolve short 8-char IDs to full UUIDs for the API
253
+ const resolved = {
254
+ ...params,
255
+ learning_id: params.learning_id
256
+ ? (this.idLookup.get(params.learning_id) ?? params.learning_id)
257
+ : undefined,
258
+ query_feedback_id: params.query_feedback_id
259
+ ? (this.idLookup.get(params.query_feedback_id) ??
260
+ params.query_feedback_id)
261
+ : undefined,
262
+ };
263
+ await this.post("/api/reasoning/feedback", resolved).catch(() => { });
264
+ }
265
+ /**
266
+ * Report which learnings were actually used (implicit feedback).
267
+ * Groups by feedback_id from searchContext for correct attribution.
268
+ */
269
+ reportUsedLearnings(usedIds) {
270
+ // Group used IDs by their feedback_id, resolving short IDs to full UUIDs
271
+ const byFeedback = new Map();
272
+ for (const id of usedIds) {
273
+ const fullId = this.idLookup.get(id) ?? id;
274
+ const fbId = this.searchContext.get(id) ?? this.searchContext.get(fullId);
275
+ if (fbId) {
276
+ const list = byFeedback.get(fbId) ?? [];
277
+ list.push(fullId);
278
+ byFeedback.set(fbId, list);
279
+ }
280
+ }
281
+ // Fire-and-forget one request per feedback_id
282
+ for (const [feedbackId, ids] of byFeedback) {
283
+ this.submitFeedback({
284
+ query_feedback_id: feedbackId,
285
+ used_ids: ids,
286
+ }).catch(() => { });
287
+ }
288
+ }
189
289
  // ─── Consolidation ──────────────────────────────────────────────
190
290
  /**
191
291
  * Trigger a consolidation run.
@@ -1 +1 @@
1
- {"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../src/tools/read.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EACV,SAAS,EAGV,MAAM,cAAc,CAAC;AAoEtB;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,GAAG,IAAI,CAwmB5E"}
1
+ {"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../src/tools/read.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EACV,SAAS,EAKV,MAAM,cAAc,CAAC;AAiItB;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,GAAG,IAAI,CAopB5E"}
@@ -42,6 +42,52 @@ function formatContextLearnings(topic, learnings, totalMatched) {
42
42
  }
43
43
  return lines.join("\n");
44
44
  }
45
+ function formatHybridResults(query, results, totalCandidates, pipeline) {
46
+ if (results.length === 0) {
47
+ return `No knowledge found for query "${query}".`;
48
+ }
49
+ const lines = [
50
+ `## Knowledge: ${query}`,
51
+ ``,
52
+ `> ${totalCandidates} candidate(s), showing top ${results.length} | Pipeline: ${pipeline.pipeline_stages.join(" → ")} (${pipeline.elapsed_ms}ms)${pipeline.feedback_id ? ` | ref: ${pipeline.feedback_id.slice(0, 8)}` : ""}`,
53
+ ``,
54
+ ];
55
+ for (const r of results) {
56
+ const finalPct = (r.scores.final_score * 100).toFixed(0);
57
+ const confPct = (r.confidence * 100).toFixed(0);
58
+ lines.push(`### ${r.summary}`);
59
+ const scoreParts = [
60
+ `**Score:** ${finalPct}%`,
61
+ `**Confidence:** ${confPct}%`,
62
+ ];
63
+ if (r.scores.bm25_score != null)
64
+ scoreParts.push(`BM25: ${r.scores.bm25_score.toFixed(2)}`);
65
+ if (r.scores.vector_similarity != null)
66
+ scoreParts.push(`Vector: ${(r.scores.vector_similarity * 100).toFixed(0)}%`);
67
+ if (r.scores.rerank_score != null)
68
+ scoreParts.push(`Rerank: ${(r.scores.rerank_score * 100).toFixed(0)}%`);
69
+ scoreParts.push(`**Category:** ${r.category}`);
70
+ lines.push(scoreParts.join(" | "));
71
+ if (r.evidence_count > 1) {
72
+ lines.push(`**Evidence:** ${r.evidence_count} source(s)`);
73
+ }
74
+ if (r.detailed_description) {
75
+ lines.push(`\n${r.detailed_description}`);
76
+ }
77
+ if (r.suggested_action) {
78
+ lines.push(`\n**Suggested action:** ${r.suggested_action}`);
79
+ }
80
+ if (r.file_patterns?.length > 0) {
81
+ lines.push(`**Related files:** ${r.file_patterns.join(", ")}`);
82
+ }
83
+ if (r.tags?.length > 0) {
84
+ lines.push(`**Tags:** ${r.tags.join(", ")}`);
85
+ }
86
+ lines.push(`*ID: ${r.id.slice(0, 8)} | Matched by: ${r.matching_strategies.join(" + ")}*`);
87
+ lines.push("");
88
+ }
89
+ return lines.join("\n");
90
+ }
45
91
  // ─── Tool registration ─────────────────────────────────────────────
46
92
  /**
47
93
  * Register read tools on the MCP server.
@@ -82,7 +128,18 @@ export function registerReadTools(server, client) {
82
128
  .describe("Visibility scope: user_repo (default), account_wide (cross-repo), user_private"),
83
129
  }, async (params) => {
84
130
  try {
85
- // Try the new context endpoint first
131
+ // 1. Try hybrid search first (BM25 + vector + RRF)
132
+ const hybridResult = await client.hybridSearch(params.topic, {
133
+ file_patterns: params.file_patterns,
134
+ limit: params.limit,
135
+ min_confidence: params.min_confidence,
136
+ visibility: params.visibility,
137
+ });
138
+ if (hybridResult.results.length > 0) {
139
+ const text = formatHybridResults(params.topic, hybridResult.results, hybridResult.total_candidates, hybridResult.pipeline);
140
+ return { content: [{ type: "text", text }] };
141
+ }
142
+ // 2. Fall back to legacy context endpoint
86
143
  const contextResult = await client.getContext(params.topic, {
87
144
  file_patterns: params.file_patterns,
88
145
  limit: params.limit,
@@ -93,7 +150,7 @@ export function registerReadTools(server, client) {
93
150
  const text = formatContextLearnings(params.topic, contextResult.learnings, contextResult.total_matched);
94
151
  return { content: [{ type: "text", text }] };
95
152
  }
96
- // Fall back to raw event query if no learnings exist
153
+ // 3. Fall back to raw event query
97
154
  const rawResult = await client.query({
98
155
  area: params.topic,
99
156
  });
@@ -470,6 +527,25 @@ export function registerReadTools(server, client) {
470
527
  "user_private (personal learnings only)"),
471
528
  }, async (params) => {
472
529
  try {
530
+ // Try hybrid search first (BM25 + vector + RRF fusion)
531
+ const hybridResult = await client
532
+ .hybridSearch(params.query, {
533
+ limit: params.limit,
534
+ min_similarity: params.min_similarity,
535
+ visibility: params.visibility,
536
+ })
537
+ .catch(() => null);
538
+ if (hybridResult && hybridResult.results.length > 0) {
539
+ return {
540
+ content: [
541
+ {
542
+ type: "text",
543
+ text: formatHybridResults(params.query, hybridResult.results, hybridResult.total_candidates, hybridResult.pipeline),
544
+ },
545
+ ],
546
+ };
547
+ }
548
+ // Fall back to legacy semantic search
473
549
  const result = await client.semanticSearch(params.query, {
474
550
  limit: params.limit,
475
551
  min_similarity: params.min_similarity,
@@ -1 +1 @@
1
- {"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../src/tools/write.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,GAAG,IAAI,CAoK7E"}
1
+ {"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../src/tools/write.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,GAAG,IAAI,CAqN7E"}
@@ -61,7 +61,8 @@ export function registerWriteTools(server, client) {
61
61
  ],
62
62
  };
63
63
  });
64
- server.tool("done", "Record task completion with outcome and quality signals", {
64
+ server.tool("done", "Record task completion with outcome and quality signals. " +
65
+ "If you used Oka learnings during the task, include their IDs in used_learning_ids.", {
65
66
  task_id: z.string().describe("Identifier for the completed task"),
66
67
  outcome: z
67
68
  .enum(["success", "partial", "failed"])
@@ -74,8 +75,20 @@ export function registerWriteTools(server, client) {
74
75
  .record(z.string(), z.number())
75
76
  .default({})
76
77
  .describe("Quality metrics (e.g., test_coverage: 0.92)"),
78
+ used_learning_ids: z
79
+ .array(z.string())
80
+ .optional()
81
+ .describe("IDs of Oka learnings used during the task"),
77
82
  }, async (params) => {
78
- await client.ingest({ event_type: "completion", payload: params });
83
+ const { used_learning_ids, ...completionPayload } = params;
84
+ await client.ingest({
85
+ event_type: "completion",
86
+ payload: completionPayload,
87
+ });
88
+ // Report implicit feedback for LTR training
89
+ if (used_learning_ids?.length) {
90
+ client.reportUsedLearnings(used_learning_ids);
91
+ }
79
92
  return {
80
93
  content: [
81
94
  {
@@ -137,4 +150,33 @@ export function registerWriteTools(server, client) {
137
150
  ],
138
151
  };
139
152
  });
153
+ // ─── feedback (LTR training signal) ──────────────────────────────
154
+ server.tool("feedback", "Report whether a learning from Oka was useful or not. " +
155
+ "Improves future search quality. Call after using context or semantic_search.", {
156
+ learning_id: z.string().describe("Learning ID from search results"),
157
+ useful: z.boolean().describe("Was this learning useful?"),
158
+ query_feedback_id: z
159
+ .string()
160
+ .optional()
161
+ .describe("The ref ID from the search that returned this learning"),
162
+ reason: z
163
+ .enum(["helpful", "outdated", "wrong", "irrelevant"])
164
+ .optional()
165
+ .describe("Why the learning was or wasn't useful"),
166
+ }, async (params) => {
167
+ await client.submitFeedback({
168
+ learning_id: params.learning_id,
169
+ useful: params.useful,
170
+ query_feedback_id: params.query_feedback_id,
171
+ reason: params.reason,
172
+ });
173
+ return {
174
+ content: [
175
+ {
176
+ type: "text",
177
+ text: `Feedback recorded: ${params.learning_id.slice(0, 8)} → ${params.useful ? "useful" : "not useful"}`,
178
+ },
179
+ ],
180
+ };
181
+ });
140
182
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oka-core/reason",
3
- "version": "0.2.12",
3
+ "version": "0.2.14",
4
4
  "description": "MCP server for institutional knowledge capture, semantic search, and consolidation",
5
5
  "private": false,
6
6
  "publishConfig": {