@gmickel/gno 1.17.0 → 1.19.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 (167) hide show
  1. package/README.md +18 -4
  2. package/assets/skill/SKILL.md +44 -1
  3. package/assets/skill/mcp-reference.md +21 -0
  4. package/package.json +3 -2
  5. package/spec/AGENTS.md +83 -0
  6. package/spec/CLAUDE.md +83 -0
  7. package/spec/bench-fixture.schema.json +137 -0
  8. package/spec/cli.md +2894 -0
  9. package/spec/db/schema.sql +442 -0
  10. package/spec/evals-agentic.md +510 -0
  11. package/spec/evals.md +1106 -0
  12. package/spec/mcp.md +2229 -0
  13. package/spec/output-schemas/activation-verification.schema.json +515 -0
  14. package/spec/output-schemas/ask.schema.json +366 -0
  15. package/spec/output-schemas/backlinks.schema.json +131 -0
  16. package/spec/output-schemas/bench-result.schema.json +120 -0
  17. package/spec/output-schemas/capture-receipt.schema.json +143 -0
  18. package/spec/output-schemas/collection-list.schema.json +45 -0
  19. package/spec/output-schemas/context-capsule-v1.schema.json +691 -0
  20. package/spec/output-schemas/context-capsule-verification.schema.json +1338 -0
  21. package/spec/output-schemas/context-list.schema.json +21 -0
  22. package/spec/output-schemas/doctor.schema.json +313 -0
  23. package/spec/output-schemas/error.schema.json +30 -0
  24. package/spec/output-schemas/expansion.schema.json +37 -0
  25. package/spec/output-schemas/get.schema.json +140 -0
  26. package/spec/output-schemas/graph-query.schema.json +99 -0
  27. package/spec/output-schemas/graph.schema.json +371 -0
  28. package/spec/output-schemas/links-list.schema.json +186 -0
  29. package/spec/output-schemas/mcp-add-collection-result.schema.json +23 -0
  30. package/spec/output-schemas/mcp-capture-result.schema.json +152 -0
  31. package/spec/output-schemas/mcp-http-error.schema.json +30 -0
  32. package/spec/output-schemas/mcp-job-list.schema.json +58 -0
  33. package/spec/output-schemas/mcp-job-status.schema.json +224 -0
  34. package/spec/output-schemas/mcp-remove-result.schema.json +39 -0
  35. package/spec/output-schemas/mcp-sync-result.schema.json +41 -0
  36. package/spec/output-schemas/mcp-tag-result.schema.json +33 -0
  37. package/spec/output-schemas/models-list.schema.json +93 -0
  38. package/spec/output-schemas/multi-get.schema.json +103 -0
  39. package/spec/output-schemas/process-status.schema.json +119 -0
  40. package/spec/output-schemas/query-diagnose.schema.json +123 -0
  41. package/spec/output-schemas/resident-status.schema.json +154 -0
  42. package/spec/output-schemas/retrieval-trace-common.schema.json +492 -0
  43. package/spec/output-schemas/retrieval-trace-delete.schema.json +16 -0
  44. package/spec/output-schemas/retrieval-trace-export.schema.json +61 -0
  45. package/spec/output-schemas/retrieval-trace-filters.schema.json +139 -0
  46. package/spec/output-schemas/retrieval-trace-judgment.schema.json +15 -0
  47. package/spec/output-schemas/retrieval-trace-list.schema.json +18 -0
  48. package/spec/output-schemas/retrieval-trace-payloads.schema.json +178 -0
  49. package/spec/output-schemas/retrieval-trace-purge.schema.json +31 -0
  50. package/spec/output-schemas/retrieval-trace-qrels.schema.json +303 -0
  51. package/spec/output-schemas/retrieval-trace-replay.schema.json +286 -0
  52. package/spec/output-schemas/retrieval-trace-show.schema.json +69 -0
  53. package/spec/output-schemas/retrieval-trace-summary.schema.json +65 -0
  54. package/spec/output-schemas/search-result.schema.json +154 -0
  55. package/spec/output-schemas/search-results.schema.json +338 -0
  56. package/spec/output-schemas/similar.schema.json +84 -0
  57. package/spec/output-schemas/status.schema.json +676 -0
  58. package/spec/output-schemas/tags-list.schema.json +48 -0
  59. package/src/app/context-runtime-types.ts +3 -0
  60. package/src/app/context-runtime.ts +15 -1
  61. package/src/cli/commands/ask.ts +106 -36
  62. package/src/cli/commands/context-build.ts +56 -9
  63. package/src/cli/commands/daemon.ts +69 -2
  64. package/src/cli/commands/get.ts +64 -3
  65. package/src/cli/commands/models/pull.ts +13 -3
  66. package/src/cli/commands/query.ts +62 -23
  67. package/src/cli/commands/replay.ts +140 -0
  68. package/src/cli/commands/search.ts +48 -3
  69. package/src/cli/commands/shared.ts +3 -1
  70. package/src/cli/commands/status.ts +2 -0
  71. package/src/cli/commands/trace.ts +200 -0
  72. package/src/cli/commands/vsearch.ts +75 -53
  73. package/src/cli/detach.ts +37 -20
  74. package/src/cli/program.ts +329 -27
  75. package/src/config/index.ts +12 -0
  76. package/src/config/retrieval-traces.ts +56 -0
  77. package/src/config/types.ts +41 -0
  78. package/src/core/context-compiler.ts +11 -4
  79. package/src/core/job-manager.ts +19 -0
  80. package/src/core/mutation-generations.ts +33 -0
  81. package/src/core/retrieval-qrels.ts +405 -0
  82. package/src/core/retrieval-replay-candidate.ts +368 -0
  83. package/src/core/retrieval-replay-types.ts +109 -0
  84. package/src/core/retrieval-replay-validation.ts +89 -0
  85. package/src/core/retrieval-replay.ts +441 -0
  86. package/src/core/retrieval-trace-evidence-origin.ts +175 -0
  87. package/src/core/retrieval-trace-export.ts +113 -0
  88. package/src/core/retrieval-trace-filter-normalization.ts +27 -0
  89. package/src/core/retrieval-trace-filters.ts +19 -0
  90. package/src/core/retrieval-trace-management-helpers.ts +247 -0
  91. package/src/core/retrieval-trace-management-types.ts +132 -0
  92. package/src/core/retrieval-trace-management.ts +422 -0
  93. package/src/core/retrieval-trace-request.ts +141 -0
  94. package/src/core/retrieval-trace-session.ts +494 -0
  95. package/src/core/retrieval-trace.ts +472 -0
  96. package/src/llm/cache.ts +13 -3
  97. package/src/llm/nodeLlamaCpp/adapter.ts +10 -1
  98. package/src/llm/nodeLlamaCpp/lifecycle.ts +71 -0
  99. package/src/mcp/context.ts +161 -0
  100. package/src/mcp/http-security.ts +477 -0
  101. package/src/mcp/http-session.ts +272 -0
  102. package/src/mcp/http-transport.ts +370 -0
  103. package/src/mcp/resources/index.ts +141 -134
  104. package/src/mcp/server.ts +19 -79
  105. package/src/mcp/tools/add-collection.ts +3 -1
  106. package/src/mcp/tools/capture.ts +3 -0
  107. package/src/mcp/tools/clear-collection-embeddings.ts +2 -0
  108. package/src/mcp/tools/context.ts +68 -16
  109. package/src/mcp/tools/embed.ts +62 -52
  110. package/src/mcp/tools/get.ts +35 -1
  111. package/src/mcp/tools/index-cmd.ts +88 -74
  112. package/src/mcp/tools/index.ts +96 -2
  113. package/src/mcp/tools/query.ts +95 -64
  114. package/src/mcp/tools/remove-collection.ts +2 -0
  115. package/src/mcp/tools/search.ts +36 -13
  116. package/src/mcp/tools/status.ts +11 -0
  117. package/src/mcp/tools/sync.ts +16 -14
  118. package/src/mcp/tools/trace.ts +143 -0
  119. package/src/mcp/tools/vsearch.ts +71 -38
  120. package/src/mcp/tools/workspace-write.ts +7 -3
  121. package/src/pipeline/answer.ts +167 -26
  122. package/src/pipeline/graph-retrieval.ts +15 -1
  123. package/src/pipeline/hybrid.ts +151 -43
  124. package/src/pipeline/search.ts +36 -3
  125. package/src/pipeline/trace-metadata.ts +47 -0
  126. package/src/pipeline/types.ts +43 -0
  127. package/src/pipeline/vsearch.ts +101 -38
  128. package/src/sdk/client.ts +380 -71
  129. package/src/sdk/documents.ts +48 -1
  130. package/src/sdk/index.ts +17 -0
  131. package/src/sdk/types.ts +28 -0
  132. package/src/serve/background-runtime.ts +12 -212
  133. package/src/serve/context-capsule.ts +67 -8
  134. package/src/serve/embed-scheduler.ts +74 -43
  135. package/src/serve/index.ts +9 -0
  136. package/src/serve/jobs.ts +78 -80
  137. package/src/serve/public/app.tsx +12 -1
  138. package/src/serve/public/components/HealthCenter.tsx +74 -1
  139. package/src/serve/public/globals.built.css +1 -1
  140. package/src/serve/public/lib/workspace-tabs.ts +2 -0
  141. package/src/serve/public/pages/Dashboard.tsx +11 -0
  142. package/src/serve/public/pages/TraceHistory.tsx +478 -0
  143. package/src/serve/public/pages/trace-history-detail.tsx +224 -0
  144. package/src/serve/resident-admission.ts +159 -0
  145. package/src/serve/resident-background-work.ts +39 -0
  146. package/src/serve/resident-request.ts +55 -0
  147. package/src/serve/resident-runtime.ts +490 -0
  148. package/src/serve/resident-status.ts +96 -0
  149. package/src/serve/retrieval-trace.ts +28 -0
  150. package/src/serve/routes/api.ts +629 -239
  151. package/src/serve/routes/mcp.ts +69 -0
  152. package/src/serve/routes/traces.ts +156 -0
  153. package/src/serve/server.ts +276 -37
  154. package/src/serve/status-model.ts +51 -0
  155. package/src/serve/status.ts +5 -0
  156. package/src/store/index.ts +31 -0
  157. package/src/store/migrations/014-retrieval-traces.ts +303 -0
  158. package/src/store/migrations/index.ts +2 -0
  159. package/src/store/retrieval-trace-codec.ts +384 -0
  160. package/src/store/sqlite/adapter.ts +179 -10
  161. package/src/store/sqlite/retrieval-trace-management-store.ts +341 -0
  162. package/src/store/sqlite/retrieval-trace-retention.ts +349 -0
  163. package/src/store/sqlite/retrieval-trace-rows.ts +267 -0
  164. package/src/store/sqlite/retrieval-trace-store.ts +515 -0
  165. package/src/store/types.ts +297 -0
  166. package/src/store/vector/sqlite-vec.ts +76 -1
  167. package/src/store/vector/types.ts +1 -1
