Run Actspan through a LiteLLM gateway
Demonstrate an allowed agent, a gateway permission denial, and an Actspan policy block before model execution. Inspect the saved outcomes, change the local policy, and restore it to let the agent run again.
LiteLLM runs as a real service with PostgreSQL-backed virtual keys. Its model responses are fixed fixtures: no OpenAI key or paid model request is needed. This is a compatibility demonstration, not a gateway policy connector.
For customer service, research and summarization, and planning with actual model responses, follow the separate live workflow demos.
Before you begin
Use the separately supplied gateway fixture. Complete its matching-file and service prerequisites below before running the requests.
Problem and flow
An engineering team already has an OpenAI-compatible agent, but model access must pass through LiteLLM's virtual keys. The team needs to distinguish a request stopped by local Actspan admission from one sent to the gateway and rejected there, while retaining the attempted configuration and execution result.
What this proves
The supplied checker pairs an allowed fixed-response workflow with a typed gateway model-access denial and the CLI's saved permission failure. A separate manual policy edit demonstrates a local block before dispatch; restoration demonstrates the allowed path again. The reports identify the local configuration revision and individual outcomes. They do not prove live model quality, remote configuration identity, shared budgets or signed gateway audit delivery. See the qualification card below for the method and current scope.
Qualification and availability
| Item | Scope |
|---|---|
| Availability | Separately supplied design-partner gateway package; absent from public2. |
| Method | Source-checked instructions; no current exact-artifact container/live acceptance record is published on this page. |
| Runtime | Recipe targets CLI 0.2.0; gateway image/config/example hashes must come from the matching handoff. |
| Current proof | Use the provider matrix for recorded trials. Native direct-provider results do not qualify this gateway route. |
| Acceptance | Inspect the named tool, handoff/checkpoint and saved records below; stop on missing prerequisites or unexpected status. |
Start here
This optional demo needs a separate complete gateway-demo handoff. Ask your
Actspan contact for this design-partner handoff; its scripts and Compose files
are not part of the public native examples archive or the free CLI download.
The source repository stays private and no clone command is required.
Once supplied, you need the Actspan 0.2.0 CLI on your PATH,
the example files, Python 3, and a running Docker installation with Docker
Compose. The helper uses Python's standard library and calls the installed CLI;
it does not require Actspan to be installed in that Python environment.
The first startup downloads the container images.
Follow the numbered steps in one terminal. Copy only the commands, without the terminal prompt or example output. Enter the supplied demo directory:
cd /path/to/actspan-gateway-demo/examples_latest/gateways/litellm
command -v actspan
If actspan is not found, activate the environment containing your existing CLI
or follow the installation guide before continuing.
1. Start the gateway and validate
python3 demo.py up
actspan validate workspace.yaml --strict-env
Expected: LiteLLM is ready at http://127.0.0.1:4008 and validation reports OK.
The helper starts the demo's LiteLLM and PostgreSQL services, creates disposable
credentials, and prepares local environment settings used by Actspan. .env
supplies the gateway endpoint and restricted key; .actspan.env disables portal
reporting and response caching. Both files have private permissions. Run the
commands in this directory so Actspan loads that configuration.
Use a clean copy of the example if setup finds an existing environment file.
The helper preserves existing files and refuses to overwrite generated files
that you have edited. Shell variables take precedence over environment files
for manual commands; use a clean shell if you previously exported different
gateway, portal, or cache settings. demo.py check explicitly sets the demo's
endpoint, restricted key, local reporting, and disabled caching for its CLI
subprocesses.
Validation checks configuration and required environment values. It does not prove that a gateway credential is authorized; the following requests exercise that boundary.
The gateway advertises two models, gpt-4.1-mini and gpt-4.1. Both are permitted
by the example's Actspan policy. The demo virtual key permits only
gpt-4.1-mini, making the gateway responsible for rejecting the second model.
The names identify mock routes; this example does not measure either model.
Run the commands yourself
2. Run and inspect the allowed agent
actspan run workspace.yaml summarize_agent \
--input-text 'Topic: Example Robotics' \
--admission=block --format text
actspan inspect summarize_agent
Expected: Status: succeeded, the Example Robotics summary, and saved token and
cost metrics. The supplied fixture has shown 123 tokens and $0.000960; these
are synthetic usage and a cost calculated from example prices, not billed model
usage. For the same run ID, runs and inspect should show the same cost.
3. Demonstrate the gateway restriction
Try the model that the virtual key cannot access:
actspan run workspace.yaml restricted_agent \
--input-text 'Topic: Example Robotics' \
--format text
actspan inspect restricted_agent
Expected: PROVIDER_PERMISSION_DENIED, HTTP 403, and a saved failed run for
restricted_agent. The reason says the key cannot access gpt-4.1. The command
intentionally exits nonzero; continue with inspection and the next step.
Both models pass the original local policy. This request reaches LiteLLM, which
rejects it using the key's permissions. The OpenAI adapter may label the message
OpenAI permission denied (403); the destination is the configured LiteLLM
endpoint. Changing an Actspan YAML file does not change the gateway's permissions.
Demonstrate a local policy block
4. Back up and change only the Actspan policy
Keep the gateway running and use the same terminal until the policy is restored.
The backup path is held in policy_demo_backup. This changes only the local
allowlist; the agent and gateway key still use the same configuration.
policy_demo_backup=$(mktemp)
cp policies.yaml "$policy_demo_backup"
python3 - <<'PY'
from pathlib import Path
path = Path("policies.yaml")
original = path.read_text()
allowed = "openai: [gpt-4.1-mini, gpt-4.1]"
if original.count(allowed) != 1:
raise SystemExit("Expected the original demo allowlist; policy was not changed.")
path.write_text(original.replace(allowed, "openai: [gpt-4.1]", 1))
print("Local policy now permits only gpt-4.1.")
PY
Expected: the policy now permits only gpt-4.1. The previously allowed
summarize_agent still requests gpt-4.1-mini.
5. Run again and inspect the saved block
actspan run workspace.yaml summarize_agent \
--input-text 'Topic: Example Robotics' \
--admission=block --format text
actspan inspect summarize_agent
actspan runs --limit 10
Expected: the run exits with code 5 and ADMISSION_BLOCKED. This is the
successful demonstration of a policy block. Inspection includes these fields:
Agent: summarize_agent
Status: blocked
Error: ADMISSION_BLOCKED
Reason: Admission blocked: POLICY_DENY::ALLOWLIST::ALLOWLIST::MODEL_NOT_ALLOWED (openai:gpt-4.1-mini)
Executed: false
Enforcement source: actspan_admission
Model: gpt-4.1-mini
Admission mode: block
Policy: gateway_compatibility@1.0.0
It also shows the attempt's own run ID and configuration revision, plus the Git
source revision when available. Keep the exact actspan inspect command printed
by the blocked run to revisit this decision later. Inspection by agent name
selects the latest saved attempt, which changes after you run the agent again.
Run history should contain one row per run ID, including the allowed run, gateway
failure, and local block. The listing uses success and error for agent records;
inspection presents those as succeeded and failed. A local block stays blocked.
6. Restore the policy and run again
cp "$policy_demo_backup" policies.yaml
rm "$policy_demo_backup"
unset policy_demo_backup
actspan run workspace.yaml summarize_agent \
--input-text 'Topic: Example Robotics' \
--admission=block --format text
actspan inspect summarize_agent
Expected: the agent succeeds again. The historical blocked record remains saved
under its own run ID. Restore the policy even if you stop the walkthrough early;
demo.py down does not restore edited policy files.
Read the saved decision
| Field | What it means for the local block |
|---|---|
Status: blocked and Executed: false |
Actspan stopped this request before model execution. |
MODEL_NOT_ALLOWED |
The requested model was outside the local allowlist. |
Enforcement source: actspan_admission |
Actspan made this decision before dispatching the model request to LiteLLM. |
| Policy name and version | Identify the selected policy. Editing its contents does not automatically increment its version label. |
| Configuration revision | Fingerprints the local configuration for this attempt, including the policy files and referenced LiteLLM config file. Editing either changes this fingerprint. |
| Source revision | The Git commit when available. Uncommitted policy edits can change the configuration revision without changing this commit. |
| Latency | Time processing the admission attempt; a value such as 0.5s is not model generation time. |
Cost and tokens: - |
No model cost or usage is recorded for the local block. A dash means unavailable, not measured zero. |
For a live presentation: Actspan checks the agent against its policy before execution and saves the decision, reason, and configuration revision as evidence. LiteLLM separately enforces permissions on requests that reach the gateway.
The local evidence reference explains
saved outcomes and revisions. The walkthrough assumes local state is enabled;
using --no-state skips persistence, so the run cannot be inspected afterward.
What the check demonstrates
7. Run the workflow, evaluation, and automated checks
After restoring the policy:
actspan run workspace.yaml company_summary \
--input-text 'Topic: Example Robotics' --format text
actspan inspect company_summary
actspan eval run eval_summary.yaml \
--fail-on-constraints \
--report-json .actspan/gateway-demo/eval.json
python3 demo.py check
actspan runs --limit 10
Expected: the workflow succeeds, the fixture evaluation passes, and all seven
automated checks report PASSED:
| Check | Expected result |
|---|---|
workspace_validation |
Workspace and required environment values validate. |
configuration_revision_recorded |
The native local configuration revision is recorded. |
allowed_workflow |
company_summary returns the fixed summary. |
gateway_model_permission |
A separate direct request receives LiteLLM's typed model-access 403. |
denial_reaches_cli |
The restricted agent returns a permission failure through Actspan. |
fixture_evaluation_and_revision |
Output checks and constraints pass for the recorded revision. |
configuration_unchanged |
The configuration is unchanged across the automated check. |
These seven checks cover the original gateway configuration. The local policy
edit, block, and restore in steps 4–6 are a separate manual demonstration. Run
check only after restoration so both models pass local admission.
The helper invokes the real CLI and writes .actspan/gateway-demo/report.json,
with evaluation details in eval.json and command output alongside them. It
separates the expected denied request from the allowed run. Helper exit codes
are 0 for passed, 1 for a failed expectation, and 2 for an inconclusive
result or setup failure. A timeout or invalid key does not prove model restrictions.
The checked setup uses LiteLLM 1.102.0, PostgreSQL 17-alpine, and mock
Responses API output. Fixture evaluations assess output structure and configured
checks; they do not measure model accuracy, factual correctness, or actual charges.
Understand the boundary
The workspace keeps the LiteLLM connection separate from its OpenAI adapter:
gateways:
litellm:
type: litellm
config_file: ./litellm_config.yaml
base_url: ${LITELLM_BASE_URL}
secrets:
api_key: ${LITELLM_API_KEY}
providers:
primary:
type: openai
gateway: litellm
primary is the provider alias used by this demo's actions; litellm is the
named gateway connection. The adapter uses the demo virtual key and gateway
endpoint. A missing gateway setting does not fall back to direct OpenAI.
config_file links the workspace to the native LiteLLM file used by the mock
Compose stack. It is relative to workspace.yaml. Actspan checks the local
file's basic structure and fingerprints its contents; Compose mounts it into
LiteLLM. Actspan does not apply the file to the running gateway.
The request uses the Responses API. This example
does not establish compatibility with gateways that expose only Chat Completions
or with every provider operation, streaming mode, or tool integration.
The helper obtains the native configuration revision using actspan verify
and retains its complete output in .actspan/gateway-demo/revision.stdout.
That command can report unsupported checks. Recording a revision does not
mean that all native controls passed or that every declared policy is enforced.
Actspan configuration fingerprints include the local file referenced by
config_file, but exclude resolved environment values and the gateway's
effective configuration. The demo also records a separate hash of its
configuration files for reproducibility. Neither hash establishes that the
running gateway loaded that file or detects remote configuration drift.
The report does not synchronize policy,
correlate gateway audit receipts, enforce an organization-wide budget, or
demonstrate remote MCP authorization.
The gateways block configures connections; it does not install or upgrade
LiteLLM or provide an admin API integration. Optional provider plugin_version
selects the Actspan adapter package, not the gateway server. See
provider and gateway configuration.
This handoff targets Actspan 0.2.0 and pins LiteLLM 1.102.0 in compose.yaml.
The default demo uses an available OpenAI adapter; init records its actual
version. The independent adapter for this handoff is 0.1.1, selected with an
optional plugin_version if that package is available from your index.
See credentials and versions for
the CLI/adapter constraints and the OPENAI_API_KEY export required by live
mode. This mock walkthrough needs only its generated LITELLM_API_KEY.
The next integration step would be to inspect a gateway's effective settings and compare them with explicit contract requirements. That capability is outside this example.
Stop the demo
8. Clean up after the policy is restored
python3 demo.py down
The helper removes the demo's services, disposable database resources, and unchanged generated environment files. Modified environment files and evidence reports are preserved. Cleanup is scoped to this demo rather than other Docker projects.
Source and references
- Open
demo.py,compose.yamlandworkspace.yamlin the supplied demo directory. - LiteLLM Responses API
- LiteLLM virtual keys and model access
- LiteLLM mock responses
- Actspan provider bindings