weftai 0.1.0a1__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.
- weftai-0.1.0a1/.gitignore +30 -0
- weftai-0.1.0a1/LICENSE +21 -0
- weftai-0.1.0a1/PKG-INFO +30 -0
- weftai-0.1.0a1/README.md +5 -0
- weftai-0.1.0a1/pyproject.toml +41 -0
- weftai-0.1.0a1/src/weftai/__init__.py +119 -0
- weftai-0.1.0a1/src/weftai/_abort.py +74 -0
- weftai-0.1.0a1/src/weftai/adapter/__init__.py +23 -0
- weftai-0.1.0a1/src/weftai/adapter/bind.py +99 -0
- weftai-0.1.0a1/src/weftai/adapter/catalog/__init__.py +19 -0
- weftai-0.1.0a1/src/weftai/adapter/catalog/chinese.py +346 -0
- weftai-0.1.0a1/src/weftai/adapter/catalog/local.py +125 -0
- weftai-0.1.0a1/src/weftai/adapter/catalog/lookup.py +131 -0
- weftai-0.1.0a1/src/weftai/adapter/catalog/western.py +412 -0
- weftai-0.1.0a1/src/weftai/adapter/dialects.py +83 -0
- weftai-0.1.0a1/src/weftai/adapter/types.py +47 -0
- weftai-0.1.0a1/src/weftai/errors.py +129 -0
- weftai-0.1.0a1/src/weftai/executor/__init__.py +4 -0
- weftai-0.1.0a1/src/weftai/executor/normalize.py +51 -0
- weftai-0.1.0a1/src/weftai/executor/pool.py +37 -0
- weftai-0.1.0a1/src/weftai/executor/runtime.py +417 -0
- weftai-0.1.0a1/src/weftai/executor/signals.py +109 -0
- weftai-0.1.0a1/src/weftai/executor/types.py +18 -0
- weftai-0.1.0a1/src/weftai/format/__init__.py +12 -0
- weftai-0.1.0a1/src/weftai/format/formatter.py +95 -0
- weftai-0.1.0a1/src/weftai/format/sanitize.py +36 -0
- weftai-0.1.0a1/src/weftai/format/step.py +133 -0
- weftai-0.1.0a1/src/weftai/format/tokens.py +16 -0
- weftai-0.1.0a1/src/weftai/ids.py +26 -0
- weftai-0.1.0a1/src/weftai/operation.py +135 -0
- weftai-0.1.0a1/src/weftai/plan/__init__.py +4 -0
- weftai-0.1.0a1/src/weftai/plan/types.py +44 -0
- weftai-0.1.0a1/src/weftai/plan/validate.py +356 -0
- weftai-0.1.0a1/src/weftai/py.typed +0 -0
- weftai-0.1.0a1/src/weftai/refs/__init__.py +3 -0
- weftai-0.1.0a1/src/weftai/refs/syntax.py +75 -0
- weftai-0.1.0a1/src/weftai/registry/__init__.py +74 -0
- weftai-0.1.0a1/src/weftai/registry/describe.py +65 -0
- weftai-0.1.0a1/src/weftai/registry/plan_schema.py +84 -0
- weftai-0.1.0a1/src/weftai/results/__init__.py +12 -0
- weftai-0.1.0a1/src/weftai/results/resolve.py +39 -0
- weftai-0.1.0a1/src/weftai/results/session.py +25 -0
- weftai-0.1.0a1/src/weftai/results/store.py +131 -0
- weftai-0.1.0a1/src/weftai/results/types.py +41 -0
- weftai-0.1.0a1/src/weftai/schema/__init__.py +29 -0
- weftai-0.1.0a1/src/weftai/schema/json.py +109 -0
- weftai-0.1.0a1/src/weftai/schema/ref.py +53 -0
- weftai-0.1.0a1/src/weftai/schema/spec.py +355 -0
- weftai-0.1.0a1/src/weftai/schema/summarize.py +107 -0
- weftai-0.1.0a1/src/weftai/schema/types.py +160 -0
- weftai-0.1.0a1/src/weftai/schema/walk.py +140 -0
- weftai-0.1.0a1/src/weftai/std/__init__.py +12 -0
- weftai-0.1.0a1/src/weftai/std/fields.py +39 -0
- weftai-0.1.0a1/src/weftai/std/match.py +119 -0
- weftai-0.1.0a1/src/weftai/std/operations.py +310 -0
- weftai-0.1.0a1/src/weftai/trace.py +56 -0
- weftai-0.1.0a1/src/weftai/util/__init__.py +3 -0
- weftai-0.1.0a1/src/weftai/util/levenshtein.py +56 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
*$py.class
|
|
4
|
+
*.so
|
|
5
|
+
.Python
|
|
6
|
+
.venv/
|
|
7
|
+
venv/
|
|
8
|
+
dist/
|
|
9
|
+
build/
|
|
10
|
+
*.egg-info/
|
|
11
|
+
.eggs/
|
|
12
|
+
.coverage
|
|
13
|
+
.coverage.*
|
|
14
|
+
htmlcov/
|
|
15
|
+
.pytest_cache/
|
|
16
|
+
.mypy_cache/
|
|
17
|
+
.ruff_cache/
|
|
18
|
+
.pyright/
|
|
19
|
+
.tox/
|
|
20
|
+
.env
|
|
21
|
+
.env.*
|
|
22
|
+
!.env.example
|
|
23
|
+
uv.lock.bak
|
|
24
|
+
.DS_Store
|
|
25
|
+
Thumbs.db
|
|
26
|
+
.idea/
|
|
27
|
+
.vscode/
|
|
28
|
+
*.tsbuildinfo
|
|
29
|
+
.coverage.*
|
|
30
|
+
htmlcov/
|
weftai-0.1.0a1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Rex Technologies
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
weftai-0.1.0a1/PKG-INFO
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: weftai
|
|
3
|
+
Version: 0.1.0a1
|
|
4
|
+
Summary: Weftai: composable AI workflows (Rex Technologies)
|
|
5
|
+
Project-URL: Homepage, https://github.com/tochi-mba/weftai-python
|
|
6
|
+
Project-URL: Documentation, https://github.com/tochi-mba/weftai-python/tree/main/docs
|
|
7
|
+
Project-URL: Source, https://github.com/tochi-mba/weftai-python
|
|
8
|
+
Author: Rex Technologies
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: agents,ai,llm,tools,workflows
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Typing :: Typed
|
|
17
|
+
Requires-Python: >=3.12
|
|
18
|
+
Requires-Dist: pydantic<3,>=2.10
|
|
19
|
+
Provides-Extra: all
|
|
20
|
+
Requires-Dist: weftai-cli; extra == 'all'
|
|
21
|
+
Requires-Dist: weftai-mcp; extra == 'all'
|
|
22
|
+
Requires-Dist: weftai-providers; extra == 'all'
|
|
23
|
+
Requires-Dist: weftai-testing; extra == 'all'
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# weftai
|
|
27
|
+
|
|
28
|
+
Core runtime and adapter catalog. Install: `pip install weftai`.
|
|
29
|
+
|
|
30
|
+
See the [workspace README](https://github.com/tochi-mba/weftai-python).
|
weftai-0.1.0a1/README.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling", "hatch-cada>=1.0.3"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "weftai"
|
|
7
|
+
version = "0.1.0a1"
|
|
8
|
+
description = "Weftai: composable AI workflows (Rex Technologies)"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.12"
|
|
12
|
+
authors = [{ name = "Rex Technologies" }]
|
|
13
|
+
keywords = ["ai", "agents", "workflows", "llm", "tools"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 4 - Beta",
|
|
16
|
+
"License :: OSI Approved :: MIT License",
|
|
17
|
+
"Programming Language :: Python :: 3.12",
|
|
18
|
+
"Programming Language :: Python :: 3.13",
|
|
19
|
+
"Typing :: Typed",
|
|
20
|
+
]
|
|
21
|
+
dependencies = ["pydantic>=2.10,<3"]
|
|
22
|
+
|
|
23
|
+
[project.optional-dependencies]
|
|
24
|
+
all = ["weftai-providers", "weftai-mcp", "weftai-cli", "weftai-testing"]
|
|
25
|
+
|
|
26
|
+
[project.urls]
|
|
27
|
+
Homepage = "https://github.com/tochi-mba/weftai-python"
|
|
28
|
+
Documentation = "https://github.com/tochi-mba/weftai-python/tree/main/docs"
|
|
29
|
+
Source = "https://github.com/tochi-mba/weftai-python"
|
|
30
|
+
|
|
31
|
+
[tool.hatch.metadata.hooks.cada]
|
|
32
|
+
strategy = "pin"
|
|
33
|
+
|
|
34
|
+
[tool.hatch.build]
|
|
35
|
+
dev-mode-dirs = ["src"]
|
|
36
|
+
|
|
37
|
+
[tool.hatch.build.targets.wheel]
|
|
38
|
+
packages = ["src/weftai"]
|
|
39
|
+
|
|
40
|
+
[tool.hatch.build.targets.sdist]
|
|
41
|
+
include = ["src/weftai", "README.md", "LICENSE"]
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"""Weftai: composable AI workflows. A Rex Technologies product."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import pkgutil
|
|
6
|
+
|
|
7
|
+
__path__ = pkgutil.extend_path(__path__, __name__)
|
|
8
|
+
|
|
9
|
+
from pydantic import BaseModel, Field, TypeAdapter, ValidationError
|
|
10
|
+
|
|
11
|
+
from weftai.errors import (
|
|
12
|
+
DefinitionError,
|
|
13
|
+
LimitExceededError,
|
|
14
|
+
PlanValidationError,
|
|
15
|
+
RefResolutionError,
|
|
16
|
+
RegistryError,
|
|
17
|
+
StepExecutionError,
|
|
18
|
+
WeftaiError,
|
|
19
|
+
format_issue,
|
|
20
|
+
format_issues,
|
|
21
|
+
)
|
|
22
|
+
from weftai.executor.runtime import create_runtime
|
|
23
|
+
from weftai.executor.types import DEFAULT_LIMITS, TRACE_VERSION
|
|
24
|
+
from weftai.format.formatter import create_formatter
|
|
25
|
+
from weftai.format.sanitize import format_property, sanitize_label
|
|
26
|
+
from weftai.format.tokens import DEFAULT_BUDGETS, estimate_tokens
|
|
27
|
+
from weftai.ids import OPERATION_NAME_PATTERN, STEP_ID_PATTERN, is_valid_operation_name, is_valid_step_id
|
|
28
|
+
from weftai.operation import define_operation, define_operation_for, provenance_type
|
|
29
|
+
from weftai.plan.types import PlanSchema, PlanStepSchema
|
|
30
|
+
from weftai.plan.validate import validate_plan
|
|
31
|
+
from weftai.refs.syntax import REF_PATTERN_SOURCE, format_ref, parse_ref
|
|
32
|
+
from weftai.registry import create_registry
|
|
33
|
+
from weftai.registry.describe import describe_operations
|
|
34
|
+
from weftai.registry.plan_schema import build_plan_schema
|
|
35
|
+
from weftai.results.resolve import resolve_ref
|
|
36
|
+
from weftai.results.session import session_view
|
|
37
|
+
from weftai.results.store import create_memory_store
|
|
38
|
+
from weftai.results.types import DEFAULT_SESSION_ID, DEFAULT_STORE_LIMITS
|
|
39
|
+
from weftai.schema.json import input_json_schema
|
|
40
|
+
from weftai.schema.ref import is_ref_schema, ref, ref_meta
|
|
41
|
+
from weftai.schema.summarize import summarize_schema
|
|
42
|
+
from weftai.schema.types import (
|
|
43
|
+
collection,
|
|
44
|
+
groups,
|
|
45
|
+
is_step_output,
|
|
46
|
+
make_collection,
|
|
47
|
+
value,
|
|
48
|
+
with_sources,
|
|
49
|
+
)
|
|
50
|
+
from weftai.std.fields import field_names, resolve_field
|
|
51
|
+
from weftai.std.match import FILTER_OPS, matches_filter
|
|
52
|
+
from weftai.std.operations import STANDARD_OP_KINDS, standard_operations
|
|
53
|
+
from weftai.trace import build_trace
|
|
54
|
+
|
|
55
|
+
VERSION = "0.1.0"
|
|
56
|
+
|
|
57
|
+
__all__ = [
|
|
58
|
+
"BaseModel",
|
|
59
|
+
"DEFAULT_BUDGETS",
|
|
60
|
+
"DEFAULT_LIMITS",
|
|
61
|
+
"DEFAULT_SESSION_ID",
|
|
62
|
+
"DEFAULT_STORE_LIMITS",
|
|
63
|
+
"DefinitionError",
|
|
64
|
+
"FILTER_OPS",
|
|
65
|
+
"Field",
|
|
66
|
+
"LimitExceededError",
|
|
67
|
+
"OPERATION_NAME_PATTERN",
|
|
68
|
+
"PlanSchema",
|
|
69
|
+
"PlanStepSchema",
|
|
70
|
+
"PlanValidationError",
|
|
71
|
+
"REF_PATTERN_SOURCE",
|
|
72
|
+
"RefResolutionError",
|
|
73
|
+
"RegistryError",
|
|
74
|
+
"STANDARD_OP_KINDS",
|
|
75
|
+
"STEP_ID_PATTERN",
|
|
76
|
+
"StepExecutionError",
|
|
77
|
+
"TRACE_VERSION",
|
|
78
|
+
"TypeAdapter",
|
|
79
|
+
"VERSION",
|
|
80
|
+
"ValidationError",
|
|
81
|
+
"WeftaiError",
|
|
82
|
+
"build_plan_schema",
|
|
83
|
+
"build_trace",
|
|
84
|
+
"collection",
|
|
85
|
+
"create_formatter",
|
|
86
|
+
"create_memory_store",
|
|
87
|
+
"create_registry",
|
|
88
|
+
"create_runtime",
|
|
89
|
+
"define_operation",
|
|
90
|
+
"define_operation_for",
|
|
91
|
+
"describe_operations",
|
|
92
|
+
"estimate_tokens",
|
|
93
|
+
"field_names",
|
|
94
|
+
"format_issue",
|
|
95
|
+
"format_issues",
|
|
96
|
+
"format_property",
|
|
97
|
+
"format_ref",
|
|
98
|
+
"groups",
|
|
99
|
+
"input_json_schema",
|
|
100
|
+
"is_ref_schema",
|
|
101
|
+
"is_step_output",
|
|
102
|
+
"is_valid_operation_name",
|
|
103
|
+
"is_valid_step_id",
|
|
104
|
+
"make_collection",
|
|
105
|
+
"matches_filter",
|
|
106
|
+
"parse_ref",
|
|
107
|
+
"provenance_type",
|
|
108
|
+
"ref",
|
|
109
|
+
"ref_meta",
|
|
110
|
+
"resolve_field",
|
|
111
|
+
"resolve_ref",
|
|
112
|
+
"sanitize_label",
|
|
113
|
+
"session_view",
|
|
114
|
+
"standard_operations",
|
|
115
|
+
"summarize_schema",
|
|
116
|
+
"validate_plan",
|
|
117
|
+
"value",
|
|
118
|
+
"with_sources",
|
|
119
|
+
]
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"""AbortController / AbortSignal, matching the DOM API the TypeScript runtime uses."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Callable
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class AbortError(Exception):
|
|
10
|
+
"""Raised or stored as `signal.reason` when a step or plan is cancelled."""
|
|
11
|
+
|
|
12
|
+
def __init__(self, message: str = "This operation was aborted") -> None:
|
|
13
|
+
super().__init__(message)
|
|
14
|
+
self.name = "AbortError"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class AbortSignal:
|
|
18
|
+
def __init__(self) -> None:
|
|
19
|
+
self._aborted = False
|
|
20
|
+
self._reason: object = None
|
|
21
|
+
self._listeners: list[tuple[Callable[[], None], bool]] = []
|
|
22
|
+
|
|
23
|
+
@property
|
|
24
|
+
def aborted(self) -> bool:
|
|
25
|
+
return self._aborted
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def reason(self) -> object:
|
|
29
|
+
return self._reason
|
|
30
|
+
|
|
31
|
+
def add_event_listener(
|
|
32
|
+
self,
|
|
33
|
+
event: str,
|
|
34
|
+
callback: Callable[[], None],
|
|
35
|
+
*,
|
|
36
|
+
once: bool = False,
|
|
37
|
+
) -> None:
|
|
38
|
+
if event != "abort":
|
|
39
|
+
return
|
|
40
|
+
if self._aborted:
|
|
41
|
+
callback()
|
|
42
|
+
return
|
|
43
|
+
self._listeners.append((callback, once))
|
|
44
|
+
|
|
45
|
+
def remove_event_listener(self, event: str, callback: Callable[[], None]) -> None:
|
|
46
|
+
if event != "abort":
|
|
47
|
+
return
|
|
48
|
+
self._listeners = [(cb, once) for cb, once in self._listeners if cb is not callback]
|
|
49
|
+
|
|
50
|
+
def _abort(self, reason: object) -> None:
|
|
51
|
+
if self._aborted:
|
|
52
|
+
return
|
|
53
|
+
self._aborted = True
|
|
54
|
+
self._reason = reason if reason is not None else AbortError()
|
|
55
|
+
listeners = list(self._listeners)
|
|
56
|
+
self._listeners.clear()
|
|
57
|
+
for callback, _once in listeners:
|
|
58
|
+
callback()
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class AbortController:
|
|
62
|
+
def __init__(self) -> None:
|
|
63
|
+
self.signal = AbortSignal()
|
|
64
|
+
|
|
65
|
+
def abort(self, reason: object = None) -> None:
|
|
66
|
+
self.signal._abort(reason)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def is_abort_like(error: object) -> bool:
|
|
70
|
+
if isinstance(error, AbortError):
|
|
71
|
+
return True
|
|
72
|
+
if isinstance(error, BaseException) and getattr(error, "name", None) == "AbortError":
|
|
73
|
+
return True
|
|
74
|
+
return False
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from weftai.adapter.bind import bind_tool, parse_tool_arguments
|
|
2
|
+
from weftai.adapter.catalog import (
|
|
3
|
+
CAPABILITIES,
|
|
4
|
+
CHINESE_CAPABILITIES,
|
|
5
|
+
LOCAL_CAPABILITIES,
|
|
6
|
+
WESTERN_CAPABILITIES,
|
|
7
|
+
lookup_capability,
|
|
8
|
+
require_capability,
|
|
9
|
+
)
|
|
10
|
+
from weftai.adapter.dialects import compile_plan_schema, contains_any_of
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"CAPABILITIES",
|
|
14
|
+
"CHINESE_CAPABILITIES",
|
|
15
|
+
"LOCAL_CAPABILITIES",
|
|
16
|
+
"WESTERN_CAPABILITIES",
|
|
17
|
+
"bind_tool",
|
|
18
|
+
"compile_plan_schema",
|
|
19
|
+
"contains_any_of",
|
|
20
|
+
"lookup_capability",
|
|
21
|
+
"parse_tool_arguments",
|
|
22
|
+
"require_capability",
|
|
23
|
+
]
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import inspect
|
|
4
|
+
import json
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from weftai.adapter.dialects import compile_plan_schema
|
|
8
|
+
from weftai.plan.types import PlanSchema
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
async def resolve_ctx(ctx: Any) -> Any:
|
|
12
|
+
if callable(ctx):
|
|
13
|
+
result = ctx()
|
|
14
|
+
if inspect.isawaitable(result):
|
|
15
|
+
return await result
|
|
16
|
+
return result
|
|
17
|
+
return ctx
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def bind_tool(runtime: Any, spec: dict[str, Any], context: dict[str, Any]) -> dict[str, Any]:
|
|
21
|
+
include = spec.get("include")
|
|
22
|
+
scoped = runtime.registry.filter(include or (lambda _op: True))
|
|
23
|
+
allow_writes = spec.get("allowWrites")
|
|
24
|
+
if allow_writes is None:
|
|
25
|
+
allow_writes = any(op.effects == "write" for op in scoped.operations)
|
|
26
|
+
dialect = spec.get("dialect") or "union"
|
|
27
|
+
schema = compile_plan_schema(scoped.operations, dialect, {"strict": spec.get("strict")})
|
|
28
|
+
description = spec.get("description") or scoped.describe()
|
|
29
|
+
on_invalid = spec.get("onInvalid") or "text"
|
|
30
|
+
|
|
31
|
+
async def execute(input: object) -> dict[str, Any]:
|
|
32
|
+
parsed = PlanSchema.safe_parse(input)
|
|
33
|
+
if not parsed.success:
|
|
34
|
+
text = format_invalid_plan([{"path": i.path, "message": i.message} for i in parsed.issues])
|
|
35
|
+
if on_invalid == "throw":
|
|
36
|
+
raise ValueError(text)
|
|
37
|
+
return {"text": text, "ok": False}
|
|
38
|
+
result = await runtime.execute(
|
|
39
|
+
parsed.data,
|
|
40
|
+
{
|
|
41
|
+
"ctx": await resolve_ctx(context["ctx"]),
|
|
42
|
+
"session": {"id": context["sessionId"]},
|
|
43
|
+
"allowWrites": allow_writes,
|
|
44
|
+
"include": spec.get("include"),
|
|
45
|
+
},
|
|
46
|
+
)
|
|
47
|
+
return {"text": result["text"], "ok": result["ok"]}
|
|
48
|
+
|
|
49
|
+
async def handle(input: object) -> str:
|
|
50
|
+
return (await execute(input))["text"]
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
"name": spec["name"],
|
|
54
|
+
"description": description,
|
|
55
|
+
"schema": schema,
|
|
56
|
+
"dialect": dialect,
|
|
57
|
+
"execute": execute,
|
|
58
|
+
"handle": handle,
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def format_invalid_plan(issues: list[dict[str, Any]]) -> str:
|
|
63
|
+
if len(issues) == 0:
|
|
64
|
+
return "Could not read this plan: the value is not a plan."
|
|
65
|
+
lines = []
|
|
66
|
+
for issue in issues:
|
|
67
|
+
path = ".".join(str(p) for p in issue.get("path") or ())
|
|
68
|
+
where = "the plan" if path == "" else f"'{path}'"
|
|
69
|
+
lines.append(f"{where}: {issue['message']}")
|
|
70
|
+
return "Could not read this plan. " + " ".join(lines)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def parse_tool_arguments(raw: object) -> dict[str, object]:
|
|
74
|
+
if raw is None:
|
|
75
|
+
return {"ok": True, "value": {}}
|
|
76
|
+
if isinstance(raw, dict | list):
|
|
77
|
+
return {"ok": True, "value": raw}
|
|
78
|
+
if isinstance(raw, bool):
|
|
79
|
+
return {
|
|
80
|
+
"ok": False,
|
|
81
|
+
"message": "Tool arguments must be a JSON object or a JSON string, not boolean.",
|
|
82
|
+
}
|
|
83
|
+
if isinstance(raw, int | float):
|
|
84
|
+
return {
|
|
85
|
+
"ok": False,
|
|
86
|
+
"message": "Tool arguments must be a JSON object or a JSON string, not number.",
|
|
87
|
+
}
|
|
88
|
+
if not isinstance(raw, str):
|
|
89
|
+
return {
|
|
90
|
+
"ok": False,
|
|
91
|
+
"message": f"Tool arguments must be a JSON object or a JSON string, not {type(raw).__name__}.",
|
|
92
|
+
}
|
|
93
|
+
trimmed = raw.strip()
|
|
94
|
+
if len(trimmed) == 0:
|
|
95
|
+
return {"ok": True, "value": {}}
|
|
96
|
+
try:
|
|
97
|
+
return {"ok": True, "value": json.loads(trimmed)}
|
|
98
|
+
except json.JSONDecodeError:
|
|
99
|
+
return {"ok": False, "message": f"Tool arguments are not valid JSON: {trimmed[:80]}."}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from weftai.adapter.catalog.chinese import CHINESE_CAPABILITIES
|
|
2
|
+
from weftai.adapter.catalog.local import LOCAL_CAPABILITIES
|
|
3
|
+
from weftai.adapter.catalog.lookup import (
|
|
4
|
+
CAPABILITIES,
|
|
5
|
+
capabilities_for,
|
|
6
|
+
lookup_capability,
|
|
7
|
+
require_capability,
|
|
8
|
+
)
|
|
9
|
+
from weftai.adapter.catalog.western import WESTERN_CAPABILITIES
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"CAPABILITIES",
|
|
13
|
+
"CHINESE_CAPABILITIES",
|
|
14
|
+
"LOCAL_CAPABILITIES",
|
|
15
|
+
"WESTERN_CAPABILITIES",
|
|
16
|
+
"capabilities_for",
|
|
17
|
+
"lookup_capability",
|
|
18
|
+
"require_capability",
|
|
19
|
+
]
|