wendell 0.1.0__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.
wendell-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,111 @@
1
+ Metadata-Version: 2.4
2
+ Name: wendell
3
+ Version: 0.1.0
4
+ Summary: Wendell CLI for agent world simulations, Park registration, and run uploads
5
+ License: Proprietary
6
+ Project-URL: Homepage, https://www.wendellai.com
7
+ Project-URL: Repository, https://github.com/croppia/wendellai
8
+ Requires-Python: >=3.10
9
+ Description-Content-Type: text/markdown
10
+ Provides-Extra: dev
11
+ Requires-Dist: pytest>=8; extra == "dev"
12
+
13
+ # Wendell CLI
14
+
15
+ Wendell is a Python CLI for evaluating agents against Wendell-managed worlds and scenario packs.
16
+
17
+ The first version is advisory by default: it reports scores, captures traces, and returns a successful process exit unless the project explicitly enables blocking gates.
18
+
19
+ ## Intended split
20
+
21
+ - Wendell system: creates worlds, versions scenario packs, owns rubrics, stores traces, and reports regressions.
22
+ - Wendell CI runner: runs in a repo or CI job, fetches or reads a scenario pack, invokes the customer's agent adapter, captures traces, evaluates gates, uploads results, and prints a concise summary.
23
+
24
+ ## Install
25
+
26
+ ```bash
27
+ uv tool install wendell
28
+ ```
29
+
30
+ Alternative installers:
31
+
32
+ ```bash
33
+ pipx install wendell
34
+ python3 -m pip install --user wendell
35
+ ```
36
+
37
+ The package installs the `wendell` command. It also installs the temporary `local-wendell` alias for existing local dogfood scripts.
38
+
39
+ ## Local development
40
+
41
+ ```bash
42
+ cd wendell-ci
43
+ python -m venv .venv
44
+ source .venv/bin/activate
45
+ pip install -e ".[dev]"
46
+ pytest
47
+ wendell --help
48
+ ```
49
+
50
+ ## Login
51
+
52
+ For local development, store an InkPass API key once:
53
+
54
+ ```bash
55
+ wendell login --api-url https://api.wendellai.com --api-key-stdin --validate
56
+ wendell auth status
57
+ ```
58
+
59
+ Credentials are stored at `~/.config/wendell/credentials.json` by default, or `$WENDELL_CONFIG_HOME/credentials.json` when set. The directory is created with `0700` permissions and the credentials file with `0600` permissions.
60
+
61
+ CI should continue to use `WENDELL_INKPASS_API_KEY`; environment variables take precedence over stored credentials.
62
+
63
+ ## Minimal config
64
+
65
+ ```toml
66
+ project = "support-agent"
67
+ mode = "advisory"
68
+ api_url = "https://api.wendell.example"
69
+ api_key_env = "WENDELL_INKPASS_API_KEY"
70
+ world = "world_support_ops_v1"
71
+ world_version = "2026-05-08.1"
72
+ scenario_pack = "smoke"
73
+ scenario_pack_version = "1.0.0"
74
+ agent_command = "python examples/simple_cli_agent.py"
75
+ upload_traces = true
76
+
77
+ [gates]
78
+ suite_min_score = 0.80
79
+ scenario_min_score = 0.75
80
+ critical_failures_allowed = 0
81
+ ```
82
+
83
+ The intended production flow is:
84
+
85
+ 1. `local-wendell` runs on the developer machine or CI worker.
86
+ 2. It fetches the pinned world, scenario pack, rubrics, and scoring contract from Wendell.
87
+ 3. It invokes the agent locally through an adapter such as `agent_command`.
88
+ 4. It captures local traces, redacts them, and uploads traces/results back to Wendell.
89
+ 5. Advisory mode exits `0`; blocking mode exits nonzero only when explicitly enabled.
90
+
91
+ Remote uploads authenticate with an InkPass API key sent as `X-API-Key`. The key needs at least `wendell:worlds:read`, `wendell:runs:create`, and `wendell:runs:read`.
92
+
93
+ ## Local worldsim dogfood config
94
+
95
+ While Wendell Cloud APIs are still taking shape, the runner can call the existing local `worldsim.services` layer directly:
96
+
97
+ ```toml
98
+ project = "workspace-access-agent"
99
+ mode = "advisory"
100
+ world = "workspace_access_support"
101
+ scenario_pack = "smoke"
102
+ worldsim_input = "../configs/customer_inputs/workspace_access_support_input.json"
103
+ agent = "careful"
104
+
105
+ [gates]
106
+ suite_min_score = 0.80
107
+ scenario_min_score = 0.75
108
+ critical_failures_allowed = 0
109
+ ```
110
+
111
+ Supported local built-in agents are `careful` and `risky`.
@@ -0,0 +1,99 @@
1
+ # Wendell CLI
2
+
3
+ Wendell is a Python CLI for evaluating agents against Wendell-managed worlds and scenario packs.
4
+
5
+ The first version is advisory by default: it reports scores, captures traces, and returns a successful process exit unless the project explicitly enables blocking gates.
6
+
7
+ ## Intended split
8
+
9
+ - Wendell system: creates worlds, versions scenario packs, owns rubrics, stores traces, and reports regressions.
10
+ - Wendell CI runner: runs in a repo or CI job, fetches or reads a scenario pack, invokes the customer's agent adapter, captures traces, evaluates gates, uploads results, and prints a concise summary.
11
+
12
+ ## Install
13
+
14
+ ```bash
15
+ uv tool install wendell
16
+ ```
17
+
18
+ Alternative installers:
19
+
20
+ ```bash
21
+ pipx install wendell
22
+ python3 -m pip install --user wendell
23
+ ```
24
+
25
+ The package installs the `wendell` command. It also installs the temporary `local-wendell` alias for existing local dogfood scripts.
26
+
27
+ ## Local development
28
+
29
+ ```bash
30
+ cd wendell-ci
31
+ python -m venv .venv
32
+ source .venv/bin/activate
33
+ pip install -e ".[dev]"
34
+ pytest
35
+ wendell --help
36
+ ```
37
+
38
+ ## Login
39
+
40
+ For local development, store an InkPass API key once:
41
+
42
+ ```bash
43
+ wendell login --api-url https://api.wendellai.com --api-key-stdin --validate
44
+ wendell auth status
45
+ ```
46
+
47
+ Credentials are stored at `~/.config/wendell/credentials.json` by default, or `$WENDELL_CONFIG_HOME/credentials.json` when set. The directory is created with `0700` permissions and the credentials file with `0600` permissions.
48
+
49
+ CI should continue to use `WENDELL_INKPASS_API_KEY`; environment variables take precedence over stored credentials.
50
+
51
+ ## Minimal config
52
+
53
+ ```toml
54
+ project = "support-agent"
55
+ mode = "advisory"
56
+ api_url = "https://api.wendell.example"
57
+ api_key_env = "WENDELL_INKPASS_API_KEY"
58
+ world = "world_support_ops_v1"
59
+ world_version = "2026-05-08.1"
60
+ scenario_pack = "smoke"
61
+ scenario_pack_version = "1.0.0"
62
+ agent_command = "python examples/simple_cli_agent.py"
63
+ upload_traces = true
64
+
65
+ [gates]
66
+ suite_min_score = 0.80
67
+ scenario_min_score = 0.75
68
+ critical_failures_allowed = 0
69
+ ```
70
+
71
+ The intended production flow is:
72
+
73
+ 1. `local-wendell` runs on the developer machine or CI worker.
74
+ 2. It fetches the pinned world, scenario pack, rubrics, and scoring contract from Wendell.
75
+ 3. It invokes the agent locally through an adapter such as `agent_command`.
76
+ 4. It captures local traces, redacts them, and uploads traces/results back to Wendell.
77
+ 5. Advisory mode exits `0`; blocking mode exits nonzero only when explicitly enabled.
78
+
79
+ Remote uploads authenticate with an InkPass API key sent as `X-API-Key`. The key needs at least `wendell:worlds:read`, `wendell:runs:create`, and `wendell:runs:read`.
80
+
81
+ ## Local worldsim dogfood config
82
+
83
+ While Wendell Cloud APIs are still taking shape, the runner can call the existing local `worldsim.services` layer directly:
84
+
85
+ ```toml
86
+ project = "workspace-access-agent"
87
+ mode = "advisory"
88
+ world = "workspace_access_support"
89
+ scenario_pack = "smoke"
90
+ worldsim_input = "../configs/customer_inputs/workspace_access_support_input.json"
91
+ agent = "careful"
92
+
93
+ [gates]
94
+ suite_min_score = 0.80
95
+ scenario_min_score = 0.75
96
+ critical_failures_allowed = 0
97
+ ```
98
+
99
+ Supported local built-in agents are `careful` and `risky`.
@@ -0,0 +1,26 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "wendell"
7
+ version = "0.1.0"
8
+ description = "Wendell CLI for agent world simulations, Park registration, and run uploads"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ dependencies = []
12
+ license = { text = "Proprietary" }
13
+
14
+ [project.urls]
15
+ Homepage = "https://www.wendellai.com"
16
+ Repository = "https://github.com/croppia/wendellai"
17
+
18
+ [project.optional-dependencies]
19
+ dev = ["pytest>=8"]
20
+
21
+ [project.scripts]
22
+ wendell = "wendell_ci.cli:main"
23
+ local-wendell = "wendell_ci.cli:main"
24
+
25
+ [tool.setuptools.packages.find]
26
+ where = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,111 @@
1
+ Metadata-Version: 2.4
2
+ Name: wendell
3
+ Version: 0.1.0
4
+ Summary: Wendell CLI for agent world simulations, Park registration, and run uploads
5
+ License: Proprietary
6
+ Project-URL: Homepage, https://www.wendellai.com
7
+ Project-URL: Repository, https://github.com/croppia/wendellai
8
+ Requires-Python: >=3.10
9
+ Description-Content-Type: text/markdown
10
+ Provides-Extra: dev
11
+ Requires-Dist: pytest>=8; extra == "dev"
12
+
13
+ # Wendell CLI
14
+
15
+ Wendell is a Python CLI for evaluating agents against Wendell-managed worlds and scenario packs.
16
+
17
+ The first version is advisory by default: it reports scores, captures traces, and returns a successful process exit unless the project explicitly enables blocking gates.
18
+
19
+ ## Intended split
20
+
21
+ - Wendell system: creates worlds, versions scenario packs, owns rubrics, stores traces, and reports regressions.
22
+ - Wendell CI runner: runs in a repo or CI job, fetches or reads a scenario pack, invokes the customer's agent adapter, captures traces, evaluates gates, uploads results, and prints a concise summary.
23
+
24
+ ## Install
25
+
26
+ ```bash
27
+ uv tool install wendell
28
+ ```
29
+
30
+ Alternative installers:
31
+
32
+ ```bash
33
+ pipx install wendell
34
+ python3 -m pip install --user wendell
35
+ ```
36
+
37
+ The package installs the `wendell` command. It also installs the temporary `local-wendell` alias for existing local dogfood scripts.
38
+
39
+ ## Local development
40
+
41
+ ```bash
42
+ cd wendell-ci
43
+ python -m venv .venv
44
+ source .venv/bin/activate
45
+ pip install -e ".[dev]"
46
+ pytest
47
+ wendell --help
48
+ ```
49
+
50
+ ## Login
51
+
52
+ For local development, store an InkPass API key once:
53
+
54
+ ```bash
55
+ wendell login --api-url https://api.wendellai.com --api-key-stdin --validate
56
+ wendell auth status
57
+ ```
58
+
59
+ Credentials are stored at `~/.config/wendell/credentials.json` by default, or `$WENDELL_CONFIG_HOME/credentials.json` when set. The directory is created with `0700` permissions and the credentials file with `0600` permissions.
60
+
61
+ CI should continue to use `WENDELL_INKPASS_API_KEY`; environment variables take precedence over stored credentials.
62
+
63
+ ## Minimal config
64
+
65
+ ```toml
66
+ project = "support-agent"
67
+ mode = "advisory"
68
+ api_url = "https://api.wendell.example"
69
+ api_key_env = "WENDELL_INKPASS_API_KEY"
70
+ world = "world_support_ops_v1"
71
+ world_version = "2026-05-08.1"
72
+ scenario_pack = "smoke"
73
+ scenario_pack_version = "1.0.0"
74
+ agent_command = "python examples/simple_cli_agent.py"
75
+ upload_traces = true
76
+
77
+ [gates]
78
+ suite_min_score = 0.80
79
+ scenario_min_score = 0.75
80
+ critical_failures_allowed = 0
81
+ ```
82
+
83
+ The intended production flow is:
84
+
85
+ 1. `local-wendell` runs on the developer machine or CI worker.
86
+ 2. It fetches the pinned world, scenario pack, rubrics, and scoring contract from Wendell.
87
+ 3. It invokes the agent locally through an adapter such as `agent_command`.
88
+ 4. It captures local traces, redacts them, and uploads traces/results back to Wendell.
89
+ 5. Advisory mode exits `0`; blocking mode exits nonzero only when explicitly enabled.
90
+
91
+ Remote uploads authenticate with an InkPass API key sent as `X-API-Key`. The key needs at least `wendell:worlds:read`, `wendell:runs:create`, and `wendell:runs:read`.
92
+
93
+ ## Local worldsim dogfood config
94
+
95
+ While Wendell Cloud APIs are still taking shape, the runner can call the existing local `worldsim.services` layer directly:
96
+
97
+ ```toml
98
+ project = "workspace-access-agent"
99
+ mode = "advisory"
100
+ world = "workspace_access_support"
101
+ scenario_pack = "smoke"
102
+ worldsim_input = "../configs/customer_inputs/workspace_access_support_input.json"
103
+ agent = "careful"
104
+
105
+ [gates]
106
+ suite_min_score = 0.80
107
+ scenario_min_score = 0.75
108
+ critical_failures_allowed = 0
109
+ ```
110
+
111
+ Supported local built-in agents are `careful` and `risky`.
@@ -0,0 +1,24 @@
1
+ README.md
2
+ pyproject.toml
3
+ src/wendell.egg-info/PKG-INFO
4
+ src/wendell.egg-info/SOURCES.txt
5
+ src/wendell.egg-info/dependency_links.txt
6
+ src/wendell.egg-info/entry_points.txt
7
+ src/wendell.egg-info/requires.txt
8
+ src/wendell.egg-info/top_level.txt
9
+ src/wendell_ci/__init__.py
10
+ src/wendell_ci/auth.py
11
+ src/wendell_ci/cli.py
12
+ src/wendell_ci/config.py
13
+ src/wendell_ci/gates.py
14
+ src/wendell_ci/models.py
15
+ src/wendell_ci/remote_client.py
16
+ src/wendell_ci/trace.py
17
+ src/wendell_ci/worldsim_client.py
18
+ tests/test_auth.py
19
+ tests/test_cli.py
20
+ tests/test_command_agent_integration.py
21
+ tests/test_config.py
22
+ tests/test_gates.py
23
+ tests/test_remote_client.py
24
+ tests/test_worldsim_integration.py
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ local-wendell = wendell_ci.cli:main
3
+ wendell = wendell_ci.cli:main
@@ -0,0 +1,3 @@
1
+
2
+ [dev]
3
+ pytest>=8
@@ -0,0 +1 @@
1
+ wendell_ci
@@ -0,0 +1,14 @@
1
+ """Wendell CI runner package."""
2
+
3
+ from .config import GateConfig, RunnerConfig
4
+ from .gates import GateDecision, evaluate_gates
5
+ from .models import ScenarioResult, SuiteResult
6
+
7
+ __all__ = [
8
+ "GateConfig",
9
+ "GateDecision",
10
+ "RunnerConfig",
11
+ "ScenarioResult",
12
+ "SuiteResult",
13
+ "evaluate_gates",
14
+ ]
@@ -0,0 +1,91 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ import json
5
+ import os
6
+ from pathlib import Path
7
+ from typing import Any
8
+
9
+
10
+ CONFIG_HOME_ENV = "WENDELL_CONFIG_HOME"
11
+ DEFAULT_PROFILE = "default"
12
+
13
+
14
+ @dataclass(frozen=True)
15
+ class StoredCredentials:
16
+ api_key: str
17
+ profile: str = DEFAULT_PROFILE
18
+ api_url: str | None = None
19
+
20
+
21
+ def config_dir() -> Path:
22
+ configured = os.environ.get(CONFIG_HOME_ENV)
23
+ if configured:
24
+ return Path(configured).expanduser()
25
+ xdg_home = os.environ.get("XDG_CONFIG_HOME")
26
+ if xdg_home:
27
+ return Path(xdg_home).expanduser() / "wendell"
28
+ return Path.home() / ".config" / "wendell"
29
+
30
+
31
+ def credentials_path() -> Path:
32
+ return config_dir() / "credentials.json"
33
+
34
+
35
+ def store_credentials(credentials: StoredCredentials) -> Path:
36
+ directory = config_dir()
37
+ directory.mkdir(parents=True, exist_ok=True)
38
+ directory.chmod(0o700)
39
+ path = credentials_path()
40
+ payload: dict[str, Any] = {
41
+ "version": 1,
42
+ "profiles": {
43
+ credentials.profile: {
44
+ "api_key": credentials.api_key,
45
+ "api_url": credentials.api_url,
46
+ }
47
+ },
48
+ "current_profile": credentials.profile,
49
+ }
50
+ path.write_text(json.dumps(payload, indent=2, sort_keys=True), encoding="utf-8")
51
+ path.chmod(0o600)
52
+ return path
53
+
54
+
55
+ def load_credentials(profile: str | None = None) -> StoredCredentials | None:
56
+ path = credentials_path()
57
+ if not path.exists():
58
+ return None
59
+ data = json.loads(path.read_text(encoding="utf-8"))
60
+ selected = profile or str(data.get("current_profile") or DEFAULT_PROFILE)
61
+ profiles = data.get("profiles")
62
+ if not isinstance(profiles, dict):
63
+ return None
64
+ profile_data = profiles.get(selected)
65
+ if not isinstance(profile_data, dict):
66
+ return None
67
+ api_key = profile_data.get("api_key")
68
+ if not isinstance(api_key, str) or not api_key:
69
+ return None
70
+ api_url = profile_data.get("api_url")
71
+ return StoredCredentials(
72
+ api_key=api_key,
73
+ profile=selected,
74
+ api_url=api_url if isinstance(api_url, str) and api_url else None,
75
+ )
76
+
77
+
78
+ def delete_credentials() -> bool:
79
+ path = credentials_path()
80
+ if not path.exists():
81
+ return False
82
+ path.unlink()
83
+ return True
84
+
85
+
86
+ def resolve_api_key(api_key_env: str) -> str | None:
87
+ env_value = os.environ.get(api_key_env)
88
+ if env_value:
89
+ return env_value
90
+ credentials = load_credentials()
91
+ return None if credentials is None else credentials.api_key