@seawork/server 1.0.19 → 1.0.20-rc.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/dist/scripts/supervisor-entrypoint.js +169 -0
- package/dist/scripts/supervisor-entrypoint.js.map +1 -1
- package/dist/scripts/supervisor.js +60 -10
- package/dist/scripts/supervisor.js.map +1 -1
- package/dist/server/client/daemon-client.d.ts +27 -1
- package/dist/server/client/daemon-client.d.ts.map +1 -1
- package/dist/server/client/daemon-client.js +45 -2
- package/dist/server/client/daemon-client.js.map +1 -1
- package/dist/server/server/agent/agent-manager.d.ts.map +1 -1
- package/dist/server/server/agent/agent-manager.js +58 -3
- package/dist/server/server/agent/agent-manager.js.map +1 -1
- package/dist/server/server/agent/agent-sdk-types.d.ts +1 -0
- package/dist/server/server/agent/agent-sdk-types.d.ts.map +1 -1
- package/dist/server/server/agent/providers/claude-agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/claude-agent.js +27 -9
- package/dist/server/server/agent/providers/claude-agent.js.map +1 -1
- package/dist/server/server/agent/providers/codex-app-server-agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/codex-app-server-agent.js +20 -5
- package/dist/server/server/agent/providers/codex-app-server-agent.js.map +1 -1
- package/dist/server/server/bootstrap.d.ts.map +1 -1
- package/dist/server/server/bootstrap.js +10 -0
- package/dist/server/server/bootstrap.js.map +1 -1
- package/dist/server/server/crash-report.d.ts +12 -0
- package/dist/server/server/crash-report.d.ts.map +1 -0
- package/dist/server/server/crash-report.js +217 -0
- package/dist/server/server/crash-report.js.map +1 -0
- package/dist/server/server/editor-targets.d.ts +3 -1
- package/dist/server/server/editor-targets.d.ts.map +1 -1
- package/dist/server/server/editor-targets.js +51 -2
- package/dist/server/server/editor-targets.js.map +1 -1
- package/dist/server/server/exports.d.ts +1 -0
- package/dist/server/server/exports.d.ts.map +1 -1
- package/dist/server/server/exports.js +5 -0
- package/dist/server/server/exports.js.map +1 -1
- package/dist/server/server/file-explorer/service.d.ts +1 -0
- package/dist/server/server/file-explorer/service.d.ts.map +1 -1
- package/dist/server/server/file-explorer/service.js +61 -10
- package/dist/server/server/file-explorer/service.js.map +1 -1
- package/dist/server/server/index.js +20 -2
- package/dist/server/server/index.js.map +1 -1
- package/dist/server/server/latency-proxy.d.ts +39 -0
- package/dist/server/server/latency-proxy.d.ts.map +1 -0
- package/dist/server/server/latency-proxy.js +148 -0
- package/dist/server/server/latency-proxy.js.map +1 -0
- package/dist/server/server/latency-tracker.d.ts +120 -0
- package/dist/server/server/latency-tracker.d.ts.map +1 -0
- package/dist/server/server/latency-tracker.js +253 -0
- package/dist/server/server/latency-tracker.js.map +1 -0
- package/dist/server/server/session.d.ts +1 -0
- package/dist/server/server/session.d.ts.map +1 -1
- package/dist/server/server/session.js +13 -1
- package/dist/server/server/session.js.map +1 -1
- package/dist/server/shared/messages.d.ts +580 -0
- package/dist/server/shared/messages.d.ts.map +1 -1
- package/dist/server/shared/messages.js +27 -0
- package/dist/server/shared/messages.js.map +1 -1
- package/dist/src/server/bug-report-redact.js +145 -0
- package/dist/src/server/bug-report-redact.js.map +1 -0
- package/dist/src/server/crash-report.js +217 -0
- package/dist/src/server/crash-report.js.map +1 -0
- package/dist/src/server/daemon-version.js +22 -0
- package/dist/src/server/daemon-version.js.map +1 -0
- package/dist/src/server/package-version.js +46 -0
- package/dist/src/server/package-version.js.map +1 -0
- package/package.json +3 -3
|
@@ -18,16 +18,23 @@ export async function listDirectoryEntries({ root, relativePath = ".", }) {
|
|
|
18
18
|
if (!stats.isDirectory()) {
|
|
19
19
|
throw new Error("Requested path is not a directory");
|
|
20
20
|
}
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
const names = await fs.readdir(directoryPath);
|
|
22
|
+
const realRoot = await fs.realpath(path.resolve(root));
|
|
23
|
+
const realParent = await fs.realpath(directoryPath);
|
|
24
|
+
const entriesWithNulls = await Promise.all(names.map(async (name) => {
|
|
25
|
+
const targetPath = path.join(directoryPath, name);
|
|
25
26
|
try {
|
|
26
|
-
|
|
27
|
+
const resolved = await resolveEntryKind({ targetPath, realRoot, realParent });
|
|
28
|
+
if (resolved === null) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
return buildEntryPayload({
|
|
27
32
|
root,
|
|
28
33
|
targetPath,
|
|
29
|
-
name
|
|
30
|
-
kind,
|
|
34
|
+
name,
|
|
35
|
+
kind: resolved.kind,
|
|
36
|
+
isSymbolicLink: resolved.isSymbolicLink,
|
|
37
|
+
stats: resolved.stats,
|
|
31
38
|
});
|
|
32
39
|
}
|
|
33
40
|
catch (error) {
|
|
@@ -148,15 +155,59 @@ async function resolveScopedPath({ root, relativePath = "." }) {
|
|
|
148
155
|
throw error;
|
|
149
156
|
}
|
|
150
157
|
}
|
|
151
|
-
|
|
152
|
-
const
|
|
153
|
-
return {
|
|
158
|
+
function buildEntryPayload({ root, targetPath, name, kind, isSymbolicLink, stats, }) {
|
|
159
|
+
const entry = {
|
|
154
160
|
name,
|
|
155
161
|
path: normalizeRelativePath({ root, targetPath }),
|
|
156
162
|
kind,
|
|
157
163
|
size: stats.size,
|
|
158
164
|
modifiedAt: stats.mtime.toISOString(),
|
|
159
165
|
};
|
|
166
|
+
if (isSymbolicLink) {
|
|
167
|
+
entry.isSymbolicLink = true;
|
|
168
|
+
}
|
|
169
|
+
return entry;
|
|
170
|
+
}
|
|
171
|
+
// Classify each entry from a fresh lstat instead of trusting the readdir snapshot,
|
|
172
|
+
// so a name that got swapped to a symlink between readdir and stat is still
|
|
173
|
+
// detected as a link and goes through the workspace-boundary check. For links
|
|
174
|
+
// we follow via fs.realpath (one follow, boundary-checked), then stat the
|
|
175
|
+
// validated realpath — the kind/size/mtime returned to the client always come
|
|
176
|
+
// from the same target we approved. Windows junctions and POSIX/Windows dir
|
|
177
|
+
// symlinks all surface as lstat.isSymbolicLink()=true here.
|
|
178
|
+
// Returns null when the resolved target is outside the workspace so the UI
|
|
179
|
+
// never offers an "expandable" affordance the scope check would later refuse.
|
|
180
|
+
async function resolveEntryKind({ targetPath, realRoot, realParent, }) {
|
|
181
|
+
const linkStats = await fs.lstat(targetPath);
|
|
182
|
+
if (linkStats.isSymbolicLink()) {
|
|
183
|
+
const realTarget = await fs.realpath(targetPath);
|
|
184
|
+
const relative = path.relative(realRoot, realTarget);
|
|
185
|
+
if (relative !== "" && (relative.startsWith("..") || path.isAbsolute(relative))) {
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
const stats = await fs.stat(realTarget);
|
|
189
|
+
// Drop directory symlinks that point at the listing directory itself or any
|
|
190
|
+
// of its ancestors. Expanding them creates infinite phantom paths
|
|
191
|
+
// (`loop/loop/loop/…`, `up/up/up/…`) without revealing anything new.
|
|
192
|
+
if (stats.isDirectory() && isAncestorOrSelf({ ancestor: realTarget, descendant: realParent })) {
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
return {
|
|
196
|
+
kind: stats.isDirectory() ? "directory" : "file",
|
|
197
|
+
stats,
|
|
198
|
+
isSymbolicLink: true,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
return {
|
|
202
|
+
kind: linkStats.isDirectory() ? "directory" : "file",
|
|
203
|
+
stats: linkStats,
|
|
204
|
+
isSymbolicLink: false,
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
function isAncestorOrSelf({ ancestor, descendant, }) {
|
|
208
|
+
const rel = path.relative(ancestor, descendant);
|
|
209
|
+
// rel === "" → same path; rel without ".." and not absolute → descendant is inside ancestor.
|
|
210
|
+
return rel === "" || (!rel.startsWith("..") && !path.isAbsolute(rel));
|
|
160
211
|
}
|
|
161
212
|
function isMissingEntryError(error) {
|
|
162
213
|
const code = error?.code;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../../../src/server/file-explorer/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,IAAI,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../../../src/server/file-explorer/service.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,6 +6,7 @@ import { resolveSeaworkHome } from "./seawork-home.js";
|
|
|
6
6
|
import { createRootLogger } from "./logger.js";
|
|
7
7
|
import { loadPersistedConfig } from "./persisted-config.js";
|
|
8
8
|
import { acquirePidLock, PidLockError, releasePidLock, updatePidLock } from "./pid-lock.js";
|
|
9
|
+
import { emitDaemonCrashReport } from "./crash-report.js";
|
|
9
10
|
async function main() {
|
|
10
11
|
let seaworkHome;
|
|
11
12
|
let logger;
|
|
@@ -212,13 +213,30 @@ async function main() {
|
|
|
212
213
|
}
|
|
213
214
|
process.on("SIGTERM", () => beginShutdown("SIGTERM"));
|
|
214
215
|
process.on("SIGINT", () => beginShutdown("SIGINT"));
|
|
216
|
+
// On fatal exit, fire a best-effort crash report to bug-intake before
|
|
217
|
+
// exiting. emitDaemonCrashReport never throws and is bounded by a 5s
|
|
218
|
+
// fetch timeout; the .finally pads another 200ms so pino async streams
|
|
219
|
+
// can flush "Uncaught exception" to daemon.log before process.exit.
|
|
220
|
+
//
|
|
221
|
+
// Exit code 75 is a sentinel telling the supervisor "I've already filed
|
|
222
|
+
// my own crash report; don't re-file from the supervisor's onWorkerCrash
|
|
223
|
+
// hook." Without this, every daemon JS-layer fatal would produce two
|
|
224
|
+
// GitHub issues — one from here, one from the supervisor seeing the
|
|
225
|
+
// abnormal exit. 75 is `EX_TEMPFAIL` from sysexits.h and isn't used
|
|
226
|
+
// elsewhere in the codebase.
|
|
227
|
+
const SELF_REPORTED_FATAL_EXIT_CODE = 75;
|
|
228
|
+
const reportAndExit = (err, kind) => {
|
|
229
|
+
void emitDaemonCrashReport({ err, kind, logger, seaworkHome }).finally(() => {
|
|
230
|
+
setTimeout(() => process.exit(SELF_REPORTED_FATAL_EXIT_CODE), 200);
|
|
231
|
+
});
|
|
232
|
+
};
|
|
215
233
|
process.on("uncaughtException", (err) => {
|
|
216
234
|
logger.fatal({ err }, "Uncaught exception — daemon crashing");
|
|
217
|
-
|
|
235
|
+
reportAndExit(err, "uncaught");
|
|
218
236
|
});
|
|
219
237
|
process.on("unhandledRejection", (reason) => {
|
|
220
238
|
logger.fatal({ err: reason }, "Unhandled promise rejection — daemon crashing");
|
|
221
|
-
|
|
239
|
+
reportAndExit(reason, "unhandled-rejection");
|
|
222
240
|
});
|
|
223
241
|
}
|
|
224
242
|
main().catch((err) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/server/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type pino from "pino";
|
|
2
|
+
/**
|
|
3
|
+
* Local transparent CONNECT proxy used in latency debug mode.
|
|
4
|
+
*
|
|
5
|
+
* It does NOT decrypt TLS, so HTTP boundaries are invisible. Each upstream
|
|
6
|
+
* connection is timestamped at two TCP-level boundaries:
|
|
7
|
+
* - first client→upstream byte (`providerRequestSentAt`): when the
|
|
8
|
+
* provider SDK puts its TLS ClientHello on the wire, after queueing /
|
|
9
|
+
* DNS / connection pool overhead inside the SDK.
|
|
10
|
+
* - first upstream→client byte (`gatewayFirstByteAt`): the upstream's
|
|
11
|
+
* TLS ServerHello — NOT the gateway HTTP TTFB. The span between these
|
|
12
|
+
* two timestamps is TLS handshake RTT; gateway processing and model
|
|
13
|
+
* generation are then bundled into the remaining "ServerHello →
|
|
14
|
+
* turn_completed" interval. The UI labels these as `tls` and `model`.
|
|
15
|
+
*
|
|
16
|
+
* Attribution: the proxy hands the two timestamps to LatencyTracker, which
|
|
17
|
+
* only records them when there is exactly one active turn (so we never
|
|
18
|
+
* misattribute under concurrent turns). See latency-tracker.ts.
|
|
19
|
+
*
|
|
20
|
+
* Only started when the daemon was launched with SEAWORK_LATENCY_PROXY=1;
|
|
21
|
+
* kept running for the lifetime of the daemon process.
|
|
22
|
+
*/
|
|
23
|
+
export declare class LatencyProxy {
|
|
24
|
+
private readonly logger;
|
|
25
|
+
private server;
|
|
26
|
+
private port;
|
|
27
|
+
constructor(logger: pino.Logger);
|
|
28
|
+
start(): Promise<number>;
|
|
29
|
+
getProxyUrl(): string | null;
|
|
30
|
+
stop(): Promise<void>;
|
|
31
|
+
private handleConnect;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Lazy-start a single shared proxy and return its URL. Subsequent calls
|
|
35
|
+
* resolve to the same instance. Safe to call from any provider hook.
|
|
36
|
+
*/
|
|
37
|
+
export declare function ensureLatencyProxyUrl(logger: pino.Logger): Promise<string>;
|
|
38
|
+
export declare function getLatencyProxyUrlSync(): string | null;
|
|
39
|
+
//# sourceMappingURL=latency-proxy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"latency-proxy.d.ts","sourceRoot":"","sources":["../../../src/server/latency-proxy.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAI7B;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,YAAY;IAIX,OAAO,CAAC,QAAQ,CAAC,MAAM;IAHnC,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,IAAI,CAAuB;gBAEN,MAAM,EAAE,IAAI,CAAC,MAAM;IAE1C,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IAqC9B,WAAW,IAAI,MAAM,GAAG,IAAI;IAItB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ3B,OAAO,CAAC,aAAa;CAsDtB;AAKD;;;GAGG;AACH,wBAAsB,qBAAqB,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAWhF;AAED,wBAAgB,sBAAsB,IAAI,MAAM,GAAG,IAAI,CAEtD"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { createServer } from "node:http";
|
|
2
|
+
import { connect } from "node:net";
|
|
3
|
+
import { latencyTracker } from "./latency-tracker.js";
|
|
4
|
+
/**
|
|
5
|
+
* Local transparent CONNECT proxy used in latency debug mode.
|
|
6
|
+
*
|
|
7
|
+
* It does NOT decrypt TLS, so HTTP boundaries are invisible. Each upstream
|
|
8
|
+
* connection is timestamped at two TCP-level boundaries:
|
|
9
|
+
* - first client→upstream byte (`providerRequestSentAt`): when the
|
|
10
|
+
* provider SDK puts its TLS ClientHello on the wire, after queueing /
|
|
11
|
+
* DNS / connection pool overhead inside the SDK.
|
|
12
|
+
* - first upstream→client byte (`gatewayFirstByteAt`): the upstream's
|
|
13
|
+
* TLS ServerHello — NOT the gateway HTTP TTFB. The span between these
|
|
14
|
+
* two timestamps is TLS handshake RTT; gateway processing and model
|
|
15
|
+
* generation are then bundled into the remaining "ServerHello →
|
|
16
|
+
* turn_completed" interval. The UI labels these as `tls` and `model`.
|
|
17
|
+
*
|
|
18
|
+
* Attribution: the proxy hands the two timestamps to LatencyTracker, which
|
|
19
|
+
* only records them when there is exactly one active turn (so we never
|
|
20
|
+
* misattribute under concurrent turns). See latency-tracker.ts.
|
|
21
|
+
*
|
|
22
|
+
* Only started when the daemon was launched with SEAWORK_LATENCY_PROXY=1;
|
|
23
|
+
* kept running for the lifetime of the daemon process.
|
|
24
|
+
*/
|
|
25
|
+
export class LatencyProxy {
|
|
26
|
+
constructor(logger) {
|
|
27
|
+
this.logger = logger;
|
|
28
|
+
this.server = null;
|
|
29
|
+
this.port = null;
|
|
30
|
+
}
|
|
31
|
+
async start() {
|
|
32
|
+
if (this.port !== null)
|
|
33
|
+
return this.port;
|
|
34
|
+
const server = createServer();
|
|
35
|
+
server.on("connect", (req, clientSocket, head) => {
|
|
36
|
+
this.handleConnect(req, clientSocket, head);
|
|
37
|
+
});
|
|
38
|
+
// Plain HTTP is uncommon for gateways but handle it defensively so a
|
|
39
|
+
// misrouted SDK request doesn't hang.
|
|
40
|
+
server.on("request", (_req, res) => {
|
|
41
|
+
res.writeHead(501, { "content-type": "text/plain" });
|
|
42
|
+
res.end("latency-proxy: only HTTPS CONNECT supported");
|
|
43
|
+
});
|
|
44
|
+
server.on("error", (err) => {
|
|
45
|
+
this.logger.warn({ err }, "latency-proxy server error");
|
|
46
|
+
});
|
|
47
|
+
await new Promise((resolve, reject) => {
|
|
48
|
+
server.once("error", reject);
|
|
49
|
+
server.listen({ host: "127.0.0.1", port: 0 }, () => {
|
|
50
|
+
server.off("error", reject);
|
|
51
|
+
resolve();
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
const address = server.address();
|
|
55
|
+
if (!address || typeof address === "string") {
|
|
56
|
+
throw new Error("latency-proxy: failed to acquire listening port");
|
|
57
|
+
}
|
|
58
|
+
this.server = server;
|
|
59
|
+
this.port = address.port;
|
|
60
|
+
this.logger.info({ port: this.port }, "latency-proxy listening");
|
|
61
|
+
return this.port;
|
|
62
|
+
}
|
|
63
|
+
getProxyUrl() {
|
|
64
|
+
return this.port === null ? null : `http://127.0.0.1:${this.port}`;
|
|
65
|
+
}
|
|
66
|
+
async stop() {
|
|
67
|
+
const server = this.server;
|
|
68
|
+
if (!server)
|
|
69
|
+
return;
|
|
70
|
+
await new Promise((resolve) => server.close(() => resolve()));
|
|
71
|
+
this.server = null;
|
|
72
|
+
this.port = null;
|
|
73
|
+
}
|
|
74
|
+
handleConnect(req, clientSocket, head) {
|
|
75
|
+
const target = req.url ?? "";
|
|
76
|
+
const [hostname, portStr] = target.split(":");
|
|
77
|
+
const port = Number(portStr) || 443;
|
|
78
|
+
if (!hostname) {
|
|
79
|
+
clientSocket.destroy();
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
let requestSentAt;
|
|
83
|
+
let firstByteAt;
|
|
84
|
+
const flushIfReady = () => {
|
|
85
|
+
if (requestSentAt !== undefined && firstByteAt !== undefined) {
|
|
86
|
+
latencyTracker.recordProxyTiming({
|
|
87
|
+
requestSent: requestSentAt,
|
|
88
|
+
firstByte: firstByteAt,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
const upstream = connect({ host: hostname, port }, () => {
|
|
93
|
+
clientSocket.write("HTTP/1.1 200 Connection Established\r\n\r\n");
|
|
94
|
+
if (head && head.length > 0) {
|
|
95
|
+
if (requestSentAt === undefined)
|
|
96
|
+
requestSentAt = Date.now();
|
|
97
|
+
upstream.write(head);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
clientSocket.on("data", (chunk) => {
|
|
101
|
+
if (requestSentAt === undefined && chunk.length > 0) {
|
|
102
|
+
requestSentAt = Date.now();
|
|
103
|
+
}
|
|
104
|
+
upstream.write(chunk);
|
|
105
|
+
});
|
|
106
|
+
upstream.on("data", (chunk) => {
|
|
107
|
+
if (firstByteAt === undefined && chunk.length > 0) {
|
|
108
|
+
firstByteAt = Date.now();
|
|
109
|
+
flushIfReady();
|
|
110
|
+
}
|
|
111
|
+
clientSocket.write(chunk);
|
|
112
|
+
});
|
|
113
|
+
const cleanup = (err) => {
|
|
114
|
+
if (err) {
|
|
115
|
+
this.logger.debug({ err, hostname, port }, "latency-proxy tunnel error");
|
|
116
|
+
}
|
|
117
|
+
clientSocket.destroy();
|
|
118
|
+
upstream.destroy();
|
|
119
|
+
};
|
|
120
|
+
clientSocket.on("end", () => upstream.end());
|
|
121
|
+
upstream.on("end", () => clientSocket.end());
|
|
122
|
+
clientSocket.on("error", cleanup);
|
|
123
|
+
upstream.on("error", cleanup);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
let sharedProxy = null;
|
|
127
|
+
let startingPromise = null;
|
|
128
|
+
/**
|
|
129
|
+
* Lazy-start a single shared proxy and return its URL. Subsequent calls
|
|
130
|
+
* resolve to the same instance. Safe to call from any provider hook.
|
|
131
|
+
*/
|
|
132
|
+
export async function ensureLatencyProxyUrl(logger) {
|
|
133
|
+
if (sharedProxy?.getProxyUrl())
|
|
134
|
+
return sharedProxy.getProxyUrl();
|
|
135
|
+
if (!startingPromise) {
|
|
136
|
+
const proxy = new LatencyProxy(logger.child({ component: "latency-proxy" }));
|
|
137
|
+
startingPromise = proxy.start().then(() => {
|
|
138
|
+
sharedProxy = proxy;
|
|
139
|
+
return proxy;
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
const proxy = await startingPromise;
|
|
143
|
+
return proxy.getProxyUrl();
|
|
144
|
+
}
|
|
145
|
+
export function getLatencyProxyUrlSync() {
|
|
146
|
+
return sharedProxy?.getProxyUrl() ?? null;
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=latency-proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"latency-proxy.js","sourceRoot":"","sources":["../../../src/server/latency-proxy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import type { LatencyBreakdown } from "../shared/messages.js";
|
|
2
|
+
/**
|
|
3
|
+
* Per-turn latency tracker. Active only when the user has enabled latency
|
|
4
|
+
* debug mode on the client (which causes `clientSentAt` to be set on the
|
|
5
|
+
* outgoing `send_agent_message_request`).
|
|
6
|
+
*
|
|
7
|
+
* Trackers are keyed by `turnId` because:
|
|
8
|
+
* - one agent can be replaced/cancelled and a new turnId issued before the
|
|
9
|
+
* old one finishes, so agentId is not unique-per-turn;
|
|
10
|
+
* - the wire `turn_completed` event carries turnId, letting the client
|
|
11
|
+
* attach the breakdown to exactly the right assistant message.
|
|
12
|
+
*
|
|
13
|
+
* Proxy attribution (providerRequestSentAt / gatewayFirstByteAt) is only
|
|
14
|
+
* recorded when there is exactly one active turn at the moment a CONNECT
|
|
15
|
+
* arrives. With multiple concurrent turns the proxy cannot distinguish which
|
|
16
|
+
* turn a given socket belongs to (loopback gives us no useful 5-tuple
|
|
17
|
+
* information), so we leave those two timestamps undefined rather than
|
|
18
|
+
* misattribute them. The client renders a partial breakdown in that case.
|
|
19
|
+
*/
|
|
20
|
+
declare class LatencyTracker {
|
|
21
|
+
private readonly turns;
|
|
22
|
+
/** agentId → turnId for currently-tracked turns. */
|
|
23
|
+
private readonly agentToTurn;
|
|
24
|
+
/**
|
|
25
|
+
* Per-agent staging area: timestamps captured before the provider has
|
|
26
|
+
* issued a turnId (session-level receive + dispatch). When agent-manager
|
|
27
|
+
* receives the turnId back from `startTurn`, it calls `promotePending` to
|
|
28
|
+
* move the staged entry under that turnId. Dropped if startTurn fails.
|
|
29
|
+
*/
|
|
30
|
+
private readonly pendingByAgent;
|
|
31
|
+
/**
|
|
32
|
+
* Map of agentId → set of in-flight turnIds (foreground + autonomous),
|
|
33
|
+
* including debug-off turns that do not get a per-turn entry. Needed
|
|
34
|
+
* because the global CONNECT proxy carries traffic from every spawned
|
|
35
|
+
* provider CLI: if a debug-off turn is in flight alongside a single
|
|
36
|
+
* debug-on turn, the proxy must not attribute the debug-off turn's
|
|
37
|
+
* CONNECT to the debug-on turn.
|
|
38
|
+
*
|
|
39
|
+
* Indexed by agentId so close/refresh teardown can sweep all turns
|
|
40
|
+
* (foreground + autonomous) belonging to one agent in a single call.
|
|
41
|
+
*
|
|
42
|
+
* Bookkeeping is idempotent: synthetic terminal events fired before any
|
|
43
|
+
* real turn_started (e.g. startTurn() throwing) are no-ops, and turns
|
|
44
|
+
* that vanish without a terminal event can be force-cleared via
|
|
45
|
+
* `forceEndAgentTurns` without skewing the count for other live turns.
|
|
46
|
+
*/
|
|
47
|
+
private readonly agentActiveTurns;
|
|
48
|
+
private globalActiveTurnCount;
|
|
49
|
+
beginPending(agentId: string, clientSentAt: number, daemonReceivedAt: number): void;
|
|
50
|
+
markPendingDispatched(agentId: string, at?: number): void;
|
|
51
|
+
/**
|
|
52
|
+
* Move the staged entry for `agentId` to a turnId-keyed slot once the
|
|
53
|
+
* provider has issued a turnId. No-op if no pending entry exists (debug
|
|
54
|
+
* mode was off for this turn).
|
|
55
|
+
*/
|
|
56
|
+
promotePending(agentId: string, turnId: string): void;
|
|
57
|
+
dropPending(agentId: string): void;
|
|
58
|
+
/**
|
|
59
|
+
* Record proxy-observed gateway timing. The proxy supplies its own
|
|
60
|
+
* timestamps and the tracker decides whether attribution is safe (i.e.
|
|
61
|
+
* unambiguous single in-flight turn). Concurrent turns → silently ignored.
|
|
62
|
+
*/
|
|
63
|
+
recordProxyTiming(at: {
|
|
64
|
+
requestSent: number;
|
|
65
|
+
firstByte: number;
|
|
66
|
+
}): void;
|
|
67
|
+
/**
|
|
68
|
+
* Account for a turn entering the in-flight pool, regardless of whether it
|
|
69
|
+
* carries per-turn latency tracking. Used by the proxy concurrency gate so
|
|
70
|
+
* debug-off turns cannot get their CONNECTs misattributed to a single
|
|
71
|
+
* debug-on turn. No-op if turnId is empty.
|
|
72
|
+
*
|
|
73
|
+
* Should be called as early as the agent-manager learns about the turnId
|
|
74
|
+
* (right after `await agent.session.startTurn(...)` returns), not waiting
|
|
75
|
+
* for the provider's `turn_started` event — the provider's first CONNECT
|
|
76
|
+
* can fire inside that window and the proxy timing must already see the
|
|
77
|
+
* turn counted to avoid being silently dropped. The `turn_started` event
|
|
78
|
+
* still calls this method later; the Set keeps it idempotent.
|
|
79
|
+
*/
|
|
80
|
+
noteTurnStarted(agentId: string, turnId: string | null | undefined): void;
|
|
81
|
+
/**
|
|
82
|
+
* Mirror of `noteTurnStarted` for terminal events. Idempotent — terminal
|
|
83
|
+
* events fired without a matching `noteTurnStarted` (e.g. synthetic
|
|
84
|
+
* turn_failed from a `startTurn` rejection that never produced a real
|
|
85
|
+
* turn_started) are no-ops and cannot decrement the count for another
|
|
86
|
+
* live turn.
|
|
87
|
+
*/
|
|
88
|
+
noteTurnEnded(agentId: string, turnId: string | null | undefined): void;
|
|
89
|
+
/**
|
|
90
|
+
* Force-clear all in-flight entries for an agent whose terminal events
|
|
91
|
+
* will not flow through handleStreamEvent (closeAgent / session refresh
|
|
92
|
+
* paths that unsubscribe before dispatching). Covers:
|
|
93
|
+
* - turns counted in agentActiveTurns (turn_started already fired);
|
|
94
|
+
* - promoted-but-not-yet-started entries in `turns` (pending → promoted
|
|
95
|
+
* by startTurn returning a turnId, but turn_started not yet seen — a
|
|
96
|
+
* real window between agent-manager.ts promote and the provider's
|
|
97
|
+
* first event);
|
|
98
|
+
* - pendingByAgent entries (never reached promotion).
|
|
99
|
+
*/
|
|
100
|
+
forceEndAgentTurns(agentId: string): void;
|
|
101
|
+
/**
|
|
102
|
+
* Pull and clear the breakdown for a completed turn. Stamps
|
|
103
|
+
* `turnCompletedAt`. Returns undefined if no tracker is active for the turn.
|
|
104
|
+
*/
|
|
105
|
+
complete(turnId: string, at?: number): LatencyBreakdown | undefined;
|
|
106
|
+
/** Drop without producing a breakdown (turn_failed / turn_canceled). */
|
|
107
|
+
drop(turnId: string): void;
|
|
108
|
+
/** Resolve agent → currently tracked turnId, if any. */
|
|
109
|
+
turnIdForAgent(agentId: string): string | undefined;
|
|
110
|
+
isActive(turnId: string): boolean;
|
|
111
|
+
activeCount(): number;
|
|
112
|
+
/** Total in-flight turn count across all agents (foreground + autonomous),
|
|
113
|
+
* including debug-off turns. Exposed for tests; the proxy concurrency
|
|
114
|
+
* gate reads it via recordProxyTiming internally. */
|
|
115
|
+
globalCount(): number;
|
|
116
|
+
}
|
|
117
|
+
export declare const latencyTracker: LatencyTracker;
|
|
118
|
+
export declare function summarizeBreakdown(b: LatencyBreakdown): Record<string, number | undefined>;
|
|
119
|
+
export {};
|
|
120
|
+
//# sourceMappingURL=latency-tracker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"latency-tracker.d.ts","sourceRoot":"","sources":["../../../src/server/latency-tracker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE9D;;;;;;;;;;;;;;;;;GAiBG;AACH,cAAM,cAAc;IAClB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAuC;IAC7D,oDAAoD;IACpD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA6B;IACzD;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAuC;IACtE;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAkC;IACnE,OAAO,CAAC,qBAAqB,CAAK;IAElC,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,GAAG,IAAI;IAInF,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,GAAE,MAAmB,GAAG,IAAI;IAMrE;;;;OAIG;IACH,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAQrD,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAIlC;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAuBvE;;;;;;;;;;;;OAYG;IACH,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI;IAazE;;;;;;OAMG;IACH,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI;IAUvE;;;;;;;;;;OAUG;IACH,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAsBzC;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,GAAE,MAAmB,GAAG,gBAAgB,GAAG,SAAS;IAc/E,wEAAwE;IACxE,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAU1B,wDAAwD;IACxD,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAInD,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAIjC,WAAW,IAAI,MAAM;IAIrB;;0DAEsD;IACtD,WAAW,IAAI,MAAM;CAGtB;AAED,eAAO,MAAM,cAAc,gBAAuB,CAAC;AAEnD,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CA+B1F"}
|