nexus-ai-pro 2.20.2 → 2.22.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 (233) hide show
  1. package/API_STABILITY.md +93 -0
  2. package/CHANGELOG.md +208 -1
  3. package/README.md +11 -6
  4. package/SECURITY.md +16 -2
  5. package/dist/adapter-kit/gather.d.ts +76 -0
  6. package/dist/adapter-kit/gather.js +147 -0
  7. package/dist/adapter-kit/index.d.ts +1 -0
  8. package/dist/adapter-kit/index.js +1 -0
  9. package/dist/adapter-kit/record.d.ts +3 -1
  10. package/dist/adapter-kit/record.js +20 -5
  11. package/dist/agent/openapi.d.ts +94 -8
  12. package/dist/agent/openapi.js +528 -32
  13. package/dist/cli/adapters.d.ts +4 -3
  14. package/dist/cli/adapters.js +71 -2
  15. package/dist/cli/doctor.js +3 -0
  16. package/dist/cli.js +3 -1
  17. package/dist/core/config-builder.d.ts +1 -0
  18. package/dist/core/config-builder.js +1 -0
  19. package/dist/core/defaults.d.ts +34 -0
  20. package/dist/core/defaults.js +39 -0
  21. package/dist/core/secure-stream.js +4 -1
  22. package/dist/decisions/completion.d.ts +10 -7
  23. package/dist/decisions/completion.js +82 -8
  24. package/dist/decisions/core.d.ts +88 -43
  25. package/dist/decisions/core.js +115 -28
  26. package/dist/decisions/errors.d.ts +25 -0
  27. package/dist/decisions/errors.js +12 -0
  28. package/dist/decisions/index.d.ts +6 -5
  29. package/dist/decisions/index.js +2 -1
  30. package/dist/decisions/integrations.d.ts +14 -5
  31. package/dist/decisions/integrations.js +16 -1
  32. package/dist/decisions/mock.d.ts +5 -3
  33. package/dist/decisions/mock.js +4 -1
  34. package/dist/decisions/pictures.d.ts +43 -0
  35. package/dist/decisions/pictures.js +103 -0
  36. package/dist/decisions/typesafe.d.ts +33 -5
  37. package/dist/decisions/typesafe.js +121 -8
  38. package/dist/doctor/index.d.ts +6 -9
  39. package/dist/doctor/index.js +41 -0
  40. package/dist/embeddings/adapters.d.ts +1 -1
  41. package/dist/embeddings/adapters.js +3 -3
  42. package/dist/embeddings/batch-google.d.ts +27 -8
  43. package/dist/embeddings/batch-google.js +112 -36
  44. package/dist/embeddings/batch-mock.js +1 -1
  45. package/dist/embeddings/batch.js +10 -4
  46. package/dist/embeddings/engine.js +14 -13
  47. package/dist/embeddings/index.d.ts +1 -1
  48. package/dist/embeddings/inputs.d.ts +26 -3
  49. package/dist/embeddings/inputs.js +84 -5
  50. package/dist/embeddings/mock.js +1 -1
  51. package/dist/embeddings/models.js +39 -4
  52. package/dist/loaders/csv.d.ts +23 -1
  53. package/dist/loaders/csv.js +125 -72
  54. package/dist/loaders/index.d.ts +7 -2
  55. package/dist/loaders/input.d.ts +6 -0
  56. package/dist/loaders/input.js +42 -1
  57. package/dist/loaders/json.d.ts +14 -3
  58. package/dist/loaders/json.js +171 -20
  59. package/dist/loaders/web.d.ts +55 -0
  60. package/dist/loaders/web.js +20 -1
  61. package/dist/mcp/client.d.ts +54 -5
  62. package/dist/mcp/client.js +171 -20
  63. package/dist/mcp/http.d.ts +45 -0
  64. package/dist/mcp/http.js +233 -0
  65. package/dist/mcp/index.d.ts +4 -2
  66. package/dist/mcp/index.js +3 -1
  67. package/dist/mcp/protocol.d.ts +107 -0
  68. package/dist/mcp/sampling.d.ts +41 -0
  69. package/dist/mcp/sampling.js +52 -0
  70. package/dist/mcp/server.d.ts +96 -14
  71. package/dist/mcp/server.js +274 -59
  72. package/dist/models/data.js +20 -1
  73. package/dist/operations/adapters.d.ts +1 -0
  74. package/dist/operations/adapters.js +3 -1
  75. package/dist/protocols/a2a-grpc.js +10 -3
  76. package/dist/protocols/a2a-signing.d.ts +65 -0
  77. package/dist/protocols/a2a-signing.js +133 -0
  78. package/dist/protocols/a2a.d.ts +14 -0
  79. package/dist/protocols/a2a.js +60 -5
  80. package/dist/providers/cohere.js +16 -2
  81. package/dist/providers/google.js +7 -1
  82. package/dist/providers/ollama.d.ts +1 -1
  83. package/dist/providers/ollama.js +35 -27
  84. package/dist/providers/openai.js +19 -2
  85. package/dist/rag/pinecone.d.ts +63 -2
  86. package/dist/rag/pinecone.js +80 -0
  87. package/dist/realtime/conversation.js +18 -0
  88. package/dist/realtime/gemini-live.transport.d.ts +28 -3
  89. package/dist/realtime/gemini-live.transport.js +170 -32
  90. package/dist/realtime/session.d.ts +2 -0
  91. package/dist/realtime/session.js +19 -4
  92. package/dist/realtime/types.d.ts +35 -3
  93. package/dist/security/output-guard.js +4 -1
  94. package/dist/server/auth.d.ts +263 -2
  95. package/dist/server/auth.js +432 -5
  96. package/dist/server/deployments.d.ts +3 -2
  97. package/dist/server/deployments.js +6 -1
  98. package/dist/telephony/index.d.ts +1 -1
  99. package/dist/telephony/manager.d.ts +8 -1
  100. package/dist/telephony/manager.js +13 -0
  101. package/dist/telephony/providers/telnyx.d.ts +18 -5
  102. package/dist/telephony/providers/telnyx.js +44 -7
  103. package/dist/telephony/providers/twilio.d.ts +3 -1
  104. package/dist/telephony/providers/twilio.js +16 -0
  105. package/dist/tracing/stores.d.ts +2 -0
  106. package/dist/tracing/stores.js +1 -0
  107. package/dist/tracing/tracer.d.ts +5 -2
  108. package/dist/tracing/tracer.js +6 -3
  109. package/dist/types/embeddings.d.ts +47 -5
  110. package/dist/types/messages.d.ts +7 -0
  111. package/dist/types/principal.d.ts +1 -1
  112. package/dist/types/response.d.ts +5 -0
  113. package/dist/types/telephony.d.ts +38 -0
  114. package/dist/types/tracing.d.ts +6 -0
  115. package/dist/version.d.ts +1 -1
  116. package/dist/version.js +1 -1
  117. package/dist/voice/providers/google.d.ts +44 -0
  118. package/dist/voice/providers/google.js +215 -0
  119. package/dist-cjs/adapter-kit/gather.d.ts +76 -0
  120. package/dist-cjs/adapter-kit/gather.js +152 -0
  121. package/dist-cjs/adapter-kit/index.d.ts +1 -0
  122. package/dist-cjs/adapter-kit/index.js +4 -1
  123. package/dist-cjs/adapter-kit/record.d.ts +3 -1
  124. package/dist-cjs/adapter-kit/record.js +20 -5
  125. package/dist-cjs/agent/openapi.d.ts +94 -8
  126. package/dist-cjs/agent/openapi.js +530 -32
  127. package/dist-cjs/cli/adapters.d.ts +4 -3
  128. package/dist-cjs/cli/adapters.js +70 -1
  129. package/dist-cjs/cli/doctor.js +3 -0
  130. package/dist-cjs/core/config-builder.d.ts +1 -0
  131. package/dist-cjs/core/config-builder.js +5 -1
  132. package/dist-cjs/core/defaults.d.ts +34 -0
  133. package/dist-cjs/core/defaults.js +44 -0
  134. package/dist-cjs/core/secure-stream.js +4 -1
  135. package/dist-cjs/decisions/completion.d.ts +10 -7
  136. package/dist-cjs/decisions/completion.js +81 -7
  137. package/dist-cjs/decisions/core.d.ts +88 -43
  138. package/dist-cjs/decisions/core.js +134 -46
  139. package/dist-cjs/decisions/errors.d.ts +25 -0
  140. package/dist-cjs/decisions/errors.js +16 -0
  141. package/dist-cjs/decisions/index.d.ts +6 -5
  142. package/dist-cjs/decisions/index.js +5 -1
  143. package/dist-cjs/decisions/integrations.d.ts +14 -5
  144. package/dist-cjs/decisions/integrations.js +16 -1
  145. package/dist-cjs/decisions/mock.d.ts +5 -3
  146. package/dist-cjs/decisions/mock.js +4 -1
  147. package/dist-cjs/decisions/pictures.d.ts +43 -0
  148. package/dist-cjs/decisions/pictures.js +109 -0
  149. package/dist-cjs/decisions/typesafe.d.ts +33 -5
  150. package/dist-cjs/decisions/typesafe.js +126 -13
  151. package/dist-cjs/doctor/index.d.ts +6 -9
  152. package/dist-cjs/doctor/index.js +41 -0
  153. package/dist-cjs/embeddings/adapters.d.ts +1 -1
  154. package/dist-cjs/embeddings/adapters.js +3 -3
  155. package/dist-cjs/embeddings/batch-google.d.ts +27 -8
  156. package/dist-cjs/embeddings/batch-google.js +112 -36
  157. package/dist-cjs/embeddings/batch-mock.js +1 -1
  158. package/dist-cjs/embeddings/batch.js +9 -3
  159. package/dist-cjs/embeddings/engine.js +13 -12
  160. package/dist-cjs/embeddings/index.d.ts +1 -1
  161. package/dist-cjs/embeddings/inputs.d.ts +26 -3
  162. package/dist-cjs/embeddings/inputs.js +89 -5
  163. package/dist-cjs/embeddings/mock.js +1 -1
  164. package/dist-cjs/embeddings/models.js +39 -4
  165. package/dist-cjs/loaders/csv.d.ts +23 -1
  166. package/dist-cjs/loaders/csv.js +126 -71
  167. package/dist-cjs/loaders/index.d.ts +7 -2
  168. package/dist-cjs/loaders/input.d.ts +6 -0
  169. package/dist-cjs/loaders/input.js +43 -1
  170. package/dist-cjs/loaders/json.d.ts +14 -3
  171. package/dist-cjs/loaders/json.js +170 -19
  172. package/dist-cjs/loaders/web.d.ts +55 -0
  173. package/dist-cjs/loaders/web.js +21 -1
  174. package/dist-cjs/mcp/client.d.ts +54 -5
  175. package/dist-cjs/mcp/client.js +171 -20
  176. package/dist-cjs/mcp/http.d.ts +45 -0
  177. package/dist-cjs/mcp/http.js +236 -0
  178. package/dist-cjs/mcp/index.d.ts +4 -2
  179. package/dist-cjs/mcp/index.js +5 -1
  180. package/dist-cjs/mcp/protocol.d.ts +107 -0
  181. package/dist-cjs/mcp/sampling.d.ts +41 -0
  182. package/dist-cjs/mcp/sampling.js +55 -0
  183. package/dist-cjs/mcp/server.d.ts +96 -14
  184. package/dist-cjs/mcp/server.js +273 -58
  185. package/dist-cjs/models/data.js +20 -1
  186. package/dist-cjs/operations/adapters.d.ts +1 -0
  187. package/dist-cjs/operations/adapters.js +3 -1
  188. package/dist-cjs/protocols/a2a-grpc.js +10 -3
  189. package/dist-cjs/protocols/a2a-signing.d.ts +65 -0
  190. package/dist-cjs/protocols/a2a-signing.js +140 -0
  191. package/dist-cjs/protocols/a2a.d.ts +14 -0
  192. package/dist-cjs/protocols/a2a.js +65 -6
  193. package/dist-cjs/providers/cohere.js +16 -2
  194. package/dist-cjs/providers/google.js +7 -1
  195. package/dist-cjs/providers/ollama.d.ts +1 -1
  196. package/dist-cjs/providers/ollama.js +35 -27
  197. package/dist-cjs/providers/openai.js +19 -2
  198. package/dist-cjs/rag/pinecone.d.ts +63 -2
  199. package/dist-cjs/rag/pinecone.js +81 -0
  200. package/dist-cjs/realtime/conversation.js +18 -0
  201. package/dist-cjs/realtime/gemini-live.transport.d.ts +28 -3
  202. package/dist-cjs/realtime/gemini-live.transport.js +170 -32
  203. package/dist-cjs/realtime/session.d.ts +2 -0
  204. package/dist-cjs/realtime/session.js +19 -4
  205. package/dist-cjs/realtime/types.d.ts +35 -3
  206. package/dist-cjs/security/output-guard.js +4 -1
  207. package/dist-cjs/server/auth.d.ts +263 -2
  208. package/dist-cjs/server/auth.js +437 -5
  209. package/dist-cjs/server/deployments.d.ts +3 -2
  210. package/dist-cjs/server/deployments.js +6 -1
  211. package/dist-cjs/telephony/index.d.ts +1 -1
  212. package/dist-cjs/telephony/manager.d.ts +8 -1
  213. package/dist-cjs/telephony/manager.js +13 -0
  214. package/dist-cjs/telephony/providers/telnyx.d.ts +18 -5
  215. package/dist-cjs/telephony/providers/telnyx.js +44 -7
  216. package/dist-cjs/telephony/providers/twilio.d.ts +3 -1
  217. package/dist-cjs/telephony/providers/twilio.js +16 -0
  218. package/dist-cjs/tracing/stores.d.ts +2 -0
  219. package/dist-cjs/tracing/stores.js +1 -0
  220. package/dist-cjs/tracing/tracer.d.ts +5 -2
  221. package/dist-cjs/tracing/tracer.js +6 -3
  222. package/dist-cjs/types/embeddings.d.ts +47 -5
  223. package/dist-cjs/types/messages.d.ts +7 -0
  224. package/dist-cjs/types/principal.d.ts +1 -1
  225. package/dist-cjs/types/response.d.ts +5 -0
  226. package/dist-cjs/types/telephony.d.ts +38 -0
  227. package/dist-cjs/types/tracing.d.ts +6 -0
  228. package/dist-cjs/version.d.ts +1 -1
  229. package/dist-cjs/version.js +1 -1
  230. package/dist-cjs/voice/providers/google.d.ts +44 -0
  231. package/dist-cjs/voice/providers/google.js +252 -0
  232. package/llms.txt +1 -1
  233. package/package.json +17 -1
