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.
- {lmnr-0.2.1 → lmnr-0.2.3}/PKG-INFO +1 -1
- {lmnr-0.2.1 → lmnr-0.2.3}/pyproject.toml +2 -2
- {lmnr-0.2.1 → lmnr-0.2.3}/src/lmnr/__init__.py +2 -1
- lmnr-0.2.3/src/lmnr/sdk/remote_debugger.py +86 -0
- {lmnr-0.2.1 → lmnr-0.2.3}/src/lmnr/types.py +4 -1
- {lmnr-0.2.1 → lmnr-0.2.3}/LICENSE +0 -0
- {lmnr-0.2.1 → lmnr-0.2.3}/README.md +0 -0
- {lmnr-0.2.1 → lmnr-0.2.3}/src/lmnr/cli/__init__.py +0 -0
- {lmnr-0.2.1 → lmnr-0.2.3}/src/lmnr/cli/__main__.py +0 -0
- {lmnr-0.2.1 → lmnr-0.2.3}/src/lmnr/cli/cli.py +0 -0
- {lmnr-0.2.1 → lmnr-0.2.3}/src/lmnr/cli/cookiecutter.json +0 -0
- {lmnr-0.2.1 → lmnr-0.2.3}/src/lmnr/cli/parser/__init__.py +0 -0
- {lmnr-0.2.1 → lmnr-0.2.3}/src/lmnr/cli/parser/nodes/__init__.py +0 -0
- {lmnr-0.2.1 → lmnr-0.2.3}/src/lmnr/cli/parser/nodes/types.py +0 -0
- {lmnr-0.2.1 → lmnr-0.2.3}/src/lmnr/cli/parser/parser.py +0 -0
- {lmnr-0.2.1 → lmnr-0.2.3}/src/lmnr/cli/parser/utils.py +0 -0
- {lmnr-0.2.1 → lmnr-0.2.3}/src/lmnr/cli/{{cookiecutter.lmnr_pipelines_dir_name}}/__init__.py +0 -0
- {lmnr-0.2.1 → lmnr-0.2.3}/src/lmnr/cli/{{cookiecutter.lmnr_pipelines_dir_name}}/engine/__init__.py +0 -0
- {lmnr-0.2.1 → lmnr-0.2.3}/src/lmnr/cli/{{cookiecutter.lmnr_pipelines_dir_name}}/engine/action.py +0 -0
- {lmnr-0.2.1 → lmnr-0.2.3}/src/lmnr/cli/{{cookiecutter.lmnr_pipelines_dir_name}}/engine/engine.py +0 -0
- {lmnr-0.2.1 → lmnr-0.2.3}/src/lmnr/cli/{{cookiecutter.lmnr_pipelines_dir_name}}/engine/state.py +0 -0
- {lmnr-0.2.1 → lmnr-0.2.3}/src/lmnr/cli/{{cookiecutter.lmnr_pipelines_dir_name}}/engine/task.py +0 -0
- {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
- {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
- {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
- {lmnr-0.2.1 → lmnr-0.2.3}/src/lmnr/cli/{{cookiecutter.lmnr_pipelines_dir_name}}/types.py +0 -0
- {lmnr-0.2.1 → lmnr-0.2.3}/src/lmnr/sdk/endpoint.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
[project]
|
2
2
|
name = "lmnr"
|
3
|
-
version = "0.2.
|
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.
|
14
|
+
version = "0.2.3"
|
15
15
|
description = "Python SDK for Laminar AI"
|
16
16
|
authors = ["lmnr.ai"]
|
17
17
|
readme = "README.md"
|
@@ -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
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{lmnr-0.2.1 → lmnr-0.2.3}/src/lmnr/cli/{{cookiecutter.lmnr_pipelines_dir_name}}/engine/__init__.py
RENAMED
File without changes
|
{lmnr-0.2.1 → lmnr-0.2.3}/src/lmnr/cli/{{cookiecutter.lmnr_pipelines_dir_name}}/engine/action.py
RENAMED
File without changes
|
{lmnr-0.2.1 → lmnr-0.2.3}/src/lmnr/cli/{{cookiecutter.lmnr_pipelines_dir_name}}/engine/engine.py
RENAMED
File without changes
|
{lmnr-0.2.1 → lmnr-0.2.3}/src/lmnr/cli/{{cookiecutter.lmnr_pipelines_dir_name}}/engine/state.py
RENAMED
File without changes
|
{lmnr-0.2.1 → lmnr-0.2.3}/src/lmnr/cli/{{cookiecutter.lmnr_pipelines_dir_name}}/engine/task.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|