@sixb/core 0.1.3 → 0.1.5

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 (271) hide show
  1. package/dist/actions/index.d.ts +2 -2
  2. package/dist/actions/index.d.ts.map +1 -1
  3. package/dist/actions/index.js +17 -18
  4. package/dist/actions/index.js.map +1 -1
  5. package/dist/actions/read-facade.d.ts +10 -2
  6. package/dist/actions/read-facade.d.ts.map +1 -1
  7. package/dist/actions/types/context.d.ts +45 -2
  8. package/dist/actions/types/context.d.ts.map +1 -1
  9. package/dist/actions/worker.js +4 -4
  10. package/dist/actions/worker.js.map +1 -1
  11. package/dist/agents/context-compaction.d.ts +40 -0
  12. package/dist/agents/context-compaction.d.ts.map +1 -0
  13. package/dist/agents/ids.d.ts +2 -0
  14. package/dist/agents/ids.d.ts.map +1 -1
  15. package/dist/agents/index.d.ts +6 -5
  16. package/dist/agents/index.d.ts.map +1 -1
  17. package/dist/agents/index.js +42 -37
  18. package/dist/agents/index.js.map +1 -1
  19. package/dist/agents/streams.d.ts +17 -1
  20. package/dist/agents/streams.d.ts.map +1 -1
  21. package/dist/agents/streams.js +4 -2
  22. package/dist/agents/streams.js.map +1 -1
  23. package/dist/agents/types.d.ts +11 -0
  24. package/dist/agents/types.d.ts.map +1 -1
  25. package/dist/agents/validation.d.ts +1 -1
  26. package/dist/agents/validation.d.ts.map +1 -1
  27. package/dist/auth/index.js +7 -3
  28. package/dist/auth/index.js.map +1 -1
  29. package/dist/authorization/index.js +6 -2
  30. package/dist/authorization/index.js.map +1 -1
  31. package/dist/bootstrap/index.js +30 -31
  32. package/dist/bootstrap/index.js.map +1 -1
  33. package/dist/{chunk-d6y2wsfg.js → chunk-1q02e95s.js} +12 -7
  34. package/dist/{chunk-d6y2wsfg.js.map → chunk-1q02e95s.js.map} +4 -3
  35. package/dist/{chunk-c6cfqydk.js → chunk-4h947jd8.js} +1 -1
  36. package/dist/{chunk-gqdd7508.js → chunk-4rh2m6zg.js} +1 -1
  37. package/dist/{chunk-f1cyvnrk.js → chunk-6d5xdj1q.js} +259 -9
  38. package/dist/chunk-6d5xdj1q.js.map +14 -0
  39. package/dist/{chunk-fmx1sz2h.js → chunk-72q2y8hn.js} +3 -3
  40. package/dist/{chunk-fmx1sz2h.js.map → chunk-72q2y8hn.js.map} +3 -3
  41. package/dist/{chunk-ttba8x6z.js → chunk-78c6xvyr.js} +68 -3
  42. package/dist/chunk-78c6xvyr.js.map +15 -0
  43. package/dist/{chunk-wb4051cx.js → chunk-819wnjz8.js} +11 -5
  44. package/dist/chunk-819wnjz8.js.map +12 -0
  45. package/dist/{chunk-177ed2mp.js → chunk-84h6qhmp.js} +233 -97
  46. package/dist/{chunk-177ed2mp.js.map → chunk-84h6qhmp.js.map} +9 -9
  47. package/dist/{chunk-pxtrxm3p.js → chunk-a09jx26t.js} +1 -1
  48. package/dist/{chunk-bv41fmjn.js → chunk-am6eczah.js} +59 -22
  49. package/dist/{chunk-bv41fmjn.js.map → chunk-am6eczah.js.map} +8 -7
  50. package/dist/{chunk-zpw39qhj.js → chunk-dm72y8wt.js} +25 -2
  51. package/dist/chunk-dm72y8wt.js.map +10 -0
  52. package/dist/{chunk-kqxgf6kv.js → chunk-drjqm1aa.js} +16 -1
  53. package/dist/{chunk-kqxgf6kv.js.map → chunk-drjqm1aa.js.map} +3 -3
  54. package/dist/chunk-dysw7nsm.js.map +1 -1
  55. package/dist/{chunk-4p9rh7jj.js → chunk-ea73pzk7.js} +1 -1
  56. package/dist/{chunk-4aw0jwk0.js → chunk-f6erf2vv.js} +1 -1
  57. package/dist/{chunk-4z3n1dzt.js → chunk-f83ka50g.js} +131 -25
  58. package/dist/chunk-f83ka50g.js.map +23 -0
  59. package/dist/{chunk-c8bw2b6c.js → chunk-gadsm794.js} +2 -2
  60. package/dist/{chunk-1ywq4hzk.js → chunk-h6h91mfy.js} +8 -10
  61. package/dist/{chunk-1ywq4hzk.js.map → chunk-h6h91mfy.js.map} +2 -2
  62. package/dist/{chunk-n5x5y80a.js → chunk-nzw7sm3b.js} +2 -2
  63. package/dist/{chunk-63te770v.js → chunk-qewtks41.js} +8 -8
  64. package/dist/{chunk-63te770v.js.map → chunk-qewtks41.js.map} +2 -2
  65. package/dist/{chunk-261ag4t4.js → chunk-r0rry8dn.js} +3 -3
  66. package/dist/{chunk-88ppkr54.js → chunk-rte5sm3z.js} +26 -2
  67. package/dist/chunk-rte5sm3z.js.map +12 -0
  68. package/dist/chunk-t0jjkep3.js.map +1 -1
  69. package/dist/{chunk-ettb0cy4.js → chunk-tbv03sx2.js} +59 -29
  70. package/dist/{chunk-ettb0cy4.js.map → chunk-tbv03sx2.js.map} +5 -5
  71. package/dist/{chunk-d2adj15j.js → chunk-tkdscva6.js} +1 -1
  72. package/dist/{chunk-xmggaxg4.js → chunk-v0egge8b.js} +201 -38
  73. package/dist/{chunk-xmggaxg4.js.map → chunk-v0egge8b.js.map} +8 -6
  74. package/dist/{chunk-z8j83gzd.js → chunk-x2yw73hy.js} +1 -1
  75. package/dist/{chunk-qer6am8w.js → chunk-xdf9yswn.js} +1 -1
  76. package/dist/{chunk-3rsf30p4.js → chunk-z3ga9q5m.js} +18 -21
  77. package/dist/{chunk-3rsf30p4.js.map → chunk-z3ga9q5m.js.map} +4 -5
  78. package/dist/{chunk-km4rkj4t.js → chunk-zp2v2rv6.js} +3 -3
  79. package/dist/execution/agent.js +26 -27
  80. package/dist/execution/agent.js.map +1 -1
  81. package/dist/execution/primitive.js +26 -27
  82. package/dist/execution/primitive.js.map +2 -2
  83. package/dist/execution/request.js +27 -28
  84. package/dist/execution/request.js.map +2 -2
  85. package/dist/http/index.js +1 -1
  86. package/dist/index.d.ts +6 -5
  87. package/dist/index.d.ts.map +1 -1
  88. package/dist/index.js +54 -55
  89. package/dist/index.js.map +1 -1
  90. package/dist/lake-storage/types.d.ts +2 -1
  91. package/dist/lake-storage/types.d.ts.map +1 -1
  92. package/dist/materializer/index.js +15 -16
  93. package/dist/materializer/index.js.map +1 -1
  94. package/dist/models/index.d.ts +40 -0
  95. package/dist/models/index.d.ts.map +1 -0
  96. package/dist/objects/execution.d.ts +6 -1
  97. package/dist/objects/execution.d.ts.map +1 -1
  98. package/dist/objects/index.js +19 -20
  99. package/dist/objects/index.js.map +1 -1
  100. package/dist/objects/link/endpoints.d.ts.map +1 -1
  101. package/dist/objects/query/executor.d.ts +1 -0
  102. package/dist/objects/query/executor.d.ts.map +1 -1
  103. package/dist/objects/query/explain.d.ts +1 -0
  104. package/dist/objects/query/explain.d.ts.map +1 -1
  105. package/dist/objects/query/index.d.ts +3 -1
  106. package/dist/objects/query/index.d.ts.map +1 -1
  107. package/dist/objects/query/index.js +30 -5
  108. package/dist/objects/query/index.js.map +1 -1
  109. package/dist/objects/query/ir.d.ts +14 -1
  110. package/dist/objects/query/ir.d.ts.map +1 -1
  111. package/dist/objects/query/links.d.ts +25 -0
  112. package/dist/objects/query/links.d.ts.map +1 -0
  113. package/dist/objects/query/normalize.d.ts.map +1 -1
  114. package/dist/objects/query/planner.d.ts.map +1 -1
  115. package/dist/objects/query/validate.d.ts +1 -0
  116. package/dist/objects/query/validate.d.ts.map +1 -1
  117. package/dist/ontology/internal.d.ts +1 -1
  118. package/dist/ontology/internal.d.ts.map +1 -1
  119. package/dist/ontology/internal.js +14 -6
  120. package/dist/ontology/internal.js.map +3 -3
  121. package/dist/ontology/json-schema.d.ts +10 -0
  122. package/dist/ontology/json-schema.d.ts.map +1 -1
  123. package/dist/pipelines/index.js +15 -16
  124. package/dist/pipelines/index.js.map +1 -1
  125. package/dist/projections/builders.d.ts +33 -4
  126. package/dist/projections/builders.d.ts.map +1 -1
  127. package/dist/projections/index.d.ts +1 -1
  128. package/dist/projections/index.d.ts.map +1 -1
  129. package/dist/projections/internal.js +15 -16
  130. package/dist/projections/internal.js.map +1 -1
  131. package/dist/projections/run-dispatch.d.ts +1 -0
  132. package/dist/projections/run-dispatch.d.ts.map +1 -1
  133. package/dist/projections/types.d.ts +12 -9
  134. package/dist/projections/types.d.ts.map +1 -1
  135. package/dist/projections/validation.d.ts +6 -5
  136. package/dist/projections/validation.d.ts.map +1 -1
  137. package/dist/query.d.ts +2 -1
  138. package/dist/query.d.ts.map +1 -1
  139. package/dist/query.js +2 -2
  140. package/dist/runtime/create.d.ts +3 -0
  141. package/dist/runtime/create.d.ts.map +1 -1
  142. package/dist/runtime/definitions.d.ts +3 -0
  143. package/dist/runtime/definitions.d.ts.map +1 -1
  144. package/dist/runtime/host.d.ts +2 -0
  145. package/dist/runtime/host.d.ts.map +1 -1
  146. package/dist/runtime/resolve-definitions.d.ts +2 -0
  147. package/dist/runtime/resolve-definitions.d.ts.map +1 -1
  148. package/dist/storage/agents/in-memory.d.ts +4 -0
  149. package/dist/storage/agents/in-memory.d.ts.map +1 -1
  150. package/dist/storage/agents/provider.js +9 -5
  151. package/dist/storage/agents/provider.js.map +1 -1
  152. package/dist/storage/agents/types.d.ts +5 -0
  153. package/dist/storage/agents/types.d.ts.map +1 -1
  154. package/dist/storage/ai-cost/provider.js +1 -1
  155. package/dist/storage/ai-usage/in-memory.d.ts +2 -1
  156. package/dist/storage/ai-usage/in-memory.d.ts.map +1 -1
  157. package/dist/storage/ai-usage/index.d.ts +1 -1
  158. package/dist/storage/ai-usage/index.d.ts.map +1 -1
  159. package/dist/storage/ai-usage/types.d.ts +6 -0
  160. package/dist/storage/ai-usage/types.d.ts.map +1 -1
  161. package/dist/storage/index.d.ts +3 -2
  162. package/dist/storage/index.d.ts.map +1 -1
  163. package/dist/storage/index.js +19 -14
  164. package/dist/storage/index.js.map +1 -1
  165. package/dist/storage/objects/in-memory.d.ts +6 -3
  166. package/dist/storage/objects/in-memory.d.ts.map +1 -1
  167. package/dist/storage/objects/index.d.ts +3 -1
  168. package/dist/storage/objects/index.d.ts.map +1 -1
  169. package/dist/storage/objects/keys.d.ts +16 -0
  170. package/dist/storage/objects/keys.d.ts.map +1 -0
  171. package/dist/storage/objects/types.d.ts +33 -6
  172. package/dist/storage/objects/types.d.ts.map +1 -1
  173. package/dist/storage/ontology/provider.js +1 -1
  174. package/dist/storage/workflow-runs/provider.js +9 -5
  175. package/dist/storage/workflow-runs/provider.js.map +1 -1
  176. package/dist/syncs/index.js +15 -16
  177. package/dist/syncs/index.js.map +1 -1
  178. package/dist/testing/agent-storage-contract.d.ts.map +1 -1
  179. package/dist/testing/ai-usage-storage-contract.d.ts.map +1 -1
  180. package/dist/testing/effective-storage-contract.d.ts +1 -1
  181. package/dist/testing/effective-storage-contract.d.ts.map +1 -1
  182. package/dist/testing/index.js +455 -40
  183. package/dist/testing/index.js.map +7 -7
  184. package/dist/testing/lake-storage-contract.d.ts.map +1 -1
  185. package/dist/testing/object-query-contract.d.ts +1 -1
  186. package/dist/testing/object-query-contract.d.ts.map +1 -1
  187. package/dist/webhooks/internal.js +13 -14
  188. package/dist/webhooks/internal.js.map +2 -2
  189. package/dist/workflows/index.js +27 -28
  190. package/dist/workflows/index.js.map +1 -1
  191. package/package.json +1 -1
  192. package/src/actions/index.ts +10 -1
  193. package/src/actions/read-facade.ts +125 -3
  194. package/src/actions/types/context.ts +69 -2
  195. package/src/agents/builders.ts +3 -3
  196. package/src/agents/context-compaction.ts +261 -0
  197. package/src/agents/ids.ts +5 -0
  198. package/src/agents/index.ts +18 -9
  199. package/src/agents/streams.ts +56 -0
  200. package/src/agents/types.ts +12 -0
  201. package/src/agents/validation.ts +39 -5
  202. package/src/http/api-routes.ts +7 -7
  203. package/src/index.ts +19 -0
  204. package/src/lake-storage/types.ts +2 -1
  205. package/src/materializer/telemetry/append.ts +33 -16
  206. package/src/models/index.ts +71 -0
  207. package/src/objects/execution.ts +20 -0
  208. package/src/objects/link/endpoints.ts +2 -1
  209. package/src/objects/query/executor.ts +42 -11
  210. package/src/objects/query/explain.ts +11 -0
  211. package/src/objects/query/index.ts +6 -0
  212. package/src/objects/query/ir.ts +16 -0
  213. package/src/objects/query/links.ts +308 -0
  214. package/src/objects/query/normalize.ts +40 -1
  215. package/src/objects/query/planner.ts +5 -0
  216. package/src/objects/query/validate.ts +58 -2
  217. package/src/ontology/internal.ts +1 -1
  218. package/src/ontology/json-schema.ts +27 -5
  219. package/src/projections/builders.ts +220 -15
  220. package/src/projections/index.ts +1 -0
  221. package/src/projections/ownership.ts +5 -5
  222. package/src/projections/registry.ts +9 -3
  223. package/src/projections/revision.ts +31 -5
  224. package/src/projections/run-dispatch.ts +10 -1
  225. package/src/projections/types.ts +13 -9
  226. package/src/projections/validation.ts +61 -19
  227. package/src/query.ts +2 -0
  228. package/src/runtime/create.ts +4 -0
  229. package/src/runtime/definitions.ts +3 -0
  230. package/src/runtime/host.ts +2 -0
  231. package/src/runtime/resolve-definitions.ts +28 -0
  232. package/src/storage/agents/in-memory.ts +15 -0
  233. package/src/storage/agents/types.ts +5 -0
  234. package/src/storage/ai-usage/in-memory.ts +23 -0
  235. package/src/storage/ai-usage/index.ts +1 -0
  236. package/src/storage/ai-usage/types.ts +10 -0
  237. package/src/storage/index.ts +11 -0
  238. package/src/storage/objects/in-memory.ts +103 -16
  239. package/src/storage/objects/index.ts +9 -0
  240. package/src/storage/objects/keys.ts +36 -0
  241. package/src/storage/objects/types.ts +34 -6
  242. package/src/storage/ontology/provider-header-validation.ts +2 -2
  243. package/src/storage/timeseries/store.ts +6 -6
  244. package/src/testing/agent-storage-contract.ts +12 -0
  245. package/src/testing/ai-usage-storage-contract.ts +35 -0
  246. package/src/testing/effective-storage-contract.ts +194 -4
  247. package/src/testing/lake-storage-contract.ts +56 -0
  248. package/src/testing/object-query-contract.ts +208 -1
  249. package/dist/agents/prompt.d.ts +0 -21
  250. package/dist/agents/prompt.d.ts.map +0 -1
  251. package/dist/chunk-4z3n1dzt.js.map +0 -23
  252. package/dist/chunk-6wetht33.js +0 -89
  253. package/dist/chunk-6wetht33.js.map +0 -10
  254. package/dist/chunk-88ppkr54.js.map +0 -12
  255. package/dist/chunk-f1cyvnrk.js.map +0 -13
  256. package/dist/chunk-ttba8x6z.js.map +0 -15
  257. package/dist/chunk-wb4051cx.js.map +0 -12
  258. package/dist/chunk-zpw39qhj.js.map +0 -10
  259. package/src/agents/prompt.ts +0 -85
  260. /package/dist/{chunk-c6cfqydk.js.map → chunk-4h947jd8.js.map} +0 -0
  261. /package/dist/{chunk-gqdd7508.js.map → chunk-4rh2m6zg.js.map} +0 -0
  262. /package/dist/{chunk-pxtrxm3p.js.map → chunk-a09jx26t.js.map} +0 -0
  263. /package/dist/{chunk-4p9rh7jj.js.map → chunk-ea73pzk7.js.map} +0 -0
  264. /package/dist/{chunk-4aw0jwk0.js.map → chunk-f6erf2vv.js.map} +0 -0
  265. /package/dist/{chunk-c8bw2b6c.js.map → chunk-gadsm794.js.map} +0 -0
  266. /package/dist/{chunk-n5x5y80a.js.map → chunk-nzw7sm3b.js.map} +0 -0
  267. /package/dist/{chunk-261ag4t4.js.map → chunk-r0rry8dn.js.map} +0 -0
  268. /package/dist/{chunk-d2adj15j.js.map → chunk-tkdscva6.js.map} +0 -0
  269. /package/dist/{chunk-z8j83gzd.js.map → chunk-x2yw73hy.js.map} +0 -0
  270. /package/dist/{chunk-qer6am8w.js.map → chunk-xdf9yswn.js.map} +0 -0
  271. /package/dist/{chunk-km4rkj4t.js.map → chunk-zp2v2rv6.js.map} +0 -0