@@ -1,13 +1,18 @@
1
1
  /**
2
- * Typed decisions: questions a model answers with a yes or no, a choice, or a score, each with its
3
- * probabilities and a confidence read from them, so software acts on an answer without parsing text.
2
+ * Typed decisions: questions a model answers with a yes or no, a choice, a score, or a box around
3
+ * something in a picture, each with a confidence read alike from any provider, so software acts on an
4
+ * answer without parsing text.
4
5
  */
5
6
  import type { CacheAdapter } from '../cache/adapters.js';
7
+ import type { ImageContent } from '../types/messages.js';
6
8
  import type { OperationLifecycleLike, ProviderCallContext } from '../types/lifecycle.js';
7
9
  import type { ResponseCost } from '../types/response.js';
8
10
  import type { RunKind } from '../types/tracing.js';
9
- /** The kinds of question there are: a yes or no, a choice among options, or a score on levels. */
10
- export type DecisionQuestionType = 'yes-no' | 'choice' | 'score';
11
+ /**
12
+ * The kinds of question there are: a yes or no, a choice among options, a score on levels, or a box
13
+ * around something in a picture.
14
+ */
15
+ export type DecisionQuestionType = 'yes-no' | 'choice' | 'score' | 'box';
11
16
  /** A question answered yes or no, with the probability that it is yes. */
