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