stigmer-sdk 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.
Files changed (67) hide show
  1. stigmer_sdk-0.1.0/.gitignore +181 -0
  2. stigmer_sdk-0.1.0/Makefile +62 -0
  3. stigmer_sdk-0.1.0/PKG-INFO +295 -0
  4. stigmer_sdk-0.1.0/README.md +268 -0
  5. stigmer_sdk-0.1.0/examples/quickstart.py +34 -0
  6. stigmer_sdk-0.1.0/pyproject.toml +43 -0
  7. stigmer_sdk-0.1.0/src/stigmer/__init__.py +165 -0
  8. stigmer_sdk-0.1.0/src/stigmer/_billing.py +220 -0
  9. stigmer_sdk-0.1.0/src/stigmer/_client.py +222 -0
  10. stigmer_sdk-0.1.0/src/stigmer/_file.py +245 -0
  11. stigmer_sdk-0.1.0/src/stigmer/_gen/__init__.py +159 -0
  12. stigmer_sdk-0.1.0/src/stigmer/_gen/_agent.py +348 -0
  13. stigmer_sdk-0.1.0/src/stigmer/_gen/_apikey.py +146 -0
  14. stigmer_sdk-0.1.0/src/stigmer/_gen/_bidi.py +40 -0
  15. stigmer_sdk-0.1.0/src/stigmer/_gen/_channel.py +384 -0
  16. stigmer_sdk-0.1.0/src/stigmer/_gen/_channelapp.py +169 -0
  17. stigmer_sdk-0.1.0/src/stigmer/_gen/_client.py +69 -0
  18. stigmer_sdk-0.1.0/src/stigmer/_gen/_environment.py +190 -0
  19. stigmer_sdk-0.1.0/src/stigmer/_gen/_errors.py +98 -0
  20. stigmer_sdk-0.1.0/src/stigmer/_gen/_eval.py +178 -0
  21. stigmer_sdk-0.1.0/src/stigmer/_gen/_evalrun.py +206 -0
  22. stigmer_sdk-0.1.0/src/stigmer/_gen/_federationissuer.py +145 -0
  23. stigmer_sdk-0.1.0/src/stigmer/_gen/_file.py +134 -0
  24. stigmer_sdk-0.1.0/src/stigmer/_gen/_grant.py +187 -0
  25. stigmer_sdk-0.1.0/src/stigmer/_gen/_identityaccount.py +213 -0
  26. stigmer_sdk-0.1.0/src/stigmer/_gen/_invitation.py +117 -0
  27. stigmer_sdk-0.1.0/src/stigmer/_gen/_license.py +174 -0
  28. stigmer_sdk-0.1.0/src/stigmer/_gen/_memory.py +143 -0
  29. stigmer_sdk-0.1.0/src/stigmer/_gen/_oauthapp.py +154 -0
  30. stigmer_sdk-0.1.0/src/stigmer/_gen/_organization.py +229 -0
  31. stigmer_sdk-0.1.0/src/stigmer/_gen/_plan.py +130 -0
  32. stigmer_sdk-0.1.0/src/stigmer/_gen/_plugin.py +195 -0
  33. stigmer_sdk-0.1.0/src/stigmer/_gen/_providerkey.py +54 -0
  34. stigmer_sdk-0.1.0/src/stigmer/_gen/_routine.py +296 -0
  35. stigmer_sdk-0.1.0/src/stigmer/_gen/_run.py +450 -0
  36. stigmer_sdk-0.1.0/src/stigmer/_gen/_score.py +184 -0
  37. stigmer_sdk-0.1.0/src/stigmer/_gen/_scoringrule.py +102 -0
  38. stigmer_sdk-0.1.0/src/stigmer/_gen/_session.py +247 -0
  39. stigmer_sdk-0.1.0/src/stigmer/_gen/_skill.py +166 -0
  40. stigmer_sdk-0.1.0/src/stigmer/_gen/_subscription.py +97 -0
  41. stigmer_sdk-0.1.0/src/stigmer/_gen/_team.py +124 -0
  42. stigmer_sdk-0.1.0/src/stigmer/_gen/_types.py +43 -0
  43. stigmer_sdk-0.1.0/src/stigmer/_gen/_vault.py +284 -0
  44. stigmer_sdk-0.1.0/src/stigmer/_github.py +95 -0
  45. stigmer_sdk-0.1.0/src/stigmer/_interceptors.py +85 -0
  46. stigmer_sdk-0.1.0/src/stigmer/_runner_adapter.py +58 -0
  47. stigmer_sdk-0.1.0/src/stigmer/_search.py +97 -0
  48. stigmer_sdk-0.1.0/src/stigmer/_skill.py +101 -0
  49. stigmer_sdk-0.1.0/src/stigmer/_tokens.py +137 -0
  50. stigmer_sdk-0.1.0/src/stigmer/_transport.py +51 -0
  51. stigmer_sdk-0.1.0/src/stigmer/_turns.py +340 -0
  52. stigmer_sdk-0.1.0/src/stigmer/py.typed +0 -0
  53. stigmer_sdk-0.1.0/tests/__init__.py +0 -0
  54. stigmer_sdk-0.1.0/tests/test_agent_mcp_servers.py +48 -0
  55. stigmer_sdk-0.1.0/tests/test_billing.py +103 -0
  56. stigmer_sdk-0.1.0/tests/test_client.py +101 -0
  57. stigmer_sdk-0.1.0/tests/test_file_routing.py +337 -0
  58. stigmer_sdk-0.1.0/tests/test_generated_annotations.py +52 -0
  59. stigmer_sdk-0.1.0/tests/test_github.py +243 -0
  60. stigmer_sdk-0.1.0/tests/test_optional_scalar_presence.py +41 -0
  61. stigmer_sdk-0.1.0/tests/test_orgless_kind_input.py +37 -0
  62. stigmer_sdk-0.1.0/tests/test_pages.py +136 -0
  63. stigmer_sdk-0.1.0/tests/test_runner_adapter.py +89 -0
  64. stigmer_sdk-0.1.0/tests/test_skill_routing.py +149 -0
  65. stigmer_sdk-0.1.0/tests/test_tokens.py +137 -0
  66. stigmer_sdk-0.1.0/tests/test_transport.py +60 -0
  67. stigmer_sdk-0.1.0/tests/test_turns.py +277 -0