12
17
  export interface YesNoQuestion {
13
18
  /** Discriminates the question. */
@@ -38,12 +43,40 @@ export interface ScoreQuestion {
38
43
  /** What each level means, lowest first. Two to ten. */
39
44
  levels: readonly string[];
40
45
  }
46
+ /** A question answered with where something is in a picture of the state: a box around it. */
47
+ export interface BoxQuestion {
48
+ /** Discriminates the question. */
49
+ type: 'box';
50
+ /**
51
+ * What to find, and in which picture, by its path in backticks, such as "the dent in `photo`". A box
52
+ * is given even for something the picture does not show: ask a yes or no beside it whether it does.
53
+ */
54
+ question: string;
55
+ }
41
56
  /** Any question. */
42
- export type DecisionQuestion = YesNoQuestion | ChoiceQuestion | ScoreQuestion;
57
+ export type DecisionQuestion = YesNoQuestion | ChoiceQuestion | ScoreQuestion | BoxQuestion;
43
58
  /** Questions by the names their answers come back under. */
44
59
  export type DecisionQuestions = Record<string, DecisionQuestion>;
45
- /** What every question of a decision is about: text, or any JSON value. */
60
+ /**
61
+ * What every question of a decision is about: text, or any JSON value. An object or a list may hold
62
+ * pictures, as image parts (`{ type: 'image', source }`) or image assets, anywhere in it; a question
63
+ * names each by its path in backticks, such as `photo` or `frames[2].frame`.
64
+ */
46
65
  export type DecisionState = string | Record<string, unknown> | readonly unknown[];
66
+ /**
67
+ * Where something is in a picture: each edge a fraction, from 0 to 1, of the picture's height (`top`,
68
+ * `bottom`) or width (`left`, `right`), measured from its top-left corner.
69
+ */
70
+ export interface DecisionBox {
71
+ /** The top edge, from the picture's top. */
72
+ top: number;
73
+ /** The bottom edge, from the picture's top: at least `top`. */
74
+ bottom: number;
75
+ /** The left edge, from the picture's left. */
76
+ left: number;
77
+ /** The right edge, from the picture's left: at least `left`. */
78
+ right: number;
79
+ }
47
80
  /** A yes-or-no question's answer. */
48
81
  export interface YesNoAnswer {
49
82
  /** Discriminates the answer. */
@@ -86,15 +119,27 @@ export interface ScoreAnswer {
86
119
  */
87
120
  confidence: number;
88
121
  }
122
+ /** A box question's answer. */
123
+ export interface BoxAnswer {
124
+ /** Discriminates the answer. */
125
+ type: 'box';
126
+ /** Where it is. */
127
+ box: DecisionBox;
128
+ /**
129
+ * How sure the answer is, from 0 to 1: the provider's own, such as TypeSafe AI's Jev gives, or how
130
+ * far several readings of the box agree, for a model asked more than once.
131
+ */
132
+ confidence: number;
133
+ }
89
134
  /** Any answer. */
90
- export type DecisionAnswer = YesNoAnswer | ChoiceAnswer | ScoreAnswer;
135
+ export type DecisionAnswer = YesNoAnswer | ChoiceAnswer | ScoreAnswer | BoxAnswer;
91
136
  /** The options of a choice question, as a union of their names. */
92
137
  type OptionsOf<O> = O extends readonly (infer K)[] ? K : keyof O;
93
138
  /** The answer a question gets: a choice's answer names only its options. */
94
139
  export type AnswerOf<Q> = Q extends YesNoQuestion ? YesNoAnswer : Q extends {
95
140
  type: 'choice';
96
141
  options: infer O;
97
- } ? ChoiceAnswer<Extract<OptionsOf<O>, string>> : Q extends ScoreQuestion ? ScoreAnswer : DecisionAnswer;
142
+ } ? ChoiceAnswer<Extract<OptionsOf<O>, string>> : Q extends ScoreQuestion ? ScoreAnswer : Q extends BoxQuestion ? BoxAnswer : DecisionAnswer;
98
143
  /** Answers by their questions' names, each typed by its question. */
99
144
  export type DecisionAnswers<Q extends DecisionQuestions> = {
100
145
  [K in keyof Q]: AnswerOf<Q[K]>;
@@ -152,12 +197,12 @@ export type DecisionProviderQuestion = YesNoQuestion | {
152
197
  name: string;
153
198
  description?: string;
154
199
  }>;
155
- } | ScoreQuestion;
200
+ } | ScoreQuestion | BoxQuestion;
156
201
  /** What a provider is asked. */
