@canonmsg/agent-sdk 1.3.0 → 1.3.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/dist/canon-agent.d.ts +12 -3
- package/dist/canon-agent.js +258 -8
- package/dist/index.d.ts +1 -1
- package/dist/types.d.ts +17 -2
- package/package.json +2 -2
package/dist/canon-agent.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type AddMemberResult, type CanonContact, type ContactCardPayload, type CreateContactRequestResult } from '@canonmsg/core';
|
|
2
|
-
import type { CanonAgentOptions, ContactAddedHandler, ContactRemovedHandler, CreateConversationOptions, MessageHandler, ReachOutOptions, ReachOutResult, ContactRequestHandler, RuntimeSignalHandler } from './types.js';
|
|
1
|
+
import { type AddMemberResult, type CanonContact, type CanonRuntimePrimitiveId, type ContactCardPayload, type CreateContactRequestResult } from '@canonmsg/core';
|
|
2
|
+
import type { CanonAgentOptions, ContactAddedHandler, ContactRemovedHandler, CreateConversationOptions, MessageHandler, ReachOutOptions, ReachOutResult, ContactRequestHandler, RuntimeSignalHandler, RuntimePrimitiveHandler } from './types.js';
|
|
3
3
|
/**
|
|
4
4
|
* Contact-graph operations exposed under `agent.contacts`. Wraps the REST
|
|
5
5
|
* endpoints in CanonClient — the same surface a human user would hit through
|
|
@@ -33,6 +33,8 @@ export declare class CanonAgent {
|
|
|
33
33
|
private interruptHandler;
|
|
34
34
|
private stopAndDropHandler;
|
|
35
35
|
private newSessionHandler;
|
|
36
|
+
private readonly primitiveHandlers;
|
|
37
|
+
private primitiveFallbackHandler;
|
|
36
38
|
/** Contact-graph operations (`agent.contacts.*`). Initialized in the constructor. */
|
|
37
39
|
readonly contacts: AgentContactsAPI;
|
|
38
40
|
/** Block/unblock operations (`agent.users.*`). Initialized in the constructor. */
|
|
@@ -45,6 +47,7 @@ export declare class CanonAgent {
|
|
|
45
47
|
private runtimeHeartbeatTimer;
|
|
46
48
|
private runtimeControlPollTimer;
|
|
47
49
|
private readonly lastSeenSignal;
|
|
50
|
+
private readonly primitiveRequestDedupe;
|
|
48
51
|
private readonly activeAbortControllers;
|
|
49
52
|
private readonly conversationMemberIds;
|
|
50
53
|
private readonly pendingMembershipChanges;
|
|
@@ -57,6 +60,7 @@ export declare class CanonAgent {
|
|
|
57
60
|
on(event: 'interrupt', handler: RuntimeSignalHandler): void;
|
|
58
61
|
on(event: 'stopAndDrop', handler: RuntimeSignalHandler): void;
|
|
59
62
|
on(event: 'newSession', handler: RuntimeSignalHandler): void;
|
|
63
|
+
onPrimitive(primitive: CanonRuntimePrimitiveId | '*', handler: RuntimePrimitiveHandler): void;
|
|
60
64
|
/**
|
|
61
65
|
* Resolve admission live for a target user (typically read off a shared
|
|
62
66
|
* contact card) and route into either an immediate message or a contact
|
|
@@ -100,6 +104,8 @@ export declare class CanonAgent {
|
|
|
100
104
|
private hasStopAndDropSupport;
|
|
101
105
|
private hasNewSessionSupport;
|
|
102
106
|
private hasRuntimeSignalSupport;
|
|
107
|
+
private hasRuntimePrimitiveSupport;
|
|
108
|
+
private hasRuntimeControlSupport;
|
|
103
109
|
private buildRuntimeDescriptor;
|
|
104
110
|
private buildRuntimeCapabilities;
|
|
105
111
|
private publishAgentRuntime;
|
|
@@ -113,7 +119,10 @@ export declare class CanonAgent {
|
|
|
113
119
|
private baselineRuntimeControlSignals;
|
|
114
120
|
private startRuntimeControlPolling;
|
|
115
121
|
private stopRuntimeControlPolling;
|
|
116
|
-
private
|
|
122
|
+
private pollRuntimeControls;
|
|
123
|
+
private handleRuntimePrimitiveRequests;
|
|
124
|
+
private clearRuntimePrimitiveRequest;
|
|
125
|
+
private prunePrimitiveRequestDedupe;
|
|
117
126
|
private handleRuntimeSignal;
|
|
118
127
|
private abortActiveTurns;
|
|
119
128
|
private resolveBatchDeliveryIntent;
|
package/dist/canon-agent.js
CHANGED
|
@@ -5,6 +5,8 @@ import { Debouncer } from './debouncer.js';
|
|
|
5
5
|
import { materializeMessageMedia, sendMediaFileMessage, uploadMediaFile, } from './media.js';
|
|
6
6
|
import { SessionManager } from './session-manager.js';
|
|
7
7
|
const AGENT_RUNTIME_HEARTBEAT_MS = 30_000;
|
|
8
|
+
const RUNTIME_PRIMITIVE_DEDUPE_TTL_MS = 5 * 60 * 1000;
|
|
9
|
+
const RUNTIME_PRIMITIVE_DEDUPE_MAX = 1_000;
|
|
8
10
|
const SDK_RUNTIME_CAPABILITIES = {
|
|
9
11
|
supportsInterrupt: false,
|
|
10
12
|
supportsQueue: true,
|
|
@@ -18,9 +20,133 @@ const DEFAULT_SDK_RUNTIME_DESCRIPTOR = {
|
|
|
18
20
|
supportsInterrupt: false,
|
|
19
21
|
streamingTextMode: 'snapshot',
|
|
20
22
|
};
|
|
23
|
+
const STANDARD_PRIMITIVE_COMMANDS = {
|
|
24
|
+
'runtime.status': {
|
|
25
|
+
id: 'runtime-status',
|
|
26
|
+
label: 'Runtime status',
|
|
27
|
+
description: 'Ask the runtime for its current status.',
|
|
28
|
+
primitive: 'runtime.status',
|
|
29
|
+
aliases: ['status'],
|
|
30
|
+
category: 'runtime',
|
|
31
|
+
placements: ['composer_slash', 'command_palette'],
|
|
32
|
+
availability: ['always'],
|
|
33
|
+
dispatch: { kind: 'primitive', primitive: 'runtime.status' },
|
|
34
|
+
},
|
|
35
|
+
'runtime.reasoning.set': {
|
|
36
|
+
id: 'thinking-level',
|
|
37
|
+
label: 'Thinking level',
|
|
38
|
+
description: 'Set the runtime reasoning or effort level.',
|
|
39
|
+
primitive: 'runtime.reasoning.set',
|
|
40
|
+
aliases: ['think', 'effort'],
|
|
41
|
+
category: 'runtime',
|
|
42
|
+
placements: ['composer_slash', 'command_palette'],
|
|
43
|
+
availability: ['always'],
|
|
44
|
+
args: [{
|
|
45
|
+
id: 'level',
|
|
46
|
+
label: 'Level',
|
|
47
|
+
kind: 'enum',
|
|
48
|
+
required: true,
|
|
49
|
+
choices: [
|
|
50
|
+
{ value: 'low', label: 'Low' },
|
|
51
|
+
{ value: 'medium', label: 'Medium' },
|
|
52
|
+
{ value: 'high', label: 'High' },
|
|
53
|
+
],
|
|
54
|
+
}],
|
|
55
|
+
dispatch: { kind: 'primitive', primitive: 'runtime.reasoning.set' },
|
|
56
|
+
},
|
|
57
|
+
'runtime.verbosity.set': {
|
|
58
|
+
id: 'verbosity',
|
|
59
|
+
label: 'Verbosity',
|
|
60
|
+
description: 'Set runtime verbosity.',
|
|
61
|
+
primitive: 'runtime.verbosity.set',
|
|
62
|
+
aliases: ['verbose'],
|
|
63
|
+
category: 'runtime',
|
|
64
|
+
placements: ['composer_slash', 'command_palette'],
|
|
65
|
+
availability: ['always'],
|
|
66
|
+
args: [{
|
|
67
|
+
id: 'level',
|
|
68
|
+
label: 'Level',
|
|
69
|
+
kind: 'enum',
|
|
70
|
+
required: true,
|
|
71
|
+
choices: [
|
|
72
|
+
{ value: 'off', label: 'Off' },
|
|
73
|
+
{ value: 'on', label: 'On' },
|
|
74
|
+
{ value: 'full', label: 'Full' },
|
|
75
|
+
],
|
|
76
|
+
}],
|
|
77
|
+
dispatch: { kind: 'primitive', primitive: 'runtime.verbosity.set' },
|
|
78
|
+
},
|
|
79
|
+
'runtime.usage': {
|
|
80
|
+
id: 'usage',
|
|
81
|
+
label: 'Usage',
|
|
82
|
+
description: 'Show or change runtime usage reporting.',
|
|
83
|
+
primitive: 'runtime.usage',
|
|
84
|
+
aliases: ['usage'],
|
|
85
|
+
category: 'runtime',
|
|
86
|
+
placements: ['composer_slash', 'command_palette'],
|
|
87
|
+
availability: ['always'],
|
|
88
|
+
dispatch: { kind: 'primitive', primitive: 'runtime.usage' },
|
|
89
|
+
},
|
|
90
|
+
'context.compact': {
|
|
91
|
+
id: 'compact-context',
|
|
92
|
+
label: 'Compact context',
|
|
93
|
+
description: 'Ask the runtime to compact its conversation context.',
|
|
94
|
+
primitive: 'context.compact',
|
|
95
|
+
aliases: ['compact'],
|
|
96
|
+
category: 'session',
|
|
97
|
+
placements: ['composer_slash', 'command_palette'],
|
|
98
|
+
availability: ['always'],
|
|
99
|
+
dispatch: { kind: 'primitive', primitive: 'context.compact' },
|
|
100
|
+
},
|
|
101
|
+
'session.new': {
|
|
102
|
+
id: 'new-session-primitive',
|
|
103
|
+
label: 'New session',
|
|
104
|
+
description: 'Ask the runtime to start a fresh session.',
|
|
105
|
+
primitive: 'session.new',
|
|
106
|
+
aliases: ['new'],
|
|
107
|
+
category: 'session',
|
|
108
|
+
placements: ['composer_slash', 'command_palette', 'session_strip'],
|
|
109
|
+
availability: ['always'],
|
|
110
|
+
dispatch: { kind: 'primitive', primitive: 'session.new' },
|
|
111
|
+
},
|
|
112
|
+
'session.reset': {
|
|
113
|
+
id: 'reset-session',
|
|
114
|
+
label: 'Reset session',
|
|
115
|
+
description: 'Ask the runtime to reset the current session.',
|
|
116
|
+
primitive: 'session.reset',
|
|
117
|
+
aliases: ['reset'],
|
|
118
|
+
category: 'session',
|
|
119
|
+
placements: ['composer_slash', 'command_palette'],
|
|
120
|
+
availability: ['always'],
|
|
121
|
+
dispatch: { kind: 'primitive', primitive: 'session.reset' },
|
|
122
|
+
},
|
|
123
|
+
};
|
|
21
124
|
function sleep(ms) {
|
|
22
125
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
23
126
|
}
|
|
127
|
+
function isRuntimePrimitiveId(value) {
|
|
128
|
+
return value === 'runtime.status'
|
|
129
|
+
|| value === 'runtime.reasoning.set'
|
|
130
|
+
|| value === 'runtime.verbosity.set'
|
|
131
|
+
|| value === 'runtime.usage'
|
|
132
|
+
|| value === 'context.compact'
|
|
133
|
+
|| value === 'session.new'
|
|
134
|
+
|| value === 'session.reset';
|
|
135
|
+
}
|
|
136
|
+
function normalizePrimitiveArgs(value) {
|
|
137
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
138
|
+
return {};
|
|
139
|
+
}
|
|
140
|
+
const args = {};
|
|
141
|
+
for (const [key, rawValue] of Object.entries(value)) {
|
|
142
|
+
if (!/^[A-Za-z0-9_-]+$/.test(key))
|
|
143
|
+
continue;
|
|
144
|
+
if (typeof rawValue === 'boolean' || typeof rawValue === 'string') {
|
|
145
|
+
args[key] = rawValue;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return args;
|
|
149
|
+
}
|
|
24
150
|
export class CanonAgent {
|
|
25
151
|
options;
|
|
26
152
|
apiClient;
|
|
@@ -36,6 +162,8 @@ export class CanonAgent {
|
|
|
36
162
|
interruptHandler = null;
|
|
37
163
|
stopAndDropHandler = null;
|
|
38
164
|
newSessionHandler = null;
|
|
165
|
+
primitiveHandlers = new Map();
|
|
166
|
+
primitiveFallbackHandler = null;
|
|
39
167
|
/** Contact-graph operations (`agent.contacts.*`). Initialized in the constructor. */
|
|
40
168
|
contacts;
|
|
41
169
|
/** Block/unblock operations (`agent.users.*`). Initialized in the constructor. */
|
|
@@ -48,6 +176,7 @@ export class CanonAgent {
|
|
|
48
176
|
runtimeHeartbeatTimer = null;
|
|
49
177
|
runtimeControlPollTimer = null;
|
|
50
178
|
lastSeenSignal = new Map();
|
|
179
|
+
primitiveRequestDedupe = new Map();
|
|
51
180
|
activeAbortControllers = new Map();
|
|
52
181
|
conversationMemberIds = new Map();
|
|
53
182
|
pendingMembershipChanges = new Map();
|
|
@@ -84,6 +213,14 @@ export class CanonAgent {
|
|
|
84
213
|
this.interruptHandler = options.runtimeControls?.onInterrupt ?? null;
|
|
85
214
|
this.stopAndDropHandler = options.runtimeControls?.onStopAndDrop ?? null;
|
|
86
215
|
this.newSessionHandler = options.runtimeControls?.onNewSession ?? null;
|
|
216
|
+
for (const [primitive, handler] of Object.entries(options.runtimePrimitives ?? {})) {
|
|
217
|
+
if (primitive === '*') {
|
|
218
|
+
this.primitiveFallbackHandler = handler;
|
|
219
|
+
}
|
|
220
|
+
else if (isRuntimePrimitiveId(primitive)) {
|
|
221
|
+
this.primitiveHandlers.set(primitive, handler);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
87
224
|
}
|
|
88
225
|
on(event, handler) {
|
|
89
226
|
if (event === 'message') {
|
|
@@ -134,6 +271,18 @@ export class CanonAgent {
|
|
|
134
271
|
}
|
|
135
272
|
this.contactRemovedHandler = handler;
|
|
136
273
|
}
|
|
274
|
+
onPrimitive(primitive, handler) {
|
|
275
|
+
if (primitive === '*') {
|
|
276
|
+
this.primitiveFallbackHandler = handler;
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
this.primitiveHandlers.set(primitive, handler);
|
|
280
|
+
}
|
|
281
|
+
if (this.running) {
|
|
282
|
+
this.startRuntimeControlPolling();
|
|
283
|
+
}
|
|
284
|
+
void this.publishAgentRuntime().catch(() => { });
|
|
285
|
+
}
|
|
137
286
|
/**
|
|
138
287
|
* Resolve admission live for a target user (typically read off a shared
|
|
139
288
|
* contact card) and route into either an immediate message or a contact
|
|
@@ -371,6 +520,12 @@ export class CanonAgent {
|
|
|
371
520
|
hasRuntimeSignalSupport() {
|
|
372
521
|
return this.hasInterruptSupport() || this.hasStopAndDropSupport() || this.hasNewSessionSupport();
|
|
373
522
|
}
|
|
523
|
+
hasRuntimePrimitiveSupport() {
|
|
524
|
+
return this.primitiveHandlers.size > 0 || Boolean(this.primitiveFallbackHandler);
|
|
525
|
+
}
|
|
526
|
+
hasRuntimeControlSupport() {
|
|
527
|
+
return this.hasRuntimeSignalSupport() || this.hasRuntimePrimitiveSupport();
|
|
528
|
+
}
|
|
374
529
|
buildRuntimeDescriptor() {
|
|
375
530
|
const source = this.options.runtimeDescriptor ?? DEFAULT_SDK_RUNTIME_DESCRIPTOR;
|
|
376
531
|
const hasInterrupt = this.hasInterruptSupport();
|
|
@@ -399,9 +554,23 @@ export class CanonAgent {
|
|
|
399
554
|
if (hasNewSession && !hasNewSessionAction) {
|
|
400
555
|
actions.push(RUNTIME_NEW_SESSION_ACTION);
|
|
401
556
|
}
|
|
557
|
+
const commands = [...(source.commands ?? [])].filter((command) => {
|
|
558
|
+
if (command.dispatch.kind !== 'primitive')
|
|
559
|
+
return true;
|
|
560
|
+
return this.primitiveHandlers.has(command.dispatch.primitive)
|
|
561
|
+
|| Boolean(this.primitiveFallbackHandler);
|
|
562
|
+
});
|
|
563
|
+
const hasCommandForPrimitive = (primitive) => commands.some((command) => (command.primitive === primitive
|
|
564
|
+
|| (command.dispatch.kind === 'primitive' && command.dispatch.primitive === primitive)));
|
|
565
|
+
for (const primitive of this.primitiveHandlers.keys()) {
|
|
566
|
+
if (!hasCommandForPrimitive(primitive)) {
|
|
567
|
+
commands.push(STANDARD_PRIMITIVE_COMMANDS[primitive]);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
402
570
|
return {
|
|
403
571
|
...source,
|
|
404
572
|
supportsInterrupt: hasInterrupt,
|
|
573
|
+
commands,
|
|
405
574
|
actions,
|
|
406
575
|
};
|
|
407
576
|
}
|
|
@@ -493,10 +662,10 @@ export class CanonAgent {
|
|
|
493
662
|
}));
|
|
494
663
|
}
|
|
495
664
|
startRuntimeControlPolling() {
|
|
496
|
-
if (!this.agentId || this.runtimeControlPollTimer || !this.
|
|
665
|
+
if (!this.agentId || this.runtimeControlPollTimer || !this.hasRuntimeControlSupport())
|
|
497
666
|
return;
|
|
498
667
|
this.runtimeControlPollTimer = setInterval(() => {
|
|
499
|
-
void this.
|
|
668
|
+
void this.pollRuntimeControls();
|
|
500
669
|
}, 2_000);
|
|
501
670
|
this.runtimeControlPollTimer.unref?.();
|
|
502
671
|
}
|
|
@@ -506,16 +675,97 @@ export class CanonAgent {
|
|
|
506
675
|
clearInterval(this.runtimeControlPollTimer);
|
|
507
676
|
this.runtimeControlPollTimer = null;
|
|
508
677
|
}
|
|
509
|
-
async
|
|
510
|
-
if (!this.agentId || !this.
|
|
678
|
+
async pollRuntimeControls() {
|
|
679
|
+
if (!this.agentId || !this.hasRuntimeControlSupport())
|
|
511
680
|
return;
|
|
512
681
|
await Promise.all(this.cachedConversationIds.map(async (conversationId) => {
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
682
|
+
if (this.hasRuntimeSignalSupport()) {
|
|
683
|
+
const raw = await Promise.resolve(rtdbRead(`/control/${conversationId}/${this.agentId}/signal`)).catch(() => null);
|
|
684
|
+
if (raw && typeof raw === 'object') {
|
|
685
|
+
await this.handleRuntimeSignal(conversationId, raw);
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
if (this.hasRuntimePrimitiveSupport()) {
|
|
689
|
+
const raw = await Promise.resolve(rtdbRead(`/control/${conversationId}/${this.agentId}/primitive`)).catch(() => null);
|
|
690
|
+
if (raw && typeof raw === 'object') {
|
|
691
|
+
await this.handleRuntimePrimitiveRequests(conversationId, raw);
|
|
692
|
+
}
|
|
693
|
+
}
|
|
517
694
|
}));
|
|
518
695
|
}
|
|
696
|
+
async handleRuntimePrimitiveRequests(conversationId, raw) {
|
|
697
|
+
if (!this.agentId)
|
|
698
|
+
return;
|
|
699
|
+
this.prunePrimitiveRequestDedupe();
|
|
700
|
+
const requests = Object.entries(raw)
|
|
701
|
+
.map(([requestId, value]) => ({ requestId, value }))
|
|
702
|
+
.filter((entry) => (Boolean(entry.requestId)
|
|
703
|
+
&& Boolean(entry.value)
|
|
704
|
+
&& typeof entry.value === 'object'
|
|
705
|
+
&& !Array.isArray(entry.value)))
|
|
706
|
+
.sort((a, b) => Number(a.value.updatedAt ?? 0) - Number(b.value.updatedAt ?? 0));
|
|
707
|
+
for (const { requestId, value } of requests) {
|
|
708
|
+
const requestKey = `${conversationId}:${requestId}`;
|
|
709
|
+
if (this.primitiveRequestDedupe.has(requestKey))
|
|
710
|
+
continue;
|
|
711
|
+
this.primitiveRequestDedupe.set(requestKey, Date.now());
|
|
712
|
+
let cleared = false;
|
|
713
|
+
try {
|
|
714
|
+
const primitive = value.id;
|
|
715
|
+
if (!isRuntimePrimitiveId(primitive)) {
|
|
716
|
+
cleared = await this.clearRuntimePrimitiveRequest(conversationId, requestId);
|
|
717
|
+
continue;
|
|
718
|
+
}
|
|
719
|
+
const handler = this.primitiveHandlers.get(primitive) ?? this.primitiveFallbackHandler;
|
|
720
|
+
if (!handler) {
|
|
721
|
+
cleared = await this.clearRuntimePrimitiveRequest(conversationId, requestId);
|
|
722
|
+
continue;
|
|
723
|
+
}
|
|
724
|
+
const args = normalizePrimitiveArgs(value.args);
|
|
725
|
+
await Promise.resolve(handler({
|
|
726
|
+
conversationId,
|
|
727
|
+
primitive,
|
|
728
|
+
args,
|
|
729
|
+
requestId,
|
|
730
|
+
updatedAt: typeof value.updatedAt === 'number' ? value.updatedAt : undefined,
|
|
731
|
+
rawText: typeof value.rawText === 'string' ? value.rawText : undefined,
|
|
732
|
+
alias: typeof value.alias === 'string' ? value.alias : undefined,
|
|
733
|
+
})).catch((error) => {
|
|
734
|
+
console.error(`[canon-sdk] Runtime primitive ${primitive} handler failed for ${conversationId}:`, error);
|
|
735
|
+
});
|
|
736
|
+
cleared = await this.clearRuntimePrimitiveRequest(conversationId, requestId);
|
|
737
|
+
}
|
|
738
|
+
finally {
|
|
739
|
+
if (cleared) {
|
|
740
|
+
this.primitiveRequestDedupe.delete(requestKey);
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
async clearRuntimePrimitiveRequest(conversationId, requestId) {
|
|
746
|
+
if (!this.agentId)
|
|
747
|
+
return false;
|
|
748
|
+
try {
|
|
749
|
+
await Promise.resolve(rtdbWrite(`/control/${conversationId}/${this.agentId}/primitive/${requestId}`, null));
|
|
750
|
+
return true;
|
|
751
|
+
}
|
|
752
|
+
catch {
|
|
753
|
+
return false;
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
prunePrimitiveRequestDedupe(now = Date.now()) {
|
|
757
|
+
for (const [key, timestamp] of this.primitiveRequestDedupe) {
|
|
758
|
+
if (now - timestamp >= RUNTIME_PRIMITIVE_DEDUPE_TTL_MS) {
|
|
759
|
+
this.primitiveRequestDedupe.delete(key);
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
while (this.primitiveRequestDedupe.size > RUNTIME_PRIMITIVE_DEDUPE_MAX) {
|
|
763
|
+
const oldestKey = this.primitiveRequestDedupe.keys().next().value;
|
|
764
|
+
if (!oldestKey)
|
|
765
|
+
break;
|
|
766
|
+
this.primitiveRequestDedupe.delete(oldestKey);
|
|
767
|
+
}
|
|
768
|
+
}
|
|
519
769
|
async handleRuntimeSignal(conversationId, raw) {
|
|
520
770
|
if (!this.agentId)
|
|
521
771
|
return;
|
package/dist/index.d.ts
CHANGED
|
@@ -7,4 +7,4 @@ export { DEFAULT_MEDIA_CACHE_DIR, getCodexImagePath, getMessageAttachments, infe
|
|
|
7
7
|
export type { AnthropicImageBlock, AnthropicImageMimeType, MaterializeMediaOptions, MaterializedCanonAttachment, ReplyWithFileOptions, UploadMediaFileOptions, } from './media.js';
|
|
8
8
|
export type { SessionConfig, Session } from './session-manager.js';
|
|
9
9
|
export type { AgentContext, CanonGroupContext, CanonKnownRecentParticipant, CanonMembershipChange, CanonContactRequest, CanonMessage, CanonConversation, CanonSelfContext, SendContextualMessageOptions, SendContextualMessageResult, SendContextualSelfContextInput, SendMessageOptions, CreateConversationOptions, } from '@canonmsg/core';
|
|
10
|
-
export type { CanonAgentOptions, ContactAddedHandler, ContactRemovedHandler, ContactRequestHandler, MessageHandler, MessageHandlerContext, ProgressMessageOptions, ProgressMessageResult, ReachOutOptions, ReachOutResult, SessionInfo, SessionOptions, DeliveryMode, } from './types.js';
|
|
10
|
+
export type { CanonAgentOptions, ContactAddedHandler, ContactRemovedHandler, ContactRequestHandler, MessageHandler, MessageHandlerContext, ProgressMessageOptions, ProgressMessageResult, ReachOutOptions, ReachOutResult, RuntimePrimitiveContext, RuntimePrimitiveHandler, RuntimePrimitiveHandlers, SessionInfo, SessionOptions, DeliveryMode, } from './types.js';
|
package/dist/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export type { AddMemberResult, AgentClientType, CanonGroupContext, CanonRuntimeDescriptor, CanonMessage, CanonConversation, CanonContact, CanonContactRequest, CanonResolveAdmissionResult, ContactAddedPayload, ContactRemovedPayload, ContactSource, AgentContext, ResolvedAdmissionState, ResolvedAdmissionTargetSummary, ResolvedTargetAdmissionPayload, CanonSelfContext, SendContextualMessageOptions, SendContextualMessageResult, SendContextualSelfContextInput, SendMessageOptions, SessionConfig, CreateConversationOptions, TurnLifecycleState, } from '@canonmsg/core';
|
|
2
|
-
import type { AddMemberResult, CanonGroupContext, CanonMessage, CanonConversation, ContactCardPayload, CanonRuntimeActionDispatch, SendMessageOptions, SendContextualSelfContextInput, SessionConfig } from '@canonmsg/core';
|
|
1
|
+
export type { AddMemberResult, AgentClientType, CanonGroupContext, CanonRuntimeDescriptor, CanonRuntimePrimitiveId, CanonMessage, CanonConversation, CanonContact, CanonContactRequest, CanonResolveAdmissionResult, ContactAddedPayload, ContactRemovedPayload, ContactSource, AgentContext, ResolvedAdmissionState, ResolvedAdmissionTargetSummary, ResolvedTargetAdmissionPayload, CanonSelfContext, SendContextualMessageOptions, SendContextualMessageResult, SendContextualSelfContextInput, SendMessageOptions, SessionConfig, CreateConversationOptions, TurnLifecycleState, } from '@canonmsg/core';
|
|
2
|
+
import type { AddMemberResult, CanonGroupContext, CanonMessage, CanonConversation, ContactCardPayload, CanonRuntimeActionDispatch, CanonRuntimePrimitiveId, SendMessageOptions, SendContextualSelfContextInput, SessionConfig } from '@canonmsg/core';
|
|
3
3
|
import type { MaterializeMediaOptions, MaterializedCanonAttachment, ReplyWithFileOptions, UploadMediaFileOptions } from './media.js';
|
|
4
4
|
export interface ProgressMessageOptions extends SendMessageOptions {
|
|
5
5
|
/**
|
|
@@ -123,6 +123,19 @@ export interface RuntimeControlHandlers {
|
|
|
123
123
|
onStopAndDrop?: RuntimeSignalHandler;
|
|
124
124
|
onNewSession?: RuntimeSignalHandler;
|
|
125
125
|
}
|
|
126
|
+
export interface RuntimePrimitiveContext {
|
|
127
|
+
conversationId: string;
|
|
128
|
+
primitive: CanonRuntimePrimitiveId;
|
|
129
|
+
args: Record<string, string | boolean>;
|
|
130
|
+
rawText?: string;
|
|
131
|
+
alias?: string;
|
|
132
|
+
requestId?: string;
|
|
133
|
+
updatedAt?: number;
|
|
134
|
+
}
|
|
135
|
+
export type RuntimePrimitiveHandler = (context: RuntimePrimitiveContext) => void | Promise<void>;
|
|
136
|
+
export type RuntimePrimitiveHandlers = Partial<Record<CanonRuntimePrimitiveId, RuntimePrimitiveHandler>> & {
|
|
137
|
+
'*'?: RuntimePrimitiveHandler;
|
|
138
|
+
};
|
|
126
139
|
export interface CanonAgentOptions {
|
|
127
140
|
apiKey: string;
|
|
128
141
|
baseUrl?: string;
|
|
@@ -141,6 +154,8 @@ export interface CanonAgentOptions {
|
|
|
141
154
|
runtimeDescriptor?: import('@canonmsg/core').CanonRuntimeDescriptor;
|
|
142
155
|
/** Optional Canon runtime signal handlers. Enables interrupt controls when provided. */
|
|
143
156
|
runtimeControls?: RuntimeControlHandlers;
|
|
157
|
+
/** Optional typed runtime primitive handlers. Enables descriptor-backed command controls when provided. */
|
|
158
|
+
runtimePrimitives?: RuntimePrimitiveHandlers;
|
|
144
159
|
/**
|
|
145
160
|
* Enable RTDB session-state reporting. Off by default.
|
|
146
161
|
* Turn-state reporting is automatic while handlers run.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@canonmsg/agent-sdk",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.1",
|
|
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": "^0.17.
|
|
31
|
+
"@canonmsg/core": "^0.17.2"
|
|
32
32
|
},
|
|
33
33
|
"publishConfig": {
|
|
34
34
|
"access": "public"
|