@agentshouse/mdruntime 0.1.0-cb1f56e16291b → 0.1.0-cb3bb3b233fa1

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 (327) hide show
  1. package/README.md +21 -19
  2. package/dist/acceptance.d.ts +3 -0
  3. package/dist/acceptance.d.ts.map +1 -0
  4. package/dist/acceptance.js +299 -0
  5. package/dist/act-lanes.d.ts +30 -0
  6. package/dist/act-lanes.d.ts.map +1 -0
  7. package/dist/act-lanes.js +225 -0
  8. package/dist/actions.d.ts +26 -0
  9. package/dist/actions.d.ts.map +1 -0
  10. package/dist/actions.js +302 -0
  11. package/dist/adapter.d.ts +113 -81
  12. package/dist/adapter.d.ts.map +1 -1
  13. package/dist/attached-model.d.ts +3 -11
  14. package/dist/attached-model.d.ts.map +1 -1
  15. package/dist/attached-model.js +20 -60
  16. package/dist/authored.d.ts +88 -0
  17. package/dist/authored.d.ts.map +1 -0
  18. package/dist/authored.js +345 -0
  19. package/dist/bootstrap.d.ts +9 -5
  20. package/dist/bootstrap.d.ts.map +1 -1
  21. package/dist/bootstrap.js +204 -85
  22. package/dist/cell.d.ts +6 -0
  23. package/dist/cell.d.ts.map +1 -0
  24. package/dist/cell.js +9 -0
  25. package/dist/chain.d.ts +2 -1
  26. package/dist/chain.d.ts.map +1 -1
  27. package/dist/change-set.d.ts +4 -0
  28. package/dist/change-set.d.ts.map +1 -1
  29. package/dist/change-set.js +6 -0
  30. package/dist/change.d.ts +5 -0
  31. package/dist/change.d.ts.map +1 -1
  32. package/dist/change.js +7 -2
  33. package/dist/chat-types.d.ts +3 -0
  34. package/dist/chat-types.d.ts.map +1 -0
  35. package/dist/chat-types.js +11 -0
  36. package/dist/client.d.ts +30 -22
  37. package/dist/client.d.ts.map +1 -1
  38. package/dist/client.js +39 -20
  39. package/dist/collection.d.ts +26 -4
  40. package/dist/collection.d.ts.map +1 -1
  41. package/dist/collection.js +19 -2
  42. package/dist/column.d.ts +5 -0
  43. package/dist/column.d.ts.map +1 -0
  44. package/dist/column.js +9 -0
  45. package/dist/compile.d.ts +9 -7
  46. package/dist/compile.d.ts.map +1 -1
  47. package/dist/compile.js +252 -318
  48. package/dist/connection.d.ts +5 -141
  49. package/dist/connection.d.ts.map +1 -1
  50. package/dist/connection.js +111 -5282
  51. package/dist/context.d.ts.map +1 -1
  52. package/dist/context.js +1 -1
  53. package/dist/conversation-live.d.ts +150 -0
  54. package/dist/conversation-live.d.ts.map +1 -0
  55. package/dist/conversation-live.js +259 -0
  56. package/dist/conversation-row.d.ts +40 -0
  57. package/dist/conversation-row.d.ts.map +1 -0
  58. package/dist/conversation-row.js +66 -0
  59. package/dist/conversation.d.ts +62 -43
  60. package/dist/conversation.d.ts.map +1 -1
  61. package/dist/conversation.js +987 -902
  62. package/dist/declaration.d.ts +10 -0
  63. package/dist/declaration.d.ts.map +1 -0
  64. package/dist/declaration.js +24 -0
  65. package/dist/discovery.d.ts +10 -0
  66. package/dist/discovery.d.ts.map +1 -0
  67. package/dist/discovery.js +150 -0
  68. package/dist/durability.d.ts +19 -0
  69. package/dist/durability.d.ts.map +1 -1
  70. package/dist/durability.js +4 -0
  71. package/dist/entry.d.ts +2 -2
  72. package/dist/entry.d.ts.map +1 -1
  73. package/dist/entry.js +18 -9
  74. package/dist/expectation.d.ts +26 -13
  75. package/dist/expectation.d.ts.map +1 -1
  76. package/dist/expectation.js +72 -19
  77. package/dist/failure.d.ts +3 -0
  78. package/dist/failure.d.ts.map +1 -1
  79. package/dist/failure.js +6 -0
  80. package/dist/figures.d.ts +49 -0
  81. package/dist/figures.d.ts.map +1 -0
  82. package/dist/figures.js +199 -0
  83. package/dist/file.d.ts +1 -1
  84. package/dist/file.d.ts.map +1 -1
  85. package/dist/file.js +3 -2
  86. package/dist/holdings.d.ts +29 -0
  87. package/dist/holdings.d.ts.map +1 -0
  88. package/dist/holdings.js +95 -0
  89. package/dist/host.d.ts +20 -4
  90. package/dist/host.d.ts.map +1 -1
  91. package/dist/host.js +72 -28
  92. package/dist/identity.d.ts +0 -1
  93. package/dist/identity.d.ts.map +1 -1
  94. package/dist/identity.js +0 -3
  95. package/dist/index.d.ts +32 -12
  96. package/dist/index.d.ts.map +1 -1
  97. package/dist/index.js +14 -5
  98. package/dist/install.d.ts +60 -0
  99. package/dist/install.d.ts.map +1 -0
  100. package/dist/install.js +537 -0
  101. package/dist/lifecycle.d.ts +7 -0
  102. package/dist/lifecycle.d.ts.map +1 -0
  103. package/dist/lifecycle.js +282 -0
  104. package/dist/listing.d.ts +52 -0
  105. package/dist/listing.d.ts.map +1 -0
  106. package/dist/listing.js +152 -0
  107. package/dist/live.d.ts +8 -6
  108. package/dist/live.d.ts.map +1 -1
  109. package/dist/live.js +110 -31
  110. package/dist/loaded.d.ts +5 -0
  111. package/dist/loaded.d.ts.map +1 -0
  112. package/dist/loaded.js +40 -0
  113. package/dist/locks.d.ts +7 -0
  114. package/dist/locks.d.ts.map +1 -0
  115. package/dist/locks.js +32 -0
  116. package/dist/lost.d.ts +5 -0
  117. package/dist/lost.d.ts.map +1 -0
  118. package/dist/lost.js +49 -0
  119. package/dist/media.d.ts +6 -1
  120. package/dist/media.d.ts.map +1 -1
  121. package/dist/media.js +68 -17
  122. package/dist/memory.d.ts +11 -3
  123. package/dist/memory.d.ts.map +1 -1
  124. package/dist/memory.js +132 -33
  125. package/dist/messages.d.ts +33 -3
  126. package/dist/messages.d.ts.map +1 -1
  127. package/dist/messages.js +98 -27
  128. package/dist/model.d.ts +2 -10
  129. package/dist/model.d.ts.map +1 -1
  130. package/dist/model.js +0 -14
  131. package/dist/models.d.ts +10 -0
  132. package/dist/models.d.ts.map +1 -0
  133. package/dist/models.js +153 -0
  134. package/dist/observation.d.ts +27 -12
  135. package/dist/observation.d.ts.map +1 -1
  136. package/dist/observation.js +184 -85
  137. package/dist/opened.d.ts +1 -1
  138. package/dist/opened.d.ts.map +1 -1
  139. package/dist/opened.js +5 -5
  140. package/dist/opening.d.ts +4 -0
  141. package/dist/opening.d.ts.map +1 -0
  142. package/dist/opening.js +53 -0
  143. package/dist/outcome.d.ts +17 -2
  144. package/dist/outcome.d.ts.map +1 -1
  145. package/dist/outcome.js +35 -2
  146. package/dist/overlay.d.ts +7 -2
  147. package/dist/overlay.d.ts.map +1 -1
  148. package/dist/overlay.js +48 -24
  149. package/dist/page-metadata.d.ts +8 -0
  150. package/dist/page-metadata.d.ts.map +1 -0
  151. package/dist/page-metadata.js +19 -0
  152. package/dist/parts.d.ts +4 -0
  153. package/dist/parts.d.ts.map +1 -0
  154. package/dist/parts.js +13 -0
  155. package/dist/paths.d.ts +1 -0
  156. package/dist/paths.d.ts.map +1 -1
  157. package/dist/paths.js +22 -0
  158. package/dist/preparation.d.ts +41 -0
  159. package/dist/preparation.d.ts.map +1 -0
  160. package/dist/preparation.js +314 -0
  161. package/dist/presence.d.ts +58 -0
  162. package/dist/presence.d.ts.map +1 -0
  163. package/dist/presence.js +231 -0
  164. package/dist/queries.d.ts +16 -0
  165. package/dist/queries.d.ts.map +1 -0
  166. package/dist/queries.js +308 -0
  167. package/dist/query.d.ts +13 -213
  168. package/dist/query.d.ts.map +1 -1
  169. package/dist/query.js +3 -524
  170. package/dist/questions.d.ts +30 -0
  171. package/dist/questions.d.ts.map +1 -0
  172. package/dist/questions.js +116 -0
  173. package/dist/queue.d.ts +40 -0
  174. package/dist/queue.d.ts.map +1 -0
  175. package/dist/queue.js +480 -0
  176. package/dist/reach.d.ts +10 -10
  177. package/dist/reach.d.ts.map +1 -1
  178. package/dist/reach.js +235 -120
  179. package/dist/react.d.ts +17 -3
  180. package/dist/react.d.ts.map +1 -1
  181. package/dist/react.js +33 -1
  182. package/dist/read.d.ts +7 -0
  183. package/dist/read.d.ts.map +1 -0
  184. package/dist/read.js +17 -0
  185. package/dist/readiness.d.ts +9 -4
  186. package/dist/readiness.d.ts.map +1 -1
  187. package/dist/readiness.js +3 -5
  188. package/dist/reads.d.ts +39 -0
  189. package/dist/reads.d.ts.map +1 -0
  190. package/dist/reads.js +178 -0
  191. package/dist/recovery.d.ts +3 -1
  192. package/dist/recovery.d.ts.map +1 -1
  193. package/dist/recovery.js +38 -8
  194. package/dist/refresh.d.ts +1 -1
  195. package/dist/refresh.d.ts.map +1 -1
  196. package/dist/refresh.js +10 -22
  197. package/dist/refusal.d.ts +5 -0
  198. package/dist/refusal.d.ts.map +1 -0
  199. package/dist/refusal.js +55 -0
  200. package/dist/replica.d.ts +11 -16
  201. package/dist/replica.d.ts.map +1 -1
  202. package/dist/replica.js +66 -35
  203. package/dist/retried.d.ts +30 -0
  204. package/dist/retried.d.ts.map +1 -0
  205. package/dist/retried.js +72 -0
  206. package/dist/room-draft.d.ts +32 -9
  207. package/dist/room-draft.d.ts.map +1 -1
  208. package/dist/room-draft.js +273 -66
  209. package/dist/room-drafts.d.ts +24 -0
  210. package/dist/room-drafts.d.ts.map +1 -0
  211. package/dist/room-drafts.js +220 -0
  212. package/dist/room-list.d.ts +10 -0
  213. package/dist/room-list.d.ts.map +1 -0
  214. package/dist/room-list.js +45 -0
  215. package/dist/rows.d.ts +16 -23
  216. package/dist/rows.d.ts.map +1 -1
  217. package/dist/rows.js +49 -191
  218. package/dist/runtime.d.ts +34 -0
  219. package/dist/runtime.d.ts.map +1 -0
  220. package/dist/runtime.js +1 -0
  221. package/dist/save.d.ts +42 -86
  222. package/dist/save.d.ts.map +1 -1
  223. package/dist/save.js +332 -228
  224. package/dist/saves.d.ts +34 -0
  225. package/dist/saves.d.ts.map +1 -0
  226. package/dist/saves.js +437 -0
  227. package/dist/search.d.ts.map +1 -1
  228. package/dist/search.js +1 -1
  229. package/dist/seed.d.ts +11 -2
  230. package/dist/seed.d.ts.map +1 -1
  231. package/dist/seed.js +71 -1
  232. package/dist/shared.d.ts +1 -6
  233. package/dist/shared.d.ts.map +1 -1
  234. package/dist/shared.js +13 -95
  235. package/dist/shown.d.ts +33 -0
  236. package/dist/shown.d.ts.map +1 -0
  237. package/dist/shown.js +309 -0
  238. package/dist/socket/admission.d.ts +7 -0
  239. package/dist/socket/admission.d.ts.map +1 -0
  240. package/dist/socket/admission.js +39 -0
  241. package/dist/socket/answers.d.ts +6 -0
  242. package/dist/socket/answers.d.ts.map +1 -0
  243. package/dist/socket/answers.js +20 -0
  244. package/dist/socket/lanes.d.ts +28 -0
  245. package/dist/socket/lanes.d.ts.map +1 -0
  246. package/dist/socket/lanes.js +103 -0
  247. package/dist/socket/reads.d.ts +10 -0
  248. package/dist/socket/reads.d.ts.map +1 -0
  249. package/dist/socket/reads.js +31 -0
  250. package/dist/socket/session.d.ts +38 -0
  251. package/dist/socket/session.d.ts.map +1 -0
  252. package/dist/socket/session.js +23 -0
  253. package/dist/socket.d.ts +67 -0
  254. package/dist/socket.d.ts.map +1 -0
  255. package/dist/socket.js +164 -0
  256. package/dist/source.d.ts +59 -0
  257. package/dist/source.d.ts.map +1 -0
  258. package/dist/source.js +93 -0
  259. package/dist/status.d.ts +0 -2
  260. package/dist/status.d.ts.map +1 -1
  261. package/dist/status.js +0 -6
  262. package/dist/store/installs.d.ts +30 -0
  263. package/dist/store/installs.d.ts.map +1 -0
  264. package/dist/store/installs.js +40 -0
  265. package/dist/store/readiness.d.ts +11 -0
  266. package/dist/store/readiness.d.ts.map +1 -0
  267. package/dist/store/readiness.js +68 -0
  268. package/dist/store/records.d.ts +223 -0
  269. package/dist/store/records.d.ts.map +1 -0
  270. package/dist/store/records.js +465 -0
  271. package/dist/store/room-held.d.ts +8 -0
  272. package/dist/store/room-held.d.ts.map +1 -0
  273. package/dist/store/room-held.js +17 -0
  274. package/dist/store/rooms-shown.d.ts +8 -0
  275. package/dist/store/rooms-shown.d.ts.map +1 -0
  276. package/dist/store/rooms-shown.js +13 -0
  277. package/dist/store/space.d.ts +11 -0
  278. package/dist/store/space.d.ts.map +1 -0
  279. package/dist/store/space.js +41 -0
  280. package/dist/store/watchers.d.ts +17 -0
  281. package/dist/store/watchers.d.ts.map +1 -0
  282. package/dist/store/watchers.js +56 -0
  283. package/dist/store/writes.d.ts +24 -0
  284. package/dist/store/writes.d.ts.map +1 -0
  285. package/dist/store/writes.js +125 -0
  286. package/dist/store.d.ts +115 -152
  287. package/dist/store.d.ts.map +1 -1
  288. package/dist/store.js +171 -395
  289. package/dist/stored.d.ts +72 -67
  290. package/dist/stored.d.ts.map +1 -1
  291. package/dist/stored.js +317 -166
  292. package/dist/surface.d.ts +90 -0
  293. package/dist/surface.d.ts.map +1 -0
  294. package/dist/surface.js +225 -0
  295. package/dist/sync.d.ts +19 -0
  296. package/dist/sync.d.ts.map +1 -0
  297. package/dist/sync.js +536 -0
  298. package/dist/tables.d.ts +112 -89
  299. package/dist/tables.d.ts.map +1 -1
  300. package/dist/tables.js +197 -283
  301. package/dist/tallies.d.ts +18 -0
  302. package/dist/tallies.d.ts.map +1 -0
  303. package/dist/tallies.js +128 -0
  304. package/dist/validation.d.ts.map +1 -1
  305. package/dist/validation.js +9 -12
  306. package/dist/windows.d.ts +1 -12
  307. package/dist/windows.d.ts.map +1 -1
  308. package/dist/windows.js +2 -75
  309. package/dist/wire.d.ts +68 -7
  310. package/dist/wire.d.ts.map +1 -1
  311. package/dist/wire.js +23 -4
  312. package/package.json +3 -2
  313. package/dist/attempt.d.ts +0 -16
  314. package/dist/attempt.d.ts.map +0 -1
  315. package/dist/attempt.js +0 -70
  316. package/dist/fence.d.ts +0 -6
  317. package/dist/fence.d.ts.map +0 -1
  318. package/dist/fence.js +0 -10
  319. package/dist/job.d.ts +0 -14
  320. package/dist/job.d.ts.map +0 -1
  321. package/dist/job.js +0 -28
  322. package/dist/log.d.ts +0 -5
  323. package/dist/log.d.ts.map +0 -1
  324. package/dist/log.js +0 -14
  325. package/dist/phrase.d.ts +0 -3
  326. package/dist/phrase.d.ts.map +0 -1
  327. package/dist/phrase.js +0 -8
