darabos commited on
Commit
a083285
Β·
1 Parent(s): d7ccb5f

Move each package into a separate module. Rename "ops" to "core". Fix test.

Browse files
Files changed (28) hide show
  1. .gitignore +1 -0
  2. README.md +1 -1
  3. lynxkite-app/pyproject.toml +5 -5
  4. lynxkite-app/src/build_frontend.py +1 -1
  5. lynxkite-app/src/lynxkite/{__init__.py β†’ app/__init__.py} +0 -0
  6. lynxkite-app/src/lynxkite/{__main__.py β†’ app/__main__.py} +1 -1
  7. lynxkite-app/src/lynxkite/{crdt.py β†’ app/crdt.py} +1 -6
  8. lynxkite-app/src/lynxkite/{main.py β†’ app/main.py} +3 -3
  9. lynxkite-app/src/lynxkite/{web_assets β†’ app/web_assets}/__init__.py +0 -0
  10. lynxkite-app/src/lynxkite/{web_assets β†’ app/web_assets}/assets/__init__.py +0 -0
  11. lynxkite-app/uv.lock +1 -1
  12. {lynxkite-ops β†’ lynxkite-core}/README.md +0 -0
  13. {lynxkite-ops β†’ lynxkite-core}/build/lib/lynxkite/executors/one_by_one.py +0 -0
  14. {lynxkite-ops β†’ lynxkite-core}/build/lib/lynxkite/ops.py +0 -0
  15. {lynxkite-ops β†’ lynxkite-core}/build/lib/lynxkite/workspace.py +0 -0
  16. {lynxkite-ops β†’ lynxkite-core}/pyproject.toml +1 -1
  17. {lynxkite-ops/src/lynxkite β†’ lynxkite-core/src/lynxkite/core}/executors/one_by_one.py +0 -0
  18. {lynxkite-ops/src/lynxkite β†’ lynxkite-core/src/lynxkite/core}/ops.py +0 -0
  19. {lynxkite-ops/src/lynxkite β†’ lynxkite-core/src/lynxkite/core}/workspace.py +0 -0
  20. lynxkite-graph-analytics/pyproject.toml +2 -2
  21. lynxkite-graph-analytics/uv.lock +4 -4
  22. lynxkite-lynxscribe/README.md +6 -0
  23. lynxkite-lynxscribe/pyproject.toml +2 -2
  24. lynxkite-lynxscribe/src/lynxscribe/lynxkite/llm_ops.py +20 -10
  25. lynxkite-lynxscribe/src/lynxscribe/lynxkite/lynxscribe_ops.py +2 -2
  26. lynxkite-lynxscribe/src/lynxscribe/lynxkite/test_llm_ops.py +0 -75
  27. lynxkite-pillow/pyproject.toml +2 -2
  28. lynxkite-pillow/uv.lock +4 -4
.gitignore CHANGED
@@ -10,4 +10,5 @@
10
  __pycache__
11
  node_modules
12
  dist
 
13
  *.egg-info
 
10
  __pycache__
11
  node_modules
12
  dist
13
+ build
14
  *.egg-info
README.md CHANGED
@@ -9,7 +9,7 @@ original LynxKite. The primary goals of this rewrite are:
9
 
10
  ## Structure
11
 
12
- - `lynxkite-ops`: Core types and utilities. Depend on this lightweight package if you are writing LynxKite plugins.
13
  - `lynxkite-app`: The LynxKite web application. Install some plugins then run this to use LynxKite.
14
  - `lynxkite-graph-analytics`: Graph analytics plugin. The classical LynxKite experience!
15
  - `lynxkite-pillow`: A simple example plugin.
 
9
 
10
  ## Structure
11
 
12
+ - `lynxkite-core`: Core types and utilities. Depend on this lightweight package if you are writing LynxKite plugins.
13
  - `lynxkite-app`: The LynxKite web application. Install some plugins then run this to use LynxKite.
14
  - `lynxkite-graph-analytics`: Graph analytics plugin. The classical LynxKite experience!
15
  - `lynxkite-pillow`: A simple example plugin.
lynxkite-app/pyproject.toml CHANGED
@@ -6,7 +6,7 @@ readme = "README.md"
6
  requires-python = ">=3.11"
