@canonmsg/agent-tools 0.3.4 → 0.4.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/README.md +2 -2
- package/dist/verb-mcp.d.ts +10 -2
- package/dist/verb-mcp.js +15 -1
- package/dist/verb-tools.js +15 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Model-facing tool definitions for the canonical Canon verbs, plus the dispatch that executes them.
|
|
4
4
|
|
|
5
|
-
This is the public tool surface of Canon's verb layer. All
|
|
5
|
+
This is the public tool surface of Canon's verb layer. All seventeen `canon.verbs.v1` verbs — `send_to`, `request_input`, `request_approval`, `check_approval`, `send_card`, `request_card`, `share_contact`, `react`, `forward`, `create_group`, `add_member`, `remove_member`, `leave_conversation`, `list_contacts`, `list_contact_requests`, `list_conversations`, `no_reply` — are projected here as JSON-Schema tool definitions and dispatched over one endpoint: `POST /agent/verbs/:verb`.
|
|
6
6
|
|
|
7
7
|
Use it if you are binding Canon into an LLM runtime that speaks tools (an MCP server, or an in-process tool mount). If you are writing an agent, use [`@canonmsg/agent-sdk`](https://www.npmjs.com/package/@canonmsg/agent-sdk) instead — it wraps this layer for you.
|
|
8
8
|
|
|
@@ -34,7 +34,7 @@ const result = await executeCanonVerbTool(client, 'send_to', {
|
|
|
34
34
|
|
|
35
35
|
A bare `CanonClient` targets production; pass a base URL from `resolveCanonRuntimeConnection({ environmentId: 'canon-dev-v1' })` to point at dev.
|
|
36
36
|
|
|
37
|
-
For an MCP mount, `createCanonVerbMcpServer(getClient, getContext?)` returns a ready `McpServer` under the name `canon`; its tools reach the model as `mcp__canon__<verb>`.
|
|
37
|
+
For an MCP mount, `createCanonVerbMcpServer(getClient, getContext?, onVerbCall?)` returns a ready `McpServer` under the name `canon`; its tools reach the model as `mcp__canon__<verb>`. `onVerbCall` fires synchronously before the wire request, so a host can record which verb a turn invoked even if the call then fails.
|
|
38
38
|
|
|
39
39
|
## Notes
|
|
40
40
|
|
package/dist/verb-mcp.d.ts
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* Detached approvals still return pending immediately.
|
|
20
20
|
*/
|
|
21
21
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
22
|
-
import type { CanonClient } from '@canonmsg/core';
|
|
22
|
+
import type { CanonClient, CanonVerbName } from '@canonmsg/core';
|
|
23
23
|
import { type VerbExecutionContext } from './verb-tools.js';
|
|
24
24
|
/** MCP server name — verbs appear to the model as `mcp__canon__<verb>`. */
|
|
25
25
|
export declare const CANON_VERB_MCP_SERVER_NAME = "canon";
|
|
@@ -29,4 +29,12 @@ export declare function createCanonVerbMcpServer(getClient: () => CanonClient |
|
|
|
29
29
|
* active conversation, current turn, turn responder). Read at call time —
|
|
30
30
|
* the session object outlives any single turn.
|
|
31
31
|
*/
|
|
32
|
-
getContext?: () => VerbExecutionContext | undefined
|
|
32
|
+
getContext?: () => VerbExecutionContext | undefined,
|
|
33
|
+
/**
|
|
34
|
+
* Observation seam: the only place a host learns that a verb tool actually
|
|
35
|
+
* executed (canUseTool fires before dispatch and can still be denied). It
|
|
36
|
+
* runs BEFORE the POST on purpose — a host flag set here survives an
|
|
37
|
+
* un-deployed server, so `no_reply` degrades to "silent turn, error shown to
|
|
38
|
+
* the model" rather than "silence never happens".
|
|
39
|
+
*/
|
|
40
|
+
onVerbCall?: (verb: CanonVerbName, args: Record<string, unknown>, context: VerbExecutionContext | undefined) => void): McpServer;
|
package/dist/verb-mcp.js
CHANGED
|
@@ -29,7 +29,15 @@ export function createCanonVerbMcpServer(getClient,
|
|
|
29
29
|
* active conversation, current turn, turn responder). Read at call time —
|
|
30
30
|
* the session object outlives any single turn.
|
|
31
31
|
*/
|
|
32
|
-
getContext
|
|
32
|
+
getContext,
|
|
33
|
+
/**
|
|
34
|
+
* Observation seam: the only place a host learns that a verb tool actually
|
|
35
|
+
* executed (canUseTool fires before dispatch and can still be denied). It
|
|
36
|
+
* runs BEFORE the POST on purpose — a host flag set here survives an
|
|
37
|
+
* un-deployed server, so `no_reply` degrades to "silent turn, error shown to
|
|
38
|
+
* the model" rather than "silence never happens".
|
|
39
|
+
*/
|
|
40
|
+
onVerbCall) {
|
|
33
41
|
// The Agent SDK's mcpServers option expects the high-level McpServer class,
|
|
34
42
|
// but its registerTool API wants Zod shapes — so the contract's JSON-Schema
|
|
35
43
|
// projections are installed directly on the underlying protocol server
|
|
@@ -66,6 +74,12 @@ getContext) {
|
|
|
66
74
|
: {};
|
|
67
75
|
const verbArgs = name === 'send_to' ? stampSendToTurnComplete(rawArgs) : rawArgs;
|
|
68
76
|
const context = getContext?.();
|
|
77
|
+
try {
|
|
78
|
+
onVerbCall?.(name, verbArgs, context);
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
// A host bookkeeping bug must never break tool dispatch.
|
|
82
|
+
}
|
|
69
83
|
const result = await executeCanonVerbTool(client, name, verbArgs, {
|
|
70
84
|
waitForResult: true,
|
|
71
85
|
signal: extra?.signal,
|
package/dist/verb-tools.js
CHANGED
|
@@ -53,6 +53,10 @@ const CANON_VERB_TOOL_DESCRIPTIONS = {
|
|
|
53
53
|
list_contacts: 'List your Canon contacts.',
|
|
54
54
|
list_contact_requests: 'List pending inbound contact requests (read-only awareness).',
|
|
55
55
|
list_conversations: 'List your Canon conversations (optionally limited).',
|
|
56
|
+
no_reply: 'End your turn without posting anything to the conversation. Use it in '
|
|
57
|
+
+ 'groups when you have nothing to add — no message is created, so no '
|
|
58
|
+
+ 'other member or agent is triggered. Optional private reason (logged, '
|
|
59
|
+
+ 'never shown). After calling this, produce no further text.',
|
|
56
60
|
};
|
|
57
61
|
/**
|
|
58
62
|
* Posture-specific completion sentences for the blocking interactive verbs.
|
|
@@ -167,6 +171,17 @@ const DEFAULT_INTERACTION_TIMEOUT_MS = 5 * 60 * 1000;
|
|
|
167
171
|
* without a conversation.
|
|
168
172
|
*/
|
|
169
173
|
export function normalizeVerbToolArgs(verb, args, context, now = Date.now()) {
|
|
174
|
+
if (verb === 'no_reply') {
|
|
175
|
+
// Silence carries a conversation for the server's audit line only, so it
|
|
176
|
+
// defaults like an interaction verb but never FAILS without one — a turn
|
|
177
|
+
// can decline to reply from a binding that has no active conversation.
|
|
178
|
+
if (typeof args.conversationId === 'string' && args.conversationId)
|
|
179
|
+
return { args };
|
|
180
|
+
if (typeof context?.conversationId === 'string' && context.conversationId) {
|
|
181
|
+
return { args: { ...args, conversationId: context.conversationId } };
|
|
182
|
+
}
|
|
183
|
+
return { args };
|
|
184
|
+
}
|
|
170
185
|
if (!INTERACTION_VERBS.has(verb))
|
|
171
186
|
return { args };
|
|
172
187
|
const completed = { ...args };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@canonmsg/agent-tools",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Canonical Canon verb tools — shared projections of canon.verbs.v1 for runtime bindings",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
"access": "public"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@canonmsg/core": "^
|
|
44
|
-
"@canonmsg/rich-cards": "^0.9.
|
|
43
|
+
"@canonmsg/core": "^10.0.0",
|
|
44
|
+
"@canonmsg/rich-cards": "^0.9.1",
|
|
45
45
|
"@modelcontextprotocol/sdk": "^1.29.0"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|