@zenera/rag 1.1.40 → 1.1.41

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.
@@ -1,5 +1,7 @@
1
1
  import { type AnyTool } from '@zenera/neo';
2
+ import type { ApiGraph } from './graph.ts';
2
3
  import { type Format } from './present.ts';
4
+ import type { Schema } from './schema.ts';
3
5
  import type { SchemaIndex } from './search.ts';
4
6
  export interface SchemaToolOptions {
5
7
  /** what `format` defaults to when the model does not say */
@@ -8,5 +10,23 @@ export interface SchemaToolOptions {
8
10
  /** name the document each answer came from; on by default past one document */
9
11
  source?: boolean;
10
12
  }
13
+ /**
14
+ * An API graph without an index around it: what every tool but `search_api`
15
+ * needs. A caller that built the graph itself — from the documents, in memory —
16
+ * gets the exact tools without paying for vectors it would never search.
17
+ */
18
+ export interface GraphSource {
19
+ graph: ApiGraph;
20
+ /** the documents' names, as each node's `source` says them */
21
+ sources: readonly string[];
22
+ /** the raw schemas by type id, for TypeScript declarations */
23
+ schemas(): Promise<Readonly<Record<string, Schema>>>;
24
+ }
11
25
  export declare function schemaTools<TCtx = unknown>(index: SchemaIndex, options?: SchemaToolOptions): AnyTool<TCtx>[];
26
+ /**
27
+ * The five exact tools — no ranking, no embedder — over a graph alone:
28
+ * `describe_types`, `find_types_with_property`, `list_api`, `grep_api` and
29
+ * `trace_api`. `schemaTools` is these plus `search_api`.
30
+ */
31
+ export declare function graphTools<TCtx = unknown>(api: GraphSource, options?: SchemaToolOptions): AnyTool<TCtx>[];
12
32
  //# sourceMappingURL=tools.d.ts.map
@@ -148,6 +148,19 @@ export function schemaTools(index, options = {}) {
148
148
  };
149
149
  },
150
150
  });
