lmnr 0.2.1__tar.gz → 0.2.2__tar.gz

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.
Files changed (27) hide show
  1. {lmnr-0.2.1 → lmnr-0.2.2}/PKG-INFO +1 -1
  2. {lmnr-0.2.1 → lmnr-0.2.2}/pyproject.toml +2 -2
  3. {lmnr-0.2.1 → lmnr-0.2.2}/src/lmnr/__init__.py +2 -1
  4. lmnr-0.2.2/src/lmnr/sdk/remote_debugger.py +85 -0
  5. {lmnr-0.2.1 → lmnr-0.2.2}/src/lmnr/types.py +4 -1
  6. {lmnr-0.2.1 → lmnr-0.2.2}/LICENSE +0 -0
  7. {lmnr-0.2.1 → lmnr-0.2.2}/README.md +0 -0
  8. {lmnr-0.2.1 → lmnr-0.2.2}/src/lmnr/cli/__init__.py +0 -0
  9. {lmnr-0.2.1 → lmnr-0.2.2}/src/lmnr/cli/__main__.py +0 -0
  10. {lmnr-0.2.1 → lmnr-0.2.2}/src/lmnr/cli/cli.py +0 -0
  11. {lmnr-0.2.1 → lmnr-0.2.2}/src/lmnr/cli/cookiecutter.json +0 -0
  12. {lmnr-0.2.1 → lmnr-0.2.2}/src/lmnr/cli/parser/__init__.py +0 -0
  13. {lmnr-0.2.1 → lmnr-0.2.2}/src/lmnr/cli/parser/nodes/__init__.py +0 -0
  14. {lmnr-0.2.1 → lmnr-0.2.2}/src/lmnr/cli/parser/nodes/types.py +0 -0
  15. {lmnr-0.2.1 → lmnr-0.2.2}/src/lmnr/cli/parser/parser.py +0 -0
  16. {lmnr-0.2.1 → lmnr-0.2.2}/src/lmnr/cli/parser/utils.py +0 -0
  17. {lmnr-0.2.1 → lmnr-0.2.2}/src/lmnr/cli/{{cookiecutter.lmnr_pipelines_dir_name}}/__init__.py +0 -0
  18. {lmnr-0.2.1 → lmnr-0.2.2}/src/lmnr/cli/{{cookiecutter.lmnr_pipelines_dir_name}}/engine/__init__.py +0 -0
  19. {lmnr-0.2.1 → lmnr-0.2.2}/src/lmnr/cli/{{cookiecutter.lmnr_pipelines_dir_name}}/engine/action.py +0 -0
  20. {lmnr-0.2.1 → lmnr-0.2.2}/src/lmnr/cli/{{cookiecutter.lmnr_pipelines_dir_name}}/engine/engine.py +0 -0
  21. {lmnr-0.2.1 → lmnr-0.2.2}/src/lmnr/cli/{{cookiecutter.lmnr_pipelines_dir_name}}/engine/state.py +0 -0
  22. {lmnr-0.2.1 → lmnr-0.2.2}/src/lmnr/cli/{{cookiecutter.lmnr_pipelines_dir_name}}/engine/task.py +0 -0
  23. {lmnr-0.2.1 → lmnr-0.2.2}/src/lmnr/cli/{{cookiecutter.lmnr_pipelines_dir_name}}/pipelines/{{cookiecutter.pipeline_dir_name}}/__init__.py +0 -0
  24. {lmnr-0.2.1 → lmnr-0.2.2}/src/lmnr/cli/{{cookiecutter.lmnr_pipelines_dir_name}}/pipelines/{{cookiecutter.pipeline_dir_name}}/nodes/functions.py +0 -0
  25. {lmnr-0.2.1 → lmnr-0.2.2}/src/lmnr/cli/{{cookiecutter.lmnr_pipelines_dir_name}}/pipelines/{{cookiecutter.pipeline_dir_name}}/{{cookiecutter.pipeline_dir_name}}.py +0 -0
  26. {lmnr-0.2.1 → lmnr-0.2.2}/src/lmnr/cli/{{cookiecutter.lmnr_pipelines_dir_name}}/types.py +0 -0
  27. {lmnr-0.2.1 → lmnr-0.2.2}/src/lmnr/sdk/endpoint.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lmnr
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Summary: Python SDK for Laminar AI
5
5
  License: Apache-2.0
