vectorsmith 0.1.0__py3-none-any.whl

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 (72) hide show
  1. vectorsmith/__init__.py +31 -0
  2. vectorsmith/anthropic.py +42 -0
  3. vectorsmith/langchain.py +5 -0
  4. vectorsmith/langchain_tools.py +110 -0
  5. vectorsmith/langgraph.py +5 -0
  6. vectorsmith/openai_agents.py +69 -0
  7. vectorsmith/runtime.py +139 -0
  8. vectorsmith-0.1.0.dist-info/METADATA +77 -0
  9. vectorsmith-0.1.0.dist-info/RECORD +72 -0
  10. vectorsmith-0.1.0.dist-info/WHEEL +4 -0
  11. vectorsmith-0.1.0.dist-info/entry_points.txt +2 -0
  12. vectorsmith_cli/__init__.py +1 -0
  13. vectorsmith_cli/drafts_cmd.py +71 -0
  14. vectorsmith_cli/http/__init__.py +1 -0
  15. vectorsmith_cli/http/app.py +136 -0
  16. vectorsmith_cli/http/builtin_oauth/__init__.py +1 -0
  17. vectorsmith_cli/http/builtin_oauth/pages.py +16 -0
  18. vectorsmith_cli/http/builtin_oauth/server.py +123 -0
  19. vectorsmith_cli/http/builtin_oauth/store.py +198 -0
  20. vectorsmith_cli/identity.py +4 -0
  21. vectorsmith_cli/init_cmd.py +100 -0
  22. vectorsmith_cli/introspect_cmd.py +46 -0
  23. vectorsmith_cli/main.py +152 -0
  24. vectorsmith_cli/serve_common.py +274 -0
  25. vectorsmith_cli/serve_http.py +65 -0
  26. vectorsmith_cli/serve_stdio.py +219 -0
  27. vectorsmith_cli/stdio_guard.py +41 -0
  28. vectorsmith_cli/test_cmd.py +68 -0
  29. vectorsmith_cli/validate_cmd.py +68 -0
  30. vectorsmith_core/__init__.py +26 -0
  31. vectorsmith_core/adapters/__init__.py +1 -0
  32. vectorsmith_core/adapters/base.py +62 -0
  33. vectorsmith_core/adapters/capabilities.py +124 -0
  34. vectorsmith_core/adapters/chroma.py +128 -0
  35. vectorsmith_core/adapters/milvus.py +129 -0
  36. vectorsmith_core/adapters/pgvector.py +186 -0
  37. vectorsmith_core/adapters/pinecone.py +106 -0
  38. vectorsmith_core/adapters/qdrant.py +270 -0
  39. vectorsmith_core/adapters/registry.py +1 -0
  40. vectorsmith_core/adapters/weaviate.py +107 -0
  41. vectorsmith_core/api.py +220 -0
  42. vectorsmith_core/compilepkg/__init__.py +1 -0
  43. vectorsmith_core/compilepkg/builtins.py +157 -0
  44. vectorsmith_core/compilepkg/compiler.py +148 -0
  45. vectorsmith_core/compilepkg/drafts.py +113 -0
  46. vectorsmith_core/compilepkg/validator.py +287 -0
  47. vectorsmith_core/embed/__init__.py +1 -0
  48. vectorsmith_core/embed/models.py +7 -0
  49. vectorsmith_core/embed/provider.py +55 -0
  50. vectorsmith_core/errors.py +98 -0
  51. vectorsmith_core/execute/__init__.py +1 -0
  52. vectorsmith_core/execute/engine.py +236 -0
  53. vectorsmith_core/execute/expr/__init__.py +6 -0
  54. vectorsmith_core/execute/expr/eval_polars.py +87 -0
  55. vectorsmith_core/execute/expr/grammar.lark +44 -0
  56. vectorsmith_core/execute/expr/parser.py +144 -0
  57. vectorsmith_core/execute/pipeline.py +143 -0
  58. vectorsmith_core/execute/single_step.py +146 -0
  59. vectorsmith_core/introspect/__init__.py +1 -0
  60. vectorsmith_core/introspect/sampling.py +115 -0
  61. vectorsmith_core/introspect/schema_export.py +65 -0
  62. vectorsmith_core/introspect/schema_export_v1.json +11 -0
  63. vectorsmith_core/introspect/types.py +1 -0
  64. vectorsmith_core/ir/__init__.py +1 -0
  65. vectorsmith_core/ir/filter.py +104 -0
  66. vectorsmith_core/py.typed +0 -0
  67. vectorsmith_core/tds/__init__.py +1 -0
  68. vectorsmith_core/tds/loader.py +214 -0
  69. vectorsmith_core/tds/models.py +262 -0
  70. vectorsmith_core/tds/schema.py +19 -0
  71. vectorsmith_core/tds/schema_v1.json +1228 -0
  72. vectorsmith_core/version.py +4 -0
