@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.
- package/CHANGELOG.md +14 -0
- package/README.md +41 -2
- package/dist/AgentHost.d.ts +201 -0
- package/dist/AgentHost.js +652 -0
- package/dist/adapters/AnthropicAdapter.d.ts +39 -0
- package/dist/adapters/AnthropicAdapter.js +200 -0
- package/dist/adapters/McpAdapter.d.ts +199 -0
- package/dist/adapters/McpAdapter.js +468 -0
- package/dist/adapters/OpenAIAdapter.d.ts +26 -0
- package/dist/adapters/OpenAIAdapter.js +158 -0
- package/dist/adapters/index.js +2 -0
- package/dist/agent/Agent.d.ts +78 -0
- package/dist/agent/Agent.js +58 -0
- package/dist/agent/ClaudeSdkAgent.d.ts +38 -0
- package/dist/agent/ClaudeSdkAgent.js +322 -0
- package/dist/agent/claudeCognition.d.ts +67 -0
- package/dist/agent/claudeCognition.js +103 -0
- package/dist/agent/claudeSdkProtocol.d.ts +11 -0
- package/dist/agent/claudeSdkTools.d.ts +19 -0
- package/dist/agent/claudeSdkTools.js +57 -0
- package/dist/agent/hostedAgentConnection.d.ts +15 -0
- package/dist/agent/hostedAgentConnection.js +29 -0
- package/dist/agent/toolManagerToSdkMcp.d.ts +12 -0
- package/dist/agent/toolManagerToSdkMcp.js +123 -0
- package/dist/brain/index.d.ts +50 -0
- package/dist/brain/index.js +45 -0
- package/dist/cognition/validateContext.d.ts +11 -0
- package/dist/cognition/validateContext.js +117 -0
- package/dist/context/applyEffects.d.ts +2 -0
- package/dist/context/applyEffects.js +89 -0
- package/dist/context/batch.d.ts +2 -0
- package/dist/context/batch.js +18 -0
- package/dist/context/classifyEnvelope.d.ts +1 -0
- package/dist/context/classifyEnvelope.js +58 -0
- package/dist/context/routingLabels.d.ts +4 -0
- package/dist/context/routingLabels.js +48 -0
- package/dist/defineAgent.d.ts +14 -0
- package/dist/defineAgent.js +68 -0
- package/dist/formatters/AgreementFormatter.d.ts +18 -0
- package/dist/formatters/AgreementFormatter.js +130 -0
- package/dist/formatters/HistoryFormatter.d.ts +26 -0
- package/dist/formatters/HistoryFormatter.js +173 -0
- package/dist/formatters/index.js +2 -0
- package/{src/index.ts → dist/index.d.ts} +7 -53
- package/dist/index.js +66 -0
- package/dist/ingress/normalizeIncoming.d.ts +65 -0
- package/dist/ingress/normalizeIncoming.js +88 -0
- package/dist/memory/MemoryStore.d.ts +55 -0
- package/dist/memory/MemoryStore.js +78 -0
- package/dist/pricing/fleetDefaults.d.ts +46 -0
- package/dist/pricing/fleetDefaults.js +168 -0
- package/dist/pricing/fleetEvalFree.d.ts +7 -0
- package/dist/pricing/fleetEvalFree.js +24 -0
- package/dist/pricing/fleetFreeTierA.gen.d.ts +6 -0
- package/{src/pricing/fleetFreeTierA.gen.ts → dist/pricing/fleetFreeTierA.gen.js} +5 -6
- package/dist/pricing/fleetTierByAgentId.gen.d.ts +7 -0
- package/dist/pricing/fleetTierByAgentId.gen.js +768 -0
- package/dist/runtime/AgentMachine.d.ts +143 -0
- package/dist/runtime/AgentMachine.js +400 -0
- package/dist/runtime/PromptBuilder.d.ts +96 -0
- package/dist/runtime/PromptBuilder.js +439 -0
- package/{src/runtime/bootstrapCtx.ts → dist/runtime/bootstrapCtx.d.ts} +1 -22
- package/dist/runtime/bootstrapCtx.js +37 -0
- package/dist/runtime/buildOutcome.d.ts +68 -0
- package/dist/runtime/buildOutcome.js +464 -0
- package/dist/runtime/defaults.d.ts +54 -0
- package/dist/runtime/defaults.js +47 -0
- package/dist/runtime/deriveRespondsToProposals.d.ts +9 -0
- package/dist/runtime/deriveRespondsToProposals.js +38 -0
- package/dist/runtime/kickoff.d.ts +15 -0
- package/dist/runtime/kickoff.js +112 -0
- package/dist/runtime/runMechanical.d.ts +25 -0
- package/dist/runtime/runMechanical.js +74 -0
- package/dist/runtime/runTurn.d.ts +63 -0
- package/dist/runtime/runTurn.js +800 -0
- package/dist/runtime/validateWorkflow.d.ts +17 -0
- package/dist/runtime/validateWorkflow.js +209 -0
- package/dist/server/ConnectionPool.d.ts +68 -0
- package/dist/server/ConnectionPool.js +166 -0
- package/dist/server/EventQueue.d.ts +33 -0
- package/dist/server/EventQueue.js +98 -0
- package/dist/server/InboxCatchUp.d.ts +24 -0
- package/dist/server/InboxCatchUp.js +214 -0
- package/dist/server/OutboxBuffer.d.ts +33 -0
- package/dist/server/OutboxBuffer.js +68 -0
- package/dist/server/SeenMessages.d.ts +13 -0
- package/dist/server/SeenMessages.js +31 -0
- package/dist/server/StateTimers.d.ts +34 -0
- package/dist/server/StateTimers.js +70 -0
- package/dist/server/ZiggsEffectHandler.d.ts +79 -0
- package/dist/server/ZiggsEffectHandler.js +319 -0
- package/dist/server/agreements/AgreementService.d.ts +50 -0
- package/dist/server/agreements/AgreementService.js +85 -0
- package/dist/server/createHealthServer.d.ts +7 -0
- package/dist/server/createHealthServer.js +75 -0
- package/dist/server/proactive/ProactiveTrigger.d.ts +33 -0
- package/dist/server/proactive/ProactiveTrigger.js +71 -0
- package/dist/server/runLauncher.d.ts +28 -0
- package/dist/server/runLauncher.js +93 -0
- package/dist/server/tasks/TaskService.d.ts +25 -0
- package/dist/server/tasks/TaskService.js +103 -0
- package/dist/server/tasks/index.js +1 -0
- package/dist/server/telemetryIngest.d.ts +24 -0
- package/dist/server/telemetryIngest.js +62 -0
- package/dist/server/tools/index.d.ts +24 -0
- package/{src/server/tools/index.ts → dist/server/tools/index.js} +4 -24
- package/dist/server/tools/tier1/protocolRunner.d.ts +39 -0
- package/dist/server/tools/tier1/protocolRunner.js +288 -0
- package/dist/server/tools/tier1/protocolTools.d.ts +12 -0
- package/dist/server/tools/tier1/protocolTools.js +37 -0
- package/dist/server/tools/tier2/connectionTools.d.ts +4 -0
- package/dist/server/tools/tier2/connectionTools.js +63 -0
- package/dist/server/tools/tier2/contextTools.d.ts +4 -0
- package/dist/server/tools/tier2/contextTools.js +46 -0
- package/dist/server/tools/tier2/discoveryTools.d.ts +4 -0
- package/dist/server/tools/tier2/discoveryTools.js +25 -0
- package/dist/server/tools/tier2/marketplaceTools.d.ts +3 -0
- package/dist/server/tools/tier2/marketplaceTools.js +22 -0
- package/dist/server/tools/tier2/paymentTools.d.ts +12 -0
- package/dist/server/tools/tier2/paymentTools.js +165 -0
- package/dist/server/ziggsconnect/ZiggsConnectClient.d.ts +35 -0
- package/dist/server/ziggsconnect/ZiggsConnectClient.js +95 -0
- package/dist/server/ziggscontext/ZiggsContextClient.d.ts +53 -0
- package/dist/server/ziggscontext/ZiggsContextClient.js +124 -0
- package/dist/server/ziggspay/ZiggsPayClient.d.ts +82 -0
- package/dist/server/ziggspay/ZiggsPayClient.js +203 -0
- package/dist/shared/ids.d.ts +1 -0
- package/dist/shared/ids.js +3 -0
- package/dist/shared/runtimeLog.d.ts +18 -0
- package/dist/shared/runtimeLog.js +68 -0
- package/dist/shared/types.d.ts +22 -0
- package/dist/shared/types.js +23 -0
- package/dist/tasks/protocolRegistry.d.ts +16 -0
- package/dist/tasks/protocolRegistry.js +20 -0
- package/dist/tools/ToolManager.d.ts +12 -0
- package/dist/tools/ToolManager.js +74 -0
- package/dist/tools/ToolProvider.d.ts +6 -0
- package/dist/tools/ToolProvider.js +21 -0
- package/dist/tools/defineTool.d.ts +27 -0
- package/dist/tools/defineTool.js +62 -0
- package/{src/tools/index.ts → dist/tools/index.d.ts} +0 -1
- package/dist/tools/index.js +6 -0
- package/dist/tools/recordReport.d.ts +41 -0
- package/dist/tools/recordReport.js +30 -0
- package/dist/types.d.ts +466 -0
- package/dist/types.js +7 -0
- package/dist/utils/jsonExtractor.d.ts +2 -0
- package/dist/utils/jsonExtractor.js +111 -0
- package/package.json +14 -6
- package/src/AgentHost.ts +0 -814
- package/src/adapters/AnthropicAdapter.ts +0 -238
- package/src/adapters/McpAdapter.ts +0 -678
- package/src/adapters/OpenAIAdapter.ts +0 -194
- package/src/agent/Agent.ts +0 -112
- package/src/agent/ClaudeSdkAgent.ts +0 -401
- package/src/agent/claudeCognition.ts +0 -139
- package/src/agent/claudeSdkTools.ts +0 -81
- package/src/agent/hostedAgentConnection.ts +0 -41
- package/src/agent/toolManagerToSdkMcp.ts +0 -136
- package/src/cognition/validateContext.ts +0 -95
- package/src/context/applyEffects.ts +0 -80
- package/src/context/batch.ts +0 -19
- package/src/context/classifyEnvelope.ts +0 -38
- package/src/context/routingLabels.ts +0 -46
- package/src/defineAgent.ts +0 -77
- package/src/formatters/AgreementFormatter.ts +0 -111
- package/src/formatters/HistoryFormatter.ts +0 -172
- package/src/ingress/normalizeIncoming.ts +0 -162
- package/src/memory/MemoryStore.ts +0 -104
- package/src/pricing/fleetDefaults.ts +0 -225
- package/src/pricing/fleetEvalFree.ts +0 -24
- package/src/pricing/fleetTierByAgentId.gen.ts +0 -775
- package/src/runtime/AgentMachine.ts +0 -484
- package/src/runtime/PromptBuilder.ts +0 -522
- package/src/runtime/buildOutcome.ts +0 -563
- package/src/runtime/defaults.ts +0 -86
- package/src/runtime/deriveRespondsToProposals.ts +0 -35
- package/src/runtime/kickoff.ts +0 -117
- package/src/runtime/runMechanical.ts +0 -106
- package/src/runtime/runTurn.ts +0 -870
- package/src/runtime/validateWorkflow.ts +0 -221
- package/src/server/ConnectionPool.ts +0 -206
- package/src/server/EventQueue.ts +0 -133
- package/src/server/InboxCatchUp.ts +0 -291
- package/src/server/OutboxBuffer.ts +0 -90
- package/src/server/SeenMessages.ts +0 -27
- package/src/server/StateTimers.ts +0 -85
- package/src/server/ZiggsEffectHandler.ts +0 -427
- package/src/server/agreements/AgreementService.ts +0 -118
- package/src/server/createHealthServer.ts +0 -85
- package/src/server/proactive/ProactiveTrigger.ts +0 -83
- package/src/server/runLauncher.ts +0 -146
- package/src/server/tasks/TaskService.ts +0 -111
- package/src/server/telemetryIngest.ts +0 -91
- package/src/server/tools/tier1/protocolRunner.ts +0 -353
- package/src/server/tools/tier1/protocolTools.ts +0 -114
- package/src/server/tools/tier2/connectionTools.ts +0 -75
- package/src/server/tools/tier2/contextTools.ts +0 -63
- package/src/server/tools/tier2/discoveryTools.ts +0 -34
- package/src/server/tools/tier2/marketplaceTools.ts +0 -27
- package/src/server/tools/tier2/paymentTools.ts +0 -170
- package/src/server/ziggsconnect/ZiggsConnectClient.ts +0 -126
- package/src/server/ziggscontext/ZiggsContextClient.ts +0 -129
- package/src/server/ziggspay/ZiggsPayClient.ts +0 -193
- package/src/shared/ids.ts +0 -3
- package/src/shared/runtimeLog.ts +0 -72
- package/src/shared/types.ts +0 -29
- package/src/tasks/protocolRegistry.ts +0 -25
- package/src/tools/ToolManager.ts +0 -95
- package/src/tools/ToolProvider.ts +0 -19
- package/src/tools/defineTool.ts +0 -90
- package/src/tools/recordReport.ts +0 -82
- package/src/types.ts +0 -483
- package/src/utils/jsonExtractor.ts +0 -100
- /package/{src/adapters/index.ts → dist/adapters/index.d.ts} +0 -0
- /package/{src/agent/claudeSdkProtocol.ts → dist/agent/claudeSdkProtocol.js} +0 -0
- /package/{src/formatters/index.ts → dist/formatters/index.d.ts} +0 -0
- /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
|
-
}
|