@gmickel/gno 1.18.0 → 1.20.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.
Files changed (153) hide show
  1. package/README.md +14 -7
  2. package/assets/skill/SKILL.md +54 -12
  3. package/assets/skill/mcp-reference.md +7 -2
  4. package/assets/skill/recipes/citation-and-provenance.md +32 -9
  5. package/package.json +2 -1
  6. package/spec/AGENTS.md +83 -0
  7. package/spec/CLAUDE.md +83 -0
  8. package/spec/bench-fixture.schema.json +137 -0
  9. package/spec/cli.md +2919 -0
  10. package/spec/db/schema.sql +442 -0
  11. package/spec/evals-agentic.md +592 -0
  12. package/spec/evals.md +1106 -0
  13. package/spec/mcp.md +2279 -0
  14. package/spec/output-schemas/activation-verification.schema.json +515 -0
  15. package/spec/output-schemas/ask.schema.json +564 -0
  16. package/spec/output-schemas/backlinks.schema.json +131 -0
  17. package/spec/output-schemas/bench-result.schema.json +120 -0
  18. package/spec/output-schemas/capture-receipt.schema.json +143 -0
  19. package/spec/output-schemas/claim-verification.schema.json +291 -0
  20. package/spec/output-schemas/collection-list.schema.json +45 -0
  21. package/spec/output-schemas/context-capsule-v1.schema.json +726 -0
  22. package/spec/output-schemas/context-capsule-verification.schema.json +1338 -0
  23. package/spec/output-schemas/context-list.schema.json +21 -0
  24. package/spec/output-schemas/doctor.schema.json +313 -0
  25. package/spec/output-schemas/error.schema.json +30 -0
  26. package/spec/output-schemas/expansion.schema.json +37 -0
  27. package/spec/output-schemas/get.schema.json +140 -0
  28. package/spec/output-schemas/graph-query.schema.json +99 -0
  29. package/spec/output-schemas/graph.schema.json +371 -0
  30. package/spec/output-schemas/links-list.schema.json +186 -0
  31. package/spec/output-schemas/mcp-add-collection-result.schema.json +23 -0
  32. package/spec/output-schemas/mcp-capture-result.schema.json +152 -0
  33. package/spec/output-schemas/mcp-http-error.schema.json +30 -0
  34. package/spec/output-schemas/mcp-job-list.schema.json +58 -0
  35. package/spec/output-schemas/mcp-job-status.schema.json +224 -0
  36. package/spec/output-schemas/mcp-remove-result.schema.json +39 -0
  37. package/spec/output-schemas/mcp-sync-result.schema.json +41 -0
  38. package/spec/output-schemas/mcp-tag-result.schema.json +33 -0
  39. package/spec/output-schemas/models-list.schema.json +93 -0
  40. package/spec/output-schemas/multi-get.schema.json +103 -0
  41. package/spec/output-schemas/process-status.schema.json +119 -0
  42. package/spec/output-schemas/query-diagnose.schema.json +123 -0
  43. package/spec/output-schemas/resident-status.schema.json +154 -0
  44. package/spec/output-schemas/retrieval-trace-common.schema.json +492 -0
  45. package/spec/output-schemas/retrieval-trace-delete.schema.json +16 -0
  46. package/spec/output-schemas/retrieval-trace-export.schema.json +61 -0
  47. package/spec/output-schemas/retrieval-trace-filters.schema.json +139 -0
  48. package/spec/output-schemas/retrieval-trace-judgment.schema.json +15 -0
  49. package/spec/output-schemas/retrieval-trace-list.schema.json +18 -0
  50. package/spec/output-schemas/retrieval-trace-payloads.schema.json +178 -0
  51. package/spec/output-schemas/retrieval-trace-purge.schema.json +31 -0
  52. package/spec/output-schemas/retrieval-trace-qrels.schema.json +303 -0
  53. package/spec/output-schemas/retrieval-trace-replay.schema.json +286 -0
  54. package/spec/output-schemas/retrieval-trace-show.schema.json +69 -0
  55. package/spec/output-schemas/retrieval-trace-summary.schema.json +65 -0
  56. package/spec/output-schemas/search-result.schema.json +154 -0
  57. package/spec/output-schemas/search-results.schema.json +338 -0
  58. package/spec/output-schemas/similar.schema.json +84 -0
  59. package/spec/output-schemas/status.schema.json +676 -0
  60. package/spec/output-schemas/tags-list.schema.json +48 -0
  61. package/src/app/context-runtime-contract.ts +10 -5
  62. package/src/app/context-runtime-input.ts +29 -1
  63. package/src/app/context-runtime-types.ts +7 -0
  64. package/src/app/context-runtime.ts +20 -2
  65. package/src/app/context-surface.ts +4 -0
  66. package/src/app/verified-ask.ts +291 -0
  67. package/src/cli/commands/ask-format.ts +255 -0
  68. package/src/cli/commands/ask.ts +144 -183
  69. package/src/cli/commands/context-build.ts +56 -9
  70. package/src/cli/commands/get.ts +64 -3
  71. package/src/cli/commands/query.ts +62 -23
  72. package/src/cli/commands/replay.ts +140 -0
  73. package/src/cli/commands/search.ts +48 -3
  74. package/src/cli/commands/shared.ts +3 -1
  75. package/src/cli/commands/trace.ts +200 -0
  76. package/src/cli/commands/vsearch.ts +75 -53
  77. package/src/cli/program.ts +287 -1
  78. package/src/config/index.ts +9 -0
  79. package/src/config/retrieval-traces.ts +56 -0
  80. package/src/config/types.ts +4 -0
  81. package/src/core/context-budget.ts +6 -0
  82. package/src/core/context-capsule-retrieval-schema.ts +4 -0
  83. package/src/core/context-capsule-schema.ts +17 -0
  84. package/src/core/context-capsule-validation.ts +3 -2
  85. package/src/core/context-capsule.ts +18 -0
  86. package/src/core/context-compiler.ts +44 -25
  87. package/src/core/context-evidence.ts +6 -0
  88. package/src/core/retrieval-qrels.ts +405 -0
  89. package/src/core/retrieval-replay-candidate.ts +368 -0
  90. package/src/core/retrieval-replay-types.ts +109 -0
  91. package/src/core/retrieval-replay-validation.ts +89 -0
  92. package/src/core/retrieval-replay.ts +441 -0
  93. package/src/core/retrieval-trace-evidence-origin.ts +178 -0
  94. package/src/core/retrieval-trace-export.ts +113 -0
  95. package/src/core/retrieval-trace-filter-normalization.ts +27 -0
  96. package/src/core/retrieval-trace-filters.ts +19 -0
  97. package/src/core/retrieval-trace-management-helpers.ts +247 -0
  98. package/src/core/retrieval-trace-management-types.ts +132 -0
  99. package/src/core/retrieval-trace-management.ts +422 -0
  100. package/src/core/retrieval-trace-request.ts +141 -0
  101. package/src/core/retrieval-trace-session.ts +507 -0
  102. package/src/core/retrieval-trace.ts +472 -0
  103. package/src/llm/errors.ts +10 -1
  104. package/src/llm/httpGeneration.ts +11 -1
  105. package/src/llm/nodeLlamaCpp/generation.ts +54 -10
  106. package/src/llm/types.ts +6 -0
  107. package/src/mcp/tools/ask.ts +228 -0
  108. package/src/mcp/tools/context.ts +87 -15
  109. package/src/mcp/tools/get.ts +35 -1
  110. package/src/mcp/tools/index.ts +83 -0
  111. package/src/mcp/tools/query.ts +95 -64
  112. package/src/mcp/tools/search.ts +36 -13
  113. package/src/mcp/tools/trace.ts +143 -0
  114. package/src/mcp/tools/vsearch.ts +71 -38
  115. package/src/pipeline/answer.ts +167 -26
  116. package/src/pipeline/claim-verification-schema.ts +235 -0
  117. package/src/pipeline/claim-verification.ts +487 -0
  118. package/src/pipeline/claim-verifier.ts +474 -0
  119. package/src/pipeline/graph-retrieval.ts +15 -1
  120. package/src/pipeline/hybrid.ts +151 -43
  121. package/src/pipeline/search.ts +36 -3
  122. package/src/pipeline/trace-metadata.ts +47 -0
  123. package/src/pipeline/types.ts +68 -0
  124. package/src/pipeline/vsearch.ts +101 -38
  125. package/src/sdk/client.ts +415 -73
  126. package/src/sdk/documents.ts +48 -1
  127. package/src/sdk/index.ts +17 -0
  128. package/src/sdk/types.ts +28 -0
  129. package/src/serve/context-capsule.ts +67 -8
  130. package/src/serve/public/app.tsx +12 -1
  131. package/src/serve/public/components/AskVerificationPanel.tsx +189 -0
  132. package/src/serve/public/globals.built.css +1 -1
  133. package/src/serve/public/lib/workspace-tabs.ts +2 -0
  134. package/src/serve/public/pages/Ask.tsx +42 -4
  135. package/src/serve/public/pages/Dashboard.tsx +10 -0
  136. package/src/serve/public/pages/TraceHistory.tsx +478 -0
  137. package/src/serve/public/pages/trace-history-detail.tsx +224 -0
  138. package/src/serve/retrieval-trace.ts +28 -0
  139. package/src/serve/routes/api.ts +508 -68
  140. package/src/serve/routes/traces.ts +156 -0
  141. package/src/serve/server.ts +87 -2
  142. package/src/store/index.ts +31 -0
  143. package/src/store/migrations/014-retrieval-traces.ts +303 -0
  144. package/src/store/migrations/index.ts +2 -0
  145. package/src/store/retrieval-trace-codec.ts +384 -0
  146. package/src/store/sqlite/adapter.ts +153 -1
  147. package/src/store/sqlite/retrieval-trace-management-store.ts +341 -0
  148. package/src/store/sqlite/retrieval-trace-retention.ts +349 -0
  149. package/src/store/sqlite/retrieval-trace-rows.ts +267 -0
  150. package/src/store/sqlite/retrieval-trace-store.ts +515 -0
  151. package/src/store/types.ts +297 -0
  152. package/src/store/vector/sqlite-vec.ts +76 -1
  153. package/src/store/vector/types.ts +1 -1