@@ -0,0 +1,31 @@
1
+ """VectorSmith application API.
2
+
3
+ In-process (LangChain, LangGraph, OpenAI Agents, Anthropic SDK)::
4
+
5
+ from vectorsmith import load_tools # LangChain / LangGraph
6
+ from vectorsmith import connect # call() or .as_openai_agents() / .as_anthropic()
7
+
8
+ MCP hosts (Claude Desktop, Claude Code, Codex, Cursor)::
9
+
10
+ vectorsmith serve tools.yaml --name invoices
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ from typing import TYPE_CHECKING, Any
16
+
17
+ from vectorsmith.runtime import BoundTools, connect
18
+
19
+ if TYPE_CHECKING:
20
+ from vectorsmith.langchain_tools import Toolset
21
+ from vectorsmith.langchain_tools import load_tools as load_tools
22
+
23
+ __all__ = ["BoundTools", "Toolset", "connect", "load_tools"]
24
+
25
+
26
+ def __getattr__(name: str) -> Any:
27
+ if name in {"load_tools", "Toolset"}:
28
+ from vectorsmith.langchain_tools import Toolset, load_tools
29
+
30
+ return {"load_tools": load_tools, "Toolset": Toolset}[name]
31
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
@@ -0,0 +1,42 @@
1
+ """Anthropic Messages API tools from a tools.yaml.
2
+
3
+ pip install "vectorsmith[qdrant]" anthropic
4
+ from vectorsmith.anthropic import load_tools
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import json
10
+ from collections.abc import Mapping
11
+ from pathlib import Path
12
+ from typing import Any
13
+
14
+ from vectorsmith.runtime import BoundTools, connect
15
+
16
+
17
+ class AnthropicToolset:
18
+ """``tools`` for ``messages.create``, plus ``execute`` for ``tool_use`` blocks."""
19
+
20
+ def __init__(self, bound: BoundTools) -> None:
21
+ self._bound = bound
22
+ self.tools = bound.as_anthropic()
23
+
24
+ @property
25
+ def names(self) -> list[str]:
26
+ return self._bound.names
27
+
28
+ async def execute(self, name: str, tool_input: Mapping[str, Any] | None = None) -> str:
29
+ result = await self._bound.call(name, tool_input)
30
+ return json.dumps(result)
31
+
32
+ async def aclose(self) -> None:
33
+ await self._bound.aclose()
34
+
35
+
36
+ def load_tools(
37
+ *sources: str | Path | dict[str, Any],
38
+ env: Mapping[str, str] | None = None,
39
+ env_file: str | Path | None = None,
40
+ ) -> AnthropicToolset:
41
+ """Compile tools.yaml into Anthropic tool defs + an in-process dispatcher."""
42
+ return AnthropicToolset(connect(*sources, env=env, env_file=env_file))
@@ -0,0 +1,5 @@
1
+ """LangChain adapter. Same as ``from vectorsmith import load_tools``."""
2
+
3
+ from vectorsmith.langchain_tools import Toolset, load_tools
4
+
5
+ __all__ = ["Toolset", "load_tools"]
@@ -0,0 +1,110 @@
1
+ """LangChain / LangGraph tools from a tools.yaml.
2
+
3
+ Application code: write YAML, then ``from vectorsmith import load_tools``.
4
+ Hosts that cannot import Python (Claude Desktop, Codex, Cursor) use
5
+ ``vectorsmith serve`` instead. Same YAML.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import asyncio
11
+ import uuid
12
+ from collections.abc import Mapping, Sequence
13
+ from pathlib import Path
14
+ from typing import Any
15
+
16
+ from langchain_core.tools import BaseTool, StructuredTool
17
+ from pydantic import BaseModel, Field, create_model
18
+
19
+ from vectorsmith.runtime import BoundTools, connect
20
+ from vectorsmith_core.api import CallContext
21
+ from vectorsmith_core.execute.engine import Engine
22
+
23
+ _JSON_TO_PY: dict[str, type] = {
24
+ "string": str,
25
+ "integer": int,
26
+ "number": float,
27
+ "boolean": bool,
28
+ }
29
+
30
+
31
+ class Toolset(list[BaseTool]):
32
+ """LangChain tools plus the engines that back them. Call ``aclose`` when done."""
33
+
34
+ def __init__(self, tools: Sequence[BaseTool], engines: Sequence[Engine]) -> None:
35
+ super().__init__(tools)
36
+ self._engines = list(engines)
37
+
38
+ async def aclose(self) -> None:
39
+ for engine in self._engines:
40
+ await engine.aclose()
41
+
42
+
43
+ def _py_type(spec: dict[str, Any]) -> type:
44
+ if spec.get("type") == "array":
45
+ item = _JSON_TO_PY.get((spec.get("items") or {}).get("type", "string"), str)
46
+ return list[item] # type: ignore[valid-type]
47
+ return _JSON_TO_PY.get(str(spec.get("type", "string")), str)
48
+
49
+
50
+ def _args_model(tool_name: str, input_schema: dict[str, Any]) -> type[BaseModel]:
51
+ props = input_schema.get("properties") or {}
52
+ required = set(input_schema.get("required") or [])
53
+ fields: dict[str, Any] = {}
54
+ for key, spec in props.items():
55
+ typ = _py_type(spec if isinstance(spec, dict) else {})
56
+ desc = spec.get("description") if isinstance(spec, dict) else None
57
+ if key in required:
58
+ fields[key] = (typ, Field(..., description=desc))
59
+ else:
60
+ default = spec.get("default") if isinstance(spec, dict) else None
61
+ fields[key] = (typ | None, Field(default, description=desc))
62
+ if not fields:
63
+ return create_model(f"{tool_name}Args")
64
+ return create_model(f"{tool_name}Args", **fields)
65
+
66
+
67
+ def _bind(engine: Engine, name: str, schema: dict[str, Any]) -> StructuredTool:
68
+ async def _arun(**kwargs: Any) -> dict[str, Any]:
69
+ clean = {k: v for k, v in kwargs.items() if v is not None}
70
+ result = await engine.call(
71
+ name, clean, ctx=CallContext(request_id=str(uuid.uuid4()))
72
+ )
73
+ return result.model_dump()
74
+
75
+ def _run(**kwargs: Any) -> dict[str, Any]:
76
+ try:
77
+ asyncio.get_running_loop()
78
+ except RuntimeError:
79
+ return asyncio.run(_arun(**kwargs))
80
+ raise RuntimeError(f"tool {name!r} must be awaited in an async context")
81
+
82
+ return StructuredTool(
83
+ name=name,
84
+ description=schema.get("description") or name,
85
+ args_schema=_args_model(name, schema.get("inputSchema") or {}),
86
+ coroutine=_arun,
87
+ func=_run,
88
+ )
89
+
90
+
91
+ def toolset_from_bound(bound: BoundTools) -> Toolset:
92
+ tools: list[BaseTool] = []
93
+ for engine in bound._engines:
94
+ for schema in engine.project.mcp_tool_schemas():
95
+ tools.append(_bind(engine, str(schema["name"]), schema))
96
+ return Toolset(tools, bound._engines)
97
+
98
+
99
+ def load_tools(
100
+ *sources: str | Path | dict[str, Any],
101
+ env: Mapping[str, str] | None = None,
102
+ env_file: str | Path | None = None,
103
+ ) -> Toolset:
104
+ """Compile one or more tools.yaml files into LangChain / LangGraph tools.
105
+
106
+ >>> from vectorsmith import load_tools
107
+ >>> tools = load_tools("tools.invoices.yaml", "tools.tickets.yaml")
108
+ >>> # pass ``tools`` into create_agent / create_react_agent; await tools.aclose()
109
+ """
110
+ return connect(*sources, env=env, env_file=env_file).as_langchain()
@@ -0,0 +1,5 @@
1
+ """LangGraph adapter. Same LangChain tools (`ToolNode`, `create_react_agent`)."""
2
+
3
+ from vectorsmith.langchain_tools import Toolset, load_tools
4
+
5
+ __all__ = ["Toolset", "load_tools"]
@@ -0,0 +1,69 @@
1
+ """OpenAI Agents SDK tools from a tools.yaml.
2
+
3
+ pip install "vectorsmith[qdrant,openai-agents]"
4
+ from vectorsmith.openai_agents import load_tools
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import json
10
+ from collections.abc import Mapping, Sequence
11
+ from pathlib import Path
12
+ from typing import Any
13
+
14
+ from vectorsmith.runtime import BoundTools, connect
15
+
16
+
17
+ class OpenAIAgentToolset(list[Any]):
18
+ """FunctionTool list plus ``aclose`` for the backing engines."""
19
+
20
+ def __init__(self, tools: Sequence[Any], bound: BoundTools) -> None:
21
+ super().__init__(tools)
22
+ self._bound = bound
23
+
24
+ async def aclose(self) -> None:
25
+ await self._bound.aclose()
26
+
27
+
28
+ def _function_tool(bound: BoundTools, schema: dict[str, Any]) -> Any:
29
+ try:
30
+ from agents import FunctionTool
31
+ except ImportError as exc:
32
+ raise ImportError(
33
+ "OpenAI Agents SDK is required. Install with: "
34
+ 'pip install "vectorsmith[openai-agents]"'
35
+ ) from exc
36
+
37
+ name = str(schema["name"])
38
+ params = schema.get("inputSchema") or {"type": "object", "properties": {}}
39
+
40
+ async def _on_invoke(_ctx: Any, raw: str) -> str:
41
+ try:
42
+ args = json.loads(raw) if raw else {}
43
+ except json.JSONDecodeError:
44
+ args = {}
45
+ if not isinstance(args, dict):
46
+ return json.dumps({"error": "tool arguments must be a JSON object"})
47
+ result = await bound.call(name, args)
48
+ return json.dumps(result)
49
+
50
+ return FunctionTool(
51
+ name=name,
52
+ description=schema.get("description") or name,
53
+ params_json_schema=params,
54
+ on_invoke_tool=_on_invoke,
55
+ strict_json_schema=False,
56
+ )
57
+
58
+
59
+ def toolset_from_bound(bound: BoundTools) -> OpenAIAgentToolset:
60
+ return OpenAIAgentToolset([_function_tool(bound, s) for s in bound.schemas], bound)
61
+
62
+
63
+ def load_tools(
64
+ *sources: str | Path | dict[str, Any],
65
+ env: Mapping[str, str] | None = None,
66
+ env_file: str | Path | None = None,
67
+ ) -> OpenAIAgentToolset:
68
+ """Compile tools.yaml into OpenAI Agents SDK ``FunctionTool``s."""
69
+ return connect(*sources, env=env, env_file=env_file).as_openai_agents()
vectorsmith/runtime.py ADDED
@@ -0,0 +1,139 @@
1
+ """Compile tools.yaml in-process. Framework adapters wrap this; MCP hosts use ``serve``."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ import uuid
7
+ from collections.abc import Mapping, Sequence
8
+ from pathlib import Path
9
+ from typing import Any
10
+
11
+ from vectorsmith_core.api import CallContext, EnvCredentialResolver, load_project
12
+ from vectorsmith_core.execute.engine import Engine
13
+
14
+
15
+ def _read_env_file(path: Path | None) -> dict[str, str]:
16
+ if path is None or not path.is_file():
17
+ return {}
18
+ out: dict[str, str] = {}
19
+ for line in path.read_text().splitlines():
20
+ line = line.strip()
21
+ if not line or line.startswith("#") or "=" not in line:
22
+ continue
23
+ key, value = line.split("=", 1)
24
+ out[key.strip()] = value.strip()
25
+ return out
26
+
27
+
28
+ def _merge_env(
29
+ env: Mapping[str, str] | None,
30
+ env_file: str | Path | None,
31
+ ) -> dict[str, str]:
32
+ merged = dict(os.environ)
33
+ if env:
34
+ merged.update(env)
35
+ merged.update(_read_env_file(Path(env_file) if env_file else None))
36
+ return merged
37
+
38
+
39
+ def _one_engine(source: str | Path | dict[str, Any], env: Mapping[str, str]) -> Engine:
40
+ project = load_project(source, env=env)
41
+ errors = [i for i in project.issues if i.severity == "error"]
42
+ if errors:
43
+ msgs = "; ".join(f"{i.code} {i.message}" for i in errors)
44
+ raise ValueError(f"tools.yaml failed validation: {msgs}")
45
+ try:
46
+ from vectorsmith_core.embed.provider import FastEmbedProvider
47
+
48
+ embed: FastEmbedProvider | None = FastEmbedProvider()
49
+ except Exception:
50
+ embed = None
51
+ return Engine(
52
+ project,
53
+ credential_resolver=EnvCredentialResolver(env),
54
+ embed_provider=embed,
55
+ )
56
+
57
+
58
+ class BoundTools:
59
+ """Compiled YAML tools. Call them directly, or adapt to an agent framework.
60
+
61
+ >>> from vectorsmith import connect
62
+ >>> vs = connect("tools.yaml")
63
+ >>> await vs.call("search_invoices", {"query": "Globex", "limit": 3})
64
+ >>> tools = vs.as_langchain() # pip install 'vectorsmith[langchain]'
65
+ """
66
+
67
+ def __init__(self, engines: Sequence[Engine]) -> None:
68
+ self._engines = list(engines)
69
+ self._by_name: dict[str, Engine] = {}
70
+ schemas: list[dict[str, Any]] = []
71
+ for engine in self._engines:
72
+ for schema in engine.project.mcp_tool_schemas():
73
+ name = str(schema["name"])
74
+ self._by_name[name] = engine
75
+ schemas.append(schema)
76
+ self._schemas = schemas
77
+
78
+ @property
79
+ def names(self) -> list[str]:
80
+ return [str(s["name"]) for s in self._schemas]
81
+
82
+ @property
83
+ def schemas(self) -> list[dict[str, Any]]:
84
+ """MCP tool schemas (``name``, ``description``, ``inputSchema``)."""
85
+ return list(self._schemas)
86
+
87
+ def as_anthropic(self) -> list[dict[str, Any]]:
88
+ """Tool defs for ``anthropic.Anthropic().messages.create(tools=...)``."""
89
+ return [
90
+ {
91
+ "name": s["name"],
92
+ "description": s.get("description") or s["name"],
93
+ "input_schema": s.get("inputSchema") or {"type": "object", "properties": {}},
94
+ }
95
+ for s in self._schemas
96
+ ]
97
+
98
+ def as_langchain(self) -> Any:
99
+ """LangChain ``StructuredTool`` list. Requires ``vectorsmith[langchain]``."""
100
+ from vectorsmith.langchain_tools import toolset_from_bound
101
+
102
+ return toolset_from_bound(self)
103
+
104
+ def as_openai_agents(self) -> Any:
105
+ """OpenAI Agents SDK ``FunctionTool`` list. Requires ``vectorsmith[openai-agents]``."""
106
+ from vectorsmith.openai_agents import toolset_from_bound
107
+
108
+ return toolset_from_bound(self)
109
+
110
+ async def call(self, name: str, args: Mapping[str, Any] | None = None) -> dict[str, Any]:
111
+ engine = self._by_name.get(name)
112
+ if engine is None:
113
+ known = ", ".join(self.names) or "(none)"
114
+ raise KeyError(f"unknown tool {name!r}; loaded: {known}")
115
+ clean = {k: v for k, v in dict(args or {}).items() if v is not None}
116
+ result = await engine.call(
117
+ name, clean, ctx=CallContext(request_id=str(uuid.uuid4()))
118
+ )
119
+ return result.model_dump()
120
+
121
+ async def aclose(self) -> None:
122
+ for engine in self._engines:
123
+ await engine.aclose()
124
+
125
+
126
+ def connect(
127
+ *sources: str | Path | dict[str, Any],
128
+ env: Mapping[str, str] | None = None,
129
+ env_file: str | Path | None = None,
130
+ ) -> BoundTools:
131
+ """Compile one or more tools.yaml files. No MCP subprocess.
132
+
133
+ Use this when you want ``await vs.call(...)`` or a non-LangChain adapter.
134
+ LangChain / LangGraph apps can keep using ``load_tools``.
135
+ """
136
+ if not sources:
137
+ raise ValueError("connect requires at least one tools.yaml path")
138
+ merged = _merge_env(env, env_file)
139
+ return BoundTools([_one_engine(source, merged) for source in sources])
@@ -0,0 +1,77 @@
1
+ Metadata-Version: 2.5
2
+ Name: vectorsmith
3
+ Version: 0.1.0
4
+ Summary: YAML tools for agents: load_tools in-process, or vectorsmith serve as MCP
5
+ Project-URL: Homepage, https://github.com/kjgpta/vectorsmith
6
+ Project-URL: Documentation, https://kjgpta.github.io/vectorsmith/
7
+ Project-URL: Issues, https://github.com/kjgpta/vectorsmith/issues
8
+ Project-URL: Changelog, https://github.com/kjgpta/vectorsmith/blob/main/CHANGELOG.md
9
+ Author: VectorSmith contributors
10
+ License: Apache-2.0
11
+ Keywords: agents,claude,codex,langchain,langgraph,mcp
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: License :: OSI Approved :: Apache Software License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
19
+ Classifier: Typing :: Typed
20
+ Requires-Python: >=3.11
21
+ Requires-Dist: argon2-cffi
22
+ Requires-Dist: httpx
23
+ Requires-Dist: jsonschema
24
+ Requires-Dist: lark
25
+ Requires-Dist: mcp>=1.2
26
+ Requires-Dist: polars>=1.0
27
+ Requires-Dist: pydantic>=2.7
28
+ Requires-Dist: pyyaml
29
+ Requires-Dist: ruamel-yaml
30
+ Requires-Dist: starlette
31
+ Requires-Dist: typer
32
+ Requires-Dist: uvicorn
33
+ Requires-Dist: watchfiles
34
+ Provides-Extra: anthropic
35
+ Requires-Dist: anthropic>=0.40; extra == 'anthropic'
36
+ Provides-Extra: chroma
37
+ Requires-Dist: chromadb>=0.5; extra == 'chroma'
38
+ Requires-Dist: fastembed>=0.3; extra == 'chroma'
39
+ Provides-Extra: langchain
40
+ Requires-Dist: langchain-core>=0.3; extra == 'langchain'
41
+ Provides-Extra: langgraph
42
+ Requires-Dist: langchain-core>=0.3; extra == 'langgraph'
43
+ Requires-Dist: langgraph>=0.2; extra == 'langgraph'
44
+ Provides-Extra: milvus
45
+ Requires-Dist: fastembed>=0.3; extra == 'milvus'
46
+ Requires-Dist: pymilvus>=2.4; extra == 'milvus'
47
+ Provides-Extra: openai-agents
48
+ Requires-Dist: openai-agents>=0.2; extra == 'openai-agents'
49
+ Provides-Extra: pgvector
50
+ Requires-Dist: fastembed>=0.3; extra == 'pgvector'
51
+ Requires-Dist: psycopg[binary,pool]>=3.2; extra == 'pgvector'
52
+ Provides-Extra: pinecone
53
+ Requires-Dist: fastembed>=0.3; extra == 'pinecone'
54
+ Requires-Dist: pinecone>=5.0; extra == 'pinecone'
55
+ Provides-Extra: qdrant
56
+ Requires-Dist: fastembed>=0.3; extra == 'qdrant'
57
+ Requires-Dist: qdrant-client>=1.9; extra == 'qdrant'
58
+ Provides-Extra: weaviate
59
+ Requires-Dist: fastembed>=0.3; extra == 'weaviate'
60
+ Requires-Dist: weaviate-client>=4.0; extra == 'weaviate'
61
+ Description-Content-Type: text/markdown
62
+
63
+ # vectorsmith
64
+
65
+ Install this package. Write a `tools.yaml`. Use `load_tools` in Python or `vectorsmith serve` as an MCP server.
66
+
67
+ ```bash
68
+ pip install "vectorsmith[qdrant,langchain]"
69
+ ```
70
+
71
+ ```python
72
+ from vectorsmith import load_tools
73
+
74
+ tools = load_tools("tools.yaml")
75
+ ```
76
+
77
+ See the repository `README.md` and `docs/` for integrations and the YAML reference.
@@ -0,0 +1,72 @@
1
+ vectorsmith/__init__.py,sha256=GeKTiJgVlm_xdbyc90_y2Cbtwh8NciBQhOnxEzWo5gw,989
2
+ vectorsmith/anthropic.py,sha256=rgU6MEwfOJQGUgozxsbowbdX-gFVjSe_BNLuGo0V87Q,1236
3
+ vectorsmith/langchain.py,sha256=IuGzmEj8-ccCvXGKgqzETTeZExl6OzrpHvA8PLQ43M8,171
4
+ vectorsmith/langchain_tools.py,sha256=JmzUaOeSehXn0CWM1AfneYbdnYOtBtn1hSodMUNx4Ng,3858
5
+ vectorsmith/langgraph.py,sha256=n9UxPoOzubNMUrV7Avv6x8DSDiNABTKnmlXbbifWuX8,180
6
+ vectorsmith/openai_agents.py,sha256=mCNypFVXY2svRut3WCsmsJhLMXORcsTqZyaFYOJJpgc,2147
7
+ vectorsmith/runtime.py,sha256=54yMtGbm8VF7lLOLWO7by3ZDmmmkejunaTjG-R6u82Y,4858
8
+ vectorsmith_cli/__init__.py,sha256=4HbPGNQQMJd5UZSftZH8clgTrAkSy9sBf2Ps5-z6SwA,23
9
+ vectorsmith_cli/drafts_cmd.py,sha256=qqmsViVPShPIfihlk_4L9Dgdtg4uzIYKQ_pgwkfIiJY,2481
10
+ vectorsmith_cli/identity.py,sha256=sIZpS8VnHWwWxbs3ce6Wb7RIToAyw6DBWU7WB4LD8Gc,147
11
+ vectorsmith_cli/init_cmd.py,sha256=fK4G2z-qnvQr4anCL8XpfXr7JdXzfbHcOAsPtxSseJE,2430
12
+ vectorsmith_cli/introspect_cmd.py,sha256=bDdyid3KtSylkruqXc6odUfkwDhhIqyKvM9j5KF4TcI,1179
13
+ vectorsmith_cli/main.py,sha256=g2zDApzSKbyc13S14KDjRM5TPQAMCQ05caadoQUNl5g,5044
14
+ vectorsmith_cli/serve_common.py,sha256=VlTeOQPxyhG13FPKjyZSmyBOvyOqQFeZacjuLd3QEqc,9570
15
+ vectorsmith_cli/serve_http.py,sha256=0TLhHSnsnpCs7WMOOuNzmkssy5kpfWQMqVBqrQv1jZc,2225
16
+ vectorsmith_cli/serve_stdio.py,sha256=UoT0_ELbeU1owru6ALFju5D1mdxHRNs-TMTgoJnaXr8,8060
17
+ vectorsmith_cli/stdio_guard.py,sha256=k4HZ3-eH4Q1fNBPQjvZzjz9WQ1XUY9_LjaFaQltI3Ao,1081
18
+ vectorsmith_cli/test_cmd.py,sha256=yyY1Wa4CBZRPJjcVd5ddvZVr8dD_meCro055A8xRJ94,2071
19
+ vectorsmith_cli/validate_cmd.py,sha256=CiI7cuJ7NRgf2yliKx4v5aICRJgjbrTWkATRYw-nRvI,1953
20
+ vectorsmith_cli/http/__init__.py,sha256=K4VECTV0gM_0BqseQl0mnHxN_DBOQ0xZWM48MRaP6E8,34
21
+ vectorsmith_cli/http/app.py,sha256=9aLL2faH8IpLUpkYk7VnR8Qs9aphkwWjJW7F8v6zhq8,4956
22
+ vectorsmith_cli/http/builtin_oauth/__init__.py,sha256=NkeW9Ge51z7U5HNCKa5Ge1hJbtChb_GN2eL_G28gWvM,54
23
+ vectorsmith_cli/http/builtin_oauth/pages.py,sha256=oG-cY1y9jF7rE_Jxzsbg55kX-GGzMzjbZDf0y59Szss,623
24
+ vectorsmith_cli/http/builtin_oauth/server.py,sha256=Erj0elNcHlHUPEFI0rGnaFCEmi0B_6mfzxa6Mi0JBrE,4231
25
+ vectorsmith_cli/http/builtin_oauth/store.py,sha256=OYatIWltGBgC2WUiNVLdEx9KEbYKRBnk7CtdJgPUBWg,6332
26
+ vectorsmith_core/__init__.py,sha256=SxAbEzTiHluRD3uTJ4S4ZvWyztL2AMKp0AiH86t3DDw,546
27
+ vectorsmith_core/api.py,sha256=2yd8Lq98hVL4ifEKw2nT0YV5IYfGCSKf-IfiDYApkAc,6772
28
+ vectorsmith_core/errors.py,sha256=tNRMI5Kh_GSDJwRF546SwPmx4x9NqP1PIKTZUVQe3m0,3223
29
+ vectorsmith_core/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
+ vectorsmith_core/version.py,sha256=OrrNqGg_HsnTK0acv_3MHDco0E48NrSrOobNBd71hHc,115
31
+ vectorsmith_core/adapters/__init__.py,sha256=vZpumSKAd8Ri3D05x-B65LXqYp3SiBtQO3baOUkwOlQ,31
32
+ vectorsmith_core/adapters/base.py,sha256=Ir9LgCWPA9fMRMwoLYnKQUw5QzjhH91ROnKsIrmm9zU,1644
33
+ vectorsmith_core/adapters/capabilities.py,sha256=_hPdZi6ksvN57D1lWafNktEJuIsFyaNG2g_2Bc5Uozs,3026
34
+ vectorsmith_core/adapters/chroma.py,sha256=DTkkctDo_266BDYthCE2bbsNeEC78G0CSxGte2FI5do,4624
35
+ vectorsmith_core/adapters/milvus.py,sha256=thIxCzISHzxyNBpmJ0-k6ngDJt2nJTOpsEa2Bh35SqE,4632
36
+ vectorsmith_core/adapters/pgvector.py,sha256=A3mPERVE6vMFjQvmNAZpn2o4id4MATNPbnlyHZiejSA,7825
37
+ vectorsmith_core/adapters/pinecone.py,sha256=U9Poqi9inpdh87wtUPS_9pPSCy5t4d21KeGMn9RVSts,4098
38
+ vectorsmith_core/adapters/qdrant.py,sha256=FFVIKR3hh9D0uALkVaVwNoBRX3upLUoZwbMdBsZGzGo,10033
39
+ vectorsmith_core/adapters/registry.py,sha256=P65WmpWhHoGxtHDSa4Gyt3Bp_7TLl7ZdifBwkAVhBqg,24
40
+ vectorsmith_core/adapters/weaviate.py,sha256=b-XYudeuDIRhbAabc80n4ODN3Qfb6-RWRMVICpuBa0M,4186
41
+ vectorsmith_core/compilepkg/__init__.py,sha256=bQvhMh273TtK_2cIBAcWWjCptB3YtWIa68yMagXR0is,63
42
+ vectorsmith_core/compilepkg/builtins.py,sha256=RSKp9Jc5MtXxr0Reg8PA0ZRpphcjDR3OomzxDxhqTB8,6083
43
+ vectorsmith_core/compilepkg/compiler.py,sha256=0DrgSg5JKWFFSSCwo4IsSpMwTVkm1bJ8ttOKnDGFDTI,4961
44
+ vectorsmith_core/compilepkg/drafts.py,sha256=dh8ait7s094p-tY-75Oyl_N4bqHpV8fpYgvD3zglDDQ,3976
45
+ vectorsmith_core/compilepkg/validator.py,sha256=c74dv2jiJnT43nFalDGrYGgAmcb4msqSdUxIiJ6nVJI,10409
46
+ vectorsmith_core/embed/__init__.py,sha256=1u-lJ4XYWAOVcS5pGX0MwrONrRiBftdmjYEBU7Fp6GE,27
47
+ vectorsmith_core/embed/models.py,sha256=RIYvRKTbyA0XPiRLT4vuRTLHy-KYDRkhnxF4oAbin8U,189
48
+ vectorsmith_core/embed/provider.py,sha256=JnJlQYpLaPful_Lli69kby22DtTcOrx1lclQUPWj3JQ,1959
49
+ vectorsmith_core/execute/__init__.py,sha256=nx75OyqCrfT47SMucX58DoHldYreak8EqGcw0YWpNaE,50
50
+ vectorsmith_core/execute/engine.py,sha256=gy1J-oWXq5eYoYz8HfTFp4gw3m3eGkxbpBdcI-YO-zE,8495
51
+ vectorsmith_core/execute/pipeline.py,sha256=mjU_v049qRTevB7k749ziG_fztiq_rjvElwXd4NLRJc,4925
52
+ vectorsmith_core/execute/single_step.py,sha256=zB23WBiDtrCJYb3UhGaXBEz8yd4iamV7ToHKP9WKOUQ,5190
53
+ vectorsmith_core/execute/expr/__init__.py,sha256=YqW9tWRm0TfQTHzkjpkCtJ2aGsel11mKj12a0wazkVc,249
54
+ vectorsmith_core/execute/expr/eval_polars.py,sha256=brOq2ZrWctEJiVt7zHwDxo3-ul52QBlJlUPkgW6g7wM,2908
55
+ vectorsmith_core/execute/expr/grammar.lark,sha256=POsY9IcXiHdVu40uc-Z_Wb_bEEAOhs3-1P_-y_babK4,892
56
+ vectorsmith_core/execute/expr/parser.py,sha256=KDpfIC6pn321r1Rr_qOjnVGgBOl8r-ecY6tv2bcWbes,3817
57
+ vectorsmith_core/introspect/__init__.py,sha256=G48XnzpQNJkGTe6z1rHoVd69VklPRU9xKxRbYKJwcIc,62
58
+ vectorsmith_core/introspect/sampling.py,sha256=0NzsIaDs_rbRC96fjyCHV_inevMwZKFJ3mMxihIjO8c,3493
59
+ vectorsmith_core/introspect/schema_export.py,sha256=KN5UaVgxvu-fb-UOrispLsbQVzO4AGY62S-asYU3S7o,1993
60
+ vectorsmith_core/introspect/schema_export_v1.json,sha256=R2jqepE4__T6WYPnjqOwKYdOSrSKCMCaS-hiF71bmqo,318
61
+ vectorsmith_core/introspect/types.py,sha256=KC3QXowqmvM1qC6dGsZ_Ms6qMfMLKWeh2e2ty9sxxCg,34
62
+ vectorsmith_core/ir/__init__.py,sha256=3Y2djgmDczH2Br6wDaRTLw_oT2j1ME6Ufrv0orQTVmI,42
63
+ vectorsmith_core/ir/filter.py,sha256=26RTgP9JWY1DIHDa16Qmmi7SqRQljELoSaIrtf6JQjA,3006
64
+ vectorsmith_core/tds/__init__.py,sha256=GOrUHuCCqT4weWSHxu8NrTreO3IA7Xr7AAUCBD-QRdg,52
65
+ vectorsmith_core/tds/loader.py,sha256=QmaxxDr1ZCBo2EOO3asigMwABcMiczhZ3eF8z76E9mw,7012
66
+ vectorsmith_core/tds/models.py,sha256=DMC7_3F3ZX_Xj_ixq85DgQx-qXuumkHB0dA893EVW6Y,7040
67
+ vectorsmith_core/tds/schema.py,sha256=TOgQwY4HKf5PwfuWbjzUNfhu8xXFRGDofkF3qR4Tkr4,494
68
+ vectorsmith_core/tds/schema_v1.json,sha256=gcJhKIgnpoFSW6Z5-JJM4Icw28rWDNytfCx-b6NJWIE,27368
69
+ vectorsmith-0.1.0.dist-info/METADATA,sha256=pa_nSXV18CW26yQp_36f3ZOXRNqi43f0ue-uJATiMLA,2814
70
+ vectorsmith-0.1.0.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
71
+ vectorsmith-0.1.0.dist-info/entry_points.txt,sha256=_XIsAsK3plnkfKB8dsnZueUEKjPEEzNyRmh2Mt2riGI,57
72
+ vectorsmith-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.32.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ vectorsmith = vectorsmith_cli.main:app
@@ -0,0 +1 @@
1
+ """VectorSmith CLI."""
@@ -0,0 +1,71 @@
1
+ """drafts list/reject and approve."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import sys
6
+ from datetime import UTC, datetime
7
+ from pathlib import Path
8
+
9
+ import yaml
10
+
11
+ from vectorsmith_core.api import draft_tool, load_project, promote_draft
12
+
13
+
14
+ def _drafts_path() -> Path:
15
+ return Path("tools.drafts.yaml")
16
+
17
+
18
+ def run_drafts(action: str, name: str | None) -> None:
19
+ path = _drafts_path()
20
+ data = {"drafts": []}
21
+ if path.exists():
22
+ loaded = yaml.safe_load(path.read_text()) or {}
23
+ data["drafts"] = loaded.get("drafts") or []
24
+ if action == "list":
25
+ for d in data["drafts"]:
26
+ tool = d.get("tool") or {}
27
+ print(f"{d.get('status', 'pending'):10} {tool.get('name', '?')}", file=sys.stderr)
28
+ return
29
+ if action == "reject" and name:
30
+ for d in data["drafts"]:
31
+ if (d.get("tool") or {}).get("name") == name:
32
+ d["status"] = "rejected"
33
+ path.write_text(yaml.safe_dump(data, sort_keys=False))
34
+ print(f"rejected {name}", file=sys.stderr)
35
+ return
36
+ print("usage: drafts list | reject NAME", file=sys.stderr)
37
+ raise SystemExit(2)
38
+
39
+
40
+ def run_approve(name: str, tools_file: Path) -> None:
41
+ path = _drafts_path()
42
+ if not path.exists():
43
+ print("no tools.drafts.yaml", file=sys.stderr)
44
+ raise SystemExit(2)
45
+ data = yaml.safe_load(path.read_text()) or {}
46
+ drafts = data.get("drafts") or []
47
+ match = next((d for d in drafts if (d.get("tool") or {}).get("name") == name), None)
48
+ if match is None:
49
+ print(f"draft {name} not found", file=sys.stderr)
50
+ raise SystemExit(2)
51
+ project = load_project(tools_file)
52
+ from vectorsmith_core.api import ToolDraft
53
+ from vectorsmith_core.tds.models import ToolSpec
54
+
55
+ spec = ToolSpec.model_validate(match["tool"])
56
+ draft = ToolDraft(spec=spec, validator_issues=[], provenance=match)
57
+ promoted = promote_draft(draft, project)
58
+ raw = yaml.safe_load(tools_file.read_text())
59
+ raw.setdefault("tools", []).append(promoted.model_dump(exclude_none=True))
60
+ header = (
61
+ f"# approved {datetime.now(UTC).isoformat()} "
62
+ f"hash={match.get('hash', '')}\n"
63
+ )
64
+ tools_file.write_text(header + yaml.safe_dump(raw, sort_keys=False))
65
+ match["status"] = "approved"
66
+ path.write_text(yaml.safe_dump(data, sort_keys=False))
67
+ print(f"Approved {name}. Toggle the connector in Claude to load it.", file=sys.stderr)
68
+
69
+
70
+ # draft_tool imported for define_tool serve path
71
+ _ = draft_tool
@@ -0,0 +1 @@
1
+ """HTTP app and builtin OAuth."""