@agentshouse/mdruntime 0.1.0-alpha.9 → 0.1.0-c0105dbd22806

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 (214) hide show
  1. package/AGENTS.md +299 -0
  2. package/README.md +54 -0
  3. package/dist/adapter.d.ts +246 -40
  4. package/dist/adapter.d.ts.map +1 -1
  5. package/dist/adapter.js +1 -10
  6. package/dist/attached-model.d.ts +11 -0
  7. package/dist/attached-model.d.ts.map +1 -0
  8. package/dist/attached-model.js +47 -0
  9. package/dist/attempt.d.ts +16 -0
  10. package/dist/attempt.d.ts.map +1 -0
  11. package/dist/attempt.js +70 -0
  12. package/dist/binary.d.ts +23 -0
  13. package/dist/binary.d.ts.map +1 -0
  14. package/dist/binary.js +8 -0
  15. package/dist/bootstrap.d.ts +17 -7
  16. package/dist/bootstrap.d.ts.map +1 -1
  17. package/dist/bootstrap.js +97 -41
  18. package/dist/change-set.d.ts +33 -0
  19. package/dist/change-set.d.ts.map +1 -0
  20. package/dist/change-set.js +90 -0
  21. package/dist/change.d.ts +24 -0
  22. package/dist/change.d.ts.map +1 -1
  23. package/dist/change.js +31 -5
  24. package/dist/chat/acts.d.ts +34 -0
  25. package/dist/chat/acts.d.ts.map +1 -0
  26. package/dist/chat/acts.js +36 -0
  27. package/dist/chat/context.d.ts +3 -0
  28. package/dist/chat/context.d.ts.map +1 -0
  29. package/dist/chat/context.js +10 -0
  30. package/dist/chat/input.d.ts +9 -0
  31. package/dist/chat/input.d.ts.map +1 -0
  32. package/dist/chat/input.js +99 -0
  33. package/dist/chat/kit.d.ts +60 -0
  34. package/dist/chat/kit.d.ts.map +1 -0
  35. package/dist/chat/kit.js +123 -0
  36. package/dist/chat/lasting.d.ts +6 -0
  37. package/dist/chat/lasting.d.ts.map +1 -0
  38. package/dist/chat/lasting.js +19 -0
  39. package/dist/chat/list.d.ts +26 -0
  40. package/dist/chat/list.d.ts.map +1 -0
  41. package/dist/chat/list.js +62 -0
  42. package/dist/chat/markdown.d.ts +20 -0
  43. package/dist/chat/markdown.d.ts.map +1 -0
  44. package/dist/chat/markdown.js +188 -0
  45. package/dist/chat/message.d.ts +6 -0
  46. package/dist/chat/message.d.ts.map +1 -0
  47. package/dist/chat/message.js +192 -0
  48. package/dist/chat/messages.d.ts +21 -0
  49. package/dist/chat/messages.d.ts.map +1 -0
  50. package/dist/chat/messages.js +151 -0
  51. package/dist/chat/name.d.ts +6 -0
  52. package/dist/chat/name.d.ts.map +1 -0
  53. package/dist/chat/name.js +37 -0
  54. package/dist/chat/opened.d.ts +11 -0
  55. package/dist/chat/opened.d.ts.map +1 -0
  56. package/dist/chat/opened.js +17 -0
  57. package/dist/chat/overlay.d.ts +31 -0
  58. package/dist/chat/overlay.d.ts.map +1 -0
  59. package/dist/chat/overlay.js +97 -0
  60. package/dist/chat/parts.d.ts +57 -0
  61. package/dist/chat/parts.d.ts.map +1 -0
  62. package/dist/chat/parts.js +119 -0
  63. package/dist/chat/process.d.ts +20 -0
  64. package/dist/chat/process.d.ts.map +1 -0
  65. package/dist/chat/process.js +32 -0
  66. package/dist/chat/provider.d.ts +63 -0
  67. package/dist/chat/provider.d.ts.map +1 -0
  68. package/dist/chat/provider.js +645 -0
  69. package/dist/chat/question.d.ts +9 -0
  70. package/dist/chat/question.d.ts.map +1 -0
  71. package/dist/chat/question.js +80 -0
  72. package/dist/chat/questions.d.ts +31 -0
  73. package/dist/chat/questions.d.ts.map +1 -0
  74. package/dist/chat/questions.js +111 -0
  75. package/dist/chat/read.d.ts +5 -0
  76. package/dist/chat/read.d.ts.map +1 -0
  77. package/dist/chat/read.js +13 -0
  78. package/dist/chat/ready.d.ts +33 -0
  79. package/dist/chat/ready.d.ts.map +1 -0
  80. package/dist/chat/ready.js +91 -0
  81. package/dist/chat/style.d.ts +4 -0
  82. package/dist/chat/style.d.ts.map +1 -0
  83. package/dist/chat/style.js +302 -0
  84. package/dist/chat.d.ts +14 -0
  85. package/dist/chat.d.ts.map +1 -0
  86. package/dist/chat.js +8 -0
  87. package/dist/client.d.ts +49 -33
  88. package/dist/client.d.ts.map +1 -1
  89. package/dist/client.js +164 -183
  90. package/dist/collection.d.ts +9 -17
  91. package/dist/collection.d.ts.map +1 -1
  92. package/dist/collection.js +83 -89
  93. package/dist/connection.d.ts +66 -48
  94. package/dist/connection.d.ts.map +1 -1
  95. package/dist/connection.js +1964 -1173
  96. package/dist/conversation.d.ts +65 -24
  97. package/dist/conversation.d.ts.map +1 -1
  98. package/dist/conversation.js +675 -334
  99. package/dist/durability.js +6 -6
  100. package/dist/entry.d.ts +17 -0
  101. package/dist/entry.d.ts.map +1 -0
  102. package/dist/entry.js +156 -0
  103. package/dist/expectation.d.ts +21 -0
  104. package/dist/expectation.d.ts.map +1 -0
  105. package/dist/expectation.js +70 -0
  106. package/dist/failure.d.ts +13 -0
  107. package/dist/failure.d.ts.map +1 -0
  108. package/dist/failure.js +19 -0
  109. package/dist/fence.d.ts +6 -0
  110. package/dist/fence.d.ts.map +1 -0
  111. package/dist/fence.js +10 -0
  112. package/dist/file.d.ts +2 -2
  113. package/dist/file.d.ts.map +1 -1
  114. package/dist/file.js +48 -71
  115. package/dist/host.d.ts +15 -3
  116. package/dist/host.d.ts.map +1 -1
  117. package/dist/host.js +109 -127
  118. package/dist/identity.d.ts +4 -0
  119. package/dist/identity.d.ts.map +1 -1
  120. package/dist/identity.js +22 -9
  121. package/dist/index.d.ts +17 -11
  122. package/dist/index.d.ts.map +1 -1
  123. package/dist/index.js +4 -3
  124. package/dist/log.js +5 -6
  125. package/dist/memory.d.ts +19 -8
  126. package/dist/memory.d.ts.map +1 -1
  127. package/dist/memory.js +304 -216
  128. package/dist/model.d.ts +16 -30
  129. package/dist/model.d.ts.map +1 -1
  130. package/dist/model.js +21 -21
  131. package/dist/observation.d.ts +27 -0
  132. package/dist/observation.d.ts.map +1 -0
  133. package/dist/observation.js +95 -0
  134. package/dist/open.d.ts +2 -0
  135. package/dist/open.d.ts.map +1 -0
  136. package/dist/open.js +1 -0
  137. package/dist/outcome.d.ts +37 -31
  138. package/dist/outcome.d.ts.map +1 -1
  139. package/dist/outcome.js +36 -18
  140. package/dist/overlay.d.ts +22 -4
  141. package/dist/overlay.d.ts.map +1 -1
  142. package/dist/overlay.js +236 -54
  143. package/dist/paths.d.ts +0 -2
  144. package/dist/paths.d.ts.map +1 -1
  145. package/dist/paths.js +6 -29
  146. package/dist/query.d.ts +219 -10
  147. package/dist/query.d.ts.map +1 -1
  148. package/dist/query.js +462 -15
  149. package/dist/reach.d.ts +42 -0
  150. package/dist/reach.d.ts.map +1 -0
  151. package/dist/reach.js +294 -0
  152. package/dist/react.d.ts +41 -0
  153. package/dist/react.d.ts.map +1 -0
  154. package/dist/react.js +64 -0
  155. package/dist/read-side.d.ts +18 -0
  156. package/dist/read-side.d.ts.map +1 -0
  157. package/dist/read-side.js +440 -0
  158. package/dist/refresh.d.ts +15 -5
  159. package/dist/refresh.d.ts.map +1 -1
  160. package/dist/refresh.js +64 -41
  161. package/dist/replica.d.ts +28 -5
  162. package/dist/replica.d.ts.map +1 -1
  163. package/dist/replica.js +249 -40
  164. package/dist/room-draft.d.ts +144 -0
  165. package/dist/room-draft.d.ts.map +1 -0
  166. package/dist/room-draft.js +438 -0
  167. package/dist/rows.d.ts +46 -0
  168. package/dist/rows.d.ts.map +1 -0
  169. package/dist/rows.js +145 -0
  170. package/dist/save.d.ts +33 -5
  171. package/dist/save.d.ts.map +1 -1
  172. package/dist/save.js +630 -366
  173. package/dist/search.d.ts +62 -0
  174. package/dist/search.d.ts.map +1 -0
  175. package/dist/search.js +125 -0
  176. package/dist/status.d.ts +6 -8
  177. package/dist/status.d.ts.map +1 -1
  178. package/dist/status.js +8 -20
  179. package/dist/store.d.ts +89 -34
  180. package/dist/store.d.ts.map +1 -1
  181. package/dist/store.js +513 -132
  182. package/dist/transfer.d.ts +5 -0
  183. package/dist/transfer.d.ts.map +1 -1
  184. package/dist/transfer.js +1 -5
  185. package/dist/wire.d.ts +59 -19
  186. package/dist/wire.d.ts.map +1 -1
  187. package/dist/wire.js +88 -105
  188. package/package.json +34 -16
  189. package/dist/adapter.js.map +0 -1
  190. package/dist/bootstrap.js.map +0 -1
  191. package/dist/change.js.map +0 -1
  192. package/dist/client.js.map +0 -1
  193. package/dist/collection.js.map +0 -1
  194. package/dist/connection.js.map +0 -1
  195. package/dist/conversation.js.map +0 -1
  196. package/dist/durability.js.map +0 -1
  197. package/dist/file.js.map +0 -1
  198. package/dist/host.js.map +0 -1
  199. package/dist/identity.js.map +0 -1
  200. package/dist/index.js.map +0 -1
  201. package/dist/log.js.map +0 -1
  202. package/dist/memory.js.map +0 -1
  203. package/dist/model.js.map +0 -1
  204. package/dist/outcome.js.map +0 -1
  205. package/dist/overlay.js.map +0 -1
  206. package/dist/paths.js.map +0 -1
  207. package/dist/query.js.map +0 -1
  208. package/dist/refresh.js.map +0 -1
  209. package/dist/replica.js.map +0 -1
  210. package/dist/save.js.map +0 -1
  211. package/dist/status.js.map +0 -1
  212. package/dist/store.js.map +0 -1
  213. package/dist/transfer.js.map +0 -1
  214. package/dist/wire.js.map +0 -1
