@sixb/core 0.1.2 → 0.1.4

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 (383) hide show
  1. package/dist/actions/index.js +19 -17
  2. package/dist/actions/index.js.map +1 -1
  3. package/dist/actions/worker.js +4 -4
  4. package/dist/actions/worker.js.map +1 -1
  5. package/dist/agents/adapters.d.ts +11 -1
  6. package/dist/agents/adapters.d.ts.map +1 -1
  7. package/dist/agents/context-compaction.d.ts +40 -0
  8. package/dist/agents/context-compaction.d.ts.map +1 -0
  9. package/dist/agents/context.js +1 -1
  10. package/dist/agents/errors.d.ts +1 -1
  11. package/dist/agents/errors.d.ts.map +1 -1
  12. package/dist/agents/execution.d.ts +3 -0
  13. package/dist/agents/execution.d.ts.map +1 -1
  14. package/dist/agents/ids.d.ts +2 -0
  15. package/dist/agents/ids.d.ts.map +1 -1
  16. package/dist/agents/index.d.ts +10 -6
  17. package/dist/agents/index.d.ts.map +1 -1
  18. package/dist/agents/index.js +51 -35
  19. package/dist/agents/index.js.map +1 -1
  20. package/dist/agents/request.d.ts.map +1 -1
  21. package/dist/agents/streams.d.ts +17 -1
  22. package/dist/agents/streams.d.ts.map +1 -1
  23. package/dist/agents/streams.js +5 -3
  24. package/dist/agents/streams.js.map +1 -1
  25. package/dist/agents/thread-context-projection.d.ts +19 -0
  26. package/dist/agents/thread-context-projection.d.ts.map +1 -0
  27. package/dist/agents/tool-definition.d.ts.map +1 -1
  28. package/dist/agents/tool-result.d.ts +6 -0
  29. package/dist/agents/tool-result.d.ts.map +1 -0
  30. package/dist/agents/types.d.ts +46 -1
  31. package/dist/agents/types.d.ts.map +1 -1
  32. package/dist/agents/validation.d.ts +2 -2
  33. package/dist/agents/validation.d.ts.map +1 -1
  34. package/dist/auth/index.js +11 -5
  35. package/dist/auth/index.js.map +1 -1
  36. package/dist/authorization/index.js +6 -2
  37. package/dist/authorization/index.js.map +1 -1
  38. package/dist/bootstrap/index.js +33 -31
  39. package/dist/bootstrap/index.js.map +1 -1
  40. package/dist/{chunk-ys1nse2v.js → chunk-1wk20wn3.js} +438 -246
  41. package/dist/{chunk-ys1nse2v.js.map → chunk-1wk20wn3.js.map} +11 -11
  42. package/dist/{chunk-sa4340y1.js → chunk-1yz3x65y.js} +7 -7
  43. package/dist/{chunk-gqdd7508.js → chunk-4rh2m6zg.js} +1 -1
  44. package/dist/{chunk-fmx1sz2h.js → chunk-72q2y8hn.js} +3 -3
  45. package/dist/{chunk-fmx1sz2h.js.map → chunk-72q2y8hn.js.map} +4 -4
  46. package/dist/{chunk-nnyp53zt.js → chunk-7gw7mepb.js} +259 -9
  47. package/dist/chunk-7gw7mepb.js.map +14 -0
  48. package/dist/{chunk-nten49ta.js → chunk-819wnjz8.js} +11 -5
  49. package/dist/chunk-819wnjz8.js.map +12 -0
  50. package/dist/chunk-96swp2wd.js +47 -0
  51. package/dist/chunk-96swp2wd.js.map +10 -0
  52. package/dist/{chunk-4x43bkbp.js → chunk-a09jx26t.js} +1 -1
  53. package/dist/{chunk-st4xgxey.js → chunk-afjpa2hs.js} +205 -48
  54. package/dist/chunk-afjpa2hs.js.map +45 -0
  55. package/dist/{chunk-0mbx247x.js → chunk-c43qr6s0.js} +427 -99
  56. package/dist/chunk-c43qr6s0.js.map +46 -0
  57. package/dist/{chunk-zg9yryhz.js → chunk-cbkm2vam.js} +3 -3
  58. package/dist/{chunk-57zpb99z.js → chunk-dm72y8wt.js} +26 -3
  59. package/dist/chunk-dm72y8wt.js.map +10 -0
  60. package/dist/chunk-drjqm1aa.js +913 -0
  61. package/dist/chunk-drjqm1aa.js.map +15 -0
  62. package/dist/chunk-dysw7nsm.js.map +1 -1
  63. package/dist/{chunk-8ryen3p3.js → chunk-f6erf2vv.js} +1 -1
  64. package/dist/{chunk-34bqh420.js → chunk-f83ka50g.js} +188 -44
  65. package/dist/chunk-f83ka50g.js.map +23 -0
  66. package/dist/{chunk-bct7hmfc.js → chunk-g13869yf.js} +3 -3
  67. package/dist/{chunk-0k4avqr2.js → chunk-hbeh8j9w.js} +2 -2
  68. package/dist/{chunk-qvybnnpe.js → chunk-nzw7sm3b.js} +2 -2
  69. package/dist/{chunk-k9pts48t.js → chunk-pn8n8sba.js} +16 -15
  70. package/dist/{chunk-k9pts48t.js.map → chunk-pn8n8sba.js.map} +3 -3
  71. package/dist/{chunk-63te770v.js → chunk-qewtks41.js} +8 -8
  72. package/dist/{chunk-63te770v.js.map → chunk-qewtks41.js.map} +2 -2
  73. package/dist/{chunk-85j5ybfj.js → chunk-rdeagz6b.js} +2 -2
  74. package/dist/{chunk-85j5ybfj.js.map → chunk-rdeagz6b.js.map} +3 -3
  75. package/dist/chunk-rhrbz7d4.js +36 -0
  76. package/dist/chunk-rhrbz7d4.js.map +10 -0
  77. package/dist/{chunk-bh6k3nc6.js → chunk-rs1wbvy6.js} +1 -1
  78. package/dist/{chunk-88ppkr54.js → chunk-rte5sm3z.js} +26 -2
  79. package/dist/chunk-rte5sm3z.js.map +12 -0
  80. package/dist/{chunk-n8herkry.js → chunk-s31d0qmq.js} +57 -20
  81. package/dist/{chunk-n8herkry.js.map → chunk-s31d0qmq.js.map} +8 -7
  82. package/dist/{chunk-7pc8b818.js → chunk-sxwk41qa.js} +1 -1
  83. package/dist/{chunk-663csy96.js → chunk-t0jjkep3.js} +2 -1
  84. package/dist/chunk-t0jjkep3.js.map +10 -0
  85. package/dist/{chunk-c6qd89g5.js → chunk-tek1qwgm.js} +6 -6
  86. package/dist/{chunk-c6qd89g5.js.map → chunk-tek1qwgm.js.map} +1 -1
  87. package/dist/{chunk-jaj13078.js → chunk-tkdscva6.js} +3 -33
  88. package/dist/{chunk-jaj13078.js.map → chunk-tkdscva6.js.map} +3 -4
  89. package/dist/{chunk-5egfka8j.js → chunk-tycbzedm.js} +2 -2
  90. package/dist/{chunk-g9t3kdtx.js → chunk-x2yw73hy.js} +1 -1
  91. package/dist/{chunk-57r1cpxx.js → chunk-xc7hq65b.js} +3 -2
  92. package/dist/{chunk-57r1cpxx.js.map → chunk-xc7hq65b.js.map} +3 -3
  93. package/dist/chunk-xdf9yswn.js +133 -0
  94. package/dist/chunk-xdf9yswn.js.map +11 -0
  95. package/dist/execution/agent.js +29 -27
  96. package/dist/execution/agent.js.map +1 -1
  97. package/dist/execution/primitive.js +29 -27
  98. package/dist/execution/primitive.js.map +2 -2
  99. package/dist/execution/request.js +30 -28
  100. package/dist/execution/request.js.map +2 -2
  101. package/dist/http/index.js +1 -1
  102. package/dist/index.d.ts +6 -5
  103. package/dist/index.d.ts.map +1 -1
  104. package/dist/index.js +60 -58
  105. package/dist/index.js.map +1 -1
  106. package/dist/lake-storage/types.d.ts +2 -1
  107. package/dist/lake-storage/types.d.ts.map +1 -1
  108. package/dist/materialization/model.d.ts +4 -0
  109. package/dist/materialization/model.d.ts.map +1 -1
  110. package/dist/materializer/edits/apply.d.ts +6 -1
  111. package/dist/materializer/edits/apply.d.ts.map +1 -1
  112. package/dist/materializer/edits/working-state.d.ts +2 -0
  113. package/dist/materializer/edits/working-state.d.ts.map +1 -1
  114. package/dist/materializer/effective/resolve.d.ts +3 -1
  115. package/dist/materializer/effective/resolve.d.ts.map +1 -1
  116. package/dist/materializer/execution/work-records.d.ts.map +1 -1
  117. package/dist/materializer/index.js +19 -17
  118. package/dist/materializer/index.js.map +1 -1
  119. package/dist/materializer/projections/replacement-plan.d.ts.map +1 -1
  120. package/dist/materializer/shared/normalize.d.ts.map +1 -1
  121. package/dist/models/index.d.ts +40 -0
  122. package/dist/models/index.d.ts.map +1 -0
  123. package/dist/objects/execution.d.ts +6 -1
  124. package/dist/objects/execution.d.ts.map +1 -1
  125. package/dist/objects/index.js +21 -19
  126. package/dist/objects/index.js.map +1 -1
  127. package/dist/objects/link/endpoints.d.ts.map +1 -1
  128. package/dist/objects/query/executor.d.ts +1 -0
  129. package/dist/objects/query/executor.d.ts.map +1 -1
  130. package/dist/objects/query/explain.d.ts +1 -0
  131. package/dist/objects/query/explain.d.ts.map +1 -1
  132. package/dist/objects/query/index.d.ts +3 -1
  133. package/dist/objects/query/index.d.ts.map +1 -1
  134. package/dist/objects/query/index.js +30 -5
  135. package/dist/objects/query/index.js.map +1 -1
  136. package/dist/objects/query/ir.d.ts +14 -1
  137. package/dist/objects/query/ir.d.ts.map +1 -1
  138. package/dist/objects/query/links.d.ts +25 -0
  139. package/dist/objects/query/links.d.ts.map +1 -0
  140. package/dist/objects/query/normalize.d.ts.map +1 -1
  141. package/dist/objects/query/planner.d.ts.map +1 -1
  142. package/dist/objects/query/validate.d.ts +1 -0
  143. package/dist/objects/query/validate.d.ts.map +1 -1
  144. package/dist/pipelines/index.js +16 -15
  145. package/dist/pipelines/index.js.map +1 -1
  146. package/dist/projections/builders.d.ts +52 -10
  147. package/dist/projections/builders.d.ts.map +1 -1
  148. package/dist/projections/index.d.ts +2 -1
  149. package/dist/projections/index.d.ts.map +1 -1
  150. package/dist/projections/internal.d.ts +4 -1
  151. package/dist/projections/internal.d.ts.map +1 -1
  152. package/dist/projections/internal.js +22 -17
  153. package/dist/projections/internal.js.map +1 -1
  154. package/dist/projections/run-dispatch.d.ts +1 -0
  155. package/dist/projections/run-dispatch.d.ts.map +1 -1
  156. package/dist/projections/timestamp.d.ts +3 -0
  157. package/dist/projections/timestamp.d.ts.map +1 -0
  158. package/dist/projections/types.d.ts +21 -9
  159. package/dist/projections/types.d.ts.map +1 -1
  160. package/dist/projections/validation.d.ts +6 -5
  161. package/dist/projections/validation.d.ts.map +1 -1
  162. package/dist/query.d.ts +2 -1
  163. package/dist/query.d.ts.map +1 -1
  164. package/dist/query.js +2 -2
  165. package/dist/queues/index.d.ts +1 -1
  166. package/dist/queues/index.d.ts.map +1 -1
  167. package/dist/queues/types.d.ts +7 -0
  168. package/dist/queues/types.d.ts.map +1 -1
  169. package/dist/runtime/ai-cost.d.ts +8 -0
  170. package/dist/runtime/ai-cost.d.ts.map +1 -0
  171. package/dist/runtime/create.d.ts +3 -0
  172. package/dist/runtime/create.d.ts.map +1 -1
  173. package/dist/runtime/definitions.d.ts +3 -0
  174. package/dist/runtime/definitions.d.ts.map +1 -1
  175. package/dist/runtime/host.d.ts +2 -0
  176. package/dist/runtime/host.d.ts.map +1 -1
  177. package/dist/runtime/resolve-definitions.d.ts +2 -0
  178. package/dist/runtime/resolve-definitions.d.ts.map +1 -1
  179. package/dist/storage/agents/in-memory.d.ts +22 -4
  180. package/dist/storage/agents/in-memory.d.ts.map +1 -1
  181. package/dist/storage/agents/index.d.ts +1 -1
  182. package/dist/storage/agents/index.d.ts.map +1 -1
  183. package/dist/storage/agents/provider.d.ts +31 -0
  184. package/dist/storage/agents/provider.d.ts.map +1 -1
  185. package/dist/storage/agents/provider.js +22 -7
  186. package/dist/storage/agents/provider.js.map +1 -1
  187. package/dist/storage/agents/types.d.ts +75 -4
  188. package/dist/storage/agents/types.d.ts.map +1 -1
  189. package/dist/storage/ai-cost/analytics.d.ts +61 -0
  190. package/dist/storage/ai-cost/analytics.d.ts.map +1 -0
  191. package/dist/storage/ai-cost/codec.d.ts +14 -0
  192. package/dist/storage/ai-cost/codec.d.ts.map +1 -0
  193. package/dist/storage/ai-cost/errors.d.ts +7 -0
  194. package/dist/storage/ai-cost/errors.d.ts.map +1 -0
  195. package/dist/storage/ai-cost/in-memory.d.ts +32 -0
  196. package/dist/storage/ai-cost/in-memory.d.ts.map +1 -0
  197. package/dist/storage/ai-cost/index.d.ts +6 -0
  198. package/dist/storage/ai-cost/index.d.ts.map +1 -0
  199. package/dist/storage/ai-cost/provider.d.ts +7 -0
  200. package/dist/storage/ai-cost/provider.d.ts.map +1 -0
  201. package/dist/storage/ai-cost/provider.js +132 -0
  202. package/dist/storage/ai-cost/provider.js.map +10 -0
  203. package/dist/storage/ai-cost/types.d.ts +154 -0
  204. package/dist/storage/ai-cost/types.d.ts.map +1 -0
  205. package/dist/storage/ai-cost/validation.d.ts +7 -0
  206. package/dist/storage/ai-cost/validation.d.ts.map +1 -0
  207. package/dist/storage/ai-usage/in-memory.d.ts +2 -1
  208. package/dist/storage/ai-usage/in-memory.d.ts.map +1 -1
  209. package/dist/storage/ai-usage/index.d.ts +1 -1
  210. package/dist/storage/ai-usage/index.d.ts.map +1 -1
  211. package/dist/storage/ai-usage/types.d.ts +6 -0
  212. package/dist/storage/ai-usage/types.d.ts.map +1 -1
  213. package/dist/storage/in-memory/index.d.ts +5 -0
  214. package/dist/storage/in-memory/index.d.ts.map +1 -1
  215. package/dist/storage/index.d.ts +6 -3
  216. package/dist/storage/index.d.ts.map +1 -1
  217. package/dist/storage/index.js +33 -21
  218. package/dist/storage/index.js.map +1 -1
  219. package/dist/storage/objects/in-memory.d.ts +6 -3
  220. package/dist/storage/objects/in-memory.d.ts.map +1 -1
  221. package/dist/storage/objects/index.d.ts +3 -1
  222. package/dist/storage/objects/index.d.ts.map +1 -1
  223. package/dist/storage/objects/keys.d.ts +16 -0
  224. package/dist/storage/objects/keys.d.ts.map +1 -0
  225. package/dist/storage/objects/types.d.ts +33 -6
  226. package/dist/storage/objects/types.d.ts.map +1 -1
  227. package/dist/storage/ontology/in-memory/materializations.d.ts.map +1 -1
  228. package/dist/storage/ontology/materializations.d.ts +3 -0
  229. package/dist/storage/ontology/materializations.d.ts.map +1 -1
  230. package/dist/storage/ontology/provider.js +1 -1
  231. package/dist/storage/operation-scope.d.ts.map +1 -1
  232. package/dist/storage/operation-scope.js +1 -1
  233. package/dist/storage/types.d.ts +2 -0
  234. package/dist/storage/types.d.ts.map +1 -1
  235. package/dist/storage/workflow-runs/provider.js +10 -5
  236. package/dist/storage/workflow-runs/provider.js.map +1 -1
  237. package/dist/syncs/index.js +16 -15
  238. package/dist/syncs/index.js.map +1 -1
  239. package/dist/testing/agent-storage-contract.d.ts +3 -2
  240. package/dist/testing/agent-storage-contract.d.ts.map +1 -1
  241. package/dist/testing/ai-cost-storage-contract.d.ts +12 -0
  242. package/dist/testing/ai-cost-storage-contract.d.ts.map +1 -0
  243. package/dist/testing/ai-usage-storage-contract.d.ts.map +1 -1
  244. package/dist/testing/effective-storage-contract.d.ts +1 -1
  245. package/dist/testing/effective-storage-contract.d.ts.map +1 -1
  246. package/dist/testing/index.d.ts +1 -0
  247. package/dist/testing/index.d.ts.map +1 -1
  248. package/dist/testing/index.js +2525 -1480
  249. package/dist/testing/index.js.map +10 -9
  250. package/dist/testing/lake-storage-contract.d.ts.map +1 -1
  251. package/dist/testing/materializer-storage-contract.d.ts.map +1 -1
  252. package/dist/testing/object-query-contract.d.ts +1 -1
  253. package/dist/testing/object-query-contract.d.ts.map +1 -1
  254. package/dist/webhooks/internal.js +14 -13
  255. package/dist/webhooks/internal.js.map +2 -2
  256. package/dist/workers/index.js +12 -2
  257. package/dist/workers/index.js.map +3 -3
  258. package/dist/workers/queue-worker.d.ts +2 -0
  259. package/dist/workers/queue-worker.d.ts.map +1 -1
  260. package/dist/workflows/execution.d.ts +3 -0
  261. package/dist/workflows/execution.d.ts.map +1 -1
  262. package/dist/workflows/index.js +30 -28
  263. package/dist/workflows/index.js.map +1 -1
  264. package/package.json +7 -1
  265. package/src/agents/adapters.ts +64 -23
  266. package/src/agents/builders.ts +3 -3
  267. package/src/agents/context-compaction.ts +261 -0
  268. package/src/agents/errors.ts +2 -2
  269. package/src/agents/execution.ts +14 -2
  270. package/src/agents/ids.ts +5 -0
  271. package/src/agents/index.ts +32 -6
  272. package/src/agents/request.ts +5 -0
  273. package/src/agents/streams.ts +56 -0
  274. package/src/agents/thread-context-projection.ts +93 -0
  275. package/src/agents/tool-definition.ts +17 -2
  276. package/src/agents/tool-result.ts +61 -0
  277. package/src/agents/types.ts +57 -1
  278. package/src/agents/validation.ts +36 -6
  279. package/src/http/api-routes.ts +7 -7
  280. package/src/index.ts +27 -0
  281. package/src/lake-storage/types.ts +2 -1
  282. package/src/materialization/model.ts +4 -0
  283. package/src/materializer/edits/apply.ts +55 -2
  284. package/src/materializer/edits/operations.ts +8 -1
  285. package/src/materializer/edits/working-state.ts +7 -0
  286. package/src/materializer/effective/resolve.ts +78 -9
  287. package/src/materializer/execution/work-records.ts +3 -1
  288. package/src/materializer/projections/entry-validator.ts +23 -1
  289. package/src/materializer/projections/replacement-plan.ts +2 -0
  290. package/src/materializer/shared/normalize.ts +16 -0
  291. package/src/materializer/telemetry/append.ts +33 -16
  292. package/src/models/index.ts +71 -0
  293. package/src/objects/execution.ts +20 -0
  294. package/src/objects/link/endpoints.ts +2 -1
  295. package/src/objects/query/executor.ts +42 -11
  296. package/src/objects/query/explain.ts +11 -0
  297. package/src/objects/query/index.ts +6 -0
  298. package/src/objects/query/ir.ts +16 -0
  299. package/src/objects/query/links.ts +308 -0
  300. package/src/objects/query/normalize.ts +40 -1
  301. package/src/objects/query/planner.ts +5 -0
  302. package/src/objects/query/validate.ts +58 -2
  303. package/src/projections/builders.ts +320 -50
  304. package/src/projections/index.ts +7 -0
  305. package/src/projections/internal.ts +4 -1
  306. package/src/projections/ownership.ts +5 -5
  307. package/src/projections/registry.ts +16 -3
  308. package/src/projections/revision.ts +35 -5
  309. package/src/projections/run-dispatch.ts +10 -1
  310. package/src/projections/timestamp.ts +66 -0
  311. package/src/projections/types.ts +20 -9
  312. package/src/projections/validation.ts +85 -19
  313. package/src/query.ts +2 -0
  314. package/src/queues/index.ts +1 -0
  315. package/src/queues/types.ts +8 -0
  316. package/src/runtime/ai-cost.ts +15 -0
  317. package/src/runtime/create.ts +4 -0
  318. package/src/runtime/definitions.ts +3 -0
  319. package/src/runtime/host.ts +2 -0
  320. package/src/runtime/resolve-definitions.ts +28 -0
  321. package/src/storage/agents/in-memory.ts +186 -4
  322. package/src/storage/agents/index.ts +5 -0
  323. package/src/storage/agents/provider.ts +225 -0
  324. package/src/storage/agents/types.ts +82 -3
  325. package/src/storage/ai-cost/analytics.ts +602 -0
  326. package/src/storage/ai-cost/codec.ts +136 -0
  327. package/src/storage/ai-cost/errors.ts +12 -0
  328. package/src/storage/ai-cost/in-memory.ts +164 -0
  329. package/src/storage/ai-cost/index.ts +35 -0
  330. package/src/storage/ai-cost/provider.ts +20 -0
  331. package/src/storage/ai-cost/types.ts +193 -0
  332. package/src/storage/ai-cost/validation.ts +337 -0
  333. package/src/storage/ai-usage/in-memory.ts +23 -0
  334. package/src/storage/ai-usage/index.ts +1 -0
  335. package/src/storage/ai-usage/types.ts +10 -0
  336. package/src/storage/in-memory/index.ts +50 -0
  337. package/src/storage/index.ts +48 -0
  338. package/src/storage/objects/in-memory.ts +103 -16
  339. package/src/storage/objects/index.ts +9 -0
  340. package/src/storage/objects/keys.ts +36 -0
  341. package/src/storage/objects/types.ts +34 -6
  342. package/src/storage/ontology/in-memory/materializations.ts +1 -0
  343. package/src/storage/ontology/materializations.ts +3 -0
  344. package/src/storage/ontology/provider-header-validation.ts +2 -2
  345. package/src/storage/operation-scope.ts +1 -0
  346. package/src/storage/types.ts +2 -0
  347. package/src/testing/agent-storage-contract.ts +353 -2
  348. package/src/testing/ai-cost-storage-contract.ts +320 -0
  349. package/src/testing/ai-usage-storage-contract.ts +35 -0
  350. package/src/testing/effective-storage-contract.ts +194 -4
  351. package/src/testing/index.ts +5 -0
  352. package/src/testing/lake-storage-contract.ts +56 -0
  353. package/src/testing/materializer-storage-contract.ts +120 -2
  354. package/src/testing/object-query-contract.ts +208 -1
  355. package/src/workers/queue-worker.ts +14 -1
  356. package/src/workflows/execution.ts +31 -10
  357. package/dist/agents/prompt.d.ts +0 -15
  358. package/dist/agents/prompt.d.ts.map +0 -1
  359. package/dist/chunk-0mbx247x.js.map +0 -43
  360. package/dist/chunk-34bqh420.js.map +0 -23
  361. package/dist/chunk-57zpb99z.js.map +0 -10
  362. package/dist/chunk-663csy96.js.map +0 -10
  363. package/dist/chunk-6wetht33.js +0 -89
  364. package/dist/chunk-6wetht33.js.map +0 -10
  365. package/dist/chunk-88ppkr54.js.map +0 -12
  366. package/dist/chunk-nnyp53zt.js.map +0 -13
  367. package/dist/chunk-nten49ta.js.map +0 -12
  368. package/dist/chunk-st4xgxey.js.map +0 -45
  369. package/dist/chunk-vp1vc6ee.js +0 -35
  370. package/dist/chunk-vp1vc6ee.js.map +0 -11
  371. package/src/agents/prompt.ts +0 -57
  372. /package/dist/{chunk-sa4340y1.js.map → chunk-1yz3x65y.js.map} +0 -0
  373. /package/dist/{chunk-gqdd7508.js.map → chunk-4rh2m6zg.js.map} +0 -0
  374. /package/dist/{chunk-4x43bkbp.js.map → chunk-a09jx26t.js.map} +0 -0
  375. /package/dist/{chunk-zg9yryhz.js.map → chunk-cbkm2vam.js.map} +0 -0
  376. /package/dist/{chunk-8ryen3p3.js.map → chunk-f6erf2vv.js.map} +0 -0
  377. /package/dist/{chunk-bct7hmfc.js.map → chunk-g13869yf.js.map} +0 -0
  378. /package/dist/{chunk-0k4avqr2.js.map → chunk-hbeh8j9w.js.map} +0 -0
  379. /package/dist/{chunk-qvybnnpe.js.map → chunk-nzw7sm3b.js.map} +0 -0
  380. /package/dist/{chunk-bh6k3nc6.js.map → chunk-rs1wbvy6.js.map} +0 -0
  381. /package/dist/{chunk-7pc8b818.js.map → chunk-sxwk41qa.js.map} +0 -0
  382. /package/dist/{chunk-5egfka8j.js.map → chunk-tycbzedm.js.map} +0 -0
  383. /package/dist/{chunk-g9t3kdtx.js.map → chunk-x2yw73hy.js.map} +0 -0
