@lmnr-ai/lmnr 0.2.3 → 0.2.5

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/README.md CHANGED
@@ -57,10 +57,16 @@ This only works in Node execution context; browser context is not supported.
57
57
 
58
58
  Example use:
59
59
 
60
- ```typescript
60
+ ```js
61
61
  import { Laminar, NodeInput } from '@lmnr-ai/lmnr';
62
62
 
63
- const myTool = ({arg1, arg2}: {arg1: string, arg2: number}): NodeInput => {
63
+ // make sure to setup arguments as object
64
+ const myTool = ({
65
+ arg1, arg2
66
+ }: {
67
+ arg1: string,
68
+ arg2: number
69
+ }): NodeInput => {
64
70
  // this tool teaches LLMs the beauty of JavaScript!
65
71
  return arg1 + arg2;
66
72
  }
@@ -83,7 +89,7 @@ If your pipeline contains tool call nodes, they will be able to call your local
83
89
  If you want to test them from the Laminar workshop in your browser, you can attach to your
84
90
  locally running debugger.
85
91
 
86
- ### Step by step instructions to use `LaminarRemoteDebugger`:
92
+ ### Step-by-step instructions to use `LaminarRemoteDebugger`:
87
93
 
88
94
  #### 1. Create your pipeline with tool call nodes
89
95
 
@@ -94,15 +100,21 @@ Add tool calls to your pipeline; node names must match the functions you want to
94
100
  Example:
95
101
 
96
102
  ```js
97
- import { LaminarRemoteDebugger } from '@lmnr-ai/lmnr';
98
-
99
- const myTool = ({arg1, arg2}: {arg1: string, arg2: number}): NodeInput => {
103
+ import { LaminarRemoteDebugger, NodeInput } from '@lmnr-ai/lmnr';
104
+
105
+ // make sure to setup arguments as object
106
+ const myTool = ({
107
+ arg1, arg2
108
+ }: {
109
+ arg1: string,
110
+ arg2: number
111
+ }): NodeInput => {
100
112
  // this tool teaches LLMs the beauty of JavaScript!
101
113
  return arg1 + arg2;
102
114
  }
103
115
 
104
- debugger = LaminarRemoteDebugger('<YOUR_PROJECT_API_KEY>', [my_tool]);
105
- debugger.start();
116
+ const dbgr = new LaminarRemoteDebugger('<YOUR_PROJECT_API_KEY>', [myTool]);
117
+ dbgr.start();
106
118
  // the session id will be printed to console.
107
119
  // It is also returned from this promise, but you may not want to `await` it
108
120
  ```
@@ -118,10 +130,3 @@ Set up `DEBUGGER_SESSION_ID` environment variable in your pipeline.
118
130
 
119
131
  You can run as many sessions as you need, experimenting with your flows.
120
132
 
121
- #### 5. Stop the debugger
122
-
123
- In order to stop the session, do
124
-
125
- ```js
126
- debugger.stop()
127
- ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lmnr-ai/lmnr",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "description": "TypeScript SDK for Laminar AI",
5
5
  "main": "src/index.ts",
6
6
  "repository": {
package/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { NodeInput, EndpointRunResponse, EndpointRunRequest, NodeWebSocketMessage, ToolCall, WebSocketError } from './types';
1
+ import { EndpointRunResponse, EndpointRunRequest, NodeWebSocketMessage, WebSocketError, ToolCallRequest, ToolCallResponse, ToolCallError } from './types';
2
2
  import { isBrowser, isNode } from 'browser-or-node';
3
3
  import { WebSocket } from 'ws';
4
4
 
@@ -53,11 +53,10 @@ export class Laminar {
53
53
 
54
54
  private async _ws_run(request: EndpointRunRequest): Promise<EndpointRunResponse> {
55
55
  if (isBrowser) {
56
- throw new Error('Running tools in the browser is not supported yet. Please use the Node.js environment.');
56
+ throw new Error('Running tools in the browser is not supported. Please use the Node.js environment.');
57
57
  } else if (isNode) {
58
58
  return this._ws_run_node(request);
59
- }
60
- else {
59
+ } else {
61
60
  throw new Error('Unsupported environment');
62
61
  }
63
62
  }
@@ -71,6 +70,7 @@ export class Laminar {
71
70
  }: EndpointRunRequest): Promise<EndpointRunResponse> {
72
71
  const socket = new WebSocket(this.ws_url, [], {headers: {'Authorization': `Bearer ${this.projectApiKey}`}});
73
72
  let response: EndpointRunResponse | null = null;
73
+ let reqId: string | null = null;
74
74
 
75
75
  socket.on('open', () => {
76
76
  socket.send(JSON.stringify({
@@ -83,19 +83,32 @@ export class Laminar {
83
83
  });
84
84
  socket.on('message', (data: NodeWebSocketMessage) => {
85
85
  try {
86
- const toolCall = JSON.parse(data.toString()) as ToolCall;
87
- const matchingTool = tools.find(tool => tool.name === toolCall.function.name);
86
+ const toolCall = JSON.parse(data.toString()) as ToolCallRequest;
87
+ reqId = toolCall.reqId;
88
+ const matchingTool = tools.find(tool => tool.name === toolCall.toolCall.function.name);
88
89
  if (!matchingTool) {
89
90
  throw new WebSocketError(
90
- `Tool ${toolCall.function.name} not found. Registered tools: ${tools.map(tool => tool.name).join(', ')}`
91
+ `Tool ${toolCall.toolCall.function.name} not found. ` +
92
+ `Registered tools: ${tools.map(tool => tool.name).join(', ')}`
91
93
  );
92
94
  }
93
95
  let args = {}
94
96
  try {
95
- args = JSON.parse(toolCall.function.arguments);
97
+ args = JSON.parse(toolCall.toolCall.function.arguments);
96
98
  } catch (e) {}
97
- const result = matchingTool(args);
98
- socket.send(JSON.stringify(result));
99
+ try {
100
+ const result = matchingTool(args);
101
+ const toolResponse = {
102
+ reqId,
103
+ response: result
104
+ } as ToolCallResponse;
105
+ socket.send(JSON.stringify(toolResponse));
106
+ } catch (e) {
107
+ socket.send(JSON.stringify({
108
+ reqId,
109
+ error: (e as Error).message
110
+ } as ToolCallError));
111
+ }
99
112
  } catch (e) {
100
113
  if (e instanceof WebSocketError) {
101
114
  throw e;
@@ -1,4 +1,12 @@
1
- import { NodeWebSocketMessage, RegisterDebuggerRequest, Tool, ToolCall, WebSocketError } from "./types";
1
+ import {
2
+ DeregisterDebuggerRequest,
3
+ NodeWebSocketMessage,
4
+ RegisterDebuggerRequest,
5
+ Tool,
6
+ ToolCallRequest,
7
+ ToolCallError,
8
+ ToolCallResponse,
9
+ } from "./types";
2
10
  import { v4 as uuidv4 } from 'uuid';
3
11
  import { WebSocket } from 'ws';
4
12
 
@@ -18,7 +26,8 @@ export class RemoteDebugger {
18
26
 
19
27
  public async start(): Promise<string> {
20
28
  this.sessionId = this.generateSessionId();
21
- console.log(this.formatSessionId());
29
+ console.log(this.formatSessionIdAndRegisteredTools());
30
+ let reqId: string | null = null;
22
31
 
23
32
  this.socket.on('open', () => {
24
33
  this.socket.send(JSON.stringify({
@@ -28,21 +37,38 @@ export class RemoteDebugger {
28
37
 
29
38
  this.socket.on('message', (data: NodeWebSocketMessage) => {
30
39
  try {
31
- const toolCall = JSON.parse(data.toString()) as ToolCall;
32
- const matchingTool = this.tools.find(tool => tool.name === toolCall.function.name);
40
+ const toolCall = JSON.parse(data.toString()) as ToolCallRequest;
41
+ reqId = toolCall.reqId;
42
+ const matchingTool = this.tools.find(tool => tool.name === toolCall.toolCall.function.name);
33
43
  if (!matchingTool) {
34
- console.error(
35
- `Tool ${toolCall.function.name} not found. Registered tools: ${this.tools.map(tool => tool.name).join(', ')}`
36
- );
44
+ const errMsg = `Tool ${toolCall.toolCall.function.name} not found. ` +
45
+ `Registered tools: ${this.tools.map(tool => tool.name).join(', ')}`;
46
+ console.error(errMsg);
47
+ this.socket.send(JSON.stringify({
48
+ reqId,
49
+ error: errMsg
50
+ } as ToolCallError));
37
51
  return;
38
52
  }
39
53
  let args = {}
40
54
  try {
41
- args = JSON.parse(toolCall.function.arguments);
55
+ args = JSON.parse(toolCall.toolCall.function.arguments);
42
56
  } catch (e) {}
43
- const result = matchingTool(args);
44
- this.socket.send(JSON.stringify(result));
57
+ try {
58
+ const result = matchingTool(args); // NodeInput
59
+ const toolResponse = {
60
+ reqId,
61
+ response: result
62
+ } as ToolCallResponse;
63
+ this.socket.send(JSON.stringify(toolResponse));
64
+ } catch (e) {
65
+ this.socket.send(JSON.stringify({
66
+ reqId,
67
+ error: (e as Error).message
68
+ } as ToolCallError));
69
+ }
45
70
  } catch (e) {
71
+ console.error(`Received invalid message: ${data.toString()}`);
46
72
  this.socket.send(JSON.stringify({
47
73
  deregister: true,
48
74
  debuggerSessionId: this.sessionId
@@ -58,7 +84,7 @@ export class RemoteDebugger {
58
84
  this.socket.send(JSON.stringify({
59
85
  deregister: true,
60
86
  debuggerSessionId: this.sessionId
61
- } as RegisterDebuggerRequest));
87
+ } as DeregisterDebuggerRequest));
62
88
  this.socket.close();
63
89
  }
64
90
 
@@ -70,12 +96,16 @@ export class RemoteDebugger {
70
96
  return uuidv4();
71
97
  }
72
98
 
73
- private formatSessionId(): string {
99
+ private formatSessionIdAndRegisteredTools(): string {
74
100
  return `
75
101
  ========================================
76
102
  Debugger Session ID:
77
103
  ${this.sessionId}
78
104
  ========================================
105
+
106
+ Registered functions:
107
+ ${this.tools.map(tool => '- ' + tool.name).join(',\n')}
108
+ ========================================
79
109
  `
80
110
  }
81
111
  }
package/src/types.ts CHANGED
@@ -20,6 +20,11 @@ export type EndpointRunResponse = {
20
20
  runId: string;
21
21
  }
22
22
 
23
+ export type ToolCallRequest = {
24
+ reqId: string;
25
+ toolCall: ToolCall;
26
+ }
27
+
23
28
  export type ToolFunctionCall = {
24
29
  name: string;
25
30
  arguments: string;
@@ -31,6 +36,11 @@ export type ToolCall = {
31
36
  function: ToolFunctionCall;
32
37
  }
33
38
 
39
+ export type ToolCallResponse = {
40
+ reqId: string;
41
+ response: NodeInput;
42
+ }
43
+
34
44
  export type NodeWebSocketMessage = {
35
45
  type: 'utf8' | 'binary';
36
46
  utf8Data?: string;
@@ -45,4 +55,9 @@ export type DeregisterDebuggerRequest = {
45
55
  debuggerSessionId: string;
46
56
  }
47
57
 
58
+ export type ToolCallError = {
59
+ reqId: string;
60
+ error: string;
61
+ }
62
+
48
63
  export class WebSocketError extends Error {}