@gmickel/gno 1.19.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 (45) hide show
  1. package/README.md +12 -7
  2. package/assets/skill/SKILL.md +27 -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 +1 -1
  6. package/spec/cli.md +42 -17
  7. package/spec/evals-agentic.md +87 -5
  8. package/spec/mcp.md +53 -3
  9. package/spec/output-schemas/ask.schema.json +198 -0
  10. package/spec/output-schemas/claim-verification.schema.json +291 -0
  11. package/spec/output-schemas/context-capsule-v1.schema.json +36 -1
  12. package/src/app/context-runtime-contract.ts +10 -5
  13. package/src/app/context-runtime-input.ts +29 -1
  14. package/src/app/context-runtime-types.ts +4 -0
  15. package/src/app/context-runtime.ts +5 -1
  16. package/src/app/context-surface.ts +4 -0
  17. package/src/app/verified-ask.ts +291 -0
  18. package/src/cli/commands/ask-format.ts +255 -0
  19. package/src/cli/commands/ask.ts +40 -149
  20. package/src/cli/program.ts +32 -1
  21. package/src/core/context-budget.ts +6 -0
  22. package/src/core/context-capsule-retrieval-schema.ts +4 -0
  23. package/src/core/context-capsule-schema.ts +17 -0
  24. package/src/core/context-capsule-validation.ts +3 -2
  25. package/src/core/context-capsule.ts +18 -0
  26. package/src/core/context-compiler.ts +33 -21
  27. package/src/core/context-evidence.ts +6 -0
  28. package/src/core/retrieval-trace-evidence-origin.ts +3 -0
  29. package/src/core/retrieval-trace-session.ts +15 -2
  30. package/src/llm/errors.ts +10 -1
  31. package/src/llm/httpGeneration.ts +11 -1
  32. package/src/llm/nodeLlamaCpp/generation.ts +54 -10
  33. package/src/llm/types.ts +6 -0
  34. package/src/mcp/tools/ask.ts +228 -0
  35. package/src/mcp/tools/context.ts +28 -7
  36. package/src/mcp/tools/index.ts +9 -0
  37. package/src/pipeline/claim-verification-schema.ts +235 -0
  38. package/src/pipeline/claim-verification.ts +487 -0
  39. package/src/pipeline/claim-verifier.ts +474 -0
  40. package/src/pipeline/types.ts +25 -0
  41. package/src/sdk/client.ts +35 -2
  42. package/src/serve/public/components/AskVerificationPanel.tsx +189 -0
  43. package/src/serve/public/globals.built.css +1 -1
  44. package/src/serve/public/pages/Ask.tsx +42 -4
  45. package/src/serve/routes/api.ts +149 -3
@@ -4,7 +4,96 @@
4
4
  "title": "GNO Ask Response",
5
5
  "description": "Response from gno ask command",
6
6
  "type": "object",
7
+ "additionalProperties": false,
7
8
  "required": ["query", "mode", "results", "meta"],
