lmnr 0.2.8__tar.gz → 0.2.9__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.8 → lmnr-0.2.9}/PKG-INFO +3 -1
- {lmnr-0.2.8 → lmnr-0.2.9}/pyproject.toml +4 -2
- {lmnr-0.2.8 → lmnr-0.2.9}/src/lmnr/cli/parser/nodes/__init__.py +0 -5
- lmnr-0.2.9/src/lmnr/cli/parser/nodes/code.py +36 -0
- {lmnr-0.2.8 → lmnr-0.2.9}/src/lmnr/cli/parser/nodes/input.py +1 -2
- lmnr-0.2.8/src/lmnr/cli/parser/nodes/code.py → lmnr-0.2.9/src/lmnr/cli/parser/nodes/json_extractor.py +5 -3
- {lmnr-0.2.8 → lmnr-0.2.9}/src/lmnr/cli/parser/nodes/llm.py +7 -2
- {lmnr-0.2.8 → lmnr-0.2.9}/src/lmnr/cli/parser/nodes/types.py +24 -6
- {lmnr-0.2.8 → lmnr-0.2.9}/src/lmnr/cli/parser/parser.py +4 -0
- {lmnr-0.2.8 → lmnr-0.2.9}/src/lmnr/cli/parser/utils.py +24 -0
- {lmnr-0.2.8 → lmnr-0.2.9}/LICENSE +0 -0
- {lmnr-0.2.8 → lmnr-0.2.9}/README.md +0 -0
- {lmnr-0.2.8 → lmnr-0.2.9}/src/lmnr/__init__.py +0 -0
- {lmnr-0.2.8 → lmnr-0.2.9}/src/lmnr/cli/__init__.py +0 -0
- {lmnr-0.2.8 → lmnr-0.2.9}/src/lmnr/cli/__main__.py +0 -0
- {lmnr-0.2.8 → lmnr-0.2.9}/src/lmnr/cli/cli.py +0 -0
- {lmnr-0.2.8 → lmnr-0.2.9}/src/lmnr/cli/parser/__init__.py +0 -0
- {lmnr-0.2.8 → lmnr-0.2.9}/src/lmnr/cli/parser/nodes/condition.py +0 -0
- {lmnr-0.2.8 → lmnr-0.2.9}/src/lmnr/cli/parser/nodes/output.py +0 -0
- {lmnr-0.2.8 → lmnr-0.2.9}/src/lmnr/cli/parser/nodes/router.py +0 -0
- {lmnr-0.2.8 → lmnr-0.2.9}/src/lmnr/cli/parser/nodes/semantic_search.py +0 -0
- {lmnr-0.2.8 → lmnr-0.2.9}/src/lmnr/sdk/endpoint.py +0 -0
- {lmnr-0.2.8 → lmnr-0.2.9}/src/lmnr/sdk/remote_debugger.py +0 -0
- {lmnr-0.2.8 → lmnr-0.2.9}/src/lmnr/types.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: lmnr
|
3
|
-
Version: 0.2.
|
3
|
+
Version: 0.2.9
|
4
4
|
Summary: Python SDK for Laminar AI
|
5
5
|
License: Apache-2.0
|
6
6
|
Author: lmnr.ai
|
@@ -14,7 +14,9 @@ Classifier: Programming Language :: Python :: 3.12
|
|
14
14
|
Requires-Dist: black (>=24.4.2,<25.0.0)
|
15
15
|
Requires-Dist: click (>=8.1.7,<9.0.0)
|
16
16
|
Requires-Dist: cookiecutter (>=2.6.0,<3.0.0)
|
17
|
+
Requires-Dist: lmnr-baml (>=0.40.0,<0.41.0)
|
17
18
|
Requires-Dist: pydantic (>=2.7.4,<3.0.0)
|
19
|
+
Requires-Dist: pystache (>=0.6.5,<0.7.0)
|
18
20
|
Requires-Dist: python-dotenv (>=1.0.1,<2.0.0)
|
19
21
|
Requires-Dist: requests (>=2.32.3,<3.0.0)
|
20
22
|
Requires-Dist: websockets (>=12.0,<13.0)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[project]
|
2
2
|
name = "lmnr"
|
3
|
-
version = "0.2.
|
3
|
+
version = "0.2.9"
|
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.9"
|
15
15
|
description = "Python SDK for Laminar AI"
|
16
16
|
authors = ["lmnr.ai"]
|
17
17
|
readme = "README.md"
|
@@ -26,6 +26,8 @@ requests = "^2.32.3"
|
|
26
26
|
websockets = "^12.0"
|
27
27
|
cookiecutter = "^2.6.0"
|
28
28
|
python-dotenv = "^1.0.1"
|
29
|
+
pystache = "^0.6.5"
|
30
|
+
lmnr-baml = "^0.40.0"
|
29
31
|
|
30
32
|
[build-system]
|
31
33
|
requires = ["poetry-core"]
|
@@ -4,21 +4,16 @@ from typing import Optional
|
|
4
4
|
import uuid
|
5
5
|
|
6
6
|
|
7
|
-
HandleType = str # "String" | "ChatMessageList" | "Any"
|
8
|
-
|
9
|
-
|
10
7
|
@dataclass
|
11
8
|
class Handle:
|
12
9
|
id: uuid.UUID
|
13
10
|
name: Optional[str]
|
14
|
-
type: HandleType
|
15
11
|
|
16
12
|
@classmethod
|
17
13
|
def from_dict(cls, dict: dict) -> "Handle":
|
18
14
|
return cls(
|
19
15
|
id=uuid.UUID(dict["id"]),
|
20
16
|
name=(dict["name"] if "name" in dict else None),
|
21
|
-
type=dict["type"],
|
22
17
|
)
|
23
18
|
|
24
19
|
|
@@ -0,0 +1,36 @@
|
|
1
|
+
from dataclasses import dataclass
|
2
|
+
import uuid
|
3
|
+
|
4
|
+
from lmnr.cli.parser.nodes import Handle, NodeFunctions
|
5
|
+
from lmnr.cli.parser.utils import map_handles
|
6
|
+
|
7
|
+
|
8
|
+
@dataclass
|
9
|
+
class CodeNode(NodeFunctions):
|
10
|
+
id: uuid.UUID
|
11
|
+
name: str
|
12
|
+
inputs: list[Handle]
|
13
|
+
outputs: list[Handle]
|
14
|
+
inputs_mappings: dict[uuid.UUID, uuid.UUID]
|
15
|
+
code: str
|
16
|
+
fn_name: str
|
17
|
+
|
18
|
+
def handles_mapping(
|
19
|
+
self, output_handle_id_to_node_name: dict[str, str]
|
20
|
+
) -> list[tuple[str, str]]:
|
21
|
+
return map_handles(
|
22
|
+
self.inputs, self.inputs_mappings, output_handle_id_to_node_name
|
23
|
+
)
|
24
|
+
|
25
|
+
def node_type(self) -> str:
|
26
|
+
return "Code"
|
27
|
+
|
28
|
+
def config(self) -> dict:
|
29
|
+
return {
|
30
|
+
"code": self.code,
|
31
|
+
"fn_name": self.fn_name,
|
32
|
+
"fn_inputs": ", ".join(
|
33
|
+
f"{handle.name}=input_to_code_node_arg({handle.name})"
|
34
|
+
for handle in self.inputs
|
35
|
+
),
|
36
|
+
}
|
@@ -2,7 +2,7 @@ from dataclasses import dataclass
|
|
2
2
|
from typing import Optional
|
3
3
|
import uuid
|
4
4
|
|
5
|
-
from lmnr.cli.parser.nodes import Handle,
|
5
|
+
from lmnr.cli.parser.nodes import Handle, NodeFunctions
|
6
6
|
from lmnr.types import NodeInput
|
7
7
|
|
8
8
|
|
@@ -12,7 +12,6 @@ class InputNode(NodeFunctions):
|
|
12
12
|
name: str
|
13
13
|
outputs: list[Handle]
|
14
14
|
input: Optional[NodeInput]
|
15
|
-
input_type: HandleType
|
16
15
|
|
17
16
|
def handles_mapping(
|
18
17
|
self, output_handle_id_to_node_name: dict[str, str]
|
@@ -1,4 +1,5 @@
|
|
1
1
|
from dataclasses import dataclass
|
2
|
+
|
2
3
|
import uuid
|
3
4
|
|
4
5
|
from lmnr.cli.parser.nodes import Handle, NodeFunctions
|
@@ -6,12 +7,13 @@ from lmnr.cli.parser.utils import map_handles
|
|
6
7
|
|
7
8
|
|
8
9
|
@dataclass
|
9
|
-
class
|
10
|
+
class JsonExtractorNode(NodeFunctions):
|
10
11
|
id: uuid.UUID
|
11
12
|
name: str
|
12
13
|
inputs: list[Handle]
|
13
14
|
outputs: list[Handle]
|
14
15
|
inputs_mappings: dict[uuid.UUID, uuid.UUID]
|
16
|
+
template: str
|
15
17
|
|
16
18
|
def handles_mapping(
|
17
19
|
self, output_handle_id_to_node_name: dict[str, str]
|
@@ -21,7 +23,7 @@ class CodeNode(NodeFunctions):
|
|
21
23
|
)
|
22
24
|
|
23
25
|
def node_type(self) -> str:
|
24
|
-
return "
|
26
|
+
return "JsonExtractor"
|
25
27
|
|
26
28
|
def config(self) -> dict:
|
27
|
-
return {}
|
29
|
+
return {"template": self.template}
|
@@ -44,8 +44,13 @@ class LLMNode(NodeFunctions):
|
|
44
44
|
"model": model,
|
45
45
|
"model_params": self.model_params,
|
46
46
|
"stream": self.stream,
|
47
|
-
"
|
47
|
+
"enable_structured_output": self.structured_output_enabled
|
48
|
+
and self.structured_output_schema is not None,
|
48
49
|
"structured_output_max_retries": self.structured_output_max_retries,
|
49
50
|
"structured_output_schema": self.structured_output_schema,
|
50
|
-
"
|
51
|
+
"structured_output_schema_target_str": (
|
52
|
+
"None"
|
53
|
+
if self.structured_output_schema_target is None
|
54
|
+
else f'"{self.structured_output_schema_target}"'
|
55
|
+
),
|
51
56
|
}
|
@@ -5,6 +5,7 @@ from lmnr.cli.parser.nodes import Handle
|
|
5
5
|
from lmnr.cli.parser.nodes.code import CodeNode
|
6
6
|
from lmnr.cli.parser.nodes.condition import ConditionNode
|
7
7
|
from lmnr.cli.parser.nodes.input import InputNode
|
8
|
+
from lmnr.cli.parser.nodes.json_extractor import JsonExtractorNode
|
8
9
|
from lmnr.cli.parser.nodes.llm import LLMNode
|
9
10
|
from lmnr.cli.parser.nodes.output import OutputNode
|
10
11
|
from lmnr.cli.parser.nodes.router import Route, RouterNode
|
@@ -32,6 +33,7 @@ Node = Union[
|
|
32
33
|
RouterNode,
|
33
34
|
SemanticSearchNode,
|
34
35
|
CodeNode,
|
36
|
+
JsonExtractorNode,
|
35
37
|
]
|
36
38
|
|
37
39
|
|
@@ -42,7 +44,6 @@ def node_from_dict(node_dict: dict) -> Node:
|
|
42
44
|
name=node_dict["name"],
|
43
45
|
outputs=[Handle.from_dict(handle) for handle in node_dict["outputs"]],
|
44
46
|
input=node_input_from_json(node_dict["input"]),
|
45
|
-
input_type=node_dict["inputType"],
|
46
47
|
)
|
47
48
|
elif node_dict["type"] == "Output":
|
48
49
|
return OutputNode(
|
@@ -86,11 +87,14 @@ def node_from_dict(node_dict: dict) -> Node:
|
|
86
87
|
node_dict["modelParams"] if "modelParams" in node_dict else None
|
87
88
|
),
|
88
89
|
stream=False,
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
90
|
+
structured_output_enabled=node_dict.get("structuredOutputEnabled", False),
|
91
|
+
structured_output_max_retries=node_dict.get(
|
92
|
+
"structuredOutputMaxRetries", 0
|
93
|
+
),
|
94
|
+
structured_output_schema=node_dict.get("structuredOutputSchema", None),
|
95
|
+
structured_output_schema_target=node_dict.get(
|
96
|
+
"structuredOutputSchemaTarget", None
|
97
|
+
),
|
94
98
|
)
|
95
99
|
elif node_dict["type"] == "Router":
|
96
100
|
return RouterNode(
|
@@ -130,6 +134,20 @@ def node_from_dict(node_dict: dict) -> Node:
|
|
130
134
|
uuid.UUID(k): uuid.UUID(v)
|
131
135
|
for k, v in node_dict["inputsMappings"].items()
|
132
136
|
},
|
137
|
+
code=node_dict["code"],
|
138
|
+
fn_name=node_dict["fnName"],
|
139
|
+
)
|
140
|
+
elif node_dict["type"] == "JsonExtractor":
|
141
|
+
return JsonExtractorNode(
|
142
|
+
id=uuid.UUID(node_dict["id"]),
|
143
|
+
name=node_dict["name"],
|
144
|
+
inputs=[Handle.from_dict(handle) for handle in node_dict["inputs"]],
|
145
|
+
outputs=[Handle.from_dict(handle) for handle in node_dict["outputs"]],
|
146
|
+
inputs_mappings={
|
147
|
+
uuid.UUID(k): uuid.UUID(v)
|
148
|
+
for k, v in node_dict["inputsMappings"].items()
|
149
|
+
},
|
150
|
+
template=node_dict["template"],
|
133
151
|
)
|
134
152
|
else:
|
135
153
|
raise ValueError(f"Node type {node_dict['type']} not supported")
|
@@ -1,3 +1,4 @@
|
|
1
|
+
from lmnr.cli.parser.utils import replace_spaces_with_underscores
|
1
2
|
from .nodes.types import node_from_dict
|
2
3
|
|
3
4
|
|
@@ -8,6 +9,9 @@ def runnable_graph_to_template_vars(graph: dict) -> dict:
|
|
8
9
|
node_id_to_node_name = {}
|
9
10
|
output_handle_id_to_node_name: dict[str, str] = {}
|
10
11
|
for node in graph["nodes"].values():
|
12
|
+
# override node names in the graph itself to be safe
|
13
|
+
node["name"] = replace_spaces_with_underscores(node["name"])
|
14
|
+
|
11
15
|
node_id_to_node_name[node["id"]] = node["name"]
|
12
16
|
for handle in node["outputs"]:
|
13
17
|
output_handle_id_to_node_name[handle["id"]] = node["name"]
|
@@ -23,3 +23,27 @@ def map_handles(
|
|
23
23
|
(input_name, output_handle_id_to_node_name[str(output_id)])
|
24
24
|
for input_name, output_id in mapping
|
25
25
|
]
|
26
|
+
|
27
|
+
|
28
|
+
def replace_spaces_with_underscores(s: str):
|
29
|
+
spaces = [
|
30
|
+
"\u0020",
|
31
|
+
"\u00A0",
|
32
|
+
"\u1680",
|
33
|
+
"\u2000",
|
34
|
+
"\u2001",
|
35
|
+
"\u2002",
|
36
|
+
"\u2003",
|
37
|
+
"\u2004",
|
38
|
+
"\u2005",
|
39
|
+
"\u2006",
|
40
|
+
"\u2007",
|
41
|
+
"\u2008",
|
42
|
+
"\u2009",
|
43
|
+
"\u200A",
|
44
|
+
"\u200B",
|
45
|
+
"\u202F",
|
46
|
+
"\u205F",
|
47
|
+
"\u3000",
|
48
|
+
]
|
49
|
+
return s.translate({ord(space): "_" for space in spaces})
|
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
|
File without changes
|
File without changes
|