package/dist/memory.js CHANGED
@@ -1,11 +1,20 @@
1
+ import { definitionAt, documentFacts, keyedDestination, keyedLink, parse, } from '@agentshouse/mdmodel';
2
+ import { NO_ROOM_TYPES, schemaTypes } from './attached-model.js';
3
+ import { selected } from './collection.js';
4
+ import { declaredType } from './outcome.js';
1
5
  import { sameChange } from './overlay.js';
2
6
  const ATTACHMENTS = 'attachments';
7
+ const UNFOUND = {
8
+ kind: 'rejected',
9
+ code: 'not_found',
10
+ fields: {},
11
+ retryable: false,
12
+ };
3
13
  function lastName(path) {
4
14
  return path.slice(path.lastIndexOf('/') + 1);
5
15
  }
6
16
  const FIXTURE_RETENTION = {
7
17
  history: { kind: 'duration', seconds: 1 },
8
- outcome: 604_800,
9
18
  refreshHorizon: 1,
10
19
  };
11
20
  function declaredRetention(value) {
@@ -52,9 +61,10 @@ export function createMemoryAdapter(options = {}) {
52
61
  const listeners = new Set();
53
62
  const modeObservers = new Set();
54
63
  const scripted = new Map();
55
- const sentTurns = new Map();
64
+ const repeats = new Map();
56
65
  const historyPageSize = options.historyPageSize;
57
66
  const attached = new Map();
67
+ const keyed = new Map();
58
68
  const linked = new WeakMap();
59
69
  const carried = new Map();
60
70
  let expiring = [];
@@ -62,6 +72,7 @@ export function createMemoryAdapter(options = {}) {
62
72
  const declaredRooms = new Set();
63
73
  let replicated = [];
64
74
  let heldCursor = null;
75
+ let agents = structuredClone(options.agents ?? []);
65
76
  let issued = 0;
66
77
  function scriptConversations(entries) {
67
78
  scripted.clear();
@@ -92,6 +103,25 @@ export function createMemoryAdapter(options = {}) {
92
103
  function heldBlob(room, path) {
93
104
  return attached.get(`${room.locator}\u0000${path}`) ?? room.blobs?.[path];
94
105
  }
106
+ function linkTo(room, path) {
107
+ const blob = room === undefined ? undefined : heldBlob(room, path);
108
+ if (blob === undefined)
109
+ return UNFOUND;
110
+ const url = linked.get(blob) ?? URL.createObjectURL(blob);
111
+ linked.set(blob, url);
112
+ return { kind: 'link', url, name: lastName(path), mediaType: declaredType(blob) };
113
+ }
114
+ function attachedKeyed(request) {
115
+ const room = rooms.find((entry) => entry.locator === options.privateRoom);
116
+ if (room === undefined) {
117
+ return { kind: 'rejected', code: 'room_not_found', fields: {}, retryable: false };
118
+ }
119
+ const path = freePath(room, request.name);
120
+ attached.set(`${room.locator}\u0000${path}`, request.blob);
121
+ const key = `memory-${keyed.size + 1}`;
122
+ keyed.set(key, { locator: room.locator, path });
123
+ return { kind: 'linked', link: keyedDestination(`/rooms/${room.handle}/${path}`, key) };
124
+ }
95
125
  function freePath(room, name) {
96
126
  const dot = name.lastIndexOf('.');
97
127
  const stem = dot > 0 ? name.slice(0, dot) : name;
@@ -102,8 +132,40 @@ export function createMemoryAdapter(options = {}) {
102
132
  return path;
103
133
  }
104
134
  }
135
+ const saved = new WeakMap();
136
+ const roomTypes = options.roomTypes ?? NO_ROOM_TYPES;
137
+ function factsAt(room, path, content) {
138
+ const types = selected({ selection: room.typedSelection ?? null }, path)
139
+ ? roomTypes.types
140
+ : schemaTypes(room.model?.kind === 'model' ? room.model.snapshot.schema : null, roomTypes);
141
+ let held = saved.get(types);
142
+ if (held === undefined) {
143
+ held = new Map();
144
+ saved.set(types, held);
145
+ }
146
+ const key = `${path}\u0000${content}`;
147
+ if (!held.has(key)) {
148
+ const facts = documentFacts(path, parse(content, path, definitionAt({ types }, path, options.typedPaths)), {
149
+ types,
150
+ });
151
+ held.set(key, facts === null ? null : JSON.parse(JSON.stringify(facts)));
152
+ }
153
+ return held.get(key);
154
+ }
155
+ function factsIn(room, paths) {
156
+ const facts = {};
157
+ for (const path of paths) {
158
+ const content = room.documents?.[path];
159
+ const held = room.facts?.[path] ?? (content === undefined ? null : factsAt(room, path, content));
160
+ if (held !== null)
161
+ facts[path] = held;
162
+ }
163
+ return facts;
164
+ }
105
165
  function retain(entries) {
106
166
  for (const room of entries) {
167
+ for (const [path, content] of Object.entries(room.documents ?? {}))
168
+ factsAt(room, path, content);
107
169
  note(room.locator, room);
108
170
  const versions = served.get(room.locator) ?? new Map();
109
171
  versions.set(room.roomVersion, room);
@@ -119,8 +181,9 @@ export function createMemoryAdapter(options = {}) {
119
181
  roomVersion: room.roomVersion,
120
182
  operations: room.operations,
121
183
  replica: room.replica,
122
- ...(room.typedSelection === undefined ? {} : { typedSelection: room.typedSelection }),
184
+ typedSelection: room.typedSelection ?? null,
123
185
  providerOwnedPaths: room.providerOwnedPaths,
186
+ authoredPaths: room.authoredPaths ?? ['**'],
124
187
  };
125
188
  }
126
189
  function page(room, after) {
@@ -136,10 +199,14 @@ export function createMemoryAdapter(options = {}) {
136
199
  roomVersion: room.roomVersion,
137
200
  ...(opening ? { models: modelsOf(room) } : {}),
138
201
  documents: named(room.documents ?? {}, taken),
202
+ facts: factsIn(room, taken),
139
203
  revisions: named(room.revisions ?? {}, [...taken, ...targets]),
140
204
  ...(room.fileIds === undefined
141
205
  ? {}
142
206
  : { fileIds: named(room.fileIds, [...taken, ...targets]) }),
207
+ ...(room.created === undefined
208
+ ? {}
209
+ : { created: named(room.created, [...taken, ...targets]) }),
143
210
  changes: named(room.changes ?? {}, [...taken, ...targets]),
144
211
  binaryFiles: named(room.binaryFiles ?? {}, targets),
145
212
  ...(opening && room.folders !== undefined ? { folders: room.folders } : {}),
@@ -163,6 +230,7 @@ export function createMemoryAdapter(options = {}) {
163
230
  const previousTargets = new Set(Object.keys(from.binaryFiles ?? {}));
164
231
  const headMoved = (path) => room.revisions?.[path] !== from.revisions?.[path] ||
165
232
  room.fileIds?.[path] !== from.fileIds?.[path] ||
233
+ room.created?.[path] !== from.created?.[path] ||
166
234
  !sameChange(room.changes?.[path], from.changes?.[path]);
167
235
  const changed = Object.keys(current)
168
236
  .filter((path) => current[path] !== previous[path] || headMoved(path))
@@ -183,10 +251,14 @@ export function createMemoryAdapter(options = {}) {
183
251
  roomVersion: room.roomVersion,
184
252
  ...(models === undefined ? {} : { models }),
185
253
  documents: named(current, taken),
254
+ facts: factsIn(room, taken),
186
255
  revisions: named(room.revisions ?? {}, [...taken, ...targets]),
187
256
  ...(room.fileIds === undefined
188
257
  ? {}
189
258
  : { fileIds: named(room.fileIds, [...taken, ...targets]) }),
259
+ ...(room.created === undefined
260
+ ? {}
261
+ : { created: named(room.created, [...taken, ...targets]) }),
190
262
  changes: named(room.changes ?? {}, [...taken, ...targets]),
191
263
  binaryFiles: named(room.binaryFiles ?? {}, targets),
192
264
  ...(opening ? foldersMoved(room, from) : {}),
@@ -221,16 +293,14 @@ export function createMemoryAdapter(options = {}) {
221
293
  }
222
294
  function pageOf(conversation, after) {
223
295
  const messages = conversation.messages ?? [];
224
- const first = typeof after === 'string' ? messages.findIndex((message) => message.position > after) : 0;
296
+ const first = typeof after === 'string' ? messages.findIndex((message) => message.change > after) : 0;
225
297
  const from = first === -1 ? messages.length : first;
226
298
  const page = messages.slice(from, from + (historyPageSize ?? messages.length));
227
299
  const last = page.at(-1);
228
300
  return {
229
301
  conversation: conversation.conversation,
230
302
  messages: page,
231
- ...(last !== undefined && from + page.length < messages.length
232
- ? { next: last.position }
233
- : {}),
303
+ ...(last !== undefined && from + page.length < messages.length ? { next: last.change } : {}),
234
304
  };
235
305
  }
236
306
  function historiesOf(request) {
@@ -250,11 +320,20 @@ export function createMemoryAdapter(options = {}) {
250
320
  function conversationAction(request) {
251
321
  const name = request.name;
252
322
  const input = (request.input ?? {});
323
+ const operation = typeof input.operation_id === 'string' ? `${name}\u0000${input.operation_id}` : null;
324
+ const first = (answer) => {
325
+ if (operation !== null)
326
+ repeats.set(operation, answer);
327
+ return answer;
328
+ };
329
+ const repeated = operation === null ? undefined : repeats.get(operation);
253
330
  if (name === 'conversations/create') {
331
+ if (repeated !== undefined)
332
+ return repeated;
254
333
  issued += 1;
255
334
  const conversation = `conversation-${issued}`;
256
335
  scripted.set(conversation, { conversation });
257
- return { kind: 'action', result: { conversation_id: conversation } };
336
+ return first({ kind: 'action', result: { conversation_id: conversation } });
258
337
  }
259
338
  const named = typeof input.conversation_id === 'string' ? input.conversation_id : '';
260
339
  const conversation = scripted.get(named);
@@ -270,26 +349,39 @@ export function createMemoryAdapter(options = {}) {
270
349
  if (outcome !== undefined)
271
350
  return outcome;
272
351
  if (name === 'conversations/send') {
273
- const operation = typeof input.operation_id === 'string' ? input.operation_id : null;
274
- const answered = operation === null ? undefined : sentTurns.get(operation);
275
- if (answered !== undefined)
276
- return { kind: 'action', result: { message_id: answered } };
352
+ if (repeated !== undefined)
353
+ return repeated;
277
354
  issued += 1;
278
- const turn = `turn-${issued}`;
279
- if (operation !== null)
280
- sentTurns.set(operation, turn);
281
- return { kind: 'action', result: { message_id: turn } };
355
+ return first({ kind: 'action', result: { message_id: `turn-${issued}` } });
282
356
  }
283
357
  if (name === 'conversations/delete')
284
358
  scripted.delete(named);
285
359
  return { kind: 'action', result: { conversation_id: named } };
286
360
  }
361
+ function decided(request) {
362
+ const { request: asked, message, decision, } = (request.input ?? {});
363
+ return {
364
+ kind: 'action',
365
+ result: {
366
+ request: asked,
367
+ ...(message === undefined ? {} : { message }),
368
+ state: decision === 'approve' ? 'started' : 'declined',
369
+ },
370
+ };
371
+ }
287
372
  function announceList() {
288
373
  const entries = [...scripted.values()].flatMap(({ conversation, listed, messages = [] }) => listed === undefined
289
374
  ? []
290
- : [{ conversation, ...listed, newest: messages.at(-1)?.position ?? null }]);
375
+ : [{ conversation, ...listed, newest: messages.at(-1)?.change ?? null }]);
291
376
  for (const listener of listeners) {
292
- listener({ kind: 'list', entries, whole: true, more: false, cursor: null });
377
+ listener({
378
+ kind: 'list',
379
+ agents: structuredClone(agents),
380
+ entries,
381
+ whole: true,
382
+ more: false,
383
+ cursor: null,
384
+ });
293
385
  }
294
386
  }
295
387
  function discovery() {
@@ -337,6 +429,7 @@ export function createMemoryAdapter(options = {}) {
337
429
  }
338
430
  return {
339
431
  ...(options.roomTypes === undefined ? {} : { roomTypes: options.roomTypes }),
432
+ ...(options.typedPaths === undefined ? {} : { typedPaths: options.typedPaths }),
340
433
  setRooms(next) {
341
434
  rooms = [...next];
342
435
  retain(rooms);
@@ -344,6 +437,9 @@ export function createMemoryAdapter(options = {}) {
344
437
  setConversations(next) {
345
438
  scriptConversations(next);
346
439
  },
440
+ setAgents(next) {
441
+ agents = structuredClone(next);
442
+ },
347
443
  open() {
348
444
  carried.clear();
349
445
  announceList();
@@ -406,9 +502,6 @@ export function createMemoryAdapter(options = {}) {
406
502
  };
407
503
  },
408
504
  history: (request) => Promise.resolve(historiesOf(request)),
409
- ...(options.agents === undefined
410
- ? {}
411
- : { agents: () => Promise.resolve(structuredClone(options.agents)) }),
412
505
  },
413
506
  serviceMode: {
414
507
  observe(notify) {
@@ -423,9 +516,10 @@ export function createMemoryAdapter(options = {}) {
423
516
  const named = asked.map((room) => room.locator);
424
517
  const unknown = asked.flatMap((room) => {
425
518
  const current = rooms.find((entry) => entry.locator === room.locator);
519
+ const version = room.roomVersion;
426
520
  return current === undefined ||
427
- current.roomVersion === room.roomVersion ||
428
- served.get(room.locator)?.has(room.roomVersion) === true
521
+ (version !== null &&
522
+ (current.roomVersion === version || served.get(room.locator)?.has(version) === true))
429
523
  ? []
430
524
  : [room.locator];
431
525
  });
@@ -435,7 +529,7 @@ export function createMemoryAdapter(options = {}) {
435
529
  expiring = expiring.filter((locator) => !named.includes(locator));
436
530
  queueMicrotask(() => {
437
531
  for (const room of asked) {
438
- if (expired.includes(room.locator))
532
+ if (expired.includes(room.locator) || room.roomVersion === null)
439
533
  carried.delete(room.locator);
440
534
  else {
441
535
  carried.set(room.locator, room.roomVersion);
@@ -559,26 +653,29 @@ export function createMemoryAdapter(options = {}) {
559
653
  return { kind: 'room-not-readable', locator: request.locator };
560
654
  const blob = heldBlob(room, request.path);
561
655
  return blob === undefined
562
- ? { kind: 'rejected', code: 'file_not_found', fields: {}, retryable: false }
563
- : { kind: 'binary', body: blob.stream(), mediaType: blob.type };
656
+ ? { kind: 'rejected', code: 'not_found', fields: {}, retryable: false }
657
+ : { kind: 'binary', body: blob.stream(), mediaType: declaredType(blob) };
564
658
  }, request);
565
659
  },
566
660
  async link(_authorization, request) {
567
661
  return resolveScript(scripts.link, () => {
662
+ if (request.kind === 'key') {
663
+ const key = keyedLink(request.link)?.key;
664
+ const named = key === undefined ? undefined : keyed.get(key);
665
+ if (named === undefined)
666
+ return UNFOUND;
667
+ return linkTo(rooms.find((entry) => entry.locator === named.locator), named.path);
668
+ }
568
669
  const room = rooms.find((entry) => entry.locator === request.locator);
569
670
  if (room === undefined)
570
671
  return { kind: 'room-not-readable', locator: request.locator };
571
- const blob = heldBlob(room, request.path);
572
- if (blob === undefined) {
573
- return { kind: 'rejected', code: 'file_not_found', fields: {}, retryable: false };
574
- }
575
- const url = linked.get(blob) ?? URL.createObjectURL(blob);
576
- linked.set(blob, url);
577
- return { kind: 'link', url, name: lastName(request.path), mediaType: blob.type };
672
+ return linkTo(room, request.path);
578
673
  }, request);
579
674
  },
580
675
  async attach(_authorization, request) {
581
676
  return resolveScript(scripts.attach, () => {
677
+ if (request.locator === undefined)
678
+ return attachedKeyed(request);
582
679
  const room = rooms.find((entry) => entry.locator === request.locator);
583
680
  if (room === undefined)
584
681
  return { kind: 'room-not-readable', locator: request.locator };
@@ -591,6 +688,8 @@ export function createMemoryAdapter(options = {}) {
591
688
  return resolveScript(scripts.action, () => {
592
689
  if (request.name.startsWith('conversations/'))
593
690
  return conversationAction(request);
691
+ if (request.name === 'agent-functions/decide')
692
+ return decided(request);
594
693
  return { kind: 'rejected', code: 'unscripted-action', fields: {}, retryable: false };
595
694
  }, request).then((answer) => {
596
695
  if (answer.kind === 'action' && answer.at !== undefined)
@@ -1,6 +1,7 @@
1
1
  import type { AcceptedMessage } from './adapter.js';
2
2
  import type { Connection } from './tables.js';
3
3
  export declare const MESSAGE_TABLES: readonly string[];
4
+ export declare const ROWS = "WITH chosen AS (\n SELECT listed.value AS conversation,\n (SELECT id FROM conversation_messages WHERE conversation = listed.value AND json_extract(message, '$.role') = 'assistant' ORDER BY position DESC, identity DESC LIMIT 1) AS answer,\n (SELECT id FROM conversation_messages WHERE conversation = listed.value AND text <> '' ORDER BY position DESC, identity DESC LIMIT 1) AS said,\n (SELECT id FROM conversation_messages WHERE conversation = listed.value AND json_extract(message, '$.role') = 'house' ORDER BY position, identity LIMIT 1) AS opened,\n (SELECT id FROM conversation_messages WHERE conversation = listed.value AND json_extract(message, '$.role') = 'house' AND json_extract(message, '$.waiting') = 1 ORDER BY position, identity LIMIT 1) AS asking\n FROM json_each(?) AS listed\n )\n SELECT chosen.conversation AS conversation,\n substr(said.text, 1, 512) AS said_text,\n json_extract(said.message, '$.role') AS said_role,\n json_extract(said.message, '$.accepted_at') AS said_at,\n answer.turn AS answered,\n substr(json_extract(answer.message, '$.failure'), 1, 512) AS failure,\n (SELECT value FROM conversation_facts WHERE conversation = chosen.conversation AND name = 'openedTurn') AS opened_turn,\n json_extract(opened.message, '$.source') AS opened_source,\n json_extract(opened.message, '$.sender') AS opened_sender,\n asking.identity AS asking_identity,\n asking.text AS asking_text,\n json_extract(asking.message, '$.accepted_at') AS asking_at,\n json_extract(asking.message, '$.source') AS asking_source,\n json_extract(asking.message, '$.sender') AS asking_sender\n FROM chosen\n LEFT JOIN conversation_messages said ON said.id = chosen.said\n LEFT JOIN conversation_messages answer ON answer.id = chosen.answer\n LEFT JOIN conversation_messages opened ON opened.id = chosen.opened\n LEFT JOIN conversation_messages asking ON asking.id = chosen.asking";
4
5
  export type HeldConversation = {
5
6
  readonly conversation: string;
6
7
  readonly read: string | null | undefined;
@@ -10,6 +11,33 @@ export type MessageWindow = {
10
11
  readonly messages: AcceptedMessage[];
11
12
  readonly more: boolean;
12
13
  };
14
+ export type HeldSource = {
15
+ readonly source: unknown;
16
+ readonly sender: string | null;
17
+ };
18
+ export type HeldRow = {
19
+ readonly conversation: string;
20
+ readonly said: {
21
+ readonly text: string;
22
+ readonly role: string | null;
23
+ readonly at: string | null;
24
+ } | null;
25
+ readonly answered: string | null;
26
+ readonly openedTurn: string | null;
27
+ readonly failure: string | null;
28
+ readonly opened: HeldSource | null;
29
+ readonly asking: (HeldSource & {
30
+ readonly identity: string;
31
+ readonly text: string;
32
+ readonly at: string | null;
33
+ }) | null;
34
+ };
35
+ export type ConversationFact = 'openedTurn' | 'dismissedSuggestion';
36
+ export type HeldFact = {
37
+ readonly conversation: string;
38
+ readonly name: ConversationFact;
39
+ readonly value: string;
40
+ };
13
41
  export type ConversationWrite = {
14
42
  readonly conversation: string;
15
43
  readonly messages: readonly AcceptedMessage[];
@@ -18,11 +46,13 @@ export type ConversationWrite = {
18
46
  readonly partial: boolean;
19
47
  };
20
48
  };
21
- export declare function heldConversations(connection: Connection): HeldConversation[];
49
+ export declare function heldConversations(connection: Connection, conversations: readonly string[] | null): HeldConversation[];
22
50
  export declare function keptMessages(connection: Connection, { conversation, messages, read }: ConversationWrite): null;
23
51
  export declare function messageWindow(connection: Connection, conversation: string, limit: number, before: readonly [string, string] | null, phrase: string | null): MessageWindow;
24
52
  export declare function messageCount(connection: Connection, conversation: string, phrase: string | null): number;
53
+ export declare function conversationRows(connection: Connection, conversations: readonly string[]): HeldRow[];
25
54
  export declare function turnArrived(connection: Connection, conversation: string, turn: string): boolean;
26
- export declare function droppedMessages(connection: Connection, conversations: readonly string[]): void;
27
- export declare function forgottenMessages(connection: Connection): void;
55
+ export declare function conversationFacts(connection: Connection): HeldFact[];
56
+ export declare function keptFact(connection: Connection, { conversation, name, value }: HeldFact): null;
57
+ export declare function forgottenConversations(connection: Connection): void;
28
58
  //# sourceMappingURL=messages.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD,OAAO,KAAK,EAAE,UAAU,EAAc,MAAM,aAAa,CAAC;AAE1D,eAAO,MAAM,cAAc,EAAE,SAAS,MAAM,EAM3C,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAAE,QAAQ,CAAC,QAAQ,EAAE,eAAe,EAAE,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC;AAE7F,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,SAAS,eAAe,EAAE,CAAC;IAC9C,QAAQ,CAAC,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;CAC3E,CAAC;AAMF,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,UAAU,GAAG,gBAAgB,EAAE,CAmB5E;AAED,wBAAgB,YAAY,CAC1B,UAAU,EAAE,UAAU,EACtB,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,iBAAiB,GAClD,IAAI,CA+BN;AAkBD,wBAAgB,aAAa,CAC3B,UAAU,EAAE,UAAU,EACtB,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,EACxC,MAAM,EAAE,MAAM,GAAG,IAAI,GACpB,aAAa,CAWf;AAED,wBAAgB,YAAY,CAC1B,UAAU,EAAE,UAAU,EACtB,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,GAAG,IAAI,GACpB,MAAM,CAOR;AAED,wBAAgB,WAAW,CAAC,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAO/F;AAED,wBAAgB,eAAe,CAAC,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAK9F;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,UAAU,GAAG,IAAI,CAG9D"}
1
+ {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"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"}
package/dist/messages.js CHANGED
@@ -1,24 +1,60 @@
1
- import { HOLDS_PHRASE } from './phrase.js';
1
+ import { sql } from '@agentshouse/mdmodel';
2
+ import { text } from './column.js';
3
+ import { EXCERPT } from './read.js';
4
+ import { tablesOf } from './stored.js';
5
+ const SAID_BY_HOUSE = `json_extract(message, '$.role') = 'house'`;
6
+ const ANSWERS_THE_TURN = `json_extract(message, '$.role') = 'assistant'`;
2
7
  export const MESSAGE_TABLES = [
3
8
  'CREATE TABLE conversation_reads (conversation TEXT PRIMARY KEY, read TEXT, partial INTEGER NOT NULL) WITHOUT ROWID',
4
- 'CREATE TABLE conversation_messages (id INTEGER PRIMARY KEY, conversation TEXT NOT NULL, identity TEXT NOT NULL, turn TEXT NOT NULL, position TEXT NOT NULL, message TEXT NOT NULL, text TEXT NOT NULL)',
9
+ 'CREATE TABLE conversation_messages (id INTEGER PRIMARY KEY, conversation TEXT NOT NULL, identity TEXT NOT NULL, turn TEXT NOT NULL, position TEXT NOT NULL, change TEXT NOT NULL, message TEXT NOT NULL, text TEXT NOT NULL)',
5
10
  'CREATE UNIQUE INDEX conversation_messages_identity ON conversation_messages (conversation, identity)',
6
11
  'CREATE INDEX conversation_messages_position ON conversation_messages (conversation, position, identity)',
7
12
  'CREATE INDEX conversation_messages_turn ON conversation_messages (conversation, turn)',
13
+ `CREATE INDEX conversation_messages_house ON conversation_messages (conversation, position, identity) WHERE ${SAID_BY_HOUSE}`,
14
+ 'CREATE TABLE conversation_facts (conversation TEXT NOT NULL, name TEXT NOT NULL, value TEXT NOT NULL, PRIMARY KEY (conversation, name)) WITHOUT ROWID',
8
15
  ];
9
- function text(value) {
10
- return typeof value === 'string' ? value : String(value);
11
- }
12
- export function heldConversations(connection) {
16
+ const NEWEST_FIRST = 'ORDER BY position DESC, identity DESC LIMIT 1';
17
+ const OLDEST_FIRST = 'ORDER BY position, identity LIMIT 1';
18
+ const OF_THE_ROW = 'SELECT id FROM conversation_messages WHERE conversation = listed.value';
19
+ export const ROWS = `WITH chosen AS (
20
+ SELECT listed.value AS conversation,
21
+ (${OF_THE_ROW} AND ${ANSWERS_THE_TURN} ${NEWEST_FIRST}) AS answer,
22
+ (${OF_THE_ROW} AND text <> '' ${NEWEST_FIRST}) AS said,
23
+ (${OF_THE_ROW} AND ${SAID_BY_HOUSE} ${OLDEST_FIRST}) AS opened,
24
+ (${OF_THE_ROW} AND ${SAID_BY_HOUSE} AND json_extract(message, '$.waiting') = 1 ${OLDEST_FIRST}) AS asking
25
+ FROM json_each(?) AS listed
26
+ )
27
+ SELECT chosen.conversation AS conversation,
28
+ substr(said.text, 1, ${EXCERPT}) AS said_text,
29
+ json_extract(said.message, '$.role') AS said_role,
30
+ json_extract(said.message, '$.accepted_at') AS said_at,
31
+ answer.turn AS answered,
32
+ substr(json_extract(answer.message, '$.failure'), 1, ${EXCERPT}) AS failure,
33
+ (SELECT value FROM conversation_facts WHERE conversation = chosen.conversation AND name = 'openedTurn') AS opened_turn,
34
+ json_extract(opened.message, '$.source') AS opened_source,
35
+ json_extract(opened.message, '$.sender') AS opened_sender,
36
+ asking.identity AS asking_identity,
37
+ asking.text AS asking_text,
38
+ json_extract(asking.message, '$.accepted_at') AS asking_at,
39
+ json_extract(asking.message, '$.source') AS asking_source,
40
+ json_extract(asking.message, '$.sender') AS asking_sender
41
+ FROM chosen
42
+ LEFT JOIN conversation_messages said ON said.id = chosen.said
43
+ LEFT JOIN conversation_messages answer ON answer.id = chosen.answer
44
+ LEFT JOIN conversation_messages opened ON opened.id = chosen.opened
45
+ LEFT JOIN conversation_messages asking ON asking.id = chosen.asking`;
46
+ export function heldConversations(connection, conversations) {
47
+ const named = conversations === null ? '' : ' AND conversation IN (SELECT value FROM json_each(?))';
48
+ const bound = conversations === null ? [] : [JSON.stringify(conversations)];
13
49
  const held = new Map();
14
- for (const row of connection.rows('SELECT conversation, read, partial FROM conversation_reads')) {
50
+ for (const row of connection.rows(`SELECT conversation, read, partial FROM conversation_reads WHERE 1 = 1${named}`, bound)) {
15
51
  held.set(text(row.conversation), {
16
52
  conversation: text(row.conversation),
17
53
  read: row.read === null ? null : text(row.read),
18
54
  partial: Number(row.partial) === 1,
19
55
  });
20
56
  }
21
- for (const row of connection.rows('SELECT DISTINCT conversation FROM conversation_messages WHERE conversation NOT IN (SELECT conversation FROM conversation_reads)')) {
57
+ for (const row of connection.rows(`SELECT DISTINCT conversation FROM conversation_messages WHERE conversation NOT IN (SELECT conversation FROM conversation_reads)${named}`, bound)) {
22
58
  held.set(text(row.conversation), {
23
59
  conversation: text(row.conversation),
24
60
  read: undefined,
@@ -29,19 +65,15 @@ export function heldConversations(connection) {
29
65
  }
30
66
  export function keptMessages(connection, { conversation, messages, read }) {
31
67
  for (const message of messages) {
32
- const [held] = connection.rows('SELECT id FROM conversation_messages WHERE conversation = ? AND identity = ?', [conversation, message.identity]);
33
- const record = [
68
+ connection.run('INSERT INTO conversation_messages (conversation, identity, turn, position, change, message, text) VALUES (?, ?, ?, ?, ?, ?, ?) ON CONFLICT (conversation, identity) DO UPDATE SET turn = excluded.turn, position = excluded.position, change = excluded.change, message = excluded.message, text = excluded.text', [
69
+ conversation,
70
+ message.identity,
34
71
  message.turn,
35
72
  message.position,
73
+ message.change,
36
74
  JSON.stringify(message.message ?? null),
37
75
  message.text,
38
- ];
39
- if (held === undefined) {
40
- connection.run('INSERT INTO conversation_messages (conversation, identity, turn, position, message, text) VALUES (?, ?, ?, ?, ?, ?)', [conversation, message.identity, ...record]);
41
- }
42
- else {
43
- connection.run('UPDATE conversation_messages SET turn = ?, position = ?, message = ?, text = ? WHERE id = ?', [...record, held.id]);
44
- }
76
+ ]);
45
77
  }
46
78
  if (read !== undefined) {
47
79
  connection.run('INSERT OR REPLACE INTO conversation_reads (conversation, read, partial) VALUES (?, ?, ?)', [conversation, read.at, read.partial ? 1 : 0]);
@@ -53,6 +85,7 @@ function accepted(row) {
53
85
  identity: text(row.identity),
54
86
  turn: text(row.turn),
55
87
  position: text(row.position),
88
+ change: text(row.change),
56
89
  text: text(row.text),
57
90
  message: JSON.parse(text(row.message)),
58
91
  };
@@ -60,11 +93,11 @@ function accepted(row) {
60
93
  function holding(phrase) {
61
94
  return phrase === null
62
95
  ? { sql: '', bind: [] }
63
- : { sql: ` AND ${HOLDS_PHRASE}(text, ?)`, bind: [phrase.toLowerCase()] };
96
+ : { sql: ` AND ${sql.HOLDS_PHRASE}(text, ?)`, bind: [phrase.toLowerCase()] };
64
97
  }
65
98
  export function messageWindow(connection, conversation, limit, before, phrase) {
66
99
  const held = holding(phrase);
67
- const rows = connection.rows(`SELECT identity, turn, position, message, text FROM conversation_messages WHERE conversation = ?${held.sql}${before === null ? '' : ' AND (position < ? OR (position = ? AND identity < ?))'} ORDER BY position DESC, identity DESC LIMIT ?`, before === null
100
+ const rows = connection.rows(`SELECT identity, turn, position, change, message, text FROM conversation_messages WHERE conversation = ?${held.sql}${before === null ? '' : ' AND (position < ? OR (position = ? AND identity < ?))'} ORDER BY position DESC, identity DESC LIMIT ?`, before === null
68
101
  ? [conversation, ...held.bind, limit + 1]
69
102
  : [conversation, ...held.bind, before[0], before[0], before[1], limit + 1]);
70
103
  return { messages: rows.slice(0, limit).map(accepted).reverse(), more: rows.length > limit };
@@ -74,16 +107,54 @@ export function messageCount(connection, conversation, phrase) {
74
107
  const [counted] = connection.rows(`SELECT count(*) AS held FROM conversation_messages WHERE conversation = ?${held.sql}`, [conversation, ...held.bind]);
75
108
  return Number(counted?.held ?? 0);
76
109
  }
110
+ function textOrNull(value) {
111
+ return value === null ? null : text(value);
112
+ }
113
+ function heldSource(source, sender) {
114
+ return {
115
+ source: source === null ? null : JSON.parse(text(source)),
116
+ sender: textOrNull(sender),
117
+ };
118
+ }
119
+ export function conversationRows(connection, conversations) {
120
+ return connection.rows(ROWS, [JSON.stringify(conversations)]).map((row) => ({
121
+ conversation: text(row.conversation),
122
+ said: row.said_text === null
123
+ ? null
124
+ : {
125
+ text: text(row.said_text),
126
+ role: textOrNull(row.said_role),
127
+ at: textOrNull(row.said_at),
128
+ },
129
+ answered: textOrNull(row.answered),
130
+ openedTurn: textOrNull(row.opened_turn),
131
+ failure: textOrNull(row.failure),
132
+ opened: row.opened_source === null ? null : heldSource(row.opened_source, row.opened_sender),
133
+ asking: row.asking_identity === null
134
+ ? null
135
+ : {
136
+ ...heldSource(row.asking_source, row.asking_sender),
137
+ identity: text(row.asking_identity),
138
+ text: text(row.asking_text),
139
+ at: textOrNull(row.asking_at),
140
+ },
141
+ }));
142
+ }
77
143
  export function turnArrived(connection, conversation, turn) {
78
144
  return (connection.rows('SELECT 1 FROM conversation_messages WHERE conversation = ? AND turn = ? LIMIT 1', [conversation, turn]).length > 0);
79
145
  }
80
- export function droppedMessages(connection, conversations) {
81
- for (const conversation of conversations) {
82
- connection.run('DELETE FROM conversation_messages WHERE conversation = ?', [conversation]);
83
- connection.run('DELETE FROM conversation_reads WHERE conversation = ?', [conversation]);
84
- }
146
+ export function conversationFacts(connection) {
147
+ return connection.rows('SELECT conversation, name, value FROM conversation_facts').map((row) => ({
148
+ conversation: text(row.conversation),
149
+ name: text(row.name),
150
+ value: text(row.value),
151
+ }));
152
+ }
153
+ export function keptFact(connection, { conversation, name, value }) {
154
+ connection.run('INSERT OR REPLACE INTO conversation_facts (conversation, name, value) VALUES (?, ?, ?)', [conversation, name, value]);
155
+ return null;
85
156
  }
86
- export function forgottenMessages(connection) {
87
- connection.run('DELETE FROM conversation_messages');
88
- connection.run('DELETE FROM conversation_reads');
157
+ export function forgottenConversations(connection) {
158
+ for (const table of tablesOf(MESSAGE_TABLES))
159
+ connection.run(`DELETE FROM ${table}`);
89
160
  }
package/dist/model.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Definition, ValueFacts, VerifiedModel } from '@agentshouse/mdmodel';
1
+ import type { Definition, VerifiedModel } from '@agentshouse/mdmodel';
2
2
  import type { Open } from './open.js';
3
3
  export type ModelIdentity = {
4
4
  identity: string;
@@ -8,7 +8,7 @@ export type ModelSnapshot = ModelIdentity & {
8
8
  schema: string | null;
9
9
  revision: string | null;
10
10
  };
11
- export type ModelUnavailableReason = Open<'not-readable' | 'revoked' | 'not-acquired' | 'invalid'>;
11
+ export type ModelUnavailableReason = Open<'not-readable' | 'revoked' | 'not-acquired'>;
12
12
  export type ModelResult = {
13
13
  kind: 'model';
14
14
  snapshot: ModelSnapshot;
@@ -20,8 +20,6 @@ export type MdType = Definition;
20
20
  export type ModelState = {
21
21
  status: 'unavailable';
22
22
  reason: ModelUnavailableReason;
23
- schema?: string | null;
24
- revision?: string | null;
25
23
  } | {
26
24
  status: 'current' | 'cached';
27
25
  snapshot: ModelSnapshot;
@@ -37,8 +35,6 @@ export type TypesResult = {
37
35
  status: Open<'unavailable'>;
38
36
  reason: ModelUnavailableReason;
39
37
  types: null;
40
- schema?: string | null;
41
- revision?: string | null;
42
38
  } | {
43
39
  status: Open<'current' | 'cached'>;
44
40
  identity: string;
@@ -54,10 +50,6 @@ export type ValidationReceipt = {
54
50
  source: Open<'current' | 'cached'>;
55
51
  };
56
52
  export declare const NO_MODEL: ModelState;
57
- export declare function definitionOf(state: ModelState, type: string | undefined): Definition | undefined;
58
53
  export declare function modelTypes(state: ModelState): TypesResult;
59
54
  export declare function storedModel(state: ModelState): StoredModel;
60
- export declare function cached(state: ModelState): ModelState;
61
- export declare function sameModel(left: ModelIdentity, right: ModelIdentity): boolean;
62
- export declare function referenceField(facts: ValueFacts | undefined): boolean;
63
55
  //# sourceMappingURL=model.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAClF,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,MAAM,aAAa,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAClE,MAAM,MAAM,aAAa,GAAG,aAAa,GAAG;IAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAC/F,MAAM,MAAM,sBAAsB,GAAG,IAAI,CAAC,cAAc,GAAG,SAAS,GAAG,cAAc,GAAG,SAAS,CAAC,CAAC;AACnG,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,aAAa,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,MAAM,EAAE,sBAAsB,CAAA;CAAE,CAAC;AAClE,MAAM,MAAM,MAAM,GAAG,UAAU,CAAC;AAChC,MAAM,MAAM,UAAU,GAClB;IACE,MAAM,EAAE,aAAa,CAAC;IACtB,MAAM,EAAE,sBAAsB,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,GACD;IACE,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC7B,QAAQ,EAAE,aAAa,CAAC;IACxB,YAAY,EAAE,aAAa,CAAC;IAC5B,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;CAC/B,CAAC;AACN,MAAM,MAAM,WAAW,GACnB,OAAO,CAAC,UAAU,EAAE;IAAE,MAAM,EAAE,aAAa,CAAA;CAAE,CAAC,GAC9C,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE;IAAE,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAA;CAAE,CAAC,EAAE,OAAO,CAAC,CAAC;AACzE,MAAM,MAAM,WAAW,GACnB;IACE,MAAM,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;IAC5B,MAAM,EAAE,sBAAsB,CAAC;IAC/B,KAAK,EAAE,IAAI,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,GACD;IACE,MAAM,EAAE,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC,CAAC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,aAAa,CAAC;IAC5B,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,CAAC;AACN,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC,CAAC;CACpC,CAAC;AACF,eAAO,MAAM,QAAQ,EAAE,UAA8D,CAAC;AACtF,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAGhG;AACD,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,WAAW,CAczD;AACD,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,WAAW,CAI1D;AACD,wBAAgB,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,CAEpD;AACD,wBAAgB,SAAS,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAE5E;AACD,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,SAAS,GAAG,OAAO,CAErE"}
1
+ {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACtE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,MAAM,aAAa,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAClE,MAAM,MAAM,aAAa,GAAG,aAAa,GAAG;IAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAC/F,MAAM,MAAM,sBAAsB,GAAG,IAAI,CAAC,cAAc,GAAG,SAAS,GAAG,cAAc,CAAC,CAAC;AACvF,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,aAAa,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,MAAM,EAAE,sBAAsB,CAAA;CAAE,CAAC;AAClE,MAAM,MAAM,MAAM,GAAG,UAAU,CAAC;AAChC,MAAM,MAAM,UAAU,GAClB;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,sBAAsB,CAAA;CAAE,GACzD;IACE,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC7B,QAAQ,EAAE,aAAa,CAAC;IACxB,YAAY,EAAE,aAAa,CAAC;IAC5B,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;CAC/B,CAAC;AACN,MAAM,MAAM,WAAW,GACnB,OAAO,CAAC,UAAU,EAAE;IAAE,MAAM,EAAE,aAAa,CAAA;CAAE,CAAC,GAC9C,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE;IAAE,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAA;CAAE,CAAC,EAAE,OAAO,CAAC,CAAC;AACzE,MAAM,MAAM,WAAW,GACnB;IAAE,MAAM,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;IAAC,MAAM,EAAE,sBAAsB,CAAC;IAAC,KAAK,EAAE,IAAI,CAAA;CAAE,GAC5E;IACE,MAAM,EAAE,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC,CAAC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,aAAa,CAAC;IAC5B,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,CAAC;AACN,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC,CAAC;CACpC,CAAC;AACF,eAAO,MAAM,QAAQ,EAAE,UAA8D,CAAC;AACtF,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,WAAW,CAczD;AACD,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,WAAW,CAI1D"}