9
+ "allOf": [
10
+ {
11
+ "if": {
12
+ "properties": { "verification": {} },
13
+ "required": ["verification"]
14
+ },
15
+ "then": {
16
+ "required": ["answer", "citations"],
17
+ "properties": {
18
+ "answer": {},
19
+ "citations": {
20
+ "type": "array",
21
+ "items": {
22
+ "type": "object",
23
+ "properties": { "evidenceId": {} },
24
+ "required": ["evidenceId"]
25
+ }
26
+ },
27
+ "meta": {
28
+ "type": "object",
29
+ "required": ["verificationRequested", "abstained"],
30
+ "properties": {
31
+ "verificationRequested": { "const": true },
32
+ "abstained": {}
33
+ }
34
+ }
35
+ }
36
+ }
37
+ },
38
+ {
39
+ "if": {
40
+ "properties": {
41
+ "meta": {
42
+ "type": "object",
43
+ "required": ["verificationRequested"],
44
+ "properties": { "verificationRequested": { "const": true } }
45
+ }
46
+ },
47
+ "required": ["meta"]
48
+ },
49
+ "then": {
50
+ "properties": { "verification": {} },
51
+ "required": ["verification"]
52
+ }
53
+ },
54
+ {
55
+ "if": {
56
+ "properties": {
57
+ "verification": {
58
+ "type": "object",
59
+ "properties": {
60
+ "claims": {
61
+ "type": "object",
62
+ "properties": { "answerStatus": { "const": "abstained" } },
63
+ "required": ["answerStatus"]
64
+ }
65
+ },
66
+ "required": ["claims"]
67
+ }
68
+ },
69
+ "required": ["verification"]
70
+ },
71
+ "then": {
72
+ "properties": {
73
+ "citations": { "type": "array", "maxItems": 0 },
74
+ "meta": {
75
+ "type": "object",
76
+ "properties": { "abstained": { "const": true } }
77
+ }
78
+ }
79
+ },
80
+ "else": {
81
+ "if": {
82
+ "properties": { "verification": {} },
83
+ "required": ["verification"]
84
+ },
85
+ "then": {
86
+ "properties": {
87
+ "citations": { "type": "array", "minItems": 1 },
88
+ "meta": {
89
+ "type": "object",
90
+ "properties": { "abstained": { "const": false } }
91
+ }
92
+ }
93
+ }
94
+ }
95
+ }
96
+ ],
8
97
  "$defs": {
9
98
  "searchResult": {
10
99
  "type": "object",
@@ -165,8 +254,13 @@
165
254
  "description": "Citations for the answer",
166
255
  "items": {
167
256
  "type": "object",
257
+ "additionalProperties": false,
168
258
  "required": ["docid", "uri"],
169
259
  "properties": {
260
+ "evidenceId": {
261
+ "type": "string",
262
+ "pattern": "^[a-f0-9]{64}$"
263
+ },
170
264
  "docid": {
171
265
  "type": "string",
172
266
  "description": "Document ID",
@@ -197,8 +291,106 @@
197
291
  "$ref": "#/$defs/searchResult"
198
292
  }
199
293
  },
294
+ "verification": {
295
+ "type": "object",
296
+ "additionalProperties": false,
297
+ "required": [
298
+ "schemaVersion",
299
+ "mode",
300
+ "capsule",
301
+ "freshness",
302
+ "claims",
303
+ "semantic"
304
+ ],
305
+ "properties": {
306
+ "schemaVersion": { "const": "1.0" },
307
+ "mode": { "const": "closed_capsule" },
308
+ "capsule": {
309
+ "$ref": "gno://schemas/context-capsule-v1@1.0"
310
+ },
311
+ "freshness": {
312
+ "$ref": "gno://schemas/context-capsule-verification@1.0"
313
+ },
314
+ "claims": {
315
+ "$ref": "gno://schemas/claim-verification@1.0"
316
+ },
317
+ "semantic": {
318
+ "type": "object",
319
+ "additionalProperties": false,
320
+ "required": [
321
+ "status",
322
+ "reason",
323
+ "schemaRequested",
324
+ "schemaEnforced",
325
+ "modelFingerprint",
326
+ "configFingerprint",
327
+ "verifierFingerprint",
328
+ "candidateClaims",
329
+ "verifiedClaims",
330
+ "unresolvedClaims",
331
+ "modelCalls",
332
+ "durationMs"
333
+ ],
334
+ "properties": {
335
+ "status": {
336
+ "enum": ["completed", "unavailable", "failed"]
337
+ },
338
+ "reason": {
339
+ "enum": [
340
+ "verified",
341
+ "no_candidates",
342
+ "verifier_unavailable",
343
+ "structured_output_unavailable",
344
+ "input_limit_exceeded",
345
+ "generation_failed",
346
+ "invalid_output"
347
+ ]
348
+ },
349
+ "schemaRequested": { "type": "boolean" },
350
+ "schemaEnforced": { "type": "boolean" },
351
+ "modelFingerprint": {
352
+ "oneOf": [
353
+ {
354
+ "type": "string",
355
+ "pattern": "^[a-f0-9]{64}$"
356
+ },
357
+ { "type": "null" }
358
+ ]
359
+ },
360
+ "configFingerprint": {
361
+ "type": "string",
362
+ "pattern": "^[a-f0-9]{64}$"
363
+ },
364
+ "verifierFingerprint": {
365
+ "oneOf": [
366
+ {
367
+ "type": "string",
368
+ "pattern": "^[a-f0-9]{64}$"
369
+ },
370
+ { "type": "null" }
371
+ ]
372
+ },
373
+ "candidateClaims": {
374
+ "type": "integer",
375
+ "minimum": 0
376
+ },
377
+ "verifiedClaims": {
378
+ "type": "integer",
379
+ "minimum": 0
380
+ },
381
+ "unresolvedClaims": {
382
+ "type": "integer",
383
+ "minimum": 0
384
+ },
385
+ "modelCalls": { "enum": [0, 1] },
386
+ "durationMs": { "type": "number", "minimum": 0 }
387
+ }
388
+ }
389
+ }
390
+ },
200
391
  "meta": {
201
392
  "type": "object",
393
+ "additionalProperties": false,
202
394
  "description": "Retrieval metadata",
203
395
  "required": ["expanded", "reranked", "vectorsUsed"],
204
396
  "properties": {
@@ -250,6 +442,12 @@
250
442
  "type": "boolean",
251
443
  "description": "Whether an answer was generated"
252
444
  },
445
+ "verificationRequested": {
446
+ "type": "boolean"
447
+ },
448
+ "abstained": {
449
+ "type": "boolean"
450
+ },
253
451
  "totalResults": {
254
452
  "type": "integer",
255
453
  "description": "Number of results returned",
@@ -0,0 +1,291 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "gno://schemas/claim-verification@1.0",
4
+ "title": "GNO Claim Verification Result",
5
+ "description": "Deterministic claim spans, Capsule-bound evidence, semantic verdicts, coverage, and abstention.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": [
9
+ "schemaVersion",
10
+ "coordinateSpace",
11
+ "capsuleId",
12
+ "answerHash",
13
+ "coverageThreshold",
14
+ "claims",
15
+ "rejectedCitations",
16
+ "coverage",
17
+ "answerStatus",
18
+ "abstained",
19
+ "abstentionReason",
20
+ "abstentionText"
21
+ ],
22
+ "properties": {
23
+ "schemaVersion": { "const": "1.0" },
24
+ "coordinateSpace": { "const": "utf16_code_units" },
25
+ "capsuleId": { "$ref": "#/definitions/sha256" },
26
+ "answerHash": { "$ref": "#/definitions/sha256" },
27
+ "coverageThreshold": { "const": 1 },
28
+ "claims": {
29
+ "type": "array",
30
+ "maxItems": 256,
31
+ "items": { "$ref": "#/definitions/claim" }
32
+ },
33
+ "rejectedCitations": {
34
+ "type": "array",
35
+ "maxItems": 256,
36
+ "items": { "$ref": "#/definitions/rejectedCitation" }
37
+ },
38
+ "coverage": { "$ref": "#/definitions/coverage" },
39
+ "answerStatus": { "enum": ["verified", "abstained"] },
40
+ "abstained": { "type": "boolean" },
41
+ "abstentionReason": {
42
+ "enum": [
43
+ "contradiction_detected",
44
+ "coverage_below_threshold",
45
+ "no_substantive_claims",
46
+ "citation_hygiene_failed",
47
+ null
48
+ ]
49
+ },
50
+ "abstentionText": { "type": ["string", "null"] }
51
+ },
52
+ "allOf": [
53
+ {
54
+ "if": { "properties": { "abstained": { "const": false } } },
55
+ "then": {
56
+ "properties": {
57
+ "answerStatus": { "const": "verified" },
58
+ "abstentionReason": { "type": "null" },
59
+ "abstentionText": { "type": "null" },
60
+ "rejectedCitations": { "type": "array", "maxItems": 0 },
61
+ "claims": {
62
+ "type": "array",
63
+ "not": {
64
+ "contains": {
65
+ "type": "object",
66
+ "required": ["rejectedCitations"],
67
+ "properties": {
68
+ "rejectedCitations": {
69
+ "type": "array",
70
+ "minItems": 1
71
+ }
72
+ }
73
+ }
74
+ }
75
+ },
76
+ "coverage": {
77
+ "type": "object",
78
+ "properties": {
79
+ "totalClaims": { "type": "integer", "minimum": 1 },
80
+ "supportedRatio": { "const": 1 },
81
+ "contradictedClaims": { "const": 0 },
82
+ "insufficientClaims": { "const": 0 },
83
+ "uncertainClaims": { "const": 0 }
84
+ }
85
+ }
86
+ }
87
+ }
88
+ },
89
+ {
90
+ "if": { "properties": { "abstained": { "const": true } } },
91
+ "then": {
92
+ "properties": {
93
+ "answerStatus": { "const": "abstained" },
94
+ "abstentionReason": { "type": "string" },
95
+ "abstentionText": { "type": "string", "minLength": 1 }
96
+ }
97
+ }
98
+ }
99
+ ],
100
+ "definitions": {
101
+ "sha256": { "type": "string", "pattern": "^[a-f0-9]{64}$" },
102
+ "evidenceReference": {
103
+ "type": "object",
104
+ "additionalProperties": false,
105
+ "required": [
106
+ "evidenceId",
107
+ "uri",
108
+ "startLine",
109
+ "endLine",
110
+ "text",
111
+ "sourceHash",
112
+ "mirrorHash",
113
+ "passageHash"
114
+ ],
115
+ "properties": {
116
+ "evidenceId": { "$ref": "#/definitions/sha256" },
117
+ "uri": {
118
+ "type": "string",
119
+ "maxLength": 2048,
120
+ "pattern": "^gno://"
121
+ },
122
+ "startLine": { "type": "integer", "minimum": 1 },
123
+ "endLine": { "type": "integer", "minimum": 1 },
124
+ "text": { "type": "string", "minLength": 1 },
125
+ "sourceHash": { "$ref": "#/definitions/sha256" },
126
+ "mirrorHash": { "$ref": "#/definitions/sha256" },
127
+ "passageHash": { "$ref": "#/definitions/sha256" }
128
+ }
129
+ },
130
+ "rejectedCitation": {
131
+ "type": "object",
132
+ "additionalProperties": false,
133
+ "required": ["marker", "start", "end", "evidenceId", "reason"],
134
+ "properties": {
135
+ "marker": { "type": "string", "minLength": 1 },
136
+ "start": { "type": "integer", "minimum": 0 },
137
+ "end": { "type": "integer", "minimum": 1 },
138
+ "evidenceId": {
139
+ "oneOf": [{ "$ref": "#/definitions/sha256" }, { "type": "null" }]
140
+ },
141
+ "reason": {
142
+ "enum": [
143
+ "malformed_citation",
144
+ "out_of_capsule",
145
+ "freshness_unavailable",
146
+ "freshness_receipt_invalid",
147
+ "freshness_receipt_mismatch",
148
+ "evidence_stale",
149
+ "evidence_missing",
150
+ "orphan_citation"
151
+ ]
152
+ }
153
+ }
154
+ },
155
+ "claim": {
156
+ "type": "object",
157
+ "additionalProperties": false,
158
+ "required": [
159
+ "claimId",
160
+ "text",
161
+ "start",
162
+ "end",
163
+ "status",
164
+ "confidence",
165
+ "rationaleCode",
166
+ "verifierFingerprint",
167
+ "evidence",
168
+ "rejectedCitations"
169
+ ],
170
+ "properties": {
171
+ "claimId": { "$ref": "#/definitions/sha256" },
172
+ "text": { "type": "string", "minLength": 1 },
173
+ "start": { "type": "integer", "minimum": 0 },
174
+ "end": { "type": "integer", "minimum": 1 },
175
+ "status": {
176
+ "enum": ["supported", "contradicted", "insufficient", "uncertain"]
177
+ },
178
+ "confidence": {
179
+ "oneOf": [
180
+ { "type": "number", "minimum": 0, "maximum": 1 },
181
+ { "type": "null" }
182
+ ]
183
+ },
184
+ "rationaleCode": {
185
+ "enum": [
186
+ "semantic_entailment",
187
+ "semantic_contradiction",
188
+ "no_valid_evidence",
189
+ "semantic_judgment_unavailable"
190
+ ]
191
+ },
192
+ "verifierFingerprint": {
193
+ "oneOf": [{ "$ref": "#/definitions/sha256" }, { "type": "null" }]
194
+ },
195
+ "evidence": {
196
+ "type": "array",
197
+ "maxItems": 256,
198
+ "items": { "$ref": "#/definitions/evidenceReference" }
199
+ },
200
+ "rejectedCitations": {
201
+ "type": "array",
202
+ "maxItems": 256,
203
+ "items": { "$ref": "#/definitions/rejectedCitation" }
204
+ }
205
+ },
206
+ "allOf": [
207
+ {
208
+ "if": {
209
+ "properties": {
210
+ "status": { "enum": ["supported", "contradicted"] }
211
+ }
212
+ },
213
+ "then": {
214
+ "properties": {
215
+ "confidence": { "type": "number" },
216
+ "verifierFingerprint": { "$ref": "#/definitions/sha256" },
217
+ "evidence": { "type": "array", "minItems": 1 }
218
+ }
219
+ }
220
+ },
221
+ {
222
+ "if": { "properties": { "status": { "const": "supported" } } },
223
+ "then": {
224
+ "properties": {
225
+ "rationaleCode": { "const": "semantic_entailment" }
226
+ }
227
+ }
228
+ },
229
+ {
230
+ "if": { "properties": { "status": { "const": "contradicted" } } },
231
+ "then": {
232
+ "properties": {
233
+ "rationaleCode": { "const": "semantic_contradiction" }
234
+ }
235
+ }
236
+ },
237
+ {
238
+ "if": {
239
+ "properties": {
240
+ "status": { "enum": ["insufficient", "uncertain"] }
241
+ }
242
+ },
243
+ "then": {
244
+ "properties": {
245
+ "confidence": { "type": "null" },
246
+ "verifierFingerprint": { "type": "null" }
247
+ }
248
+ }
249
+ },
250
+ {
251
+ "if": { "properties": { "status": { "const": "insufficient" } } },
252
+ "then": {
253
+ "properties": {
254
+ "rationaleCode": { "const": "no_valid_evidence" },
255
+ "evidence": { "type": "array", "maxItems": 0 }
256
+ }
257
+ }
258
+ },
259
+ {
260
+ "if": { "properties": { "status": { "const": "uncertain" } } },
261
+ "then": {
262
+ "properties": {
263
+ "rationaleCode": { "const": "semantic_judgment_unavailable" },
264
+ "evidence": { "type": "array", "minItems": 1 }
265
+ }
266
+ }
267
+ }
268
+ ]
269
+ },
270
+ "coverage": {
271
+ "type": "object",
272
+ "additionalProperties": false,
273
+ "required": [
274
+ "totalClaims",
275
+ "supportedClaims",
276
+ "contradictedClaims",
277
+ "insufficientClaims",
278
+ "uncertainClaims",
279
+ "supportedRatio"
280
+ ],
281
+ "properties": {
282
+ "totalClaims": { "type": "integer", "minimum": 0 },
283
+ "supportedClaims": { "type": "integer", "minimum": 0 },
284
+ "contradictedClaims": { "type": "integer", "minimum": 0 },
285
+ "insufficientClaims": { "type": "integer", "minimum": 0 },
286
+ "uncertainClaims": { "type": "integer", "minimum": 0 },
287
+ "supportedRatio": { "type": "number", "minimum": 0, "maximum": 1 }
288
+ }
289
+ }
290
+ }
291
+ }
@@ -196,6 +196,23 @@
196
196
  { "type": "null" }
197
197
  ]
198
198
  },
199
+ "intent": {
200
+ "oneOf": [
201
+ { "type": "string", "minLength": 1, "maxLength": 16384 },
202
+ { "type": "null" }
203
+ ]
204
+ },
205
+ "exclude": {
206
+ "type": "array",
207
+ "maxItems": 128,
208
+ "items": { "type": "string", "minLength": 1, "maxLength": 256 }
209
+ },
210
+ "minScore": {
211
+ "oneOf": [
212
+ { "type": "number", "minimum": 0, "maximum": 1 },
213
+ { "type": "null" }
214
+ ]
215
+ },
199
216
  "queryModes": {
200
217
  "type": "array",
201
218
  "maxItems": 128,
@@ -203,7 +220,8 @@
203
220
  },
204
221
  "limit": { "type": "integer", "minimum": 1 },
205
222
  "candidateLimit": { "type": "integer", "minimum": 1 },
206
- "graphRequested": { "type": "boolean" }
223
+ "graphRequested": { "type": "boolean" },
224
+ "rerankRequested": { "type": "boolean" }
207
225
  }
208
226
  },