package/dist/memory.js CHANGED
@@ -1,41 +1,47 @@
1
- import { ROOM_CONTRACT_VERSION } from './adapter.js';
2
- import { MD_MODEL } from './collection.js';
1
+ import { sameChange } from './overlay.js';
3
2
  const FIXTURE_RETENTION = {
4
- history: {
5
- kind: 'duration',
6
- seconds: 1
7
- },
3
+ history: { kind: 'duration', seconds: 1 },
8
4
  outcome: 1,
9
- refreshHorizon: 1
5
+ refreshHorizon: 1,
10
6
  };
11
7
  function declaredRetention(value) {
12
8
  const retention = value ?? FIXTURE_RETENTION;
13
- if (retention.history.kind === 'no-declared-time-bound') return retention;
9
+ if (retention.history.kind === 'no-declared-time-bound')
10
+ return retention;
14
11
  if (Number.isFinite(retention.history.seconds) && retention.history.seconds > 0) {
15
12
  return retention;
16
13
  }
17
14
  throw new Error('history retention duration must be a finite positive number of seconds');
18
15
  }
16
+ const MODEL_ABSENT = { kind: 'model-unavailable', reason: 'not-readable' };
17
+ function modelsOf(room) {
18
+ return {
19
+ collection: room.model ?? MODEL_ABSENT,
20
+ ...(room.typedSelection === undefined
21
+ ? {}
22
+ : { selection: room.selectionModel ?? MODEL_ABSENT }),
23
+ };
24
+ }
25
+ function changedModels(room, from) {
26
+ const now = modelsOf(room);
27
+ return JSON.stringify(now) === JSON.stringify(modelsOf(from)) ? undefined : now;
28
+ }
19
29
  function named(source, paths) {
20
30
  const taken = {};
21
- for (const path of paths){
31
+ for (const path of paths) {
22
32
  const value = source[path];
23
- if (value !== undefined) taken[path] = value;
33
+ if (value !== undefined)
34
+ taken[path] = value;
24
35
  }
25
36
  return taken;
26
37
  }
27
38
  async function resolveScript(answer, fallback, request) {
28
- if (answer === undefined) return fallback();
39
+ if (answer === undefined)
40
+ return fallback();
29
41
  return typeof answer === 'function' ? answer(request) : answer;
30
42
  }
31
43
  export function createMemoryAdapter(options = {}) {
32
- let rooms = options.rooms === undefined ? [] : [
33
- ...options.rooms
34
- ];
35
- const mdModel = options.mdModel ?? MD_MODEL;
36
- const supportedVersions = options.supportedVersions ?? [
37
- ROOM_CONTRACT_VERSION
38
- ];
44
+ let rooms = options.rooms === undefined ? [] : [...options.rooms];
39
45
  const capabilities = options.capabilities ?? [];
40
46
  const providerLimits = options.providerLimits ?? [];
41
47
  const retention = declaredRetention(options.retention);
@@ -45,20 +51,44 @@ export function createMemoryAdapter(options = {}) {
45
51
  const refreshPages = new Map();
46
52
  const observers = new Set();
47
53
  const listeners = new Set();
54
+ const modeObservers = new Set();
48
55
  const scripted = new Map();
49
56
  const unsealed = new Map();
50
57
  const sealed = new Set();
51
58
  const historyPageSize = options.historyPageSize;
52
- let selected = [];
53
- let viewed = [];
59
+ let held = [];
60
+ let expiring = [];
61
+ let replicated = [];
54
62
  let issued = 0;
55
63
  function scriptConversations(entries) {
56
64
  scripted.clear();
57
- for (const entry of entries)scripted.set(entry.conversation, entry);
65
+ for (const entry of entries)
66
+ scripted.set(entry.conversation, entry);
58
67
  }
59
68
  scriptConversations(options.conversations ?? []);
69
+ const ordinals = new Map();
70
+ function note(locator, answer) {
71
+ const roomVersion = answer.roomVersion;
72
+ const key = `${locator}\u0000${String(roomVersion)}`;
73
+ if (typeof roomVersion === 'string' && !ordinals.has(key))
74
+ ordinals.set(key, ordinals.size);
75
+ return answer;
76
+ }
77
+ function reached(locator, roomVersion, target) {
78
+ const scripted = scripts.reached;
79
+ if (typeof scripted === 'boolean')
80
+ return scripted;
81
+ if (scripted !== undefined)
82
+ return scripted(locator, roomVersion, target);
83
+ if (roomVersion === target)
84
+ return true;
85
+ const held = ordinals.get(`${locator}\u0000${roomVersion}`);
86
+ const wanted = ordinals.get(`${locator}\u0000${target}`);
87
+ return held !== undefined && wanted !== undefined && held >= wanted;
88
+ }
60
89
  function retain(entries) {
61
- for (const room of entries){
90
+ for (const room of entries) {
91
+ note(room.locator, room);
62
92
  const versions = served.get(room.locator) ?? new Map();
63
93
  versions.set(room.roomVersion, room);
64
94
  served.set(room.locator, versions);
@@ -69,107 +99,112 @@ export function createMemoryAdapter(options = {}) {
69
99
  return {
70
100
  name: room.name,
71
101
  locator: room.locator,
72
- collectionRoot: room.collectionRoot,
102
+ handle: room.handle,
73
103
  roomVersion: room.roomVersion,
74
104
  operations: room.operations,
75
105
  replica: room.replica,
76
- attachedModel: room.attachedModel,
77
- ...room.typedSelection === undefined ? {} : {
78
- typedSelection: room.typedSelection
79
- },
80
- providerOwnedPaths: room.providerOwnedPaths
106
+ ...(room.typedSelection === undefined ? {} : { typedSelection: room.typedSelection }),
107
+ providerOwnedPaths: room.providerOwnedPaths,
81
108
  };
82
109
  }
83
- function page(room, from) {
110
+ function page(room, after) {
84
111
  const paths = Object.keys(room.documents ?? {}).sort();
112
+ const opening = after === undefined;
113
+ const from = opening ? 0 : paths.filter((path) => path <= after).length;
85
114
  const size = pageSize ?? paths.length;
86
115
  const taken = paths.slice(from, from + size);
87
116
  const next = from + taken.length;
117
+ const targets = opening ? Object.keys(room.binaryFiles ?? {}) : [];
88
118
  return {
89
119
  kind: 'bootstrap',
90
120
  roomVersion: room.roomVersion,
121
+ ...(opening ? { models: modelsOf(room) } : {}),
91
122
  documents: named(room.documents ?? {}, taken),
92
- revisions: named(room.revisions ?? {}, taken),
93
- binaryTargets: from === 0 ? room.binaryTargets ?? [] : [],
94
- ...next < paths.length ? {
95
- pageToken: String(next)
96
- } : {}
123
+ revisions: named(room.revisions ?? {}, [...taken, ...targets]),
124
+ changes: named(room.changes ?? {}, [...taken, ...targets]),
125
+ binaryFiles: named(room.binaryFiles ?? {}, targets),
126
+ ...(next < paths.length ? { pageToken: taken.at(-1) } : {}),
97
127
  };
98
128
  }
99
129
  function advancement(room, from, at) {
100
130
  const current = room.documents ?? {};
101
131
  const previous = from.documents ?? {};
102
- const currentTargets = new Set(room.binaryTargets ?? []);
103
- const previousTargets = new Set(from.binaryTargets ?? []);
104
- const changed = Object.keys(current).filter((path)=>current[path] !== previous[path]).sort();
132
+ const currentTargets = new Set(Object.keys(room.binaryFiles ?? {}));
133
+ const previousTargets = new Set(Object.keys(from.binaryFiles ?? {}));
134
+ const headMoved = (path) => room.revisions?.[path] !== from.revisions?.[path] ||
135
+ !sameChange(room.changes?.[path], from.changes?.[path]);
136
+ const changed = Object.keys(current)
137
+ .filter((path) => current[path] !== previous[path] || headMoved(path))
138
+ .sort();
105
139
  const size = pageSize ?? changed.length;
106
140
  const taken = changed.slice(at, at + size);
107
141
  const next = at + taken.length;
108
142
  const opening = at === 0;
109
143
  const pageToken = next < changed.length ? `refresh-${refreshPages.size}` : undefined;
110
- if (pageToken !== undefined) refreshPages.set(pageToken, {
111
- room,
112
- from,
113
- at: next
114
- });
144
+ if (pageToken !== undefined)
145
+ refreshPages.set(pageToken, { room, from, at: next });
146
+ const targets = opening
147
+ ? [...currentTargets].filter((target) => !previousTargets.has(target) || headMoved(target))
148
+ : [];
149
+ const models = opening ? changedModels(room, from) : undefined;
115
150
  return {
116
151
  kind: 'net-advancement',
117
152
  roomVersion: room.roomVersion,
153
+ ...(models === undefined ? {} : { models }),
118
154
  documents: named(current, taken),
119
- revisions: named(room.revisions ?? {}, taken),
120
- binaryTargets: opening ? [
121
- ...currentTargets
122
- ].filter((target)=>!previousTargets.has(target)) : [],
123
- removals: opening ? [
124
- ...Object.keys(previous).filter((path)=>!(path in current) && !currentTargets.has(path)),
125
- ...[
126
- ...previousTargets
127
- ].filter((target)=>!currentTargets.has(target) && !(target in current))
128
- ].sort() : [],
129
- ...pageToken === undefined ? {} : {
130
- pageToken
131
- }
155
+ revisions: named(room.revisions ?? {}, [...taken, ...targets]),
156
+ changes: named(room.changes ?? {}, [...taken, ...targets]),
157
+ binaryFiles: named(room.binaryFiles ?? {}, targets),
158
+ removals: opening
159
+ ? [
160
+ ...Object.keys(previous).filter((path) => !(path in current) && !currentTargets.has(path)),
161
+ ...[...previousTargets].filter((target) => !currentTargets.has(target) && !(target in current)),
162
+ ].sort()
163
+ : [],
164
+ ...(pageToken === undefined ? {} : { pageToken }),
132
165
  };
133
166
  }
134
- function historyOf(conversation, cursor) {
167
+ function pageOf(conversation, after) {
135
168
  const messages = conversation.messages ?? [];
136
- const until = typeof cursor === 'string' ? Number(cursor) : messages.length;
137
- if (!Number.isInteger(until) || until < 0 || until > messages.length) {
138
- return {
139
- kind: 'rejected',
140
- code: 'unknown-cursor',
141
- fields: {
142
- cursor
143
- }
144
- };
145
- }
146
- const size = historyPageSize ?? messages.length;
147
- const from = Math.max(0, until - size);
169
+ const first = typeof after === 'string' ? messages.findIndex((message) => message.position > after) : 0;
170
+ const from = first === -1 ? messages.length : first;
171
+ const page = messages.slice(from, from + (historyPageSize ?? messages.length));
172
+ const last = page.at(-1);
148
173
  return {
149
- kind: 'action',
150
- result: {
151
- messages: messages.slice(from, until),
152
- ...from === 0 ? {} : {
153
- cursor: String(from)
154
- }
155
- }
174
+ conversation: conversation.conversation,
175
+ messages: page,
176
+ ...(last !== undefined && from + page.length < messages.length
177
+ ? { next: last.position }
178
+ : {}),
156
179
  };
157
180
  }
181
+ function historiesOf(input) {
182
+ const asked = input?.conversations;
183
+ if (!Array.isArray(asked))
184
+ return { kind: 'rejected', code: 'invalid_request', fields: {}, retryable: false };
185
+ const histories = [];
186
+ for (const entry of asked) {
187
+ const conversation = typeof entry.conversation === 'string' ? scripted.get(entry.conversation) : undefined;
188
+ if (conversation === undefined)
189
+ continue;
190
+ const outcome = conversation.outcomes?.['conversation.history'];
191
+ if (outcome !== undefined)
192
+ return outcome;
193
+ histories.push(pageOf(conversation, entry.after));
194
+ }
195
+ const result = { histories };
196
+ return { kind: 'action', result };
197
+ }
158
198
  function conversationAction(request) {
159
199
  const name = request.name;
160
- const input = request.input ?? {};
200
+ const input = (request.input ?? {});
201
+ if (name === 'conversation.history')
202
+ return historiesOf(request.input);
161
203
  if (name === 'conversation.create') {
162
204
  issued += 1;
163
205
  const conversation = `conversation-${issued}`;
164
- scripted.set(conversation, {
165
- conversation
166
- });
167
- return {
168
- kind: 'action',
169
- result: {
170
- conversation
171
- }
172
- };
206
+ scripted.set(conversation, { conversation });
207
+ return { kind: 'action', result: { conversation } };
173
208
  }
174
209
  const named = typeof input.conversation === 'string' ? input.conversation : '';
175
210
  const conversation = scripted.get(named);
@@ -177,219 +212,272 @@ export function createMemoryAdapter(options = {}) {
177
212
  return {
178
213
  kind: 'rejected',
179
214
  code: 'unknown-conversation',
180
- fields: {
181
- conversation: named
182
- }
215
+ fields: { conversation: named },
216
+ retryable: false,
183
217
  };
184
218
  }
185
219
  const outcome = conversation.outcomes?.[name];
186
- if (outcome !== undefined) return outcome;
187
- if (name === 'conversation.history') return historyOf(conversation, input.cursor);
220
+ if (outcome !== undefined)
221
+ return outcome;
188
222
  if (name === 'conversation.send') {
189
223
  issued += 1;
190
224
  const turn = `turn-${issued}`;
191
225
  unsealed.set(turn, named);
192
- return {
193
- kind: 'action',
194
- result: {
195
- turn
196
- }
197
- };
226
+ return { kind: 'action', result: { turn } };
198
227
  }
199
228
  if (name === 'conversation.cancel') {
200
229
  const turn = typeof input.turn === 'string' ? input.turn : '';
201
230
  if (sealed.has(turn) || !unsealed.has(turn)) {
202
- return {
203
- kind: 'rejected',
204
- code: 'turn-sealed',
205
- fields: {
206
- turn
207
- }
208
- };
231
+ return { kind: 'rejected', code: 'turn-sealed', fields: { turn }, retryable: false };
209
232
  }
210
233
  unsealed.delete(turn);
211
- return {
212
- kind: 'action',
213
- result: {
214
- turn,
215
- cancelled: true
216
- }
217
- };
234
+ return { kind: 'action', result: { turn, cancelled: true } };
218
235
  }
219
- if (name === 'conversation.delete') scripted.delete(named);
220
- return {
221
- kind: 'action',
222
- result: {
223
- conversation: named
224
- }
225
- };
236
+ if (name === 'conversation.delete')
237
+ scripted.delete(named);
238
+ return { kind: 'action', result: { conversation: named } };
239
+ }
240
+ function announceList() {
241
+ const entries = [...scripted.values()].flatMap(({ conversation, listed }) => listed === undefined ? [] : [{ conversation, ...listed }]);
242
+ for (const listener of listeners)
243
+ listener({ kind: 'list', entries });
226
244
  }
227
245
  function discovery() {
228
246
  return {
229
247
  kind: 'discovery',
230
- supportedVersions,
231
- mdModel,
232
248
  rooms: rooms.map(declared),
233
249
  capabilities,
234
250
  providerLimits,
235
- retention
251
+ retention,
252
+ ...(options.member === undefined ? {} : { member: options.member }),
236
253
  };
237
254
  }
238
255
  return {
239
- setRooms (next) {
240
- rooms = [
241
- ...next
242
- ];
256
+ ...(options.exhaustiveDiscovery === undefined ? {} : { exhaustiveDiscovery: true }),
257
+ setRooms(next) {
258
+ rooms = [...next];
243
259
  retain(rooms);
244
260
  },
245
- setConversations (next) {
261
+ setConversations(next) {
246
262
  scriptConversations(next);
247
263
  },
248
- notifyRoomVersion (notification) {
249
- for (const observer of observers)observer(notification);
264
+ open() {
265
+ announceList();
266
+ for (const observer of observers)
267
+ observer({ kind: 'opened' });
268
+ },
269
+ close(revoked = false) {
270
+ for (const observer of observers)
271
+ observer({ kind: 'closed', revoked });
272
+ },
273
+ expire(locators) {
274
+ expiring = [...locators];
250
275
  },
251
- notifyConversation (event) {
276
+ notifyRoomVersion({ locator, roomVersion }) {
277
+ for (const observer of observers)
278
+ observer({ kind: 'room-version', locator, roomVersion });
279
+ },
280
+ notifyConversation(event) {
252
281
  if (event.kind === 'accepted-message') {
253
282
  sealed.add(event.message.turn);
254
283
  unsealed.delete(event.message.turn);
255
284
  }
256
- for (const listener of listeners)listener(event);
285
+ for (const listener of listeners)
286
+ listener(event);
287
+ },
288
+ notifyServiceMode(mode) {
289
+ for (const observer of modeObservers)
290
+ observer(mode);
257
291
  },
258
- selectedRooms () {
259
- return selected;
292
+ heldRooms() {
293
+ return held;
260
294
  },
261
- viewedConversations () {
262
- return viewed;
295
+ replicatedConversations() {
296
+ return replicated;
263
297
  },
264
298
  conversations: {
265
- view (next) {
266
- viewed = [
267
- ...next
268
- ];
299
+ replicate(next) {
300
+ replicated = [...next];
269
301
  },
270
- observe (notify) {
302
+ observe(notify) {
271
303
  listeners.add(notify);
272
- return ()=>{
304
+ return () => {
273
305
  listeners.delete(notify);
274
306
  };
275
- }
307
+ },
276
308
  },
277
- roomVersions: {
278
- select (locators) {
279
- selected = [
280
- ...locators
281
- ];
309
+ serviceMode: {
310
+ observe(notify) {
311
+ modeObservers.add(notify);
312
+ return () => {
313
+ modeObservers.delete(notify);
314
+ };
315
+ },
316
+ },
317
+ roomStream: {
318
+ hold(asked) {
319
+ held = asked.map((room) => room.locator);
320
+ const expired = expiring.filter((locator) => held.includes(locator));
321
+ expiring = [];
322
+ const moved = asked.flatMap((room) => {
323
+ const current = rooms.find((entry) => entry.locator === room.locator);
324
+ return current === undefined ||
325
+ expired.includes(room.locator) ||
326
+ current.roomVersion === room.roomVersion
327
+ ? []
328
+ : [{ locator: room.locator, roomVersion: current.roomVersion }];
329
+ });
330
+ queueMicrotask(() => {
331
+ for (const observer of observers) {
332
+ for (const room of moved)
333
+ observer({ kind: 'room-version', ...room });
334
+ observer({ kind: 'opening', expired });
335
+ }
336
+ });
282
337
  },
283
- observe (notify) {
338
+ reopen() {
339
+ queueMicrotask(() => {
340
+ for (const observer of observers)
341
+ observer({ kind: 'closed', revoked: false });
342
+ });
343
+ },
344
+ observe(notify) {
284
345
  observers.add(notify);
285
- return ()=>{
346
+ queueMicrotask(() => {
347
+ if (!observers.has(notify))
348
+ return;
349
+ if (options.unopened === true) {
350
+ notify({ kind: 'closed', revoked: false });
351
+ return;
352
+ }
353
+ announceList();
354
+ notify({ kind: 'opened' });
355
+ });
356
+ return () => {
286
357
  observers.delete(notify);
287
358
  };
288
- }
359
+ },
289
360
  },
290
- script (operation, answer) {
291
- if (answer === undefined) delete scripts[operation];
292
- else scripts[operation] = answer;
361
+ script(operation, answer) {
362
+ if (answer === undefined)
363
+ delete scripts[operation];
364
+ else
365
+ scripts[operation] = answer;
293
366
  },
294
- async model (_authorization, request) {
295
- return resolveScript(scripts.model, ()=>{
296
- const room = rooms.find((entry)=>entry.locator === request.locator);
297
- const answer = request.attached === 'collection' ? room?.model : room?.selectionModel;
298
- return answer ?? {
299
- kind: 'model-unavailable',
300
- reason: 'not-readable'
301
- };
302
- }, request);
367
+ async authorize() {
368
+ return resolveScript(scripts.authorize, () => ({}), undefined);
303
369
  },
304
- async authorize () {
305
- return resolveScript(scripts.authorize, ()=>({}), undefined);
370
+ async discover(_authorization) {
371
+ return resolveScript(scripts.discover, discovery, undefined).then((answer) => {
372
+ if (answer.kind === 'discovery')
373
+ for (const room of answer.rooms)
374
+ note(room.locator, room);
375
+ return answer;
376
+ });
306
377
  },
307
- async discover (_authorization) {
308
- return resolveScript(scripts.discover, discovery, undefined);
378
+ reached,
379
+ follows(locator, roomVersion, next) {
380
+ const scripted = scripts.follows;
381
+ if (typeof scripted === 'boolean')
382
+ return scripted;
383
+ if (scripted !== undefined)
384
+ return scripted(locator, roomVersion, next);
385
+ return true;
309
386
  },
310
- async bootstrap (_authorization, request) {
311
- return resolveScript(scripts.bootstrap, ()=>{
312
- const room = rooms.find((entry)=>entry.locator === request.locator);
387
+ async bootstrap(_authorization, request) {
388
+ return resolveScript(scripts.bootstrap, () => {
389
+ const room = rooms.find((entry) => entry.locator === request.locator);
313
390
  if (room === undefined) {
314
- return {
315
- kind: 'room-not-readable',
316
- locator: request.locator
317
- };
391
+ return { kind: 'room-not-readable', locator: request.locator };
318
392
  }
319
- return page(room, request.pageToken === undefined ? 0 : Number(request.pageToken));
320
- }, request);
393
+ return page(room, request.pageToken);
394
+ }, request).then((answer) => note(request.locator, answer));
321
395
  },
322
- async refresh (_authorization, request) {
323
- return resolveScript(scripts.refresh, ()=>{
324
- const room = rooms.find((entry)=>entry.locator === request.locator);
396
+ async refresh(_authorization, request) {
397
+ return resolveScript(scripts.refresh, () => {
398
+ const room = rooms.find((entry) => entry.locator === request.locator);
325
399
  if (room === undefined) {
326
- return {
327
- kind: 'room-not-readable',
328
- locator: request.locator
329
- };
400
+ return { kind: 'room-not-readable', locator: request.locator };
330
401
  }
331
402
  if (request.pageToken !== undefined) {
332
403
  const continuation = refreshPages.get(request.pageToken);
333
- if (continuation === undefined || continuation.room.locator !== request.locator || continuation.from.roomVersion !== request.fromRoomVersion) {
404
+ if (continuation === undefined ||
405
+ continuation.room.locator !== request.locator ||
406
+ continuation.from.roomVersion !== request.fromRoomVersion) {
334
407
  throw new Error('Invalid Refresh Page Token');
335
408
  }
336
409
  return advancement(continuation.room, continuation.from, continuation.at);
337
410
  }
338
411
  if (request.fromRoomVersion === room.roomVersion) {
339
- return {
340
- kind: 'still-current'
341
- };
412
+ return { kind: 'still-current' };
342
413
  }
343
414
  const from = served.get(room.locator)?.get(request.fromRoomVersion);
344
- if (from === undefined) return {
345
- kind: 'beyond-horizon'
346
- };
415
+ if (from === undefined)
416
+ return { kind: 'beyond-horizon' };
347
417
  return advancement(room, from, 0);
348
- }, request);
418
+ }, request).then((answer) => note(request.locator, answer));
349
419
  },
350
- async mutate (_authorization, request) {
351
- return resolveScript(scripts.mutate, ()=>{
352
- const room = rooms.find((entry)=>entry.locator === request.locator);
420
+ async mutate(_authorization, request) {
421
+ return resolveScript(scripts.mutate, () => {
422
+ const room = rooms.find((entry) => entry.locator === request.locator);
353
423
  if (room === undefined) {
354
- return {
355
- kind: 'room-not-readable',
356
- locator: request.locator
357
- };
424
+ return { kind: 'room-not-readable', locator: request.locator };
358
425
  }
359
426
  return {
360
427
  kind: 'rejected',
361
428
  code: 'unscripted-mutation',
362
429
  fields: {},
363
- affected: {}
430
+ retryable: false,
431
+ affected: {},
364
432
  };
365
- }, request);
433
+ }, request).then((answer) => note(request.locator, answer));
366
434
  },
367
- async history (_authorization, request) {
368
- return resolveScript(scripts.history, ()=>{
369
- const room = rooms.find((entry)=>entry.locator === request.locator);
435
+ async history(_authorization, request) {
436
+ return resolveScript(scripts.history, () => {
437
+ const room = rooms.find((entry) => entry.locator === request.locator);
370
438
  if (room === undefined) {
371
- return {
372
- kind: 'room-not-readable',
373
- locator: request.locator
374
- };
439
+ return { kind: 'room-not-readable', locator: request.locator };
375
440
  }
376
441
  return {
377
442
  kind: 'history',
378
- revisions: []
443
+ revisions: [],
379
444
  };
380
445
  }, request);
381
446
  },
382
- async action (_authorization, request) {
383
- return resolveScript(scripts.action, ()=>{
384
- if (request.name.startsWith('conversation.')) return conversationAction(request);
385
- return {
386
- kind: 'rejected',
387
- code: 'unscripted-action',
388
- fields: {}
389
- };
447
+ async binary(_authorization, request) {
448
+ return resolveScript(scripts.binary, () => {
449
+ if (request.kind === 'reference') {
450
+ return { kind: 'rejected', code: 'unscripted-binary', fields: {}, retryable: false };
451
+ }
452
+ const room = rooms.find((entry) => entry.locator === request.locator);
453
+ if (room === undefined)
454
+ return { kind: 'room-not-readable', locator: request.locator };
455
+ const blob = room.blobs?.[request.path];
456
+ return blob === undefined
457
+ ? { kind: 'rejected', code: 'file_not_found', fields: {}, retryable: false }
458
+ : { kind: 'binary', blob };
390
459
  }, request);
391
- }
460
+ },
461
+ referrerScope(referrer) {
462
+ if (typeof referrer !== 'object' || referrer === null)
463
+ return null;
464
+ const { room, path, message } = referrer;
465
+ if (typeof message === 'string')
466
+ return { kind: 'conversations' };
467
+ if (typeof room !== 'string')
468
+ return null;
469
+ return { kind: 'room', locator: room, ...(typeof path === 'string' ? { path } : {}) };
470
+ },
471
+ async action(_authorization, request) {
472
+ return resolveScript(scripts.action, () => {
473
+ if (request.name.startsWith('conversation.'))
474
+ return conversationAction(request);
475
+ return { kind: 'rejected', code: 'unscripted-action', fields: {}, retryable: false };
476
+ }, request).then((answer) => {
477
+ if (answer.kind === 'action' && answer.at !== undefined)
478
+ note(answer.at.locator, answer.at);
479
+ return answer;
480
+ });
481
+ },
392
482
  };
393
483
  }
394
-
395
- //# sourceMappingURL=memory.js.map