@ziggs-ai/agent-sdk 0.1.12 → 0.2.1

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 (218) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +41 -2
  3. package/dist/AgentHost.d.ts +201 -0
  4. package/dist/AgentHost.js +652 -0
  5. package/dist/adapters/AnthropicAdapter.d.ts +39 -0
  6. package/dist/adapters/AnthropicAdapter.js +200 -0
  7. package/dist/adapters/McpAdapter.d.ts +199 -0
  8. package/dist/adapters/McpAdapter.js +468 -0
  9. package/dist/adapters/OpenAIAdapter.d.ts +26 -0
  10. package/dist/adapters/OpenAIAdapter.js +158 -0
  11. package/dist/adapters/index.js +2 -0
  12. package/dist/agent/Agent.d.ts +78 -0
  13. package/dist/agent/Agent.js +58 -0
  14. package/dist/agent/ClaudeSdkAgent.d.ts +38 -0
  15. package/dist/agent/ClaudeSdkAgent.js +322 -0
  16. package/dist/agent/claudeCognition.d.ts +67 -0
  17. package/dist/agent/claudeCognition.js +103 -0
  18. package/dist/agent/claudeSdkProtocol.d.ts +11 -0
  19. package/dist/agent/claudeSdkTools.d.ts +19 -0
  20. package/dist/agent/claudeSdkTools.js +57 -0
  21. package/dist/agent/hostedAgentConnection.d.ts +15 -0
  22. package/dist/agent/hostedAgentConnection.js +29 -0
  23. package/dist/agent/toolManagerToSdkMcp.d.ts +12 -0
  24. package/dist/agent/toolManagerToSdkMcp.js +123 -0
  25. package/dist/brain/index.d.ts +50 -0
  26. package/dist/brain/index.js +45 -0
  27. package/dist/cognition/validateContext.d.ts +11 -0
  28. package/dist/cognition/validateContext.js +117 -0
  29. package/dist/context/applyEffects.d.ts +2 -0
  30. package/dist/context/applyEffects.js +89 -0
  31. package/dist/context/batch.d.ts +2 -0
  32. package/dist/context/batch.js +18 -0
  33. package/dist/context/classifyEnvelope.d.ts +1 -0
  34. package/dist/context/classifyEnvelope.js +58 -0
  35. package/dist/context/routingLabels.d.ts +4 -0
  36. package/dist/context/routingLabels.js +48 -0
  37. package/dist/defineAgent.d.ts +14 -0
  38. package/dist/defineAgent.js +68 -0
  39. package/dist/formatters/AgreementFormatter.d.ts +18 -0
  40. package/dist/formatters/AgreementFormatter.js +130 -0
  41. package/dist/formatters/HistoryFormatter.d.ts +26 -0
  42. package/dist/formatters/HistoryFormatter.js +173 -0
  43. package/dist/formatters/index.js +2 -0
  44. package/{src/index.ts → dist/index.d.ts} +7 -53
  45. package/dist/index.js +66 -0
  46. package/dist/ingress/normalizeIncoming.d.ts +65 -0
  47. package/dist/ingress/normalizeIncoming.js +88 -0
  48. package/dist/memory/MemoryStore.d.ts +55 -0
  49. package/dist/memory/MemoryStore.js +78 -0
  50. package/dist/pricing/fleetDefaults.d.ts +46 -0
  51. package/dist/pricing/fleetDefaults.js +168 -0
  52. package/dist/pricing/fleetEvalFree.d.ts +7 -0
  53. package/dist/pricing/fleetEvalFree.js +24 -0
  54. package/dist/pricing/fleetFreeTierA.gen.d.ts +6 -0
  55. package/{src/pricing/fleetFreeTierA.gen.ts → dist/pricing/fleetFreeTierA.gen.js} +5 -6
  56. package/dist/pricing/fleetTierByAgentId.gen.d.ts +7 -0
  57. package/dist/pricing/fleetTierByAgentId.gen.js +768 -0
  58. package/dist/runtime/AgentMachine.d.ts +143 -0
  59. package/dist/runtime/AgentMachine.js +400 -0
  60. package/dist/runtime/PromptBuilder.d.ts +96 -0
  61. package/dist/runtime/PromptBuilder.js +439 -0
  62. package/{src/runtime/bootstrapCtx.ts → dist/runtime/bootstrapCtx.d.ts} +1 -22
  63. package/dist/runtime/bootstrapCtx.js +37 -0
  64. package/dist/runtime/buildOutcome.d.ts +68 -0
  65. package/dist/runtime/buildOutcome.js +464 -0
  66. package/dist/runtime/defaults.d.ts +54 -0
  67. package/dist/runtime/defaults.js +47 -0
  68. package/dist/runtime/deriveRespondsToProposals.d.ts +9 -0
  69. package/dist/runtime/deriveRespondsToProposals.js +38 -0
  70. package/dist/runtime/kickoff.d.ts +15 -0
  71. package/dist/runtime/kickoff.js +112 -0
  72. package/dist/runtime/runMechanical.d.ts +25 -0
  73. package/dist/runtime/runMechanical.js +74 -0
  74. package/dist/runtime/runTurn.d.ts +63 -0
  75. package/dist/runtime/runTurn.js +800 -0
  76. package/dist/runtime/validateWorkflow.d.ts +17 -0
  77. package/dist/runtime/validateWorkflow.js +209 -0
  78. package/dist/server/ConnectionPool.d.ts +68 -0
  79. package/dist/server/ConnectionPool.js +166 -0
  80. package/dist/server/EventQueue.d.ts +33 -0
  81. package/dist/server/EventQueue.js +98 -0
  82. package/dist/server/InboxCatchUp.d.ts +24 -0
  83. package/dist/server/InboxCatchUp.js +214 -0
  84. package/dist/server/OutboxBuffer.d.ts +33 -0
  85. package/dist/server/OutboxBuffer.js +68 -0
  86. package/dist/server/SeenMessages.d.ts +13 -0
  87. package/dist/server/SeenMessages.js +31 -0
  88. package/dist/server/StateTimers.d.ts +34 -0
  89. package/dist/server/StateTimers.js +70 -0
  90. package/dist/server/ZiggsEffectHandler.d.ts +79 -0
  91. package/dist/server/ZiggsEffectHandler.js +319 -0
  92. package/dist/server/agreements/AgreementService.d.ts +50 -0
  93. package/dist/server/agreements/AgreementService.js +85 -0
  94. package/dist/server/createHealthServer.d.ts +7 -0
  95. package/dist/server/createHealthServer.js +75 -0
  96. package/dist/server/proactive/ProactiveTrigger.d.ts +33 -0
  97. package/dist/server/proactive/ProactiveTrigger.js +71 -0
  98. package/dist/server/runLauncher.d.ts +28 -0
  99. package/dist/server/runLauncher.js +93 -0
  100. package/dist/server/tasks/TaskService.d.ts +25 -0
  101. package/dist/server/tasks/TaskService.js +103 -0
  102. package/dist/server/tasks/index.js +1 -0
  103. package/dist/server/telemetryIngest.d.ts +24 -0
  104. package/dist/server/telemetryIngest.js +62 -0
  105. package/dist/server/tools/index.d.ts +24 -0
  106. package/{src/server/tools/index.ts → dist/server/tools/index.js} +4 -24
  107. package/dist/server/tools/tier1/protocolRunner.d.ts +39 -0
  108. package/dist/server/tools/tier1/protocolRunner.js +288 -0
  109. package/dist/server/tools/tier1/protocolTools.d.ts +12 -0
  110. package/dist/server/tools/tier1/protocolTools.js +37 -0
  111. package/dist/server/tools/tier2/connectionTools.d.ts +4 -0
  112. package/dist/server/tools/tier2/connectionTools.js +63 -0
  113. package/dist/server/tools/tier2/contextTools.d.ts +4 -0
  114. package/dist/server/tools/tier2/contextTools.js +46 -0
  115. package/dist/server/tools/tier2/discoveryTools.d.ts +4 -0
  116. package/dist/server/tools/tier2/discoveryTools.js +25 -0
  117. package/dist/server/tools/tier2/marketplaceTools.d.ts +3 -0
  118. package/dist/server/tools/tier2/marketplaceTools.js +22 -0
  119. package/dist/server/tools/tier2/paymentTools.d.ts +12 -0
  120. package/dist/server/tools/tier2/paymentTools.js +165 -0
  121. package/dist/server/ziggsconnect/ZiggsConnectClient.d.ts +35 -0
  122. package/dist/server/ziggsconnect/ZiggsConnectClient.js +95 -0
  123. package/dist/server/ziggscontext/ZiggsContextClient.d.ts +53 -0
  124. package/dist/server/ziggscontext/ZiggsContextClient.js +124 -0
  125. package/dist/server/ziggspay/ZiggsPayClient.d.ts +82 -0
  126. package/dist/server/ziggspay/ZiggsPayClient.js +203 -0
  127. package/dist/shared/ids.d.ts +1 -0
  128. package/dist/shared/ids.js +3 -0
  129. package/dist/shared/runtimeLog.d.ts +18 -0
  130. package/dist/shared/runtimeLog.js +68 -0
  131. package/dist/shared/types.d.ts +22 -0
  132. package/dist/shared/types.js +23 -0
  133. package/dist/tasks/protocolRegistry.d.ts +16 -0
  134. package/dist/tasks/protocolRegistry.js +20 -0
  135. package/dist/tools/ToolManager.d.ts +12 -0
  136. package/dist/tools/ToolManager.js +74 -0
  137. package/dist/tools/ToolProvider.d.ts +6 -0
  138. package/dist/tools/ToolProvider.js +21 -0
  139. package/dist/tools/defineTool.d.ts +27 -0
  140. package/dist/tools/defineTool.js +62 -0
  141. package/{src/tools/index.ts → dist/tools/index.d.ts} +0 -1
  142. package/dist/tools/index.js +6 -0
  143. package/dist/tools/recordReport.d.ts +41 -0
  144. package/dist/tools/recordReport.js +30 -0
  145. package/dist/types.d.ts +466 -0
  146. package/dist/types.js +7 -0
  147. package/dist/utils/jsonExtractor.d.ts +2 -0
  148. package/dist/utils/jsonExtractor.js +111 -0
  149. package/package.json +14 -6
  150. package/src/AgentHost.ts +0 -814
  151. package/src/adapters/AnthropicAdapter.ts +0 -238
  152. package/src/adapters/McpAdapter.ts +0 -678
  153. package/src/adapters/OpenAIAdapter.ts +0 -194
  154. package/src/agent/Agent.ts +0 -112
  155. package/src/agent/ClaudeSdkAgent.ts +0 -401
  156. package/src/agent/claudeCognition.ts +0 -139
  157. package/src/agent/claudeSdkTools.ts +0 -81
  158. package/src/agent/hostedAgentConnection.ts +0 -41
  159. package/src/agent/toolManagerToSdkMcp.ts +0 -136
  160. package/src/cognition/validateContext.ts +0 -95
  161. package/src/context/applyEffects.ts +0 -80
  162. package/src/context/batch.ts +0 -19
  163. package/src/context/classifyEnvelope.ts +0 -38
  164. package/src/context/routingLabels.ts +0 -46
  165. package/src/defineAgent.ts +0 -77
  166. package/src/formatters/AgreementFormatter.ts +0 -111
  167. package/src/formatters/HistoryFormatter.ts +0 -172
  168. package/src/ingress/normalizeIncoming.ts +0 -162
  169. package/src/memory/MemoryStore.ts +0 -104
  170. package/src/pricing/fleetDefaults.ts +0 -225
  171. package/src/pricing/fleetEvalFree.ts +0 -24
  172. package/src/pricing/fleetTierByAgentId.gen.ts +0 -775
  173. package/src/runtime/AgentMachine.ts +0 -484
  174. package/src/runtime/PromptBuilder.ts +0 -522
  175. package/src/runtime/buildOutcome.ts +0 -563
  176. package/src/runtime/defaults.ts +0 -86
  177. package/src/runtime/deriveRespondsToProposals.ts +0 -35
  178. package/src/runtime/kickoff.ts +0 -117
  179. package/src/runtime/runMechanical.ts +0 -106
  180. package/src/runtime/runTurn.ts +0 -870
  181. package/src/runtime/validateWorkflow.ts +0 -221
  182. package/src/server/ConnectionPool.ts +0 -206
  183. package/src/server/EventQueue.ts +0 -133
  184. package/src/server/InboxCatchUp.ts +0 -291
  185. package/src/server/OutboxBuffer.ts +0 -90
  186. package/src/server/SeenMessages.ts +0 -27
  187. package/src/server/StateTimers.ts +0 -85
  188. package/src/server/ZiggsEffectHandler.ts +0 -427
  189. package/src/server/agreements/AgreementService.ts +0 -118
  190. package/src/server/createHealthServer.ts +0 -85
  191. package/src/server/proactive/ProactiveTrigger.ts +0 -83
  192. package/src/server/runLauncher.ts +0 -146
  193. package/src/server/tasks/TaskService.ts +0 -111
  194. package/src/server/telemetryIngest.ts +0 -91
  195. package/src/server/tools/tier1/protocolRunner.ts +0 -353
  196. package/src/server/tools/tier1/protocolTools.ts +0 -114
  197. package/src/server/tools/tier2/connectionTools.ts +0 -75
  198. package/src/server/tools/tier2/contextTools.ts +0 -63
  199. package/src/server/tools/tier2/discoveryTools.ts +0 -34
  200. package/src/server/tools/tier2/marketplaceTools.ts +0 -27
  201. package/src/server/tools/tier2/paymentTools.ts +0 -170
  202. package/src/server/ziggsconnect/ZiggsConnectClient.ts +0 -126
  203. package/src/server/ziggscontext/ZiggsContextClient.ts +0 -129
  204. package/src/server/ziggspay/ZiggsPayClient.ts +0 -193
  205. package/src/shared/ids.ts +0 -3
  206. package/src/shared/runtimeLog.ts +0 -72
  207. package/src/shared/types.ts +0 -29
  208. package/src/tasks/protocolRegistry.ts +0 -25
  209. package/src/tools/ToolManager.ts +0 -95
  210. package/src/tools/ToolProvider.ts +0 -19
  211. package/src/tools/defineTool.ts +0 -90
  212. package/src/tools/recordReport.ts +0 -82
  213. package/src/types.ts +0 -483
  214. package/src/utils/jsonExtractor.ts +0 -100
  215. /package/{src/adapters/index.ts → dist/adapters/index.d.ts} +0 -0
  216. /package/{src/agent/claudeSdkProtocol.ts → dist/agent/claudeSdkProtocol.js} +0 -0
  217. /package/{src/formatters/index.ts → dist/formatters/index.d.ts} +0 -0
  218. /package/{src/server/tasks/index.ts → dist/server/tasks/index.d.ts} +0 -0
