optimus-tool-call-staging 0.2.11 → 0.2.13
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/lib/pending-events.d.ts +43 -0
- package/dist/lib/pending-events.d.ts.map +1 -0
- package/dist/lib/pending-events.js +107 -0
- package/dist/lib/pending-events.js.map +1 -0
- package/dist/lib/streaming.d.ts +12 -0
- package/dist/lib/streaming.d.ts.map +1 -1
- package/dist/lib/streaming.js +64 -7
- package/dist/lib/streaming.js.map +1 -1
- package/dist/test/canonical.test.js +22 -1
- package/dist/test/canonical.test.js.map +1 -1
- package/dist/test/endpoint-config.test.js +20 -6
- package/dist/test/endpoint-config.test.js.map +1 -1
- package/dist/test/integration-canonical.test.js +20 -1
- package/dist/test/integration-canonical.test.js.map +1 -1
- package/dist/test/pending-events.test.d.ts +13 -0
- package/dist/test/pending-events.test.d.ts.map +1 -0
- package/dist/test/pending-events.test.js +209 -0
- package/dist/test/pending-events.test.js.map +1 -0
- package/dist/test/streaming-http.test.d.ts +11 -0
- package/dist/test/streaming-http.test.d.ts.map +1 -0
- package/dist/test/streaming-http.test.js +181 -0
- package/dist/test/streaming-http.test.js.map +1 -0
- package/package.json +3 -2
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Durable pending-event buffer for telemetry that failed to send.
|
|
3
|
+
*
|
|
4
|
+
* Note on scope: this buffer handles Optimus backend unavailability, not
|
|
5
|
+
* general internet connectivity loss. If the developer is fully offline,
|
|
6
|
+
* the AI agent itself cannot reach its API, so no tool calls are generated
|
|
7
|
+
* and hooks never fire — there is nothing to buffer. The realistic failure
|
|
8
|
+
* modes this covers are: Optimus backend deploying or restarting mid-session,
|
|
9
|
+
* transient 5xx errors, and network path issues specific to app.optimuslabs.io
|
|
10
|
+
* while the AI API endpoint remains reachable.
|
|
11
|
+
*
|
|
12
|
+
* On network failure or 5xx, events are appended as JSONL to
|
|
13
|
+
* ~/opt-ai-sec/management/telemetry/pending_events.jsonl.
|
|
14
|
+
* On the next hook invocation, drainPendingEvents() atomically claims that
|
|
15
|
+
* file (via rename) so a concurrent hook process won't double-send the same
|
|
16
|
+
* batch.
|
|
17
|
+
*/
|
|
18
|
+
import type { TelemetryEvent } from "./telemetry.js";
|
|
19
|
+
/**
|
|
20
|
+
* Resolve the telemetry directory at call time so that tests can override it
|
|
21
|
+
* by setting OPTIMUS_TELEMETRY_DIR before calling any function.
|
|
22
|
+
*/
|
|
23
|
+
export declare function getPendingDir(): string;
|
|
24
|
+
export declare function getPendingFile(): string;
|
|
25
|
+
export declare function getClientErrorsFile(): string;
|
|
26
|
+
/**
|
|
27
|
+
* Append events to the pending file for retry on the next hook invocation.
|
|
28
|
+
* Used for network failures and transient server errors (5xx).
|
|
29
|
+
*/
|
|
30
|
+
export declare function appendPendingEvents(events: TelemetryEvent[]): void;
|
|
31
|
+
/**
|
|
32
|
+
* Log events that failed with a 4xx HTTP error.
|
|
33
|
+
* These are not retried — the request was malformed or rejected by the server.
|
|
34
|
+
* Each line is a JSON object with the HTTP status, timestamp, and original event.
|
|
35
|
+
*/
|
|
36
|
+
export declare function appendClientErrors(events: TelemetryEvent[], httpStatus: number): void;
|
|
37
|
+
/**
|
|
38
|
+
* Atomically claim and parse the pending file.
|
|
39
|
+
* Uses rename so two concurrent hook processes never read the same batch.
|
|
40
|
+
* Returns [] if the file does not exist or cannot be read.
|
|
41
|
+
*/
|
|
42
|
+
export declare function drainPendingEvents(): TelemetryEvent[];
|
|
43
|
+
//# sourceMappingURL=pending-events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pending-events.d.ts","sourceRoot":"","sources":["../../src/lib/pending-events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD;;;GAGG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAItC;AAED,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C;AAOD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,cAAc,EAAE,GAAG,IAAI,CAWlE;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,cAAc,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAgBrF;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,IAAI,cAAc,EAAE,CAyBrD"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Durable pending-event buffer for telemetry that failed to send.
|
|
3
|
+
*
|
|
4
|
+
* Note on scope: this buffer handles Optimus backend unavailability, not
|
|
5
|
+
* general internet connectivity loss. If the developer is fully offline,
|
|
6
|
+
* the AI agent itself cannot reach its API, so no tool calls are generated
|
|
7
|
+
* and hooks never fire — there is nothing to buffer. The realistic failure
|
|
8
|
+
* modes this covers are: Optimus backend deploying or restarting mid-session,
|
|
9
|
+
* transient 5xx errors, and network path issues specific to app.optimuslabs.io
|
|
10
|
+
* while the AI API endpoint remains reachable.
|
|
11
|
+
*
|
|
12
|
+
* On network failure or 5xx, events are appended as JSONL to
|
|
13
|
+
* ~/opt-ai-sec/management/telemetry/pending_events.jsonl.
|
|
14
|
+
* On the next hook invocation, drainPendingEvents() atomically claims that
|
|
15
|
+
* file (via rename) so a concurrent hook process won't double-send the same
|
|
16
|
+
* batch.
|
|
17
|
+
*/
|
|
18
|
+
import { homedir } from "os";
|
|
19
|
+
import path from "path";
|
|
20
|
+
import fs from "fs";
|
|
21
|
+
/**
|
|
22
|
+
* Resolve the telemetry directory at call time so that tests can override it
|
|
23
|
+
* by setting OPTIMUS_TELEMETRY_DIR before calling any function.
|
|
24
|
+
*/
|
|
25
|
+
export function getPendingDir() {
|
|
26
|
+
return process.env.OPTIMUS_TELEMETRY_DIR
|
|
27
|
+
? path.resolve(process.env.OPTIMUS_TELEMETRY_DIR)
|
|
28
|
+
: path.join(homedir(), "opt-ai-sec", "management", "telemetry");
|
|
29
|
+
}
|
|
30
|
+
export function getPendingFile() {
|
|
31
|
+
return path.join(getPendingDir(), "pending_events.jsonl");
|
|
32
|
+
}
|
|
33
|
+
export function getClientErrorsFile() {
|
|
34
|
+
return path.join(getPendingDir(), "client_errors.jsonl");
|
|
35
|
+
}
|
|
36
|
+
function writeLines(dir, file, lines) {
|
|
37
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
38
|
+
fs.appendFileSync(file, lines.join("\n") + "\n", "utf8");
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Append events to the pending file for retry on the next hook invocation.
|
|
42
|
+
* Used for network failures and transient server errors (5xx).
|
|
43
|
+
*/
|
|
44
|
+
export function appendPendingEvents(events) {
|
|
45
|
+
if (events.length === 0)
|
|
46
|
+
return;
|
|
47
|
+
const dir = getPendingDir();
|
|
48
|
+
try {
|
|
49
|
+
writeLines(dir, getPendingFile(), events.map((e) => JSON.stringify(e)));
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
console.error("[optimus-tool-call] Failed to write pending events to disk:", err instanceof Error ? err.message : String(err));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Log events that failed with a 4xx HTTP error.
|
|
57
|
+
* These are not retried — the request was malformed or rejected by the server.
|
|
58
|
+
* Each line is a JSON object with the HTTP status, timestamp, and original event.
|
|
59
|
+
*/
|
|
60
|
+
export function appendClientErrors(events, httpStatus) {
|
|
61
|
+
if (events.length === 0)
|
|
62
|
+
return;
|
|
63
|
+
const dir = getPendingDir();
|
|
64
|
+
const failedAt = new Date().toISOString();
|
|
65
|
+
try {
|
|
66
|
+
writeLines(dir, getClientErrorsFile(), events.map((e) => JSON.stringify({ http_status: httpStatus, failed_at: failedAt, event: e })));
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
console.error("[optimus-tool-call] Failed to log client errors to disk:", err instanceof Error ? err.message : String(err));
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Atomically claim and parse the pending file.
|
|
74
|
+
* Uses rename so two concurrent hook processes never read the same batch.
|
|
75
|
+
* Returns [] if the file does not exist or cannot be read.
|
|
76
|
+
*/
|
|
77
|
+
export function drainPendingEvents() {
|
|
78
|
+
const pendingFile = getPendingFile();
|
|
79
|
+
const tmpFile = pendingFile + ".draining";
|
|
80
|
+
try {
|
|
81
|
+
fs.renameSync(pendingFile, tmpFile);
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
return [];
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
const content = fs.readFileSync(tmpFile, "utf8");
|
|
88
|
+
fs.unlinkSync(tmpFile);
|
|
89
|
+
const events = [];
|
|
90
|
+
for (const line of content.split("\n")) {
|
|
91
|
+
const trimmed = line.trim();
|
|
92
|
+
if (!trimmed)
|
|
93
|
+
continue;
|
|
94
|
+
try {
|
|
95
|
+
events.push(JSON.parse(trimmed));
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
// skip malformed lines
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return events;
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return [];
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=pending-events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pending-events.js","sourceRoot":"","sources":["../../src/lib/pending-events.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/streaming.d.ts
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
* Telemetry streaming — batch and send events to Optimus backend.
|
|
3
3
|
*/
|
|
4
4
|
import { TelemetryEvent } from "./telemetry.js";
|
|
5
|
+
/** Thrown by sendBatch when the server rejects the request with a 4xx status. Not retryable. */
|
|
6
|
+
export declare class ClientError extends Error {
|
|
7
|
+
readonly httpStatus: number;
|
|
8
|
+
constructor(status: number, message: string);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Route a send failure to the right local buffer.
|
|
12
|
+
* 4xx → client_errors.jsonl (logged, never retried)
|
|
13
|
+
* anything else → pending_events.jsonl (retried on next hook invocation)
|
|
14
|
+
* Exported for unit testing without needing to mock the HTTP stack.
|
|
15
|
+
*/
|
|
16
|
+
export declare function routeFailure(events: TelemetryEvent[], err: unknown): void;
|
|
5
17
|
/**
|
|
6
18
|
* Add an event to the queue and flush if needed.
|
|
7
19
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"streaming.d.ts","sourceRoot":"","sources":["../../src/lib/streaming.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"streaming.d.ts","sourceRoot":"","sources":["../../src/lib/streaming.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAMhD,gGAAgG;AAChG,qBAAa,WAAY,SAAQ,KAAK;IACpC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;gBAChB,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAI5C;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,cAAc,EAAE,EAAE,GAAG,EAAE,OAAO,GAAG,IAAI,CAMzE;AAsDD;;GAEG;AACH,wBAAsB,UAAU,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAyBrE;AAED;;GAEG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CA6BjD;AAwLD;;;GAGG;AACH,wBAAgB,cAAc,IAAI,IAAI,CA0BrC"}
|
package/dist/lib/streaming.js
CHANGED
|
@@ -7,6 +7,28 @@ import { ensureStartupMetadataSynced } from "./startup-sync.js";
|
|
|
7
7
|
import { cloneToolCallMetadataForWire } from "./telemetry/wire-metadata.js";
|
|
8
8
|
import { loadEndpointBase } from "./endpoint-config.js";
|
|
9
9
|
import { tryResolveHardwareUuid } from "./hardware-uuid.js";
|
|
10
|
+
import { appendPendingEvents, appendClientErrors, drainPendingEvents } from "./pending-events.js";
|
|
11
|
+
/** Thrown by sendBatch when the server rejects the request with a 4xx status. Not retryable. */
|
|
12
|
+
export class ClientError extends Error {
|
|
13
|
+
constructor(status, message) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.httpStatus = status;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Route a send failure to the right local buffer.
|
|
20
|
+
* 4xx → client_errors.jsonl (logged, never retried)
|
|
21
|
+
* anything else → pending_events.jsonl (retried on next hook invocation)
|
|
22
|
+
* Exported for unit testing without needing to mock the HTTP stack.
|
|
23
|
+
*/
|
|
24
|
+
export function routeFailure(events, err) {
|
|
25
|
+
if (err instanceof ClientError) {
|
|
26
|
+
appendClientErrors(events, err.httpStatus);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
appendPendingEvents(events);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
10
32
|
const DEBUG = !!process.env.OPTIMUS_DEBUG;
|
|
11
33
|
const dbg = (...args) => { if (DEBUG)
|
|
12
34
|
console.error(...args); };
|
|
@@ -29,11 +51,28 @@ function logBatchSent(endpoint, httpStatus, eventCount) {
|
|
|
29
51
|
}
|
|
30
52
|
// Backend configuration
|
|
31
53
|
const OPTIMUS_API_BASE = loadEndpointBase();
|
|
32
|
-
const BATCH_SIZE = parseInt(process.env.OPTIMUS_BATCH_SIZE || "1", 10); // Default to 1 for testing
|
|
33
54
|
const BATCH_TIMEOUT_MS = 5000; // 5 seconds
|
|
55
|
+
// Read at call time so tests can set OPTIMUS_BATCH_SIZE in before() after module load.
|
|
56
|
+
function getBatchSize() {
|
|
57
|
+
return parseInt(process.env.OPTIMUS_BATCH_SIZE || "1", 10);
|
|
58
|
+
}
|
|
34
59
|
// In-memory event queue
|
|
35
60
|
let eventQueue = [];
|
|
36
61
|
let batchTimer = null;
|
|
62
|
+
// Drain the pending file once per process lifetime, before the first send.
|
|
63
|
+
let pendingDrained = false;
|
|
64
|
+
async function sendPendingIfAny() {
|
|
65
|
+
const pending = drainPendingEvents();
|
|
66
|
+
if (pending.length === 0)
|
|
67
|
+
return;
|
|
68
|
+
dbg(`[optimus-tool-call] Retrying ${pending.length} pending event(s) from disk`);
|
|
69
|
+
try {
|
|
70
|
+
await sendBatch(pending);
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
routeFailure(pending, err);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
37
76
|
/**
|
|
38
77
|
* Add an event to the queue and flush if needed.
|
|
39
78
|
*/
|
|
@@ -41,9 +80,13 @@ export async function queueEvent(event) {
|
|
|
41
80
|
if (!event) {
|
|
42
81
|
return;
|
|
43
82
|
}
|
|
83
|
+
if (!pendingDrained) {
|
|
84
|
+
pendingDrained = true;
|
|
85
|
+
await sendPendingIfAny();
|
|
86
|
+
}
|
|
44
87
|
eventQueue.push(event);
|
|
45
88
|
// Flush immediately if batch size reached
|
|
46
|
-
if (eventQueue.length >=
|
|
89
|
+
if (eventQueue.length >= getBatchSize()) {
|
|
47
90
|
await flushEvents();
|
|
48
91
|
}
|
|
49
92
|
else if (!batchTimer) {
|
|
@@ -74,10 +117,13 @@ export async function flushEvents() {
|
|
|
74
117
|
await sendBatch(eventsToSend);
|
|
75
118
|
}
|
|
76
119
|
catch (err) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
120
|
+
if (err instanceof ClientError) {
|
|
121
|
+
console.error(`[optimus-tool-call] HTTP ${err.httpStatus} for ${eventsToSend.length} event(s), logging to disk (will not retry):`, err.message);
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
console.error(`[optimus-tool-call] Failed to send ${eventsToSend.length} event(s), buffering for retry:`, err instanceof Error ? err.message : String(err));
|
|
125
|
+
}
|
|
126
|
+
routeFailure(eventsToSend, err);
|
|
81
127
|
}
|
|
82
128
|
}
|
|
83
129
|
/**
|
|
@@ -157,7 +203,11 @@ async function sendBatch(events) {
|
|
|
157
203
|
if (!response.ok) {
|
|
158
204
|
const responseText = await response.text();
|
|
159
205
|
dbg(`[optimus-tool-call] Response body: ${responseText}`);
|
|
160
|
-
|
|
206
|
+
const msg = `HTTP ${response.status}: ${response.statusText} - ${responseText}`;
|
|
207
|
+
if (response.status >= 400 && response.status < 500) {
|
|
208
|
+
throw new ClientError(response.status, msg);
|
|
209
|
+
}
|
|
210
|
+
throw new Error(msg);
|
|
161
211
|
}
|
|
162
212
|
logBatchSent(endpoint, response.status, events.length);
|
|
163
213
|
dbg(`[optimus-tool-call] ✅ Successfully sent ${events.length} events`);
|
|
@@ -173,6 +223,10 @@ async function sendBatch(events) {
|
|
|
173
223
|
}
|
|
174
224
|
}
|
|
175
225
|
catch (err) {
|
|
226
|
+
if (err instanceof ClientError) {
|
|
227
|
+
console.error(`[optimus-tool-call] ❌ ${err.message}`);
|
|
228
|
+
throw err;
|
|
229
|
+
}
|
|
176
230
|
const errorMsg = `Failed to send events to ${endpoint}: ${err instanceof Error ? err.message : String(err)}`;
|
|
177
231
|
console.error(`[optimus-tool-call] ❌ ${errorMsg}`);
|
|
178
232
|
throw new Error(errorMsg);
|
|
@@ -207,6 +261,9 @@ function sendViaHttp(endpoint, headers, payload, eventCount) {
|
|
|
207
261
|
logBatchSent(endpoint, res.statusCode, eventCount);
|
|
208
262
|
resolve();
|
|
209
263
|
}
|
|
264
|
+
else if (res.statusCode && res.statusCode >= 400 && res.statusCode < 500) {
|
|
265
|
+
reject(new ClientError(res.statusCode, `HTTP ${res.statusCode}: ${data || res.statusMessage || "Client error"}`));
|
|
266
|
+
}
|
|
210
267
|
else {
|
|
211
268
|
reject(new Error(`HTTP ${res.statusCode}: ${res.statusMessage || "Unknown error"}`));
|
|
212
269
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"streaming.js","sourceRoot":"","sources":["../../src/lib/streaming.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,2BAA2B,EAAE,MAAM,mBAAmB,CAAC;AAEhE,OAAO,EAAE,4BAA4B,EAAE,MAAM,8BAA8B,CAAC;AAC5E,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"streaming.js","sourceRoot":"","sources":["../../src/lib/streaming.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,27 @@
|
|
|
1
|
-
import { test } from "node:test";
|
|
1
|
+
import { test, beforeEach, afterEach } from "node:test";
|
|
2
2
|
import assert from "node:assert";
|
|
3
3
|
import { normalizeToCanonical } from "../lib/telemetry/canonical.js";
|
|
4
|
+
// Clear agent-detection env vars so tests rely on payload-based detection,
|
|
5
|
+
// not whatever agent is running the test suite (e.g. Claude Code sets CLAUDE_CODE_SESSION_ID).
|
|
6
|
+
let _savedAgentEnv = {};
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
_savedAgentEnv = {
|
|
9
|
+
CLAUDE_CODE_SESSION_ID: process.env.CLAUDE_CODE_SESSION_ID,
|
|
10
|
+
CURSOR_SESSION_ID: process.env.CURSOR_SESSION_ID,
|
|
11
|
+
CURSOR: process.env.CURSOR,
|
|
12
|
+
};
|
|
13
|
+
delete process.env.CLAUDE_CODE_SESSION_ID;
|
|
14
|
+
delete process.env.CURSOR_SESSION_ID;
|
|
15
|
+
delete process.env.CURSOR;
|
|
16
|
+
});
|
|
17
|
+
afterEach(() => {
|
|
18
|
+
for (const [key, val] of Object.entries(_savedAgentEnv)) {
|
|
19
|
+
if (val !== undefined)
|
|
20
|
+
process.env[key] = val;
|
|
21
|
+
else
|
|
22
|
+
delete process.env[key];
|
|
23
|
+
}
|
|
24
|
+
});
|
|
4
25
|
test("normalizeToCanonical - Claude PreToolUse hook", () => {
|
|
5
26
|
const raw = {
|
|
6
27
|
hook_event_name: "PreToolUse",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"canonical.test.js","sourceRoot":"","sources":["../../src/test/canonical.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"canonical.test.js","sourceRoot":"","sources":["../../src/test/canonical.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,12 +3,18 @@ import assert from "node:assert";
|
|
|
3
3
|
import fs from "node:fs";
|
|
4
4
|
import os from "node:os";
|
|
5
5
|
import path from "node:path";
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
// Resolve workspace optimus-tofu — lib re-export may load npm when management env ≠ development.
|
|
7
|
+
import { loadEndpointBase } from "../../../optimus-tofu/dist/endpoint-config.js";
|
|
8
|
+
test("loadEndpointBase - uses default when no env and no management file", () => {
|
|
8
9
|
const root = fs.mkdtempSync(path.join(os.tmpdir(), "optimus-tool-call-default-"));
|
|
9
|
-
const
|
|
10
|
+
const fakeHome = fs.mkdtempSync(path.join(os.tmpdir(), "optimus-tool-call-home-empty-"));
|
|
11
|
+
const base = loadEndpointBase({
|
|
12
|
+
cwd: root,
|
|
13
|
+
env: { HOME: fakeHome },
|
|
14
|
+
});
|
|
10
15
|
assert.strictEqual(base, "https://demo.optimuslabs.io/");
|
|
11
16
|
fs.rmSync(root, { recursive: true, force: true });
|
|
17
|
+
fs.rmSync(fakeHome, { recursive: true, force: true });
|
|
12
18
|
});
|
|
13
19
|
test("loadEndpointBase - OPTIMUS_ENDPOINT env overrides file/default", () => {
|
|
14
20
|
const root = fs.mkdtempSync(path.join(os.tmpdir(), "optimus-tool-call-endpoint-env-"));
|
|
@@ -31,13 +37,21 @@ test("loadEndpointBase - OPTIMUS_API_URL env takes precedence", () => {
|
|
|
31
37
|
assert.strictEqual(base, "http://localhost:8080/");
|
|
32
38
|
fs.rmSync(root, { recursive: true, force: true });
|
|
33
39
|
});
|
|
34
|
-
test("loadEndpointBase - reads OPTIMUS_ENDPOINT from optimus_dev.env
|
|
40
|
+
test("loadEndpointBase - reads OPTIMUS_ENDPOINT from management optimus_dev.env (not cwd)", () => {
|
|
35
41
|
const root = fs.mkdtempSync(path.join(os.tmpdir(), "optimus-tool-call-env-file-"));
|
|
42
|
+
const fakeHome = fs.mkdtempSync(path.join(os.tmpdir(), "optimus-tool-call-home-"));
|
|
43
|
+
const mgmt = path.join(fakeHome, "opt-ai-sec", "management");
|
|
44
|
+
fs.mkdirSync(mgmt, { recursive: true });
|
|
45
|
+
fs.writeFileSync(path.join(mgmt, "optimus_dev.env"), "OPTIMUS_ENDPOINT=https://demo.optimuslabs.io\n");
|
|
36
46
|
const nested = path.join(root, "a", "b", "c");
|
|
37
47
|
fs.mkdirSync(nested, { recursive: true });
|
|
38
|
-
fs.writeFileSync(path.join(root, "optimus_dev.env"), "OPTIMUS_ENDPOINT=https://
|
|
39
|
-
const base = loadEndpointBase({
|
|
48
|
+
fs.writeFileSync(path.join(root, "optimus_dev.env"), "OPTIMUS_ENDPOINT=https://wrong-from-cwd.example/\n");
|
|
49
|
+
const base = loadEndpointBase({
|
|
50
|
+
cwd: nested,
|
|
51
|
+
env: { HOME: fakeHome },
|
|
52
|
+
});
|
|
40
53
|
assert.strictEqual(base, "https://demo.optimuslabs.io/");
|
|
41
54
|
fs.rmSync(root, { recursive: true, force: true });
|
|
55
|
+
fs.rmSync(fakeHome, { recursive: true, force: true });
|
|
42
56
|
});
|
|
43
57
|
//# sourceMappingURL=endpoint-config.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"endpoint-config.test.js","sourceRoot":"","sources":["../../src/test/endpoint-config.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,gBAAgB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"endpoint-config.test.js","sourceRoot":"","sources":["../../src/test/endpoint-config.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,26 @@
|
|
|
1
|
-
import { test } from "node:test";
|
|
1
|
+
import { test, beforeEach, afterEach } from "node:test";
|
|
2
2
|
import assert from "node:assert";
|
|
3
3
|
import { buildTelemetryEvent } from "../lib/telemetry.js";
|
|
4
4
|
import { normalizeToCanonical } from "../lib/telemetry/canonical.js";
|
|
5
|
+
let _savedAgentEnv = {};
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
_savedAgentEnv = {
|
|
8
|
+
CLAUDE_CODE_SESSION_ID: process.env.CLAUDE_CODE_SESSION_ID,
|
|
9
|
+
CURSOR_SESSION_ID: process.env.CURSOR_SESSION_ID,
|
|
10
|
+
CURSOR: process.env.CURSOR,
|
|
11
|
+
};
|
|
12
|
+
delete process.env.CLAUDE_CODE_SESSION_ID;
|
|
13
|
+
delete process.env.CURSOR_SESSION_ID;
|
|
14
|
+
delete process.env.CURSOR;
|
|
15
|
+
});
|
|
16
|
+
afterEach(() => {
|
|
17
|
+
for (const [key, val] of Object.entries(_savedAgentEnv)) {
|
|
18
|
+
if (val !== undefined)
|
|
19
|
+
process.env[key] = val;
|
|
20
|
+
else
|
|
21
|
+
delete process.env[key];
|
|
22
|
+
}
|
|
23
|
+
});
|
|
5
24
|
/**
|
|
6
25
|
* Integration tests verifying that Claude and Cursor produce identical
|
|
7
26
|
* telemetry events for the same tool invocations.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"integration-canonical.test.js","sourceRoot":"","sources":["../../src/test/integration-canonical.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"integration-canonical.test.js","sourceRoot":"","sources":["../../src/test/integration-canonical.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for pending-events.ts and streaming.ts failure routing.
|
|
3
|
+
*
|
|
4
|
+
* pending-events.ts functions are tested against a temp dir via
|
|
5
|
+
* OPTIMUS_TELEMETRY_DIR so we exercise the real code paths without
|
|
6
|
+
* touching ~/opt-ai-sec/management/telemetry on the developer's machine.
|
|
7
|
+
*
|
|
8
|
+
* routeFailure + ClientError are tested to prove that 4xx errors go to
|
|
9
|
+
* client_errors.jsonl and network errors go to pending_events.jsonl without
|
|
10
|
+
* needing to mock the full HTTP stack.
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=pending-events.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pending-events.test.d.ts","sourceRoot":"","sources":["../../src/test/pending-events.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG"}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for pending-events.ts and streaming.ts failure routing.
|
|
3
|
+
*
|
|
4
|
+
* pending-events.ts functions are tested against a temp dir via
|
|
5
|
+
* OPTIMUS_TELEMETRY_DIR so we exercise the real code paths without
|
|
6
|
+
* touching ~/opt-ai-sec/management/telemetry on the developer's machine.
|
|
7
|
+
*
|
|
8
|
+
* routeFailure + ClientError are tested to prove that 4xx errors go to
|
|
9
|
+
* client_errors.jsonl and network errors go to pending_events.jsonl without
|
|
10
|
+
* needing to mock the full HTTP stack.
|
|
11
|
+
*/
|
|
12
|
+
import { test, before, after, beforeEach } from "node:test";
|
|
13
|
+
import assert from "node:assert";
|
|
14
|
+
import fs from "fs";
|
|
15
|
+
import os from "os";
|
|
16
|
+
import path from "path";
|
|
17
|
+
// --- Temp dir setup ---
|
|
18
|
+
const tmpDir = path.join(os.tmpdir(), `optimus-pending-test-${process.pid}`);
|
|
19
|
+
before(() => {
|
|
20
|
+
fs.mkdirSync(tmpDir, { recursive: true });
|
|
21
|
+
process.env.OPTIMUS_TELEMETRY_DIR = tmpDir;
|
|
22
|
+
});
|
|
23
|
+
after(() => {
|
|
24
|
+
delete process.env.OPTIMUS_TELEMETRY_DIR;
|
|
25
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
26
|
+
});
|
|
27
|
+
// Clear any files between tests so they don't interfere with each other.
|
|
28
|
+
beforeEach(() => {
|
|
29
|
+
for (const f of fs.readdirSync(tmpDir)) {
|
|
30
|
+
fs.rmSync(path.join(tmpDir, f), { force: true });
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
// Imports must come AFTER env var is set so getPendingDir() resolves correctly.
|
|
34
|
+
// Node ESM caches modules, but getPendingDir() is called lazily so the env
|
|
35
|
+
// var set in `before()` is picked up on each function call.
|
|
36
|
+
import { appendPendingEvents, drainPendingEvents, appendClientErrors, getPendingDir, getPendingFile, getClientErrorsFile, } from "../lib/pending-events.js";
|
|
37
|
+
import { ClientError, routeFailure } from "../lib/streaming.js";
|
|
38
|
+
function mockEvent(id) {
|
|
39
|
+
return {
|
|
40
|
+
timestamp: "2024-01-01T00:00:00Z",
|
|
41
|
+
agent_identity: "test",
|
|
42
|
+
event_type: "tool_call",
|
|
43
|
+
tool_use_id: id,
|
|
44
|
+
tool_call_metadata: { tool_name: "Bash", tool_input: { command: "ls" } },
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
// ── getPendingDir / path helpers ────────────────────────────────────────────
|
|
48
|
+
test("getPendingDir returns OPTIMUS_TELEMETRY_DIR when set", () => {
|
|
49
|
+
assert.strictEqual(getPendingDir(), tmpDir);
|
|
50
|
+
});
|
|
51
|
+
test("getPendingFile points inside OPTIMUS_TELEMETRY_DIR", () => {
|
|
52
|
+
assert.strictEqual(path.dirname(getPendingFile()), tmpDir);
|
|
53
|
+
assert.ok(getPendingFile().endsWith("pending_events.jsonl"));
|
|
54
|
+
});
|
|
55
|
+
test("getClientErrorsFile points inside OPTIMUS_TELEMETRY_DIR", () => {
|
|
56
|
+
assert.strictEqual(path.dirname(getClientErrorsFile()), tmpDir);
|
|
57
|
+
assert.ok(getClientErrorsFile().endsWith("client_errors.jsonl"));
|
|
58
|
+
});
|
|
59
|
+
// ── appendPendingEvents ──────────────────────────────────────────────────────
|
|
60
|
+
test("appendPendingEvents creates file on first call", () => {
|
|
61
|
+
appendPendingEvents([mockEvent("p1")]);
|
|
62
|
+
assert.ok(fs.existsSync(getPendingFile()));
|
|
63
|
+
});
|
|
64
|
+
test("appendPendingEvents writes one JSONL line per event", () => {
|
|
65
|
+
appendPendingEvents([mockEvent("a"), mockEvent("b")]);
|
|
66
|
+
const lines = fs.readFileSync(getPendingFile(), "utf8").trim().split("\n");
|
|
67
|
+
assert.strictEqual(lines.length, 2);
|
|
68
|
+
assert.strictEqual(JSON.parse(lines[0]).tool_use_id, "a");
|
|
69
|
+
assert.strictEqual(JSON.parse(lines[1]).tool_use_id, "b");
|
|
70
|
+
});
|
|
71
|
+
test("appendPendingEvents accumulates across multiple calls", () => {
|
|
72
|
+
appendPendingEvents([mockEvent("x1")]);
|
|
73
|
+
appendPendingEvents([mockEvent("x2"), mockEvent("x3")]);
|
|
74
|
+
const events = drainPendingEvents();
|
|
75
|
+
assert.strictEqual(events.length, 3);
|
|
76
|
+
assert.strictEqual(events[0].tool_use_id, "x1");
|
|
77
|
+
assert.strictEqual(events[2].tool_use_id, "x3");
|
|
78
|
+
});
|
|
79
|
+
test("appendPendingEvents is a no-op for empty array", () => {
|
|
80
|
+
appendPendingEvents([]);
|
|
81
|
+
assert.ok(!fs.existsSync(getPendingFile()));
|
|
82
|
+
});
|
|
83
|
+
// ── drainPendingEvents ───────────────────────────────────────────────────────
|
|
84
|
+
test("drainPendingEvents returns [] when no file exists", () => {
|
|
85
|
+
assert.deepStrictEqual(drainPendingEvents(), []);
|
|
86
|
+
});
|
|
87
|
+
test("drainPendingEvents returns all written events", () => {
|
|
88
|
+
appendPendingEvents([mockEvent("r1"), mockEvent("r2")]);
|
|
89
|
+
const events = drainPendingEvents();
|
|
90
|
+
assert.strictEqual(events.length, 2);
|
|
91
|
+
assert.strictEqual(events[0].tool_use_id, "r1");
|
|
92
|
+
assert.strictEqual(events[1].tool_use_id, "r2");
|
|
93
|
+
});
|
|
94
|
+
test("drainPendingEvents removes the file", () => {
|
|
95
|
+
appendPendingEvents([mockEvent("d1")]);
|
|
96
|
+
drainPendingEvents();
|
|
97
|
+
assert.ok(!fs.existsSync(getPendingFile()));
|
|
98
|
+
});
|
|
99
|
+
test("drainPendingEvents is idempotent — second drain returns []", () => {
|
|
100
|
+
appendPendingEvents([mockEvent("i1")]);
|
|
101
|
+
drainPendingEvents();
|
|
102
|
+
assert.deepStrictEqual(drainPendingEvents(), []);
|
|
103
|
+
});
|
|
104
|
+
test("drainPendingEvents skips malformed lines", () => {
|
|
105
|
+
fs.writeFileSync(getPendingFile(), `${JSON.stringify(mockEvent("ok1"))}\nnot-json\n${JSON.stringify(mockEvent("ok2"))}\n`, "utf8");
|
|
106
|
+
const events = drainPendingEvents();
|
|
107
|
+
assert.strictEqual(events.length, 2);
|
|
108
|
+
assert.strictEqual(events[0].tool_use_id, "ok1");
|
|
109
|
+
assert.strictEqual(events[1].tool_use_id, "ok2");
|
|
110
|
+
});
|
|
111
|
+
test("drainPendingEvents is atomic — concurrent drain sees no file", () => {
|
|
112
|
+
appendPendingEvents([mockEvent("a1")]);
|
|
113
|
+
const tmp = getPendingFile() + ".draining";
|
|
114
|
+
fs.renameSync(getPendingFile(), tmp);
|
|
115
|
+
assert.deepStrictEqual(drainPendingEvents(), []);
|
|
116
|
+
fs.unlinkSync(tmp);
|
|
117
|
+
});
|
|
118
|
+
// ── appendClientErrors ───────────────────────────────────────────────────────
|
|
119
|
+
test("appendClientErrors creates client_errors.jsonl", () => {
|
|
120
|
+
appendClientErrors([mockEvent("c1")], 400);
|
|
121
|
+
assert.ok(fs.existsSync(getClientErrorsFile()));
|
|
122
|
+
});
|
|
123
|
+
test("appendClientErrors stores http_status alongside event", () => {
|
|
124
|
+
appendClientErrors([mockEvent("c2")], 422);
|
|
125
|
+
const line = fs.readFileSync(getClientErrorsFile(), "utf8").trim();
|
|
126
|
+
const entry = JSON.parse(line);
|
|
127
|
+
assert.strictEqual(entry.http_status, 422);
|
|
128
|
+
assert.strictEqual(entry.event.tool_use_id, "c2");
|
|
129
|
+
});
|
|
130
|
+
test("appendClientErrors stores a valid failed_at ISO timestamp", () => {
|
|
131
|
+
appendClientErrors([mockEvent("c3")], 403);
|
|
132
|
+
const line = fs.readFileSync(getClientErrorsFile(), "utf8").trim();
|
|
133
|
+
const entry = JSON.parse(line);
|
|
134
|
+
assert.ok(!isNaN(new Date(entry.failed_at).getTime()));
|
|
135
|
+
});
|
|
136
|
+
test("appendClientErrors accumulates multiple calls", () => {
|
|
137
|
+
appendClientErrors([mockEvent("d1")], 400);
|
|
138
|
+
appendClientErrors([mockEvent("d2")], 403);
|
|
139
|
+
const lines = fs.readFileSync(getClientErrorsFile(), "utf8").trim().split("\n");
|
|
140
|
+
assert.strictEqual(lines.length, 2);
|
|
141
|
+
assert.strictEqual(JSON.parse(lines[0]).http_status, 400);
|
|
142
|
+
assert.strictEqual(JSON.parse(lines[1]).http_status, 403);
|
|
143
|
+
});
|
|
144
|
+
test("appendClientErrors does not touch pending_events.jsonl", () => {
|
|
145
|
+
appendClientErrors([mockEvent("e1")], 400);
|
|
146
|
+
assert.ok(!fs.existsSync(getPendingFile()));
|
|
147
|
+
});
|
|
148
|
+
test("appendClientErrors is a no-op for empty array", () => {
|
|
149
|
+
appendClientErrors([], 400);
|
|
150
|
+
assert.ok(!fs.existsSync(getClientErrorsFile()));
|
|
151
|
+
});
|
|
152
|
+
// ── ClientError ──────────────────────────────────────────────────────────────
|
|
153
|
+
test("ClientError stores httpStatus", () => {
|
|
154
|
+
const err = new ClientError(400, "bad request");
|
|
155
|
+
assert.strictEqual(err.httpStatus, 400);
|
|
156
|
+
assert.ok(err instanceof Error);
|
|
157
|
+
});
|
|
158
|
+
test("ClientError is instanceof Error and ClientError", () => {
|
|
159
|
+
const err = new ClientError(422, "unprocessable");
|
|
160
|
+
assert.ok(err instanceof ClientError);
|
|
161
|
+
assert.ok(err instanceof Error);
|
|
162
|
+
});
|
|
163
|
+
// ── routeFailure — the critical branching logic ──────────────────────────────
|
|
164
|
+
test("routeFailure writes to client_errors.jsonl for ClientError (4xx)", () => {
|
|
165
|
+
const events = [mockEvent("route-4xx")];
|
|
166
|
+
routeFailure(events, new ClientError(400, "bad request"));
|
|
167
|
+
assert.ok(fs.existsSync(getClientErrorsFile()), "client_errors.jsonl should exist");
|
|
168
|
+
assert.ok(!fs.existsSync(getPendingFile()), "pending_events.jsonl should NOT exist");
|
|
169
|
+
const line = JSON.parse(fs.readFileSync(getClientErrorsFile(), "utf8").trim());
|
|
170
|
+
assert.strictEqual(line.http_status, 400);
|
|
171
|
+
assert.strictEqual(line.event.tool_use_id, "route-4xx");
|
|
172
|
+
});
|
|
173
|
+
test("routeFailure writes to pending_events.jsonl for network error", () => {
|
|
174
|
+
const events = [mockEvent("route-net")];
|
|
175
|
+
routeFailure(events, new Error("fetch failed"));
|
|
176
|
+
assert.ok(fs.existsSync(getPendingFile()), "pending_events.jsonl should exist");
|
|
177
|
+
assert.ok(!fs.existsSync(getClientErrorsFile()), "client_errors.jsonl should NOT exist");
|
|
178
|
+
const drained = drainPendingEvents();
|
|
179
|
+
assert.strictEqual(drained.length, 1);
|
|
180
|
+
assert.strictEqual(drained[0].tool_use_id, "route-net");
|
|
181
|
+
});
|
|
182
|
+
test("routeFailure with 401 goes to client_errors, not pending", () => {
|
|
183
|
+
routeFailure([mockEvent("route-401")], new ClientError(401, "unauthorized"));
|
|
184
|
+
assert.ok(fs.existsSync(getClientErrorsFile()));
|
|
185
|
+
assert.ok(!fs.existsSync(getPendingFile()));
|
|
186
|
+
});
|
|
187
|
+
test("routeFailure with 422 records correct status in client_errors", () => {
|
|
188
|
+
routeFailure([mockEvent("route-422")], new ClientError(422, "validation failed"));
|
|
189
|
+
const line = JSON.parse(fs.readFileSync(getClientErrorsFile(), "utf8").trim());
|
|
190
|
+
assert.strictEqual(line.http_status, 422);
|
|
191
|
+
});
|
|
192
|
+
test("routeFailure with timeout error goes to pending for retry", () => {
|
|
193
|
+
routeFailure([mockEvent("timeout")], new Error("Request timeout"));
|
|
194
|
+
const drained = drainPendingEvents();
|
|
195
|
+
assert.strictEqual(drained.length, 1);
|
|
196
|
+
assert.strictEqual(drained[0].tool_use_id, "timeout");
|
|
197
|
+
});
|
|
198
|
+
test("routeFailure separates: network failure then 4xx both recorded correctly", () => {
|
|
199
|
+
routeFailure([mockEvent("net1")], new Error("ECONNREFUSED"));
|
|
200
|
+
routeFailure([mockEvent("client1")], new ClientError(400, "bad"));
|
|
201
|
+
// pending has the network failure event
|
|
202
|
+
const drained = drainPendingEvents();
|
|
203
|
+
assert.strictEqual(drained.length, 1);
|
|
204
|
+
assert.strictEqual(drained[0].tool_use_id, "net1");
|
|
205
|
+
// client_errors has the 4xx event
|
|
206
|
+
const errLine = JSON.parse(fs.readFileSync(getClientErrorsFile(), "utf8").trim());
|
|
207
|
+
assert.strictEqual(errLine.event.tool_use_id, "client1");
|
|
208
|
+
});
|
|
209
|
+
//# sourceMappingURL=pending-events.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pending-events.test.js","sourceRoot":"","sources":["../../src/test/pending-events.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* End-to-end HTTP routing tests for streaming.ts.
|
|
3
|
+
*
|
|
4
|
+
* These tests prove that the actual fetch response (4xx, 5xx, network error)
|
|
5
|
+
* causes events to land in the right local file — without mocking the routing
|
|
6
|
+
* logic itself. globalThis.fetch is replaced with a controllable stub, and a
|
|
7
|
+
* fake auth key is pre-written so the auth handshake passes without hitting
|
|
8
|
+
* a real backend.
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=streaming-http.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"streaming-http.test.d.ts","sourceRoot":"","sources":["../../src/test/streaming-http.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* End-to-end HTTP routing tests for streaming.ts.
|
|
3
|
+
*
|
|
4
|
+
* These tests prove that the actual fetch response (4xx, 5xx, network error)
|
|
5
|
+
* causes events to land in the right local file — without mocking the routing
|
|
6
|
+
* logic itself. globalThis.fetch is replaced with a controllable stub, and a
|
|
7
|
+
* fake auth key is pre-written so the auth handshake passes without hitting
|
|
8
|
+
* a real backend.
|
|
9
|
+
*/
|
|
10
|
+
import { test, before, after, beforeEach } from "node:test";
|
|
11
|
+
import assert from "node:assert";
|
|
12
|
+
import fs from "fs";
|
|
13
|
+
import os from "os";
|
|
14
|
+
import path from "path";
|
|
15
|
+
import { queueEvent } from "../lib/streaming.js";
|
|
16
|
+
import { getPendingFile, getClientErrorsFile } from "../lib/pending-events.js";
|
|
17
|
+
// ── Temp environment ────────────────────────────────────────────────────────
|
|
18
|
+
const tmpDir = path.join(os.tmpdir(), `optimus-stream-http-${process.pid}`);
|
|
19
|
+
const telemetryDir = path.join(tmpDir, "telemetry");
|
|
20
|
+
const authKeyPath = path.join(tmpDir, "opt-ai-sec", "management", "auth_key.txt");
|
|
21
|
+
// Hardware UUID written into the fake auth key — must match OPTIMUS_HARDWARE_UUID.
|
|
22
|
+
const HARDWARE_UUID = "test-uuid-http-aabbcc";
|
|
23
|
+
// ── Fetch stub ──────────────────────────────────────────────────────────────
|
|
24
|
+
// Each test sets this to control what batch_create returns.
|
|
25
|
+
let batchResponse = { status: 200 };
|
|
26
|
+
const originalFetch = globalThis.fetch;
|
|
27
|
+
function stubFetch(url, _init) {
|
|
28
|
+
const u = String(url);
|
|
29
|
+
// Auth handshake — always succeed so auth never blocks the batch send.
|
|
30
|
+
if (u.includes("/endpoint_security/auth/")) {
|
|
31
|
+
return Promise.resolve(new Response(JSON.stringify({ status: "authenticated" }), {
|
|
32
|
+
status: 200,
|
|
33
|
+
headers: { "Content-Type": "application/json" },
|
|
34
|
+
}));
|
|
35
|
+
}
|
|
36
|
+
// Startup sync is disabled via env, but guard here too.
|
|
37
|
+
if (u.includes("/endpoint_security/startup/")) {
|
|
38
|
+
return Promise.resolve(new Response("{}", { status: 200 }));
|
|
39
|
+
}
|
|
40
|
+
// Batch ingest — controlled per test.
|
|
41
|
+
if (u.includes("/api/tool-calls/events/batch_create/")) {
|
|
42
|
+
if (batchResponse === "network_error") {
|
|
43
|
+
return Promise.reject(new Error("fetch failed: ECONNREFUSED"));
|
|
44
|
+
}
|
|
45
|
+
const { status } = batchResponse;
|
|
46
|
+
const body = status < 400 ? '{"status":"ok"}' : `{"error":"test rejection ${status}"}`;
|
|
47
|
+
return Promise.resolve(new Response(body, { status }));
|
|
48
|
+
}
|
|
49
|
+
return Promise.reject(new Error(`Unexpected URL in test stub: ${u}`));
|
|
50
|
+
}
|
|
51
|
+
// ── Lifecycle ───────────────────────────────────────────────────────────────
|
|
52
|
+
before(() => {
|
|
53
|
+
// Pre-write a fake auth key so readStoredAuthKey succeeds on first call.
|
|
54
|
+
fs.mkdirSync(path.dirname(authKeyPath), { recursive: true });
|
|
55
|
+
fs.writeFileSync(authKeyPath, JSON.stringify({
|
|
56
|
+
key: "test-signing-key-aaaabbbbcccc",
|
|
57
|
+
key_id: "test-key-id",
|
|
58
|
+
hardware_uuid: HARDWARE_UUID,
|
|
59
|
+
stored_at: new Date().toISOString(),
|
|
60
|
+
}), { mode: 0o600 });
|
|
61
|
+
fs.mkdirSync(telemetryDir, { recursive: true });
|
|
62
|
+
process.env.HOME = tmpDir;
|
|
63
|
+
process.env.OPTIMUS_TELEMETRY_DIR = telemetryDir;
|
|
64
|
+
process.env.OPTIMUS_HARDWARE_UUID = HARDWARE_UUID;
|
|
65
|
+
process.env.OPTIMUS_SKIP_STARTUP_SYNC = "1";
|
|
66
|
+
process.env.OPTIMUS_BATCH_SIZE = "1"; // flush on every queueEvent call
|
|
67
|
+
globalThis.fetch = stubFetch;
|
|
68
|
+
});
|
|
69
|
+
after(() => {
|
|
70
|
+
globalThis.fetch = originalFetch;
|
|
71
|
+
delete process.env.OPTIMUS_TELEMETRY_DIR;
|
|
72
|
+
delete process.env.OPTIMUS_HARDWARE_UUID;
|
|
73
|
+
delete process.env.OPTIMUS_SKIP_STARTUP_SYNC;
|
|
74
|
+
delete process.env.OPTIMUS_BATCH_SIZE;
|
|
75
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
76
|
+
});
|
|
77
|
+
beforeEach(() => {
|
|
78
|
+
// Clear telemetry files between tests.
|
|
79
|
+
try {
|
|
80
|
+
for (const f of fs.readdirSync(telemetryDir)) {
|
|
81
|
+
fs.rmSync(path.join(telemetryDir, f), { force: true });
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch { /* dir may not exist yet */ }
|
|
85
|
+
batchResponse = { status: 200 };
|
|
86
|
+
});
|
|
87
|
+
// ── Helpers ─────────────────────────────────────────────────────────────────
|
|
88
|
+
function makeEvent(id) {
|
|
89
|
+
return {
|
|
90
|
+
timestamp: new Date().toISOString(),
|
|
91
|
+
agent_identity: "test",
|
|
92
|
+
event_type: "tool_call",
|
|
93
|
+
tool_use_id: id,
|
|
94
|
+
tool_call_metadata: { tool_name: "Bash", tool_input: { command: "ls" } },
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
async function sendOne(id) {
|
|
98
|
+
await queueEvent(makeEvent(id));
|
|
99
|
+
}
|
|
100
|
+
// ── Tests ───────────────────────────────────────────────────────────────────
|
|
101
|
+
test("200 OK — no local files written", async () => {
|
|
102
|
+
batchResponse = { status: 200 };
|
|
103
|
+
await sendOne("ok-1");
|
|
104
|
+
assert.ok(!fs.existsSync(getPendingFile()), "pending_events.jsonl should not exist on success");
|
|
105
|
+
assert.ok(!fs.existsSync(getClientErrorsFile()), "client_errors.jsonl should not exist on success");
|
|
106
|
+
});
|
|
107
|
+
test("400 Bad Request — written to client_errors.jsonl, not pending", async () => {
|
|
108
|
+
batchResponse = { status: 400 };
|
|
109
|
+
await sendOne("bad-400");
|
|
110
|
+
assert.ok(fs.existsSync(getClientErrorsFile()), "client_errors.jsonl should exist");
|
|
111
|
+
assert.ok(!fs.existsSync(getPendingFile()), "pending_events.jsonl should NOT exist for 4xx");
|
|
112
|
+
const entry = JSON.parse(fs.readFileSync(getClientErrorsFile(), "utf8").trim());
|
|
113
|
+
assert.strictEqual(entry.http_status, 400);
|
|
114
|
+
assert.strictEqual(entry.event.tool_use_id, "bad-400");
|
|
115
|
+
});
|
|
116
|
+
test("422 Unprocessable — written to client_errors.jsonl with correct status", async () => {
|
|
117
|
+
batchResponse = { status: 422 };
|
|
118
|
+
await sendOne("bad-422");
|
|
119
|
+
const entry = JSON.parse(fs.readFileSync(getClientErrorsFile(), "utf8").trim());
|
|
120
|
+
assert.strictEqual(entry.http_status, 422);
|
|
121
|
+
assert.ok(!fs.existsSync(getPendingFile()));
|
|
122
|
+
});
|
|
123
|
+
test("401 Unauthorized — written to client_errors.jsonl (not retried)", async () => {
|
|
124
|
+
batchResponse = { status: 401 };
|
|
125
|
+
await sendOne("bad-401");
|
|
126
|
+
assert.ok(fs.existsSync(getClientErrorsFile()));
|
|
127
|
+
assert.ok(!fs.existsSync(getPendingFile()));
|
|
128
|
+
});
|
|
129
|
+
test("500 Server Error — written to pending_events.jsonl for retry", async () => {
|
|
130
|
+
batchResponse = { status: 500 };
|
|
131
|
+
await sendOne("server-err");
|
|
132
|
+
assert.ok(fs.existsSync(getPendingFile()), "pending_events.jsonl should exist for 5xx");
|
|
133
|
+
assert.ok(!fs.existsSync(getClientErrorsFile()), "client_errors.jsonl should NOT exist for 5xx");
|
|
134
|
+
const lines = fs.readFileSync(getPendingFile(), "utf8").trim().split("\n");
|
|
135
|
+
const event = JSON.parse(lines[0]);
|
|
136
|
+
assert.strictEqual(event.tool_use_id, "server-err");
|
|
137
|
+
});
|
|
138
|
+
test("503 Service Unavailable — written to pending_events.jsonl for retry", async () => {
|
|
139
|
+
batchResponse = { status: 503 };
|
|
140
|
+
await sendOne("svc-unavail");
|
|
141
|
+
assert.ok(fs.existsSync(getPendingFile()));
|
|
142
|
+
assert.ok(!fs.existsSync(getClientErrorsFile()));
|
|
143
|
+
});
|
|
144
|
+
test("Network error (ECONNREFUSED) — written to pending_events.jsonl for retry", async () => {
|
|
145
|
+
batchResponse = "network_error";
|
|
146
|
+
await sendOne("net-fail");
|
|
147
|
+
assert.ok(fs.existsSync(getPendingFile()), "pending_events.jsonl should exist on network failure");
|
|
148
|
+
assert.ok(!fs.existsSync(getClientErrorsFile()));
|
|
149
|
+
const lines = fs.readFileSync(getPendingFile(), "utf8").trim().split("\n");
|
|
150
|
+
assert.strictEqual(JSON.parse(lines[0]).tool_use_id, "net-fail");
|
|
151
|
+
});
|
|
152
|
+
test("client_errors.jsonl entry has failed_at timestamp", async () => {
|
|
153
|
+
batchResponse = { status: 400 };
|
|
154
|
+
await sendOne("ts-check");
|
|
155
|
+
const entry = JSON.parse(fs.readFileSync(getClientErrorsFile(), "utf8").trim());
|
|
156
|
+
assert.ok(!isNaN(new Date(entry.failed_at).getTime()), "failed_at must be a valid ISO date");
|
|
157
|
+
});
|
|
158
|
+
test("multiple 4xx events accumulate in client_errors.jsonl", async () => {
|
|
159
|
+
batchResponse = { status: 400 };
|
|
160
|
+
await sendOne("multi-1");
|
|
161
|
+
await sendOne("multi-2");
|
|
162
|
+
const lines = fs.readFileSync(getClientErrorsFile(), "utf8").trim().split("\n");
|
|
163
|
+
assert.strictEqual(lines.length, 2);
|
|
164
|
+
assert.strictEqual(JSON.parse(lines[0]).event.tool_use_id, "multi-1");
|
|
165
|
+
assert.strictEqual(JSON.parse(lines[1]).event.tool_use_id, "multi-2");
|
|
166
|
+
});
|
|
167
|
+
test("mixed: 400 then 500 — correct files written independently", async () => {
|
|
168
|
+
batchResponse = { status: 400 };
|
|
169
|
+
await sendOne("mix-4xx");
|
|
170
|
+
batchResponse = { status: 500 };
|
|
171
|
+
await sendOne("mix-5xx");
|
|
172
|
+
// client_errors has the 4xx event
|
|
173
|
+
const errLines = fs.readFileSync(getClientErrorsFile(), "utf8").trim().split("\n");
|
|
174
|
+
assert.strictEqual(errLines.length, 1);
|
|
175
|
+
assert.strictEqual(JSON.parse(errLines[0]).event.tool_use_id, "mix-4xx");
|
|
176
|
+
// pending has the 5xx event
|
|
177
|
+
const pendingLines = fs.readFileSync(getPendingFile(), "utf8").trim().split("\n");
|
|
178
|
+
assert.strictEqual(pendingLines.length, 1);
|
|
179
|
+
assert.strictEqual(JSON.parse(pendingLines[0]).tool_use_id, "mix-5xx");
|
|
180
|
+
});
|
|
181
|
+
//# sourceMappingURL=streaming-http.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"streaming-http.test.js","sourceRoot":"","sources":["../../src/test/streaming-http.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "optimus-tool-call-staging",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.13",
|
|
4
4
|
"description": "Agentic audit sensor — streams raw tool call metadata; the Optimus backend classifies on ingest",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"scripts": {
|
|
12
12
|
"build": "rm -rf dist && tsc && node ../../scripts/ensure-bin-executable.mjs",
|
|
13
13
|
"dev": "tsx src/index.ts",
|
|
14
|
+
"pretest": "npm run build --prefix ../optimus-tofu && npm run build",
|
|
14
15
|
"test": "node --test dist/test/*.test.js",
|
|
15
16
|
"prepare": "npm run build"
|
|
16
17
|
},
|
|
@@ -45,6 +46,6 @@
|
|
|
45
46
|
"typescript": "^5.0.0"
|
|
46
47
|
},
|
|
47
48
|
"dependencies": {
|
|
48
|
-
"optimus-tofu-staging": "
|
|
49
|
+
"optimus-tofu-staging": "file:../optimus-tofu"
|
|
49
50
|
}
|
|
50
51
|
}
|