@@ -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
@@ -0,0 +1,308 @@
1
+ import { createHash } from "node:crypto"
2
+ import { isAllowed } from "../../authorization"
3
+ import { stableJsonStringify } from "../../json"
4
+ import {
5
+ type LinkDirection,
6
+ type ObjectBatchKey,
7
+ type ObjectLinkCursor,
8
+ type ObjectLinkRow,
9
+ type ObjectRow,
10
+ type ObjectStorage,
11
+ objectBatchKey,
12
+ objectLinkCursor,
13
+ } from "../../storage"
14
+ import { ObjectQueryExecutionError } from "./errors"
15
+ import { executeObjectQuery, type QueryExecutorOptions } from "./executor"
16
+ import type { ObjectQuery } from "./ir"
17
+ import { normalizeObjectQuery } from "./normalize"
18
+ import { validateObjectQuery } from "./validate"
19
+
20
+ export interface ExecuteObjectQueryLinksInput {
21
+ projectId: string
22
+ query: ObjectQuery
23
+ direction?: LinkDirection
24
+ linkId?: string
25
+ includeObjects?: boolean
26
+ pageSize?: number
27
+ pageToken?: string
28
+ }
29
+
30
+ export interface ExecuteObjectQueryLinksResult {
31
+ objects: readonly ObjectRow[]
32
+ links: readonly ObjectLinkRow[]
33
+ hasMore: boolean
34
+ nextPageToken?: string
35
+ }
36
+
37
+ const MAX_LINK_QUERY_OBJECTS = 1_000
38
+ const MAX_LINK_PAGE_SIZE = 1_000
39
+ const DEFAULT_LINK_PAGE_SIZE = 100
40
+ const LINK_PAGE_TOKEN_PREFIX = "link:v1:"
41
+
42
+ /**
43
+ * Select a bounded object set with the query IR, then return physical links
44
+ * incident to that set. This is a separate terminal because edge rows and edge
45
+ * pagination are a different response contract from object-set queries.
46
+ */
47
+ export async function executeObjectQueryLinks(
48
+ input: ExecuteObjectQueryLinksInput,
49
+ options: QueryExecutorOptions
50
+ ): Promise<ExecuteObjectQueryLinksResult> {
51
+ const direction = input.direction ?? "both"
52
+ if (direction !== "outgoing" && direction !== "incoming" && direction !== "both") {
53
+ throw new ObjectQueryExecutionError(
54
+ "invalid_link_direction",
55
+ "direction must be 'outgoing', 'incoming', or 'both'",
56
+ "$.direction"
57
+ )
58
+ }
59
+ if (input.linkId !== undefined && input.linkId.length === 0) {
60
+ throw new ObjectQueryExecutionError("invalid_link_id", "linkId must not be empty", "$.linkId")
61
+ }
62
+
63
+ const pageSize = input.pageSize ?? DEFAULT_LINK_PAGE_SIZE
64
+ if (!Number.isInteger(pageSize) || pageSize <= 0 || pageSize > MAX_LINK_PAGE_SIZE) {
65
+ throw new ObjectQueryExecutionError(
66
+ "invalid_link_page_size",
67
+ `pageSize must be an integer between 1 and ${MAX_LINK_PAGE_SIZE}`,
68
+ "$.pageSize"
69
+ )
70
+ }
71
+ const validated = validateObjectQuery(normalizeObjectQuery(input.query), {
72
+ ontology: options.ontology,
73
+ maxLimit: options.maxLimit,
74
+ maxPageSize: options.maxPageSize,
75
+ maxRefs: options.maxRefs,
76
+ normalize: false,
77
+ })
78
+ assertLinkSelectorShape(validated.query)
79
+ const selectorQuery = validated.query
80
+ const pageScope = linkPageScope(input.projectId, selectorQuery, direction, input.linkId)
81
+ const cursor = decodeLinkPageToken(input.pageToken, pageScope)
82
+
83
+ // A root page already has an explicit result bound and must execute directly: nesting it under a
84
+ // probe limit would expose the provider's internal pageSize+1 row. All other selector shapes are
85
+ // capped here before the provider receives the selected identities.
86
+ const boundedSelector =
87
+ selectorQuery.kind === "page"
88
+ ? selectorQuery
89
+ : { kind: "limit" as const, limit: MAX_LINK_QUERY_OBJECTS + 1, input: selectorQuery }
90
+ const selection = await executeObjectQuery(
91
+ {
92
+ projectId: input.projectId,
93
+ query: boundedSelector,
94
+ includeTotal: false,
95
+ },
96
+ {
97
+ ...options,
98
+ maxLimit: Math.max(options.maxLimit ?? 1_000, MAX_LINK_QUERY_OBJECTS + 1),
99
+ }
100
+ )
101
+ if (selection.objects.length > MAX_LINK_QUERY_OBJECTS) {
102
+ throw new ObjectQueryExecutionError(
103
+ "link_query_object_limit_exceeded",
104
+ `Link query selected more than ${MAX_LINK_QUERY_OBJECTS} objects; add a limit or page node`,
105
+ "$.query"
106
+ )
107
+ }
108
+
109
+ const selected = selection.objects
110
+ if (selected.length === 0) {
111
+ return { objects: [], links: [], hasMore: false }
112
+ }
113
+
114
+ const endpointObjectTypeIds = visibleEndpointTypeIds(options)
115
+ const page = await options.storage.queryLinks({
116
+ projectId: input.projectId,
117
+ objectRefs: selected.map((row) => ({
118
+ objectTypeId: row.objectTypeId,
119
+ primaryId: row.primaryId,
120
+ })),
121
+ direction,
122
+ ...(input.linkId === undefined ? {} : { linkId: input.linkId }),
123
+ ...(endpointObjectTypeIds === undefined ? {} : { endpointObjectTypeIds }),
124
+ ...(cursor === undefined ? {} : { after: cursor }),
125
+ limit: pageSize,
126
+ })
127
+ const lastLink = page.links.at(-1)
128
+ let nextPageToken: string | undefined
129
+ if (page.hasMore) {
130
+ if (!lastLink) {
131
+ throw new Error("[Sixb] Object storage returned hasMore for an empty link page.")
132
+ }
133
+ nextPageToken = encodeLinkPageToken(objectLinkCursor(lastLink), pageScope)
134
+ }
135
+ const objects = input.includeObjects
136
+ ? await hydrateLinkQueryObjects(input.projectId, selected, page.links, options.storage)
137
+ : []
138
+
139
+ return {
140
+ objects,
141
+ links: page.links,
142
+ hasMore: page.hasMore,
143
+ ...(nextPageToken ? { nextPageToken } : {}),
144
+ }
145
+ }
146
+
147
+ interface EncodedLinkPageToken {
148
+ version: 1
149
+ scope: string
150
+ cursor: ObjectLinkCursor
151
+ }
152
+
153
+ function assertLinkSelectorShape(query: ObjectQuery, path = "$.query", root = true): void {
154
+ switch (query.kind) {
155
+ case "project":
156
+ case "expand":
157
+ throw new ObjectQueryExecutionError(
158
+ "link_selector_output_shape_not_supported",
159
+ `Link selectors do not support '${query.kind}' nodes; remove output shaping from the selector`,
160
+ path
161
+ )
162
+ case "page":
163
+ if (!root) {
164
+ throw new ObjectQueryExecutionError(
165
+ "link_selector_page_must_be_root",
166
+ "A page node in a link selector must be the outermost node",
167
+ path
168
+ )
169
+ }
170
+ assertLinkSelectorShape(query.input, `${path}.input`, false)
171
+ return
172
+ case "start":
173
+ case "refs":
174
+ return
175
+ case "set": {
176
+ for (const [index, input] of query.inputs.entries()) {
177
+ assertLinkSelectorShape(input, `${path}.inputs[${index}]`, false)
178
+ }
179
+ return
180
+ }
181
+ case "filter":
182
+ case "text":
183
+ case "vector":
184
+ case "traverse":
185
+ case "sort":
186
+ case "limit":
187
+ assertLinkSelectorShape(query.input, `${path}.input`, false)
188
+ return
189
+ }
190
+ }
191
+
192
+ function visibleEndpointTypeIds(options: QueryExecutorOptions): readonly string[] | undefined {
193
+ if (!options.authorization) return undefined
194
+ return options.ontology
195
+ .listObjectTypes()
196
+ .filter((objectType) =>
197
+ isAllowed(options.authorization, { kind: "object.view", objectTypeId: objectType.id })
198
+ )
199
+ .map((objectType) => objectType.id)
200
+ }
201
+
202
+ function objectIdentity(objectTypeId: string, primaryId: string): ObjectBatchKey {
203
+ return objectBatchKey(objectTypeId, primaryId)
204
+ }
205
+
206
+ function linkPageScope(
207
+ projectId: string,
208
+ query: ObjectQuery,
209
+ direction: LinkDirection,
210
+ linkId: string | undefined
211
+ ): string {
212
+ return createHash("sha256")
213
+ .update(
214
+ stableJsonStringify({
215
+ projectId,
216
+ query,
217
+ direction,
218
+ linkId: linkId ?? null,
219
+ })
220
+ )
221
+ .digest("base64url")
222
+ }
223
+
224
+ function encodeLinkPageToken(cursor: ObjectLinkCursor, scope: string): string {
225
+ const payload: EncodedLinkPageToken = { version: 1, scope, cursor }
226
+ return `${LINK_PAGE_TOKEN_PREFIX}${Buffer.from(JSON.stringify(payload)).toString("base64url")}`
227
+ }
228
+
229
+ function decodeLinkPageToken(
230
+ token: string | undefined,
231
+ expectedScope: string
232
+ ): ObjectLinkCursor | undefined {
233
+ if (token === undefined) return undefined
234
+ try {
235
+ if (!token.startsWith(LINK_PAGE_TOKEN_PREFIX)) throw new Error("invalid prefix")
236
+ const value = JSON.parse(
237
+ Buffer.from(token.slice(LINK_PAGE_TOKEN_PREFIX.length), "base64url").toString("utf8")
238
+ ) as unknown
239
+ if (
240
+ !isPlainObject(value) ||
241
+ value.version !== 1 ||
242
+ typeof value.scope !== "string" ||
243
+ !isObjectLinkCursor(value.cursor)
244
+ ) {
245
+ throw new Error("invalid cursor")
246
+ }
247
+ if (value.scope !== expectedScope) {
248
+ throw new Error("cursor scope mismatch")
249
+ }
250
+ return value.cursor
251
+ } catch {
252
+ throw new ObjectQueryExecutionError(
253
+ "invalid_link_page_token",
254
+ "pageToken is not a valid object-links cursor",
255
+ "$.pageToken"
256
+ )
257
+ }
258
+ }
259
+
260
+ function isObjectLinkCursor(value: unknown): value is ObjectLinkCursor {
261
+ return (
262
+ Array.isArray(value) && value.length === 5 && value.every((part) => typeof part === "string")
263
+ )
264
+ }
265
+
266
+ function isPlainObject(value: unknown): value is Record<string, unknown> {
267
+ return typeof value === "object" && value !== null && !Array.isArray(value)
268
+ }
269
+
270
+ async function hydrateLinkQueryObjects(
271
+ projectId: string,
272
+ selected: readonly ObjectRow[],
273
+ links: readonly ObjectLinkRow[],
274
+ storage: ObjectStorage
275
+ ): Promise<ObjectRow[]> {
276
+ const byIdentity = new Map(
277
+ selected.map((row) => [objectIdentity(row.objectTypeId, row.primaryId), row])
278
+ )
279
+ const orderedIdentities = selected.map((row) => objectIdentity(row.objectTypeId, row.primaryId))
280
+ const seenIdentities = new Set(orderedIdentities)
281
+ const missingRefs: { objectTypeId: string; primaryId: string }[] = []
282
+
283
+ for (const link of links) {
284
+ for (const ref of [
285
+ { objectTypeId: link.sourceTypeId, primaryId: link.sourceId },
286
+ { objectTypeId: link.targetTypeId, primaryId: link.targetId },
287
+ ]) {
288
+ const identity = objectIdentity(ref.objectTypeId, ref.primaryId)
289
+ if (seenIdentities.has(identity)) continue
290
+ seenIdentities.add(identity)
291
+ orderedIdentities.push(identity)
292
+ missingRefs.push(ref)
293
+ }
294
+ }
295
+
296
+ if (missingRefs.length > 0) {
297
+ const hydrated = await storage.getByPrimaryIdBatch({ projectId, items: missingRefs })
298
+ for (const ref of missingRefs) {
299
+ const row = hydrated.get(objectBatchKey(ref.objectTypeId, ref.primaryId))
300
+ if (row) byIdentity.set(objectIdentity(ref.objectTypeId, ref.primaryId), row)
301
+ }
302
+ }
303
+
304
+ return orderedIdentities.flatMap((identity) => {
305
+ const row = byIdentity.get(identity)
306
+ return row ? [row] : []
307
+ })
308
+ }
@@ -22,6 +22,11 @@ function normalizeNode(query: ObjectQuery): ObjectQuery {
22
22
  switch (query.kind) {
23
23
  case "start":
24
24
  return { ...query }
25
+ case "refs":
26
+ return {
27
+ kind: "refs",
28
+ refs: uniqueRefs(query.refs),
29
+ }
25
30
  case "filter":
26
31
  return normalizeFilter(query.input, query.predicate)
27
32
  case "text":
@@ -63,7 +68,14 @@ function normalizeNode(query: ObjectQuery): ObjectQuery {
63
68
  * lands above another `expand` is merged into one.
64
69
  */
65
70
  function hoistExpand(query: ObjectQuery): ObjectQuery {
66
- if (query.kind === "start" || query.kind === "set" || query.kind === "expand") return query
71
+ if (
72
+ query.kind === "start" ||
73
+ query.kind === "refs" ||
74
+ query.kind === "set" ||
75
+ query.kind === "expand"
76
+ ) {
77
+ return query
78
+ }
67
79
  if (query.input.kind !== "expand") return query
68
80
 
69
81
  const inner = query.input
@@ -236,6 +248,33 @@ function uniqueStrings(values: readonly string[]): string[] {
236
248
  return [...new Set(values)]
237
249
  }
238
250
 
251
+ function uniqueRefs(
252
+ refs: readonly { objectTypeId: string; primaryId: string }[]
253
+ ): { objectTypeId: string; primaryId: string }[] {
254
+ const seen = new Set<string>()
255
+ const unique = refs.flatMap((ref) => {
256
+ const key = JSON.stringify([ref.objectTypeId, ref.primaryId])
257
+ if (seen.has(key)) return []
258
+ seen.add(key)
259
+ return [{ ...ref }]
260
+ })
261
+
262
+ // `refs` is an object-set source, not a positional batch response. Canonical
263
+ // identity order makes equivalent sets normalize identically and matches the
264
+ // default ordering used by provider query sources.
265
+ return unique.sort(
266
+ (left, right) =>
267
+ compareStrings(left.objectTypeId, right.objectTypeId) ||
268
+ compareStrings(left.primaryId, right.primaryId)
269
+ )
270
+ }
271
+
272
+ function compareStrings(left: string, right: string): number {
273
+ if (left < right) return -1
274
+ if (left > right) return 1
275
+ return 0
276
+ }
277
+
239
278
  function uniqueStringRecord(
240
279
  record: Readonly<Record<string, readonly string[]>>
241
280
  ): Record<string, string[]> {
@@ -40,6 +40,7 @@ const DEFAULT_MAX_FALLBACK_ROWS = 1_000
40
40
  // accidental full scans.
41
41
  const fallbackNodeKinds = new Set<ObjectQuery["kind"]>([
42
42
  "start",
43
+ "refs",
43
44
  "filter",
44
45
  "sort",
45
46
  "limit",
@@ -195,6 +196,8 @@ function collectNodeProviderIssues(
195
196
  )
196
197
  }
197
198
  return
199
+ case "refs":
200
+ return
198
201
  case "filter":
199
202
  collectPredicateProviderIssues(query.predicate, `${path}.predicate`, capabilities, issues)
200
203
  collectNodeProviderIssues(query.input, `${path}.input`, capabilities, issues)
@@ -474,6 +477,7 @@ function collectFallbackNodeIssues(
474
477
 
475
478
  switch (query.kind) {
476
479
  case "start":
480
+ case "refs":
477
481
  return
478
482
  case "filter":
479
483
  case "limit":
@@ -512,6 +516,7 @@ function hasExplicitResultBound(query: ObjectQuery): boolean {
512
516
  switch (query.kind) {
513
517
  case "limit":
514
518
  case "page":
519
+ case "refs":
515
520
  return true
516
521
  case "start":
517
522
  return false