package/src/sdk/client.ts CHANGED
@@ -85,6 +85,18 @@ import {
85
85
  import { resolveEffectiveIndex } from "../core/indexed-reference";
86
86
  import { resolveNoteCreatePlan } from "../core/note-creation";
87
87
  import { resolveNotePreset } from "../core/note-presets";
88
+ import { RetrievalTraceManagementService } from "../core/retrieval-trace-management";
89
+ import {
90
+ finishRetrievalTraceAfterError,
91
+ retrievalTraceFilters,
92
+ startRetrievalTraceRequest,
93
+ } from "../core/retrieval-trace-request";
94
+ import {
95
+ attachRetrievalTraceMetadata,
96
+ getRetrievalTraceMetadata,
97
+ RETRIEVAL_TRACE_METADATA,
98
+ type RetrievalTraceSession,
99
+ } from "../core/retrieval-trace-session";
88
100
  import { extractSections } from "../core/sections";
89
101
  import { normalizeStructuredQueryInput } from "../core/structured-query";
90
102
  import { parseAndValidateTagFilter } from "../core/tags";
@@ -98,8 +110,9 @@ import { LlmAdapter } from "../llm/nodeLlamaCpp/adapter";
98
110
  import { resolveDownloadPolicy } from "../llm/policy";
99
111
  import { resolveModelUri } from "../llm/registry";
100
112
  import {
113
+ answerTraceTerminalStatus,
101
114
  generateGroundedAnswer,
102
- processAnswerResult,
115
+ processAnswerResultWithTrace,
103
116
  } from "../pipeline/answer";
104
117
  import { formatQueryForEmbedding } from "../pipeline/contextual";
105
118
  import { searchHybrid } from "../pipeline/hybrid";
@@ -145,6 +158,21 @@ function unwrapStore<T>(
145
158
  return result.value;
146
159
  }
147
160
 
161
+ function unwrapTraceStore<T>(result: StoreResult<T>): T {
162
+ if (result.ok) return result.value;
163
+ const code =
164
+ result.error.code === "NOT_FOUND"
165
+ ? "NOT_FOUND"
166
+ : result.error.code === "INVALID_INPUT" ||
167
+ result.error.code === "CONSTRAINT_VIOLATION"
168
+ ? "VALIDATION"
169
+ : "STORE";
170
+ throw sdkError(code, result.error.message, {
171
+ cause: result.error.cause,
172
+ details: { traceCode: result.error.code },
173
+ });
174
+ }
175
+
148
176
  async function resolveClientState(
149
177
  options: GnoClientInitOptions = {}
150
178
  ): Promise<OpenedClientState> {
@@ -429,9 +457,33 @@ class GnoClientImpl implements GnoClient {
429
457
  options: import("../pipeline/types").SearchOptions = {}
430
458
  ): Promise<SearchResults> {
431
459
  this.assertOpen();
432
- return this.decorateSearchResults(
433
- unwrapStore(await searchBm25(this.store, query, options))
434
- );
460
+ let traceSession: RetrievalTraceSession | null = null;
461
+ try {
462
+ traceSession = unwrapStore(
463
+ await startRetrievalTraceRequest({
464
+ store: this.store,
465
+ config: this.config,
466
+ query,
467
+ filters: retrievalTraceFilters(options),
468
+ pipeline: "bm25",
469
+ indexName: this.indexName,
470
+ })
471
+ );
472
+ return attachRetrievalTraceMetadata(
473
+ this.decorateSearchResults(
474
+ unwrapStore(
475
+ await searchBm25(this.store, query, {
476
+ ...options,
477
+ traceSession: traceSession ?? undefined,
478
+ })
479
+ )
480
+ ),
481
+ traceSession ?? undefined
482
+ );
483
+ } catch (cause) {
484
+ await finishRetrievalTraceAfterError(traceSession, cause);
485
+ throw cause;
486
+ }
435
487
  }
436
488
 
437
489
  async vsearch(
@@ -440,14 +492,33 @@ class GnoClientImpl implements GnoClient {
440
492
  ): Promise<SearchResults> {
441
493
  this.assertOpen();
442
494
 
443
- const ports = await this.createRuntimePorts({
444
- embed: true,
445
- requiredEmbed: true,
446
- embedModel: options.model,
447
- collection: options.collection,
448
- });
495
+ let ports: RuntimePorts | null = null;
496
+ let traceSession: RetrievalTraceSession | null = null;
449
497
 
450
498
  try {
499
+ const embedUri = resolveModelUri(
500
+ this.config,
501
+ "embed",
502
+ options.model,
503
+ options.collection
504
+ );
505
+ traceSession = unwrapStore(
506
+ await startRetrievalTraceRequest({
507
+ store: this.store,
508
+ config: this.config,
509
+ query,
510
+ filters: retrievalTraceFilters(options),
511
+ pipeline: "vector",
512
+ indexName: this.indexName,
513
+ modelUris: [embedUri],
514
+ })
515
+ );
516
+ ports = await this.createRuntimePorts({
517
+ embed: true,
518
+ requiredEmbed: true,
519
+ embedModel: options.model,
520
+ collection: options.collection,
521
+ });
451
522
  if (!ports.embedPort || !ports.vectorIndex) {
452
523
  throw sdkError(
453
524
  "MODEL",
@@ -464,23 +535,29 @@ class GnoClientImpl implements GnoClient {
464
535
  });
465
536
  }
466
537
 
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
538
+ return attachRetrievalTraceMetadata(
539
+ this.decorateSearchResults(
540
+ unwrapStore(
541
+ await searchVectorWithEmbedding(
542
+ {
543
+ store: this.store,
544
+ vectorIndex: ports.vectorIndex,
545
+ embedPort: ports.embedPort,
546
+ config: this.config,
547
+ },
548
+ query,
549
+ new Float32Array(queryEmbedResult.value),
550
+ { ...options, traceSession: traceSession ?? undefined }
551
+ )
479
552
  )
480
- )
553
+ ),
554
+ traceSession ?? undefined
481
555
  );
556
+ } catch (cause) {
557
+ await finishRetrievalTraceAfterError(traceSession, cause);
558
+ throw cause;
482
559
  } finally {
483
- await this.disposeRuntimePorts(ports);
560
+ if (ports) await this.disposeRuntimePorts(ports);
484
561
  }
485
562
  }
486
563
 
@@ -506,36 +583,81 @@ class GnoClientImpl implements GnoClient {
506
583
  : undefined,
507
584
  };
508
585
 
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
- });
586
+ const expandRequested = !options.noExpand && !options.queryModes?.length;
587
+ const rerankRequested = !options.noRerank;
588
+ const embedUri = resolveModelUri(
589
+ this.config,
590
+ "embed",
591
+ options.embedModel,
592
+ options.collection
593
+ );
594
+ const expandUri = expandRequested
595
+ ? resolveModelUri(
596
+ this.config,
597
+ "expand",
598
+ options.expandModel ?? options.genModel,
599
+ options.collection
600
+ )
601
+ : undefined;
602
+ const rerankUri = rerankRequested
603
+ ? resolveModelUri(
604
+ this.config,
605
+ "rerank",
606
+ options.rerankModel,
607
+ options.collection
608
+ )
609
+ : undefined;
610
+ let ports: RuntimePorts | null = null;
611
+ let traceSession: RetrievalTraceSession | null = null;
519
612
 