6
6
  Author: lmnr.ai
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "lmnr"
3
- version = "0.2.1"
3
+ version = "0.2.2"
4
4
  description = "Python SDK for Laminar AI"
5
5
  authors = [
6
6
  { name = "lmnr.ai", email = "founders@lmnr.ai" }
@@ -11,7 +11,7 @@ license = "Apache-2.0"
11
11
 
12
12
  [tool.poetry]
13
13
  name = "lmnr"
14
- version = "0.2.1"
14
+ version = "0.2.2"
15
15
  description = "Python SDK for Laminar AI"
16
16
  authors = ["lmnr.ai"]
17
17
  readme = "README.md"
@@ -4,4 +4,5 @@ from .types import (
4
4
  EndpointRunError,
5
5
  EndpointRunResponse,
6
6
  NodeInput
7
- )
7
+ )
8
+ from .sdk.remote_debugger import RemoteDebugger as LaminarRemoteDebugger
@@ -0,0 +1,85 @@
1
+ from typing import Callable
2
+ from websockets.sync.client import connect
3
+ from lmnr.types import NodeInput, RegisterDebuggerRequest, SDKError, ToolCall
4
+ import uuid
5
+ import json
6
+ from threading import Thread
7
+
8
+ class RemoteDebugger:
9
+ def __init__(self, project_api_key: str, tools: list[Callable[..., NodeInput]] = []):
10
+ self.project_api_key = project_api_key
11
+ self.url = 'wss://api.lmnr.ai/v2/endpoint/ws'
12
+ self.tools = tools
13
+ self.thread = Thread(target=self._run)
14
+ self.stop_flag = False
15
+ self.session = None
16
+
17
+ def start(self):
18
+ self.stop_flag = False
19
+ self.thread.start()
20
+
21
+ def stop(self):
22
+ self.stop_flag = True
23
+ self.thread.join()
24
+ self.session = None
25
+ # python allows running threads only once, so we need to create a new thread
26
+ # in case the user wants to start the debugger again
27
+ self.thread = Thread(target=self._run)
28
+
29
+ def _run(self):
30
+ self.session = self._generate_session_id()
31
+ request = RegisterDebuggerRequest(debugger_session_id=self.session)
32
+ with connect(
33
+ self.url,
34
+ additional_headers={
35
+ 'Authorization': f'Bearer {self.project_api_key}'
36
+ }
37
+ ) as websocket:
38
+ websocket.send(request.model_dump_json())
39
+ while not self.stop_flag:
40
+ try:
41
+ # blocks the thread until a message is received or a timeout (3 seconds) occurs
42
+ message = websocket.recv(3)
43
+ except TimeoutError:
44
+ continue
45
+ try:
46
+ tool_call = ToolCall.model_validate_json(message)
47
+ except:
48
+ raise SDKError(f'Invalid message received:\n{message}')
49
+ matching_tools = [
50
+ tool for tool in self.tools
51
+ if tool.__name__ == tool_call.function.name
52
+ ]
53
+ if not matching_tools:
54
+ raise SDKError(
55
+ f'Tool {tool_call.function.name} not found.'
56
+ ' Registered tools: '
57
+ f'{", ".join([tool.__name__ for tool in self.tools])}'
58
+ )
59
+ tool = matching_tools[0]
60
+ if tool.__name__ == tool_call.function.name:
61
+ # default the arguments to an empty dictionary
62
+ arguments = {}
63
+ try:
64
+ arguments = json.loads(tool_call.function.arguments)
65
+ except:
66
+ pass
67
+ response = tool(**arguments)
68
+ websocket.send(json.dumps(response))
69
+
70
+
71
+ def get_session_id(self) -> str:
72
+ return self._format_session_id(self.session)
73
+
74
+ def _generate_session_id(self) -> str:
75
+ return uuid.uuid4().urn[9:]
76
+
77
+ def _format_session_id(self, session_id: str) -> str:
78
+ return \
79
+ f"""
80
+ ========================================
81
+ Debugger Session ID:
82
+ {session_id}
83
+ ========================================
84
+ """
85
+
@@ -49,4 +49,7 @@ class ToolCallRequest(pydantic.BaseModel):
49
49
  class ToolCall(pydantic.BaseModel):
50
50
  id: Optional[str]
51
51
  type: Optional[str]
52
- function: ToolCallRequest
52
+ function: ToolCallRequest
53
+
54
+ class RegisterDebuggerRequest(pydantic.BaseModel):
55
+ debugger_session_id: str
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes