prism-tool 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.
- prism/__init__.py +0 -0
- prism/cli.py +62 -0
- prism/linter.py +66 -0
- prism_tool-0.1.0.dist-info/METADATA +67 -0
- prism_tool-0.1.0.dist-info/RECORD +8 -0
- prism_tool-0.1.0.dist-info/WHEEL +5 -0
- prism_tool-0.1.0.dist-info/entry_points.txt +2 -0
- prism_tool-0.1.0.dist-info/top_level.txt +1 -0
prism/__init__.py
ADDED
|
File without changes
|
prism/cli.py
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
from rich.console import Console
|
|
3
|
+
from rich.table import Table
|
|
4
|
+
|
|
5
|
+
app = typer.Typer()
|
|
6
|
+
console = Console()
|
|
7
|
+
|
|
8
|
+
@app.command()
|
|
9
|
+
def lint(provider: str = "openai-strict"):
|
|
10
|
+
"""Lint a tool function for provider compatibility."""
|
|
11
|
+
from prism.linter import lint_tool
|
|
12
|
+
|
|
13
|
+
console.print("\n[bold cyan]Paste your function. Press Enter twice when done.[/bold cyan]\n")
|
|
14
|
+
|
|
15
|
+
lines = []
|
|
16
|
+
while True:
|
|
17
|
+
line = input()
|
|
18
|
+
if line == "" and lines and lines[-1] == "":
|
|
19
|
+
break
|
|
20
|
+
lines.append(line)
|
|
21
|
+
|
|
22
|
+
code = "\n".join(lines)
|
|
23
|
+
namespace = {}
|
|
24
|
+
|
|
25
|
+
try:
|
|
26
|
+
exec(code, namespace)
|
|
27
|
+
except Exception as e:
|
|
28
|
+
console.print(f"[red]Error: {e}[/red]")
|
|
29
|
+
raise typer.Exit()
|
|
30
|
+
|
|
31
|
+
func = None
|
|
32
|
+
for name, obj in namespace.items():
|
|
33
|
+
if callable(obj) and not name.startswith("_"):
|
|
34
|
+
func = obj
|
|
35
|
+
break
|
|
36
|
+
|
|
37
|
+
if not func:
|
|
38
|
+
console.print("[red]No function found.[/red]")
|
|
39
|
+
raise typer.Exit()
|
|
40
|
+
|
|
41
|
+
warnings = lint_tool(func, providers=[provider])
|
|
42
|
+
|
|
43
|
+
if not warnings:
|
|
44
|
+
console.print(f"\n[green]✅ No issues found.[/green]\n")
|
|
45
|
+
return
|
|
46
|
+
|
|
47
|
+
table = Table(title=f"Prism — {provider}", show_lines=True)
|
|
48
|
+
table.add_column("Level", style="red", width=8)
|
|
49
|
+
table.add_column("Param", style="yellow", width=15)
|
|
50
|
+
table.add_column("Issue", width=40)
|
|
51
|
+
table.add_column("Fix", style="green", width=30)
|
|
52
|
+
|
|
53
|
+
for w in warnings:
|
|
54
|
+
table.add_row(w["level"], w["param"], w["issue"], w["fix"])
|
|
55
|
+
|
|
56
|
+
console.print(table)
|
|
57
|
+
|
|
58
|
+
def main():
|
|
59
|
+
app()
|
|
60
|
+
|
|
61
|
+
if __name__ == "__main__":
|
|
62
|
+
main()
|
prism/linter.py
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import inspect
|
|
2
|
+
from typing import get_type_hints, Union, Any
|
|
3
|
+
|
|
4
|
+
def lint_tool(func, providers=["openai-strict"]):
|
|
5
|
+
warnings = []
|
|
6
|
+
sig = inspect.signature(func)
|
|
7
|
+
|
|
8
|
+
try:
|
|
9
|
+
hints = get_type_hints(func)
|
|
10
|
+
except Exception:
|
|
11
|
+
hints = {}
|
|
12
|
+
|
|
13
|
+
for param_name, param in sig.parameters.items():
|
|
14
|
+
if param_name in ("return", "self", "cls"):
|
|
15
|
+
continue
|
|
16
|
+
|
|
17
|
+
has_default = param.default != inspect.Parameter.empty
|
|
18
|
+
annotation = hints.get(param_name)
|
|
19
|
+
|
|
20
|
+
if "openai-strict" in providers and has_default and param.default is not None:
|
|
21
|
+
warnings.append({
|
|
22
|
+
"provider": "openai-strict",
|
|
23
|
+
"level": "ERROR",
|
|
24
|
+
"param": param_name,
|
|
25
|
+
"issue": f"Has default '{param.default}' — OpenAI strict will reject this.",
|
|
26
|
+
"fix": "Remove the default value."
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
if param_name not in hints:
|
|
30
|
+
warnings.append({
|
|
31
|
+
"provider": "all",
|
|
32
|
+
"level": "WARNING",
|
|
33
|
+
"param": param_name,
|
|
34
|
+
"issue": "No type annotation. Providers will reject this.",
|
|
35
|
+
"fix": f"Add a type like: {param_name}: str"
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
if annotation is Any:
|
|
39
|
+
warnings.append({
|
|
40
|
+
"provider": "openai-strict",
|
|
41
|
+
"level": "ERROR",
|
|
42
|
+
"param": param_name,
|
|
43
|
+
"issue": "'Any' type is rejected by OpenAI strict mode.",
|
|
44
|
+
"fix": "Replace with a concrete type like str or dict."
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
if annotation and hasattr(annotation, "__origin__"):
|
|
48
|
+
if annotation.__origin__ is Union:
|
|
49
|
+
warnings.append({
|
|
50
|
+
"provider": "openai-strict",
|
|
51
|
+
"level": "ERROR",
|
|
52
|
+
"param": param_name,
|
|
53
|
+
"issue": "Union types fail in OpenAI strict mode.",
|
|
54
|
+
"fix": "Use a single concrete type."
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
if not func.__doc__:
|
|
58
|
+
warnings.append({
|
|
59
|
+
"provider": "all",
|
|
60
|
+
"level": "WARNING",
|
|
61
|
+
"param": "function",
|
|
62
|
+
"issue": "No docstring. AI uses this as the tool description.",
|
|
63
|
+
"fix": 'Add a docstring: """What this tool does."""'
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
return warnings
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: prism-tool
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Catch AI agent tool schema failures before they reach the provider
|
|
5
|
+
Home-page: https://github.com/sanim-science/prism-sdk
|
|
6
|
+
Author: Sanim
|
|
7
|
+
Requires-Python: >=3.8
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
Requires-Dist: typer
|
|
10
|
+
Requires-Dist: rich
|
|
11
|
+
Requires-Dist: pydantic
|
|
12
|
+
Requires-Dist: jsonschema
|
|
13
|
+
Dynamic: author
|
|
14
|
+
Dynamic: description
|
|
15
|
+
Dynamic: description-content-type
|
|
16
|
+
Dynamic: home-page
|
|
17
|
+
Dynamic: requires-dist
|
|
18
|
+
Dynamic: requires-python
|
|
19
|
+
Dynamic: summary
|
|
20
|
+
|
|
21
|
+
# Prism
|
|
22
|
+
|
|
23
|
+
Catch AI agent tool schema failures before they reach the provider.
|
|
24
|
+
|
|
25
|
+
## The Problem
|
|
26
|
+
|
|
27
|
+
You write a tool for your AI agent. It works locally.
|
|
28
|
+
Then it fails with a cryptic 400 error in production.
|
|
29
|
+
No explanation. No hint. Just failure.
|
|
30
|
+
|
|
31
|
+
Prism catches these before they ever reach OpenAI or Anthropic.
|
|
32
|
+
|
|
33
|
+
## Install
|
|
34
|
+
|
|
35
|
+
pip install prism-sdk
|
|
36
|
+
|
|
37
|
+
## Quick Start
|
|
38
|
+
|
|
39
|
+
from prism.linter import lint_tool
|
|
40
|
+
|
|
41
|
+
def search_products(query: str, limit: int = 10, category=None):
|
|
42
|
+
pass
|
|
43
|
+
|
|
44
|
+
issues = lint_tool(search_products)
|
|
45
|
+
for issue in issues:
|
|
46
|
+
print(f"[{issue['level']}] {issue['param']}: {issue['issue']}")
|
|
47
|
+
|
|
48
|
+
## Output
|
|
49
|
+
|
|
50
|
+
[ERROR] limit: Has default '10' — OpenAI strict will reject this.
|
|
51
|
+
[WARNING] category: No type annotation. Providers will reject this.
|
|
52
|
+
[WARNING] function: No docstring. AI uses this as the tool description.
|
|
53
|
+
|
|
54
|
+
## What It Catches
|
|
55
|
+
|
|
56
|
+
| Issue | Providers Affected |
|
|
57
|
+
|-------|--------------------|
|
|
58
|
+
| Default values not in required[] | OpenAI strict |
|
|
59
|
+
| Union types | OpenAI strict |
|
|
60
|
+
| Missing type annotations | All |
|
|
61
|
+
| Any type | OpenAI strict |
|
|
62
|
+
| Missing docstring | All |
|
|
63
|
+
|
|
64
|
+
## Status
|
|
65
|
+
|
|
66
|
+
Early development. Built to solve a real problem.
|
|
67
|
+
Issues and feedback welcome.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
prism/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
prism/cli.py,sha256=asMbFWYbM0X7bY0XbtYh7mwEHxaJQV5y8LUj5gw2OVg,1651
|
|
3
|
+
prism/linter.py,sha256=kg0HdujyVPJjeTnlQ5XCg08LNGJyXVbl1reBeNbzrV0,2355
|
|
4
|
+
prism_tool-0.1.0.dist-info/METADATA,sha256=U13xs0sGf-JO9H2Byp2qaKsqNAyFbGZuetvU0tyYCK4,1745
|
|
5
|
+
prism_tool-0.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
6
|
+
prism_tool-0.1.0.dist-info/entry_points.txt,sha256=Kn-Imyf8zRkFPeWfcmS5w1SaQPSzv-hmDi1bBJpXgDY,41
|
|
7
|
+
prism_tool-0.1.0.dist-info/top_level.txt,sha256=ptR0npZTwkVELlV5R3NcfhrvslYW8AvRiFoKmX7tZp4,6
|
|
8
|
+
prism_tool-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
prism
|