package/src/sdk/client.ts CHANGED
@@ -57,6 +57,7 @@ import {
57
57
  INDEX_NAME_REQUIREMENTS,
58
58
  isValidIndexName,
59
59
  } from "../app/index-name";
60
+ import { buildVerifiedAsk } from "../app/verified-ask";
60
61
  import {
61
62
  ConfigSchema,
62
63
  loadConfig,
@@ -85,6 +86,18 @@ import {
85
86
  import { resolveEffectiveIndex } from "../core/indexed-reference";
86
87
  import { resolveNoteCreatePlan } from "../core/note-creation";
87
88
  import { resolveNotePreset } from "../core/note-presets";
89
+ import { RetrievalTraceManagementService } from "../core/retrieval-trace-management";
90
+ import {
91
+ finishRetrievalTraceAfterError,
92
+ retrievalTraceFilters,
93
+ startRetrievalTraceRequest,
94
+ } from "../core/retrieval-trace-request";
95
+ import {
96
+ attachRetrievalTraceMetadata,
97
+ getRetrievalTraceMetadata,
98
+ RETRIEVAL_TRACE_METADATA,
99
+ type RetrievalTraceSession,
100
+ } from "../core/retrieval-trace-session";
88
101
  import { extractSections } from "../core/sections";
89
102
  import { normalizeStructuredQueryInput } from "../core/structured-query";
90
103
  import { parseAndValidateTagFilter } from "../core/tags";
@@ -98,8 +111,9 @@ import { LlmAdapter } from "../llm/nodeLlamaCpp/adapter";
98
111
  import { resolveDownloadPolicy } from "../llm/policy";
99
112
  import { resolveModelUri } from "../llm/registry";
100
113
  import {
114
+ answerTraceTerminalStatus,
101
115
  generateGroundedAnswer,
102
- processAnswerResult,
116
+ processAnswerResultWithTrace,
103
117
  } from "../pipeline/answer";
104
118
  import { formatQueryForEmbedding } from "../pipeline/contextual";
105
119
  import { searchHybrid } from "../pipeline/hybrid";
@@ -145,6 +159,21 @@ function unwrapStore<T>(
145
159
  return result.value;
146
160
  }
147
161
 
162
+ function unwrapTraceStore<T>(result: StoreResult<T>): T {
163
+ if (result.ok) return result.value;
164
+ const code =
165
+ result.error.code === "NOT_FOUND"
166
+ ? "NOT_FOUND"
167
+ : result.error.code === "INVALID_INPUT" ||
168
+ result.error.code === "CONSTRAINT_VIOLATION"
169
+ ? "VALIDATION"
170
+ : "STORE";
171
+ throw sdkError(code, result.error.message, {
172
+ cause: result.error.cause,
173
+ details: { traceCode: result.error.code },
174
+ });
175
+ }
176
+
148
177
  async function resolveClientState(
149
178
  options: GnoClientInitOptions = {}
150
179
  ): Promise<OpenedClientState> {
@@ -429,9 +458,33 @@ class GnoClientImpl implements GnoClient {
429
458
  options: import("../pipeline/types").SearchOptions = {}
430
459
  ): Promise<SearchResults> {
431
460
  this.assertOpen();
432
- return this.decorateSearchResults(
433
- unwrapStore(await searchBm25(this.store, query, options))
434
- );
461
+ let traceSession: RetrievalTraceSession | null = null;
462
+ try {
463
+ traceSession = unwrapStore(
464
+ await startRetrievalTraceRequest({
465
+ store: this.store,
466
+ config: this.config,
467
+ query,
468
+ filters: retrievalTraceFilters(options),
469
+ pipeline: "bm25",
470
+ indexName: this.indexName,
471
+ })
472
+ );
473
+ return attachRetrievalTraceMetadata(
474
+ this.decorateSearchResults(
475
+ unwrapStore(
476
+ await searchBm25(this.store, query, {
477
+ ...options,
478
+ traceSession: traceSession ?? undefined,
479
+ })
480
+ )
481
+ ),
482
+ traceSession ?? undefined
483
+ );
484
+ } catch (cause) {
485
+ await finishRetrievalTraceAfterError(traceSession, cause);
486
+ throw cause;
487
+ }
435
488
  }
436
489
 
437
490
  async vsearch(
@@ -440,14 +493,33 @@ class GnoClientImpl implements GnoClient {
440
493
  ): Promise<SearchResults> {
441
494
  this.assertOpen();
442
495
 
443
- const ports = await this.createRuntimePorts({
444
- embed: true,
445
- requiredEmbed: true,
446
- embedModel: options.model,
447
- collection: options.collection,
448
- });
496
+ let ports: RuntimePorts | null = null;
497
+ let traceSession: RetrievalTraceSession | null = null;
449
498
 
450
499
  try {
500
+ const embedUri = resolveModelUri(
501
+ this.config,
502
+ "embed",
503
+ options.model,
504
+ options.collection
505
+ );
506
+ traceSession = unwrapStore(
507
+ await startRetrievalTraceRequest({
508
+ store: this.store,
509
+ config: this.config,
510
+ query,
511
+ filters: retrievalTraceFilters(options),
512
+ pipeline: "vector",
513
+ indexName: this.indexName,
514
+ modelUris: [embedUri],
515
+ })
516
+ );
517
+ ports = await this.createRuntimePorts({
518
+ embed: true,
519
+ requiredEmbed: true,
520
+ embedModel: options.model,
521
+ collection: options.collection,
522
+ });
451
523
  if (!ports.embedPort || !ports.vectorIndex) {
452
524
  throw sdkError(
453
525
  "MODEL",
@@ -464,23 +536,29 @@ class GnoClientImpl implements GnoClient {
464
536
  });
465
537
  }
466
538
 
467
- return this.decorateSearchResults(
468
- unwrapStore(
469
- await searchVectorWithEmbedding(
470
- {
471
- store: this.store,
472
- vectorIndex: ports.vectorIndex,
473
- embedPort: ports.embedPort,
474
- config: this.config,
475
- },
476
- query,
477
- new Float32Array(queryEmbedResult.value),
478
- options
539
+ return attachRetrievalTraceMetadata(
540
+ this.decorateSearchResults(
541
+ unwrapStore(
542
+ await searchVectorWithEmbedding(
543
+ {
544
+ store: this.store,
545
+ vectorIndex: ports.vectorIndex,
546
+ embedPort: ports.embedPort,
547
+ config: this.config,
548
+ },
549
+ query,
550
+ new Float32Array(queryEmbedResult.value),
551
+ { ...options, traceSession: traceSession ?? undefined }
552
+ )
479
553
  )
480
- )
554
+ ),
555
+ traceSession ?? undefined
481
556
  );
557
+ } catch (cause) {
558
+ await finishRetrievalTraceAfterError(traceSession, cause);
559
+ throw cause;
482
560
  } finally {
483
- await this.disposeRuntimePorts(ports);
561
+ if (ports) await this.disposeRuntimePorts(ports);
484
562
  }
485
563
  }
486
564
 
@@ -506,36 +584,81 @@ class GnoClientImpl implements GnoClient {
506
584
  : undefined,
507
585
  };
508
586
 
509
- const ports = await this.createRuntimePorts({
510
- embed: true,
511
- expand: !options.noExpand && !options.queryModes?.length,
512
- rerank: !options.noRerank,
513
- embedModel: options.embedModel,
514
- expandModel: options.expandModel,
515
- genModel: options.genModel,
516
- rerankModel: options.rerankModel,
517
- collection: options.collection,
518
- });
587
+ const expandRequested = !options.noExpand && !options.queryModes?.length;
588
+ const rerankRequested = !options.noRerank;
589
+ const embedUri = resolveModelUri(
590
+ this.config,
591
+ "embed",
592
+ options.embedModel,
593
+ options.collection
594
+ );
595
+ const expandUri = expandRequested
596
+ ? resolveModelUri(
597
+ this.config,
598
+ "expand",
599
+ options.expandModel ?? options.genModel,
600
+ options.collection
601
+ )
602
+ : undefined;
603
+ const rerankUri = rerankRequested
604
+ ? resolveModelUri(
605
+ this.config,
606
+ "rerank",
607
+ options.rerankModel,
608
+ options.collection
609
+ )
610
+ : undefined;
611
+ let ports: RuntimePorts | null = null;
612
+ let traceSession: RetrievalTraceSession | null = null;
519
613
 
520
614
  try {
521
- return this.decorateSearchResults(
522
- unwrapStore(
523
- await searchHybrid(
524
- {
525
- store: this.store,
526
- config: this.config,
527
- vectorIndex: ports.vectorIndex,
528
- embedPort: ports.embedPort,
529
- expandPort: ports.expandPort,
530
- rerankPort: ports.rerankPort,
531
- },
532
- query,
533
- options
615
+ traceSession = unwrapStore(
616
+ await startRetrievalTraceRequest({
617
+ store: this.store,
618
+ config: this.config,
619
+ query,
620
+ filters: retrievalTraceFilters(options),
621
+ pipeline: "hybrid",
622
+ indexName: this.indexName,
623
+ modelUris: [embedUri, expandUri, rerankUri].filter(
624
+ (value): value is string => Boolean(value)
625
+ ),
626
+ })
627
+ );
628
+ ports = await this.createRuntimePorts({
629
+ embed: true,
630
+ expand: expandRequested,
631
+ rerank: rerankRequested,
632
+ embedModel: options.embedModel,
633
+ expandModel: options.expandModel,
634
+ genModel: options.genModel,
635
+ rerankModel: options.rerankModel,
636
+ collection: options.collection,
637
+ });
638
+ return attachRetrievalTraceMetadata(
639
+ this.decorateSearchResults(
640
+ unwrapStore(
641
+ await searchHybrid(
642
+ {
643
+ store: this.store,
644
+ config: this.config,
645
+ vectorIndex: ports.vectorIndex,
646
+ embedPort: ports.embedPort,
647
+ expandPort: ports.expandPort,
648
+ rerankPort: ports.rerankPort,
649
+ },
650
+ query,
651
+ { ...options, traceSession: traceSession ?? undefined }
652
+ )
534
653
  )
535
- )
654
+ ),
655
+ traceSession ?? undefined
536
656
  );
657
+ } catch (cause) {
658
+ await finishRetrievalTraceAfterError(traceSession, cause);
659
+ throw cause;
537
660
  } finally {
538
- await this.disposeRuntimePorts(ports);
661
+ if (ports) await this.disposeRuntimePorts(ports);
539
662
  }
540
663
  }
541
664
 
@@ -558,28 +681,109 @@ class GnoClientImpl implements GnoClient {
558
681
  : undefined,
559
682
  };
560
683
 
561
- const answerRequested = Boolean(options.answer && !options.noAnswer);
562
- const needsExpansionGen = !options.noExpand && !options.queryModes?.length;
563
- const ports = await this.createRuntimePorts({
564
- embed: true,
565
- expand: needsExpansionGen,
566
- answer: answerRequested,
567
- rerank: !options.noRerank,
568
- expandModel: options.expandModel,
569
- genModel: options.genModel,
570
- embedModel: options.embedModel,
571
- rerankModel: options.rerankModel,
572
- collection: options.collection,
573
- });
684
+ const verificationRequested = options.verify === true;
685
+ const answerRequested =
686
+ verificationRequested || Boolean(options.answer && !options.noAnswer);
687
+ const needsExpansionGen =
688
+ !verificationRequested &&
689
+ !options.noExpand &&
690
+ !options.queryModes?.length;
691
+ const rerankRequested = !options.noRerank;
692
+ const embedUri = resolveModelUri(
693
+ this.config,
694
+ "embed",
695
+ options.embedModel,
696
+ options.collection
697
+ );
698
+ const expandUri = needsExpansionGen
699
+ ? resolveModelUri(
700
+ this.config,
701
+ "expand",
702
+ options.expandModel ?? options.genModel,
703
+ options.collection
704
+ )
705
+ : undefined;
706
+ const answerUri = answerRequested
707
+ ? resolveModelUri(
708
+ this.config,
709
+ "gen",
710
+ options.genModel,
711
+ options.collection
712
+ )
713
+ : undefined;
714
+ const rerankUri = rerankRequested
715
+ ? resolveModelUri(
716
+ this.config,
717
+ "rerank",
718
+ options.rerankModel,
719
+ options.collection
720
+ )
721
+ : undefined;
722
+ let ports: RuntimePorts | null = null;
723
+ let traceSession: RetrievalTraceSession | null = null;
574
724
 
575
725
  try {
726
+ traceSession = unwrapStore(
727
+ await startRetrievalTraceRequest({
728
+ store: this.store,
729
+ config: this.config,
730
+ query,
731
+ filters: retrievalTraceFilters(options),
732
+ pipeline: "ask",
733
+ indexName: this.indexName,
734
+ modelUris: [embedUri, expandUri, answerUri, rerankUri].filter(
735
+ (value): value is string => Boolean(value)
736
+ ),
737
+ })
738
+ );
739
+ ports = await this.createRuntimePorts({
740
+ embed: true,
741
+ expand: needsExpansionGen,
742
+ answer: answerRequested,
743
+ rerank: rerankRequested,
744
+ expandModel: options.expandModel,
745
+ genModel: options.genModel,
746
+ embedModel: options.embedModel,
747
+ rerankModel: options.rerankModel,
748
+ collection: options.collection,
749
+ });
576
750
  if (answerRequested && !ports.answerPort) {
751
+ await traceSession?.recordCapability(
752
+ "answer_generation",
753
+ "unavailable",
754
+ "model_unavailable"
755
+ );
756
+ await traceSession?.finish("failed");
577
757
  throw sdkError(
578
758
  "MODEL",
579
759
  "Answer generation requested but no generation model is available"
580
760
  );
581
761
  }
582
762
 
763
+ if (verificationRequested && ports.answerPort) {
764
+ const verified = await buildVerifiedAsk(query, options, {
765
+ store: this.store,
766
+ config: this.config,
767
+ indexName: this.indexName,
768
+ vectorIndex: ports.vectorIndex,
769
+ embedPort: ports.embedPort,
770
+ rerankPort: ports.rerankPort,
771
+ genPort: ports.answerPort,
772
+ traceSession: traceSession ?? undefined,
773
+ });
774
+ if (traceSession) {
775
+ unwrapStore(
776
+ await traceSession.finish(
777
+ answerTraceTerminalStatus(verified.citations)
778
+ )
779
+ );
780
+ }
781
+ return attachRetrievalTraceMetadata(
782
+ verified,
783
+ traceSession ?? undefined
784
+ );
785
+ }
786
+
583
787
  const searchResult = unwrapStore(
584
788
  await searchHybrid(
585
789
  {
@@ -603,11 +807,15 @@ class GnoClientImpl implements GnoClient {
603
807
  tagsAll: options.tagsAll,
604
808
  tagsAny: options.tagsAny,
605
809
  exclude: options.exclude,
810
+ minScore: options.minScore,
811
+ graph: options.graph,
812
+ noGraph: options.noGraph,
606
813
  queryModes: options.queryModes,
607
814
  noExpand: options.noExpand,
608
815
  noRerank: options.noRerank,
609
816
  candidateLimit: options.candidateLimit,
610
817
  queryLanguageHint: options.queryLanguageHint,
818
+ traceSession: traceSession ?? undefined,
611
819
  }
612
820
  )
613
821
  );
@@ -622,6 +830,7 @@ class GnoClientImpl implements GnoClient {
622
830
  ports.answerPort &&
623
831
  searchResult.results.length > 0
624
832
  ) {
833
+ await traceSession?.recordCapability("answer_generation", "attempted");
625
834
  const rawAnswer = await generateGroundedAnswer(
626
835
  { genPort: ports.answerPort, store: this.store },
627
836
  query,
@@ -629,16 +838,26 @@ class GnoClientImpl implements GnoClient {
629
838
  options.maxAnswerTokens ?? 512
630
839
  );
631
840
  if (!rawAnswer) {
841
+ await traceSession?.recordCapability(
842
+ "answer_generation",
843
+ "failed",
844
+ "generation_failed"
845
+ );
846
+ await traceSession?.finish("failed");
632
847
  throw sdkError("MODEL", "Answer generation failed");
633
848
  }
634
- const processed = processAnswerResult(rawAnswer);
849
+ await traceSession?.recordCapability("answer_generation", "used");
850
+ const processed = await processAnswerResultWithTrace(
851
+ rawAnswer,
852
+ traceSession ?? undefined
853
+ );
635
854
  answer = processed.answer;
636
855
  citations = processed.citations;
637
856
  answerContext = processed.answerContext;
638
857
  answerGenerated = true;
639
858
  }
640
859
 
641
- return {
860
+ const askResult: AskResult = {
642
861
  query,
643
862
  mode: searchResult.meta.vectorsUsed ? "hybrid" : "bm25_only",
644
863
  queryLanguage: searchResult.meta.queryLanguage ?? "und",
@@ -658,8 +877,26 @@ class GnoClientImpl implements GnoClient {
658
877
  answerContext,
659
878
  },
660
879
  };
880
+ if (answerRequested && traceSession) {
881
+ if (!answerGenerated) {
882
+ unwrapStore(
883
+ await traceSession.recordCapability(
884
+ "answer_generation",
885
+ "unavailable",
886
+ "no_evidence"
887
+ )
888
+ );
889
+ }
890
+ unwrapStore(
891
+ await traceSession.finish(answerTraceTerminalStatus(citations))
892
+ );
893
+ }
894
+ return attachRetrievalTraceMetadata(askResult, traceSession ?? undefined);
895
+ } catch (cause) {
896
+ await finishRetrievalTraceAfterError(traceSession, cause);
897
+ throw cause;
661
898
  } finally {
662
- await this.disposeRuntimePorts(ports);
899
+ if (ports) await this.disposeRuntimePorts(ports);
663
900
  }
664
901
  }
665
902
 
@@ -673,13 +910,48 @@ class GnoClientImpl implements GnoClient {
673
910
  const collection =
674
911
  input.collections?.length === 1 ? input.collections[0] : undefined;
675
912
  const useModels = input.depthPolicy !== "fast";
676
- const ports = await this.createRuntimePorts({
677
- embed: useModels,
678
- rerank: useModels,
679
- collection,
680
- });
913
+ const modelUris = useModels
914
+ ? [
915
+ resolveModelUri(this.config, "embed", undefined, collection),
916
+ resolveModelUri(this.config, "rerank", undefined, collection),
917
+ ]
918
+ : [];
919
+ let ports: RuntimePorts | null = null;
920
+ let traceSession: RetrievalTraceSession | null = null;
681
921
  try {
682
- return await buildContextCapsule(
922
+ traceSession = unwrapStore(
923
+ await startRetrievalTraceRequest({
924
+ store: this.store,
925
+ config: this.config,
926
+ query: input.query ?? input.goal,
927
+ goal: input.goal,
928
+ filters: {
929
+ limit: input.limit,
930
+ collection,
931
+ collections: [...(input.collections ?? [])].sort(),
932
+ lang: input.lang,
933
+ tagsAll: input.tagsAll,
934
+ tagsAny: input.tagsAny,
935
+ since: input.since,
936
+ until: input.until,
937
+ categories: input.categories,
938
+ author: input.author,
939
+ graph: input.graph,
940
+ candidateLimit: input.candidateLimit,
941
+ queryModes: input.queryModes,
942
+ uriPrefix: input.uriPrefix ?? undefined,
943
+ },
944
+ pipeline: "context",
945
+ indexName: this.indexName,
946
+ modelUris,
947
+ })
948
+ );
949
+ ports = await this.createRuntimePorts({
950
+ embed: useModels,
951
+ rerank: useModels,
952
+ collection,
953
+ });
954
+ const capsule = await buildContextCapsule(
683
955
  { ...input, indexName: this.indexName },
684
956
  {
685
957
  store: this.store,
@@ -688,10 +960,16 @@ class GnoClientImpl implements GnoClient {
688
960
  vectorIndex: ports.vectorIndex,
689
961
  embedPort: ports.embedPort,
690
962
  rerankPort: ports.rerankPort,
963
+ traceSession: traceSession ?? undefined,
691
964
  }
692
965
  );
966
+ if (traceSession) unwrapStore(await traceSession.finish("completed"));
967
+ return attachRetrievalTraceMetadata(capsule, traceSession ?? undefined);
968
+ } catch (cause) {
969
+ await finishRetrievalTraceAfterError(traceSession, cause);
970
+ throw cause;
693
971
  } finally {
694
- await this.disposeRuntimePorts(ports);
972
+ if (ports) await this.disposeRuntimePorts(ports);
695
973
  }
696
974
  }
697
975
 
@@ -726,10 +1004,20 @@ class GnoClientImpl implements GnoClient {
726
1004
  ref,
727
1005
  options
728
1006
  );
729
- return {
1007
+ const decorated = {
730
1008
  ...result,
731
1009
  uri: decorateUriForIndex(result.uri, scoped.indexName),
732
1010
  };
1011
+ const traceMetadata = getRetrievalTraceMetadata(result);
1012
+ if (traceMetadata) {
1013
+ Object.defineProperty(decorated, RETRIEVAL_TRACE_METADATA, {
1014
+ configurable: false,
1015
+ enumerable: false,
1016
+ value: traceMetadata,
1017
+ writable: false,
1018
+ });
1019
+ }
1020
+ return decorated;
733
1021
  } finally {
734
1022
  await scoped.close();
735
1023
  }
@@ -788,6 +1076,60 @@ class GnoClientImpl implements GnoClient {
788
1076
  );
789
1077
  }
790
1078
 
1079
+ async listRetrievalTraces(
1080
+ options: import("../core/retrieval-trace-management").RetrievalTraceListRequest = {}
1081
+ ) {
1082
+ this.assertOpen();
1083
+ return unwrapTraceStore(
1084
+ await new RetrievalTraceManagementService(this.store).list(options)
1085
+ );
1086
+ }
1087
+
1088
+ async getRetrievalTrace(
1089
+ traceId: string,
1090
+ options: { detailLimit?: number } = {}
1091
+ ) {
1092
+ this.assertOpen();
1093
+ return unwrapTraceStore(
1094
+ await new RetrievalTraceManagementService(this.store).show(
1095
+ traceId,
1096
+ options
1097
+ )
1098
+ );
1099
+ }
1100
+
1101
+ async labelRetrievalTrace(
1102
+ input: import("../core/retrieval-trace-management").RetrievalTraceLabelRequest
1103
+ ) {
1104
+ this.assertOpen();
1105
+ return unwrapTraceStore(
1106
+ await new RetrievalTraceManagementService(this.store).label(input)
1107
+ );
1108
+ }
1109
+
1110
+ async exportRetrievalTraces(
1111
+ input: import("../core/retrieval-trace-management").RetrievalTraceExportRequest
1112
+ ) {
1113
+ this.assertOpen();
1114
+ return unwrapTraceStore(
1115
+ await new RetrievalTraceManagementService(this.store).export(input)
1116
+ );
1117
+ }
1118
+
1119
+ async deleteRetrievalTrace(traceId: string) {
1120
+ this.assertOpen();
1121
+ return unwrapTraceStore(
1122
+ await new RetrievalTraceManagementService(this.store).delete(traceId)
1123
+ );
1124
+ }
1125
+
1126
+ async purgeRetrievalTraces() {
1127
+ this.assertOpen();
1128
+ return unwrapTraceStore(
1129
+ await new RetrievalTraceManagementService(this.store).purge()
1130
+ );
1131
+ }
1132
+
791
1133
  async update(options: GnoUpdateOptions = {}): Promise<SyncResult> {
792
1134
  this.assertOpen();
793
1135
  const collections = this.getCollections(options.collection);