7
  dependencies = [
8
  "fastapi[standard]>=0.115.6",
9
- "lynxkite-ops",
10
  "orjson>=3.10.13",
11
  "pycrdt-websocket>=0.15.3",
12
  "pydantic-to-typescript>=2.0.0",
@@ -14,7 +14,7 @@ dependencies = [
14
  ]
15
 
16
  [tool.uv.sources]
17
- lynxkite-ops = { path = "../lynxkite-ops" }
18
 
19
  [build-system]
20
  requires = ["setuptools", "wheel", "setuptools-scm"]
@@ -25,8 +25,8 @@ namespaces = true
25
  where = ["src"]
26
 
27
  [tool.setuptools.package-data]
28
- "lynxkite.web_assets" = ["*"]
29
- "lynxkite.web_assets.assets" = ["*"]
30
 
31
  [tool.setuptools]
32
  py-modules = ["build_frontend"]
@@ -36,4 +36,4 @@ include-package-data = true
36
  build_py = "build_frontend.build_py"
37
 
38
  [project.scripts]
39
- lynxkite = "lynxkite.__main__:main"
 
6
  requires-python = ">=3.11"
7
  dependencies = [
8
  "fastapi[standard]>=0.115.6",
9
+ "lynxkite-core",
10
  "orjson>=3.10.13",
11
  "pycrdt-websocket>=0.15.3",
12
  "pydantic-to-typescript>=2.0.0",
 
14
  ]
15
 
16
  [tool.uv.sources]
17
+ lynxkite-core = { path = "../lynxkite-core" }
18
 
19
  [build-system]
20
  requires = ["setuptools", "wheel", "setuptools-scm"]
 
25
  where = ["src"]
26
 
27
  [tool.setuptools.package-data]
28
+ "lynxkite.app.web_assets" = ["*"]
29
+ "lynxkite.app.web_assets.assets" = ["*"]
30
 
31
  [tool.setuptools]
32
  py-modules = ["build_frontend"]
 
36
  build_py = "build_frontend.build_py"
37
 
38
  [project.scripts]
39
+ lynxkite = "lynxkite.app.__main__:main"
lynxkite-app/src/build_frontend.py CHANGED
@@ -11,7 +11,7 @@ class build_py(_build_py):
11
  print("\n\nBuilding frontend...", __file__)
12
  here = Path(__file__).parent.parent
13
  frontend_dir = here / "web"
14
- package_dir = here / "src" / "lynxkite" / "web_assets"
15
  subprocess.check_call(["npm", "install"], cwd=frontend_dir)
16
  subprocess.check_call(["npm", "run", "build"], cwd=frontend_dir)
17
  print("files in", frontend_dir / "dist")
 
11
  print("\n\nBuilding frontend...", __file__)
12
  here = Path(__file__).parent.parent
13
  frontend_dir = here / "web"
14
+ package_dir = here / "src" / "lynxkite" / "app" / "web_assets"
15
  subprocess.check_call(["npm", "install"], cwd=frontend_dir)
16
  subprocess.check_call(["npm", "run", "build"], cwd=frontend_dir)
17
  print("files in", frontend_dir / "dist")
lynxkite-app/src/lynxkite/{__init__.py β†’ app/__init__.py} RENAMED
File without changes
lynxkite-app/src/lynxkite/{__main__.py β†’ app/__main__.py} RENAMED
@@ -6,7 +6,7 @@ import os
6
  def main():
7
  port = int(os.environ.get("PORT", "8000"))
8
  reload = bool(os.environ.get("LYNXKITE_RELOAD", ""))
9
- uvicorn.run("lynxkite.main:app", host="0.0.0.0", port=port, reload=reload)
10
 
11
 
12
  if __name__ == "__main__":
 
6
  def main():
7
  port = int(os.environ.get("PORT", "8000"))
8
  reload = bool(os.environ.get("LYNXKITE_RELOAD", ""))
9
+ uvicorn.run("lynxkite.app.main:app", host="0.0.0.0", port=port, reload=reload)
10
 
11
 
12
  if __name__ == "__main__":
lynxkite-app/src/lynxkite/{crdt.py β†’ app/crdt.py} RENAMED
@@ -11,6 +11,7 @@ import pycrdt_websocket
11
  import pycrdt_websocket.ystore
12
  import uvicorn
13
  import builtins
 
14
 
15
  router = fastapi.APIRouter()
16
  DATA_PATH = pathlib.Path.cwd() / "data"
@@ -119,8 +120,6 @@ def crdt_update(crdt_obj, python_obj, boxes=set()):
119
 
120
 
121
  def try_to_load_workspace(ws, name):
122
- from . import workspace
123
-
124
  json_path = f"data/{name}"
125
  if os.path.exists(json_path):
126
  ws_pyd = workspace.load(json_path)
@@ -132,8 +131,6 @@ delayed_executions = {}
132
 
133
 
134
  async def workspace_changed(name, changes, ws_crdt):
135
- from . import workspace
136
-
137
  ws_pyd = workspace.Workspace.model_validate(ws_crdt.to_py())
138
  # Do not trigger execution for superficial changes.
139
  # This is a quick solution until we build proper caching.
@@ -157,8 +154,6 @@ async def workspace_changed(name, changes, ws_crdt):
157
 
158
 
159
  async def execute(name, ws_crdt, ws_pyd, delay=0):
160
- from . import workspace
161
-
162
  if delay:
163
  try:
164
  await asyncio.sleep(delay)
 
11
  import pycrdt_websocket.ystore
12
  import uvicorn
13
  import builtins
14
+ from lynxkite.core import workspace
15
 
16
  router = fastapi.APIRouter()
17
  DATA_PATH = pathlib.Path.cwd() / "data"
 
120
 
121
 
122
  def try_to_load_workspace(ws, name):
 
 
123
  json_path = f"data/{name}"
124
  if os.path.exists(json_path):
125
  ws_pyd = workspace.load(json_path)
 
131
 
132
 
133
  async def workspace_changed(name, changes, ws_crdt):
 
 
134
  ws_pyd = workspace.Workspace.model_validate(ws_crdt.to_py())
135
  # Do not trigger execution for superficial changes.
136
  # This is a quick solution until we build proper caching.
 
154
 
155
 
156
  async def execute(name, ws_crdt, ws_pyd, delay=0):
 
 
157
  if delay:
158
  try:
159
  await asyncio.sleep(delay)
lynxkite-app/src/lynxkite/{main.py β†’ app/main.py} RENAMED
@@ -8,8 +8,8 @@ import pathlib
8
  import pkgutil
9
  from fastapi.staticfiles import StaticFiles
10
  import starlette
11
- from lynxkite import ops
12
- from lynxkite import workspace
13
  from . import crdt
14
 
15
  here = pathlib.Path(__file__).parent
@@ -122,5 +122,5 @@ class SPAStaticFiles(StaticFiles):
122
  raise ex
123
 
124
 
125
- static_dir = SPAStaticFiles(packages=[("lynxkite", "web_assets")], html=True)
126
  app.mount("/", static_dir, name="web_assets")
 
8
  import pkgutil
9
  from fastapi.staticfiles import StaticFiles
10
  import starlette
11
+ from lynxkite.core import ops
12
+ from lynxkite.core import workspace
13
  from . import crdt
14
 
15
  here = pathlib.Path(__file__).parent
 
122
  raise ex
123
 
124
 
125
+ static_dir = SPAStaticFiles(packages=[("lynxkite.app", "web_assets")], html=True)
126
  app.mount("/", static_dir, name="web_assets")
lynxkite-app/src/lynxkite/{web_assets β†’ app/web_assets}/__init__.py RENAMED
File without changes
lynxkite-app/src/lynxkite/{web_assets β†’ app/web_assets}/assets/__init__.py RENAMED
File without changes
lynxkite-app/uv.lock CHANGED
@@ -209,7 +209,7 @@ wheels = [
209
  [[package]]
210
  name = "lynxkite"
211
  version = "0.1.0"
212
- source = { virtual = "." }
213
  dependencies = [
214
  { name = "fastapi", extra = ["standard"] },
215
  { name = "lynxkite-ops" },
 
209
  [[package]]
210
  name = "lynxkite"
211
  version = "0.1.0"
212
+ source = { editable = "." }
213
  dependencies = [
214
  { name = "fastapi", extra = ["standard"] },
215
  { name = "lynxkite-ops" },
{lynxkite-ops β†’ lynxkite-core}/README.md RENAMED
File without changes
{lynxkite-ops β†’ lynxkite-core}/build/lib/lynxkite/executors/one_by_one.py RENAMED
File without changes
{lynxkite-ops β†’ lynxkite-core}/build/lib/lynxkite/ops.py RENAMED
File without changes
{lynxkite-ops β†’ lynxkite-core}/build/lib/lynxkite/workspace.py RENAMED
File without changes
{lynxkite-ops β†’ lynxkite-core}/pyproject.toml RENAMED
@@ -1,5 +1,5 @@
1
  [project]
2
- name = "lynxkite-ops"
3
  version = "0.1.0"
4
  description = "A lightweight dependency for authoring LynxKite operations and executors"
5
  readme = "README.md"
 
1
  [project]
2
+ name = "lynxkite-core"
3
  version = "0.1.0"
4
  description = "A lightweight dependency for authoring LynxKite operations and executors"
5
  readme = "README.md"
{lynxkite-ops/src/lynxkite β†’ lynxkite-core/src/lynxkite/core}/executors/one_by_one.py RENAMED
File without changes
{lynxkite-ops/src/lynxkite β†’ lynxkite-core/src/lynxkite/core}/ops.py RENAMED
File without changes
{lynxkite-ops/src/lynxkite β†’ lynxkite-core/src/lynxkite/core}/workspace.py RENAMED
File without changes
lynxkite-graph-analytics/pyproject.toml CHANGED
@@ -5,11 +5,11 @@ description = "The graph analytics executor and boxes for LynxKite"
5
  readme = "README.md"
6
  requires-python = ">=3.11"
7
  dependencies = [
8
- "lynxkite-ops",
9
  "networkx>=3.4.2",
10
  "pandas>=2.2.3",
11
  "polars[gpu]>=1.14.0",
12
  ]
13
 
14
  [tool.uv.sources]
15
- lynxkite-ops = { path = "../lynxkite-ops" }
 
5
  readme = "README.md"
6
  requires-python = ">=3.11"
7
  dependencies = [
8
+ "lynxkite-core",
9
  "networkx>=3.4.2",
10
  "pandas>=2.2.3",
11
  "polars[gpu]>=1.14.0",
12
  ]
13
 
14
  [tool.uv.sources]
15
+ lynxkite-core = { path = "../lynxkite-core" }
lynxkite-graph-analytics/uv.lock CHANGED
@@ -79,7 +79,7 @@ name = "lynxkite-graph-analytics"
79
  version = "0.1.0"
80
  source = { virtual = "." }
81
  dependencies = [
82
- { name = "lynxkite-ops" },
83
  { name = "networkx" },
84
  { name = "pandas" },
85
  { name = "polars", extra = ["gpu"] },
@@ -87,16 +87,16 @@ dependencies = [
87
 
88
  [package.metadata]
89
  requires-dist = [
90
- { name = "lynxkite-ops", virtual = "../lynxkite-ops" },
91
  { name = "networkx", specifier = ">=3.4.2" },
92
  { name = "pandas", specifier = ">=2.2.3" },
93
  { name = "polars", extras = ["gpu"], specifier = ">=1.14.0" },
94
  ]
95
 
96
  [[package]]
97
- name = "lynxkite-ops"
98
  version = "0.1.0"
99
- source = { virtual = "../lynxkite-ops" }
100
 
101
  [[package]]
102
  name = "networkx"
 
79
  version = "0.1.0"
80
  source = { virtual = "." }
81
  dependencies = [
82
+ { name = "lynxkite-core" },
83
  { name = "networkx" },
84
  { name = "pandas" },
85
  { name = "polars", extra = ["gpu"] },
 
87
 
88
  [package.metadata]
89
  requires-dist = [
90
+ { name = "lynxkite-core", virtual = "../lynxkite-core" },
91
  { name = "networkx", specifier = ">=3.4.2" },
92
  { name = "pandas", specifier = ">=2.2.3" },
93
  { name = "polars", extras = ["gpu"], specifier = ">=1.14.0" },
94
  ]
95
 
96
  [[package]]
97
+ name = "lynxkite-core"
98
  version = "0.1.0"
99
+ source = { virtual = "../lynxkite-core" }
100
 
101
  [[package]]
102
  name = "networkx"
lynxkite-lynxscribe/README.md CHANGED
@@ -9,3 +9,9 @@ WEBUI_AUTH=false OPENAI_API_BASE_URL=http://localhost:8000/api/service/server.ly
9
  ```
10
 
11
  Or use [Lynx WebUI](https://github.com/biggraph/lynx-webui/) instead of Open WebUI.
 
 
 
 
 
 
 
9
  ```
10
 
11
  Or use [Lynx WebUI](https://github.com/biggraph/lynx-webui/) instead of Open WebUI.
12
+
13
+ Run tests with:
14
+
15
+ ```bash
16
+ uv run pytest
17
+ ```
lynxkite-lynxscribe/pyproject.toml CHANGED
@@ -5,8 +5,8 @@ description = "LynxKite operations for LynxScribe chat applications"
5
  readme = "README.md"
6
  requires-python = ">=3.11"
7
  dependencies = [
8
- "lynxkite-ops",
9
  ]
10
 
11
  [tool.uv.sources]
12
- lynxkite-ops = { path = "../lynxkite-ops" }
 
5
  readme = "README.md"
6
  requires-python = ">=3.11"
7
  dependencies = [
8
+ "lynxkite-core",
9
  ]
10
 
11
  [tool.uv.sources]
12
+ lynxkite-core = { path = "../lynxkite-core" }
lynxkite-lynxscribe/src/lynxscribe/lynxkite/llm_ops.py CHANGED
@@ -1,17 +1,19 @@
1
- """For specifying an LLM agent logic flow."""
2
 
3
- from . import ops
4
- import chromadb
 
 
 
 
 
5
  import enum
6
  import jinja2
7
  import json
8
- import openai
9
  import numpy as np
10
  import pandas as pd
11
- from .executors import one_by_one
12
 
13
- chat_client = openai.OpenAI(base_url="http://localhost:8080/v1")
14
- embedding_client = openai.OpenAI(base_url="http://localhost:7997/")
15
  jinja = jinja2.Environment()
16
  chroma_client = None
17
  LLM_CACHE = {}
@@ -21,6 +23,9 @@ op = ops.op_registration(ENV)
21
 
22
 
23
  def chat(*args, **kwargs):
 
 
 
24
  key = json.dumps({"method": "chat", "args": args, "kwargs": kwargs})
25
  if key not in LLM_CACHE:
26
  completion = chat_client.chat.completions.create(*args, **kwargs)
@@ -29,6 +34,9 @@ def chat(*args, **kwargs):
29
 
30
 
31
  def embedding(*args, **kwargs):
 
 
 
32
  key = json.dumps({"method": "embedding", "args": args, "kwargs": kwargs})
33
  if key not in LLM_CACHE:
34
  res = embedding_client.embeddings.create(*args, **kwargs)
@@ -97,9 +105,9 @@ def add_neighbors(nodes, edges, item):
97
 
98
  @op("Create prompt")
99
  def create_prompt(input, *, save_as="prompt", template: ops.LongStr):
100
- assert (
101
- template
102
- ), "Please specify the template. Refer to columns using the Jinja2 syntax."
103
  t = jinja.from_string(template)
104
  prompt = t.render(**input)
105
  return {**input, save_as: prompt}
@@ -186,6 +194,8 @@ def rag(
186
  else:
187
  collection_name = _ctx.node.id.replace(" ", "_")
188
  if chroma_client is None:
 
 
189
  chroma_client = chromadb.Client()
190
  for c in chroma_client.list_collections():
191
  if c.name == collection_name:
 
1
+ """For specifying an LLM agent logic flow.
2
 
3
+ This is very much a prototype. It might end up merged into LynxScribe
4
+ as an "agentic logic flow". It might just get deleted.
5
+
6
+ (This is why the dependencies are left hanging.)
7
+ """
8
+
9
+ from lynxkite.core import ops
10
  import enum
11
  import jinja2
12
  import json
 
13
  import numpy as np
14
  import pandas as pd
15
+ from lynxkite.core.executors import one_by_one
16
 
 
 
17
  jinja = jinja2.Environment()
18
  chroma_client = None
19
  LLM_CACHE = {}
 
23
 
24
 
25
  def chat(*args, **kwargs):
26
+ import openai
27
+
28
+ chat_client = openai.OpenAI(base_url="http://localhost:8080/v1")
29
  key = json.dumps({"method": "chat", "args": args, "kwargs": kwargs})
30
  if key not in LLM_CACHE:
31
  completion = chat_client.chat.completions.create(*args, **kwargs)
 
34
 
35
 
36
  def embedding(*args, **kwargs):
37
+ import openai
38
+
39
+ embedding_client = openai.OpenAI(base_url="http://localhost:7997/")
40
  key = json.dumps({"method": "embedding", "args": args, "kwargs": kwargs})
41
  if key not in LLM_CACHE:
42
  res = embedding_client.embeddings.create(*args, **kwargs)
 
105
 
106
  @op("Create prompt")
107
  def create_prompt(input, *, save_as="prompt", template: ops.LongStr):
108
+ assert template, (
109
+ "Please specify the template. Refer to columns using the Jinja2 syntax."
110
+ )
111
  t = jinja.from_string(template)
112
  prompt = t.render(**input)
113
  return {**input, save_as: prompt}
 
194
  else:
195
  collection_name = _ctx.node.id.replace(" ", "_")
196
  if chroma_client is None:
197
+ import chromadb
198
+
199
  chroma_client = chromadb.Client()
200
  for c in chroma_client.list_collections():
201
  if c.name == collection_name:
lynxkite-lynxscribe/src/lynxscribe/lynxkite/lynxscribe_ops.py CHANGED
@@ -221,7 +221,7 @@ def view(input):
221
 
222
  async def get_chat_api(ws):
223
  import pathlib
224
- from . import workspace
225
 
226
  DATA_PATH = pathlib.Path.cwd() / "data"
227
  path = DATA_PATH / ws
@@ -304,7 +304,7 @@ async def api_service_get(request):
304
 
305
  def get_lynxscribe_workspaces():
306
  import pathlib
307
- from . import workspace
308
 
309
  DATA_DIR = pathlib.Path.cwd() / "data"
310
  workspaces = []
 
221
 
222
  async def get_chat_api(ws):
223
  import pathlib
224
+ from lynxkite.core import workspace
225
 
226
  DATA_PATH = pathlib.Path.cwd() / "data"
227
  path = DATA_PATH / ws
 
304
 
305
  def get_lynxscribe_workspaces():
306
  import pathlib
307
+ from lynxkite.core import workspace
308
 
309
  DATA_DIR = pathlib.Path.cwd() / "data"
310
  workspaces = []
lynxkite-lynxscribe/src/lynxscribe/lynxkite/test_llm_ops.py DELETED
@@ -1,75 +0,0 @@
1
- import unittest
2
- from . import ops
3
- from . import llm_ops
4
- from .executors import one_by_one
5
- from . import workspace
6
-
7
- def make_node(id, op, type='basic', **params):
8
- return workspace.WorkspaceNode(
9
- id=id,
10
- type=type,
11
- position=workspace.Position(x=0, y=0),
12
- data=workspace.WorkspaceNodeData(title=op, params=params),
13
- )
14
- def make_input(id):
15
- return make_node(
16
- id, 'Input CSV',
17
- filename='/Users/danieldarabos/Downloads/aimo-train.csv',
18
- key='problem')
19
- def make_edge(source, target, targetHandle='input'):
20
- return workspace.WorkspaceEdge(
21
- id=f'{source}-{target}', source=source, target=target, sourceHandle='', targetHandle=targetHandle)
22
-
23
- class LLMOpsTest(unittest.TestCase):
24
- def testExecute(self):
25
- ws = workspace.Workspace(env='LLM logic', nodes=[
26
- make_node(
27
- '0', 'Input CSV',
28
- filename='/Users/danieldarabos/Downloads/aimo-train.csv',
29
- key='problem'),
30
- make_node(
31
- '1', 'View', type='table_view'),
32
- ], edges=[
33
- make_edge('0', '1')
34
- ])
35
- catalog = ops.CATALOGS[ws.env]
36
- one_by_one.execute(ws, catalog)
37
- # self.assertEqual('', ws.nodes[1].data.display)
38
-
39
- def testStages(self):
40
- ws = workspace.Workspace(env='LLM logic', nodes=[
41
- make_input('in1'), make_input('in2'), make_input('in3'),
42
- make_node('rag1', 'RAG'), make_node('rag2', 'RAG'),
43
- make_node('p1', 'Create prompt'), make_node('p2', 'Create prompt'),
44
- ], edges=[
45
- make_edge('in1', 'rag1', 'db'), make_edge('in2', 'rag1'),
46
- make_edge('rag1', 'p1'), make_edge('p1', 'rag2', 'db'),
47
- make_edge('in3', 'p2'), make_edge('p3', 'rag2'),
48
- ])
49
- catalog = ops.CATALOGS[ws.env]
50
- stages = one_by_one.get_stages(ws, catalog)
51
- print(stages)
52
- # self.assertEqual('', stages)
53
-
54
- def testStagesMultiInput(self):
55
- ws = workspace.Workspace(env='LLM logic', nodes=[
56
- make_node('doc', 'Input document'),
57
- make_node('split', 'Split document'),
58
- make_node('graph', 'Build document graph'),
59
- make_node('chat', 'Input chat'),
60
- make_node('rag', 'RAG'),
61
- make_node('neighbors', 'Add neighbors'),
62
- ], edges=[
63
- make_edge('doc', 'split'), make_edge('split', 'graph'),
64
- make_edge('split', 'rag', 'db'), make_edge('chat', 'rag', 'input'),
65
- make_edge('split', 'neighbors', 'nodes'),
66
- make_edge('graph', 'neighbors', 'edges'),
67
- make_edge('rag', 'neighbors', 'item'),
68
- ])
69
- catalog = ops.CATALOGS[ws.env]
70
- stages = one_by_one.get_stages(ws, catalog)
71
- print(stages)
72
- # self.assertEqual('', stages)
73
-
74
- if __name__ == '__main__':
75
- unittest.main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lynxkite-pillow/pyproject.toml CHANGED
@@ -5,9 +5,9 @@ description = "An example LynxKite plugin that wraps some Pillow image processin
5
  readme = "README.md"
6
  requires-python = ">=3.11"
7
  dependencies = [
8
- "lynxkite-ops",
9
  "pillow>=11.1.0",
10
  ]
11
 
12
  [tool.uv.sources]
13
- lynxkite-ops = { path = "../lynxkite-ops" }
 
5
  readme = "README.md"
6
  requires-python = ">=3.11"
7
  dependencies = [
8
+ "lynxkite-core",
9
  "pillow>=11.1.0",
10
  ]
11
 
12
  [tool.uv.sources]
13
+ lynxkite-core = { path = "../lynxkite-core" }
lynxkite-pillow/uv.lock CHANGED
@@ -2,22 +2,22 @@ version = 1
2
  requires-python = ">=3.11"
3
 
4
  [[package]]
5
- name = "lynxkite-ops"
6
  version = "0.1.0"
7
- source = { virtual = "../lynxkite-ops" }
8
 
9
  [[package]]
10
  name = "lynxkite-pillow"
11
  version = "0.1.0"
12
  source = { virtual = "." }
13
  dependencies = [
14
- { name = "lynxkite-ops" },
15
  { name = "pillow" },
16
  ]
17
 
18
  [package.metadata]
19
  requires-dist = [
20
- { name = "lynxkite-ops", virtual = "../lynxkite-ops" },
21
  { name = "pillow", specifier = ">=11.1.0" },
22
  ]
23
 
 
2
  requires-python = ">=3.11"
3
 
4
  [[package]]
5
+ name = "lynxkite-core"
6
  version = "0.1.0"
7
+ source = { virtual = "../lynxkite-core" }
8
 
9
  [[package]]
10
  name = "lynxkite-pillow"
11
  version = "0.1.0"
12
  source = { virtual = "." }
13
  dependencies = [
14
+ { name = "lynxkite-core" },
15
  { name = "pillow" },
16
  ]
17
 
18
  [package.metadata]
19
  requires-dist = [
20
+ { name = "lynxkite-core", virtual = "../lynxkite-core" },
21
  { name = "pillow", specifier = ">=11.1.0" },
22
  ]
23