157
202
  export interface DecisionProviderRequest {
158
203
  /** The model to ask. */
159
204
  model: string;
160
- /** What every question is about. */
205
+ /** What every question is about, with any pictures it holds, which `statePictures()` lists. */
161
206
  state: DecisionState;
162
207
  /** The questions, by name. */
163
208
  questions: Record<string, DecisionProviderQuestion>;
@@ -172,6 +217,10 @@ export type DecisionDistribution = {
172
217
  } | {
173
218
  type: 'score';
174
219
  probabilities: readonly number[];
220
+ } | {
221
+ type: 'box';
222
+ box: DecisionBox;
223
+ confidence: number;
175
224
  };
176
225
  /** What a provider answers. */
177
226
  export interface DecisionProviderResult {
@@ -194,6 +243,8 @@ export interface DecisionProviderCapabilities {
194
243
  maxLevels: number;
195
244
  /** Most questions one decision may ask, when it has a limit. */
196
245
  maxQuestions?: number;
246
+ /** Whether it reads the pictures a state holds. A provider without it is not asked about a picture. */
247
+ images?: boolean;
197
248
  /** The model asked when a request names none. */
198
249
  defaultModel: string;
199
250
  /** The models it serves, when it lists them. */
@@ -232,30 +283,7 @@ export interface DecisionProvider {
232
283
  /** Answers every question of a decision. */
233
284
  decide(request: DecisionProviderRequest, context: DecisionCallContext): Promise<DecisionProviderResult>;
234
285
  }
235
- /** Why a decision failed. */
236
- export type DecisionErrorCode = 'DECISION_NO_PROVIDER' | 'DECISION_UNSUPPORTED' | 'DECISION_INVALID' | 'DECISION_FAILED';
237
- /** Raised for a decision no provider can serve, a question that is malformed, or a provider's failure. */
238
- export declare class DecisionError extends Error {
239
- /**
240
- * A stable code: `DECISION_NO_PROVIDER`, `DECISION_UNSUPPORTED` (a provider cannot take the
241
- * question), `DECISION_INVALID` (the request, or an answer, is malformed), or `DECISION_FAILED`.
242
- */
243
- readonly code: DecisionErrorCode;
244
- /** Whether asking again, or another provider, may help: a timeout or an overloaded service may. */
245
- readonly retryable: boolean;
246
- /** The HTTP status a provider answered with, when it did. */
247
- readonly status?: number | undefined;
248
- constructor(message: string,
249
- /**
250
- * A stable code: `DECISION_NO_PROVIDER`, `DECISION_UNSUPPORTED` (a provider cannot take the
251
- * question), `DECISION_INVALID` (the request, or an answer, is malformed), or `DECISION_FAILED`.
252
- */
253
- code: DecisionErrorCode,
254
- /** Whether asking again, or another provider, may help: a timeout or an overloaded service may. */
255
- retryable?: boolean,
256
- /** The HTTP status a provider answered with, when it did. */
257
- status?: number | undefined);
258
- }
286
+ export { DecisionError, type DecisionErrorCode } from './errors.js';
259
287
  /** A yes-or-no answer's confidence: how far its probability is from an even chance, `|2p - 1|`. */
260
288
  export declare function yesNoConfidence(probability: number): number;
261
289
  /**
@@ -275,6 +303,11 @@ export declare function scoreConfidence(probabilities: readonly number[]): numbe
275
303
  * `DECISION_INVALID` for probabilities that do not fit the question.
276
304
  */
277
305
  export declare function decisionAnswer(question: DecisionProviderQuestion, distribution: DecisionDistribution): DecisionAnswer;
306
+ /**
307
+ * How far two boxes overlap, from 0 to 1: the area they share over the area they cover together, the
308
+ * intersection over union by which a box is judged against where the thing is.
309
+ */
310
+ export declare function boxOverlap(a: DecisionBox, b: DecisionBox): number;
278
311
  /** What to do with an answer: act on it, have a person review it, or neither. */
279
312
  export type GateOutcome = 'act' | 'review' | 'abstain';
280
313
  /** The confidences a gate acts at, and has reviewed at. */
@@ -345,6 +378,7 @@ export interface CalibrationReport {
345
378
  /**
346
379
  * The probability an answer gives its own answer: a yes or no's `max(p, 1 - p)`, a choice's for its
347
380
  * option, and a score's for its level. Its confidence measures how far that is above an even spread.
381
+ * A box has no probabilities, so its confidence stands for one.
348
382
  */
349
383
  export declare function answerProbability(answer: DecisionAnswer): number;
350
384
  /**
@@ -355,11 +389,13 @@ export declare function answerProbability(answer: DecisionAnswer): number;
355
389
  */
356
390
  export declare function calibrate(samples: readonly CalibrationSample[], options?: CalibrateOptions): CalibrationReport;
357
391
  /**
358
- * Whether an answer is right: a yes-or-no or a choice by its answer, and a score by its most probable
359
- * level, or by its weighted score within `tolerance` levels when one is given.
392
+ * Whether an answer is right: a yes-or-no or a choice by its answer, a score by its most probable
393
+ * level, or by its weighted score within `tolerance` levels when one is given, and a box by how far it
394
+ * overlaps the expected one, `boxOverlap()`, at least `overlap` (one half by default).
360
395
  */
361
- export declare function answeredRight(answer: DecisionAnswer, expected: boolean | string | number, options?: {
396
+ export declare function answeredRight(answer: DecisionAnswer, expected: boolean | string | number | DecisionBox, options?: {
362
397
  tolerance?: number;
398
+ overlap?: number;
363
399
  }): boolean;
364
400
  /** A decision model's price, in US dollars per million tokens. */
365
401
  export interface DecisionPrice {
@@ -493,8 +529,11 @@ export interface DecisionConformanceCase {
493
529
  state: DecisionState;
494
530
  /** The question. */
495
531
  question: DecisionQuestion;
496
- /** The right answer: a yes or no, a choice's option, or a score's level. */
497
- expected: boolean | string | number;
532
+ /**
533
+ * The right answer: a yes or no, a choice's option, a score's level, or where a box should be, which
534
+ * an answer overlapping it by half or more matches.
535
+ */
536
+ expected: boolean | string | number | DecisionBox;
498
537
  }
499
538
  /** Options for `runDecisionConformance()`. */
500
539
  export interface DecisionConformanceOptions {
@@ -505,6 +544,11 @@ export interface DecisionConformanceOptions {
505
544
  * as it is told passes without them; a real model is held to them.
506
545
  */
507
546
  cases?: readonly DecisionConformanceCase[];
547
+ /**
548
+ * A picture for the checks of a provider that reads pictures or answers boxes: it is asked a yes or
549
+ * no about the picture, and a box around what it shows. Without one, those checks are skipped.
550
+ */
551
+ picture?: ImageContent;
508
552
  }
509
553
  /** How a provider did against the decision contract. */
510
554
  export interface DecisionConformanceReport {
@@ -514,12 +558,13 @@ export interface DecisionConformanceReport {
514
558
  passed: string[];
515
559
  /** Checks that failed, each with why. */
516
560
  failures: string[];
561
+ /** Checks that were not run, each with why, such as a box with no picture given to ask about. */
562
+ skipped: string[];
517
563
  }
518
564
  /**
519
565
  * Checks a provider against the decision contract: its capabilities are coherent; each question type
520
- * it declares comes back as probabilities that fit the question; several questions in one decision
521
- * each get their own answer; a stopped call is not answered; and every case is answered right. Never
522
- * throws; failures are listed.
566
+ * it declares comes back as probabilities, or a box, that fit the question; a provider that reads
567
+ * pictures answers about one; several questions in one decision each get their own answer; a stopped
568
+ * call is not answered; and every case is answered right. Never throws; failures are listed.
523
569
  */
524
570
  export declare function runDecisionConformance(provider: DecisionProvider, options?: DecisionConformanceOptions): Promise<DecisionConformanceReport>;
525
- export {};
@@ -2,18 +2,9 @@ import { createCacheKey } from '../cache/memory-cache.js';
2
2
  import { withLifecycle } from '../lifecycle/run.js';
3
3
  import { generateRequestId } from '../utils/ids.js';
4
4
  import { sha256Hex } from '../utils/sha256.js';
5
- export class DecisionError extends Error {
6
- code;
7
- retryable;
8
- status;
9
- constructor(message, code, retryable = false, status) {
10
- super(message);
11
- this.code = code;
12
- this.retryable = retryable;
13
- this.status = status;
14
- this.name = 'DecisionError';
15
- }
16
- }
5
+ import { DecisionError } from './errors.js';
6
+ import { pictureDigest, replacePictures, statePictures } from './pictures.js';
7
+ export { DecisionError } from './errors.js';
17
8
  export function yesNoConfidence(probability) {
18
9
  return clamp(Math.abs(2 * probability - 1));
19
10
  }
@@ -73,8 +64,36 @@ export function decisionAnswer(question, distribution) {
73
64
  confidence: scoreConfidence(weights),
74
65
  };
75
66
  }
67
+ if (question.type === 'box' && distribution.type === 'box') {
68
+ const edge = (name) => {
69
+ const value = distribution.box?.[name];
70
+ if (typeof value !== 'number' || !Number.isFinite(value) || value < 0 || value > 1) {
71
+ throw new DecisionError(`The box's ${name} edge is ${String(value)}, not a number from 0 to 1`, 'DECISION_INVALID');
72
+ }
73
+ return value;
74
+ };
75
+ const box = { top: edge('top'), bottom: edge('bottom'), left: edge('left'), right: edge('right') };
76
+ if (box.top > box.bottom || box.left > box.right) {
77
+ throw new DecisionError(`The box's edges cross: top ${box.top} and bottom ${box.bottom}, left ${box.left} and right ${box.right}`, 'DECISION_INVALID');
78
+ }
79
+ const confidence = distribution.confidence;
80
+ if (typeof confidence !== 'number' || !Number.isFinite(confidence) || confidence < 0 || confidence > 1) {
81
+ throw new DecisionError(`The box's confidence is ${String(confidence)}, not a number from 0 to 1`, 'DECISION_INVALID');
82
+ }
83
+ return { type: 'box', box, confidence };
84
+ }
76
85
  throw new DecisionError(`Unknown question type "${question.type}"`, 'DECISION_INVALID');
77
86
  }
87
+ export function boxOverlap(a, b) {
88
+ const width = Math.max(0, Math.min(a.right, b.right) - Math.max(a.left, b.left));
89
+ const height = Math.max(0, Math.min(a.bottom, b.bottom) - Math.max(a.top, b.top));
90
+ const shared = width * height;
91
+ const area = (box) => Math.max(0, box.right - box.left) * Math.max(0, box.bottom - box.top);
92
+ const union = area(a) + area(b) - shared;
93
+ if (union <= 0)
94
+ return a.top === b.top && a.left === b.left && a.bottom === b.bottom && a.right === b.right ? 1 : 0;
95
+ return shared / union;
96
+ }
78
97
  export function gate(answer, thresholds) {
79
98
  if (answer.confidence >= thresholds.act)
80
99
  return 'act';
@@ -85,6 +104,8 @@ export function answerProbability(answer) {
85
104
  return Math.max(answer.probability, 1 - answer.probability);
86
105
  if (answer.type === 'choice')
87
106
  return answer.probabilities[answer.choice] ?? 0;
107
+ if (answer.type === 'box')
108
+ return answer.confidence;
88
109
  return answer.probabilities[answer.level] ?? 0;
89
110
  }
90
111
  export function calibrate(samples, options = {}) {
@@ -144,6 +165,11 @@ export function answeredRight(answer, expected, options = {}) {
144
165
  return answer.yes === expected;
145
166
  if (answer.type === 'choice')
146
167
  return answer.choice === expected;
168
+ if (answer.type === 'box') {
169
+ if (expected === null || typeof expected !== 'object')
170
+ return false;
171
+ return boxOverlap(answer.box, expected) >= (options.overlap ?? 0.5);
172
+ }
147
173
  if (typeof expected !== 'number')
148
174
  return false;
149
175
  return options.tolerance === undefined
@@ -194,6 +220,7 @@ export class DecisionManager {
194
220
  async decide(request) {
195
221
  request.signal?.throwIfAborted();
196
222
  const questions = normalizeQuestions(request.questions);
223
+ const pictures = picturesOf(request.state, questions);
197
224
  const chosen = request.provider ?? this.config.defaultProvider ?? this.providers.keys().next().value;
198
225
  if (chosen === undefined)
199
226
  throw new DecisionError('No decision provider is registered', 'DECISION_NO_PROVIDER');
@@ -203,14 +230,14 @@ export class DecisionManager {
203
230
  const provider = this.providers.get(name);
204
231
  if (!provider)
205
232
  throw new DecisionError(`No decision provider is registered as "${name}"`, 'DECISION_NO_PROVIDER');
206
- const unfit = unsupported(provider, questions);
233
+ const unfit = unsupported(provider, questions, pictures);
207
234
  if (unfit) {
208
235
  if (position > 0)
209
236
  continue;
210
237
  throw new DecisionError(`Decision provider "${name}" ${unfit}`, 'DECISION_UNSUPPORTED');
211
238
  }
212
239
  try {
213
- return (await this.ask(name, provider, request, questions));
240
+ return (await this.ask(name, provider, request, questions, pictures));
214
241
  }
215
242
  catch (error) {
216
243
  last = error;
@@ -220,12 +247,15 @@ export class DecisionManager {
220
247
  }
221
248
  throw last;
222
249
  }
223
- async ask(name, provider, request, questions) {
250
+ async ask(name, provider, request, questions, pictures) {
224
251
  const model = request.model ?? provider.info.capabilities.defaultModel;
225
252
  const started = Date.now();
226
253
  const cache = request.cache === false ? undefined : this.config.cache;
254
+ const described = pictures.length
255
+ ? replacePictures(request.state, (picture) => ({ picture: pictureDigest(picture.part) }))
256
+ : request.state;
227
257
  const key = cache
228
- ? `nexus:decision:${sha256Hex(createCacheKey({ name, model, tenant: request.tenantId, state: request.state, questions }))}`
258
+ ? `nexus:decision:${sha256Hex(createCacheKey({ name, model, tenant: request.tenantId, state: described, questions }))}`
229
259
  : undefined;
230
260
  if (cache && key) {
231
261
  const hit = await cache.store.get(key);
@@ -245,7 +275,7 @@ export class DecisionManager {
245
275
  const run = this.runtime.tracer?.startRun({
246
276
  name: `decide ${Object.keys(questions).join(', ')}`,
247
277
  kind: 'decision',
248
- inputs: { state: request.state, questions },
278
+ inputs: { state: described, questions },
249
279
  model,
250
280
  provider: name,
251
281
  ...(request.metadata ? { metadata: request.metadata } : {}),
@@ -257,11 +287,18 @@ export class DecisionManager {
257
287
  provider: name,
258
288
  model,
259
289
  ...(request.tenantId !== undefined ? { tenantId: request.tenantId } : {}),
260
- metadata: { questions: Object.keys(questions).length, ...request.metadata },
290
+ metadata: {
291
+ questions: Object.keys(questions).length,
292
+ ...(pictures.length ? { pictures: pictures.length } : {}),
293
+ ...request.metadata,
294
+ },
261
295
  }, request.signal ? { signal: request.signal } : {}, async (ticket) => {
262
296
  const estimate = charged
263
297
  ? undefined
264
- : priceDecision(model, { inputTokens: Math.ceil(JSON.stringify({ state: request.state, questions }).length / 4) }, this.prices());
298
+ : priceDecision(model, {
299
+ inputTokens: Math.ceil(JSON.stringify({ state: described, questions }).length / 4) +
300
+ pictures.length * PICTURE_TOKENS,
301
+ }, this.prices());
265
302
  if (ticket && estimate)
266
303
  await ticket.reserve(estimate.amount);
267
304
  const answered = await provider.decide({ model, state: request.state, questions }, {
@@ -321,7 +358,7 @@ export async function decide(provider, request) {
321
358
  return new DecisionManager({ providers: { [provider.info.name]: provider } }).decide(request);
322
359
  }
323
360
  export async function runDecisionConformance(provider, options = {}) {
324
- const report = { provider: provider.info.name, passed: [], failures: [] };
361
+ const report = { provider: provider.info.name, passed: [], failures: [], skipped: [] };
325
362
  const check = async (name, run) => {
326
363
  try {
327
364
  await run();
@@ -342,6 +379,8 @@ export async function runDecisionConformance(provider, options = {}) {
342
379
  throw new Error('a choice needs two options');
343
380
  if (capabilities.types.includes('score') && !(capabilities.maxLevels >= 2))
344
381
  throw new Error('a score needs two levels');
382
+ if (capabilities.types.includes('box') && capabilities.images !== true)
383
+ throw new Error('it answers boxes, and reads no pictures to find them in');
345
384
  if (!capabilities.defaultModel.trim())
346
385
  throw new Error('it names no default model');
347
386
  });
@@ -358,11 +397,19 @@ export async function runDecisionConformance(provider, options = {}) {
358
397
  options: { early: 'Before it was due', late: 'After it was due' },
359
398
  },
360
399
  score: { type: 'score', question: 'How much of it was paid?', levels: ['None', 'Some', 'All'] },
400
+ box: { type: 'box', question: 'What `photo` shows most, wherever it is' },
361
401
  };
402
+ const picture = options.picture;
403
+ const stateFor = (type) => type === 'box' && picture ? { invoice: state, photo: picture } : state;
404
+ const askable = capabilities.types.filter((type) => type !== 'box' || picture);
362
405
  for (const type of capabilities.types) {
406
+ if (!askable.includes(type)) {
407
+ report.skipped.push(`a ${type} question: no picture was given to ask about`);
408
+ continue;
409
+ }
363
410
  await check(`a ${type} question`, async () => {
364
411
  const question = samples[type];
365
- const { answers } = await ask(state, { asked: question });
412
+ const { answers } = await ask(stateFor(type), { asked: question });
366
413
  const answer = answers.asked;
367
414
  if (answer.type !== type)
368
415
  throw new Error(`answered as a ${answer.type}`);
@@ -370,9 +417,21 @@ export async function runDecisionConformance(provider, options = {}) {
370
417
  throw new Error(`confidence ${answer.confidence}`);
371
418
  });
372
419
  }
420
+ if (capabilities.images) {
421
+ if (picture) {
422
+ await check('a question about a picture', async () => {
423
+ const { answers } = await ask({ invoice: state, photo: picture }, { shown: { type: 'yes-no', question: 'Does `photo` show anything at all?' } });
424
+ if (answers.shown.type !== 'yes-no')
425
+ throw new Error(`answered as a ${answers.shown.type}`);
426
+ });
427
+ }
428
+ else {
429
+ report.skipped.push('a question about a picture: no picture was given to ask about');
430
+ }
431
+ }
373
432
  await check('several questions in one decision', async () => {
374
- const questions = Object.fromEntries(capabilities.types.map((type) => [`q-${type}`, samples[type]]));
375
- const { answers } = await ask(state, questions);
433
+ const questions = Object.fromEntries(askable.map((type) => [`q-${type}`, samples[type]]));
434
+ const { answers } = await ask(askable.includes('box') ? stateFor('box') : state, questions);
376
435
  for (const name of Object.keys(questions))
377
436
  if (!answers[name])
378
437
  throw new Error(`"${name}" got no answer`);
@@ -380,11 +439,12 @@ export async function runDecisionConformance(provider, options = {}) {
380
439
  await check('a stopped decision is not answered', async () => {
381
440
  const controller = new AbortController();
382
441
  controller.abort(new Error('stopped'));
383
- const question = samples[capabilities.types[0] ?? 'yes-no'];
442
+ const type = askable[0] ?? 'yes-no';
443
+ const question = samples[type];
384
444
  const answered = await provider
385
445
  .decide({
386
446
  model: options.model ?? capabilities.defaultModel,
387
- state,
447
+ state: stateFor(type),
388
448
  questions: normalizeQuestions({ asked: question }),
389
449
  }, { signal: controller.signal, requestId: generateRequestId() })
390
450
  .then(() => true, () => false);
@@ -396,7 +456,13 @@ export async function runDecisionConformance(provider, options = {}) {
396
456
  const { answers } = await ask(item.state, { asked: item.question });
397
457
  const answer = answers.asked;
398
458
  if (!answeredRight(answer, item.expected)) {
399
- const given = answer.type === 'yes-no' ? answer.yes : answer.type === 'choice' ? answer.choice : answer.level;
459
+ const given = answer.type === 'yes-no'
460
+ ? answer.yes
461
+ : answer.type === 'choice'
462
+ ? answer.choice
463
+ : answer.type === 'box'
464
+ ? answer.box
465
+ : answer.level;
400
466
  throw new Error(`expected ${JSON.stringify(item.expected)}, answered ${JSON.stringify(given)}`);
401
467
  }
402
468
  });
@@ -438,18 +504,39 @@ function normalizeQuestions(questions) {
438
504
  }
439
505
  normalized[name] = question;
440
506
  }
507
+ else if (question?.type === 'box') {
508
+ if (typeof question.question !== 'string' || !question.question.trim()) {
509
+ throw new DecisionError(`Box "${name}" needs a question: what to find, and in which picture`, 'DECISION_INVALID');
510
+ }
511
+ normalized[name] = { type: 'box', question: question.question };
512
+ }
441
513
  else {
442
- throw new DecisionError(`Question "${name}" is a yes-no, a choice, or a score, not ${JSON.stringify(question?.type)}`, 'DECISION_INVALID');
514
+ throw new DecisionError(`Question "${name}" is a yes-no, a choice, a score, or a box, not ${JSON.stringify(question?.type)}`, 'DECISION_INVALID');
443
515
  }
444
516
  }
445
517
  return normalized;
446
518
  }
447
- function unsupported(provider, questions) {
519
+ const PICTURE_TOKENS = 1_600;
520
+ function picturesOf(state, questions) {
521
+ const pictures = typeof state === 'string' ? [] : statePictures(state);
522
+ if (pictures.some((picture) => picture.path === '')) {
523
+ throw new DecisionError('A picture that is the whole state has no path for a question to name it by: hold it under a key, such as { photo: picture }', 'DECISION_INVALID');
524
+ }
525
+ const box = Object.entries(questions).find(([, question]) => question.type === 'box');
526
+ if (box && pictures.length === 0) {
527
+ throw new DecisionError(`Box "${box[0]}" asks where something is in a picture, and the state holds none`, 'DECISION_INVALID');
528
+ }
529
+ return pictures;
530
+ }
531
+ function unsupported(provider, questions, pictures = []) {
448
532
  const capabilities = provider.info.capabilities;
449
533
  const count = Object.keys(questions).length;
450
534
  if (capabilities.maxQuestions !== undefined && count > capabilities.maxQuestions) {
451
535
  return `takes at most ${capabilities.maxQuestions} questions, not ${count}`;
452
536
  }
537
+ if (pictures.length > 0 && capabilities.images !== true) {
538
+ return `does not read pictures, and the state holds ${pictures.length}, such as \`${pictures[0]?.path}\``;
539
+ }
453
540
  for (const [name, question] of Object.entries(questions)) {
454
541
  if (!capabilities.types.includes(question.type))
455
542
  return `does not answer ${question.type} questions, such as "${name}"`;
@@ -0,0 +1,25 @@
1
+ /** Why a decision failed, apart from the rest of the contract, so every part of it can raise one. */
2
+ /** Why a decision failed. */
3
+ export type DecisionErrorCode = 'DECISION_NO_PROVIDER' | 'DECISION_UNSUPPORTED' | 'DECISION_INVALID' | 'DECISION_FAILED';
4
+ /** Raised for a decision no provider can serve, a question that is malformed, or a provider's failure. */
5
+ export declare class DecisionError extends Error {
6
+ /**
7
+ * A stable code: `DECISION_NO_PROVIDER`, `DECISION_UNSUPPORTED` (a provider cannot take the
8
+ * question), `DECISION_INVALID` (the request, or an answer, is malformed), or `DECISION_FAILED`.
9
+ */
10
+ readonly code: DecisionErrorCode;
11
+ /** Whether asking again, or another provider, may help: a timeout or an overloaded service may. */
12
+ readonly retryable: boolean;
13
+ /** The HTTP status a provider answered with, when it did. */
14
+ readonly status?: number | undefined;
15
+ constructor(message: string,
16
+ /**
17
+ * A stable code: `DECISION_NO_PROVIDER`, `DECISION_UNSUPPORTED` (a provider cannot take the
18
+ * question), `DECISION_INVALID` (the request, or an answer, is malformed), or `DECISION_FAILED`.
19
+ */
20
+ code: DecisionErrorCode,
21
+ /** Whether asking again, or another provider, may help: a timeout or an overloaded service may. */
22
+ retryable?: boolean,
23
+ /** The HTTP status a provider answered with, when it did. */
24
+ status?: number | undefined);
25
+ }
@@ -0,0 +1,12 @@
1
+ export class DecisionError extends Error {
2
+ code;
3
+ retryable;
4
+ status;
5
+ constructor(message, code, retryable = false, status) {
6
+ super(message);
7
+ this.code = code;
8
+ this.retryable = retryable;
9
+ this.status = status;
10
+ this.name = 'DecisionError';
11
+ }
12
+ }
@@ -1,9 +1,10 @@
1
1
  /**
2
- * Typed decisions: questions a model answers with a yes or no, a choice, or a score, each with its
3
- * probabilities and a confidence read from them, so software acts on an answer without parsing text.
4
- * The contract, its manager, gates, and calibration; decisions from any completion model; and
5
- * decisions in graphs, agents, and evaluations.
2
+ * Typed decisions: questions a model answers with a yes or no, a choice, a score, or a box around
3
+ * something in a picture, each with a confidence read alike from any provider, so software acts on an
4
+ * answer without parsing text. The contract, its manager, gates, and calibration; the pictures a state
5
+ * holds; decisions from any completion model; and decisions in graphs, agents, and evaluations.
6
6
  */
7
7
  export { type CompletionDecisionMethod, completionDecisions, type CompletionDecisionsOptions, type DecisionCompletionClient, } from './completion.js';
8
8
  export { decisionEvaluator, type DecisionEvaluatorOptions, decisionGuard, type DecisionGuardOptions, type DecisionGuardReview, type DecisionManagerLike, decisionModel, type DecisionModelOptions, decisionPermissions, type DecisionPermissionsOptions, type DecisionRequestOptions, decisionRoute, type DecisionRouteOptions, reviewUnsure, } from './integrations.js';
9
- export { answeredRight, type AnswerOf, answerProbability, type CachedDecision, calibrate, type CalibrateOptions, type CalibrationBin, type CalibrationReport, type CalibrationSample, type ChoiceAnswer, choiceConfidence, type ChoiceQuestion, decide, DECISION_PRICES, decisionAnswer, type DecisionAnswer, type DecisionAnswers, type DecisionCallContext, type DecisionConfig, type DecisionConformanceCase, type DecisionConformanceOptions, type DecisionConformanceReport, type DecisionDistribution, DecisionError, type DecisionErrorCode, DecisionManager, type DecisionPrice, type DecisionProvider, type DecisionProviderCapabilities, type DecisionProviderInfo, type DecisionProviderQuestion, type DecisionProviderRequest, type DecisionProviderResult, type DecisionQuestion, type DecisionQuestions, type DecisionQuestionType, type DecisionRequest, type DecisionResult, type DecisionRunLike, type DecisionRuntime, type DecisionState, type DecisionTracerLike, type DecisionUsage, gate, type GateOutcome, type GateThresholds, priceDecision, runDecisionConformance, type ScoreAnswer, scoreConfidence, type ScoreQuestion, type YesNoAnswer, yesNoConfidence, type YesNoQuestion, } from './core.js';
9
+ export { answeredRight, type AnswerOf, answerProbability, type BoxAnswer, boxOverlap, type BoxQuestion, type CachedDecision, calibrate, type CalibrateOptions, type CalibrationBin, type CalibrationReport, type CalibrationSample, type ChoiceAnswer, choiceConfidence, type ChoiceQuestion, decide, DECISION_PRICES, decisionAnswer, type DecisionAnswer, type DecisionAnswers, type DecisionBox, type DecisionCallContext, type DecisionConfig, type DecisionConformanceCase, type DecisionConformanceOptions, type DecisionConformanceReport, type DecisionDistribution, DecisionError, type DecisionErrorCode, DecisionManager, type DecisionPrice, type DecisionProvider, type DecisionProviderCapabilities, type DecisionProviderInfo, type DecisionProviderQuestion, type DecisionProviderRequest, type DecisionProviderResult, type DecisionQuestion, type DecisionQuestions, type DecisionQuestionType, type DecisionRequest, type DecisionResult, type DecisionRunLike, type DecisionRuntime, type DecisionState, type DecisionTracerLike, type DecisionUsage, gate, type GateOutcome, type GateThresholds, priceDecision, runDecisionConformance, type ScoreAnswer, scoreConfidence, type ScoreQuestion, type YesNoAnswer, yesNoConfidence, type YesNoQuestion, } from './core.js';
10
+ export { type DecisionPicture, type ReadDecisionPicture, readPicture, statePictures } from './pictures.js';
@@ -1,3 +1,4 @@
1
1
  export { completionDecisions, } from './completion.js';
2
2
  export { decisionEvaluator, decisionGuard, decisionModel, decisionPermissions, decisionRoute, reviewUnsure, } from './integrations.js';
3
- export { answeredRight, answerProbability, calibrate, choiceConfidence, decide, DECISION_PRICES, decisionAnswer, DecisionError, DecisionManager, gate, priceDecision, runDecisionConformance, scoreConfidence, yesNoConfidence, } from './core.js';
3
+ export { answeredRight, answerProbability, boxOverlap, calibrate, choiceConfidence, decide, DECISION_PRICES, decisionAnswer, DecisionError, DecisionManager, gate, priceDecision, runDecisionConformance, scoreConfidence, yesNoConfidence, } from './core.js';
4
+ export { readPicture, statePictures } from './pictures.js';
@@ -6,7 +6,7 @@
6
6
  import type { AgentMiddleware } from '../agent/create-agent.js';
7
7
  import type { PermissionPolicyLike, PermissionRequest } from '../agent/permissions.js';
8
8
  import type { EvaluationContext, EvaluationScore, Evaluator } from '../types/evaluate.js';
9
- import type { ChoiceAnswer, ChoiceQuestion, DecisionQuestions, DecisionRequest, DecisionResult, DecisionState, ScoreQuestion, YesNoAnswer, YesNoQuestion } from './core.js';
9
+ import { type BoxQuestion, type ChoiceAnswer, type ChoiceQuestion, type DecisionBox, type DecisionQuestions, type DecisionRequest, type DecisionResult, type DecisionState, type ScoreQuestion, type YesNoAnswer, type YesNoQuestion } from './core.js';
10
10
  /** Anything that answers decisions, such as a `DecisionManager`. */
11
11
  export interface DecisionManagerLike {
12
12
  /** Answers every question of a decision. */
@@ -117,8 +117,8 @@ export declare function decisionModel<const K extends string>(decisions: Decisio
117
117
  export interface DecisionEvaluatorOptions<I = unknown, O = unknown> {
118
118
  /** The score's key. */
119
119
  key: string;
120
- /** The question: a yes or no, a score, or a choice. */
121
- question: YesNoQuestion | ScoreQuestion | ChoiceQuestion;
120
+ /** The question: a yes or no, a score, a choice, or a box about a picture the state holds. */
121
+ question: YesNoQuestion | ScoreQuestion | ChoiceQuestion | BoxQuestion;
122
122
  /** What the question is about. Defaults to the example's inputs, the output, and what was expected. */
123
123
  state?: (context: EvaluationContext<I, O>) => DecisionState;
124
124
  /**
@@ -126,13 +126,22 @@ export interface DecisionEvaluatorOptions<I = unknown, O = unknown> {
126
126
  * passes (the top one by default); for a choice, the option that does.
127
127
  */
128
128
  passing?: boolean | number | string;
129
+ /**
130
+ * For a box, where the thing is, such as from the example's expected output: the score is how far
131
+ * the box overlaps it, `boxOverlap()`, and it passes at `overlap` or more. Without it, the score is
132
+ * the box's confidence.
133
+ */
134
+ where?: (context: EvaluationContext<I, O>) => DecisionBox | undefined;
135
+ /** The overlap a box passes at, from 0 to 1. Defaults to one half. */
136
+ overlap?: number;
129
137
  /** Whom and what to ask. */
130
138
  request?: DecisionRequestOptions;
131
139
  }
132
140
  /**
133
141
  * An evaluator that asks a decision: the score is the probability of yes, the score's level as a
134
- * share of the top one, or the passing option's probability, and its metadata carries the answer's
135
- * confidence and probabilities, so an uncertain score can go to people with `reviewUnsure()`.
142
+ * share of the top one, the passing option's probability, or how far a box overlaps where the thing
143
+ * is, and its metadata carries the answer's confidence and probabilities, or its box, so an uncertain
144
+ * score can go to people with `reviewUnsure()`.
136
145
  */
137
146
  export declare function decisionEvaluator<I = unknown, O = unknown>(decisions: DecisionManagerLike, options: DecisionEvaluatorOptions<I, O>): Evaluator<I, O>;
138
147
  /**