@synapsor/client 0.1.0 → 0.1.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 +7 -8
- package/bin/synapsor.mjs +294 -0
- package/generated-contract.mjs +13 -3
- package/package.json +10 -5
- package/synapsor.mjs +48 -4
package/README.md
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
# Synapsor Node.js
|
|
1
|
+
# Synapsor Node.js SDK
|
|
2
2
|
|
|
3
|
-
The Node.js
|
|
4
|
-
|
|
3
|
+
The Synapsor Node.js SDK connects applications to hosted or local Synapsor
|
|
4
|
+
databases. Use it for SQL, branch workflows, agent contexts, capabilities,
|
|
5
|
+
evidence, memory, and safe write proposals from Node.js applications.
|
|
5
6
|
|
|
6
7
|
## Local Usage
|
|
7
8
|
|
|
@@ -35,7 +36,7 @@ await db.close();
|
|
|
35
36
|
|
|
36
37
|
## Hosted Usage
|
|
37
38
|
|
|
38
|
-
Install from npm
|
|
39
|
+
Install from npm:
|
|
39
40
|
|
|
40
41
|
```bash
|
|
41
42
|
npm install @synapsor/client
|
|
@@ -59,14 +60,12 @@ const ctx = await db.invokeAgentCapability("chat.prepare_llm_context", { questio
|
|
|
59
60
|
```
|
|
60
61
|
|
|
61
62
|
Use database-scoped API keys from the Synapsor control panel for hosted projects.
|
|
62
|
-
The cloud gateway pins those keys to the database runtime branch before forwarding
|
|
63
|
-
requests to the single-node runtime.
|
|
64
63
|
|
|
65
64
|
## API Surface
|
|
66
65
|
|
|
67
66
|
- `execute(sql)` and `query(sql)`
|
|
68
67
|
- `setSession({...})`
|
|
69
|
-
- `invokeAgentCapability(name, args)`
|
|
68
|
+
- `invokeAgentCapability(name, args, options)`
|
|
70
69
|
- `listCapabilities(query)`
|
|
71
70
|
- `rememberFact({...})`
|
|
72
71
|
- `proposeMemoryFact({...})`
|
|
@@ -77,7 +76,7 @@ requests to the single-node runtime.
|
|
|
77
76
|
- `retireFact(id, {...})` and `forgetFact(id, reason)`
|
|
78
77
|
- `checkFactForAction({...})`
|
|
79
78
|
- branch helpers: `createBranch`, `useBranch`, `diffBranch`, `mergeBranch`, `dropBranch`
|
|
80
|
-
- write lifecycle helpers: `previewWrite`, `approveWrite`, `commitWrite`, `rejectWrite`
|
|
79
|
+
- write lifecycle helpers: `previewWrite`, `approveWrite`, `commitWrite`, `rejectWrite`, `settleWrite`
|
|
81
80
|
- `readResource(uri)`
|
|
82
81
|
|
|
83
82
|
Errors from Synapsor become `SynapsorError` with `status` and `payload`.
|
package/bin/synapsor.mjs
ADDED
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { chmod, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
import { dirname, join } from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
import { createInterface } from "node:readline/promises";
|
|
8
|
+
import { stdin as input, stdout as output } from "node:process";
|
|
9
|
+
|
|
10
|
+
const PACKAGE_VERSION = "0.1.2";
|
|
11
|
+
const DEFAULT_BASE_URL = "https://synapsor.ai";
|
|
12
|
+
const ERROR_HINTS = new Map([
|
|
13
|
+
["AUTH_REQUIRED", "Set SYNAPSOR_API_KEY or run `synapsor config set api-key`."],
|
|
14
|
+
["BILLING_REQUIRED", "Builder resources require active or trialing Builder billing."],
|
|
15
|
+
["LIMIT_EXCEEDED", "You reached a controlled-beta hard limit. Upgrade or reduce usage."],
|
|
16
|
+
["FORBIDDEN", "The API key is not allowed to perform this operation."],
|
|
17
|
+
["NOT_FOUND", "Check the project, database, handle, or run id."],
|
|
18
|
+
["BETA_UNAVAILABLE", "This feature is not self-serve in the controlled beta."],
|
|
19
|
+
]);
|
|
20
|
+
|
|
21
|
+
function configPath() {
|
|
22
|
+
const override = process.env.SYNAPSOR_CLI_CONFIG_HOME;
|
|
23
|
+
return join(override || join(homedir(), ".config"), "synapsor", "config.json");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async function loadConfig(profile = "default") {
|
|
27
|
+
const path = configPath();
|
|
28
|
+
if (!existsSync(path)) return { path, profile, data: {}, current: {} };
|
|
29
|
+
const raw = JSON.parse(await readFile(path, "utf8"));
|
|
30
|
+
const profiles = raw.profiles && typeof raw.profiles === "object" ? raw.profiles : {};
|
|
31
|
+
return { path, profile, data: raw, current: profiles[profile] || {} };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function saveConfig(profile, patch) {
|
|
35
|
+
const existing = await loadConfig(profile);
|
|
36
|
+
const data = existing.data.profiles ? existing.data : { profiles: {} };
|
|
37
|
+
data.profiles[profile] = { ...(data.profiles[profile] || {}), ...patch };
|
|
38
|
+
const path = configPath();
|
|
39
|
+
await mkdir(dirname(path), { recursive: true });
|
|
40
|
+
await writeFile(path, JSON.stringify(data, null, 2) + "\n", { mode: 0o600 });
|
|
41
|
+
try {
|
|
42
|
+
await chmod(path, 0o600);
|
|
43
|
+
} catch {
|
|
44
|
+
// Best effort on platforms without POSIX modes.
|
|
45
|
+
}
|
|
46
|
+
return path;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function parse(argv) {
|
|
50
|
+
const globals = { json: false, profile: "default", project: "", db: "", baseUrl: "" };
|
|
51
|
+
const args = [];
|
|
52
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
53
|
+
const arg = argv[i];
|
|
54
|
+
if (arg === "--json") {
|
|
55
|
+
const next = argv[i + 1] || "";
|
|
56
|
+
if (/^\s*[\[{]/.test(next)) {
|
|
57
|
+
args.push(arg);
|
|
58
|
+
args.push(argv[++i]);
|
|
59
|
+
} else {
|
|
60
|
+
globals.json = true;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
else if (arg === "--yes" || arg === "-y") globals.yes = true;
|
|
64
|
+
else if (["--profile", "--project", "--db", "--base-url"].includes(arg)) {
|
|
65
|
+
const key = arg === "--base-url" ? "baseUrl" : arg.slice(2);
|
|
66
|
+
globals[key] = argv[++i] || "";
|
|
67
|
+
}
|
|
68
|
+
else args.push(arg);
|
|
69
|
+
}
|
|
70
|
+
return { globals, args };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function redact(value) {
|
|
74
|
+
const text = String(value || "");
|
|
75
|
+
if (!text) return "";
|
|
76
|
+
return `${text.slice(0, 8)}...redacted`;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function print(payload, globals) {
|
|
80
|
+
if (globals.json) {
|
|
81
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if (Array.isArray(payload)) {
|
|
85
|
+
for (const item of payload) console.log(formatLine(item));
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
if (payload && typeof payload === "object") {
|
|
89
|
+
console.log(formatLine(payload));
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
console.log(String(payload));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function formatLine(item) {
|
|
96
|
+
if (!item || typeof item !== "object") return String(item);
|
|
97
|
+
const preferred = ["project_id", "database_id", "name", "plan", "status", "billing_status", "runtime_branch", "key_id"];
|
|
98
|
+
const parts = [];
|
|
99
|
+
for (const key of preferred) {
|
|
100
|
+
if (item[key] !== undefined && item[key] !== null && item[key] !== "") parts.push(`${key}=${item[key]}`);
|
|
101
|
+
}
|
|
102
|
+
return parts.length ? parts.join(" ") : JSON.stringify(item);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async function requireApiKey(config) {
|
|
106
|
+
const key = process.env.SYNAPSOR_API_KEY || config.current.apiKey || "";
|
|
107
|
+
if (!key) {
|
|
108
|
+
const error = new Error("AUTH_REQUIRED: configure an API key from the Synapsor dashboard. Public demo: https://synapsor.ai/demo");
|
|
109
|
+
error.code = "AUTH_REQUIRED";
|
|
110
|
+
throw error;
|
|
111
|
+
}
|
|
112
|
+
return key;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async function client(globals) {
|
|
116
|
+
const config = await loadConfig(globals.profile);
|
|
117
|
+
const baseUrl = (globals.baseUrl || process.env.SYNAPSOR_BASE_URL || config.current.baseUrl || DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
118
|
+
const apiKey = await requireApiKey(config);
|
|
119
|
+
return { baseUrl, apiKey };
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async function request(globals, method, path, body) {
|
|
123
|
+
const { baseUrl, apiKey } = await client(globals);
|
|
124
|
+
const init = { method, headers: { accept: "application/json", authorization: `Bearer ${apiKey}` } };
|
|
125
|
+
if (body !== undefined) {
|
|
126
|
+
init.headers["content-type"] = "application/json";
|
|
127
|
+
init.body = JSON.stringify(body);
|
|
128
|
+
}
|
|
129
|
+
const response = await fetch(`${baseUrl}${path}`, init);
|
|
130
|
+
const text = await response.text();
|
|
131
|
+
let payload = {};
|
|
132
|
+
if (text.trim()) {
|
|
133
|
+
try {
|
|
134
|
+
payload = JSON.parse(text);
|
|
135
|
+
} catch {
|
|
136
|
+
payload = { ok: false, error: "INVALID_JSON_RESPONSE", body_preview: text.slice(0, 240) };
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (!response.ok || payload.ok === false) {
|
|
140
|
+
const errorCode = mapError(payload.error || response.status);
|
|
141
|
+
const error = new Error(`${errorCode}: ${payload.message || payload.error || `HTTP ${response.status}`}`);
|
|
142
|
+
error.code = errorCode;
|
|
143
|
+
error.payload = payload;
|
|
144
|
+
throw error;
|
|
145
|
+
}
|
|
146
|
+
return payload;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function mapError(error) {
|
|
150
|
+
const text = String(error || "").toLowerCase();
|
|
151
|
+
if (text.includes("auth") || text.includes("session") || text.includes("token")) return "AUTH_REQUIRED";
|
|
152
|
+
if (text.includes("payment") || text.includes("billing")) return "BILLING_REQUIRED";
|
|
153
|
+
if (text.includes("quota") || text.includes("limit")) return "LIMIT_EXCEEDED";
|
|
154
|
+
if (text.includes("denied") || text.includes("forbidden")) return "FORBIDDEN";
|
|
155
|
+
if (text.includes("not_found")) return "NOT_FOUND";
|
|
156
|
+
if (text.includes("plan_not_available")) return "BETA_UNAVAILABLE";
|
|
157
|
+
return String(error || "REQUEST_FAILED").toUpperCase();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async function confirm(globals, label) {
|
|
161
|
+
if (globals.yes) return;
|
|
162
|
+
const rl = createInterface({ input, output });
|
|
163
|
+
const answer = await rl.question(`${label} Type yes to continue: `);
|
|
164
|
+
rl.close();
|
|
165
|
+
if (answer.trim().toLowerCase() !== "yes") throw new Error("FORBIDDEN: confirmation required");
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
async function readStdinSecret() {
|
|
169
|
+
const rl = createInterface({ input, output });
|
|
170
|
+
const value = await rl.question("Paste Synapsor API key: ");
|
|
171
|
+
rl.close();
|
|
172
|
+
return value.trim();
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async function main(argv = process.argv.slice(2)) {
|
|
176
|
+
const { globals, args } = parse(argv);
|
|
177
|
+
const [cmd, sub, third, ...rest] = args;
|
|
178
|
+
if (!cmd || cmd === "--help" || cmd === "help") return help();
|
|
179
|
+
if (cmd === "--version" || cmd === "version") return console.log(PACKAGE_VERSION);
|
|
180
|
+
|
|
181
|
+
if (cmd === "config") {
|
|
182
|
+
if (sub === "get") {
|
|
183
|
+
const config = await loadConfig(globals.profile);
|
|
184
|
+
return print({ profile: globals.profile, baseUrl: config.current.baseUrl || DEFAULT_BASE_URL, apiKey: redact(process.env.SYNAPSOR_API_KEY || config.current.apiKey) }, globals);
|
|
185
|
+
}
|
|
186
|
+
if (sub === "set" && third === "base-url") {
|
|
187
|
+
const value = rest[0];
|
|
188
|
+
if (!value) throw new Error("BASE_URL_REQUIRED: usage `synapsor config set base-url https://synapsor.ai`");
|
|
189
|
+
await saveConfig(globals.profile, { baseUrl: value.replace(/\/+$/, "") });
|
|
190
|
+
return print({ ok: true, profile: globals.profile, baseUrl: value.replace(/\/+$/, "") }, globals);
|
|
191
|
+
}
|
|
192
|
+
if (sub === "set" && third === "api-key") {
|
|
193
|
+
const value = rest[0] || await readStdinSecret();
|
|
194
|
+
if (!value) throw new Error("AUTH_REQUIRED: API key required");
|
|
195
|
+
await saveConfig(globals.profile, { apiKey: value });
|
|
196
|
+
return print({ ok: true, profile: globals.profile, apiKey: redact(value) }, globals);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (cmd === "projects") {
|
|
201
|
+
if (sub === "list") {
|
|
202
|
+
const payload = await request(globals, "GET", "/v1/control/projects");
|
|
203
|
+
return print(payload.projects || [], globals);
|
|
204
|
+
}
|
|
205
|
+
if (sub === "create") {
|
|
206
|
+
const name = third;
|
|
207
|
+
if (!name) throw new Error("PROJECT_NAME_REQUIRED: usage `synapsor projects create <name>`");
|
|
208
|
+
return print(await request(globals, "POST", "/v1/control/projects", { name, plan: "free" }), globals);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (cmd === "db") {
|
|
213
|
+
if (sub === "list") {
|
|
214
|
+
const payload = await request(globals, "GET", "/v1/control/databases");
|
|
215
|
+
return print(payload.databases || [], globals);
|
|
216
|
+
}
|
|
217
|
+
if (sub === "create") {
|
|
218
|
+
const name = third;
|
|
219
|
+
if (!name) throw new Error("DATABASE_NAME_REQUIRED: usage `synapsor db create <name> --project <project>`");
|
|
220
|
+
return print(await request(globals, "POST", "/v1/control/databases", { name, project_id: globals.project, plan: "free" }), globals);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (cmd === "sql") {
|
|
225
|
+
const db = globals.db || "";
|
|
226
|
+
let sql = args.slice(1).join(" ").trim();
|
|
227
|
+
const fileIndex = args.indexOf("--file");
|
|
228
|
+
if (fileIndex >= 0) sql = await readFile(args[fileIndex + 1], "utf8");
|
|
229
|
+
if (!db) throw new Error("DATABASE_REQUIRED: use `--db <database_id>`");
|
|
230
|
+
if (!sql) throw new Error("SQL_REQUIRED: pass SQL after --db or use --file");
|
|
231
|
+
return print(await request(globals, "POST", "/v1/control/console/sql", { project_id: globals.project, database_id: db, sql }), globals);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (cmd === "invoke") {
|
|
235
|
+
const capability = sub;
|
|
236
|
+
const jsonIndex = args.indexOf("--json");
|
|
237
|
+
const body = jsonIndex >= 0 ? JSON.parse(args[jsonIndex + 1] || "{}") : {};
|
|
238
|
+
if (!capability) throw new Error("CAPABILITY_REQUIRED: usage `synapsor invoke <capability> --db <database> --json '{...}'`");
|
|
239
|
+
if (!globals.db) throw new Error("DATABASE_REQUIRED: use `--db <database_id>`");
|
|
240
|
+
return print(await request(globals, "POST", "/v1/control/console/invoke", { project_id: globals.project, database_id: globals.db, capability, arguments: body }), globals);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (cmd === "evidence" && sub === "get") {
|
|
244
|
+
if (!third || !globals.db) throw new Error("EVIDENCE_OR_DATABASE_REQUIRED: usage `synapsor evidence get <handle> --db <database>`");
|
|
245
|
+
return print(await request(globals, "POST", "/v1/control/console/evidence", { project_id: globals.project, database_id: globals.db, uri: third }), globals);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (cmd === "proposal" && ["preview", "approve", "reject"].includes(sub)) {
|
|
249
|
+
if (!third || !globals.db) throw new Error("PROPOSAL_OR_DATABASE_REQUIRED: usage `synapsor proposal preview <handle> --db <database>`");
|
|
250
|
+
if (sub !== "preview") await confirm(globals, `Proposal ${sub} is auditable and may change workflow state.`);
|
|
251
|
+
return print(await request(globals, "POST", `/v1/control/console/proposals/${sub}`, { project_id: globals.project, database_id: globals.db, proposal: third }), globals);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (cmd === "replay") {
|
|
255
|
+
if (!sub || !globals.db) throw new Error("RUN_OR_DATABASE_REQUIRED: usage `synapsor replay <run-id> --db <database>`");
|
|
256
|
+
return print(await request(globals, "POST", "/v1/control/console/replay", { project_id: globals.project, database_id: globals.db, run_id: sub }), globals);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
throw new Error(`UNKNOWN_COMMAND: ${args.join(" ")}`);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function help() {
|
|
263
|
+
console.log(`Synapsor CLI ${PACKAGE_VERSION}
|
|
264
|
+
|
|
265
|
+
Usage:
|
|
266
|
+
synapsor --version
|
|
267
|
+
synapsor config set base-url https://synapsor.ai
|
|
268
|
+
synapsor config set api-key
|
|
269
|
+
synapsor config get
|
|
270
|
+
synapsor projects list
|
|
271
|
+
synapsor projects create <name>
|
|
272
|
+
synapsor db list --project <project>
|
|
273
|
+
synapsor db create <name> --project <project>
|
|
274
|
+
synapsor sql --db <database> "SELECT 1;"
|
|
275
|
+
synapsor sql --db <database> --file ./query.sql
|
|
276
|
+
synapsor invoke <capability> --db <database> --json '{"ticket_id":"TICK-1001"}'
|
|
277
|
+
synapsor evidence get <evidence-handle> --db <database>
|
|
278
|
+
synapsor proposal preview <proposal-handle> --db <database>
|
|
279
|
+
synapsor proposal approve <proposal-handle> --db <database> --yes
|
|
280
|
+
synapsor proposal reject <proposal-handle> --db <database> --yes
|
|
281
|
+
synapsor replay <run-id> --db <database>
|
|
282
|
+
|
|
283
|
+
Environment:
|
|
284
|
+
SYNAPSOR_API_KEY, SYNAPSOR_BASE_URL
|
|
285
|
+
|
|
286
|
+
Synapsor CLI runs Synapsor SQL/API commands only. It never executes server shell commands.`);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
main().catch((error) => {
|
|
290
|
+
const code = error.code || String(error.message || "REQUEST_FAILED").split(":", 1)[0];
|
|
291
|
+
console.error(error.message || String(error));
|
|
292
|
+
if (ERROR_HINTS.has(code)) console.error(ERROR_HINTS.get(code));
|
|
293
|
+
process.exitCode = 1;
|
|
294
|
+
});
|
package/generated-contract.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Generated by tools/generate_openapi_sdk_contract.py. Do not edit by hand.
|
|
2
2
|
export const PROTOCOL_VERSION = "v1";
|
|
3
|
-
export const CONTRACT_SHA256 = "
|
|
3
|
+
export const CONTRACT_SHA256 = "d6f052592bc48920a04ecdce12ca82160a57662b67a14a8ce95f0262cb86d6d0";
|
|
4
4
|
export const OPENAPI_OPERATIONS = Object.freeze({
|
|
5
5
|
"approveAgentProposal": {
|
|
6
6
|
"method": "POST",
|
|
@@ -209,6 +209,14 @@ export const OPENAPI_OPERATIONS = Object.freeze({
|
|
|
209
209
|
"public": false,
|
|
210
210
|
"python_method": "run_hybrid_reembed_jobs",
|
|
211
211
|
"request_schema": "#/components/schemas/HybridReembedRunRequest"
|
|
212
|
+
},
|
|
213
|
+
"settleAgentProposal": {
|
|
214
|
+
"method": "POST",
|
|
215
|
+
"node_method": "settleWrite",
|
|
216
|
+
"path": "/v1/agent/proposals/settle",
|
|
217
|
+
"public": false,
|
|
218
|
+
"python_method": "settle_write",
|
|
219
|
+
"request_schema": "#/components/schemas/ProposalLifecycleRequest"
|
|
212
220
|
}
|
|
213
221
|
});
|
|
214
222
|
export const PYTHON_OPERATION_METHODS = Object.freeze({
|
|
@@ -237,7 +245,8 @@ export const PYTHON_OPERATION_METHODS = Object.freeze({
|
|
|
237
245
|
"previewAgentProposal": "preview_write",
|
|
238
246
|
"rejectAgentProposal": "reject_write",
|
|
239
247
|
"resumeHybridReembedJob": "resume_hybrid_reembed_job",
|
|
240
|
-
"runHybridReembedJobs": "run_hybrid_reembed_jobs"
|
|
248
|
+
"runHybridReembedJobs": "run_hybrid_reembed_jobs",
|
|
249
|
+
"settleAgentProposal": "settle_write"
|
|
241
250
|
});
|
|
242
251
|
export const NODE_OPERATION_METHODS = Object.freeze({
|
|
243
252
|
"approveAgentProposal": "approveWrite",
|
|
@@ -265,7 +274,8 @@ export const NODE_OPERATION_METHODS = Object.freeze({
|
|
|
265
274
|
"previewAgentProposal": "previewWrite",
|
|
266
275
|
"rejectAgentProposal": "rejectWrite",
|
|
267
276
|
"resumeHybridReembedJob": "resumeHybridReembedJob",
|
|
268
|
-
"runHybridReembedJobs": "runHybridReembedJobs"
|
|
277
|
+
"runHybridReembedJobs": "runHybridReembedJobs",
|
|
278
|
+
"settleAgentProposal": "settleWrite"
|
|
269
279
|
});
|
|
270
280
|
export const PUBLIC_OPERATIONS = Object.freeze([
|
|
271
281
|
"getHealth",
|
package/package.json
CHANGED
|
@@ -1,20 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@synapsor/client",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Node.js
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "Node.js SDK for Synapsor, the agent-native database for auditable AI applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./synapsor.mjs",
|
|
7
|
+
"bin": {
|
|
8
|
+
"synapsor": "bin/synapsor.mjs"
|
|
9
|
+
},
|
|
7
10
|
"exports": {
|
|
8
|
-
".": "./synapsor.mjs"
|
|
11
|
+
".": "./synapsor.mjs",
|
|
12
|
+
"./bin/synapsor": "./bin/synapsor.mjs"
|
|
9
13
|
},
|
|
10
14
|
"files": [
|
|
15
|
+
"bin/synapsor.mjs",
|
|
11
16
|
"synapsor.mjs",
|
|
12
17
|
"generated-contract.mjs",
|
|
13
18
|
"README.md",
|
|
14
19
|
"package.json"
|
|
15
20
|
],
|
|
16
21
|
"scripts": {
|
|
17
|
-
"build": "node --check synapsor.mjs && node --check generated-contract.mjs",
|
|
22
|
+
"build": "node --check synapsor.mjs && node --check generated-contract.mjs && node --check bin/synapsor.mjs",
|
|
18
23
|
"test": "node --test test/*.test.mjs"
|
|
19
24
|
},
|
|
20
25
|
"keywords": [
|
|
@@ -28,7 +33,7 @@
|
|
|
28
33
|
"homepage": "https://synapsor.ai",
|
|
29
34
|
"repository": {
|
|
30
35
|
"type": "git",
|
|
31
|
-
"url": "git+https://github.com/
|
|
36
|
+
"url": "git+https://github.com/synapsor/synapsor.git"
|
|
32
37
|
},
|
|
33
38
|
"bugs": {
|
|
34
39
|
"url": "https://synapsor.ai/contact"
|
package/synapsor.mjs
CHANGED
|
@@ -236,14 +236,47 @@ export class Synapsor {
|
|
|
236
236
|
return results.at(-1).result?.rows ?? [];
|
|
237
237
|
}
|
|
238
238
|
|
|
239
|
-
async invokeAgentCapability(capability, args = {}, {
|
|
239
|
+
async invokeAgentCapability(capability, args = {}, {
|
|
240
|
+
session = undefined,
|
|
241
|
+
traceId = undefined,
|
|
242
|
+
trace_id = undefined,
|
|
243
|
+
mode = undefined,
|
|
244
|
+
autoBranch = undefined,
|
|
245
|
+
auto_branch = undefined,
|
|
246
|
+
responseEnvelope = undefined,
|
|
247
|
+
response_envelope = undefined,
|
|
248
|
+
includeAuditTrail = undefined,
|
|
249
|
+
include_audit_trail = undefined,
|
|
250
|
+
settlementPolicy = undefined,
|
|
251
|
+
settlement_policy = undefined,
|
|
252
|
+
} = {}) {
|
|
240
253
|
const payload = {
|
|
241
254
|
capability,
|
|
242
255
|
arguments: args,
|
|
243
256
|
session: this.requireSession(session),
|
|
244
257
|
};
|
|
245
|
-
|
|
246
|
-
|
|
258
|
+
const trace = traceId ?? trace_id;
|
|
259
|
+
const branch = autoBranch ?? auto_branch;
|
|
260
|
+
const envelope = responseEnvelope ?? response_envelope;
|
|
261
|
+
const audit = includeAuditTrail ?? include_audit_trail;
|
|
262
|
+
const policy = settlementPolicy ?? settlement_policy;
|
|
263
|
+
if (trace !== undefined) {
|
|
264
|
+
payload.trace_id = trace;
|
|
265
|
+
}
|
|
266
|
+
if (mode !== undefined) {
|
|
267
|
+
payload.mode = mode;
|
|
268
|
+
}
|
|
269
|
+
if (branch !== undefined) {
|
|
270
|
+
payload.auto_branch = Boolean(branch);
|
|
271
|
+
}
|
|
272
|
+
if (envelope !== undefined) {
|
|
273
|
+
payload.response_envelope = Boolean(envelope);
|
|
274
|
+
}
|
|
275
|
+
if (audit !== undefined) {
|
|
276
|
+
payload.include_audit_trail = Boolean(audit);
|
|
277
|
+
}
|
|
278
|
+
if (policy !== undefined) {
|
|
279
|
+
payload.settlement_policy = policy;
|
|
247
280
|
}
|
|
248
281
|
return this.request("POST", "/v1/agent/invoke", payload);
|
|
249
282
|
}
|
|
@@ -414,6 +447,13 @@ export class Synapsor {
|
|
|
414
447
|
return this.proposalLifecycle("cancel", proposal, options);
|
|
415
448
|
}
|
|
416
449
|
|
|
450
|
+
async settleWrite(proposal, settlementPolicy, options = {}) {
|
|
451
|
+
return this.proposalLifecycle("settle", proposal, {
|
|
452
|
+
...options,
|
|
453
|
+
settlementPolicy,
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
|
|
417
457
|
async replayAgentRun(runId, options = {}) {
|
|
418
458
|
return this.request("POST", "/v1/agent/runs/replay", {
|
|
419
459
|
run_id: Number(runId),
|
|
@@ -422,19 +462,23 @@ export class Synapsor {
|
|
|
422
462
|
});
|
|
423
463
|
}
|
|
424
464
|
|
|
425
|
-
async proposalLifecycle(action, proposal, { session = undefined, promoteBranch = undefined, promote_branch = undefined, targetBranch = undefined, target_branch = undefined } = {}) {
|
|
465
|
+
async proposalLifecycle(action, proposal, { session = undefined, promoteBranch = undefined, promote_branch = undefined, targetBranch = undefined, target_branch = undefined, settlementPolicy = undefined, settlement_policy = undefined } = {}) {
|
|
426
466
|
const payload = {
|
|
427
467
|
proposal,
|
|
428
468
|
session: this.requireSession(session),
|
|
429
469
|
};
|
|
430
470
|
const shouldPromote = promoteBranch ?? promote_branch;
|
|
431
471
|
const target = targetBranch ?? target_branch;
|
|
472
|
+
const policy = settlementPolicy ?? settlement_policy;
|
|
432
473
|
if (shouldPromote !== undefined) {
|
|
433
474
|
payload.promote_branch = Boolean(shouldPromote);
|
|
434
475
|
}
|
|
435
476
|
if (target !== undefined) {
|
|
436
477
|
payload.target_branch = target;
|
|
437
478
|
}
|
|
479
|
+
if (policy !== undefined) {
|
|
480
|
+
payload.settlement_policy = policy;
|
|
481
|
+
}
|
|
438
482
|
return this.request("POST", `/v1/agent/proposals/${action}`, payload);
|
|
439
483
|
}
|
|
440
484
|
|