151
+ return [
152
+ searchApi,
153
+ ...graphTools({ graph: index.graph, sources: names, schemas: () => index.schemas() }, options),
154
+ ];
155
+ }
156
+ /**
157
+ * The five exact tools — no ranking, no embedder — over a graph alone:
158
+ * `describe_types`, `find_types_with_property`, `list_api`, `grep_api` and
159
+ * `trace_api`. `schemaTools` is these plus `search_api`.
160
+ */
161
+ export function graphTools(api, options = {}) {
162
+ const docs = options.docs ?? true;
163
+ const source = options.source ?? api.sources.length > 1;
151
164
  const describeTypes = tool({
152
165
  name: 'describe_types',
153
166
  group: GROUP,
@@ -164,7 +177,7 @@ export function schemaTools(index, options = {}) {
164
177
  additionalProperties: false,
165
178
  },
166
179
  execute: async ({ names, only }) => {
167
- const known = names.filter((name) => index.graph.hasNode(`Type:${name}`));
180
+ const known = names.filter((name) => api.graph.hasNode(`Type:${name}`));
168
181
  const missing = names.filter((name) => !known.includes(name));
169
182
  if (known.length === 0) {
170
183
  return {
@@ -172,8 +185,8 @@ export function schemaTools(index, options = {}) {
172
185
  hint: 'search for it first',
173
186
  };
174
187
  }
175
- const schemas = await index.schemas();
176
- const sub = subgraphOf(index, known.map((name) => `Type:${name}`));
188
+ const schemas = await api.schemas();
189
+ const sub = subgraphOf(api.graph, known.map((name) => `Type:${name}`));
177
190
  const code = toTypeScript(sub, schemas, { docs, onlyHits: false });
178
191
  return {
179
192
  typescript: only?.length ? narrow(code, only) : code,
@@ -203,11 +216,11 @@ export function schemaTools(index, options = {}) {
203
216
  execute: async ({ property, direction }) => {
204
217
  const wanted = property.toLowerCase();
205
218
  const candidates = [];
206
- index.graph.forEachNode((id, a) => {
219
+ api.graph.forEachNode((id, a) => {
207
220
  if (a.kind !== 'property' || a.name.toLowerCase() !== wanted || !a.parent) {
208
221
  return;
209
222
  }
210
- const owner = index.graph.getNodeAttributes(`Type:${a.parent}`) ?? a;
223
+ const owner = api.graph.getNodeAttributes(`Type:${a.parent}`) ?? a;
211
224
  if (direction && direction !== 'any' && !onSide(owner.direction, direction)) {
212
225
  return;
213
226
  }
@@ -278,7 +291,7 @@ export function schemaTools(index, options = {}) {
278
291
  }
279
292
  let result;
280
293
  try {
281
- result = listNodes(index.graph, {
294
+ result = listNodes(api.graph, {
282
295
  kind: subject,
283
296
  name: name ? [loose(name, { regex })] : undefined,
284
297
  path: path ? [loose(path, { regex })] : undefined,
@@ -294,7 +307,7 @@ export function schemaTools(index, options = {}) {
294
307
  return {
295
308
  found: result.found,
296
309
  truncated: result.truncated,
297
- [PLURALS[subject]]: result.rows.map((r) => line(index.graph, subject, r, source)),
310
+ [PLURALS[subject]]: result.rows.map((r) => line(api.graph, subject, r, source)),
298
311
  };
299
312
  },
300
313
  });
@@ -342,7 +355,7 @@ export function schemaTools(index, options = {}) {
342
355
  execute: async ({ pattern, regex, kind, name, path, source: only, limit }) => {
343
356
  let result;
344
357
  try {
345
- result = grepNodes(index.graph, matcher(pattern, { regex }), {
358
+ result = grepNodes(api.graph, matcher(pattern, { regex }), {
346
359
  kinds: kind ? [kind] : undefined,
347
360
  name: name ? [loose(name)] : undefined,
348
361
  path: path ? [loose(path)] : undefined,
@@ -417,10 +430,10 @@ export function schemaTools(index, options = {}) {
417
430
  execute: async ({ of: wanted, kind, direction, source: only, limit, routes }) => {
418
431
  let result;
419
432
  try {
420
- result = traceNodes(index.graph, {
421
- ids: index.graph.hasNode(wanted) ? [wanted] : undefined,
433
+ result = traceNodes(api.graph, {
434
+ ids: api.graph.hasNode(wanted) ? [wanted] : undefined,
422
435
  kinds: kind ? [kind] : undefined,
423
- name: index.graph.hasNode(wanted) ? undefined : [loose(wanted)],
436
+ name: api.graph.hasNode(wanted) ? undefined : [loose(wanted)],
424
437
  source: only,
425
438
  limit: Math.min(limit ?? DEFAULT_TRACES, MAX_TRACES),
426
439
  maxRoutes: Math.min(routes ?? DEFAULT_ROUTES, MAX_ROWS),
@@ -445,12 +458,12 @@ export function schemaTools(index, options = {}) {
445
458
  operations: t.routes
446
459
  .filter((r) => !side || r.direction === side || r.direction === 'both')
447
460
  .map((r) => `${r.attributes.httpMethod} ${r.attributes.path} ` +
448
- `${r.attributes.name} (${r.direction})${source ? ` ${sourceTag(r.attributes.source)}` : ''} ${chainOf(index.graph, t.id, r)}`),
461
+ `${r.attributes.name} (${r.direction})${source ? ` ${sourceTag(r.attributes.source)}` : ''} ${chainOf(api.graph, t.id, r)}`),
449
462
  })),
450
463
  };
451
464
  },
452
465
  });
453
- return [searchApi, describeTypes, findTypesWithProperty, listApi, grepApi, traceApi];
466
+ return [describeTypes, findTypesWithProperty, listApi, grepApi, traceApi];
454
467
  }
455
468
  // ---------------------------------------------------------------------------
456
469
  const SUBJECTS = {
@@ -487,8 +500,8 @@ function chosen(format, fallback) {
487
500
  function onSide(direction, wanted) {
488
501
  return direction === wanted || direction === 'both';
489
502
  }
490
- function subgraphOf(index, ids) {
491
- const [first] = stitch(index.graph, ids.map((id) => ({ id, term: id, field: 'describe', score: 1 })), { maxNodes: DEFAULT_MAX_NODES * ids.length });
503
+ function subgraphOf(graph, ids) {
504
+ const [first] = stitch(graph, ids.map((id) => ({ id, term: id, field: 'describe', score: 1 })), { maxNodes: DEFAULT_MAX_NODES * ids.length });
492
505
  return first ?? { nodes: [], edges: [], hits: [], score: 0, truncated: false };
493
506
  }
494
507
  /** Keeps the declarations, drops the field lines nobody asked about. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zenera/rag",
3
- "version": "1.1.40",
3
+ "version": "1.1.41",
4
4
  "description": "Retrieval over a corpus: openapi/swagger documents as a searchable graph, markdown and text as searchable passages.",
5
5
  "keywords": [
6
6
  "agents",
@@ -61,8 +61,8 @@
61
61
  "dependencies": {
62
62
  "@apidevtools/swagger-parser": "^12.0.0",
63
63
  "@lancedb/lancedb": "^0.38.0",
64
- "@zenera/cli": "^1.1.40",
65
- "@zenera/neo": "^1.1.40",
64
+ "@zenera/cli": "^1.1.41",
65
+ "@zenera/neo": "^1.1.41",
66
66
  "graphology": "^0.26.0",
67
67
  "remark-frontmatter": "^5.0.0",
68
68
  "remark-gfm": "^4.0.1",