@avernet-plugin/deepseek-harness-channel-bcn 0.1.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/LEGAL.md +9 -0
- package/LICENSE +176 -0
- package/README.md +242 -0
- package/cordis.patch.yml +5 -0
- package/dist/bridge.d.ts +51 -0
- package/dist/bridge.d.ts.map +1 -0
- package/dist/bridge.js +695 -0
- package/dist/bridge.js.map +1 -0
- package/dist/config.d.ts +23 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +60 -0
- package/dist/config.js.map +1 -0
- package/dist/configure.d.ts +18 -0
- package/dist/configure.d.ts.map +1 -0
- package/dist/configure.js +207 -0
- package/dist/configure.js.map +1 -0
- package/dist/credentials.d.ts +15 -0
- package/dist/credentials.d.ts.map +1 -0
- package/dist/credentials.js +44 -0
- package/dist/credentials.js.map +1 -0
- package/dist/endpoint.d.ts +21 -0
- package/dist/endpoint.d.ts.map +1 -0
- package/dist/endpoint.js +156 -0
- package/dist/endpoint.js.map +1 -0
- package/dist/http-client.d.ts +28 -0
- package/dist/http-client.d.ts.map +1 -0
- package/dist/http-client.js +106 -0
- package/dist/http-client.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +42 -0
- package/dist/index.js.map +1 -0
- package/dist/protocol.d.ts +107 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +157 -0
- package/dist/protocol.js.map +1 -0
- package/dist/route-tool.d.ts +5 -0
- package/dist/route-tool.d.ts.map +1 -0
- package/dist/route-tool.js +38 -0
- package/dist/route-tool.js.map +1 -0
- package/dist/session-identity.d.ts +22 -0
- package/dist/session-identity.d.ts.map +1 -0
- package/dist/session-identity.js +35 -0
- package/dist/session-identity.js.map +1 -0
- package/dist/task-tools.d.ts +9 -0
- package/dist/task-tools.d.ts.map +1 -0
- package/dist/task-tools.js +81 -0
- package/dist/task-tools.js.map +1 -0
- package/dist/ws-client.d.ts +62 -0
- package/dist/ws-client.d.ts.map +1 -0
- package/dist/ws-client.js +433 -0
- package/dist/ws-client.js.map +1 -0
- package/install-dsh.sh +95 -0
- package/package.json +80 -0
package/dist/endpoint.js
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { lookup as dnsLookup } from 'node:dns/promises';
|
|
2
|
+
import { BlockList, isIP } from 'node:net';
|
|
3
|
+
const BLOCKED_IPV6 = new BlockList();
|
|
4
|
+
BLOCKED_IPV6.addSubnet('::', 96, 'ipv6');
|
|
5
|
+
BLOCKED_IPV6.addSubnet('64:ff9b::', 96, 'ipv6');
|
|
6
|
+
BLOCKED_IPV6.addSubnet('64:ff9b:1::', 48, 'ipv6');
|
|
7
|
+
BLOCKED_IPV6.addSubnet('fc00::', 7, 'ipv6');
|
|
8
|
+
BLOCKED_IPV6.addSubnet('fe80::', 10, 'ipv6');
|
|
9
|
+
BLOCKED_IPV6.addSubnet('fec0::', 10, 'ipv6');
|
|
10
|
+
BLOCKED_IPV6.addSubnet('ff00::', 8, 'ipv6');
|
|
11
|
+
BLOCKED_IPV6.addSubnet('100::', 64, 'ipv6');
|
|
12
|
+
BLOCKED_IPV6.addSubnet('2001::', 32, 'ipv6');
|
|
13
|
+
BLOCKED_IPV6.addSubnet('2001:2::', 48, 'ipv6');
|
|
14
|
+
BLOCKED_IPV6.addSubnet('2001:db8::', 32, 'ipv6');
|
|
15
|
+
BLOCKED_IPV6.addSubnet('2001:20::', 28, 'ipv6');
|
|
16
|
+
BLOCKED_IPV6.addSubnet('2002::', 16, 'ipv6');
|
|
17
|
+
export async function resolveEndpoint(input, resolver = async (hostname) => dnsLookup(hostname, { all: true, verbatim: true })) {
|
|
18
|
+
const baseUrl = parseEndpoint(input);
|
|
19
|
+
const hostname = stripIpv6Brackets(baseUrl.hostname).toLowerCase();
|
|
20
|
+
const literalFamily = isIP(hostname);
|
|
21
|
+
const addresses = literalFamily
|
|
22
|
+
? [{ address: hostname, family: literalFamily }]
|
|
23
|
+
: await resolver(hostname);
|
|
24
|
+
if (addresses.length === 0)
|
|
25
|
+
throw new Error('BCN endpoint hostname resolved to no addresses');
|
|
26
|
+
const normalized = addresses.map(({ address, family }) => {
|
|
27
|
+
const actualFamily = isIP(address);
|
|
28
|
+
if ((family !== 4 && family !== 6) || actualFamily !== family) {
|
|
29
|
+
throw new Error('BCN endpoint hostname returned an invalid DNS address');
|
|
30
|
+
}
|
|
31
|
+
return { address, family };
|
|
32
|
+
});
|
|
33
|
+
const loopbackHost = hostname === 'localhost'
|
|
34
|
+
|| (literalFamily !== 0 && normalized.every(item => isLoopbackAddress(item.address)));
|
|
35
|
+
if (loopbackHost) {
|
|
36
|
+
if (!normalized.every(item => isLoopbackAddress(item.address))) {
|
|
37
|
+
throw new Error('Loopback BCN endpoint resolved outside the loopback range');
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
else if (!normalized.every(item => isPublicAddress(item.address))) {
|
|
41
|
+
throw new Error('BCN endpoint resolved to a private, link-local, or reserved address');
|
|
42
|
+
}
|
|
43
|
+
const lookup = createPinnedLookup(hostname, normalized);
|
|
44
|
+
const webSocketUrl = new URL('ws/bot', baseUrl);
|
|
45
|
+
webSocketUrl.protocol = baseUrl.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
46
|
+
return { baseUrl, webSocketUrl, addresses: normalized, lookup, loopback: loopbackHost };
|
|
47
|
+
}
|
|
48
|
+
export function canonicalizeEndpoint(input) {
|
|
49
|
+
return parseEndpoint(input).toString();
|
|
50
|
+
}
|
|
51
|
+
export function parseEndpoint(input) {
|
|
52
|
+
let parsed;
|
|
53
|
+
try {
|
|
54
|
+
parsed = new URL(input);
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
throw new Error('BCN endpoint must be an absolute HTTP(S) URL');
|
|
58
|
+
}
|
|
59
|
+
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
|
|
60
|
+
throw new Error('BCN endpoint must use HTTP or HTTPS');
|
|
61
|
+
}
|
|
62
|
+
if (!parsed.hostname)
|
|
63
|
+
throw new Error('BCN endpoint must include a hostname');
|
|
64
|
+
if (parsed.username || parsed.password || parsed.search || parsed.hash) {
|
|
65
|
+
throw new Error('BCN endpoint must not contain credentials, query parameters, or a fragment');
|
|
66
|
+
}
|
|
67
|
+
parsed.pathname = `${parsed.pathname.replace(/\/+$/, '')}/`;
|
|
68
|
+
return parsed;
|
|
69
|
+
}
|
|
70
|
+
export function isPublicAddress(address) {
|
|
71
|
+
const family = isIP(address);
|
|
72
|
+
if (family === 4)
|
|
73
|
+
return isPublicIpv4(address);
|
|
74
|
+
if (family === 6)
|
|
75
|
+
return isPublicIpv6(address);
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
export function isLoopbackAddress(address) {
|
|
79
|
+
const normalized = address.toLowerCase();
|
|
80
|
+
if (normalized === '::1')
|
|
81
|
+
return true;
|
|
82
|
+
if (normalized.startsWith('::ffff:'))
|
|
83
|
+
return isLoopbackAddress(normalized.slice(7));
|
|
84
|
+
const parts = parseIpv4(normalized);
|
|
85
|
+
return parts?.[0] === 127;
|
|
86
|
+
}
|
|
87
|
+
function isPublicIpv4(address) {
|
|
88
|
+
const parts = parseIpv4(address);
|
|
89
|
+
if (!parts)
|
|
90
|
+
return false;
|
|
91
|
+
const [a, b, c] = parts;
|
|
92
|
+
if (a === 0 || a === 10 || a === 127 || a >= 224)
|
|
93
|
+
return false;
|
|
94
|
+
if (a === 100 && b >= 64 && b <= 127)
|
|
95
|
+
return false;
|
|
96
|
+
if (a === 169 && b === 254)
|
|
97
|
+
return false;
|
|
98
|
+
if (a === 172 && b >= 16 && b <= 31)
|
|
99
|
+
return false;
|
|
100
|
+
if (a === 192 && b === 168)
|
|
101
|
+
return false;
|
|
102
|
+
if (a === 198 && (b === 18 || b === 19))
|
|
103
|
+
return false;
|
|
104
|
+
if (a === 192 && b === 0 && (c === 0 || c === 2))
|
|
105
|
+
return false;
|
|
106
|
+
if (a === 198 && b === 51 && c === 100)
|
|
107
|
+
return false;
|
|
108
|
+
if (a === 203 && b === 0 && c === 113)
|
|
109
|
+
return false;
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
function isPublicIpv6(address) {
|
|
113
|
+
const normalized = address.toLowerCase().split('%', 1)[0] ?? '';
|
|
114
|
+
if (!normalized || normalized.startsWith('::ffff:'))
|
|
115
|
+
return false;
|
|
116
|
+
return !BLOCKED_IPV6.check(normalized, 'ipv6');
|
|
117
|
+
}
|
|
118
|
+
function parseIpv4(address) {
|
|
119
|
+
const parts = address.split('.');
|
|
120
|
+
if (parts.length !== 4)
|
|
121
|
+
return undefined;
|
|
122
|
+
const values = parts.map(part => Number(part));
|
|
123
|
+
if (values.some(value => !Number.isInteger(value) || value < 0 || value > 255))
|
|
124
|
+
return undefined;
|
|
125
|
+
return values;
|
|
126
|
+
}
|
|
127
|
+
function stripIpv6Brackets(hostname) {
|
|
128
|
+
return hostname.startsWith('[') && hostname.endsWith(']') ? hostname.slice(1, -1) : hostname;
|
|
129
|
+
}
|
|
130
|
+
function createPinnedLookup(expectedHostname, addresses) {
|
|
131
|
+
let cursor = 0;
|
|
132
|
+
return ((hostname, options, callback) => {
|
|
133
|
+
if (stripIpv6Brackets(hostname).toLowerCase() !== expectedHostname) {
|
|
134
|
+
callback(new Error('Refusing DNS lookup for an unexpected BCN hostname'));
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const optionRecord = typeof options === 'object' && options !== null
|
|
138
|
+
? options
|
|
139
|
+
: { family: typeof options === 'number' ? options : 0 };
|
|
140
|
+
const matching = optionRecord.family === 4 || optionRecord.family === 6
|
|
141
|
+
? addresses.filter(item => item.family === optionRecord.family)
|
|
142
|
+
: [...addresses];
|
|
143
|
+
if (matching.length === 0) {
|
|
144
|
+
callback(new Error('No validated BCN address matches the requested address family'));
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
if (optionRecord.all) {
|
|
148
|
+
callback(null, matching);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
const selected = matching[cursor % matching.length];
|
|
152
|
+
cursor += 1;
|
|
153
|
+
callback(null, selected?.address, selected?.family);
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=endpoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"endpoint.js","sourceRoot":"","sources":["../src/endpoint.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Config } from './config.js';
|
|
2
|
+
import type { ResolvedEndpoint } from './endpoint.js';
|
|
3
|
+
import { type BotSession, type RegisterBotResponse } from './protocol.js';
|
|
4
|
+
export interface HttpTransport {
|
|
5
|
+
requestJson(endpoint: ResolvedEndpoint, path: string, options: {
|
|
6
|
+
method: 'POST';
|
|
7
|
+
headers?: Record<string, string>;
|
|
8
|
+
body?: unknown;
|
|
9
|
+
query?: URLSearchParams;
|
|
10
|
+
}, timeoutMs: number): Promise<unknown>;
|
|
11
|
+
}
|
|
12
|
+
export declare class NodeHttpTransport implements HttpTransport {
|
|
13
|
+
requestJson(endpoint: ResolvedEndpoint, path: string, options: {
|
|
14
|
+
method: 'POST';
|
|
15
|
+
headers?: Record<string, string>;
|
|
16
|
+
body?: unknown;
|
|
17
|
+
query?: URLSearchParams;
|
|
18
|
+
}, timeoutMs: number): Promise<unknown>;
|
|
19
|
+
}
|
|
20
|
+
export declare class BcnOnboardingClient {
|
|
21
|
+
private readonly endpoint;
|
|
22
|
+
private readonly transport;
|
|
23
|
+
private readonly timeoutMs;
|
|
24
|
+
constructor(endpoint: ResolvedEndpoint, transport: HttpTransport, timeoutMs: number);
|
|
25
|
+
register(token: string, botName: string): Promise<RegisterBotResponse>;
|
|
26
|
+
onboard(session: BotSession, config: Config): Promise<void>;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=http-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-client.d.ts","sourceRoot":"","sources":["../src/http-client.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAIL,KAAK,UAAU,EACf,KAAK,mBAAmB,EACzB,MAAM,eAAe,CAAC;AAEvB,MAAM,WAAW,aAAa;IAC5B,WAAW,CACT,QAAQ,EAAE,gBAAgB,EAC1B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,eAAe,CAAA;KAAE,EACtG,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC,CAAC;CACrB;AAED,qBAAa,iBAAkB,YAAW,aAAa;IAC/C,WAAW,CACf,QAAQ,EAAE,gBAAgB,EAC1B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,eAAe,CAAA;KAAE,EACtG,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC;CA6DpB;AAED,qBAAa,mBAAmB;IAE5B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAFT,QAAQ,EAAE,gBAAgB,EAC1B,SAAS,EAAE,aAAa,EACxB,SAAS,EAAE,MAAM;IAG9B,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAiBtE,OAAO,CAAC,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAqBlE"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { request as httpRequest } from 'node:http';
|
|
2
|
+
import { request as httpsRequest } from 'node:https';
|
|
3
|
+
import { MAX_FRAME_BYTES, asNonEmptyString, asRecord, } from './protocol.js';
|
|
4
|
+
export class NodeHttpTransport {
|
|
5
|
+
async requestJson(endpoint, path, options, timeoutMs) {
|
|
6
|
+
const url = new URL(path.replace(/^\/+/, ''), endpoint.baseUrl);
|
|
7
|
+
if (options.query)
|
|
8
|
+
url.search = options.query.toString();
|
|
9
|
+
const body = options.body === undefined ? undefined : Buffer.from(JSON.stringify(options.body), 'utf8');
|
|
10
|
+
if (body && body.byteLength > MAX_FRAME_BYTES)
|
|
11
|
+
throw new Error('BCN HTTP request body exceeds 2 MiB');
|
|
12
|
+
const requestOptions = {
|
|
13
|
+
protocol: url.protocol,
|
|
14
|
+
hostname: url.hostname,
|
|
15
|
+
port: url.port || undefined,
|
|
16
|
+
path: `${url.pathname}${url.search}`,
|
|
17
|
+
method: options.method,
|
|
18
|
+
lookup: endpoint.lookup,
|
|
19
|
+
headers: {
|
|
20
|
+
accept: 'application/json',
|
|
21
|
+
...(body ? { 'content-type': 'application/json', 'content-length': String(body.byteLength) } : {}),
|
|
22
|
+
...options.headers,
|
|
23
|
+
},
|
|
24
|
+
agent: false,
|
|
25
|
+
};
|
|
26
|
+
// COSEC: endpoint resolution rejects non-public destinations (except exact
|
|
27
|
+
// loopback development), pins DNS, and this client never follows redirects.
|
|
28
|
+
// HTTP is an explicit deployment option; production operators should prefer HTTPS.
|
|
29
|
+
return new Promise((resolve, reject) => {
|
|
30
|
+
const request = (url.protocol === 'https:' ? httpsRequest : httpRequest)(requestOptions, response => {
|
|
31
|
+
let total = 0;
|
|
32
|
+
const chunks = [];
|
|
33
|
+
response.on('data', (chunk) => {
|
|
34
|
+
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
35
|
+
total += buffer.byteLength;
|
|
36
|
+
if (total > MAX_FRAME_BYTES) {
|
|
37
|
+
request.destroy(new Error('BCN HTTP response exceeds 2 MiB'));
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
chunks.push(buffer);
|
|
41
|
+
});
|
|
42
|
+
response.on('end', () => {
|
|
43
|
+
const status = response.statusCode ?? 0;
|
|
44
|
+
if (status < 200 || status >= 300) {
|
|
45
|
+
reject(new Error(`BCN HTTP request failed with status ${status}`));
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const raw = Buffer.concat(chunks).toString('utf8');
|
|
49
|
+
if (!raw) {
|
|
50
|
+
resolve({});
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
resolve(JSON.parse(raw));
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
reject(new Error('BCN HTTP response is not valid JSON'));
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
request.setTimeout(timeoutMs, () => request.destroy(new Error('BCN HTTP request timed out')));
|
|
62
|
+
request.on('error', error => reject(new Error('BCN HTTP request failed', { cause: error })));
|
|
63
|
+
if (body)
|
|
64
|
+
request.write(body);
|
|
65
|
+
request.end();
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
export class BcnOnboardingClient {
|
|
70
|
+
endpoint;
|
|
71
|
+
transport;
|
|
72
|
+
timeoutMs;
|
|
73
|
+
constructor(endpoint, transport, timeoutMs) {
|
|
74
|
+
this.endpoint = endpoint;
|
|
75
|
+
this.transport = transport;
|
|
76
|
+
this.timeoutMs = timeoutMs;
|
|
77
|
+
}
|
|
78
|
+
async register(token, botName) {
|
|
79
|
+
const query = new URLSearchParams({ token, 'bot-name': botName });
|
|
80
|
+
const response = asRecord(await this.transport.requestJson(this.endpoint, 'register', { method: 'POST', query }, this.timeoutMs));
|
|
81
|
+
const registeredName = asNonEmptyString(response?.bot_name);
|
|
82
|
+
const botUuid = asNonEmptyString(response?.bot_uuid);
|
|
83
|
+
const botToken = asNonEmptyString(response?.bot_token);
|
|
84
|
+
if (!registeredName || !botUuid || !botToken) {
|
|
85
|
+
throw new Error('BCN registration returned an incomplete Bot Session');
|
|
86
|
+
}
|
|
87
|
+
return { bot_name: registeredName, bot_uuid: botUuid, bot_token: botToken };
|
|
88
|
+
}
|
|
89
|
+
async onboard(session, config) {
|
|
90
|
+
const response = asRecord(await this.transport.requestJson(this.endpoint, 'bots/onboard', {
|
|
91
|
+
method: 'POST',
|
|
92
|
+
headers: { authorization: `Bearer ${session.botToken}` },
|
|
93
|
+
body: {
|
|
94
|
+
name: config.botName || session.botName,
|
|
95
|
+
summary: config.summary,
|
|
96
|
+
domains: config.domains,
|
|
97
|
+
skills: config.skills,
|
|
98
|
+
scopes: config.scopes,
|
|
99
|
+
},
|
|
100
|
+
}, this.timeoutMs));
|
|
101
|
+
if (response?.onboarded !== true || asNonEmptyString(response.bot_uuid) !== session.botUuid) {
|
|
102
|
+
throw new Error('BCN rejected Bot descriptor onboarding');
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=http-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-client.js","sourceRoot":"","sources":["../src/http-client.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import { Config, type Config as PluginConfig } from './config.js';
|
|
3
|
+
export declare const name = "deepseek-harness-channel-bcn";
|
|
4
|
+
export declare const inject: string[];
|
|
5
|
+
export { Config };
|
|
6
|
+
export type { Config as DeepSeekHarnessBcnConfig } from './config.js';
|
|
7
|
+
export declare function apply(ctx: Context, rawConfig: PluginConfig): Promise<() => Promise<void>>;
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAEnD,OAAO,EAAE,MAAM,EAAmB,KAAK,MAAM,IAAI,YAAY,EAAE,MAAM,aAAa,CAAC;AAInF,eAAO,MAAM,IAAI,iCAAiC,CAAC;AACnD,eAAO,MAAM,MAAM,UASlB,CAAC;AACF,OAAO,EAAE,MAAM,EAAE,CAAC;AAClB,YAAY,EAAE,MAAM,IAAI,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAEtE,wBAAsB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,CA0B/F"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { BcnBridge } from './bridge.js';
|
|
2
|
+
import { Config, normalizeConfig } from './config.js';
|
|
3
|
+
import { loadOrOnboardBotSession, persistBotSession } from './credentials.js';
|
|
4
|
+
import { BcnWsClient } from './ws-client.js';
|
|
5
|
+
export const name = 'deepseek-harness-channel-bcn';
|
|
6
|
+
export const inject = [
|
|
7
|
+
'agentDefaultModel',
|
|
8
|
+
'agentPresets',
|
|
9
|
+
'agents',
|
|
10
|
+
'credentials',
|
|
11
|
+
'sessions',
|
|
12
|
+
'sessionPersistence',
|
|
13
|
+
'systemPrompt',
|
|
14
|
+
'tools',
|
|
15
|
+
];
|
|
16
|
+
export { Config };
|
|
17
|
+
export async function apply(ctx, rawConfig) {
|
|
18
|
+
const config = normalizeConfig(rawConfig);
|
|
19
|
+
const log = ctx.logger(name);
|
|
20
|
+
if (!config.enabled) {
|
|
21
|
+
log.info('BCN channel is installed but disabled');
|
|
22
|
+
return async () => { };
|
|
23
|
+
}
|
|
24
|
+
const { session, endpoint } = await loadOrOnboardBotSession(ctx, config);
|
|
25
|
+
let bridge;
|
|
26
|
+
const client = new BcnWsClient({
|
|
27
|
+
endpoint,
|
|
28
|
+
session,
|
|
29
|
+
config,
|
|
30
|
+
status: () => bridge?.busy ? 'busy' : 'idle',
|
|
31
|
+
onSessionChanged: rotated => persistBotSession(ctx, config, rotated),
|
|
32
|
+
log,
|
|
33
|
+
});
|
|
34
|
+
bridge = new BcnBridge(ctx, client, config, log);
|
|
35
|
+
bridge.start();
|
|
36
|
+
client.start();
|
|
37
|
+
return async () => {
|
|
38
|
+
await bridge?.dispose();
|
|
39
|
+
await client.stop();
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,MAAM,EAAE,eAAe,EAA+B,MAAM,aAAa,CAAC;AACnF,OAAO,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC9E,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,MAAM,CAAC,MAAM,IAAI,GAAG,8BAA8B,CAAC;AACnD,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,mBAAmB;IACnB,cAAc;IACd,QAAQ;IACR,aAAa;IACb,UAAU;IACV,oBAAoB;IACpB,cAAc;IACd,OAAO;CACR,CAAC;AACF,OAAO,EAAE,MAAM,EAAE,CAAC;AAGlB,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,GAAY,EAAE,SAAuB;IAC/D,MAAM,MAAM,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC;IAC1C,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC7B,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,GAAG,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAC;QAClD,OAAO,KAAK,IAAI,EAAE,GAAE,CAAC,CAAC;IACxB,CAAC;IAED,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,MAAM,uBAAuB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACzE,IAAI,MAA6B,CAAC;IAClC,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC;QAC7B,QAAQ;QACR,OAAO;QACP,MAAM;QACN,MAAM,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM;QAC5C,gBAAgB,EAAE,OAAO,CAAC,EAAE,CAAC,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC;QACpE,GAAG;KACJ,CAAC,CAAC;IACH,MAAM,GAAG,IAAI,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC;IACjD,MAAM,CAAC,KAAK,EAAE,CAAC;IACf,MAAM,CAAC,KAAK,EAAE,CAAC;IAEf,OAAO,KAAK,IAAI,EAAE;QAChB,MAAM,MAAM,EAAE,OAAO,EAAE,CAAC;QACxB,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;IACtB,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
export declare const BCN_PROTOCOL_VERSION = 2;
|
|
2
|
+
export declare const MAX_FRAME_BYTES: number;
|
|
3
|
+
export interface RequestFrame {
|
|
4
|
+
type: 'req';
|
|
5
|
+
id: string;
|
|
6
|
+
method: string;
|
|
7
|
+
params: Record<string, unknown>;
|
|
8
|
+
}
|
|
9
|
+
export interface ResponseFrame {
|
|
10
|
+
type: 'res';
|
|
11
|
+
id: string;
|
|
12
|
+
ok: boolean;
|
|
13
|
+
payload?: Record<string, unknown>;
|
|
14
|
+
error?: {
|
|
15
|
+
code: string;
|
|
16
|
+
message: string;
|
|
17
|
+
retryable: boolean;
|
|
18
|
+
details?: unknown;
|
|
19
|
+
retry_after_ms?: number;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export interface EventFrame {
|
|
23
|
+
type: 'event';
|
|
24
|
+
event: string;
|
|
25
|
+
payload: Record<string, unknown>;
|
|
26
|
+
seq?: number;
|
|
27
|
+
}
|
|
28
|
+
export type BcnFrame = RequestFrame | ResponseFrame | EventFrame;
|
|
29
|
+
export interface BotSession {
|
|
30
|
+
version: 1;
|
|
31
|
+
endpoint: string;
|
|
32
|
+
botUuid: string;
|
|
33
|
+
botToken: string;
|
|
34
|
+
botName: string;
|
|
35
|
+
}
|
|
36
|
+
export interface RegisterBotResponse {
|
|
37
|
+
bot_name: string;
|
|
38
|
+
bot_uuid: string;
|
|
39
|
+
bot_token: string;
|
|
40
|
+
}
|
|
41
|
+
export interface BotConnectResponse {
|
|
42
|
+
is_new: boolean;
|
|
43
|
+
token: string;
|
|
44
|
+
bot_uuid: string;
|
|
45
|
+
protocol_version: number;
|
|
46
|
+
min_supported_version?: number;
|
|
47
|
+
env?: Record<string, string>;
|
|
48
|
+
}
|
|
49
|
+
export interface MessageContent {
|
|
50
|
+
role: string;
|
|
51
|
+
content: Array<Record<string, unknown>>;
|
|
52
|
+
timestamp: number;
|
|
53
|
+
}
|
|
54
|
+
export interface ChatSendParams {
|
|
55
|
+
session_key: string;
|
|
56
|
+
bcs_group_id: string;
|
|
57
|
+
bcs_session_id?: string;
|
|
58
|
+
message: MessageContent;
|
|
59
|
+
channel: Record<string, unknown>;
|
|
60
|
+
session_context: Record<string, unknown>;
|
|
61
|
+
timeout_ms?: number;
|
|
62
|
+
idempotency_key?: string;
|
|
63
|
+
tags?: string[];
|
|
64
|
+
attachments?: Array<Record<string, unknown>>;
|
|
65
|
+
}
|
|
66
|
+
export interface ChatInjectParams {
|
|
67
|
+
session_key: string;
|
|
68
|
+
bcs_group_id: string;
|
|
69
|
+
bcs_session_id?: string;
|
|
70
|
+
message: MessageContent;
|
|
71
|
+
channel: Record<string, unknown>;
|
|
72
|
+
session_context: Record<string, unknown>;
|
|
73
|
+
tags?: string[];
|
|
74
|
+
attachments?: Array<Record<string, unknown>>;
|
|
75
|
+
}
|
|
76
|
+
export interface RouteSelector {
|
|
77
|
+
type: 'name' | 'bot';
|
|
78
|
+
value: string;
|
|
79
|
+
}
|
|
80
|
+
export interface ChatEventRouting {
|
|
81
|
+
responders: Array<{
|
|
82
|
+
type: string;
|
|
83
|
+
value?: string;
|
|
84
|
+
}>;
|
|
85
|
+
mode: 'required' | 'optional';
|
|
86
|
+
reason: string;
|
|
87
|
+
include_self: boolean;
|
|
88
|
+
dedupe_key?: string;
|
|
89
|
+
}
|
|
90
|
+
export interface PendingRouteIntent {
|
|
91
|
+
responders: Array<{
|
|
92
|
+
type: string;
|
|
93
|
+
value?: string;
|
|
94
|
+
}>;
|
|
95
|
+
mode: 'required' | 'optional';
|
|
96
|
+
reason: string;
|
|
97
|
+
includeSelf: boolean;
|
|
98
|
+
dedupeKey?: string;
|
|
99
|
+
}
|
|
100
|
+
export declare function asRecord(value: unknown): Record<string, unknown> | undefined;
|
|
101
|
+
export declare function asNonEmptyString(value: unknown): string | undefined;
|
|
102
|
+
export declare function parseFrame(value: unknown): BcnFrame | undefined;
|
|
103
|
+
export declare function parseBotSession(value: string): BotSession;
|
|
104
|
+
export declare function parseChatSendParams(value: unknown): ChatSendParams;
|
|
105
|
+
export declare function parseChatInjectParams(value: unknown): ChatInjectParams;
|
|
106
|
+
export declare function extractMessageText(message: MessageContent): string;
|
|
107
|
+
//# sourceMappingURL=protocol.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,oBAAoB,IAAI,CAAC;AACtC,eAAO,MAAM,eAAe,QAAkB,CAAC;AAE/C,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,KAAK,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,KAAK,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,KAAK,CAAC,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,EAAE,OAAO,CAAC;QACnB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC;CACH;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,QAAQ,GAAG,YAAY,GAAG,aAAa,GAAG,UAAU,CAAC;AAEjE,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,CAAC,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;IACzB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACxC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,cAAc,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,WAAW,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAC9C;AAED,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,cAAc,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACzC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,WAAW,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAC9C;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACpD,IAAI,EAAE,UAAU,GAAG,UAAU,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACpD,IAAI,EAAE,UAAU,GAAG,UAAU,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAG5E;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAInE;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,QAAQ,GAAG,SAAS,CAqC/D;AAoBD,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAgBzD;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,cAAc,CAElE;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,gBAAgB,CAEtE;AAgDD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,cAAc,GAAG,MAAM,CASlE"}
|
package/dist/protocol.js
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
export const BCN_PROTOCOL_VERSION = 2;
|
|
2
|
+
export const MAX_FRAME_BYTES = 2 * 1024 * 1024;
|
|
3
|
+
export function asRecord(value) {
|
|
4
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
5
|
+
return undefined;
|
|
6
|
+
return value;
|
|
7
|
+
}
|
|
8
|
+
export function asNonEmptyString(value) {
|
|
9
|
+
if (typeof value !== 'string')
|
|
10
|
+
return undefined;
|
|
11
|
+
const trimmed = value.trim();
|
|
12
|
+
return trimmed || undefined;
|
|
13
|
+
}
|
|
14
|
+
export function parseFrame(value) {
|
|
15
|
+
const frame = asRecord(value);
|
|
16
|
+
const id = asNonEmptyString(frame?.id);
|
|
17
|
+
if (!frame || !asNonEmptyString(frame.type))
|
|
18
|
+
return undefined;
|
|
19
|
+
if (frame.type === 'res') {
|
|
20
|
+
if (!id || typeof frame.ok !== 'boolean')
|
|
21
|
+
return undefined;
|
|
22
|
+
const payload = frame.payload === undefined ? undefined : asRecord(frame.payload);
|
|
23
|
+
if (frame.payload !== undefined && !payload)
|
|
24
|
+
return undefined;
|
|
25
|
+
const error = frame.error === undefined ? undefined : parseResponseError(frame.error);
|
|
26
|
+
if (frame.error !== undefined && !error)
|
|
27
|
+
return undefined;
|
|
28
|
+
if (!frame.ok && !error)
|
|
29
|
+
return undefined;
|
|
30
|
+
return {
|
|
31
|
+
type: 'res',
|
|
32
|
+
id,
|
|
33
|
+
ok: frame.ok,
|
|
34
|
+
...(payload ? { payload } : {}),
|
|
35
|
+
...(error ? { error } : {}),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
if (frame.type === 'req') {
|
|
39
|
+
const method = asNonEmptyString(frame.method);
|
|
40
|
+
const params = asRecord(frame.params);
|
|
41
|
+
if (!id || !method || !params)
|
|
42
|
+
return undefined;
|
|
43
|
+
return { type: 'req', id, method, params };
|
|
44
|
+
}
|
|
45
|
+
if (frame.type === 'event') {
|
|
46
|
+
const event = asNonEmptyString(frame.event);
|
|
47
|
+
const payload = asRecord(frame.payload);
|
|
48
|
+
const seq = frame.seq === undefined ? undefined : Number(frame.seq);
|
|
49
|
+
if (!event || !payload || (seq !== undefined && (!Number.isSafeInteger(seq) || seq < 0)))
|
|
50
|
+
return undefined;
|
|
51
|
+
return { type: 'event', event, payload, ...(seq !== undefined ? { seq } : {}) };
|
|
52
|
+
}
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
function parseResponseError(value) {
|
|
56
|
+
const error = asRecord(value);
|
|
57
|
+
const code = asNonEmptyString(error?.code);
|
|
58
|
+
const message = asNonEmptyString(error?.message);
|
|
59
|
+
if (!error || !code || !message || typeof error.retryable !== 'boolean')
|
|
60
|
+
return undefined;
|
|
61
|
+
const retryAfterMs = error.retry_after_ms;
|
|
62
|
+
if (retryAfterMs !== undefined && (!Number.isSafeInteger(retryAfterMs) || Number(retryAfterMs) < 0)) {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
code,
|
|
67
|
+
message,
|
|
68
|
+
retryable: error.retryable,
|
|
69
|
+
...(Object.hasOwn(error, 'details') ? { details: error.details } : {}),
|
|
70
|
+
...(retryAfterMs !== undefined ? { retry_after_ms: Number(retryAfterMs) } : {}),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
export function parseBotSession(value) {
|
|
74
|
+
let parsed;
|
|
75
|
+
try {
|
|
76
|
+
parsed = JSON.parse(value);
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
throw new Error('BCN Bot Session credential is not valid JSON');
|
|
80
|
+
}
|
|
81
|
+
const record = asRecord(parsed);
|
|
82
|
+
const endpoint = asNonEmptyString(record?.endpoint);
|
|
83
|
+
const botUuid = asNonEmptyString(record?.botUuid);
|
|
84
|
+
const botToken = asNonEmptyString(record?.botToken);
|
|
85
|
+
const botName = asNonEmptyString(record?.botName);
|
|
86
|
+
if (record?.version !== 1 || !endpoint || !botUuid || !botToken || !botName) {
|
|
87
|
+
throw new Error('BCN Bot Session credential has an unsupported or incomplete shape');
|
|
88
|
+
}
|
|
89
|
+
return { version: 1, endpoint, botUuid, botToken, botName };
|
|
90
|
+
}
|
|
91
|
+
export function parseChatSendParams(value) {
|
|
92
|
+
return parseChatParams(value, true);
|
|
93
|
+
}
|
|
94
|
+
export function parseChatInjectParams(value) {
|
|
95
|
+
return parseChatParams(value, false);
|
|
96
|
+
}
|
|
97
|
+
function parseChatParams(value, allowSendFields) {
|
|
98
|
+
const record = asRecord(value);
|
|
99
|
+
const sessionKey = asNonEmptyString(record?.session_key);
|
|
100
|
+
const groupId = asNonEmptyString(record?.bcs_group_id);
|
|
101
|
+
const message = asRecord(record?.message);
|
|
102
|
+
const channel = asRecord(record?.channel);
|
|
103
|
+
const sessionContext = asRecord(record?.session_context);
|
|
104
|
+
if (!record || !sessionKey || !groupId || !message || !channel || !sessionContext) {
|
|
105
|
+
throw new Error('chat params require session_key, bcs_group_id, message, channel, and session_context');
|
|
106
|
+
}
|
|
107
|
+
if (!Array.isArray(message.content) || !Number.isFinite(message.timestamp) || typeof message.role !== 'string') {
|
|
108
|
+
throw new Error('chat message has an invalid shape');
|
|
109
|
+
}
|
|
110
|
+
const content = message.content.map((block) => {
|
|
111
|
+
const item = asRecord(block);
|
|
112
|
+
if (!item || !asNonEmptyString(item.type))
|
|
113
|
+
throw new Error('chat message contains an invalid content block');
|
|
114
|
+
return item;
|
|
115
|
+
});
|
|
116
|
+
const bcsSessionId = asNonEmptyString(record.bcs_session_id);
|
|
117
|
+
const attachments = Array.isArray(record.attachments)
|
|
118
|
+
? record.attachments.flatMap((item) => {
|
|
119
|
+
const attachment = asRecord(item);
|
|
120
|
+
return attachment ? [attachment] : [];
|
|
121
|
+
})
|
|
122
|
+
: undefined;
|
|
123
|
+
const base = {
|
|
124
|
+
session_key: sessionKey,
|
|
125
|
+
bcs_group_id: groupId,
|
|
126
|
+
...(bcsSessionId ? { bcs_session_id: bcsSessionId } : {}),
|
|
127
|
+
message: { role: message.role, content, timestamp: Number(message.timestamp) },
|
|
128
|
+
channel,
|
|
129
|
+
session_context: sessionContext,
|
|
130
|
+
...(Array.isArray(record.tags) ? { tags: record.tags.filter((item) => typeof item === 'string') } : {}),
|
|
131
|
+
...(attachments ? { attachments } : {}),
|
|
132
|
+
};
|
|
133
|
+
if (!allowSendFields)
|
|
134
|
+
return base;
|
|
135
|
+
const idempotencyKey = asNonEmptyString(record.idempotency_key);
|
|
136
|
+
return {
|
|
137
|
+
...base,
|
|
138
|
+
...(typeof record.timeout_ms === 'number' && Number.isFinite(record.timeout_ms)
|
|
139
|
+
? { timeout_ms: record.timeout_ms }
|
|
140
|
+
: {}),
|
|
141
|
+
...(idempotencyKey ? { idempotency_key: idempotencyKey } : {}),
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
export function extractMessageText(message) {
|
|
145
|
+
const chunks = [];
|
|
146
|
+
for (const block of message.content) {
|
|
147
|
+
if (block.type === 'text' && typeof block.text === 'string')
|
|
148
|
+
chunks.push(block.text);
|
|
149
|
+
}
|
|
150
|
+
const text = chunks.join('').trim();
|
|
151
|
+
if (!text)
|
|
152
|
+
throw new Error('BCN message contains no visible text');
|
|
153
|
+
if (Buffer.byteLength(text, 'utf8') > 1024 * 1024)
|
|
154
|
+
throw new Error('BCN message text exceeds 1 MiB');
|
|
155
|
+
return text;
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=protocol.js.map
|