520
613
  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
614
+ traceSession = unwrapStore(
615
+ await startRetrievalTraceRequest({
616
+ store: this.store,
617
+ config: this.config,
618
+ query,
619
+ filters: retrievalTraceFilters(options),
620
+ pipeline: "hybrid",
621
+ indexName: this.indexName,
622
+ modelUris: [embedUri, expandUri, rerankUri].filter(
623
+ (value): value is string => Boolean(value)
624
+ ),
625
+ })
626
+ );
627
+ ports = await this.createRuntimePorts({
628
+ embed: true,
629
+ expand: expandRequested,
630
+ rerank: rerankRequested,
631
+ embedModel: options.embedModel,
632
+ expandModel: options.expandModel,
633
+ genModel: options.genModel,
634
+ rerankModel: options.rerankModel,
635
+ collection: options.collection,
636
+ });
637
+ return attachRetrievalTraceMetadata(
638
+ this.decorateSearchResults(
639
+ unwrapStore(
640
+ await searchHybrid(
641
+ {
642
+ store: this.store,
643
+ config: this.config,
644
+ vectorIndex: ports.vectorIndex,
645
+ embedPort: ports.embedPort,
646
+ expandPort: ports.expandPort,
647
+ rerankPort: ports.rerankPort,
648
+ },
649
+ query,
650
+ { ...options, traceSession: traceSession ?? undefined }
651
+ )
534
652
  )
535
- )
653
+ ),
654
+ traceSession ?? undefined
536
655
  );
