@convilyn/sdk-author 0.7.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 ADDED
@@ -0,0 +1,310 @@
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/CoreNovus/convilyn-author-js/main/docs/assets/corenovus-community-banner.png" alt="CoreNovus Community — Connected AI Workflows" />
3
+ </p>
4
+
5
+ # @convilyn/sdk-author
6
+
7
+ [![CI](https://github.com/CoreNovus/convilyn-author-js/actions/workflows/ci.yml/badge.svg)](https://github.com/CoreNovus/convilyn-author-js/actions/workflows/ci.yml)
8
+
9
+ Official Convilyn **Author SDK** for TypeScript / JavaScript — build and host
10
+ tool servers, author workflow specs, and create reusable AI workflow components
11
+ for the Convilyn AI platform. The counterpart to the consumer SDK
12
+ [`@convilyn/sdk`](https://www.npmjs.com/package/@convilyn/sdk): where the
13
+ consumer SDK *calls* Convilyn with a `ck_` key, the Author SDK lets you *extend*
14
+ the platform — authoring tools and workflows that the gateway calls back into,
15
+ secured by HMAC. The wire shapes match Convilyn's gateway and authoring APIs
16
+ exactly.
17
+
18
+ Convilyn Author helps builders turn tools, services, and repeated processes into
19
+ reusable workflow building blocks. It is part of the CoreNovus vision for
20
+ practical AI workflows across cloud services, local machines, AI PCs, edge
21
+ devices, and future IoT environments.
22
+
23
+ > **Public mirror** of Convilyn's monorepo (the source of truth). Contributions
24
+ > are welcome and land in the shipped package — see
25
+ > **[CONTRIBUTING.md](CONTRIBUTING.md)** (fork → PR → upstreamed, authorship
26
+ > preserved).
27
+
28
+ > **Status: feature-complete surface (0.x).** Ships the tool-server foundation,
29
+ > the `WorkflowSpec` builder, the `ToolServer` + JSON-RPC `/mcp` runtime, the
30
+ > `convilyn-author` CLI, confirmation-token signing, and the `ConvilynClient`
31
+ > platform client + local test harness. Only what is documented here is exported
32
+ > and covered by SemVer; while `0.x`, minor versions may still adjust the surface.
33
+
34
+ ## Install
35
+
36
+ ```bash
37
+ npm install @convilyn/sdk-author
38
+ ```
39
+
40
+ Node 18+ (uses `node:crypto`). Ships ESM + CJS + type declarations. Runtime
41
+ dependencies are minimal — `commander` (CLI) and `zod-to-json-schema` — plus
42
+ `zod` as a peer dependency.
43
+
44
+ ## Tool-server foundation
45
+
46
+ ### HMAC inbound verification
47
+
48
+ The gateway signs every call it makes to your tool server; verify the signature
49
+ to reject forged requests (use this if you run your own HTTP framework — the
50
+ SDK's built-in runtime, `serve`, does it for you).
51
+
52
+ ```ts
53
+ import { verifySignature, InvalidSignatureError } from '@convilyn/sdk-author'
54
+
55
+ try {
56
+ // `verifySignature` reads the `x-convilyn-signature` / `-timestamp` headers.
57
+ verifySignature(
58
+ process.env.CONVILYN_HMAC_SECRET!,
59
+ rawBodyBytes,
60
+ req.headers as Record<string, string | undefined>,
61
+ )
62
+ // ...handle the verified request
63
+ } catch (err) {
64
+ if (err instanceof InvalidSignatureError) {
65
+ // err.reason ∈ missing_secret | missing_header | invalid_timestamp |
66
+ // timestamp_out_of_range | signature_mismatch
67
+ res.writeHead(401).end()
68
+ }
69
+ }
70
+ ```
71
+
72
+ `signRequest(secret, body, unixSeconds)` produces the matching
73
+ `{ signature, timestamp }` pair — for tests, or for calling a developer-hosted
74
+ server directly.
75
+
76
+ ### Manifest, data store, context, config
77
+
78
+ ```ts
79
+ import { ConvilynManifest, InMemoryDataStore, ToolResult, SDKConfig } from '@convilyn/sdk-author'
80
+
81
+ const manifest = new ConvilynManifest(
82
+ { name: 'weather', version: '1.0.0', description: 'Weather tools' },
83
+ {
84
+ tools: [
85
+ {
86
+ name: 'get_weather',
87
+ description: 'Get current weather',
88
+ inputSchema: { type: 'object', properties: { location: { type: 'string' } } },
89
+ idempotent: true,
90
+ },
91
+ ],
92
+ }
93
+ )
94
+ await manifest.save('convilyn.manifest.json')
95
+
96
+ const store = new InMemoryDataStore()
97
+ const refId = await store.store({ large: 'payload' }) // → "td_<12-hex>"
98
+
99
+ const result = ToolResult.ok({ refId, summary: 'Weather for Taipei' })
100
+
101
+ const config = SDKConfig.fromEnv() // reads CONVILYN_* env vars
102
+ ```
103
+
104
+ Tools return `{ ref_id, summary }` (build with `ToolResult.ok(...)` /
105
+ `ToolResult.fail(...)`) so the agent's context stays small and fetches the full
106
+ data by `ref_id` later.
107
+
108
+ ## Workflow authoring
109
+
110
+ `WorkflowSpec` is an immutable fluent builder for a portable workflow — a
111
+ `specId` (the portal's `dev_<developer-id>.<name>` namespace), a name, a system
112
+ prompt, and a palette of `"server:tool"` references. It validates client-side
113
+ as you build (name ≤80, ≤20 tools, semver version, rejects the
114
+ `request_user_input` tool, …) and has one method per wire contract:
115
+
116
+ - `compile()` → the snake_case **`WorkflowBlueprint`** publish artifact
117
+ (`spec_id`/`version`/`public_schema_version`; cross-SDK parity with the
118
+ Python author SDK) — what `submitWorkflow` / `push` send to the portal.
119
+ - `toExportPayload()` → the camelCase user_workflows **`ExportPayload`**
120
+ (canvas/authoring contract; carries UI-only positions/notes/canvasLayout).
121
+
122
+ ```ts
123
+ import { WorkflowSpec, buildWorkflowPolicies } from '@convilyn/sdk-author'
124
+
125
+ const spec = new WorkflowSpec('Invoice summariser', { specId: 'dev_abc123.invoice_summariser' })
126
+ .withDescription('Extracts totals from invoices')
127
+ .withSystemPrompt('You summarise invoices into a totals table.')
128
+ .useTools('doc-parser-mcp:extract_text', 'doc-parser-mcp:extract_tables')
129
+ .withTags(['finance'])
130
+
131
+ await spec.save('workflow.spec.json') // portable WorkflowBlueprint JSON
132
+ const reloaded = await WorkflowSpec.load('workflow.spec.json') // loads blueprint OR ExportPayload
133
+
134
+ // Optional high-level policies (attached when publishing a workflow):
135
+ const policies = buildWorkflowPolicies({
136
+ retry: { maxAttempts: 3, retryOn: ['transient'] },
137
+ timeout: { maxStepCount: 12 },
138
+ })
139
+
140
+ // Compile the blueprint locally, then publish it through the Developer Portal:
141
+ const compiled = spec.compile() // → pass to client.submitWorkflow({ workflow_spec, server_ids })
142
+ ```
143
+
144
+ ## Tool server
145
+
146
+ `defineTool` declares a tool from a [Zod](https://zod.dev/) schema — the single
147
+ source of truth for the manifest `input_schema`, the handler's argument types,
148
+ and runtime validation of inbound calls. `ToolServer` registers tools and
149
+ `serve` runs the JSON-RPC `/mcp` runtime (`/health`, `/manifest`, and an
150
+ HMAC-verified `POST /mcp`), interchangeable with the Python / Go author SDKs
151
+ behind the same gateway. `zod` is a peerDependency — install it alongside the
152
+ SDK and `import { z } from 'zod'` yourself.
153
+
154
+ ```ts
155
+ import { defineTool, ToolServer, ToolResult, serve } from '@convilyn/sdk-author'
156
+ import { z } from 'zod'
157
+
158
+ const echo = defineTool({
159
+ name: 'echo',
160
+ description: 'Echo the input text back.',
161
+ input: z.object({ text: z.string().min(1) }),
162
+ idempotent: true,
163
+ handler: (args) => ToolResult.ok({ echoed: args.text }, `Echoed ${args.text.length} chars`),
164
+ })
165
+
166
+ const server = new ToolServer({ name: 'echo-server', version: '1.0.0', description: 'demo' })
167
+ server.register(echo)
168
+
169
+ // Run it (CONVILYN_HMAC_SECRET / CONVILYN_PORT come from the env via SDKConfig):
170
+ serve(server, { port: 8080 })
171
+ ```
172
+
173
+ ## CLI
174
+
175
+ The package ships a `convilyn-author` binary:
176
+
177
+ ```bash
178
+ npx convilyn-author init my-server # scaffold a TS project
179
+ cd my-server && npm install && npm run build
180
+ npx convilyn-author dev # run the JSON-RPC /mcp server (serve)
181
+ npx convilyn-author synth # write convilyn.manifest.json
182
+ npx convilyn-author test # local compliance checks (runComplianceChecks)
183
+ npx convilyn-author push --endpoint-url https://my-server.example.com # publish
184
+ ```
185
+
186
+ `synth` / `dev` / `test` load a **built** JS module (default `server.js`,
187
+ override with `--file dist/server.js`) that exports a `ToolServer` as its default
188
+ or a named `server` export.
189
+
190
+ `push` submits your server + workflow to the **Developer Portal** (wrapping
191
+ `ConvilynClient.submitServer` + `submitWorkflow`): set a `cvl_` key in
192
+ `CONVILYN_API_KEY`, then `push --endpoint-url <https://...>` (the HTTPS URL where
193
+ *you* host the server) with `--file` (built server, default `server.js`) and
194
+ `--workflow-file` (a `workflow.spec.json` or a built module, default
195
+ `workflow.spec.json`). The managed `deploy --hosted` provisions your server in
196
+ the **Convilyn-Hosted Author Runtime** (no infrastructure of your own):
197
+ `deploy --hosted [--region us-east-1]` hands over the manifest (plus the
198
+ compiled workflow when `workflow.spec.json` exists), then `logs <runtimeId>`
199
+ tails the runtime logs and `rollback <runtimeId>` flips back to the previous
200
+ version. Without `--hosted`, `deploy` errors and points at
201
+ `push --endpoint-url` (BYO). Both commands speak the same Developer Portal wire
202
+ contract as `ConvilynClient`.
203
+
204
+ ## Developer Portal client
205
+
206
+ `ConvilynClient` is a `fetch`-based client for the **Developer Portal**
207
+ (`/api/v1/developers/*`) — the platform's third-party author/publish surface,
208
+ mirroring the Python `convilyn-author` SDK. You **build and test your own** tool
209
+ server + workflow locally (`ToolServer`, `WorkflowSpec`, `runComplianceChecks`),
210
+ then **integrate** them by registering through the portal. Authenticate with a
211
+ `cvl_` developer key as a Bearer token (`CONVILYN_API_KEY`); the base URL is
212
+ `${CONVILYN_PLATFORM_URL}/api/v1`.
213
+
214
+ > The SDK does **not** call the first-party console surfaces (`/user_workflows/*`,
215
+ > `/mcp/tools/catalog`) — those are JWT/session endpoints owned by the web UI, not
216
+ > an author-publishing API. Validate and cost-preview your work **locally** with
217
+ > `runComplianceChecks` / `WorkflowSpec.compile` before submitting.
218
+
219
+ ```ts
220
+ import { ConvilynClient, ToolServer, WorkflowSpec } from '@convilyn/sdk-author'
221
+
222
+ // 1) Register once (no auth) → mint + capture a cvl_ key. Save it; shown once.
223
+ const client = new ConvilynClient()
224
+ const { api_key } = await client.register({ email: 'dev@example.com', name: 'Dev' })
225
+ // …or pass an existing cvl_ key: new ConvilynClient({ apiKey: myCvlKey })
226
+ // …or set it in the environment: export CONVILYN_API_KEY=cvl_your_key
227
+
228
+ // 2) Submit your own tool server for verification.
229
+ const server = await client.submitServer({
230
+ manifest: myToolServer.manifest().toWire(),
231
+ endpoint_url: 'https://my-server.example.com',
232
+ })
233
+ await client.testServer(server.server_id) // sandbox test
234
+ await client.serverStatus(server.server_id) // → verified / active / rejected
235
+
236
+ // 3) Submit your compiled workflow, referencing the server(s) it uses.
237
+ const spec = new WorkflowSpec('Invoice summariser', { specId: 'dev_abc123.invoice_summariser' })
238
+ .withSystemPrompt('…')
239
+ .useTools('my-server:extract_text')
240
+ const wf = await client.submitWorkflow({ workflow_spec: spec.compile(), server_ids: [server.server_id] })
241
+ await client.testWorkflow(wf.workflow_id)
242
+ ```
243
+
244
+ Also available: `listServers` / `deactivateServer`, `listWorkflows` /
245
+ `workflowStatus` / `deactivateWorkflow`, and the hosted-runtime surface
246
+ `deployHostedRuntime` / `rollbackHostedRuntime` / `getHostedRuntimeLogs`.
247
+ A non-2xx response throws
248
+ `ConvilynApiError` (with `.status` and `.body`); an authed call with no key throws
249
+ `ConvilynAuthorError` before any network call.
250
+
251
+ ## Confirmation tokens
252
+
253
+ For tools that require a human confirmation handshake, the SDK signs and verifies
254
+ confirmation tokens byte-for-byte compatibly with the gateway and the Python / Go
255
+ author SDKs:
256
+
257
+ ```ts
258
+ import { mintConfirmationToken, verifyConfirmationToken, CONFIRMATION_TTL_SECONDS } from '@convilyn/sdk-author'
259
+
260
+ const secret = process.env.CONVILYN_TOOL_CONFIRMATION_SECRET!
261
+ const expiresAtUnix = Math.floor(Date.now() / 1000) + CONFIRMATION_TTL_SECONDS
262
+ const token = mintConfirmationToken({ toolName: 'submit_order', arguments: args, expiresAtUnix, secret })
263
+
264
+ // On the confirming re-call, with `confirmation_token` present in arguments:
265
+ verifyConfirmationToken({ toolName: 'submit_order', arguments: argsWithToken, token, secret })
266
+ // throws ConfirmationInvalidError on a malformed / expired / mismatched token
267
+ ```
268
+
269
+ The argument digest strips volatile presigned-URL params, so a re-presigned URL
270
+ still matches the originally-confirmed arguments.
271
+
272
+ ## Local testing harness
273
+
274
+ `invokeTool` drives a `ToolServer` in-process (no HTTP), returning the same wire
275
+ envelope the gateway would receive — ideal for unit tests:
276
+
277
+ ```ts
278
+ import { invokeTool } from '@convilyn/sdk-author'
279
+
280
+ const wire = await invokeTool(server, 'echo', { text: 'hi' })
281
+ expect(wire.status).toBe('ok')
282
+ expect(wire.data).toEqual({ echoed: 'hi' })
283
+ ```
284
+
285
+ ## Authentication at a glance
286
+
287
+ | Secret (env) | Used for |
288
+ |---|---|
289
+ | `CONVILYN_API_KEY` | `cvl_` developer key — Bearer auth to the Developer Portal (`ConvilynClient`) |
290
+ | `CONVILYN_HMAC_SECRET` | Verifying inbound `POST /mcp` calls from the gateway (`serve` / `verifySignature`) |
291
+ | `CONVILYN_TOOL_CONFIRMATION_SECRET` | Minting / verifying confirmation tokens |
292
+
293
+ ## Getting a runnable starter
294
+
295
+ `npx convilyn-author init my-server` scaffolds a complete TypeScript
296
+ tool-server project (`server.ts`, build config, `.env.example`) — the fastest
297
+ way to see the tool server, manifest, and compliance checks working together.
298
+
299
+ ## Public API & Stability
300
+
301
+ This package follows [Semantic Versioning](https://semver.org/). **The SemVer
302
+ contract is exactly the set of names exported from the package root**; anything
303
+ not exported there is internal and may change in any release. The `package.json`
304
+ `exports` map blocks deep imports, and a packaging test pins the public surface.
305
+ While the package is `0.x` (pre-1.0), minor versions may still contain breaking
306
+ changes as the surface stabilises toward 1.0.
307
+
308
+ ## License
309
+
310
+ Apache-2.0 — see [LICENSE](./LICENSE).