209
227
  "capabilityStates": {
@@ -538,6 +556,23 @@
538
556
  },
539
557
  "retrievalRank": { "type": "integer", "minimum": 1 },
540
558
  "selectionRank": { "type": "integer", "minimum": 1 },
559
+ "retrievalSources": {
560
+ "type": "array",
561
+ "minItems": 1,
562
+ "maxItems": 6,
563
+ "uniqueItems": true,
564
+ "items": {
565
+ "enum": [
566
+ "bm25",
567
+ "vector",
568
+ "bm25_variant",
569
+ "vector_variant",
570
+ "hyde",
571
+ "graph"
572
+ ]
573
+ }
574
+ },
575
+ "graphExpanded": { "type": "boolean" },
541
576
  "facets": { "$ref": "#/definitions/facets" },
542
577
  "trust": { "const": "untrusted" },
543
578
  "egress": {
@@ -24,8 +24,9 @@ import { resolveModelUri } from "../llm/registry";
24
24
  const fingerprint = (value: unknown): string =>
25
25
  sha256Text(canonicalVerifierJson(value));
26
26
 
27
- const configFingerprint = (deps: ContextCapsuleRuntimeDeps): string =>
28
- fingerprint(deps.config);
27
+ export const contextRuntimeConfigFingerprint = (
28
+ deps: Pick<ContextCapsuleRuntimeDeps, "config">
29
+ ): string => fingerprint(deps.config);
29
30
 
30
31
  const configuredContextFingerprint = (
31
32
  deps: ContextCapsuleRuntimeDeps
@@ -75,7 +76,7 @@ const capsuleCapabilityStates = (
75
76
  ["embedding_unavailable"]
76
77
  ),
77
78
  reranking: capabilityState(
78
- input.depthPolicy !== "fast",
79
+ input.depthPolicy !== "fast" && !input.noRerank,
79
80
  draft.retrieval.reranked,
80
81
  ["reranking_unavailable"]
81
82
  ),
@@ -191,10 +192,14 @@ export const projectContextCapsule = (
191
192
  request: {
192
193
  author: input.author,
193
194
  lang: input.lang,
195
+ intent: input.intent,
196
+ exclude: input.exclude,
197
+ minScore: input.minScore,
194
198
  queryModes: input.queryModes,
195
199
  limit: input.limit,
196
200
  candidateLimit: input.candidateLimit,
197
201
  graphRequested: input.graph,
202
+ rerankRequested: input.depthPolicy !== "fast" && !input.noRerank,
198
203
  },
199
204
  capabilityStates,
200
205
  indexSnapshot: {
@@ -221,7 +226,7 @@ export const projectContextCapsule = (
221
226
  : null,
222
227
  },
223
228
  fingerprints: {
224
- config: configFingerprint(deps),
229
+ config: contextRuntimeConfigFingerprint(deps),
225
230
  retrieval: retrievalFingerprint(base, snapshots.contextFingerprint),
226
231
  embeddingModel: capabilities.semanticSearch
227
232
  ? sha256Text(deps.embedPort?.modelUri ?? "")
@@ -292,7 +297,7 @@ export const currentContextFingerprints = (
292
297
  capsule: ContextCapsuleV1,
293
298
  deps: ContextCapsuleRuntimeDeps
294
299
  ) => ({
295
- config: configFingerprint(deps),
300
+ config: contextRuntimeConfigFingerprint(deps),
296
301
  retrieval: retrievalFingerprint(capsule, configuredContextFingerprint(deps)),
297
302
  embeddingModel: capsule.capabilities.semanticSearch
298
303
  ? sha256Text(
@@ -315,16 +315,40 @@ export const normalizeContextBuildInput = (
315
315
  "Context graph flag must be boolean"
316
316
  );
317
317
  }
318
+ if (input.noRerank !== undefined && typeof input.noRerank !== "boolean") {
319
+ throw new ContextRuntimeError(
320
+ "invalid_filter",
321
+ "Context noRerank flag must be boolean"
322
+ );
323
+ }
324
+ if (
325
+ input.minScore !== undefined &&
326
+ (typeof input.minScore !== "number" ||
327
+ !Number.isFinite(input.minScore) ||
328
+ input.minScore < 0 ||
329
+ input.minScore > 1)
330
+ ) {
331
+ throw new ContextRuntimeError(
332
+ "invalid_filter",
333
+ "Context minimum score must be between 0 and 1"
334
+ );
335
+ }
318
336
  const author =
319
337
  typeof input.author === "string"
320
338
  ? input.author.normalize("NFC").trim()
321
339
  : null;
322
340
  const lang =
323
341
  typeof input.lang === "string" ? input.lang.normalize("NFC").trim() : null;
342
+ const intent =
343
+ typeof input.intent === "string"
344
+ ? input.intent.normalize("NFC").trim()
345
+ : null;
324
346
  if (
325
347
  (input.author !== undefined &&
326
348
  (!author || author.length > MAX_FILTER_LENGTH)) ||
327
- (input.lang !== undefined && (!lang || !isValidLanguageHint(lang)))
349
+ (input.lang !== undefined && (!lang || !isValidLanguageHint(lang))) ||
350
+ (input.intent !== undefined &&
351
+ (!intent || intent.length > MAX_TEXT_LENGTH || intent.includes("\r")))
328
352
  ) {
329
353
  throw new ContextRuntimeError(
330
354
  "invalid_filter",
@@ -344,9 +368,13 @@ export const normalizeContextBuildInput = (
344
368
  categories: canonicalFilters(input.categories, "categories"),
345
369
  author,
346
370
  lang,
371
+ intent,
372
+ exclude: canonicalFilters(input.exclude, "exclude"),
373
+ minScore: input.minScore ?? null,
347
374
  since: temporalRange.since,
348
375
  until: temporalRange.until,
349
376
  graph: input.graph ?? false,
377
+ noRerank: input.noRerank ?? false,
350
378
  limit,
351
379
  candidateLimit,
352
380
  budgetTokens,