@rcs-campaigns/agent-toolkit 0.1.5
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 +176 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +375 -0
- package/dist/client.d.ts +97 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +175 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/mcp.d.ts +3 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +178 -0
- package/dist/openapi.d.ts +36 -0
- package/dist/openapi.d.ts.map +1 -0
- package/dist/openapi.js +590 -0
- package/dist/tools.d.ts +93 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +1333 -0
- package/package.json +69 -0
package/dist/client.js
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GatewayClient = exports.GatewayError = void 0;
|
|
4
|
+
exports.detectSkin = detectSkin;
|
|
5
|
+
exports.readVersion = readVersion;
|
|
6
|
+
exports.skinLabels = skinLabels;
|
|
7
|
+
exports.normalizeChannel = normalizeChannel;
|
|
8
|
+
exports.resolveConfig = resolveConfig;
|
|
9
|
+
const node_fs_1 = require("node:fs");
|
|
10
|
+
const node_path_1 = require("node:path");
|
|
11
|
+
/**
|
|
12
|
+
* Which skin this process was launched as, from the bin name in argv.
|
|
13
|
+
*
|
|
14
|
+
* `wa`/`wa-mcp` mean the caller came in through the WhatsApp-branded docs and
|
|
15
|
+
* expects WhatsApp unless they say otherwise. Anything else (including being
|
|
16
|
+
* imported as a library) is treated as the neutral RCS skin, which leaves the
|
|
17
|
+
* channel to the server. Detection is deliberately conservative: an unknown
|
|
18
|
+
* argv, a bundler-rewritten path, or a direct import all fall through to 'rcs'.
|
|
19
|
+
*/
|
|
20
|
+
function detectSkin(argv = process.argv) {
|
|
21
|
+
const invoked = argv[1];
|
|
22
|
+
if (typeof invoked !== 'string')
|
|
23
|
+
return 'rcs';
|
|
24
|
+
// basename without extension, so ".../bin/wa-mcp.js" → "wa-mcp".
|
|
25
|
+
const base = invoked.split(/[\\/]/).pop() ?? '';
|
|
26
|
+
const name = base.replace(/\.(js|cjs|mjs|ts)$/, '');
|
|
27
|
+
return name === 'wa' || name === 'wa-mcp' ? 'wa' : 'rcs';
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The package's own version, read at runtime rather than restated in a
|
|
31
|
+
* constant. A hardcoded copy silently goes stale the first time anyone bumps
|
|
32
|
+
* for a release, and both skins show this string to a user. From dist/ and from
|
|
33
|
+
* src/ alike the package root is one level up.
|
|
34
|
+
*/
|
|
35
|
+
function readVersion() {
|
|
36
|
+
try {
|
|
37
|
+
const pkg = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(__dirname, '..', 'package.json'), 'utf8'));
|
|
38
|
+
return typeof pkg.version === 'string' ? pkg.version : '0.0.0';
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return '0.0.0';
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/** Human-readable product + channel names for the running skin. */
|
|
45
|
+
function skinLabels(skin = detectSkin()) {
|
|
46
|
+
return skin === 'wa'
|
|
47
|
+
? { product: 'WhatsApp Campaigns', channel: 'WhatsApp', slug: 'wa-campaigns' }
|
|
48
|
+
: { product: 'RCS Campaigns', channel: 'RCS', slug: 'rcs-campaigns' };
|
|
49
|
+
}
|
|
50
|
+
/** First environment variable that is set and non-empty, under either prefix. */
|
|
51
|
+
function fromEnv(...names) {
|
|
52
|
+
for (const name of names) {
|
|
53
|
+
const value = process.env[name];
|
|
54
|
+
if (value)
|
|
55
|
+
return value;
|
|
56
|
+
}
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Brand ids a user may type where a channel is expected (MSG-1867 phase 3).
|
|
61
|
+
* CANONICAL ids first, then the LEGACY spellings that are still persisted in
|
|
62
|
+
* keys, org metadata and old docs until the brand-id data migration has run
|
|
63
|
+
* everywhere. Mirrors `BRAND_IDS` / `BRAND_ID_ALIASES` in
|
|
64
|
+
* `@msg2ai/template-core`; this package is zero-dependency and published to
|
|
65
|
+
* npm, so it cannot import that registry.
|
|
66
|
+
*/
|
|
67
|
+
const BRAND_CHANNELS = {
|
|
68
|
+
'rcs-campaigns': 'RCS',
|
|
69
|
+
'rcs-surveys': 'RCS',
|
|
70
|
+
'wa-campaigns': 'WHATSAPP',
|
|
71
|
+
'wa-surveys': 'WHATSAPP',
|
|
72
|
+
// legacy spellings — accepted, never emitted
|
|
73
|
+
'rcs-templates': 'RCS',
|
|
74
|
+
'wa-templates': 'WHATSAPP'
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* Normalize a channel from configuration or a tool argument. Accepts the channel
|
|
78
|
+
* enum itself (any case) AND a brand id — canonical or legacy — resolving it to
|
|
79
|
+
* that brand's channel. Always returns the canonical channel enum; unknown
|
|
80
|
+
* values are ignored.
|
|
81
|
+
*/
|
|
82
|
+
function normalizeChannel(value) {
|
|
83
|
+
if (typeof value !== 'string')
|
|
84
|
+
return undefined;
|
|
85
|
+
const v = value.trim();
|
|
86
|
+
const upper = v.toUpperCase();
|
|
87
|
+
if (upper === 'RCS' || upper === 'WHATSAPP')
|
|
88
|
+
return upper;
|
|
89
|
+
return BRAND_CHANNELS[v.toLowerCase()];
|
|
90
|
+
}
|
|
91
|
+
/** Normalize a channel from configuration; unknown values are ignored. */
|
|
92
|
+
function readChannel(value) {
|
|
93
|
+
return normalizeChannel(value);
|
|
94
|
+
}
|
|
95
|
+
/** A gateway error carrying the HTTP status + the server's error envelope. */
|
|
96
|
+
class GatewayError extends Error {
|
|
97
|
+
status;
|
|
98
|
+
details;
|
|
99
|
+
constructor(message, status, details) {
|
|
100
|
+
super(message);
|
|
101
|
+
this.name = 'GatewayError';
|
|
102
|
+
this.status = status;
|
|
103
|
+
this.details = details;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
exports.GatewayError = GatewayError;
|
|
107
|
+
/**
|
|
108
|
+
* Resolve config from explicit values, falling back to the environment.
|
|
109
|
+
*
|
|
110
|
+
* WA_* and RCS_* are accepted interchangeably. When both are set the one
|
|
111
|
+
* matching the running skin wins, so a machine configured for both does the
|
|
112
|
+
* expected thing under either bin.
|
|
113
|
+
*/
|
|
114
|
+
function resolveConfig(partial) {
|
|
115
|
+
const skin = detectSkin();
|
|
116
|
+
const [urlFirst, urlSecond] = skin === 'wa'
|
|
117
|
+
? ['WA_GATEWAY_URL', 'RCS_GATEWAY_URL']
|
|
118
|
+
: ['RCS_GATEWAY_URL', 'WA_GATEWAY_URL'];
|
|
119
|
+
const [keyFirst, keySecond] = skin === 'wa'
|
|
120
|
+
? ['WA_AGENT_KEY', 'RCS_AGENT_KEY']
|
|
121
|
+
: ['RCS_AGENT_KEY', 'WA_AGENT_KEY'];
|
|
122
|
+
const baseUrl = partial?.baseUrl ?? fromEnv(urlFirst, urlSecond) ?? 'http://localhost:3002';
|
|
123
|
+
const apiKey = partial?.apiKey ?? fromEnv(keyFirst, keySecond) ?? '';
|
|
124
|
+
if (!apiKey) {
|
|
125
|
+
throw new Error(`No agent key configured. Set ${keyFirst} or pass apiKey explicitly.`);
|
|
126
|
+
}
|
|
127
|
+
// Explicit beats env beats skin default. The wa skin assumes WhatsApp; the rcs
|
|
128
|
+
// skin stays silent and lets the server pick the org's own brand channel.
|
|
129
|
+
const defaultChannel = partial?.defaultChannel ??
|
|
130
|
+
readChannel(fromEnv('WA_DEFAULT_CHANNEL', 'RCS_DEFAULT_CHANNEL')) ??
|
|
131
|
+
(skin === 'wa' ? 'WHATSAPP' : undefined);
|
|
132
|
+
return { baseUrl: baseUrl.replace(/\/$/, ''), apiKey, defaultChannel };
|
|
133
|
+
}
|
|
134
|
+
class GatewayClient {
|
|
135
|
+
config;
|
|
136
|
+
constructor(config) {
|
|
137
|
+
this.config = config;
|
|
138
|
+
}
|
|
139
|
+
static fromEnv(partial) {
|
|
140
|
+
return new GatewayClient(resolveConfig(partial));
|
|
141
|
+
}
|
|
142
|
+
/** Issue a request against the gateway and return `data` from the envelope. */
|
|
143
|
+
async call(spec) {
|
|
144
|
+
const url = new URL(`${this.config.baseUrl}/api/agent${spec.path}`);
|
|
145
|
+
for (const [k, v] of Object.entries(spec.query ?? {})) {
|
|
146
|
+
if (v !== undefined && v !== '')
|
|
147
|
+
url.searchParams.set(k, String(v));
|
|
148
|
+
}
|
|
149
|
+
const res = await fetch(url, {
|
|
150
|
+
method: spec.method,
|
|
151
|
+
headers: {
|
|
152
|
+
Authorization: `Bearer ${this.config.apiKey}`,
|
|
153
|
+
...(spec.body !== undefined
|
|
154
|
+
? { 'Content-Type': 'application/json' }
|
|
155
|
+
: {})
|
|
156
|
+
},
|
|
157
|
+
body: spec.body !== undefined ? JSON.stringify(spec.body) : undefined
|
|
158
|
+
});
|
|
159
|
+
const text = await res.text();
|
|
160
|
+
let parsed = undefined;
|
|
161
|
+
try {
|
|
162
|
+
parsed = text ? JSON.parse(text) : undefined;
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
// Non-JSON body (e.g. a proxy error page); surface the raw text.
|
|
166
|
+
if (!res.ok)
|
|
167
|
+
throw new GatewayError(text || res.statusText, res.status);
|
|
168
|
+
}
|
|
169
|
+
if (!res.ok || parsed?.success === false) {
|
|
170
|
+
throw new GatewayError(parsed?.error ?? `Request failed (${res.status})`, res.status, parsed?.details);
|
|
171
|
+
}
|
|
172
|
+
return (parsed?.data ?? parsed);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
exports.GatewayClient = GatewayClient;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @rcs-campaigns/agent-toolkit
|
|
3
|
+
*
|
|
4
|
+
* Two agent skins over one gateway client:
|
|
5
|
+
* - the MCP server (`rcs-mcp` bin, ./mcp)
|
|
6
|
+
* - the CLI (`rcs` bin, ./cli)
|
|
7
|
+
* sharing the typed gateway client (./client) and the declarative tool catalog
|
|
8
|
+
* (./tools). Importing the package gives you the client + catalog to embed in
|
|
9
|
+
* your own agent; the bins are the ready-made skins.
|
|
10
|
+
*
|
|
11
|
+
* @see docs/design/AGENT-ENABLEMENT-AND-X402-DESIGN.md
|
|
12
|
+
*/
|
|
13
|
+
export * from './client';
|
|
14
|
+
export * from './tools';
|
|
15
|
+
export * from './openapi';
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
/**
|
|
18
|
+
* @rcs-campaigns/agent-toolkit
|
|
19
|
+
*
|
|
20
|
+
* Two agent skins over one gateway client:
|
|
21
|
+
* - the MCP server (`rcs-mcp` bin, ./mcp)
|
|
22
|
+
* - the CLI (`rcs` bin, ./cli)
|
|
23
|
+
* sharing the typed gateway client (./client) and the declarative tool catalog
|
|
24
|
+
* (./tools). Importing the package gives you the client + catalog to embed in
|
|
25
|
+
* your own agent; the bins are the ready-made skins.
|
|
26
|
+
*
|
|
27
|
+
* @see docs/design/AGENT-ENABLEMENT-AND-X402-DESIGN.md
|
|
28
|
+
*/
|
|
29
|
+
__exportStar(require("./client"), exports);
|
|
30
|
+
__exportStar(require("./tools"), exports);
|
|
31
|
+
__exportStar(require("./openapi"), exports);
|
package/dist/mcp.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":""}
|
package/dist/mcp.js
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
/**
|
|
5
|
+
* `rcs-mcp` — a Model Context Protocol (MCP) server exposing the RCS Campaigns
|
|
6
|
+
* agent gateway as tools, so Claude (and any MCP-capable agent) can search, read,
|
|
7
|
+
* render, create, clone, submit, and send RCS templates.
|
|
8
|
+
*
|
|
9
|
+
* Transport: stdio with newline-delimited JSON-RPC 2.0 (the MCP stdio framing).
|
|
10
|
+
* It is implemented by hand against the protocol so this package carries ZERO
|
|
11
|
+
* runtime dependencies — nothing to install, nothing to drift, and it slots into
|
|
12
|
+
* the workspace without touching the lockfile's external graph.
|
|
13
|
+
*
|
|
14
|
+
* Credentials: the agent key + gateway URL come from the environment
|
|
15
|
+
* (RCS_AGENT_KEY / RCS_GATEWAY_URL). This process holds the key only to forward
|
|
16
|
+
* it as a Bearer token to the gateway — all business logic stays server-side.
|
|
17
|
+
*
|
|
18
|
+
* Wire it up (e.g. Claude Code):
|
|
19
|
+
* claude mcp add rcs-campaigns -- npx -y -p @rcs-campaigns/agent-toolkit rcs-mcp
|
|
20
|
+
* (with RCS_AGENT_KEY + RCS_GATEWAY_URL set in the environment)
|
|
21
|
+
*/
|
|
22
|
+
const node_readline_1 = require("node:readline");
|
|
23
|
+
const client_1 = require("./client");
|
|
24
|
+
const tools_1 = require("./tools");
|
|
25
|
+
const PROTOCOL_VERSION = '2024-11-05';
|
|
26
|
+
/**
|
|
27
|
+
* The MCP host shows `serverInfo` and `instructions` to the user and injects the
|
|
28
|
+
* latter as system guidance. Both must match the skin the server was launched
|
|
29
|
+
* as: an agent that registered `wa-mcp` should not find "RCS Campaigns" and
|
|
30
|
+
* "RCS-first" in its own tool list, contradicting the docs that sent it here.
|
|
31
|
+
* Same catalog, same gateway — only the words the model reads differ.
|
|
32
|
+
*/
|
|
33
|
+
const SKIN = (0, client_1.detectSkin)();
|
|
34
|
+
const { product: PRODUCT, channel: CHANNEL, slug: SLUG } = (0, client_1.skinLabels)(SKIN);
|
|
35
|
+
const SERVER_INFO = { name: SLUG, version: (0, client_1.readVersion)() };
|
|
36
|
+
/**
|
|
37
|
+
* Surfaced to MCP hosts as the initialize result's `instructions` string — hosts
|
|
38
|
+
* inject it as system guidance for the model. It teaches the canonical workflow
|
|
39
|
+
* so an agent does not have to discover the submit-before-RCS step by trial:
|
|
40
|
+
* without it, sends silently fall back to SMS and the agent has no cue why.
|
|
41
|
+
*/
|
|
42
|
+
const INSTRUCTIONS = [
|
|
43
|
+
`${PRODUCT} agent gateway — author, approve, and send ${CHANNEL}-first message`,
|
|
44
|
+
'templates and conversational surveys over one typed contract.',
|
|
45
|
+
'',
|
|
46
|
+
'Canonical template flow:',
|
|
47
|
+
' search_templates → clone_template (into your org) → render_template (preview)',
|
|
48
|
+
' → submit_template (provider approval) → send_message.',
|
|
49
|
+
'Surveys mirror it: search_surveys/create_survey → submit_survey → send_survey →',
|
|
50
|
+
'get_results.',
|
|
51
|
+
'',
|
|
52
|
+
`IMPORTANT — rich ${CHANNEL} requires approval. A freshly created or cloned`,
|
|
53
|
+
'template delivers as SMS fallback ONLY until it is submitted AND',
|
|
54
|
+
'provider-approved. send_message returns a funnel whose `fellBackToSms` count',
|
|
55
|
+
`is > 0 whenever the rich ${CHANNEL} path was unavailable — submit the template`,
|
|
56
|
+
`and wait for approval to deliver rich ${CHANNEL}. send_message/send_survey bill`,
|
|
57
|
+
'your org and are irreversible.',
|
|
58
|
+
'',
|
|
59
|
+
'Call `capabilities` first to see the tool catalog and which scopes your key holds.'
|
|
60
|
+
].join('\n');
|
|
61
|
+
/** Write one newline-delimited JSON-RPC message to stdout. */
|
|
62
|
+
function send(msg) {
|
|
63
|
+
process.stdout.write(`${JSON.stringify(msg)}\n`);
|
|
64
|
+
}
|
|
65
|
+
function reply(id, result) {
|
|
66
|
+
send({ jsonrpc: '2.0', id, result });
|
|
67
|
+
}
|
|
68
|
+
function replyError(id, code, message, data) {
|
|
69
|
+
send({ jsonrpc: '2.0', id, error: { code, message, data } });
|
|
70
|
+
}
|
|
71
|
+
// Lazily build the client so `tools/list` works even before a key is set, but a
|
|
72
|
+
// `tools/call` without a key fails cleanly with a helpful message.
|
|
73
|
+
let client = null;
|
|
74
|
+
let config = null;
|
|
75
|
+
function getClient() {
|
|
76
|
+
if (!client) {
|
|
77
|
+
config = (0, client_1.resolveConfig)();
|
|
78
|
+
client = new client_1.GatewayClient(config);
|
|
79
|
+
}
|
|
80
|
+
return client;
|
|
81
|
+
}
|
|
82
|
+
async function handleToolCall(id, params) {
|
|
83
|
+
const name = params?.name;
|
|
84
|
+
const args = params?.arguments ?? {};
|
|
85
|
+
const tool = (0, tools_1.findTool)(name);
|
|
86
|
+
if (!tool) {
|
|
87
|
+
return replyError(id, -32602, `Unknown tool: ${name}`);
|
|
88
|
+
}
|
|
89
|
+
try {
|
|
90
|
+
const gateway = getClient();
|
|
91
|
+
// Resolve the skin's default channel before mapping args to a request, so
|
|
92
|
+
// `wa-mcp` sends WhatsApp without every caller repeating themselves.
|
|
93
|
+
const resolved = (0, tools_1.withDefaultChannel)(tool, args, config?.defaultChannel);
|
|
94
|
+
const data = await gateway.call(tool.toRequest(resolved));
|
|
95
|
+
// MCP tool results are content blocks; we return the JSON payload as text so
|
|
96
|
+
// the agent can parse it. isError stays false on success.
|
|
97
|
+
reply(id, {
|
|
98
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
99
|
+
isError: false
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
const message = err instanceof client_1.GatewayError
|
|
104
|
+
? `Gateway ${err.status}: ${err.message}`
|
|
105
|
+
: err instanceof Error
|
|
106
|
+
? err.message
|
|
107
|
+
: String(err);
|
|
108
|
+
// Surface the failure as an MCP tool error (not a protocol error) so the
|
|
109
|
+
// agent can read it and decide what to do (e.g. fix args, request a scope).
|
|
110
|
+
reply(id, {
|
|
111
|
+
content: [{ type: 'text', text: message }],
|
|
112
|
+
isError: true
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
function handleMessage(msg) {
|
|
117
|
+
switch (msg.method) {
|
|
118
|
+
case 'initialize': {
|
|
119
|
+
// Echo the client's requested protocol version when it sends one (the spec
|
|
120
|
+
// negotiates on it); fall back to the version we implement against.
|
|
121
|
+
const requested = msg.params?.protocolVersion;
|
|
122
|
+
reply(msg.id, {
|
|
123
|
+
protocolVersion: typeof requested === 'string' ? requested : PROTOCOL_VERSION,
|
|
124
|
+
capabilities: { tools: {} },
|
|
125
|
+
serverInfo: SERVER_INFO,
|
|
126
|
+
instructions: INSTRUCTIONS
|
|
127
|
+
});
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
case 'notifications/initialized':
|
|
131
|
+
return; // notification: no response
|
|
132
|
+
case 'ping':
|
|
133
|
+
reply(msg.id, {});
|
|
134
|
+
return;
|
|
135
|
+
case 'tools/list':
|
|
136
|
+
reply(msg.id, {
|
|
137
|
+
tools: tools_1.TOOLS.map((t) => ({
|
|
138
|
+
name: t.name,
|
|
139
|
+
description: t.description,
|
|
140
|
+
inputSchema: t.inputSchema
|
|
141
|
+
}))
|
|
142
|
+
});
|
|
143
|
+
return;
|
|
144
|
+
case 'tools/call':
|
|
145
|
+
void handleToolCall(msg.id, msg.params);
|
|
146
|
+
return;
|
|
147
|
+
default:
|
|
148
|
+
// Unknown request -> method-not-found; ignore unknown notifications.
|
|
149
|
+
if (msg.id !== undefined && msg.id !== null) {
|
|
150
|
+
replyError(msg.id, -32601, `Method not found: ${msg.method}`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
function main() {
|
|
155
|
+
const rl = (0, node_readline_1.createInterface)({ input: process.stdin });
|
|
156
|
+
rl.on('line', (line) => {
|
|
157
|
+
const trimmed = line.trim();
|
|
158
|
+
if (!trimmed)
|
|
159
|
+
return;
|
|
160
|
+
let msg;
|
|
161
|
+
try {
|
|
162
|
+
msg = JSON.parse(trimmed);
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
return; // ignore malformed lines (no id to respond to)
|
|
166
|
+
}
|
|
167
|
+
try {
|
|
168
|
+
handleMessage(msg);
|
|
169
|
+
}
|
|
170
|
+
catch (err) {
|
|
171
|
+
if (msg.id !== undefined && msg.id !== null) {
|
|
172
|
+
replyError(msg.id, -32603, 'Internal error', String(err));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
rl.on('close', () => process.exit(0));
|
|
177
|
+
}
|
|
178
|
+
main();
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export interface OpenApiServer {
|
|
2
|
+
url: string;
|
|
3
|
+
description: string;
|
|
4
|
+
}
|
|
5
|
+
export interface BuildOpenApiOptions {
|
|
6
|
+
/**
|
|
7
|
+
* The webhook event types to document under the top-level `webhooks` object.
|
|
8
|
+
*
|
|
9
|
+
* Defaults to `WEBHOOK_EVENT_NAMES`, which IS the vocabulary — `apps/server`
|
|
10
|
+
* re-exports it as `WEBHOOK_EVENTS` rather than declaring a second list, so
|
|
11
|
+
* the default is already the server's answer and passing it explicitly (as
|
|
12
|
+
* `routes/agent.ts` does) is a no-op that documents the intent. The override
|
|
13
|
+
* stays for an embedder generating a document for a gateway build that
|
|
14
|
+
* fires a different set.
|
|
15
|
+
*/
|
|
16
|
+
webhookEvents?: readonly string[];
|
|
17
|
+
/** Document version stamped into `info.version`. */
|
|
18
|
+
version?: string;
|
|
19
|
+
}
|
|
20
|
+
/** Anything JSON-serialisable. The document is data, not a typed AST. */
|
|
21
|
+
type Json = Record<string, any>;
|
|
22
|
+
/** `/conversations/:id` → `/conversations/{id}` (OpenAPI path templating). */
|
|
23
|
+
export declare function toOpenApiPath(path: string): string;
|
|
24
|
+
/** The `:param` names in an Express-style path, in order. */
|
|
25
|
+
export declare function pathParamsOf(path: string): string[];
|
|
26
|
+
/**
|
|
27
|
+
* Build the gateway's OpenAPI 3.1 document.
|
|
28
|
+
*
|
|
29
|
+
* `servers` is supplied by the caller because only the server knows which
|
|
30
|
+
* environment it is: a published spec whose host is a placeholder cannot be
|
|
31
|
+
* imported into Postman or a code generator without hand-editing, which is the
|
|
32
|
+
* exact defect this replaces.
|
|
33
|
+
*/
|
|
34
|
+
export declare function buildOpenApiDocument(servers: OpenApiServer[], options?: BuildOpenApiOptions): Json;
|
|
35
|
+
export {};
|
|
36
|
+
//# sourceMappingURL=openapi.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openapi.d.ts","sourceRoot":"","sources":["../src/openapi.ts"],"names":[],"mappings":"AA0BA,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,mBAAmB;IAClC;;;;;;;;;OASG;IACH,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,oDAAoD;IACpD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,yEAAyE;AACzE,KAAK,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAMhC,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,6DAA6D;AAC7D,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAEnD;AAwfD;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,aAAa,EAAE,EACxB,OAAO,GAAE,mBAAwB,GAChC,IAAI,CAmFN"}
|