aweshare 0.2.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/LICENSE +21 -0
- package/README.md +246 -0
- package/apps/agent/dist/adapters.d.ts +15 -0
- package/apps/agent/dist/adapters.js +25 -0
- package/apps/agent/dist/adapters.js.map +1 -0
- package/apps/agent/dist/cli.d.ts +2 -0
- package/apps/agent/dist/cli.js +175 -0
- package/apps/agent/dist/cli.js.map +1 -0
- package/apps/agent/dist/config.d.ts +38 -0
- package/apps/agent/dist/config.js +150 -0
- package/apps/agent/dist/config.js.map +1 -0
- package/apps/agent/dist/connection.d.ts +40 -0
- package/apps/agent/dist/connection.js +359 -0
- package/apps/agent/dist/connection.js.map +1 -0
- package/apps/agent/dist/doctor.d.ts +14 -0
- package/apps/agent/dist/doctor.js +125 -0
- package/apps/agent/dist/doctor.js.map +1 -0
- package/apps/agent/dist/health.d.ts +15 -0
- package/apps/agent/dist/health.js +45 -0
- package/apps/agent/dist/health.js.map +1 -0
- package/apps/agent/dist/index.d.ts +5 -0
- package/apps/agent/dist/index.js +6 -0
- package/apps/agent/dist/index.js.map +1 -0
- package/apps/agent/package.json +20 -0
- package/apps/hub/dist/admin.d.ts +10 -0
- package/apps/hub/dist/admin.js +208 -0
- package/apps/hub/dist/admin.js.map +1 -0
- package/apps/hub/dist/auth.d.ts +17 -0
- package/apps/hub/dist/auth.js +28 -0
- package/apps/hub/dist/auth.js.map +1 -0
- package/apps/hub/dist/cli.d.ts +2 -0
- package/apps/hub/dist/cli.js +243 -0
- package/apps/hub/dist/cli.js.map +1 -0
- package/apps/hub/dist/config.d.ts +25 -0
- package/apps/hub/dist/config.js +53 -0
- package/apps/hub/dist/config.js.map +1 -0
- package/apps/hub/dist/consumer.d.ts +18 -0
- package/apps/hub/dist/consumer.js +157 -0
- package/apps/hub/dist/consumer.js.map +1 -0
- package/apps/hub/dist/db.d.ts +91 -0
- package/apps/hub/dist/db.js +236 -0
- package/apps/hub/dist/db.js.map +1 -0
- package/apps/hub/dist/http.d.ts +31 -0
- package/apps/hub/dist/http.js +118 -0
- package/apps/hub/dist/http.js.map +1 -0
- package/apps/hub/dist/limiter.d.ts +35 -0
- package/apps/hub/dist/limiter.js +78 -0
- package/apps/hub/dist/limiter.js.map +1 -0
- package/apps/hub/dist/limits.d.ts +30 -0
- package/apps/hub/dist/limits.js +52 -0
- package/apps/hub/dist/limits.js.map +1 -0
- package/apps/hub/dist/meter.d.ts +25 -0
- package/apps/hub/dist/meter.js +135 -0
- package/apps/hub/dist/meter.js.map +1 -0
- package/apps/hub/dist/sanitize.d.ts +3 -0
- package/apps/hub/dist/sanitize.js +56 -0
- package/apps/hub/dist/sanitize.js.map +1 -0
- package/apps/hub/dist/server.d.ts +25 -0
- package/apps/hub/dist/server.js +77 -0
- package/apps/hub/dist/server.js.map +1 -0
- package/apps/hub/dist/tokens.d.ts +9 -0
- package/apps/hub/dist/tokens.js +35 -0
- package/apps/hub/dist/tokens.js.map +1 -0
- package/apps/hub/dist/tunnel.d.ts +108 -0
- package/apps/hub/dist/tunnel.js +424 -0
- package/apps/hub/dist/tunnel.js.map +1 -0
- package/apps/hub/package.json +21 -0
- package/bin/aweshare.mjs +43 -0
- package/package.json +47 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
import { isValidAlias, PROTOCOLS } from 'aweshare-protocol';
|
|
5
|
+
import { parse as parseToml } from 'smol-toml';
|
|
6
|
+
export function agentDir(env = process.env) {
|
|
7
|
+
return env.AWESHARE_AGENT_DIR ?? join(homedir(), '.aweshare');
|
|
8
|
+
}
|
|
9
|
+
export class ConfigError extends Error {
|
|
10
|
+
problems;
|
|
11
|
+
constructor(message, problems) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.problems = problems;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export function loadAgentConfig(dir) {
|
|
17
|
+
const configPath = join(dir, 'config.toml');
|
|
18
|
+
const secretsPath = join(dir, 'secrets.json');
|
|
19
|
+
if (!existsSync(configPath)) {
|
|
20
|
+
throw new ConfigError(`no config at ${configPath} — run 'aweshare agent init' first`, []);
|
|
21
|
+
}
|
|
22
|
+
let raw;
|
|
23
|
+
try {
|
|
24
|
+
raw = parseToml(readFileSync(configPath, 'utf8'));
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
throw new ConfigError(`config.toml is not valid TOML: ${err instanceof Error ? err.message : err}`, []);
|
|
28
|
+
}
|
|
29
|
+
const secrets = existsSync(secretsPath)
|
|
30
|
+
? JSON.parse(readFileSync(secretsPath, 'utf8'))
|
|
31
|
+
: {};
|
|
32
|
+
const problems = [];
|
|
33
|
+
const hubUrl = typeof raw.hubUrl === 'string' ? raw.hubUrl : '';
|
|
34
|
+
if (!/^https?:\/\//.test(hubUrl))
|
|
35
|
+
problems.push('hubUrl must be an http(s) URL');
|
|
36
|
+
const token = typeof raw.token === 'string' ? raw.token : '';
|
|
37
|
+
if (!token.startsWith('asp_'))
|
|
38
|
+
problems.push('token must be a producer token (asp_...)');
|
|
39
|
+
const backends = [];
|
|
40
|
+
const seenBackendIds = new Set();
|
|
41
|
+
if (raw.backends !== undefined && !Array.isArray(raw.backends)) {
|
|
42
|
+
problems.push('backends must be a [[backends]] list');
|
|
43
|
+
}
|
|
44
|
+
for (const b of Array.isArray(raw.backends) ? raw.backends : []) {
|
|
45
|
+
const id = typeof b.id === 'string' ? b.id : '';
|
|
46
|
+
const protocol = b.protocol;
|
|
47
|
+
const baseUrl = typeof b.baseUrl === 'string' ? b.baseUrl : '';
|
|
48
|
+
const keyRef = typeof b.keyRef === 'string' ? b.keyRef : undefined;
|
|
49
|
+
if (!id)
|
|
50
|
+
problems.push('backend: id is required');
|
|
51
|
+
else if (seenBackendIds.has(id))
|
|
52
|
+
problems.push(`backend: duplicate id '${id}'`);
|
|
53
|
+
else
|
|
54
|
+
seenBackendIds.add(id);
|
|
55
|
+
if (!PROTOCOLS.includes(protocol)) {
|
|
56
|
+
problems.push(`backend '${id || '?'}': protocol must be openai or anthropic`);
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (!/^https?:\/\//.test(baseUrl)) {
|
|
60
|
+
problems.push(`backend '${id}': baseUrl must be an http(s) URL`);
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (keyRef && !(keyRef in secrets)) {
|
|
64
|
+
problems.push(`backend '${id}': keyRef '${keyRef}' not found in secrets.json`);
|
|
65
|
+
}
|
|
66
|
+
backends.push({ id, protocol: protocol, baseUrl, keyRef });
|
|
67
|
+
}
|
|
68
|
+
const backendIds = new Set(backends.map((b) => b.id));
|
|
69
|
+
const offerings = [];
|
|
70
|
+
if (raw.offerings !== undefined && !Array.isArray(raw.offerings)) {
|
|
71
|
+
problems.push('offerings must be an [[offerings]] list');
|
|
72
|
+
}
|
|
73
|
+
for (const o of Array.isArray(raw.offerings)
|
|
74
|
+
? raw.offerings
|
|
75
|
+
: []) {
|
|
76
|
+
const alias = typeof o.alias === 'string' ? o.alias : '';
|
|
77
|
+
const backend = typeof o.backend === 'string' ? o.backend : '';
|
|
78
|
+
const upstreamModel = typeof o.upstreamModel === 'string' ? o.upstreamModel : '';
|
|
79
|
+
const maxConcurrency = o.maxConcurrency === undefined ? 1 : Number(o.maxConcurrency);
|
|
80
|
+
if (!isValidAlias(alias)) {
|
|
81
|
+
problems.push(`offering: invalid alias '${alias}' (namespace/name, lowercase)`);
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if (!backendIds.has(backend)) {
|
|
85
|
+
problems.push(`offering '${alias}': unknown backend '${backend}'`);
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (!upstreamModel) {
|
|
89
|
+
problems.push(`offering '${alias}': upstreamModel is required (the real backend model id)`);
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (!Number.isInteger(maxConcurrency) || maxConcurrency < 1 || maxConcurrency > 64) {
|
|
93
|
+
problems.push(`offering '${alias}': maxConcurrency must be an integer 1..64`);
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
offerings.push({ alias, backend, upstreamModel, maxConcurrency });
|
|
97
|
+
}
|
|
98
|
+
if (problems.length > 0) {
|
|
99
|
+
throw new ConfigError(`config.toml has problems:\n - ${problems.join('\n - ')}`, problems);
|
|
100
|
+
}
|
|
101
|
+
return { config: { hubUrl: hubUrl.replace(/\/+$/, ''), token, backends, offerings }, secrets };
|
|
102
|
+
}
|
|
103
|
+
/** tmp+rename atomic write with owner-only permissions. */
|
|
104
|
+
export function writeFileAtomic(path, content, mode = 0o600) {
|
|
105
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
106
|
+
const tmp = `${path}.tmp-${process.pid}`;
|
|
107
|
+
writeFileSync(tmp, content, { mode });
|
|
108
|
+
renameSync(tmp, path);
|
|
109
|
+
}
|
|
110
|
+
export const CONFIG_TEMPLATE = `# aweshare agent configuration (~/.aweshare/config.toml)
|
|
111
|
+
# Secrets live in ~/.aweshare/secrets.json and never leave this machine.
|
|
112
|
+
|
|
113
|
+
hubUrl = "http://127.0.0.1:8787"
|
|
114
|
+
token = "asp_PASTE_PRODUCER_TOKEN"
|
|
115
|
+
|
|
116
|
+
# Backends hold the upstream API. baseUrl follows the SDK convention:
|
|
117
|
+
# openai-style (OpenAI/Ollama/vLLM/LM Studio) includes /v1, e.g. http://127.0.0.1:11434/v1
|
|
118
|
+
# anthropic-style excludes /v1, e.g. https://api.anthropic.com
|
|
119
|
+
# responses-style includes the version path, e.g. https://open.bigmodel.cn/api/v1
|
|
120
|
+
[[backends]]
|
|
121
|
+
id = "ollama"
|
|
122
|
+
protocol = "openai"
|
|
123
|
+
baseUrl = "http://127.0.0.1:11434/v1"
|
|
124
|
+
# keyRef = "ollama-key" # optional; keys live in secrets.json
|
|
125
|
+
|
|
126
|
+
[[backends]]
|
|
127
|
+
id = "openai"
|
|
128
|
+
protocol = "openai"
|
|
129
|
+
baseUrl = "https://api.openai.com/v1"
|
|
130
|
+
keyRef = "openai-key"
|
|
131
|
+
|
|
132
|
+
# Offerings map a public alias (namespace/name) to a backend model.
|
|
133
|
+
# The namespace must match your producer name on the hub.
|
|
134
|
+
[[offerings]]
|
|
135
|
+
alias = "YOUR_NAME/qwen2.5.7b"
|
|
136
|
+
backend = "ollama"
|
|
137
|
+
upstreamModel = "qwen2.5:7b" # must match 'ollama list' exactly, including the tag
|
|
138
|
+
maxConcurrency = 1 # start at 1 for local models
|
|
139
|
+
|
|
140
|
+
[[offerings]]
|
|
141
|
+
alias = "YOUR_NAME/gpt-4o"
|
|
142
|
+
backend = "openai"
|
|
143
|
+
upstreamModel = "gpt-4o-2024-11-20"
|
|
144
|
+
maxConcurrency = 4
|
|
145
|
+
`;
|
|
146
|
+
export const SECRETS_TEMPLATE = `{
|
|
147
|
+
"openai-key": "sk-PASTE_YOUR_KEY"
|
|
148
|
+
}
|
|
149
|
+
`;
|
|
150
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type RegisteredMessage } from 'aweshare-protocol';
|
|
2
|
+
import { type Logger } from 'pino';
|
|
3
|
+
import { type ResolvedBackend } from './adapters.js';
|
|
4
|
+
import type { AgentConfig } from './config.js';
|
|
5
|
+
export interface AgentConnectionOptions {
|
|
6
|
+
config: AgentConfig;
|
|
7
|
+
secrets: Record<string, string>;
|
|
8
|
+
log?: Logger;
|
|
9
|
+
}
|
|
10
|
+
/** Outbound-only tunnel client with reconnect, heartbeat and health reporting. */
|
|
11
|
+
export declare class AgentConnection {
|
|
12
|
+
private readonly opts;
|
|
13
|
+
private ws;
|
|
14
|
+
private stopped;
|
|
15
|
+
private backoffMs;
|
|
16
|
+
private jobs;
|
|
17
|
+
private health;
|
|
18
|
+
private heartbeatTimer;
|
|
19
|
+
private probeTimer;
|
|
20
|
+
private backends;
|
|
21
|
+
private registeredWaiters;
|
|
22
|
+
private readonly log;
|
|
23
|
+
constructor(opts: AgentConnectionOptions);
|
|
24
|
+
/** In-flight jobs; completed or canceled jobs are removed. Exposed for tests. */
|
|
25
|
+
get activeJobCount(): number;
|
|
26
|
+
/** Resolves after the next successful register (used by tests and doctor). */
|
|
27
|
+
whenRegistered(): Promise<RegisteredMessage>;
|
|
28
|
+
start(): Promise<void>;
|
|
29
|
+
stop(): Promise<void>;
|
|
30
|
+
private runConnection;
|
|
31
|
+
private register;
|
|
32
|
+
private sendHeartbeat;
|
|
33
|
+
/** Minimal live probe for degraded backends; success clears the degraded state. */
|
|
34
|
+
private probeDegraded;
|
|
35
|
+
}
|
|
36
|
+
export declare function probeTarget(backend: ResolvedBackend): {
|
|
37
|
+
url: string;
|
|
38
|
+
headers: Record<string, string>;
|
|
39
|
+
};
|
|
40
|
+
export declare function probeBody(model: string, protocol?: 'openai' | 'anthropic' | 'responses'): Record<string, unknown>;
|
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
import { BACKPRESSURE_LIMIT_BYTES, chunkBody, decodeChunkFrame, parseControlMessage, WIRE_VERSION, } from 'aweshare-protocol';
|
|
2
|
+
import pino, {} from 'pino';
|
|
3
|
+
import { WebSocket } from 'ws';
|
|
4
|
+
import { buildUpstreamRequest } from './adapters.js';
|
|
5
|
+
import { classifyStatus, HealthGate } from './health.js';
|
|
6
|
+
const RECONNECT_BASE_MS = 1500;
|
|
7
|
+
const RECONNECT_MAX_MS = 15_000;
|
|
8
|
+
const HEARTBEAT_INTERVAL_MS = 15_000;
|
|
9
|
+
const DEGRADED_PROBE_INTERVAL_MS = 30_000;
|
|
10
|
+
const CONNECT_TIMEOUT_MS = 30_000;
|
|
11
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
12
|
+
/** One tunneled request: collect body chunks, call upstream, stream back. */
|
|
13
|
+
class Job {
|
|
14
|
+
ws;
|
|
15
|
+
backend;
|
|
16
|
+
health;
|
|
17
|
+
msg;
|
|
18
|
+
log;
|
|
19
|
+
onDone;
|
|
20
|
+
chunks = [];
|
|
21
|
+
controller = new AbortController();
|
|
22
|
+
aborted = false;
|
|
23
|
+
executed = false;
|
|
24
|
+
constructor(ws, backend, health, msg, log,
|
|
25
|
+
/** Called exactly once when the job settles; the connection drops it from its map. */
|
|
26
|
+
onDone = () => { }) {
|
|
27
|
+
this.ws = ws;
|
|
28
|
+
this.backend = backend;
|
|
29
|
+
this.health = health;
|
|
30
|
+
this.msg = msg;
|
|
31
|
+
this.log = log;
|
|
32
|
+
this.onDone = onDone;
|
|
33
|
+
}
|
|
34
|
+
onChunk(payload) {
|
|
35
|
+
this.chunks.push(Buffer.from(payload));
|
|
36
|
+
}
|
|
37
|
+
abort() {
|
|
38
|
+
this.aborted = true;
|
|
39
|
+
this.controller.abort();
|
|
40
|
+
}
|
|
41
|
+
onEnd() {
|
|
42
|
+
if (this.executed)
|
|
43
|
+
return;
|
|
44
|
+
this.executed = true;
|
|
45
|
+
void this.execute().finally(() => this.onDone(this.msg.requestId));
|
|
46
|
+
}
|
|
47
|
+
async execute() {
|
|
48
|
+
const { requestId } = this.msg;
|
|
49
|
+
this.log.debug(`request ${requestId} executing against ${this.backend.baseUrl}`);
|
|
50
|
+
if (this.aborted || this.ws.readyState !== WebSocket.OPEN)
|
|
51
|
+
return;
|
|
52
|
+
const { url, headers } = buildUpstreamRequest(this.backend, this.msg);
|
|
53
|
+
// head/connect phase timeout; streaming itself has no deadline (consumer cancel rules)
|
|
54
|
+
const connectTimer = setTimeout(() => this.controller.abort(new Error('upstream connect timeout')), CONNECT_TIMEOUT_MS);
|
|
55
|
+
try {
|
|
56
|
+
const resp = await fetch(url, {
|
|
57
|
+
method: this.msg.method,
|
|
58
|
+
headers,
|
|
59
|
+
// GET/HEAD must carry no body, even an empty one
|
|
60
|
+
body: this.chunks.length > 0 ? Buffer.concat(this.chunks) : undefined,
|
|
61
|
+
signal: this.controller.signal,
|
|
62
|
+
redirect: 'manual',
|
|
63
|
+
});
|
|
64
|
+
clearTimeout(connectTimer);
|
|
65
|
+
this.log.debug(`request ${requestId} upstream ${this.backend.id} -> ${resp.status}`);
|
|
66
|
+
const reason = classifyStatus(resp.status);
|
|
67
|
+
this.health.record(this.backend.id, reason === null, reason ?? undefined);
|
|
68
|
+
if (this.aborted || this.ws.readyState !== WebSocket.OPEN)
|
|
69
|
+
return;
|
|
70
|
+
this.send({
|
|
71
|
+
type: 'response.head',
|
|
72
|
+
requestId,
|
|
73
|
+
status: resp.status,
|
|
74
|
+
headers: pickHeaders(resp),
|
|
75
|
+
});
|
|
76
|
+
// upstream HTTP errors pass through transparently: status + body relayed as-is
|
|
77
|
+
if (resp.body) {
|
|
78
|
+
for await (const chunk of resp.body) {
|
|
79
|
+
if (this.aborted || this.ws.readyState !== WebSocket.OPEN)
|
|
80
|
+
return;
|
|
81
|
+
for (const frame of chunkBody(requestId, chunk)) {
|
|
82
|
+
await this.waitForDrain();
|
|
83
|
+
if (this.aborted)
|
|
84
|
+
return;
|
|
85
|
+
this.ws.send(frame);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
this.send({ type: 'response.end', requestId });
|
|
90
|
+
}
|
|
91
|
+
catch (err) {
|
|
92
|
+
clearTimeout(connectTimer);
|
|
93
|
+
if (this.aborted)
|
|
94
|
+
return;
|
|
95
|
+
this.log.warn(`request ${requestId} upstream ${this.backend.id} failed: ${err instanceof Error ? err.message : err}`);
|
|
96
|
+
this.health.record(this.backend.id, false, 'NETWORK');
|
|
97
|
+
this.send({
|
|
98
|
+
type: 'response.error',
|
|
99
|
+
requestId,
|
|
100
|
+
code: 'BACKEND_UNREACHABLE',
|
|
101
|
+
message: `upstream ${this.backend.id} failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
send(msg) {
|
|
106
|
+
if (this.ws.readyState === WebSocket.OPEN)
|
|
107
|
+
this.ws.send(JSON.stringify(msg));
|
|
108
|
+
}
|
|
109
|
+
async waitForDrain() {
|
|
110
|
+
while (this.ws.bufferedAmount > BACKPRESSURE_LIMIT_BYTES) {
|
|
111
|
+
await sleep(20);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/** undici decompresses gzip/br; relayed bytes are identity, so drop encoding markers. */
|
|
116
|
+
function pickHeaders(resp) {
|
|
117
|
+
const out = {};
|
|
118
|
+
const skip = new Set([
|
|
119
|
+
'transfer-encoding',
|
|
120
|
+
'content-length',
|
|
121
|
+
'content-encoding',
|
|
122
|
+
'connection',
|
|
123
|
+
'keep-alive',
|
|
124
|
+
'set-cookie',
|
|
125
|
+
]);
|
|
126
|
+
for (const [key, value] of resp.headers) {
|
|
127
|
+
const lower = key.toLowerCase();
|
|
128
|
+
if (skip.has(lower) || lower.startsWith('proxy-'))
|
|
129
|
+
continue;
|
|
130
|
+
out[lower] = value;
|
|
131
|
+
}
|
|
132
|
+
return out;
|
|
133
|
+
}
|
|
134
|
+
/** Outbound-only tunnel client with reconnect, heartbeat and health reporting. */
|
|
135
|
+
export class AgentConnection {
|
|
136
|
+
opts;
|
|
137
|
+
ws = null;
|
|
138
|
+
stopped = true;
|
|
139
|
+
backoffMs = RECONNECT_BASE_MS;
|
|
140
|
+
jobs = new Map();
|
|
141
|
+
health = new HealthGate();
|
|
142
|
+
heartbeatTimer = null;
|
|
143
|
+
probeTimer = null;
|
|
144
|
+
backends;
|
|
145
|
+
registeredWaiters = [];
|
|
146
|
+
log;
|
|
147
|
+
constructor(opts) {
|
|
148
|
+
this.opts = opts;
|
|
149
|
+
this.log = opts.log ?? pino({ level: process.env.AWESHARE_LOG ?? 'info' });
|
|
150
|
+
this.backends = new Map(opts.config.backends.map((b) => [
|
|
151
|
+
b.id,
|
|
152
|
+
{ ...b, apiKey: b.keyRef ? opts.secrets[b.keyRef] : undefined },
|
|
153
|
+
]));
|
|
154
|
+
}
|
|
155
|
+
/** In-flight jobs; completed or canceled jobs are removed. Exposed for tests. */
|
|
156
|
+
get activeJobCount() {
|
|
157
|
+
return this.jobs.size;
|
|
158
|
+
}
|
|
159
|
+
/** Resolves after the next successful register (used by tests and doctor). */
|
|
160
|
+
whenRegistered() {
|
|
161
|
+
return new Promise((resolve) => this.registeredWaiters.push(resolve));
|
|
162
|
+
}
|
|
163
|
+
async start() {
|
|
164
|
+
this.stopped = false;
|
|
165
|
+
this.heartbeatTimer = setInterval(() => this.sendHeartbeat(), HEARTBEAT_INTERVAL_MS);
|
|
166
|
+
this.probeTimer = setInterval(() => void this.probeDegraded(), DEGRADED_PROBE_INTERVAL_MS);
|
|
167
|
+
while (!this.stopped) {
|
|
168
|
+
try {
|
|
169
|
+
await this.runConnection();
|
|
170
|
+
}
|
|
171
|
+
catch (err) {
|
|
172
|
+
this.log.debug(`connect failed: ${err instanceof Error ? err.message : err}`);
|
|
173
|
+
}
|
|
174
|
+
if (this.stopped)
|
|
175
|
+
break;
|
|
176
|
+
await sleep(this.backoffMs);
|
|
177
|
+
this.backoffMs = Math.min(this.backoffMs * 2, RECONNECT_MAX_MS);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
async stop() {
|
|
181
|
+
this.stopped = true;
|
|
182
|
+
if (this.heartbeatTimer)
|
|
183
|
+
clearInterval(this.heartbeatTimer);
|
|
184
|
+
if (this.probeTimer)
|
|
185
|
+
clearInterval(this.probeTimer);
|
|
186
|
+
for (const job of this.jobs.values())
|
|
187
|
+
job.abort();
|
|
188
|
+
this.jobs.clear();
|
|
189
|
+
await new Promise((resolve) => {
|
|
190
|
+
if (!this.ws || this.ws.readyState === WebSocket.CLOSED) {
|
|
191
|
+
resolve(undefined);
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
this.ws.once('close', () => resolve(undefined));
|
|
195
|
+
this.ws.close();
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
runConnection() {
|
|
199
|
+
const { config } = this.opts;
|
|
200
|
+
const wsUrl = `${config.hubUrl.replace(/^http/, 'ws')}/ws/v1/producer`;
|
|
201
|
+
return new Promise((resolve) => {
|
|
202
|
+
const ws = new WebSocket(wsUrl, {
|
|
203
|
+
headers: { authorization: `Bearer ${config.token}` },
|
|
204
|
+
maxPayload: 256 * 1024,
|
|
205
|
+
});
|
|
206
|
+
this.ws = ws;
|
|
207
|
+
let wireOk = false;
|
|
208
|
+
ws.on('message', (data, isBinary) => {
|
|
209
|
+
try {
|
|
210
|
+
if (isBinary) {
|
|
211
|
+
const frame = decodeChunkFrame(data);
|
|
212
|
+
this.jobs.get(frame.requestId)?.onChunk(frame.payload);
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
const msg = parseControlMessage(data.toString('utf8'));
|
|
216
|
+
if (msg.type === 'hello') {
|
|
217
|
+
if (msg.wireVersion !== WIRE_VERSION) {
|
|
218
|
+
this.log.error(`wire version mismatch: hub=${msg.wireVersion} agent=${WIRE_VERSION}`);
|
|
219
|
+
ws.close();
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
wireOk = true;
|
|
223
|
+
this.register();
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
if (!wireOk)
|
|
227
|
+
return;
|
|
228
|
+
if (msg.type === 'registered') {
|
|
229
|
+
this.backoffMs = RECONNECT_BASE_MS;
|
|
230
|
+
for (const reject of msg.rejected) {
|
|
231
|
+
this.log.warn(`offering rejected: ${reject.alias} (${reject.reason})`);
|
|
232
|
+
}
|
|
233
|
+
const waiterList = this.registeredWaiters;
|
|
234
|
+
this.registeredWaiters = [];
|
|
235
|
+
for (const waiter of waiterList)
|
|
236
|
+
waiter(msg);
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
if (msg.type === 'request.start') {
|
|
240
|
+
const backend = this.backends.get(msg.backendId);
|
|
241
|
+
if (!backend) {
|
|
242
|
+
ws.send(JSON.stringify({
|
|
243
|
+
type: 'response.error',
|
|
244
|
+
requestId: msg.requestId,
|
|
245
|
+
code: 'BACKEND_NOT_FOUND',
|
|
246
|
+
message: `backend '${msg.backendId}' is not configured on this agent`,
|
|
247
|
+
}));
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
const job = new Job(ws, backend, this.health, msg, this.log, (id) => this.jobs.delete(id));
|
|
251
|
+
this.jobs.set(msg.requestId, job);
|
|
252
|
+
this.log.debug(`request ${msg.requestId} accepted on backend ${msg.backendId}`);
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
if (msg.type === 'request.end') {
|
|
256
|
+
this.jobs.get(msg.requestId)?.onEnd();
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
if (msg.type === 'request.cancel') {
|
|
260
|
+
this.jobs.get(msg.requestId)?.abort();
|
|
261
|
+
this.jobs.delete(msg.requestId);
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
catch (err) {
|
|
266
|
+
this.log.warn(`bad frame from hub: ${err instanceof Error ? err.message : err}`);
|
|
267
|
+
ws.close(1008);
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
ws.on('close', () => {
|
|
271
|
+
for (const job of this.jobs.values())
|
|
272
|
+
job.abort();
|
|
273
|
+
this.jobs.clear();
|
|
274
|
+
this.ws = null;
|
|
275
|
+
resolve(undefined);
|
|
276
|
+
});
|
|
277
|
+
ws.on('error', (err) => {
|
|
278
|
+
this.log.debug(`tunnel error: ${err.message}`);
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
register() {
|
|
283
|
+
const ws = this.ws;
|
|
284
|
+
if (!ws || ws.readyState !== WebSocket.OPEN)
|
|
285
|
+
return;
|
|
286
|
+
ws.send(JSON.stringify({
|
|
287
|
+
type: 'register',
|
|
288
|
+
offerings: this.opts.config.offerings.map((o) => ({
|
|
289
|
+
alias: o.alias,
|
|
290
|
+
protocol: this.backends.get(o.backend)?.protocol,
|
|
291
|
+
upstreamModel: o.upstreamModel,
|
|
292
|
+
backendId: o.backend,
|
|
293
|
+
maxConcurrency: o.maxConcurrency,
|
|
294
|
+
})),
|
|
295
|
+
}));
|
|
296
|
+
}
|
|
297
|
+
sendHeartbeat() {
|
|
298
|
+
const ws = this.ws;
|
|
299
|
+
if (!ws || ws.readyState !== WebSocket.OPEN)
|
|
300
|
+
return;
|
|
301
|
+
ws.send(JSON.stringify({ type: 'heartbeat', backendStatus: this.health.statusMap() }));
|
|
302
|
+
}
|
|
303
|
+
/** Minimal live probe for degraded backends; success clears the degraded state. */
|
|
304
|
+
async probeDegraded() {
|
|
305
|
+
for (const backend of this.backends.values()) {
|
|
306
|
+
if (!this.health.isDegraded(backend.id))
|
|
307
|
+
continue;
|
|
308
|
+
const offering = this.opts.config.offerings.find((o) => o.backend === backend.id);
|
|
309
|
+
if (!offering)
|
|
310
|
+
continue;
|
|
311
|
+
try {
|
|
312
|
+
const { url, headers } = probeTarget(backend);
|
|
313
|
+
const resp = await fetch(url, {
|
|
314
|
+
method: 'POST',
|
|
315
|
+
headers,
|
|
316
|
+
body: JSON.stringify(probeBody(offering.upstreamModel, backend.protocol)),
|
|
317
|
+
signal: AbortSignal.timeout(10_000),
|
|
318
|
+
});
|
|
319
|
+
const reason = classifyStatus(resp.status);
|
|
320
|
+
this.health.record(backend.id, reason === null, reason ?? undefined);
|
|
321
|
+
// drain to free the socket
|
|
322
|
+
await resp.arrayBuffer().catch(() => undefined);
|
|
323
|
+
}
|
|
324
|
+
catch {
|
|
325
|
+
this.health.record(backend.id, false, 'NETWORK');
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
export function probeTarget(backend) {
|
|
331
|
+
const base = backend.baseUrl.replace(/\/+$/, '');
|
|
332
|
+
const path = backend.protocol === 'anthropic'
|
|
333
|
+
? '/v1/messages'
|
|
334
|
+
: backend.protocol === 'responses'
|
|
335
|
+
? '/responses'
|
|
336
|
+
: '/chat/completions';
|
|
337
|
+
const headers = { 'content-type': 'application/json' };
|
|
338
|
+
if (backend.protocol === 'anthropic') {
|
|
339
|
+
if (backend.apiKey)
|
|
340
|
+
headers['x-api-key'] = backend.apiKey;
|
|
341
|
+
headers['anthropic-version'] = '2023-06-01';
|
|
342
|
+
}
|
|
343
|
+
else if (backend.apiKey) {
|
|
344
|
+
headers.authorization = `Bearer ${backend.apiKey}`;
|
|
345
|
+
}
|
|
346
|
+
return { url: base + path, headers };
|
|
347
|
+
}
|
|
348
|
+
export function probeBody(model, protocol = 'openai') {
|
|
349
|
+
if (protocol === 'responses') {
|
|
350
|
+
return {
|
|
351
|
+
model,
|
|
352
|
+
input: [{ role: 'user', content: 'ping' }],
|
|
353
|
+
max_output_tokens: 1,
|
|
354
|
+
stream: false,
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
return { model, messages: [{ role: 'user', content: 'ping' }], max_tokens: 1, stream: false };
|
|
358
|
+
}
|
|
359
|
+
//# sourceMappingURL=connection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection.js","sourceRoot":"","sources":["../src/connection.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface DoctorCheck {
|
|
2
|
+
name: string;
|
|
3
|
+
ok: boolean;
|
|
4
|
+
detail: string;
|
|
5
|
+
}
|
|
6
|
+
export interface DoctorReport {
|
|
7
|
+
ok: boolean;
|
|
8
|
+
checks: DoctorCheck[];
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Pre-flight diagnostics, in fasten's order of "find the first failing link":
|
|
12
|
+
* direct backend replay first, hub last. Never guess past a failure.
|
|
13
|
+
*/
|
|
14
|
+
export declare function runDoctor(dir: string): Promise<DoctorReport>;
|