@canonmsg/agent-sdk 2.0.0 → 2.1.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 +209 -1
- package/dist/runtime-card.d.ts +29 -0
- package/dist/runtime-card.js +22 -0
- package/dist/types.d.ts +31 -2
- package/package.json +2 -2
package/dist/canon-agent.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { ApprovalManager, CanonClient, buildCanonGroupContext, createTurnOutputController, createRuntimeStatePublisher, diffCanonMemberIds, FINAL_MESSAGE_HANDOFF_MS, RUNTIME_NEW_SESSION_ACTION, RUNTIME_STOP_ACTION, RUNTIME_STOP_AND_DROP_ACTION, buildRuntimeInputOutcome, initRTDBAuth, rtdbRead, rtdbWrite, normalizeTurnMetadata, reachOutToCanonContact, resolveCanonReplyContext, resolveMessageActiveSelfContextId, resolveRuntimeProvenance, selectActiveSelfContexts, } from '@canonmsg/core';
|
|
1
|
+
import { ApprovalManager, CanonClient, buildCanonGroupContext, createTurnOutputController, createRuntimeStatePublisher, diffCanonMemberIds, FINAL_MESSAGE_HANDOFF_MS, RUNTIME_NEW_SESSION_ACTION, RUNTIME_STOP_ACTION, RUNTIME_STOP_AND_DROP_ACTION, buildRuntimeCardOutcome, buildRuntimeInputOutcome, initRTDBAuth, rtdbRead, rtdbWrite, normalizeTurnMetadata, reachOutToCanonContact, resolveCanonReplyContext, resolveMessageActiveSelfContextId, resolveRuntimeProvenance, selectActiveSelfContexts, } from '@canonmsg/core';
|
|
2
2
|
import { randomUUID } from 'node:crypto';
|
|
3
3
|
import { AuthManager } from './auth.js';
|
|
4
4
|
import { Debouncer } from './debouncer.js';
|
|
5
|
+
import { buildRuntimeCardCreateArgs } from './runtime-card.js';
|
|
5
6
|
import { materializeMessageMedia, materializeReplyContextMedia, sendMediaFileMessage, uploadMediaFile, } from './media.js';
|
|
6
7
|
import { SessionManager } from './session-manager.js';
|
|
7
8
|
const AGENT_RUNTIME_HEARTBEAT_MS = 30_000;
|
|
@@ -23,6 +24,17 @@ const DEFAULT_SDK_RUNTIME_DESCRIPTOR = {
|
|
|
23
24
|
runtimeControls: [],
|
|
24
25
|
supportsInterrupt: false,
|
|
25
26
|
streamingTextMode: 'snapshot',
|
|
27
|
+
runtimeCards: {
|
|
28
|
+
rich: {
|
|
29
|
+
schema: 'canon.card.v1',
|
|
30
|
+
lifecycle: 'blocking_requires_action',
|
|
31
|
+
responder: 'agent_owner',
|
|
32
|
+
result: 'action_or_values',
|
|
33
|
+
maxTimeoutMs: 30 * 60_000,
|
|
34
|
+
blockKinds: ['summary', 'metricGrid', 'chart', 'table', 'list', 'callout', 'actions'],
|
|
35
|
+
native: true,
|
|
36
|
+
},
|
|
37
|
+
},
|
|
26
38
|
};
|
|
27
39
|
const STANDARD_PRIMITIVE_COMMANDS = {
|
|
28
40
|
'runtime.status': {
|
|
@@ -146,6 +158,13 @@ function safeRuntimeInputId(value, kind) {
|
|
|
146
158
|
? normalized
|
|
147
159
|
: `${kind}_${randomUUID()}`;
|
|
148
160
|
}
|
|
161
|
+
function safeRuntimeCardId(value) {
|
|
162
|
+
const raw = value?.trim() || `card_${randomUUID()}`;
|
|
163
|
+
const normalized = raw.replace(/[.#$\[\]\/\s]+/g, '_').slice(0, 80);
|
|
164
|
+
return RUNTIME_INPUT_ID_PATTERN.test(normalized)
|
|
165
|
+
? normalized
|
|
166
|
+
: `card_${randomUUID()}`;
|
|
167
|
+
}
|
|
149
168
|
function isRuntimePrimitiveId(value) {
|
|
150
169
|
return value === 'runtime.status'
|
|
151
170
|
|| value === 'runtime.reasoning.set'
|
|
@@ -1512,6 +1531,193 @@ export class CanonAgent {
|
|
|
1512
1531
|
if (abortController.signal.aborted || isAbortLikeError(error)) {
|
|
1513
1532
|
throw error;
|
|
1514
1533
|
}
|
|
1534
|
+
if (!requestCreated) {
|
|
1535
|
+
throw error;
|
|
1536
|
+
}
|
|
1537
|
+
shouldPersistTurnState = false;
|
|
1538
|
+
return result;
|
|
1539
|
+
}
|
|
1540
|
+
};
|
|
1541
|
+
const sendCard = async (request) => {
|
|
1542
|
+
throwIfAborted();
|
|
1543
|
+
const cardId = safeRuntimeCardId(request.cardId ?? request.card.cardId);
|
|
1544
|
+
const explicitExpiresAt = request.expiresAt instanceof Date
|
|
1545
|
+
? request.expiresAt.getTime()
|
|
1546
|
+
: typeof request.expiresAt === 'number'
|
|
1547
|
+
? request.expiresAt
|
|
1548
|
+
: typeof request.expiresAt === 'string'
|
|
1549
|
+
? Date.parse(request.expiresAt)
|
|
1550
|
+
: null;
|
|
1551
|
+
const timeoutMs = Math.max(1_000, request.timeoutMs ?? DEFAULT_RUNTIME_INPUT_TIMEOUT_MS);
|
|
1552
|
+
const expiresAtMs = explicitExpiresAt && Number.isFinite(explicitExpiresAt)
|
|
1553
|
+
? explicitExpiresAt
|
|
1554
|
+
: Date.now() + timeoutMs;
|
|
1555
|
+
// Fire-and-forget: post the durable card and return. The backend treats an
|
|
1556
|
+
// action-less card as display (no pending state, no response expected).
|
|
1557
|
+
await this.apiClient.createRuntimeCardRequest(buildRuntimeCardCreateArgs({ request, conversationId, cardId, fallbackTurnId: turnId, expiresAtMs }));
|
|
1558
|
+
try {
|
|
1559
|
+
await turnOutput.addBlock({
|
|
1560
|
+
id: `card:${cardId}`,
|
|
1561
|
+
kind: 'status',
|
|
1562
|
+
status: 'completed',
|
|
1563
|
+
title: request.card.title,
|
|
1564
|
+
summary: request.card.template ?? 'runtime card',
|
|
1565
|
+
});
|
|
1566
|
+
}
|
|
1567
|
+
catch { }
|
|
1568
|
+
return { status: 'displayed', cardId };
|
|
1569
|
+
};
|
|
1570
|
+
const requestCard = async (request) => {
|
|
1571
|
+
throwIfAborted();
|
|
1572
|
+
// Action-less cards are fire-and-forget display/report cards — never block.
|
|
1573
|
+
const hasActions = Array.isArray(request.card.blocks)
|
|
1574
|
+
&& request.card.blocks.some((block) => block.kind === 'actions');
|
|
1575
|
+
if (!hasActions)
|
|
1576
|
+
return sendCard(request);
|
|
1577
|
+
const cardId = safeRuntimeCardId(request.cardId ?? request.card.cardId);
|
|
1578
|
+
const explicitExpiresAt = request.expiresAt instanceof Date
|
|
1579
|
+
? request.expiresAt.getTime()
|
|
1580
|
+
: typeof request.expiresAt === 'number'
|
|
1581
|
+
? request.expiresAt
|
|
1582
|
+
: typeof request.expiresAt === 'string'
|
|
1583
|
+
? Date.parse(request.expiresAt)
|
|
1584
|
+
: null;
|
|
1585
|
+
const timeoutMs = Math.max(1_000, request.timeoutMs ?? DEFAULT_RUNTIME_INPUT_TIMEOUT_MS);
|
|
1586
|
+
const expiresAtMs = explicitExpiresAt && Number.isFinite(explicitExpiresAt)
|
|
1587
|
+
? explicitExpiresAt
|
|
1588
|
+
: Date.now() + timeoutMs;
|
|
1589
|
+
let result = { status: 'timeout', cardId };
|
|
1590
|
+
let requestCreated = false;
|
|
1591
|
+
let requestResolved = false;
|
|
1592
|
+
const cancelPendingRequest = async () => {
|
|
1593
|
+
if (!requestCreated || requestResolved)
|
|
1594
|
+
return;
|
|
1595
|
+
try {
|
|
1596
|
+
await this.apiClient.consumeRuntimeCardResponse({
|
|
1597
|
+
conversationId,
|
|
1598
|
+
cardId,
|
|
1599
|
+
cancel: true,
|
|
1600
|
+
});
|
|
1601
|
+
requestResolved = true;
|
|
1602
|
+
}
|
|
1603
|
+
catch { }
|
|
1604
|
+
};
|
|
1605
|
+
shouldPersistTurnState = true;
|
|
1606
|
+
try {
|
|
1607
|
+
await this.apiClient.createRuntimeCardRequest(buildRuntimeCardCreateArgs({ request, conversationId, cardId, fallbackTurnId: turnId, expiresAtMs }));
|
|
1608
|
+
requestCreated = true;
|
|
1609
|
+
try {
|
|
1610
|
+
await turnOutput.addBlock({
|
|
1611
|
+
id: `card:${cardId}`,
|
|
1612
|
+
kind: 'input',
|
|
1613
|
+
status: 'pending',
|
|
1614
|
+
title: request.card.title,
|
|
1615
|
+
summary: request.card.template ?? 'runtime card',
|
|
1616
|
+
});
|
|
1617
|
+
await turnOutput.waitingInput();
|
|
1618
|
+
}
|
|
1619
|
+
catch { }
|
|
1620
|
+
await writeTurn('waiting_input');
|
|
1621
|
+
try {
|
|
1622
|
+
await this.apiClient.setTyping(conversationId, false);
|
|
1623
|
+
}
|
|
1624
|
+
catch { }
|
|
1625
|
+
while (Date.now() < expiresAtMs) {
|
|
1626
|
+
throwIfAborted();
|
|
1627
|
+
try {
|
|
1628
|
+
const response = await this.apiClient.consumeRuntimeCardResponse({
|
|
1629
|
+
conversationId,
|
|
1630
|
+
cardId,
|
|
1631
|
+
});
|
|
1632
|
+
if (response.status === 'submitted') {
|
|
1633
|
+
requestResolved = true;
|
|
1634
|
+
result = {
|
|
1635
|
+
status: 'submitted',
|
|
1636
|
+
cardId,
|
|
1637
|
+
...(response.actionId ? { actionId: response.actionId } : {}),
|
|
1638
|
+
...(response.values ? { values: response.values } : {}),
|
|
1639
|
+
};
|
|
1640
|
+
break;
|
|
1641
|
+
}
|
|
1642
|
+
if (response.status === 'cancelled' || response.status === 'timeout') {
|
|
1643
|
+
requestResolved = true;
|
|
1644
|
+
result = { status: response.status, cardId };
|
|
1645
|
+
break;
|
|
1646
|
+
}
|
|
1647
|
+
}
|
|
1648
|
+
catch {
|
|
1649
|
+
// Keep waiting; the control path is the authoritative source and
|
|
1650
|
+
// transient consume failures should not leak response values.
|
|
1651
|
+
}
|
|
1652
|
+
await sleepWithAbort(Math.min(RUNTIME_INPUT_POLL_MS, Math.max(1, expiresAtMs - Date.now())), abortController.signal);
|
|
1653
|
+
}
|
|
1654
|
+
if (!requestResolved) {
|
|
1655
|
+
try {
|
|
1656
|
+
const response = await this.apiClient.consumeRuntimeCardResponse({
|
|
1657
|
+
conversationId,
|
|
1658
|
+
cardId,
|
|
1659
|
+
});
|
|
1660
|
+
if (response.status === 'submitted') {
|
|
1661
|
+
result = {
|
|
1662
|
+
status: 'submitted',
|
|
1663
|
+
cardId,
|
|
1664
|
+
...(response.actionId ? { actionId: response.actionId } : {}),
|
|
1665
|
+
...(response.values ? { values: response.values } : {}),
|
|
1666
|
+
};
|
|
1667
|
+
}
|
|
1668
|
+
else if (response.status === 'cancelled' || response.status === 'timeout') {
|
|
1669
|
+
result = { status: response.status, cardId };
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1672
|
+
catch { }
|
|
1673
|
+
requestResolved = true;
|
|
1674
|
+
}
|
|
1675
|
+
// The interactive path never yields 'displayed' (that returns early via
|
|
1676
|
+
// sendCard); narrow for buildRuntimeCardOutcome's resolution status.
|
|
1677
|
+
const resolutionStatus = result.status === 'displayed' ? 'timeout' : result.status;
|
|
1678
|
+
const outcome = buildRuntimeCardOutcome(cardId, resolutionStatus, {
|
|
1679
|
+
reason: resolutionStatus,
|
|
1680
|
+
});
|
|
1681
|
+
await this.apiClient.sendMessage(conversationId, outcome.text, {
|
|
1682
|
+
metadata: {
|
|
1683
|
+
...outcome.metadata,
|
|
1684
|
+
turnId: request.turnId ?? turnId,
|
|
1685
|
+
turnSemantics: 'control',
|
|
1686
|
+
replyBehavior: 'suppress_auto_reply',
|
|
1687
|
+
},
|
|
1688
|
+
});
|
|
1689
|
+
throwIfAborted();
|
|
1690
|
+
shouldPersistTurnState = false;
|
|
1691
|
+
try {
|
|
1692
|
+
await turnOutput.completeBlock(`card:${cardId}`, {
|
|
1693
|
+
summary: `Card ${result.status}`,
|
|
1694
|
+
});
|
|
1695
|
+
}
|
|
1696
|
+
catch { }
|
|
1697
|
+
try {
|
|
1698
|
+
await this.apiClient.setTyping(conversationId, true, 'thinking');
|
|
1699
|
+
}
|
|
1700
|
+
catch { }
|
|
1701
|
+
await setLiveState('thinking', 'Thinking...', 'thinking');
|
|
1702
|
+
return result;
|
|
1703
|
+
}
|
|
1704
|
+
catch (error) {
|
|
1705
|
+
const shouldSendInterruptedOutcome = requestCreated && !requestResolved;
|
|
1706
|
+
await cancelPendingRequest();
|
|
1707
|
+
if (abortController.signal.aborted || isAbortLikeError(error)) {
|
|
1708
|
+
if (shouldSendInterruptedOutcome) {
|
|
1709
|
+
const outcome = buildRuntimeCardOutcome(cardId, 'cancelled', { reason: 'interrupted' });
|
|
1710
|
+
await this.apiClient.sendMessage(conversationId, outcome.text, {
|
|
1711
|
+
metadata: {
|
|
1712
|
+
...outcome.metadata,
|
|
1713
|
+
turnId: request.turnId ?? turnId,
|
|
1714
|
+
turnSemantics: 'control',
|
|
1715
|
+
replyBehavior: 'suppress_auto_reply',
|
|
1716
|
+
},
|
|
1717
|
+
}).catch(() => { });
|
|
1718
|
+
}
|
|
1719
|
+
throw error;
|
|
1720
|
+
}
|
|
1515
1721
|
shouldPersistTurnState = false;
|
|
1516
1722
|
return result;
|
|
1517
1723
|
}
|
|
@@ -1580,6 +1786,8 @@ export class CanonAgent {
|
|
|
1580
1786
|
provenance,
|
|
1581
1787
|
requestApproval,
|
|
1582
1788
|
requestRuntimeInput,
|
|
1789
|
+
requestCard,
|
|
1790
|
+
sendCard,
|
|
1583
1791
|
abortSignal: abortController.signal,
|
|
1584
1792
|
media: {
|
|
1585
1793
|
materialize: (message = hydratedMessages[hydratedMessages.length - 1], options) => {
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { RuntimeCardNativeMetadata, RuntimeCardV1 } from '@canonmsg/core';
|
|
2
|
+
import type { RuntimeCardRequest } from './types';
|
|
3
|
+
/** Arguments passed to `CanonClient.createRuntimeCardRequest`. */
|
|
4
|
+
export interface RuntimeCardCreateArgs {
|
|
5
|
+
conversationId: string;
|
|
6
|
+
card: RuntimeCardV1;
|
|
7
|
+
cardId: string;
|
|
8
|
+
expiresAt: number;
|
|
9
|
+
responseUserId?: string;
|
|
10
|
+
runtimeId?: string;
|
|
11
|
+
turnId?: string;
|
|
12
|
+
native?: RuntimeCardNativeMetadata;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Build the `createRuntimeCardRequest` payload shared by `sendCard` (display)
|
|
16
|
+
* and `requestCard` (interactive).
|
|
17
|
+
*
|
|
18
|
+
* `responseUserId` is OMITTED unless the developer supplied one, so the Canon
|
|
19
|
+
* backend infers a reachable responder (the owner when they are a conversation
|
|
20
|
+
* member, otherwise the sole other member). Pre-filling the owner here would
|
|
21
|
+
* break agent-to-user DMs where the owner is not a member of the conversation.
|
|
22
|
+
*/
|
|
23
|
+
export declare function buildRuntimeCardCreateArgs(input: {
|
|
24
|
+
request: RuntimeCardRequest;
|
|
25
|
+
conversationId: string;
|
|
26
|
+
cardId: string;
|
|
27
|
+
fallbackTurnId?: string;
|
|
28
|
+
expiresAtMs: number;
|
|
29
|
+
}): RuntimeCardCreateArgs;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build the `createRuntimeCardRequest` payload shared by `sendCard` (display)
|
|
3
|
+
* and `requestCard` (interactive).
|
|
4
|
+
*
|
|
5
|
+
* `responseUserId` is OMITTED unless the developer supplied one, so the Canon
|
|
6
|
+
* backend infers a reachable responder (the owner when they are a conversation
|
|
7
|
+
* member, otherwise the sole other member). Pre-filling the owner here would
|
|
8
|
+
* break agent-to-user DMs where the owner is not a member of the conversation.
|
|
9
|
+
*/
|
|
10
|
+
export function buildRuntimeCardCreateArgs(input) {
|
|
11
|
+
const { request, conversationId, cardId, fallbackTurnId, expiresAtMs } = input;
|
|
12
|
+
return {
|
|
13
|
+
conversationId,
|
|
14
|
+
cardId,
|
|
15
|
+
card: { ...request.card, cardId },
|
|
16
|
+
expiresAt: expiresAtMs,
|
|
17
|
+
...(request.responseUserId ? { responseUserId: request.responseUserId } : {}),
|
|
18
|
+
...(request.runtimeId ? { runtimeId: request.runtimeId } : {}),
|
|
19
|
+
turnId: request.turnId ?? fallbackTurnId,
|
|
20
|
+
...(request.native ? { native: request.native } : {}),
|
|
21
|
+
};
|
|
22
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export type { AddMemberResult, AgentClientType, CanonGroupContext, CanonRuntimeActivityItem, CanonRuntimeActivityKind, CanonRuntimeActivityStatus, CanonRuntimeDescriptor, CanonRuntimeFact, CanonRuntimeFactGroup, CanonRuntimePrimitiveId, CanonRuntimeProvenance, CanonMessage, CanonConversation, CanonReplyContext, CanonContact, CanonContactRequest, CanonResolveAdmissionResult, ContactAddedPayload, ContactRemovedPayload, ContactSource, AgentContext, ResolvedAdmissionState, ResolvedAdmissionTargetSummary, ResolvedTargetAdmissionPayload, CanonSelfContext, SendContextualMessageOptions, SendContextualMessageResult, SendContextualSelfContextInput, SendMessageOptions, SessionConfig, CreateConversationOptions, TurnLifecycleState, TurnOutputBlock, TurnOutputBlockInput, ApprovalNativeRequestMetadata, ApprovalRequestCategory, ApprovalRequestDetail, ApprovalRequestMetadata, ApprovalRisk, ApprovalReplyMetadata, ApprovalOutcomeMetadata, RuntimeInputChoice, RuntimeInputAnswers, RuntimeInputKind, RuntimeInputNativeMetadata, RuntimeInputQuestion, SessionRule, ApprovalResult, } from '@canonmsg/core';
|
|
2
|
-
import type { AddMemberResult, CanonGroupContext, CanonMessage, CanonConversation, CanonReplyContext, ContactCardPayload, CanonRuntimeActionDispatch, CanonRuntimePrimitiveId, CanonRuntimeProvenance, ApprovalNativeRequestMetadata, ApprovalRequestCategory, ApprovalRequestDetail, ApprovalResult, ApprovalRisk, RuntimeInputChoice, RuntimeInputAnswers, RuntimeInputKind, RuntimeInputNativeMetadata, RuntimeInputQuestion, SendMessageOptions, SendContextualSelfContextInput, SessionConfig, TurnOutputBlock, TurnOutputBlockInput } from '@canonmsg/core';
|
|
1
|
+
export type { AddMemberResult, AgentClientType, CanonGroupContext, CanonRuntimeActivityItem, CanonRuntimeActivityKind, CanonRuntimeActivityStatus, CanonRuntimeDescriptor, CanonRuntimeFact, CanonRuntimeFactGroup, CanonRuntimePrimitiveId, CanonRuntimeProvenance, CanonMessage, CanonConversation, CanonReplyContext, CanonContact, CanonContactRequest, CanonResolveAdmissionResult, ContactAddedPayload, ContactRemovedPayload, ContactSource, AgentContext, ResolvedAdmissionState, ResolvedAdmissionTargetSummary, ResolvedTargetAdmissionPayload, CanonSelfContext, SendContextualMessageOptions, SendContextualMessageResult, SendContextualSelfContextInput, SendMessageOptions, SessionConfig, CreateConversationOptions, TurnLifecycleState, TurnOutputBlock, TurnOutputBlockInput, ApprovalNativeRequestMetadata, ApprovalRequestCategory, ApprovalRequestDetail, ApprovalRequestMetadata, ApprovalRisk, ApprovalReplyMetadata, ApprovalOutcomeMetadata, RuntimeInputChoice, RuntimeInputAnswers, RuntimeInputKind, RuntimeInputNativeMetadata, RuntimeInputQuestion, RuntimeCardNativeMetadata, RuntimeCardV1, SessionRule, ApprovalResult, } from '@canonmsg/core';
|
|
2
|
+
import type { AddMemberResult, CanonGroupContext, CanonMessage, CanonConversation, CanonReplyContext, ContactCardPayload, CanonRuntimeActionDispatch, CanonRuntimePrimitiveId, CanonRuntimeProvenance, ApprovalNativeRequestMetadata, ApprovalRequestCategory, ApprovalRequestDetail, ApprovalResult, ApprovalRisk, RuntimeInputChoice, RuntimeInputAnswers, RuntimeInputKind, RuntimeInputNativeMetadata, RuntimeInputQuestion, RuntimeCardNativeMetadata, RuntimeCardV1, SendMessageOptions, SendContextualSelfContextInput, SessionConfig, TurnOutputBlock, TurnOutputBlockInput } from '@canonmsg/core';
|
|
3
3
|
import type { MaterializeMediaOptions, MaterializedCanonAttachment, ReplyWithFileOptions, UploadMediaFileOptions } from './media.js';
|
|
4
4
|
export interface ProgressMessageOptions extends SendMessageOptions {
|
|
5
5
|
/**
|
|
@@ -85,6 +85,22 @@ export interface RuntimeInputResult {
|
|
|
85
85
|
answers?: RuntimeInputAnswers;
|
|
86
86
|
inputId: string;
|
|
87
87
|
}
|
|
88
|
+
export interface RuntimeCardRequest {
|
|
89
|
+
card: RuntimeCardV1;
|
|
90
|
+
cardId?: string;
|
|
91
|
+
expiresAt?: string | number | Date;
|
|
92
|
+
responseUserId?: string;
|
|
93
|
+
timeoutMs?: number;
|
|
94
|
+
runtimeId?: string;
|
|
95
|
+
turnId?: string;
|
|
96
|
+
native?: RuntimeCardNativeMetadata;
|
|
97
|
+
}
|
|
98
|
+
export interface RuntimeCardResult {
|
|
99
|
+
status: 'submitted' | 'cancelled' | 'timeout' | 'displayed';
|
|
100
|
+
cardId: string;
|
|
101
|
+
actionId?: string;
|
|
102
|
+
values?: Record<string, unknown>;
|
|
103
|
+
}
|
|
88
104
|
export interface MessageHandlerContext {
|
|
89
105
|
messages: CanonMessage[];
|
|
90
106
|
history: CanonMessage[];
|
|
@@ -144,6 +160,19 @@ export interface MessageHandlerContext {
|
|
|
144
160
|
* never persisted in Canon message metadata.
|
|
145
161
|
*/
|
|
146
162
|
requestRuntimeInput: (request: RuntimeInputRequest) => Promise<RuntimeInputResult>;
|
|
163
|
+
/**
|
|
164
|
+
* Ask the agent owner to review/respond to a generic rich card. The visible
|
|
165
|
+
* card document is redacted for presentation; raw response values return
|
|
166
|
+
* only to the calling runtime through Canon's control path.
|
|
167
|
+
*/
|
|
168
|
+
requestCard: (request: RuntimeCardRequest) => Promise<RuntimeCardResult>;
|
|
169
|
+
/**
|
|
170
|
+
* Post a fire-and-forget display/report card and return immediately with
|
|
171
|
+
* `{ status: 'displayed' }` — no waiting-input lifecycle. Use requestCard for
|
|
172
|
+
* cards that expect a response. (requestCard also auto-detects action-less
|
|
173
|
+
* cards and delegates here.)
|
|
174
|
+
*/
|
|
175
|
+
sendCard: (request: RuntimeCardRequest) => Promise<RuntimeCardResult>;
|
|
147
176
|
/** Canon-managed local media access for the current conversation. */
|
|
148
177
|
media: {
|
|
149
178
|
materialize: (message?: CanonMessage, options?: Omit<MaterializeMediaOptions, 'agentId' | 'conversationId' | 'messageId'>) => Promise<MaterializedCanonAttachment[]>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@canonmsg/agent-sdk",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.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": "^1.
|
|
31
|
+
"@canonmsg/core": "^1.2.0"
|
|
32
32
|
},
|
|
33
33
|
"publishConfig": {
|
|
34
34
|
"access": "public"
|