@canonmsg/agent-sdk 3.2.4 → 3.3.0
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/dist/canon-agent.js +39 -14
- package/dist/realtime.js +7 -1
- package/package.json +2 -2
package/dist/canon-agent.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ApprovalManager, CanonClient, ControlChannelPoller, buildCanonTurnContextV2, buildCanonGroupContext, buildParticipationHistorySnapshot, createTurnOutputController, createRuntimeStatePublisher, createTypingStatusPublisher, diffCanonMemberIds, FINAL_MESSAGE_HANDOFF_MS, RUNTIME_NEW_SESSION_ACTION, RUNTIME_STOP_ACTION, RUNTIME_STOP_AND_DROP_ACTION, buildRuntimeCardOutcome, buildRuntimeInputOutcome, initRTDBAuth, normalizeTurnMetadata, reachOutToCanonContact, resolveCanonReplyContext, resolveMessageActiveSelfContextId, resolveRuntimeProvenance, selectActiveSelfContexts, renderCanonHostInboundContent, } from '@canonmsg/core';
|
|
2
|
-
import { randomUUID } from 'node:crypto';
|
|
1
|
+
import { ApprovalManager, CanonClient, ControlChannelPoller, buildCanonTurnContextV2, buildCanonGroupContext, buildParticipationHistorySnapshot, createTurnOutputController, createRuntimeStatePublisher, createTypingStatusPublisher, diffCanonMemberIds, FINAL_MESSAGE_HANDOFF_MS, RUNTIME_NEW_SESSION_ACTION, RUNTIME_STOP_ACTION, RUNTIME_STOP_AND_DROP_ACTION, buildRuntimeCardOutcome, buildRuntimeInputOutcome, initRTDBAuth, normalizeTurnMetadata, reachOutToCanonContact, resolveCanonReplyContext, resolveMessageActiveSelfContextId, resolveRuntimeProvenance, selectActiveSelfContexts, renderCanonHostInboundContent, sendMessageWithRetry, } from '@canonmsg/core';
|
|
2
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
3
3
|
import { AuthManager } from './auth.js';
|
|
4
4
|
import { Debouncer } from './debouncer.js';
|
|
5
5
|
import { buildRuntimeCardCreateArgs } from './runtime-card.js';
|
|
@@ -12,6 +12,7 @@ const RUNTIME_PRIMITIVE_DEDUPE_MAX = 1_000;
|
|
|
12
12
|
const DEFAULT_RUNTIME_INPUT_TIMEOUT_MS = 5 * 60_000;
|
|
13
13
|
const RUNTIME_INPUT_POLL_MS = 1_000;
|
|
14
14
|
const RUNTIME_INPUT_ID_PATTERN = /^[A-Za-z0-9_.:-]{1,160}$/;
|
|
15
|
+
const SDK_MESSAGE_ID_READABLE_MAX = 120;
|
|
15
16
|
const SDK_RUNTIME_CAPABILITIES = {
|
|
16
17
|
supportsInterrupt: false,
|
|
17
18
|
supportsInputInterrupt: false,
|
|
@@ -32,8 +33,8 @@ const DEFAULT_SDK_RUNTIME_DESCRIPTOR = {
|
|
|
32
33
|
responder: 'agent_owner',
|
|
33
34
|
result: 'action_or_values',
|
|
34
35
|
maxTimeoutMs: 30 * 60_000,
|
|
35
|
-
blockKinds: ['summary', 'metricGrid', 'chart', 'table', 'list', 'callout', 'actions'],
|
|
36
|
-
actionFieldTypes: ['text', 'textarea', 'select', 'multiSelect', 'boolean'],
|
|
36
|
+
blockKinds: ['summary', 'metricGrid', 'chart', 'table', 'list', 'callout', 'actions', 'mediaPreview', 'details'],
|
|
37
|
+
actionFieldTypes: ['text', 'textarea', 'select', 'multiSelect', 'boolean', 'date', 'number', 'currency', 'searchSelect', 'lineItems'],
|
|
37
38
|
native: true,
|
|
38
39
|
},
|
|
39
40
|
},
|
|
@@ -167,6 +168,19 @@ function safeRuntimeCardId(value) {
|
|
|
167
168
|
? normalized
|
|
168
169
|
: `card_${randomUUID()}`;
|
|
169
170
|
}
|
|
171
|
+
function buildSdkMessageId(parts) {
|
|
172
|
+
const raw = parts
|
|
173
|
+
.map((part) => part == null ? '' : String(part))
|
|
174
|
+
.filter(Boolean)
|
|
175
|
+
.join(':');
|
|
176
|
+
const hash = createHash('sha256').update(raw || 'sdk-message').digest('hex').slice(0, 16);
|
|
177
|
+
const readable = (raw || 'sdk-message')
|
|
178
|
+
.replace(/[^A-Za-z0-9_.:-]+/g, '_')
|
|
179
|
+
.replace(/_+/g, '_')
|
|
180
|
+
.replace(/^[:_.-]+|[:_.-]+$/g, '')
|
|
181
|
+
.slice(0, SDK_MESSAGE_ID_READABLE_MAX);
|
|
182
|
+
return `${readable || 'sdk-message'}:${hash}`;
|
|
183
|
+
}
|
|
170
184
|
function isRuntimePrimitiveId(value) {
|
|
171
185
|
return value === 'runtime.status'
|
|
172
186
|
|| value === 'runtime.reasoning.set'
|
|
@@ -1101,6 +1115,7 @@ export class CanonAgent {
|
|
|
1101
1115
|
const turnOpenedAt = Date.now();
|
|
1102
1116
|
let turnState = 'thinking';
|
|
1103
1117
|
let shouldPersistTurnState = false;
|
|
1118
|
+
let durableMessageSequence = 0;
|
|
1104
1119
|
const agentId = this.agentId;
|
|
1105
1120
|
const runtimeState = this.createRuntimeStatePublisher();
|
|
1106
1121
|
const queueDepth = () => this.sessionManager?.getQueueDepth(conversationId) ?? 0;
|
|
@@ -1208,7 +1223,7 @@ export class CanonAgent {
|
|
|
1208
1223
|
throwIfAborted();
|
|
1209
1224
|
const sendOptions = withActiveSelfContext(options);
|
|
1210
1225
|
const turnTrail = turnOutput.getFinalTrail();
|
|
1211
|
-
const result = await
|
|
1226
|
+
const result = await sendDurableMessage(text, {
|
|
1212
1227
|
...sendOptions,
|
|
1213
1228
|
metadata: {
|
|
1214
1229
|
...(sendOptions.metadata ?? {}),
|
|
@@ -1216,7 +1231,7 @@ export class CanonAgent {
|
|
|
1216
1231
|
turnSemantics: 'turn_complete',
|
|
1217
1232
|
...(turnTrail.length > 0 ? { turnTrail } : {}),
|
|
1218
1233
|
},
|
|
1219
|
-
});
|
|
1234
|
+
}, ['sdk', 'final', conversationId, turnId]);
|
|
1220
1235
|
await sleep(FINAL_MESSAGE_HANDOFF_MS);
|
|
1221
1236
|
try {
|
|
1222
1237
|
await this.typingSignals.clear(conversationId);
|
|
@@ -1266,6 +1281,16 @@ export class CanonAgent {
|
|
|
1266
1281
|
return base;
|
|
1267
1282
|
return activeSelfContextId ? { ...base, selfContextId: activeSelfContextId } : base;
|
|
1268
1283
|
};
|
|
1284
|
+
const sendDurableMessage = (text, options, fallbackMessageIdParts) => {
|
|
1285
|
+
const messageId = options?.messageId
|
|
1286
|
+
?? buildSdkMessageId([...fallbackMessageIdParts, durableMessageSequence += 1]);
|
|
1287
|
+
return sendMessageWithRetry(this.apiClient, conversationId, text, {
|
|
1288
|
+
...(options ?? {}),
|
|
1289
|
+
messageId,
|
|
1290
|
+
}, {
|
|
1291
|
+
sleep: (ms) => sleepWithAbort(ms, abortController.signal),
|
|
1292
|
+
});
|
|
1293
|
+
};
|
|
1269
1294
|
// Build agent context (fallback to minimal if not yet received)
|
|
1270
1295
|
const agent = this.agentContext ?? {
|
|
1271
1296
|
agentId: this.agentId,
|
|
@@ -1549,14 +1574,14 @@ export class CanonAgent {
|
|
|
1549
1574
|
kind: request.kind,
|
|
1550
1575
|
reason: result.status,
|
|
1551
1576
|
});
|
|
1552
|
-
await
|
|
1577
|
+
await sendDurableMessage(outcome.text, {
|
|
1553
1578
|
metadata: {
|
|
1554
1579
|
...outcome.metadata,
|
|
1555
1580
|
turnId: request.turnId ?? turnId,
|
|
1556
1581
|
turnSemantics: 'control',
|
|
1557
1582
|
replyBehavior: 'suppress_auto_reply',
|
|
1558
1583
|
},
|
|
1559
|
-
});
|
|
1584
|
+
}, ['sdk', 'runtime-input-outcome', conversationId, request.turnId ?? turnId, inputId, result.status]);
|
|
1560
1585
|
throwIfAborted();
|
|
1561
1586
|
shouldPersistTurnState = false;
|
|
1562
1587
|
try {
|
|
@@ -1725,14 +1750,14 @@ export class CanonAgent {
|
|
|
1725
1750
|
const outcome = buildRuntimeCardOutcome(cardId, resolutionStatus, {
|
|
1726
1751
|
reason: resolutionStatus,
|
|
1727
1752
|
});
|
|
1728
|
-
await
|
|
1753
|
+
await sendDurableMessage(outcome.text, {
|
|
1729
1754
|
metadata: {
|
|
1730
1755
|
...outcome.metadata,
|
|
1731
1756
|
turnId: request.turnId ?? turnId,
|
|
1732
1757
|
turnSemantics: 'control',
|
|
1733
1758
|
replyBehavior: 'suppress_auto_reply',
|
|
1734
1759
|
},
|
|
1735
|
-
});
|
|
1760
|
+
}, ['sdk', 'runtime-card-outcome', conversationId, request.turnId ?? turnId, cardId, resolutionStatus]);
|
|
1736
1761
|
throwIfAborted();
|
|
1737
1762
|
shouldPersistTurnState = false;
|
|
1738
1763
|
try {
|
|
@@ -1754,14 +1779,14 @@ export class CanonAgent {
|
|
|
1754
1779
|
if (abortController.signal.aborted || isAbortLikeError(error)) {
|
|
1755
1780
|
if (shouldSendInterruptedOutcome) {
|
|
1756
1781
|
const outcome = buildRuntimeCardOutcome(cardId, 'cancelled', { reason: 'interrupted' });
|
|
1757
|
-
await
|
|
1782
|
+
await sendDurableMessage(outcome.text, {
|
|
1758
1783
|
metadata: {
|
|
1759
1784
|
...outcome.metadata,
|
|
1760
1785
|
turnId: request.turnId ?? turnId,
|
|
1761
1786
|
turnSemantics: 'control',
|
|
1762
1787
|
replyBehavior: 'suppress_auto_reply',
|
|
1763
1788
|
},
|
|
1764
|
-
}).catch(() => { });
|
|
1789
|
+
}, ['sdk', 'runtime-card-outcome', conversationId, request.turnId ?? turnId, cardId, 'interrupted']).catch(() => { });
|
|
1765
1790
|
}
|
|
1766
1791
|
throw error;
|
|
1767
1792
|
}
|
|
@@ -1933,13 +1958,13 @@ export class CanonAgent {
|
|
|
1933
1958
|
}
|
|
1934
1959
|
catch { }
|
|
1935
1960
|
if (text) {
|
|
1936
|
-
await
|
|
1961
|
+
await sendDurableMessage(text, {
|
|
1937
1962
|
metadata: {
|
|
1938
1963
|
turnId,
|
|
1939
1964
|
turnSemantics: 'control',
|
|
1940
1965
|
replyBehavior: 'suppress_auto_reply',
|
|
1941
1966
|
},
|
|
1942
|
-
});
|
|
1967
|
+
}, ['sdk', 'waiting-input-note', conversationId, turnId]);
|
|
1943
1968
|
}
|
|
1944
1969
|
},
|
|
1945
1970
|
},
|
package/dist/realtime.js
CHANGED
|
@@ -211,7 +211,13 @@ export class RealtimeManager {
|
|
|
211
211
|
if (message.senderId === this.agentId)
|
|
212
212
|
continue;
|
|
213
213
|
const createdAtMs = messageCreatedAtMs(message.createdAt);
|
|
214
|
-
|
|
214
|
+
// Use a strict lower bound of `< lowerBoundMs` (not `<=`): a
|
|
215
|
+
// gap-dropped message can share the same createdAt millisecond as
|
|
216
|
+
// the last message seen over SSE (server timestamps collide under
|
|
217
|
+
// bursts — exactly the scenario catch-up targets). The id-dedupe on
|
|
218
|
+
// the next line suppresses the already-delivered boundary message,
|
|
219
|
+
// so excluding by `<=` would only drop never-seen same-ms peers.
|
|
220
|
+
if (!createdAtMs || createdAtMs < lowerBoundMs)
|
|
215
221
|
continue;
|
|
216
222
|
if (this.hasSeenInboundMessage(conversation.id, message.id))
|
|
217
223
|
continue;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@canonmsg/agent-sdk",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.0",
|
|
4
4
|
"description": "Canon Agent SDK — build AI agents that participate in Canon conversations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"node": ">=18.0.0"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@canonmsg/core": "^2.
|
|
31
|
+
"@canonmsg/core": "^2.7.0"
|
|
32
32
|
},
|
|
33
33
|
"publishConfig": {
|
|
34
34
|
"access": "public"
|