@canonmsg/agent-sdk 0.8.3 → 0.9.2

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 CHANGED
@@ -41,8 +41,73 @@ No additional dependencies required — the SDK uses native `fetch` and `Readabl
41
41
  | `historyLimit` | `number` | `50` | Number of historical messages to fetch (max 100) |
42
42
  | `sessions` | `SessionOptions` | `undefined` | Enable per-conversation session queues and persistent metadata |
43
43
  | `clientType` | `AgentClientType` | `'generic'` | Agent runtime label used for Canon capability detection |
44
+ | `runtimeDescriptor` | `CanonRuntimeDescriptor` | minimal generic descriptor | Optional setup/live controls and runtime capability metadata for Canon UI |
44
45
  | `sessionState` | `boolean` | `false` | Publish RTDB session-state for the conversations this agent is active in |
45
46
 
47
+ ### Optional runtime controls
48
+
49
+ Generic SDK agents publish no setup controls by default. If your SDK runtime has local workspace access, you can opt in by publishing a descriptor with explicit project choices:
50
+
51
+ ```typescript
52
+ const agent = new CanonAgent({
53
+ apiKey: process.env.CANON_API_KEY!,
54
+ runtimeDescriptor: {
55
+ coreControls: [
56
+ {
57
+ id: 'workspace',
58
+ label: 'Project',
59
+ options: [
60
+ {
61
+ value: 'workspace-canon',
62
+ label: 'canon',
63
+ description: 'dev/canon',
64
+ workspaceRootId: 'dev',
65
+ workspaceRelativePath: 'canon',
66
+ source: 'discovered',
67
+ },
68
+ {
69
+ value: 'workspace-yumyumv2',
70
+ label: 'yumyumv2',
71
+ description: 'dev/yumyumv2',
72
+ workspaceRootId: 'dev',
73
+ workspaceRelativePath: 'yumyumv2',
74
+ source: 'discovered',
75
+ },
76
+ ],
77
+ defaultValue: 'workspace-canon',
78
+ availability: 'setup',
79
+ liveBehavior: 'none',
80
+ selectionPolicy: 'inherit',
81
+ description: 'Choose one of the local projects this SDK host is configured to use.',
82
+ },
83
+ ],
84
+ runtimeControls: [],
85
+ workspaceRoots: [
86
+ { id: 'dev', label: '~/dev' },
87
+ ],
88
+ },
89
+ });
90
+ ```
91
+
92
+ The descriptor only drives Canon UI and validation. Your SDK agent is still responsible for reading session config and safely mapping selected values to local directories.
93
+
94
+ Node SDK builders can reuse `buildConfiguredWorkspaceOptionsWithRoots` from `@canonmsg/core` to produce the same stable project IDs and root metadata used by the first-party Claude Code and Codex hosts.
95
+
96
+ Current rules of thumb:
97
+
98
+ - Canon does not infer real runtime support from `clientType`; if you do not publish a descriptor, Canon should behave as a mostly status-only generic agent surface.
99
+ - `availability` controls where a setting appears:
100
+ - `setup`: session creation only
101
+ - `live`: live strip only
102
+ - `setup_and_live`: both surfaces
103
+ - `liveBehavior` controls how truthful live editing should be:
104
+ - `immediate`: Canon may show a pending state until the runtime snapshot reflects the applied value
105
+ - `next_turn`: Canon may let the user queue the change, but should label it as applying on the next turn
106
+ - `none`: Canon never exposes it as live-editable
107
+ - `selectionPolicy: 'required_explicit'` means Canon should require the user to make a choice instead of silently inheriting a default
108
+ - `workspaceRoots` and `writableRoots` document allowed roots and let Canon group project choices. Canon still stores the selected concrete `workspaceId`; it does not send arbitrary root-relative paths to generic SDK agents.
109
+ - Publishing a descriptor does not automatically make your SDK agent enforce those controls. If you advertise model, workspace, execution mode, or runtime-native controls, your runtime must actually read and apply the stored config.
110
+
46
111
  ## Delivery Modes
47
112
 
48
113
  The SDK supports three delivery modes for receiving messages:
@@ -10,9 +10,15 @@ const SDK_RUNTIME_CAPABILITIES = {
10
10
  supportsInterrupt: false,
11
11
  supportsQueue: true,
12
12
  supportsInterleave: false,
13
- supportsRequiresAction: false,
13
+ supportsRequiresAction: true,
14
14
  supportsNonFinalPermanentMessages: false,
15
15
  };
16
+ const DEFAULT_SDK_RUNTIME_DESCRIPTOR = {
17
+ coreControls: [],
18
+ runtimeControls: [],
19
+ supportsInterrupt: false,
20
+ streamingTextMode: 'snapshot',
21
+ };
16
22
  function sleep(ms) {
17
23
  return new Promise((resolve) => setTimeout(resolve, ms));
18
24
  }
@@ -201,6 +207,7 @@ export class CanonAgent {
201
207
  await rtdbWrite(`/agent-runtime/${this.agentId}`, {
202
208
  clientType: this.options.clientType ?? 'generic',
203
209
  hostMode: false,
210
+ runtimeDescriptor: this.options.runtimeDescriptor ?? DEFAULT_SDK_RUNTIME_DESCRIPTOR,
204
211
  updatedAt: { '.sv': 'timestamp' },
205
212
  });
206
213
  }
@@ -401,7 +408,16 @@ export class CanonAgent {
401
408
  sourceConversationId: conversationId,
402
409
  targetConversationId,
403
410
  text,
404
- ...options,
411
+ ...(options ?? {}),
412
+ messageOptions: {
413
+ ...(options?.messageOptions ?? {}),
414
+ metadata: {
415
+ ...(options?.messageOptions?.metadata ?? {}),
416
+ turnId,
417
+ turnSemantics: 'turn_complete',
418
+ turnComplete: true,
419
+ },
420
+ },
405
421
  });
406
422
  };
407
423
  const uploadFile = (filePath, options) => uploadMediaFile(this.apiClient, conversationId, filePath, options);
package/dist/types.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export type { AgentClientType, CanonMessage, CanonConversation, CanonContactRequest, AgentContext, CanonResolvedWorkSession, CanonWorkSession, CanonWorkSessionContext, CanonWorkSessionConversationRole, CanonWorkSessionDisclosureMode, CanonWorkSessionParticipant, CanonWorkSessionStatus, CreateWorkSessionOptions, SendLinkedMessageOptions, SendLinkedMessageResult, SendMessageOptions, CreateConversationOptions, TurnLifecycleState, UpdateWorkSessionConversationOptions, } from '@canonmsg/core';
1
+ export type { AgentClientType, CanonRuntimeDescriptor, CanonMessage, CanonConversation, CanonContactRequest, AgentContext, CanonResolvedWorkSession, CanonWorkSession, CanonWorkSessionContext, CanonWorkSessionConversationRole, CanonWorkSessionDisclosureMode, CanonWorkSessionParticipant, CanonWorkSessionStatus, CreateWorkSessionOptions, SendLinkedMessageOptions, SendLinkedMessageResult, SendMessageOptions, CreateConversationOptions, TurnLifecycleState, UpdateWorkSessionConversationOptions, } from '@canonmsg/core';
2
2
  import type { CanonMessage, CanonConversation, CreateWorkSessionOptions, SendMessageOptions, UpdateWorkSessionConversationOptions } from '@canonmsg/core';
3
3
  import type { MaterializeMediaOptions, MaterializedCanonAttachment, ReplyWithFileOptions, UploadMediaFileOptions } from './media.js';
4
4
  export type SDKMessage = CanonMessage;
@@ -117,6 +117,8 @@ export interface CanonAgentOptions {
117
117
  sessions?: SessionOptions;
118
118
  /** Agent client type for capability detection. Defaults to 'generic'. */
119
119
  clientType?: import('@canonmsg/core').AgentClientType;
120
+ /** Optional runtime descriptor published to Canon for setup/live UI rendering. */
121
+ runtimeDescriptor?: import('@canonmsg/core').CanonRuntimeDescriptor;
120
122
  /**
121
123
  * Enable RTDB session-state reporting. Off by default.
122
124
  * 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": "0.8.3",
3
+ "version": "0.9.2",
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.7.5"
31
+ "@canonmsg/core": "^0.10.0"
32
32
  },
33
33
  "publishConfig": {
34
34
  "access": "public"