656
+ } catch (cause) {
657
+ await finishRetrievalTraceAfterError(traceSession, cause);
658
+ throw cause;
537
659
  } finally {
538
- await this.disposeRuntimePorts(ports);
660
+ if (ports) await this.disposeRuntimePorts(ports);
539
661
  }
540
662
  }
541
663
 
@@ -560,20 +682,72 @@ class GnoClientImpl implements GnoClient {
560
682
 
561
683
  const answerRequested = Boolean(options.answer && !options.noAnswer);
562
684
  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
- });
685
+ const rerankRequested = !options.noRerank;
686
+ const embedUri = resolveModelUri(
687
+ this.config,
688
+ "embed",
689
+ options.embedModel,
690
+ options.collection
691
+ );
692
+ const expandUri = needsExpansionGen
693
+ ? resolveModelUri(
694
+ this.config,
695
+ "expand",
696
+ options.expandModel ?? options.genModel,
697
+ options.collection
698
+ )
699
+ : undefined;
700
+ const answerUri = answerRequested
701
+ ? resolveModelUri(
702
+ this.config,
703
+ "gen",
704
+ options.genModel,
705
+ options.collection
706
+ )
707
+ : undefined;
708
+ const rerankUri = rerankRequested
709
+ ? resolveModelUri(
710
+ this.config,
711
+ "rerank",
712
+ options.rerankModel,
713
+ options.collection
714
+ )
715
+ : undefined;
716
+ let ports: RuntimePorts | null = null;
717
+ let traceSession: RetrievalTraceSession | null = null;
574
718
 