@@ -0,0 +1,181 @@
1
+ # Binaries for programs and plugins
2
+ *.exe
3
+ *.exe~
4
+ *.dll
5
+ *.so
6
+ *.dylib
7
+ bin/
8
+ dist/
9
+ # Turborepo's local task cache and per-package task logs (turbo.json).
10
+ .turbo
11
+ dist-slim/
12
+ dist-slim-pkgs/
13
+ # Per-arch trees the Docker image build stages (scripts/smoke-docker-image.mjs).
14
+ dist-slim-amd64/
15
+ dist-slim-arm64/
16
+ # The compose-runner image's CLI tarballs (scripts/stage-compose-runner-cli.mjs).
17
+ backend/services/runner/stage/
18
+ # The server library tarballs a consumer installs (scripts/stage-server-library.mjs).
19
+ backend/services/stigmer-server/stage/
20
+
21
+ # Desktop embedded-runner staging: a symlink in dev (setup-runner-dev.sh),
22
+ # the staged slim artifact in packaged builds (stage-runner-slim.sh).
23
+ client-apps/desktop/src-tauri/resources/runner
24
+ client-apps/desktop/src-tauri/resources/runtime
25
+
26
+ # Test binary, built with `go test -c`
27
+ *.test
28
+
29
+ # Output of the go coverage tool
30
+ *.out
31
+ coverage.txt
32
+ coverage.html
33
+
34
+ # A vitest run's v8 coverage (`--coverage.enabled`), in each package
35
+ coverage/
36
+
37
+ # Stryker's copies of the files it changes in place during a mutation sweep
38
+ # (scripts/mutation-sweep.mjs), which it removes when the run ends
39
+ .stryker-tmp/
40
+
41
+ # Go workspace sum file (auto-generated, can be ignored)
42
+ go.work.sum
43
+
44
+ # Dependency directories (Go)
45
+ vendor/
46
+
47
+ # Python
48
+ __pycache__/
49
+ *.py[cod]
50
+ *$py.class
51
+ *.so
52
+ .Python
53
+ build/
54
+ develop-eggs/
55
+ downloads/
56
+ eggs/
57
+ .eggs/
58
+ /lib/
59
+ /lib64/
60
+ parts/
61
+ sdist/
62
+ var/
63
+ wheels/
64
+ *.egg-info/
65
+ .installed.cfg
66
+ *.egg
67
+ # The setuptools sdist artifact (a FILE named MANIFEST). With
68
+ # core.ignorecase this pattern also swallows source directories named
69
+ # manifest/ (e.g. sdk/*/src/manifest) — the negation re-includes those
70
+ # while the artifact file stays ignored.
71
+ MANIFEST
72
+ !**/manifest/
73
+ *.pyc
74
+ .pytest_cache/
75
+ .coverage
76
+ htmlcov/
77
+
78
+ # Virtual environments
79
+ venv/
80
+ env/
81
+ ENV/
82
+ .venv
83
+
84
+ # IDEs
85
+ .idea/
86
+ .vscode/
87
+ *.swp
88
+ *.swo
89
+ *~
90
+ .DS_Store
91
+
92
+ # Java / Maven
93
+ target/
94
+
95
+ # Node.js
96
+ node_modules/
97
+
98
+ # Stigmer specific
99
+ .stigmer/
100
+ *.skill
101
+ *.db
102
+ *.db-shm
103
+ *.db-wal
104
+
105
+ # Temporary files
106
+ *.log
107
+ # ...except the benchmark fixture's sync log, data the instrument reads
108
+ # (test/conformance/fixtures/working-agent/README.md).
109
+ !test/conformance/fixtures/working-agent/evals/_fixture/workspace/logs/*.log
110
+ *.tmp
111
+ tmp/
112
+
113
+ # Proto generated files (tracked, but ignore in development)
114
+ # We'll commit generated code for now
115
+ # *.pb.go
116
+ # *_pb2.py
117
+ # *_pb2.pyi
118
+
119
+ # Build artifacts
120
+ *.o
121
+ *.a
122
+ *.out
123
+ .agent-runner-image-built
124
+
125
+ # Codegen tool binaries (go build drops these in the module/repo root)
126
+ /generator
127
+ /proto2schema
128
+ tools/codegen/generator/generator
129
+
130
+ # Go service binaries (prevent accidental commits of built binaries in service dirs)
131
+ backend/services/*/stigmer-server
132
+ backend/services/*/agent-runner
133
+ backend/services/*/cmd/*/server
134
+ backend/services/*/server
135
+
136
+ # npm auth tokens (never commit)
137
+ .npmrc
138
+
139
+ # Vale (downloaded style packages — run `vale sync` to fetch)
140
+ vale/styles/Google/
141
+ vale/styles/Microsoft/
142
+ vale/styles/alex/
143
+
144
+ # uv lockfile (project uses Poetry; uv.lock is auto-generated noise)
145
+ uv.lock
146
+
147
+ # Environment files (local secrets, never commit)
148
+ .env
149
+ .env_export
150
+ # Vite local env overrides (e.g. desktop .env.development.local — machine-specific paths)
151
+ .env*.local
152
+
153
+ # Integration test output
154
+ .test-output*/
155
+
156
+ # TypeDoc JSON intermediates (regenerated by `make gen-react-sdk-docs` /
157
+ # `gen-ink-sdk-docs` before every use; they embed the HEAD commit SHA in
158
+ # every source URL, so tracking them creates churn on every SDK commit)
159
+ sdk/*/typedoc-output.json
160
+
161
+ # Cursor
162
+ _cursor/
163
+ _aacursor/
164
+ *.bak
165
+
166
+ # Internal planning/history migrated to the private stigmer-cloud repo (do not re-add)
167
+ _changelog/
168
+ _investigations/
169
+ _projects/
170
+ _roles/
171
+ .cursor/plans/
172
+
173
+ # Compiled codegen toolchain binaries (built ad hoc via `go build` in tools/;
174
+ # the tools are always run via `go run ./tools/codegen/...` — never commit them)
175
+ /tools/generator
176
+ /tools/proto2schema
177
+ /tools/codegen/generator/generator
178
+ /tools/codegen/proto2schema/proto2schema
179
+
180
+ # The docs snippet gate's Python venv and Java classpath (make docs-snippets-toolchains)
181
+ /.docs-snippets-toolchains/
@@ -0,0 +1,62 @@
1
+ # Stigmer Python SDK - Makefile
2
+
3
+ .PHONY: help
4
+ help: ## Display this help message
5
+ @echo "Stigmer Python SDK - Available targets:"
6
+ @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-20s\033[0m %s\n", $$1, $$2}'
7
+
8
+ .PHONY: codegen-clients
9
+ codegen-clients: ## Generate SDK client code from service schemas
10
+ @echo "Generating Python SDK client code..."
11
+ @echo " Wiping src/stigmer/_gen/ directory..."
12
+ @rm -rf src/stigmer/_gen
13
+ @mkdir -p src/stigmer/_gen
14
+ @# The generator runs from TypeScript source via the repo-pinned tsx
15
+ @# (never bare npx — oss#531) and reads proto metadata from
16
+ @# @stigmer/apis, which must be built first (incremental; a no-op when
17
+ @# fresh). A bare CI checkout has no dist/ — skipping this fails module
18
+ @# resolution.
19
+ @cd ../.. && test -x node_modules/.bin/tsx || { echo "error: node_modules/.bin/tsx not found — run 'npm install' at the repo root"; exit 1; }
20
+ @cd ../.. && npm run build -w @stigmer/apis --silent
21
+ @cd ../.. && node_modules/.bin/tsx tools/codegen/src/generator/main.ts \
22
+ --schema-dir tools/codegen/schemas \
23
+ --output-dir sdk/python/src/stigmer/_gen \
24
+ --target sdk-client-python
25
+
26
+ .PHONY: codegen
27
+ codegen: codegen-clients ## Run code generation pipeline
28
+ @echo ""
29
+ @echo "Python SDK code generation complete!"
30
+ @echo "Generated files live in src/stigmer/_gen/"
31
+
32
+ .PHONY: codegen-verify
33
+ codegen-verify: codegen ## Generate code and verify syntax
34
+ @echo "Verifying generated Python files..."
35
+ @python3 -c "import ast, pathlib; \
36
+ files = list(pathlib.Path('src/stigmer/_gen').glob('*.py')); \
37
+ [ast.parse(f.read_text()) for f in files]; \
38
+ print(f' {len(files)} files passed syntax check')"
39
+ @echo ""
40
+ @echo "Code generation verified successfully!"
41
+
42
+ # The tests run in a virtual environment (the system Python on Homebrew and
43
+ # Ubuntu 24.04 refuses a global pip install, PEP 668) against the in-tree
44
+ # proto stubs, never PyPI's stigmer-apis, which lags the tree. VENV may sit
45
+ # outside the package, where a build here can never pack it.
46
+ VENV ?= .venv
47
+ PYTHON ?= python3
48
+
49
+ .PHONY: test
50
+ test: ## Run the SDK's tests against the in-tree proto stubs
51
+ @test -x $(VENV)/bin/python || $(PYTHON) -m venv $(VENV)
52
+ @# A .venv made by uv has no pip.
53
+ @$(VENV)/bin/python -m pip --version >/dev/null 2>&1 || $(VENV)/bin/python -m ensurepip --default-pip >/dev/null
54
+ @$(VENV)/bin/python -m pip install --quiet --disable-pip-version-check ../../apis/stubs/python/stigmer
55
+ @$(VENV)/bin/python -m pip install --quiet --disable-pip-version-check -e '.[test]'
56
+ @$(VENV)/bin/python -m pytest tests
57
+
58
+ .PHONY: clean
59
+ clean: ## Clean build artifacts and the test environment
60
+ @rm -rf dist build *.egg-info src/*.egg-info .venv .pytest_cache
61
+
62
+ .DEFAULT_GOAL := help
@@ -0,0 +1,295 @@
1
+ Metadata-Version: 2.5
2
+ Name: stigmer-sdk
3
+ Version: 0.1.0
4
+ Summary: Python client for Stigmer, the open-source backend for the agents in your product
5
+ Project-URL: Homepage, https://stigmer.ai
6
+ Project-URL: Repository, https://github.com/stigmer/stigmer
7
+ Project-URL: Documentation, https://stigmer.ai/docs/sdk/python
8
+ Author-email: Stigmer <engineering@stigmer.ai>
9
+ License-Expression: Apache-2.0
10
+ Keywords: ai-agents,api-client,grpc,sdk,stigmer
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
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: Typing :: Typed
19
+ Requires-Python: >=3.11
20
+ Requires-Dist: grpcio>=1.60.0
21
+ Requires-Dist: protobuf>=6.32.0
22
+ Requires-Dist: stigmer-apis==0.1.0
23
+ Provides-Extra: test
24
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'test'
25
+ Requires-Dist: pytest>=8; extra == 'test'
26
+ Description-Content-Type: text/markdown
27
+
28
+ # stigmer
29
+
30
+ Python client for [Stigmer](https://stigmer.ai), the open-source backend for the agents in your product. Provides typed API clients for every Stigmer resource with authentication, error handling, and cross-resource search.
31
+
32
+ ## Installation
33
+
34
+ ```bash
35
+ pip install stigmer-sdk
36
+ ```
37
+
38
+ `stigmer-apis` (generated protobuf stubs) is installed automatically as a dependency.
39
+
40
+ ## Quick Start
41
+
42
+ Before you start, run Stigmer on your machine with `stigmer up` and give it a model key ([Start Stigmer and add your model key](https://stigmer.ai/docs/getting-started/quickstart#start-stigmer-and-add-your-model-key)). Without a key the server refuses the message, and the program prints why.
43
+
44
+ This program connects to that Stigmer, sets up a small agent, asks it one thing and prints its answer:
45
+
46
+ ```python
47
+ """The Stigmer quick start: connect to the Stigmer running on this machine,
48
+ set up a small agent, ask it one thing and print its answer.
49
+
50
+ Start Stigmer first with `stigmer up` (given a model key), then:
51
+ python quickstart.py
52
+ """
53
+
54
+ import sys
55
+
56
+ from stigmer import AgentInput, ResourceRef, SessionSpecInput, StigmerClient, StigmerError
57
+
58
+ try:
59
+ # `stigmer up` serves on localhost:7234 and needs no key on your machine.
60
+ with StigmerClient(base_url="localhost:7234", insecure=True) as client:
61
+ # apply creates the agent, or updates it when you run this again.
62
+ agent = client.agents.apply(
63
+ AgentInput(
64
+ name="greeter",
65
+ org="stigmer",
66
+ instructions="You greet people in one short, friendly sentence.",
67
+ )
68
+ )
69
+
70
+ turn = client.send_and_wait(
71
+ org="stigmer",
72
+ session_spec=SessionSpecInput(agent_ref=ResourceRef(org="stigmer", slug=agent.metadata.slug)),
73
+ message="Say hello to a developer trying Stigmer for the first time.",
74
+ )
75
+ except StigmerError as err:
76
+ sys.exit(f"stigmer: {err}")
77
+
78
+ if turn.phase != "completed":
79
+ sys.exit(f"the turn did not complete ({turn.phase}): {turn.error}")
80
+ print(turn.answer)
81
+ ```
82
+
83
+ It is `examples/quickstart.py`. Run `python quickstart.py`; it prints the agent's answer, for example "Hello, and welcome to Stigmer!".
84
+
85
+ `send_and_wait` sends the message and waits for the agent's answer, reconnecting if the stream drops. A turn that waits for a person's approval returns with `phase` `"waiting"` and its `asks`; answer them with `client.sessions.confirm_tool_use` and call `client.wait_for_turn` with the outcome's `last_seq`.
86
+
87
+ ### On Stigmer Cloud
88
+
89
+ Make two changes: connect with an API key, `StigmerClient(os.environ["STIGMER_API_KEY"])` (keys read `stk_…`), and use your own organization, `os.environ["STIGMER_ORG"]`, where the program says `"stigmer"`.
90
+
91
+ ## Resource Clients
92
+
93
+ Every resource type has a typed client accessible as a property on `StigmerClient`:
94
+
95
+ | Property | Resource |
96
+ |------------------------|--------------------|
97
+ | `agents` | Agent |
98
+ | `runs` | Run |
99
+ | `api_keys` | ApiKey |
100
+ | `grants` | Grant |
101
+ | `identity_accounts` | IdentityAccount |
102
+ | `federation_issuers` | FederationIssuer |
103
+ | `organizations` | Organization |
104
+ | `plugins` | Plugin |
105
+ | `sessions` | Session |
106
+ | `skills` | Skill |
107
+ | `vaults` | Vault |
108
+ | `search` | Cross-resource search |
109
+ | `tokens` | User-token minting (service-account keys) |
110
+
111
+ ## Common Operations
112
+
113
+ ```python
114
+ import os
115
+
116
+ from ai.stigmer.agentic.agent.v1 import io_pb2 as agent_io_pb2
117
+ from ai.stigmer.commons.apiresource import io_pb2 as apiresource_io_pb2
118
+ from stigmer import StigmerClient, AgentInput, ResourceRef
119
+
120
+ with StigmerClient(os.environ["STIGMER_API_KEY"]) as client:
121
+ # Create
122
+ agent = client.agents.create(AgentInput(
123
+ name="my-agent",
124
+ org="my-org",
125
+ description="Turns a customer's ledger into a variance report",
126
+ instructions="Be helpful and concise.",
127
+ ))
128
+
129
+ # Get by ID
130
+ agent = client.agents.get("agent-id")
131
+
132
+ # Get by reference (org + slug)
133
+ agent = client.agents.get_by_reference(ResourceRef(org="my-org", slug="my-agent"))
134
+
135
+ # Update: read, change, then name the fields you changed. Every other
136
+ # field keeps its stored value. The read's etag makes the save fail with
137
+ # "aborted" if someone changed the agent since.
138
+ current = client.agents.get("agent-id")
139
+ current.spec.description = "Updated description"
140
+ updated = client.agents.update(current, ["spec.description"])
141
+
142
+ # Rename: change the slug people type. The id stays, so everything that
143
+ # points at the agent keeps working; the old slug reads for 30 days.
144
+ renamed = client.agents.rename(
145
+ apiresource_io_pb2.RenameInput(resource_id="agent-id", slug="variance-reporter")
146
+ )
147
+
148
+ # Delete
149
+ deleted = client.agents.delete("agent-id")
150
+
151
+ # List: one page of the org's agents, newest first. A page carries
152
+ # next_page_token while more follow; page_size 0 asks for the default 50.
153
+ page = client.agents.list(agent_io_pb2.ListAgentsRequest(org="my-org", page_size=20))
154
+
155
+ # Every agent, page after page: list_all follows the tokens.
156
+ for a in client.agents.list_all(agent_io_pb2.ListAgentsRequest(org="my-org")):
157
+ print(a.metadata.slug)
158
+
159
+ # Only the agents carrying every label given.
160
+ finance = client.agents.list(
161
+ agent_io_pb2.ListAgentsRequest(org="my-org", labels={"team": "finance"})
162
+ )
163
+ ```
164
+
165
+ ## Cross-Resource Search
166
+
167
+ ```python
168
+ import os
169
+
170
+ from stigmer import StigmerClient, ApiResourceKind, SearchParams
171
+
172
+ with StigmerClient(os.environ["STIGMER_API_KEY"]) as client:
173
+ results = client.search.query(SearchParams(
174
+ kinds=[ApiResourceKind.agent, ApiResourceKind.skill],
175
+ org="my-org",
176
+ query="variance report",
177
+ ))
178
+ ```
179
+
180
+ ## User Tokens
181
+
182
+ A product that embeds Stigmer mints a short-lived token for each person
183
+ signed in to it, from its own backend, with an ordinary client built on a
184
+ service account's API key. The account must be an admin of the organization
185
+ the token is for, or of its parent organization; a person's key is refused.
186
+ Pass `access_token` to the React SDK's `StigmerProvider` through
187
+ `getAccessToken`:
188
+
189
+ ```python
190
+ import os
191
+
192
+ from stigmer import StigmerClient
193
+
194
+ with StigmerClient(os.environ["STIGMER_API_KEY"]) as client:
195
+ result = client.tokens.mint_user_token(
196
+ org="acme",
197
+ user_id=user.id,
198
+ user_email=user.email,
199
+ user_name=user.name,
200
+ )
201
+ print(result.access_token, result.expires_at)
202
+ ```
203
+
204
+ ## Billing
205
+
206
+ An organization's billing account (its Stripe customer), the Stripe portal
207
+ and card setup sessions. Token usage is read from the run client's usage
208
+ reports (`get_run_usage_report`, `get_session_usage_report`,
209
+ `get_agent_usage_report`, `get_org_usage_report`), counted in tokens and never
210
+ priced. Queries require `can_view_billing` on the org and the org's own
211
+ billing commands require `can_manage_billing`. The operator pricing methods
212
+ (`list_model_pricing_baselines`, `upsert_model_pricing_baseline`,
213
+ `retire_model_pricing_baseline`) require `can_manage_model_pricing` on the
214
+ platform:
215
+
216
+ ```python
217
+ import os
218
+
219
+ from stigmer import CreatePaymentMethodSetupSessionParams, StigmerClient
220
+
221
+ with StigmerClient(os.environ["STIGMER_API_KEY"]) as client:
222
+ account = client.billing.get_billing_account(org)
223
+
224
+ setup = client.billing.create_payment_method_setup_session(
225
+ CreatePaymentMethodSetupSessionParams(
226
+ org=org,
227
+ success_url="https://example.com/billing?setup=success",
228
+ cancel_url="https://example.com/billing",
229
+ )
230
+ )
231
+ ```
232
+
233
+ ## Error Handling
234
+
235
+ All SDK operations raise `StigmerError` with structured error codes:
236
+
237
+ ```python
238
+ import os
239
+
240
+ from stigmer import StigmerClient, StigmerError, is_not_found, is_retryable
241
+
242
+ with StigmerClient(os.environ["STIGMER_API_KEY"]) as client:
243
+ try:
244
+ agent = client.agents.get("nonexistent")
245
+ except StigmerError as err:
246
+ if is_not_found(err):
247
+ print("Agent not found")
248
+ elif is_retryable(err):
249
+ print("Transient error, retry later")
250
+ else:
251
+ print(f"Error [{err.code.value}]: {err}")
252
+ ```
253
+
254
+ Error codes: `not-found`, `permission-denied`, `unauthenticated`, `invalid-argument`, `already-exists`, `resource-exhausted`, `failed-precondition`, `internal`, `unavailable`, `cancelled`, `unknown`.
255
+
256
+ ## Configuration
257
+
258
+ ```python
259
+ StigmerClient(
260
+ api_key: str | None = None, # Stigmer API key, "stk_…" (required unless insecure)
261
+ *,
262
+ base_url: str = "api.stigmer.ai:443", # gRPC target address
263
+ insecure: bool = False, # Skip TLS (local development only)
264
+ )
265
+ ```
266
+
267
+ On your machine, `stigmer up` serves on `localhost:7234` and needs no key; leave the key out on that plain-text connection, and the client sends no `authorization` header:
268
+
269
+ ```python
270
+ client = StigmerClient(base_url="localhost:7234", insecure=True)
271
+ ```
272
+
273
+ A client with no key on a TLS connection is refused at construction, as is an empty key.
274
+
275
+ For a CI job or a script, use a [service account's](https://stigmer.ai/docs/guides/authentication/service-accounts) API key, not a person's: it keeps working when that person leaves and works only in its own organization.
276
+
277
+ ## Code Generation
278
+
279
+ The resource clients in `src/stigmer/_gen/` are generated from protobuf service schemas. To regenerate after proto changes:
280
+
281
+ ```bash
282
+ cd sdk/python
283
+ make codegen
284
+ ```
285
+
286
+ Handwritten code lives in `src/stigmer/` (outside `_gen/`): `_client.py`, `_transport.py`, `_interceptors.py`, `_search.py`, `_tokens.py`, `_turns.py`, and `__init__.py`.
287
+
288
+ ## Tests
289
+
290
+ ```bash
291
+ cd sdk/python
292
+ make test
293
+ ```
294
+
295
+ It makes a virtual environment in `.venv`, installs the SDK and the proto stubs from this repository into it (not PyPI's `stigmer-apis`, which can lag the tree), and runs `pytest`. `make clean` removes the environment.