lightrace 0.1.6 → 0.1.8
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/client.d.ts +14 -35
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +60 -84
- package/dist/client.js.map +1 -1
- package/dist/dev-server.d.ts +18 -0
- package/dist/dev-server.d.ts.map +1 -0
- package/dist/dev-server.js +95 -0
- package/dist/dev-server.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/integrations/_base.d.ts +70 -0
- package/dist/integrations/_base.d.ts.map +1 -0
- package/dist/integrations/_base.js +167 -0
- package/dist/integrations/_base.js.map +1 -0
- package/dist/integrations/anthropic.d.ts +15 -0
- package/dist/integrations/anthropic.d.ts.map +1 -0
- package/dist/integrations/anthropic.js +229 -0
- package/dist/integrations/anthropic.js.map +1 -0
- package/dist/integrations/llamaindex.d.ts +14 -0
- package/dist/integrations/llamaindex.d.ts.map +1 -0
- package/dist/integrations/llamaindex.js +222 -0
- package/dist/integrations/llamaindex.js.map +1 -0
- package/dist/integrations/openai.d.ts +17 -0
- package/dist/integrations/openai.d.ts.map +1 -0
- package/dist/integrations/openai.js +259 -0
- package/dist/integrations/openai.js.map +1 -0
- package/dist/trace.d.ts.map +1 -1
- package/dist/trace.js +2 -1
- package/dist/trace.js.map +1 -1
- package/dist/types.d.ts +2 -39
- package/dist/types.d.ts.map +1 -1
- package/package.json +31 -5
- package/dist/security.d.ts +0 -20
- package/dist/security.d.ts.map +0 -1
- package/dist/security.js +0 -46
- package/dist/security.js.map +0 -1
- package/dist/tool-client.d.ts +0 -46
- package/dist/tool-client.d.ts.map +0 -1
- package/dist/tool-client.js +0 -237
- package/dist/tool-client.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lightrace",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.1.8",
|
|
4
|
+
"description": "Agentic development kit — LLM tracing, tool management, and agent primitives",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
@@ -13,6 +13,18 @@
|
|
|
13
13
|
"./integrations/langchain": {
|
|
14
14
|
"import": "./dist/integrations/langchain.js",
|
|
15
15
|
"types": "./dist/integrations/langchain.d.ts"
|
|
16
|
+
},
|
|
17
|
+
"./integrations/anthropic": {
|
|
18
|
+
"import": "./dist/integrations/anthropic.js",
|
|
19
|
+
"types": "./dist/integrations/anthropic.d.ts"
|
|
20
|
+
},
|
|
21
|
+
"./integrations/openai": {
|
|
22
|
+
"import": "./dist/integrations/openai.js",
|
|
23
|
+
"types": "./dist/integrations/openai.d.ts"
|
|
24
|
+
},
|
|
25
|
+
"./integrations/llamaindex": {
|
|
26
|
+
"import": "./dist/integrations/llamaindex.js",
|
|
27
|
+
"types": "./dist/integrations/llamaindex.d.ts"
|
|
16
28
|
}
|
|
17
29
|
},
|
|
18
30
|
"files": [
|
|
@@ -33,16 +45,16 @@
|
|
|
33
45
|
"precommit": "lint-staged"
|
|
34
46
|
},
|
|
35
47
|
"dependencies": {
|
|
48
|
+
"@hono/node-server": "^1.14.3",
|
|
36
49
|
"@opentelemetry/api": "^1.9.0",
|
|
37
50
|
"@opentelemetry/exporter-trace-otlp-http": "^0.213.0",
|
|
38
51
|
"@opentelemetry/sdk-trace-base": "^2.6.0",
|
|
39
|
-
"
|
|
52
|
+
"hono": "^4.8.3"
|
|
40
53
|
},
|
|
41
54
|
"devDependencies": {
|
|
42
55
|
"@eslint/js": "^9.0.0",
|
|
43
56
|
"@langchain/core": "^1.1.32",
|
|
44
57
|
"@types/node": "^22.0.0",
|
|
45
|
-
"@types/ws": "^8.5.0",
|
|
46
58
|
"eslint": "^9.0.0",
|
|
47
59
|
"husky": "^9.1.0",
|
|
48
60
|
"lint-staged": "^16.0.0",
|
|
@@ -54,6 +66,9 @@
|
|
|
54
66
|
},
|
|
55
67
|
"peerDependencies": {
|
|
56
68
|
"@langchain/core": ">=0.2.0",
|
|
69
|
+
"@anthropic-ai/sdk": ">=0.30.0",
|
|
70
|
+
"openai": ">=4.0.0",
|
|
71
|
+
"llamaindex": ">=0.5.0",
|
|
57
72
|
"zod": "^3.0.0"
|
|
58
73
|
},
|
|
59
74
|
"peerDependenciesMeta": {
|
|
@@ -62,6 +77,15 @@
|
|
|
62
77
|
},
|
|
63
78
|
"@langchain/core": {
|
|
64
79
|
"optional": true
|
|
80
|
+
},
|
|
81
|
+
"@anthropic-ai/sdk": {
|
|
82
|
+
"optional": true
|
|
83
|
+
},
|
|
84
|
+
"openai": {
|
|
85
|
+
"optional": true
|
|
86
|
+
},
|
|
87
|
+
"llamaindex": {
|
|
88
|
+
"optional": true
|
|
65
89
|
}
|
|
66
90
|
},
|
|
67
91
|
"lint-staged": {
|
|
@@ -81,7 +105,9 @@
|
|
|
81
105
|
"observability",
|
|
82
106
|
"langfuse",
|
|
83
107
|
"opentelemetry",
|
|
84
|
-
"
|
|
108
|
+
"agent",
|
|
109
|
+
"adk",
|
|
110
|
+
"tool-management"
|
|
85
111
|
],
|
|
86
112
|
"author": "Lightrace Contributors",
|
|
87
113
|
"engines": {
|
package/dist/security.d.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Create HMAC-SHA256 signature for a tool invocation.
|
|
3
|
-
*/
|
|
4
|
-
export declare function sign(sessionToken: string, nonce: string, tool: string, inputData: unknown): string;
|
|
5
|
-
/**
|
|
6
|
-
* Verify HMAC-SHA256 signature.
|
|
7
|
-
*/
|
|
8
|
-
export declare function verify(sessionToken: string, nonce: string, tool: string, inputData: unknown, signature: string): boolean;
|
|
9
|
-
/**
|
|
10
|
-
* Tracks single-use nonces with TTL to prevent replay attacks.
|
|
11
|
-
*/
|
|
12
|
-
export declare class NonceTracker {
|
|
13
|
-
private seen;
|
|
14
|
-
private ttlMs;
|
|
15
|
-
constructor(ttlSeconds?: number);
|
|
16
|
-
/** Returns true if the nonce is fresh (not seen before). Marks it as used. */
|
|
17
|
-
checkAndMark(nonce: string): boolean;
|
|
18
|
-
private cleanup;
|
|
19
|
-
}
|
|
20
|
-
//# sourceMappingURL=security.d.ts.map
|
package/dist/security.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../src/security.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,wBAAgB,IAAI,CAClB,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,OAAO,GACjB,MAAM,CAIR;AAED;;GAEG;AACH,wBAAgB,MAAM,CACpB,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,OAAO,EAClB,SAAS,EAAE,MAAM,GAChB,OAAO,CAOT;AAED;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,IAAI,CAA6B;IACzC,OAAO,CAAC,KAAK,CAAS;gBAEV,UAAU,SAAK;IAI3B,8EAA8E;IAC9E,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAOpC,OAAO,CAAC,OAAO;CAMhB"}
|
package/dist/security.js
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
2
|
-
/**
|
|
3
|
-
* Create HMAC-SHA256 signature for a tool invocation.
|
|
4
|
-
*/
|
|
5
|
-
export function sign(sessionToken, nonce, tool, inputData) {
|
|
6
|
-
const payload = nonce + tool + JSON.stringify(inputData, Object.keys(inputData ?? {}).sort());
|
|
7
|
-
return createHmac("sha256", sessionToken).update(payload).digest("hex");
|
|
8
|
-
}
|
|
9
|
-
/**
|
|
10
|
-
* Verify HMAC-SHA256 signature.
|
|
11
|
-
*/
|
|
12
|
-
export function verify(sessionToken, nonce, tool, inputData, signature) {
|
|
13
|
-
const expected = sign(sessionToken, nonce, tool, inputData);
|
|
14
|
-
try {
|
|
15
|
-
return timingSafeEqual(Buffer.from(expected, "hex"), Buffer.from(signature, "hex"));
|
|
16
|
-
}
|
|
17
|
-
catch {
|
|
18
|
-
return false;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Tracks single-use nonces with TTL to prevent replay attacks.
|
|
23
|
-
*/
|
|
24
|
-
export class NonceTracker {
|
|
25
|
-
seen = new Map();
|
|
26
|
-
ttlMs;
|
|
27
|
-
constructor(ttlSeconds = 60) {
|
|
28
|
-
this.ttlMs = ttlSeconds * 1000;
|
|
29
|
-
}
|
|
30
|
-
/** Returns true if the nonce is fresh (not seen before). Marks it as used. */
|
|
31
|
-
checkAndMark(nonce) {
|
|
32
|
-
this.cleanup();
|
|
33
|
-
if (this.seen.has(nonce))
|
|
34
|
-
return false;
|
|
35
|
-
this.seen.set(nonce, Date.now());
|
|
36
|
-
return true;
|
|
37
|
-
}
|
|
38
|
-
cleanup() {
|
|
39
|
-
const cutoff = Date.now() - this.ttlMs;
|
|
40
|
-
for (const [nonce, time] of this.seen) {
|
|
41
|
-
if (time < cutoff)
|
|
42
|
-
this.seen.delete(nonce);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
//# sourceMappingURL=security.js.map
|
package/dist/security.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"security.js","sourceRoot":"","sources":["../src/security.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE1D;;GAEG;AACH,MAAM,UAAU,IAAI,CAClB,YAAoB,EACpB,KAAa,EACb,IAAY,EACZ,SAAkB;IAElB,MAAM,OAAO,GACX,KAAK,GAAG,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,MAAM,CAAC,IAAI,CAAE,SAAoB,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC5F,OAAO,UAAU,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC1E,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,MAAM,CACpB,YAAoB,EACpB,KAAa,EACb,IAAY,EACZ,SAAkB,EAClB,SAAiB;IAEjB,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;IAC5D,IAAI,CAAC;QACH,OAAO,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC;IACtF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,OAAO,YAAY;IACf,IAAI,GAAG,IAAI,GAAG,EAAkB,CAAC;IACjC,KAAK,CAAS;IAEtB,YAAY,UAAU,GAAG,EAAE;QACzB,IAAI,CAAC,KAAK,GAAG,UAAU,GAAG,IAAI,CAAC;IACjC,CAAC;IAED,8EAA8E;IAC9E,YAAY,CAAC,KAAa;QACxB,IAAI,CAAC,OAAO,EAAE,CAAC;QACf,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC;QACvC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;QACjC,OAAO,IAAI,CAAC;IACd,CAAC;IAEO,OAAO;QACb,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;QACvC,KAAK,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACtC,IAAI,IAAI,GAAG,MAAM;gBAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC;CACF"}
|
package/dist/tool-client.d.ts
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Get the state passed with the current tool invocation.
|
|
3
|
-
* Returns undefined if not in an invocation context or no state was provided.
|
|
4
|
-
*/
|
|
5
|
-
export declare function getInvokeState(): unknown;
|
|
6
|
-
export declare class ToolClient {
|
|
7
|
-
private host;
|
|
8
|
-
private publicKey;
|
|
9
|
-
private secretKey;
|
|
10
|
-
private sdkInstanceId;
|
|
11
|
-
private heartbeatInterval;
|
|
12
|
-
private maxReconnectDelay;
|
|
13
|
-
private sessionToken;
|
|
14
|
-
private nonceTracker;
|
|
15
|
-
private running;
|
|
16
|
-
private ws;
|
|
17
|
-
private reconnectTimer;
|
|
18
|
-
private heartbeatTimer;
|
|
19
|
-
constructor(options: {
|
|
20
|
-
host: string;
|
|
21
|
-
publicKey: string;
|
|
22
|
-
secretKey: string;
|
|
23
|
-
sdkInstanceId?: string;
|
|
24
|
-
heartbeatInterval?: number;
|
|
25
|
-
maxReconnectDelay?: number;
|
|
26
|
-
});
|
|
27
|
-
private get wsUrl();
|
|
28
|
-
start(): void;
|
|
29
|
-
stop(): void;
|
|
30
|
-
private connect;
|
|
31
|
-
private cleanup;
|
|
32
|
-
private handleMessage;
|
|
33
|
-
private registerTools;
|
|
34
|
-
private startHeartbeat;
|
|
35
|
-
/**
|
|
36
|
-
* Handle an invoke message. Validates signature and nonce, then fires off
|
|
37
|
-
* isolated execution without blocking the WS message handler.
|
|
38
|
-
*/
|
|
39
|
-
private handleInvoke;
|
|
40
|
-
/**
|
|
41
|
-
* Execute a tool invocation in isolation with a timeout.
|
|
42
|
-
* Runs outside the WS message handler so heartbeats continue flowing.
|
|
43
|
-
*/
|
|
44
|
-
private executeToolIsolated;
|
|
45
|
-
}
|
|
46
|
-
//# sourceMappingURL=tool-client.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tool-client.d.ts","sourceRoot":"","sources":["../src/tool-client.ts"],"names":[],"mappings":"AAkBA;;;GAGG;AACH,wBAAgB,cAAc,IAAI,OAAO,CAExC;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,iBAAiB,CAAS;IAClC,OAAO,CAAC,iBAAiB,CAAS;IAElC,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,YAAY,CAAwB;IAC5C,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,cAAc,CAA8C;IACpE,OAAO,CAAC,cAAc,CAA+C;gBAEzD,OAAO,EAAE;QACnB,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,iBAAiB,CAAC,EAAE,MAAM,CAAC;KAC5B;IASD,OAAO,KAAK,KAAK,GAIhB;IAED,KAAK,IAAI,IAAI;IAQb,IAAI,IAAI,IAAI;IAUZ,OAAO,CAAC,OAAO;IAmCf,OAAO,CAAC,OAAO;IASf,OAAO,CAAC,aAAa;IAyBrB,OAAO,CAAC,aAAa;IAgBrB,OAAO,CAAC,cAAc;IAQtB;;;OAGG;IACH,OAAO,CAAC,YAAY;IAwCpB;;;OAGG;YACW,mBAAmB;CAyElC"}
|
package/dist/tool-client.js
DELETED
|
@@ -1,237 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* WebSocket client for remote tool invocation.
|
|
3
|
-
*
|
|
4
|
-
* Tool execution is isolated: handleInvoke fires-and-forgets so the WS
|
|
5
|
-
* message handler is never blocked, allowing heartbeats to continue.
|
|
6
|
-
*/
|
|
7
|
-
import { AsyncLocalStorage } from "node:async_hooks";
|
|
8
|
-
import WebSocket from "ws";
|
|
9
|
-
import { _getToolRegistry } from "./trace.js";
|
|
10
|
-
import { generateId } from "./utils.js";
|
|
11
|
-
import { restoreContext } from "./context.js";
|
|
12
|
-
import { sign, verify, NonceTracker } from "./security.js";
|
|
13
|
-
import { jsonSerializable } from "./utils.js";
|
|
14
|
-
/** AsyncLocalStorage for invoke state -- tools can access via getInvokeState(). */
|
|
15
|
-
const invokeStateStorage = new AsyncLocalStorage();
|
|
16
|
-
/**
|
|
17
|
-
* Get the state passed with the current tool invocation.
|
|
18
|
-
* Returns undefined if not in an invocation context or no state was provided.
|
|
19
|
-
*/
|
|
20
|
-
export function getInvokeState() {
|
|
21
|
-
return invokeStateStorage.getStore();
|
|
22
|
-
}
|
|
23
|
-
export class ToolClient {
|
|
24
|
-
host;
|
|
25
|
-
publicKey;
|
|
26
|
-
secretKey;
|
|
27
|
-
sdkInstanceId;
|
|
28
|
-
heartbeatInterval;
|
|
29
|
-
maxReconnectDelay;
|
|
30
|
-
sessionToken = null;
|
|
31
|
-
nonceTracker = new NonceTracker(60);
|
|
32
|
-
running = false;
|
|
33
|
-
ws = null;
|
|
34
|
-
reconnectTimer = null;
|
|
35
|
-
heartbeatTimer = null;
|
|
36
|
-
constructor(options) {
|
|
37
|
-
this.host = options.host.replace(/\/$/, "");
|
|
38
|
-
this.publicKey = options.publicKey;
|
|
39
|
-
this.secretKey = options.secretKey;
|
|
40
|
-
this.sdkInstanceId = options.sdkInstanceId ?? generateId();
|
|
41
|
-
this.heartbeatInterval = (options.heartbeatInterval ?? 30) * 1000;
|
|
42
|
-
this.maxReconnectDelay = (options.maxReconnectDelay ?? 30) * 1000;
|
|
43
|
-
}
|
|
44
|
-
get wsUrl() {
|
|
45
|
-
return (this.host.replace("http://", "ws://").replace("https://", "wss://") + "/api/public/tools/ws");
|
|
46
|
-
}
|
|
47
|
-
start() {
|
|
48
|
-
const registry = _getToolRegistry();
|
|
49
|
-
if (registry.size === 0)
|
|
50
|
-
return;
|
|
51
|
-
this.running = true;
|
|
52
|
-
this.connect(1000);
|
|
53
|
-
}
|
|
54
|
-
stop() {
|
|
55
|
-
this.running = false;
|
|
56
|
-
if (this.reconnectTimer)
|
|
57
|
-
clearTimeout(this.reconnectTimer);
|
|
58
|
-
if (this.heartbeatTimer)
|
|
59
|
-
clearInterval(this.heartbeatTimer);
|
|
60
|
-
if (this.ws) {
|
|
61
|
-
this.ws.close();
|
|
62
|
-
this.ws = null;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
connect(delay) {
|
|
66
|
-
if (!this.running)
|
|
67
|
-
return;
|
|
68
|
-
const auth = Buffer.from(`${this.publicKey}:${this.secretKey}`).toString("base64");
|
|
69
|
-
const ws = new WebSocket(this.wsUrl, {
|
|
70
|
-
headers: { Authorization: `Basic ${auth}` },
|
|
71
|
-
});
|
|
72
|
-
ws.on("open", () => {
|
|
73
|
-
this.ws = ws;
|
|
74
|
-
});
|
|
75
|
-
ws.on("message", (data) => {
|
|
76
|
-
try {
|
|
77
|
-
const msg = JSON.parse(data.toString());
|
|
78
|
-
this.handleMessage(ws, msg);
|
|
79
|
-
}
|
|
80
|
-
catch {
|
|
81
|
-
// ignore malformed messages
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
ws.on("close", () => {
|
|
85
|
-
this.cleanup();
|
|
86
|
-
if (this.running) {
|
|
87
|
-
const nextDelay = Math.min(delay * 2, this.maxReconnectDelay);
|
|
88
|
-
this.reconnectTimer = setTimeout(() => this.connect(nextDelay), delay);
|
|
89
|
-
}
|
|
90
|
-
});
|
|
91
|
-
ws.on("error", () => {
|
|
92
|
-
// close event will handle reconnection
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
cleanup() {
|
|
96
|
-
if (this.heartbeatTimer) {
|
|
97
|
-
clearInterval(this.heartbeatTimer);
|
|
98
|
-
this.heartbeatTimer = null;
|
|
99
|
-
}
|
|
100
|
-
this.sessionToken = null;
|
|
101
|
-
this.ws = null;
|
|
102
|
-
}
|
|
103
|
-
handleMessage(ws, msg) {
|
|
104
|
-
switch (msg.type) {
|
|
105
|
-
case "connected":
|
|
106
|
-
this.sessionToken = msg.sessionToken;
|
|
107
|
-
this.registerTools(ws);
|
|
108
|
-
this.startHeartbeat(ws);
|
|
109
|
-
break;
|
|
110
|
-
case "registered":
|
|
111
|
-
// Tools registered successfully
|
|
112
|
-
break;
|
|
113
|
-
case "invoke":
|
|
114
|
-
this.handleInvoke(ws, msg);
|
|
115
|
-
break;
|
|
116
|
-
case "heartbeat_ack":
|
|
117
|
-
break;
|
|
118
|
-
case "error":
|
|
119
|
-
console.error(`[lightrace] Server error: ${msg.message}`);
|
|
120
|
-
break;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
registerTools(ws) {
|
|
124
|
-
const registry = _getToolRegistry();
|
|
125
|
-
const tools = Array.from(registry.entries()).map(([name, entry]) => ({
|
|
126
|
-
name,
|
|
127
|
-
inputSchema: entry.inputSchema,
|
|
128
|
-
}));
|
|
129
|
-
ws.send(JSON.stringify({
|
|
130
|
-
type: "register",
|
|
131
|
-
sdkInstanceId: this.sdkInstanceId,
|
|
132
|
-
tools,
|
|
133
|
-
}));
|
|
134
|
-
}
|
|
135
|
-
startHeartbeat(ws) {
|
|
136
|
-
this.heartbeatTimer = setInterval(() => {
|
|
137
|
-
if (ws.readyState === WebSocket.OPEN) {
|
|
138
|
-
ws.send(JSON.stringify({ type: "heartbeat" }));
|
|
139
|
-
}
|
|
140
|
-
}, this.heartbeatInterval);
|
|
141
|
-
}
|
|
142
|
-
/**
|
|
143
|
-
* Handle an invoke message. Validates signature and nonce, then fires off
|
|
144
|
-
* isolated execution without blocking the WS message handler.
|
|
145
|
-
*/
|
|
146
|
-
handleInvoke(ws, msg) {
|
|
147
|
-
const { nonce, tool, input, state, signature: sig } = msg;
|
|
148
|
-
// Verify HMAC
|
|
149
|
-
if (!this.sessionToken || !verify(this.sessionToken, nonce, tool, input, sig)) {
|
|
150
|
-
ws.send(JSON.stringify({ type: "error", message: "Invalid signature" }));
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
// Check nonce freshness
|
|
154
|
-
if (!this.nonceTracker.checkAndMark(nonce)) {
|
|
155
|
-
ws.send(JSON.stringify({ type: "error", message: "Replayed nonce" }));
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
const registry = _getToolRegistry();
|
|
159
|
-
const entry = registry.get(tool);
|
|
160
|
-
if (!entry) {
|
|
161
|
-
ws.send(JSON.stringify({
|
|
162
|
-
type: "result",
|
|
163
|
-
nonce,
|
|
164
|
-
output: null,
|
|
165
|
-
error: `Tool not found: ${tool}`,
|
|
166
|
-
durationMs: 0,
|
|
167
|
-
signature: sign(this.sessionToken, nonce, tool, null),
|
|
168
|
-
}));
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
171
|
-
// Fire and forget -- don't block the WS message handler
|
|
172
|
-
this.executeToolIsolated(ws, nonce, tool, input, state, entry).catch((err) => console.error("[lightrace] Tool execution error:", err));
|
|
173
|
-
}
|
|
174
|
-
/**
|
|
175
|
-
* Execute a tool invocation in isolation with a timeout.
|
|
176
|
-
* Runs outside the WS message handler so heartbeats continue flowing.
|
|
177
|
-
*/
|
|
178
|
-
async executeToolIsolated(ws, nonce, tool, input, state, entry) {
|
|
179
|
-
// Restore registered context variables from __lightrace_context
|
|
180
|
-
const contextData = state &&
|
|
181
|
-
typeof state === "object" &&
|
|
182
|
-
"__lightrace_context" in state
|
|
183
|
-
? state.__lightrace_context
|
|
184
|
-
: {};
|
|
185
|
-
if (contextData && typeof contextData === "object") {
|
|
186
|
-
restoreContext(contextData);
|
|
187
|
-
}
|
|
188
|
-
const start = performance.now();
|
|
189
|
-
const timeoutMs = 30_000;
|
|
190
|
-
let timeoutId;
|
|
191
|
-
try {
|
|
192
|
-
const output = await Promise.race([
|
|
193
|
-
invokeStateStorage.run(state ?? null, async () => {
|
|
194
|
-
let result;
|
|
195
|
-
if (input && typeof input === "object" && !Array.isArray(input)) {
|
|
196
|
-
result = await entry.fn(input);
|
|
197
|
-
}
|
|
198
|
-
else {
|
|
199
|
-
result =
|
|
200
|
-
input !== null && input !== undefined ? await entry.fn(input) : await entry.fn();
|
|
201
|
-
}
|
|
202
|
-
return jsonSerializable(result);
|
|
203
|
-
}),
|
|
204
|
-
new Promise((_, reject) => {
|
|
205
|
-
timeoutId = setTimeout(() => reject(new Error("Tool execution timed out")), timeoutMs);
|
|
206
|
-
}),
|
|
207
|
-
]);
|
|
208
|
-
clearTimeout(timeoutId);
|
|
209
|
-
const durationMs = Math.round(performance.now() - start);
|
|
210
|
-
if (ws.readyState === WebSocket.OPEN) {
|
|
211
|
-
ws.send(JSON.stringify({
|
|
212
|
-
type: "result",
|
|
213
|
-
nonce,
|
|
214
|
-
output,
|
|
215
|
-
durationMs,
|
|
216
|
-
signature: sign(this.sessionToken, nonce, tool, output),
|
|
217
|
-
}));
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
catch (err) {
|
|
221
|
-
clearTimeout(timeoutId);
|
|
222
|
-
const durationMs = Math.round(performance.now() - start);
|
|
223
|
-
const error = err instanceof Error ? err.message : String(err);
|
|
224
|
-
if (ws.readyState === WebSocket.OPEN) {
|
|
225
|
-
ws.send(JSON.stringify({
|
|
226
|
-
type: "result",
|
|
227
|
-
nonce,
|
|
228
|
-
output: null,
|
|
229
|
-
error,
|
|
230
|
-
durationMs,
|
|
231
|
-
signature: sign(this.sessionToken, nonce, tool, null),
|
|
232
|
-
}));
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
//# sourceMappingURL=tool-client.js.map
|
package/dist/tool-client.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tool-client.js","sourceRoot":"","sources":["../src/tool-client.ts"],"names":[],"mappings":"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"}
|