575
719
  try {
720
+ traceSession = unwrapStore(
721
+ await startRetrievalTraceRequest({
722
+ store: this.store,
723
+ config: this.config,
724
+ query,
725
+ filters: retrievalTraceFilters(options),
726
+ pipeline: "ask",
727
+ indexName: this.indexName,
728
+ modelUris: [embedUri, expandUri, answerUri, rerankUri].filter(
729
+ (value): value is string => Boolean(value)
730
+ ),
731
+ })
732
+ );
733
+ ports = await this.createRuntimePorts({
734
+ embed: true,
735
+ expand: needsExpansionGen,
736
+ answer: answerRequested,
737
+ rerank: rerankRequested,
738
+ expandModel: options.expandModel,
739
+ genModel: options.genModel,
740
+ embedModel: options.embedModel,
741
+ rerankModel: options.rerankModel,
742
+ collection: options.collection,
743
+ });
576
744
  if (answerRequested && !ports.answerPort) {
745
+ await traceSession?.recordCapability(
746
+ "answer_generation",
747
+ "unavailable",
748
+ "model_unavailable"
749
+ );
750
+ await traceSession?.finish("failed");
577
751
  throw sdkError(
578
752
  "MODEL",
579
753
  "Answer generation requested but no generation model is available"
@@ -608,6 +782,7 @@ class GnoClientImpl implements GnoClient {
608
782
  noRerank: options.noRerank,
609
783
  candidateLimit: options.candidateLimit,
610
784
  queryLanguageHint: options.queryLanguageHint,
785
+ traceSession: traceSession ?? undefined,
611
786
  }
612
787
  )
613
788
  );
@@ -622,6 +797,7 @@ class GnoClientImpl implements GnoClient {
622
797
  ports.answerPort &&
623
798
  searchResult.results.length > 0
624
799
  ) {
800
+ await traceSession?.recordCapability("answer_generation", "attempted");
625
801
  const rawAnswer = await generateGroundedAnswer(
626
802
  { genPort: ports.answerPort, store: this.store },
627
803
  query,
@@ -629,16 +805,26 @@ class GnoClientImpl implements GnoClient {
629
805
  options.maxAnswerTokens ?? 512
630
806
  );
631
807
  if (!rawAnswer) {
808
+ await traceSession?.recordCapability(
809
+ "answer_generation",
810
+ "failed",
811
+ "generation_failed"
812
+ );
813
+ await traceSession?.finish("failed");
632
814
  throw sdkError("MODEL", "Answer generation failed");
633
815
  }
634
- const processed = processAnswerResult(rawAnswer);
816
+ await traceSession?.recordCapability("answer_generation", "used");
817
+ const processed = await processAnswerResultWithTrace(
818
+ rawAnswer,
819
+ traceSession ?? undefined
820
+ );
635
821
  answer = processed.answer;
636
822
  citations = processed.citations;
637
823
  answerContext = processed.answerContext;
638
824
  answerGenerated = true;
639
825
  }
640
826
 
641
- return {
827
+ const askResult: AskResult = {
642
828
  query,
643
829
  mode: searchResult.meta.vectorsUsed ? "hybrid" : "bm25_only",
644
830
  queryLanguage: searchResult.meta.queryLanguage ?? "und",
@@ -658,8 +844,26 @@ class GnoClientImpl implements GnoClient {
658
844
  answerContext,
659
845
  },
660
846
  };
847
+ if (answerRequested && traceSession) {
848
+ if (!answerGenerated) {
849
+ unwrapStore(
850
+ await traceSession.recordCapability(
851
+ "answer_generation",
852
+ "unavailable",
853
+ "no_evidence"
854
+ )
855
+ );
856
+ }
857
+ unwrapStore(
858
+ await traceSession.finish(answerTraceTerminalStatus(citations))
859
+ );
860
+ }
861
+ return attachRetrievalTraceMetadata(askResult, traceSession ?? undefined);
862
+ } catch (cause) {
863
+ await finishRetrievalTraceAfterError(traceSession, cause);
864
+ throw cause;
661
865
  } finally {
662
- await this.disposeRuntimePorts(ports);
866
+ if (ports) await this.disposeRuntimePorts(ports);
663
867
  }
664
868
  }
665
869
 
@@ -673,13 +877,48 @@ class GnoClientImpl implements GnoClient {
673
877
  const collection =
674
878
  input.collections?.length === 1 ? input.collections[0] : undefined;
675
879
  const useModels = input.depthPolicy !== "fast";
676
- const ports = await this.createRuntimePorts({
677
- embed: useModels,
678
- rerank: useModels,
679
- collection,
680
- });
880
+ const modelUris = useModels
881
+ ? [
882
+ resolveModelUri(this.config, "embed", undefined, collection),
883
+ resolveModelUri(this.config, "rerank", undefined, collection),
884
+ ]
885
+ : [];
886
+ let ports: RuntimePorts | null = null;
887
+ let traceSession: RetrievalTraceSession | null = null;
681
888
  try {
682
- return await buildContextCapsule(
889
+ traceSession = unwrapStore(
890
+ await startRetrievalTraceRequest({
891
+ store: this.store,
892
+ config: this.config,
893
+ query: input.query ?? input.goal,
894
+ goal: input.goal,
895
+ filters: {
896
+ limit: input.limit,
897
+ collection,
898
+ collections: [...(input.collections ?? [])].sort(),
899
+ lang: input.lang,
900
+ tagsAll: input.tagsAll,
901
+ tagsAny: input.tagsAny,
902
+ since: input.since,
903
+ until: input.until,
904
+ categories: input.categories,
905
+ author: input.author,
906
+ graph: input.graph,
907
+ candidateLimit: input.candidateLimit,
908
+ queryModes: input.queryModes,
909
+ uriPrefix: input.uriPrefix ?? undefined,
910
+ },
911
+ pipeline: "context",
912
+ indexName: this.indexName,
913
+ modelUris,
914
+ })
915
+ );
916
+ ports = await this.createRuntimePorts({
917
+ embed: useModels,
918
+ rerank: useModels,
919
+ collection,
920
+ });
921
+ const capsule = await buildContextCapsule(
683
922
  { ...input, indexName: this.indexName },
684
923
  {
685
924
  store: this.store,
@@ -688,10 +927,16 @@ class GnoClientImpl implements GnoClient {
688
927
  vectorIndex: ports.vectorIndex,
689
928
  embedPort: ports.embedPort,
690
929
  rerankPort: ports.rerankPort,
930
+ traceSession: traceSession ?? undefined,
691
931
  }
692
932
  );
933
+ if (traceSession) unwrapStore(await traceSession.finish("completed"));
934
+ return attachRetrievalTraceMetadata(capsule, traceSession ?? undefined);
935
+ } catch (cause) {
936
+ await finishRetrievalTraceAfterError(traceSession, cause);
937
+ throw cause;
693
938
  } finally {
694
- await this.disposeRuntimePorts(ports);
939
+ if (ports) await this.disposeRuntimePorts(ports);
695
940
  }
696
941
  }
697
942
 
@@ -726,10 +971,20 @@ class GnoClientImpl implements GnoClient {
726
971
  ref,
727
972
  options
728
973
  );
729
- return {
974
+ const decorated = {
730
975
  ...result,
731
976
  uri: decorateUriForIndex(result.uri, scoped.indexName),
732
977
  };
978
+ const traceMetadata = getRetrievalTraceMetadata(result);
979
+ if (traceMetadata) {
980
+ Object.defineProperty(decorated, RETRIEVAL_TRACE_METADATA, {
981
+ configurable: false,
982
+ enumerable: false,
983
+ value: traceMetadata,
984
+ writable: false,
985
+ });
986
+ }
987
+ return decorated;
733
988
  } finally {
734
989
  await scoped.close();
735
990
  }
@@ -788,6 +1043,60 @@ class GnoClientImpl implements GnoClient {
788
1043
  );
789
1044
  }
790
1045
 
1046
+ async listRetrievalTraces(
1047
+ options: import("../core/retrieval-trace-management").RetrievalTraceListRequest = {}
1048
+ ) {
1049
+ this.assertOpen();
1050
+ return unwrapTraceStore(
1051
+ await new RetrievalTraceManagementService(this.store).list(options)
1052
+ );
1053
+ }
1054
+
1055
+ async getRetrievalTrace(
1056
+ traceId: string,
1057
+ options: { detailLimit?: number } = {}
1058
+ ) {
1059
+ this.assertOpen();
1060
+ return unwrapTraceStore(
1061
+ await new RetrievalTraceManagementService(this.store).show(
1062
+ traceId,
1063
+ options
1064
+ )
1065
+ );
1066
+ }
1067
+
1068
+ async labelRetrievalTrace(
1069
+ input: import("../core/retrieval-trace-management").RetrievalTraceLabelRequest
1070
+ ) {
1071
+ this.assertOpen();
1072
+ return unwrapTraceStore(
1073
+ await new RetrievalTraceManagementService(this.store).label(input)
1074
+ );
1075
+ }
1076
+
1077
+ async exportRetrievalTraces(
1078
+ input: import("../core/retrieval-trace-management").RetrievalTraceExportRequest
1079
+ ) {
1080
+ this.assertOpen();
1081
+ return unwrapTraceStore(
1082
+ await new RetrievalTraceManagementService(this.store).export(input)
1083
+ );
1084
+ }
1085
+
1086
+ async deleteRetrievalTrace(traceId: string) {
1087
+ this.assertOpen();
1088
+ return unwrapTraceStore(
1089
+ await new RetrievalTraceManagementService(this.store).delete(traceId)
1090
+ );
1091
+ }
1092
+
1093
+ async purgeRetrievalTraces() {
1094
+ this.assertOpen();
1095
+ return unwrapTraceStore(
1096
+ await new RetrievalTraceManagementService(this.store).purge()
1097
+ );
1098
+ }
1099
+
791
1100
  async update(options: GnoUpdateOptions = {}): Promise<SyncResult> {
792
1101
  this.assertOpen();
793
1102
  const collections = this.getCollections(options.collection);
@@ -24,6 +24,11 @@ import type {
24
24
 
25
25
  import { getDocumentCapabilities } from "../core/document-capabilities";
26
26
  import { isGlobPattern, parseRef, splitRefs } from "../core/ref-parser";
27
+ import {
28
+ attachRetrievalTraceMetadata,
29
+ evidenceFromExactDocument,
30
+ RetrievalTraceSession,
31
+ } from "../core/retrieval-trace-session";
27
32
  import { sdkError } from "./errors";
28
33
 
29
34
  const URI_PREFIX_PATTERN = /^gno:\/\/[^/]+\//;
@@ -72,7 +77,7 @@ function buildConversionMeta(
72
77
  };
73
78
  }
74
79
 
75
- export async function getDocumentByRef(
80
+ async function getDocumentByRefUntraced(
76
81
  store: StorePort,
77
82
  config: Config,
78
83
  ref: string,
@@ -159,6 +164,48 @@ export async function getDocumentByRef(
159
164
  };
160
165
  }
161
166
 
167
+ export async function getDocumentByRef(
168
+ store: StorePort,
169
+ config: Config,
170
+ ref: string,
171
+ options: GnoGetOptions = {}
172
+ ): Promise<GetResponse> {
173
+ const response = await getDocumentByRefUntraced(store, config, ref, options);
174
+ if (!options.traceId) return response;
175
+ const resumed = await RetrievalTraceSession.resume({
176
+ store,
177
+ config: config.retrievalTraces,
178
+ traceId: options.traceId,
179
+ });
180
+ if (!resumed.ok) {
181
+ throw sdkError("STORE", resumed.error.message, {
182
+ cause: resumed.error.cause,
183
+ });
184
+ }
185
+ const traceSession = resumed.value;
186
+ if (!traceSession) return response;
187
+ const lines = response.returnedLines ?? {
188
+ start: 1,
189
+ end: response.totalLines,
190
+ };
191
+ const evidence = evidenceFromExactDocument({
192
+ docid: response.docid,
193
+ uri: response.uri,
194
+ sourceHash: response.source.sourceHash,
195
+ mirrorHash: response.conversion?.mirrorHash,
196
+ content: response.content,
197
+ startLine: lines.start,
198
+ endLine: lines.end,
199
+ });
200
+ if (evidence) {
201
+ const got = await traceSession.recordEvidence("get", [evidence]);
202
+ if (!got.ok) throw sdkError("STORE", got.error.message);
203
+ const opened = await traceSession.recordEvidence("open", [evidence]);
204
+ if (!opened.ok) throw sdkError("STORE", opened.error.message);
205
+ }
206
+ return attachRetrievalTraceMetadata(response, traceSession);
207
+ }
208
+
162
209
  function truncateContent(
163
210
  content: string,
164
211
  maxBytes: number
package/src/sdk/index.ts CHANGED
@@ -72,3 +72,20 @@ export {
72
72
  ContextRuntimeError,
73
73
  type ContextRuntimeErrorCode,
74
74
  } from "../app/context-runtime";
75
+ export {
76
+ getRetrievalTraceMetadata,
77
+ RETRIEVAL_TRACE_METADATA,
78
+ type RetrievalTraceSurfaceMetadata,
79
+ } from "../core/retrieval-trace-session";
80
+ export type {
81
+ RetrievalTraceDeleteResult,
82
+ RetrievalTraceDetail,
83
+ RetrievalTraceExportRequest,
84
+ RetrievalTraceExportResult,
85
+ RetrievalTraceLabelRequest,
86
+ RetrievalTraceLabelResult,
87
+ RetrievalTraceListRequest,
88
+ RetrievalTraceListResult,
89
+ RetrievalTracePurgeResult,
90
+ RetrievalTraceSummary,
91
+ } from "../core/retrieval-trace-management";