@@ -1,291 +0,0 @@
1
- import {
2
- ContextReadClient,
3
- ContextDiscoveryClient,
4
- InboxClient,
5
- getChatsForAgreement,
6
- getAgreementStatus,
7
- type InboxScopeEntry,
8
- type InboxAck,
9
- type Creds,
10
- } from '@ziggs-ai/api-client';
11
- import { SeenMessages } from './SeenMessages.js';
12
- import { runtimeLog } from '../shared/runtimeLog.js';
13
-
14
- export interface InboxCatchUpDeps {
15
- creds: Creds;
16
- ownAgentId: string;
17
- baseUrl?: string;
18
- seen: SeenMessages;
19
- onMessage: (text: string, metadata: Record<string, unknown>) => Promise<void>;
20
- onResourceEvent: (event: Record<string, unknown>) => Promise<void>;
21
- label?: string;
22
- }
23
-
24
- export interface InboxCatchUpResult {
25
- scopes: number;
26
- messagesDelivered: number;
27
- resourceEvents: number;
28
- acked: number;
29
- truncated: boolean;
30
- }
31
-
32
- type WireRow = Record<string, unknown>;
33
-
34
- const READ_PAGE = 100;
35
-
36
- function log(label: string, msg: string): void {
37
- runtimeLog.info(label, msg);
38
- }
39
-
40
- function warn(label: string, msg: string): void {
41
- runtimeLog.warn(label, msg);
42
- }
43
-
44
- const TERMINAL_AGREEMENT_STATUSES = new Set(['fulfilled', 'cancelled', 'refunded']);
45
-
46
- /** ZIG-832 P4: is this agreement finished (so its backlog must not be re-run)? */
47
- async function isTerminalAgreement(agreementId: string, creds: Creds): Promise<boolean> {
48
- try {
49
- const res = (await getAgreementStatus(agreementId, creds)) as
50
- | { status?: string; agreement?: { status?: string } }
51
- | undefined;
52
- const status = res?.status ?? res?.agreement?.status;
53
- return status != null && TERMINAL_AGREEMENT_STATUSES.has(status);
54
- } catch {
55
- // On lookup failure, don't skip — fall through to normal delivery.
56
- return false;
57
- }
58
- }
59
-
60
- /** Map Mongo message row → wire metadata for normalizeIncomingEvent. */
61
- function rowToMetadata(row: WireRow, chatId: string): Record<string, unknown> {
62
- const senderRaw = row.sender as { agentId?: string; id?: string; type?: string } | undefined;
63
- const senderId = String(senderRaw?.agentId ?? senderRaw?.id ?? '');
64
- const receiver = row.receiver as { id?: string; type?: string } | undefined;
65
- const senderType =
66
- senderRaw?.type ??
67
- (receiver?.type === 'agent' ? 'agent' : 'user');
68
-
69
- return {
70
- chatId,
71
- chat_id: chatId,
72
- messageId: row.messageId,
73
- sender: { id: senderId, type: senderType },
74
- senderId,
75
- senderType: String(senderType).toUpperCase(),
76
- receiver: receiver ?? null,
77
- receiverId: receiver?.id ?? null,
78
- entryType: row.entryType ?? 'message',
79
- content_type: row.content_type ?? row.contentType ?? 'text',
80
- contentType: row.content_type ?? row.contentType ?? 'text',
81
- task: row.task ?? null,
82
- agreement: row.agreement ?? null,
83
- operation: row.operation ?? null,
84
- agreementId: row.agreementId ?? null,
85
- timestamp: row.timestamp,
86
- text: row.text,
87
- };
88
- }
89
-
90
- async function chatIdsForScope(
91
- scope: InboxScopeEntry,
92
- creds: Creds,
93
- baseUrl: string | undefined,
94
- discovery: ContextDiscoveryClient,
95
- ): Promise<string[]> {
96
- const { kind, id } = scope.scope;
97
- switch (kind) {
98
- case 'chat':
99
- return [id];
100
- case 'agreement': {
101
- const links = (await getChatsForAgreement(id, creds)) as Array<{ chatId?: string }>;
102
- return [...new Set(links.map((l) => l.chatId).filter(Boolean) as string[])];
103
- }
104
- case 'org': {
105
- const reach = await discovery.discover();
106
- return [
107
- ...new Set(
108
- reach
109
- .filter((r) => r.scope.kind === 'chat')
110
- .map((r) => r.scope.id),
111
- ),
112
- ];
113
- }
114
- default:
115
- return [];
116
- }
117
- }
118
-
119
- async function deliverMessagesForScope(
120
- deps: InboxCatchUpDeps,
121
- scope: InboxScopeEntry,
122
- chatIds: string[],
123
- reader: ContextReadClient,
124
- countCap: number,
125
- ): Promise<number> {
126
- let delivered = 0;
127
- const label = deps.label ?? 'InboxCatchUp';
128
- const expected = scope.newMessages;
129
- let remaining = expected >= countCap ? Number.POSITIVE_INFINITY : expected;
130
-
131
- for (const chatId of chatIds) {
132
- if (remaining <= 0) break;
133
- let after = scope.since;
134
- let pages = 0;
135
- const maxPages = 20;
136
-
137
- while (remaining > 0 && pages < maxPages) {
138
- const limit = Math.min(READ_PAGE, remaining === Number.POSITIVE_INFINITY ? READ_PAGE : remaining);
139
- const page = await reader.read<WireRow>('messages', {
140
- via: `chat:${chatId}`,
141
- after,
142
- direction: 'forward',
143
- limit,
144
- });
145
-
146
- for (const row of page.items) {
147
- const messageId = String(row.messageId ?? '');
148
- if (deps.seen.has(messageId)) continue;
149
-
150
- const text = typeof row.text === 'string' ? row.text : '';
151
- if (!text.trim()) continue;
152
-
153
- const metadata = rowToMetadata(row, chatId);
154
- await deps.onMessage(text, metadata);
155
- delivered++;
156
- if (remaining !== Number.POSITIVE_INFINITY) remaining--;
157
- }
158
-
159
- if (!page.hasMore || !page.latestSequence) break;
160
- after = page.latestSequence;
161
- pages++;
162
- }
163
- }
164
-
165
- if (delivered < expected && expected >= countCap) {
166
- warn(label, `scope ${scope.scope.kind}:${scope.scope.id} may be incomplete (count cap)`);
167
- }
168
-
169
- return delivered;
170
- }
171
-
172
- /**
173
- * Pull-based recovery after reconnect (ZIG-434 / ZIG-446 / ZIG-454).
174
- * Inbox → read message deltas → deliver → ack. Push remains a hint;
175
- * this path survives backend restarts that drop in-memory pending queues.
176
- */
177
- export async function runInboxCatchUp(deps: InboxCatchUpDeps): Promise<InboxCatchUpResult> {
178
- const label = deps.label ?? 'InboxCatchUp';
179
- const inbox = new InboxClient(deps.creds.operatorKey, deps.creds.agentId, deps.baseUrl);
180
- const reader = new ContextReadClient(deps.creds.operatorKey, deps.creds.agentId, deps.baseUrl);
181
- const discovery = new ContextDiscoveryClient(deps.creds.operatorKey, deps.creds.agentId, deps.baseUrl);
182
-
183
- const envelope = await inbox.getInbox();
184
- const countCap = envelope.countCap;
185
-
186
- let messagesDelivered = 0;
187
- let resourceEvents = 0;
188
- const toAck: InboxAck[] = [];
189
-
190
- if (envelope.truncatedScopes > 0) {
191
- // Informational only — does NOT block acking the scopes actually
192
- // returned below. truncatedScopes just means the caller's total reach
193
- // exceeded the server's per-call scope cap (backend/src/inbox/inbox.service.ts,
194
- // INBOX_MAX_SCOPES); each entry in envelope.scopes is still an
195
- // independently accurate, safe-to-ack unit of news for that scope. Never
196
- // acking here meant a busy long-lived agent (reach > cap) would never ack
197
- // anything and re-deliver its entire backlog on every reconnect forever.
198
- warn(label, `inbox truncatedScopes=${envelope.truncatedScopes} (reach exceeds per-call cap — examined scopes are still acked normally)`);
199
- }
200
-
201
- for (const scope of envelope.scopes) {
202
- // ZIG-832 P4: a re-host runs catch-up from the server watermark and would
203
- // re-deliver an already-finished agreement's backlog, re-running a completed
204
- // pipeline and burning tokens. If this is an agreement scope that has reached
205
- // a terminal status, ack it (so it drops out of future catch-ups) and skip
206
- // re-delivery. Only agreement scopes — chat scopes may carry genuinely new
207
- // conversation, so those are never skipped on status. (The deeper fix, acking
208
- // the watermark on the live-push path so nothing re-delivers, is tracked
209
- // separately.)
210
- if (
211
- scope.scope.kind === 'agreement' &&
212
- (scope.newMessages > 0 || scope.newArtifacts > 0) &&
213
- (await isTerminalAgreement(scope.scope.id, deps.creds))
214
- ) {
215
- if (scope.latestAt) {
216
- toAck.push({ kind: scope.scope.kind, id: scope.scope.id, upTo: scope.latestAt });
217
- }
218
- log(label, `scope agreement:${scope.scope.id} terminal — acked, not re-delivered`);
219
- continue;
220
- }
221
-
222
- const chatIds = await chatIdsForScope(scope, deps.creds, deps.baseUrl, discovery);
223
- if (!chatIds.length && (scope.newMessages > 0 || scope.newArtifacts > 0)) {
224
- warn(
225
- label,
226
- `no chat ids for scope ${scope.scope.kind}:${scope.scope.id} (${scope.newMessages} msgs)`,
227
- );
228
- }
229
-
230
- if (scope.newMessages > 0 && chatIds.length) {
231
- const n = await deliverMessagesForScope(deps, scope, chatIds, reader, countCap);
232
- messagesDelivered += n;
233
- log(label, `scope ${scope.scope.kind}:${scope.scope.id} delivered ${n} message(s)`);
234
- }
235
-
236
- if (scope.newArtifacts > 0) {
237
- for (const chatId of chatIds) {
238
- await deps.onResourceEvent({
239
- kind: 'artifact',
240
- ts: scope.latestAt ?? new Date().toISOString(),
241
- resourceId: chatId,
242
- chatId,
243
- change: 'created',
244
- });
245
- resourceEvents++;
246
- }
247
- }
248
-
249
- if (scope.latestAt && (scope.newMessages > 0 || scope.newArtifacts > 0)) {
250
- toAck.push({
251
- kind: scope.scope.kind,
252
- id: scope.scope.id,
253
- upTo: scope.latestAt,
254
- });
255
- }
256
- }
257
-
258
- for (const proposal of envelope.proposalsAwaitingMe) {
259
- await deps.onResourceEvent({
260
- kind: 'agreement',
261
- ts: proposal.proposedAt ?? new Date().toISOString(),
262
- resourceId: proposal.agreementId,
263
- agreementId: proposal.agreementId,
264
- change: 'created',
265
- reason: 'proposal_pending',
266
- });
267
- resourceEvents++;
268
- }
269
-
270
- let acked = 0;
271
- if (toAck.length) {
272
- await inbox.ack(toAck);
273
- acked = toAck.length;
274
- log(label, `acked ${acked} scope(s)`);
275
- }
276
-
277
- if (messagesDelivered > 0 || resourceEvents > 0) {
278
- log(
279
- label,
280
- `catch-up complete: ${messagesDelivered} message(s), ${resourceEvents} resource hint(s)`,
281
- );
282
- }
283
-
284
- return {
285
- scopes: envelope.scopes.length,
286
- messagesDelivered,
287
- resourceEvents,
288
- acked,
289
- truncated: envelope.truncatedScopes > 0,
290
- };
291
- }
@@ -1,90 +0,0 @@
1
- import { runtimeLog } from '../shared/runtimeLog.js';
2
-
3
- interface PendingMessage {
4
- text: string;
5
- receiverId: string;
6
- timestamp: number;
7
- }
8
-
9
- export interface OutboxBufferOptions {
10
- ttlMs?: number;
11
- }
12
-
13
- interface HistoryEntryShape {
14
- entryType?: string;
15
- text?: string;
16
- sender?: { id?: string; type?: string };
17
- receiver?: { id?: string };
18
- timestamp?: number;
19
- }
20
-
21
- /**
22
- * Tracks outbound messages locally until server history syncs them, then
23
- * merges any unmatched ones into the next read context. Prevents the LLM
24
- * from re-saying things it already said when the server is slow to publish.
25
- */
26
- export class OutboxBuffer {
27
- private _pending: Map<string, PendingMessage[]> = new Map();
28
- private _ttlMs: number;
29
-
30
- constructor(options: OutboxBufferOptions = {}) {
31
- this._ttlMs = Number.isFinite(options.ttlMs) ? Math.max(1_000, options.ttlMs!) : 10 * 60 * 1000;
32
- }
33
-
34
- track(chatId: string, msg: { text: string; receiverId: string }): void {
35
- this._gcChat(chatId);
36
- if (!this._pending.has(chatId)) this._pending.set(chatId, []);
37
- this._pending.get(chatId)!.push({ text: msg.text, receiverId: msg.receiverId, timestamp: Date.now() });
38
- }
39
-
40
- merge(chatId: string, history: HistoryEntryShape[], agentId: string | null): void {
41
- this._gcChat(chatId);
42
- const pending = this._pending.get(chatId);
43
- if (!pending || pending.length === 0) return;
44
-
45
- const matchedIndices = new Set<number>();
46
- const remaining: PendingMessage[] = [];
47
-
48
- for (const msg of pending) {
49
- const matchIdx = history.findIndex((entry, idx) =>
50
- !matchedIndices.has(idx) &&
51
- entry.text === msg.text &&
52
- entry.sender?.id === agentId,
53
- );
54
- if (matchIdx !== -1) matchedIndices.add(matchIdx);
55
- else remaining.push(msg);
56
- }
57
-
58
- for (const msg of remaining) {
59
- history.push({
60
- entryType: 'message',
61
- text: msg.text,
62
- sender: { id: agentId || undefined, type: 'agent' },
63
- receiver: { id: msg.receiverId },
64
- timestamp: msg.timestamp,
65
- });
66
- }
67
-
68
- if (remaining.length === 0) this._pending.delete(chatId);
69
- else this._pending.set(chatId, remaining);
70
- }
71
-
72
- gc(): void {
73
- for (const chatId of this._pending.keys()) this._gcChat(chatId);
74
- }
75
-
76
- private _gcChat(chatId: string): void {
77
- const pending = this._pending.get(chatId);
78
- if (!pending?.length) return;
79
- const cutoff = Date.now() - this._ttlMs;
80
- const fresh = pending.filter(msg => msg.timestamp >= cutoff);
81
- if (fresh.length === 0) {
82
- this._pending.delete(chatId);
83
- runtimeLog.warn('OutboxBuffer', `expired all pending messages chatId=${chatId}`);
84
- return;
85
- }
86
- if (fresh.length !== pending.length) {
87
- this._pending.set(chatId, fresh);
88
- }
89
- }
90
- }
@@ -1,27 +0,0 @@
1
- /**
2
- * Dedupes delivery across push (WS flush) and pull (inbox catch-up).
3
- * ZIG-434 / ZIG-454: inbox is reconciliation source; stable message ids
4
- * prevent double-processing when both paths fire for the same row.
5
- */
6
- export class SeenMessages {
7
- private readonly order: string[] = [];
8
- private readonly seen = new Set<string>();
9
-
10
- constructor(private readonly maxSize = 5_000) {}
11
-
12
- has(messageId: string | null | undefined): boolean {
13
- if (!messageId || typeof messageId !== 'string') return false;
14
- return this.seen.has(messageId);
15
- }
16
-
17
- mark(messageId: string | null | undefined): void {
18
- if (!messageId || typeof messageId !== 'string') return;
19
- if (this.seen.has(messageId)) return;
20
- this.seen.add(messageId);
21
- this.order.push(messageId);
22
- while (this.order.length > this.maxSize) {
23
- const oldest = this.order.shift();
24
- if (oldest) this.seen.delete(oldest);
25
- }
26
- }
27
- }
@@ -1,85 +0,0 @@
1
- import { runtimeLog } from '../shared/runtimeLog.js';
2
-
3
- export interface StateTimeoutEvent {
4
- type: 'state-timeout';
5
- state: string;
6
- waitedMs: number;
7
- epoch: number;
8
- }
9
-
10
- interface ArmedTimer {
11
- epoch: number;
12
- state: string;
13
- timeoutMs: number;
14
- armedAt: number;
15
- handle: ReturnType<typeof setTimeout>;
16
- }
17
-
18
- /**
19
- * Per-lane liveness timers for parked states declaring timeoutMs. Owned by
20
- * AgentHost. A firing timer enqueues a state-timeout frame on the SAME lane
21
- * (caller-provided enqueue → EventQueue), so it serializes behind any real
22
- * event and can never race one. Epochs make stale frames identifiable: a
23
- * queued timeout frame whose epoch is not the lane's currently-armed epoch was
24
- * superseded (a tick ran after it fired) and must be dropped.
25
- *
26
- * In-memory only: process restart loses all timers; each lane re-arms on its
27
- * next real event (sessionStore persists { ctx, state } but not timers).
28
- */
29
- export class StateTimers {
30
- private _timers = new Map<string, ArmedTimer>();
31
- private _epoch = 0;
32
- private _enqueue: (event: StateTimeoutEvent, laneKey: string) => void;
33
-
34
- constructor(enqueue: (event: StateTimeoutEvent, laneKey: string) => void) {
35
- this._enqueue = enqueue;
36
- }
37
-
38
- /** Re-arm is idempotent: any previously armed timer for the lane is cancelled first. */
39
- arm(laneKey: string, state: string, timeoutMs: number): void {
40
- this.clear(laneKey);
41
- const epoch = ++this._epoch;
42
- const handle = setTimeout(() => {
43
- runtimeLog.debug('StateTimers', `fired laneKey=${laneKey} state=${state} waitedMs=${timeoutMs} epoch=${epoch}`);
44
- this._enqueue({ type: 'state-timeout', state, waitedMs: timeoutMs, epoch }, laneKey);
45
- }, timeoutMs);
46
- (handle as unknown as { unref?: () => void }).unref?.();
47
- this._timers.set(laneKey, { epoch, state, timeoutMs, armedAt: Date.now(), handle });
48
- }
49
-
50
- clear(laneKey: string): void {
51
- const t = this._timers.get(laneKey);
52
- if (!t) return;
53
- clearTimeout(t.handle);
54
- this._timers.delete(laneKey);
55
- }
56
-
57
- clearAll(): void {
58
- for (const key of [...this._timers.keys()]) this.clear(key);
59
- }
60
-
61
- /**
62
- * Drop stale state-timeout events from an incoming frame (single event or an
63
- * EventQueue-coalesced { type: 'batch', events } frame). Returns null when
64
- * nothing survives (pure stale-timeout frame — the lane's live timer, if any,
65
- * must be left untouched by the caller in that case).
66
- */
67
- stripStale(event: unknown, laneKey: string): unknown | null {
68
- const pending = this._timers.get(laneKey);
69
- const fresh = (ev: unknown): boolean => {
70
- const e = ev as { type?: string; epoch?: number };
71
- if (e?.type !== 'state-timeout') return true;
72
- const ok = pending !== undefined && e.epoch === pending.epoch;
73
- if (!ok) runtimeLog.debug('StateTimers', `dropping stale state-timeout laneKey=${laneKey} epoch=${e.epoch} armed=${pending?.epoch ?? 'none'}`);
74
- return ok;
75
- };
76
- const b = event as { type?: string; events?: unknown[] };
77
- if (b?.type === 'batch' && Array.isArray(b.events)) {
78
- const kept = b.events.filter(fresh);
79
- if (kept.length === 0) return null;
80
- if (kept.length === b.events.length) return event;
81
- return kept.length === 1 ? kept[0] : { type: 'batch', events: kept };
82
- }
83
- return fresh(event) ? event : null;
84
- }
85
- }