@@ -90,7 +90,6 @@ function prepareTelemetryAppend(
90
90
  points: raw.input.points.map((point) => validateTelemetryPoint(context.ontology, point)),
91
91
  })
92
92
  const inputPointCount = telemetryInputPointCount(input, rawInputPointCount)
93
- validateTelemetryBatch(input, inputPointCount)
94
93
 
95
94
  const ontologyRevision = context.projectionRegistry.ontologyRevision
96
95
  const execution = prepareMaterializerExecution(context.projectId, raw.scope)
@@ -114,21 +113,6 @@ function telemetryInputPointCount(
114
113
  return input.points.length
115
114
  }
116
115
 
117
- function validateTelemetryBatch(input: NormalizedTelemetryAppend, inputPointCount: number): void {
118
- if (input.source.kind === "projection") {
119
- if (input.source.sourceRowCount === 0) {
120
- throw new MaterializationValidationError(
121
- "Projection telemetry batches must consume at least one source row; an empty dataset produces no batch commit."
122
- )
123
- }
124
- if (input.source.sourceRowCount !== inputPointCount + input.source.sourceRowsSkipped) {
125
- throw new MaterializationValidationError(
126
- "Projection telemetry sourceRowCount must equal input points plus skipped rows."
127
- )
128
- }
129
- }
130
- }
131
-
132
116
  function prepareRuntimeTelemetry(
133
117
  context: Pick<MaterializerContext, "projectId" | "clock">,
134
118
  input: NormalizedTelemetryAppend,
@@ -157,6 +141,7 @@ function prepareProjectionTelemetry(
157
141
  )
158
142
  validateTelemetryProjectionDataset(resolvedProjection, source)
159
143
  validateTelemetryOwnership(resolvedProjection, input)
144
+ validateTelemetryBatchCardinality(resolvedProjection, source, inputPointCount)
160
145
 
161
146
  const runIdentity = createProjectionRunMaterializationIdentity({
162
147
  resolved: resolvedProjection,
@@ -182,6 +167,38 @@ function prepareProjectionTelemetry(
182
167
  }
183
168
  }
184
169
 
170
+ function validateTelemetryBatchCardinality(
171
+ resolved: ResolvedTelemetryProjection,
172
+ source: ProjectionTelemetrySource,
173
+ inputPointCount: number
174
+ ): void {
175
+ if (source.sourceRowCount === 0) {
176
+ throw new MaterializationValidationError(
177
+ "Projection telemetry batches must consume at least one source row; an empty dataset produces no batch commit."
178
+ )
179
+ }
180
+
181
+ const mappedPropertyCount = resolved.ownership.telemetry.length
182
+ if (mappedPropertyCount === 0) {
183
+ throw new MaterializationValidationError(
184
+ `Telemetry projection '${resolved.projectionId}' must own at least one telemetry property.`
185
+ )
186
+ }
187
+
188
+ const sourceRowsEmitted = source.sourceRowCount - source.sourceRowsSkipped
189
+ const maximumPointCount = sourceRowsEmitted * mappedPropertyCount
190
+ if (!Number.isSafeInteger(maximumPointCount)) {
191
+ throw new MaterializationValidationError(
192
+ `Telemetry projection '${resolved.projectionId}' batch point capacity exceeds the safe integer range.`
193
+ )
194
+ }
195
+ if (inputPointCount < sourceRowsEmitted || inputPointCount > maximumPointCount) {
196
+ throw new MaterializationValidationError(
197
+ `Telemetry projection '${resolved.projectionId}' must emit between ${sourceRowsEmitted} and ${maximumPointCount} points for ${source.sourceRowCount} source rows with ${source.sourceRowsSkipped} skipped.`
198
+ )
199
+ }
200
+ }
201
+
185
202
  function validateTelemetryProjectionDataset(
186
203
  resolved: ResolvedTelemetryProjection,
187
204
  source: ProjectionTelemetrySource
@@ -0,0 +1,71 @@
1
+ import type { LanguageModelV4 } from "@ai-sdk/provider"
2
+ import { createDefinitionCatalog, type DefinitionCatalog } from "../runtime/definitions"
3
+ import { RuntimeError } from "../runtime/errors"
4
+
5
+ /** The configured language models, with the project default. */
6
+ export interface LanguageModelCatalog extends DefinitionCatalog<LanguageModelEntry> {
7
+ readonly default: LanguageModelEntry
8
+ }
9
+
10
+ /**
11
+ * One configured language model.
12
+ *
13
+ * `ref` is derived, never author-supplied, and stays internal to the runtime: it identifies the
14
+ * configured binding, not a vendor model. The AI SDK's `provider` names the binding, so
15
+ * `openai.chat(...)` and `openai.responses(...)` are distinct entries even for one vendor model,
16
+ * and neither matches the canonical id the worker resolves for billing
17
+ * (`SDK_PROVIDER_BINDINGS` in `@sixb/agent-worker`). Anything user-facing should key on
18
+ * `provider` + `modelId` instead.
19
+ */
20
+ export interface LanguageModelEntry {
21
+ readonly ref: string
22
+ readonly provider: string
23
+ readonly modelId: string
24
+ readonly model: LanguageModelV4
25
+ }
26
+
27
+ /** Models a project allows Sixb to use, organized by technical model kind. */
28
+ export interface ModelCatalog {
29
+ readonly language: LanguageModelCatalog
30
+ }
31
+
32
+ export interface ModelCatalogInput {
33
+ /** Ordered; the first entry is the project default. */
34
+ readonly language: readonly LanguageModelV4[]
35
+ }
36
+
37
+ /**
38
+ * Identify a catalog entry by the binding its model was constructed from.
39
+ *
40
+ * `gateway("openai/gpt-5.4")` and `openai("gpt-5.4")` are different entries on purpose: they route
41
+ * differently and bill differently. See {@link LanguageModelEntry}.
42
+ */
43
+ export function modelRef(model: LanguageModelV4): string {
44
+ return `${model.provider}/${model.modelId}`
45
+ }
46
+
47
+ /** Build the immutable project model catalog. Rejects duplicates and an empty catalog. */
48
+ export function createModelCatalog(input: ModelCatalogInput): ModelCatalog {
49
+ const byRef = new Map<string, LanguageModelEntry>()
50
+
51
+ for (const model of input.language) {
52
+ const ref = modelRef(model)
53
+ if (byRef.has(ref)) {
54
+ throw new RuntimeError(
55
+ `[Sixb] Duplicate language model '${ref}' in 'models'. Each provider and model id pair may be configured once.`
56
+ )
57
+ }
58
+ byRef.set(ref, Object.freeze({ ref, provider: model.provider, modelId: model.modelId, model }))
59
+ }
60
+
61
+ const [defaultEntry] = byRef.values()
62
+ if (defaultEntry === undefined) {
63
+ throw new RuntimeError(
64
+ "[Sixb] 'models.language' needs at least one model. Configure one or omit 'models' from createSixb()."
65
+ )
66
+ }
67
+
68
+ return Object.freeze({
69
+ language: Object.freeze({ ...createDefinitionCatalog(byRef), default: defaultEntry }),
70
+ })
71
+ }
@@ -29,8 +29,11 @@ import {
29
29
  type ExecuteObjectFacetsInput,
30
30
  type ExecuteObjectFacetsResult,
31
31
  type ExecuteObjectQueryInput,
32
+ type ExecuteObjectQueryLinksInput,
33
+ type ExecuteObjectQueryLinksResult,
32
34
  type ExecuteObjectQueryResult,
33
35
  executeObjectQuery,
36
+ executeObjectQueryLinks,
34
37
  existsObjects,
35
38
  facetObjects,
36
39
  } from "./query"
@@ -121,6 +124,12 @@ export interface ExecutionObjectSet<
121
124
  byId(id: string): ExecutionObjectByIdHandle<TObjectType, TValueTypes>
122
125
  }
123
126
 
127
+ /** Public input for querying physical links incident to an object query result. */
128
+ export type ObjectQueryLinksInput = Omit<ExecuteObjectQueryLinksInput, "projectId">
129
+
130
+ /** Public result returned by {@link ObjectsRuntime.queryLinks}. */
131
+ export type ObjectQueryLinksResult = ExecuteObjectQueryLinksResult
132
+
124
133
  export interface ObjectsRuntime<TOntologySources extends readonly OntologySource[]>
125
134
  extends ExecutionObjectOperations {
126
135
  <TObjectType extends RegisteredObjectType<TOntologySources>>(
@@ -131,6 +140,7 @@ export interface ObjectsRuntime<TOntologySources extends readonly OntologySource
131
140
  RegisteredObjectType<TOntologySources>
132
141
  >
133
142
  executeQuery(input: Omit<ExecuteObjectQueryInput, "projectId">): Promise<ExecuteObjectQueryResult>
143
+ queryLinks(input: ObjectQueryLinksInput): Promise<ObjectQueryLinksResult>
134
144
  count(input: Omit<ExecuteObjectCountInput, "projectId">): Promise<ExecuteObjectCountResult>
135
145
  exists(input: Omit<ExecuteObjectExistsInput, "projectId">): Promise<ExecuteObjectExistsResult>
136
146
  facet(input: Omit<ExecuteObjectFacetsInput, "projectId">): Promise<ExecuteObjectFacetsResult>
@@ -208,6 +218,16 @@ export function createObjectsRuntime<TOntologySources extends readonly OntologyS
208
218
  authorization: runtime.authorization,
209
219
  }
210
220
  ),
221
+ queryLinks: (input: ObjectQueryLinksInput) =>
222
+ executeObjectQueryLinks(
223
+ { projectId: runtime.projectId, ...input },
224
+ {
225
+ ontology: runtime.ontology,
226
+ storage: runtime.storage.objects,
227
+ runtimeAuthorization: runtime.runtimeAuthorization,
228
+ authorization: runtime.authorization,
229
+ }
230
+ ),
211
231
  count: (input: Omit<ExecuteObjectCountInput, "projectId">) =>
212
232
  countObjects(
213
233
  { projectId: runtime.projectId, ...input },
@@ -7,6 +7,7 @@
7
7
  */
8
8
 
9
9
  import type { SixbRuntimeContext } from "../../runtime/types"
10
+ import { objectBatchKey } from "../../storage"
10
11
  import { ObjectNotFoundError } from "../../storage/errors"
11
12
 
12
13
  export interface LinkEndpointItem {
@@ -62,5 +63,5 @@ export function requireEndpoints(item: LinkEndpointItem, existing: EndpointExist
62
63
  }
63
64
 
64
65
  function endpointKey(objectTypeId: string, primaryId: string): string {
65
- return `${objectTypeId}:${primaryId}`
66
+ return objectBatchKey(objectTypeId, primaryId)
66
67
  }
@@ -7,6 +7,7 @@ import type {
7
7
  ExpandedLinkValue,
8
8
  ExpandedObjectRow,
9
9
  FacetObjectsResult,
10
+ ObjectBatchKey,
10
11
  ObjectFacetRequest,
11
12
  ObjectFacetResult,
12
13
  ObjectLinkRow,
@@ -16,6 +17,7 @@ import type {
16
17
  ObjectStorage,
17
18
  QueryObjectsResult,
18
19
  } from "../../storage"
20
+ import { linkBatchKey, objectBatchKey } from "../../storage"
19
21
  import {
20
22
  ObjectQueryExecutionError,
21
23
  ObjectQueryPlanningError,
@@ -52,6 +54,7 @@ export interface QueryExecutorOptions
52
54
  storage: ObjectStorage
53
55
  maxLimit?: number
54
56
  maxPageSize?: number
57
+ maxRefs?: number
55
58
  maxFacetLimit?: number
56
59
  /**
57
60
  * Per-parent cap on how many links a single `expand` hydrates, applied as a
@@ -132,6 +135,7 @@ export async function executeObjectQuery(
132
135
  ontology: options.ontology,
133
136
  maxLimit: options.maxLimit,
134
137
  maxPageSize: options.maxPageSize,
138
+ maxRefs: options.maxRefs,
135
139
  normalize: false,
136
140
  })
137
141
  assertQueryViewable(validated, options)
@@ -199,6 +203,7 @@ export async function countObjects(
199
203
  ontology: options.ontology,
200
204
  maxLimit: options.maxLimit,
201
205
  maxPageSize: options.maxPageSize,
206
+ maxRefs: options.maxRefs,
202
207
  normalize: false,
203
208
  })
204
209
  assertQueryViewable(validated, options)
@@ -259,6 +264,7 @@ export async function existsObjects(
259
264
  ontology: options.ontology,
260
265
  maxLimit: options.maxLimit,
261
266
  maxPageSize: options.maxPageSize,
267
+ maxRefs: options.maxRefs,
262
268
  normalize: false,
263
269
  })
264
270
  assertQueryViewable(validated, options)
@@ -319,6 +325,7 @@ export async function facetObjects(
319
325
  ontology: options.ontology,
320
326
  maxLimit: options.maxLimit,
321
327
  maxPageSize: options.maxPageSize,
328
+ maxRefs: options.maxRefs,
322
329
  normalize: false,
323
330
  })
324
331
  assertQueryViewable(validated, options)
@@ -435,6 +442,7 @@ function resolveExpansions(query: ObjectQuery, ctx: ExpansionResolutionContext):
435
442
  }
436
443
  }
437
444
  case "start":
445
+ case "refs":
438
446
  return query
439
447
  case "set":
440
448
  return {
@@ -555,6 +563,8 @@ function expandIncludeSubtypes(query: ObjectQuery, ontology: OntologyRegistry):
555
563
  inputs: objectTypeIds.map((objectTypeId) => ({ kind: "start", objectTypeId })),
556
564
  }
557
565
  }
566
+ case "refs":
567
+ return query
558
568
  case "filter":
559
569
  case "text":
560
570
  case "vector":
@@ -598,6 +608,8 @@ async function evaluateFallbackQuery(
598
608
  switch (query.kind) {
599
609
  case "start":
600
610
  return evaluateFallbackStart(projectId, query, options, maxRows)
611
+ case "refs":
612
+ return evaluateFallbackRefs(projectId, query, options)
601
613
  case "filter": {
602
614
  const input = await evaluateFallbackQuery(projectId, query.input, options, maxRows)
603
615
  return completeFallbackEvaluation(
@@ -672,6 +684,23 @@ async function evaluateFallbackQuery(
672
684
  }
673
685
  }
674
686
 
687
+ async function evaluateFallbackRefs(
688
+ projectId: string,
689
+ query: Extract<ObjectQuery, { kind: "refs" }>,
690
+ options: QueryExecutorOptions
691
+ ): Promise<FallbackEvaluation> {
692
+ const rows = await options.storage.getByPrimaryIdBatch({
693
+ projectId,
694
+ items: query.refs,
695
+ })
696
+ return completeFallbackEvaluation(
697
+ query.refs.flatMap((ref, order) => {
698
+ const row = rows.get(objectBatchKey(ref.objectTypeId, ref.primaryId))
699
+ return row ? [{ row, order }] : []
700
+ })
701
+ )
702
+ }
703
+
675
704
  /**
676
705
  * A candidate neighbour for one parent under a single expansion: the object to
677
706
  * hydrate plus the metadata carried on the link edge. For outgoing expansions
@@ -769,7 +798,9 @@ async function collectOutgoingEdges(
769
798
  })
770
799
 
771
800
  return parents.map((parent) => {
772
- const links = linksByKey.get(`${parent.objectTypeId}:${parent.primaryId}:${expansion.linkId}`)
801
+ const links = linksByKey.get(
802
+ linkBatchKey(parent.objectTypeId, parent.primaryId, expansion.linkId)
803
+ )
773
804
  if (!links) return []
774
805
  return links.map((link) => ({
775
806
  neighborTypeId: link.targetTypeId,
@@ -821,8 +852,8 @@ async function fetchExpansionTargets(
821
852
  projectId: string,
822
853
  edgesByParent: readonly ExpansionEdge[][],
823
854
  options: QueryExecutorOptions
824
- ): Promise<Map<string, ObjectRow>> {
825
- const seen = new Set<string>()
855
+ ): Promise<ReadonlyMap<ObjectBatchKey, ObjectRow>> {
856
+ const seen = new Set<ObjectBatchKey>()
826
857
  const items: { objectTypeId: string; primaryId: string }[] = []
827
858
  for (const edges of edgesByParent) {
828
859
  for (const edge of edges) {
@@ -841,10 +872,10 @@ async function fetchExpansionTargets(
841
872
  async function enrichExpansionTargets(
842
873
  projectId: string,
843
874
  trimmedByParent: readonly ExpansionEdge[][],
844
- baseTargets: Map<string, ObjectRow>,
875
+ baseTargets: ReadonlyMap<ObjectBatchKey, ObjectRow>,
845
876
  expansion: ObjectExpansion,
846
877
  options: QueryExecutorOptions
847
- ): Promise<Map<string, ObjectRow>> {
878
+ ): Promise<ReadonlyMap<ObjectBatchKey, ObjectRow>> {
848
879
  if (!expansion.expand || expansion.expand.length === 0) {
849
880
  return baseTargets
850
881
  }
@@ -862,7 +893,7 @@ async function enrichExpansionTargets(
862
893
  }
863
894
 
864
895
  const enriched = await hydrateExpansions(projectId, uniqueTargets, expansion.expand, options)
865
- const enrichedByKey = new Map<string, ObjectRow>()
896
+ const enrichedByKey = new Map<ObjectBatchKey, ObjectRow>()
866
897
  for (const row of enriched) {
867
898
  enrichedByKey.set(targetKey(row.objectTypeId, row.primaryId), row)
868
899
  }
@@ -872,7 +903,7 @@ async function enrichExpansionTargets(
872
903
  function trimExpansionEdges(
873
904
  edges: readonly ExpansionEdge[],
874
905
  expansion: ObjectExpansion,
875
- baseTargets: Map<string, ObjectRow>,
906
+ baseTargets: ReadonlyMap<ObjectBatchKey, ObjectRow>,
876
907
  options: QueryExecutorOptions
877
908
  ): ExpansionEdge[] {
878
909
  let ordered = edges
@@ -899,7 +930,7 @@ function compareExpansionEdges(
899
930
  left: ExpansionEdge,
900
931
  right: ExpansionEdge,
901
932
  fields: readonly ObjectQuerySortField[],
902
- baseTargets: Map<string, ObjectRow>
933
+ baseTargets: ReadonlyMap<ObjectBatchKey, ObjectRow>
903
934
  ): number {
904
935
  const leftRow = baseTargets.get(targetKey(left.neighborTypeId, left.neighborId))
905
936
  const rightRow = baseTargets.get(targetKey(right.neighborTypeId, right.neighborId))
@@ -954,8 +985,8 @@ function toLinkValue(
954
985
  return rows
955
986
  }
956
987
 
957
- function targetKey(objectTypeId: string, id: string): string {
958
- return `${objectTypeId}:${id}`
988
+ function targetKey(objectTypeId: string, id: string): ObjectBatchKey {
989
+ return objectBatchKey(objectTypeId, id)
959
990
  }
960
991
 
961
992
  async function evaluateFallbackStart(
@@ -1300,7 +1331,7 @@ function facetValueSortKey(value: unknown): string {
1300
1331
  }
1301
1332
 
1302
1333
  function rowIdentityKey(row: ObjectRow): string {
1303
- return `${row.objectTypeId}:${row.primaryId}`
1334
+ return objectBatchKey(row.objectTypeId, row.primaryId)
1304
1335
  }
1305
1336
 
1306
1337
  function encodePageOffset(offset: number): string {
@@ -18,6 +18,7 @@ export interface ObjectQueryExplainOptions {
18
18
  normalize?: boolean
19
19
  maxLimit?: number
20
20
  maxPageSize?: number
21
+ maxRefs?: number
21
22
  }
22
23
 
23
24
  export interface ObjectQueryExplanation {
@@ -47,6 +48,7 @@ export function explainObjectQuery(
47
48
  ontology: options.ontology,
48
49
  maxLimit: options.maxLimit,
49
50
  maxPageSize: options.maxPageSize,
51
+ maxRefs: options.maxRefs,
50
52
  normalize: false,
51
53
  })
52
54
  : []
@@ -57,6 +59,7 @@ export function explainObjectQuery(
57
59
  ontology: options.ontology,
58
60
  maxLimit: options.maxLimit,
59
61
  maxPageSize: options.maxPageSize,
62
+ maxRefs: options.maxRefs,
60
63
  normalize: false,
61
64
  }).result
62
65
  : undefined
@@ -84,6 +87,14 @@ function buildExplainNode(query: ObjectQuery, path: string): ObjectQueryExplainN
84
87
  },
85
88
  children: [],
86
89
  }
90
+ case "refs":
91
+ return {
92
+ path,
93
+ kind: query.kind,
94
+ summary: `refs ${query.refs.length}`,
95
+ details: { refs: query.refs },
96
+ children: [],
97
+ }
87
98
  case "filter":
88
99
  return {
89
100
  path,
@@ -44,6 +44,7 @@ export type {
44
44
  ObjectQueryPredicateIn,
45
45
  ObjectQueryPredicateNot,
46
46
  ObjectQueryProject,
47
+ ObjectQueryRefs,
47
48
  ObjectQueryResultShape,
48
49
  ObjectQuerySet,
49
50
  ObjectQuerySetOperation,
@@ -56,6 +57,11 @@ export type {
56
57
  ObjectQueryVector,
57
58
  QueryScalarKind,
58
59
  } from "./ir"
60
+ export type {
61
+ ExecuteObjectQueryLinksInput,
62
+ ExecuteObjectQueryLinksResult,
63
+ } from "./links"
64
+ export { executeObjectQueryLinks } from "./links"
59
65
  export { normalizeObjectQuery, normalizeObjectQueryPredicate } from "./normalize"
60
66
  export type {
61
67
  ObjectQueryPlan,
@@ -5,6 +5,8 @@
5
5
  * storage backend. Providers can push down the subset they support, while the
6
6
  * core planner decides whether a bounded fallback is acceptable.
7
7
  */
8
+ import type { ObjectRef } from "../../ontology/refs"
9
+
8
10
  export type ObjectQueryDirection = "outgoing" | "incoming"
9
11
  export type ObjectQuerySetOperation = "union" | "intersect" | "subtract"
10
12
  export type ObjectQuerySortDirection = "asc" | "desc"
@@ -21,6 +23,7 @@ export type QueryScalarKind =
21
23
 
22
24
  export type ObjectQuery =
23
25
  | ObjectQueryStart
26
+ | ObjectQueryRefs
24
27
  | ObjectQueryFilter
25
28
  | ObjectQueryText
26
29
  | ObjectQueryVector
@@ -38,6 +41,19 @@ export interface ObjectQueryStart {
38
41
  includeSubtypes?: boolean
39
42
  }
40
43
 
44
+ /**
45
+ * Starts a query from an explicit, heterogeneous set of object identities.
46
+ *
47
+ * Unlike `start`, this source is intrinsically bounded. Providers can compile
48
+ * it natively for composition with the rest of the IR; core resolves it through
49
+ * `getByPrimaryIdBatch` when pushdown is unavailable. Normalization removes
50
+ * duplicate identities and orders the set canonically by type and primary id.
51
+ */
52
+ export interface ObjectQueryRefs {
53
+ kind: "refs"
54
+ refs: readonly ObjectRef[]
55
+ }
56
+
41
57
  export interface ObjectQueryFilter {
42
58
  kind: "filter"
43
59
  input: ObjectQuery