maitai-cli 0.1.1__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.
@@ -0,0 +1,250 @@
1
+ Metadata-Version: 2.4
2
+ Name: maitai-cli
3
+ Version: 0.1.1
4
+ Summary: CLI for the Maitai Platform Developer API (api/v1)
5
+ Author-email: Maitai <support@trymaitai.com>
6
+ License: MIT
7
+ Project-URL: Documentation, https://docs.trymaitai.ai
8
+ Project-URL: API Reference, https://docs.trymaitai.ai/api-reference
9
+ Project-URL: Portal, https://portal.trymaitai.com
10
+ Keywords: maitai,cli,api,ai,llm
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Requires-Python: >=3.9
21
+ Description-Content-Type: text/markdown
22
+ Requires-Dist: typer>=0.9.0
23
+ Requires-Dist: httpx>=0.25.0
24
+ Requires-Dist: rich>=13.0.0
25
+ Provides-Extra: dev
26
+ Requires-Dist: pytest; extra == "dev"
27
+ Requires-Dist: ruff; extra == "dev"
28
+
29
+ # Maitai CLI
30
+
31
+ Command-line interface for the [Maitai Platform Developer API](https://docs.trymaitai.ai/api-reference) (api/v1).
32
+
33
+ Resource commands (`applications`, `agents`, etc.) are **generated from the OpenAPI spec**. When the API changes, run `python scripts/generate_openapi.py` from the repo root to regenerate the CLI.
34
+
35
+ ## Install
36
+
37
+ ```bash
38
+ # From the maitai-mono repo (cli directory)
39
+ pip install .
40
+
41
+ # Or install in development mode
42
+ pip install -e .
43
+ ```
44
+
45
+ ## Authenticate
46
+
47
+ Create an API key in the [Portal](https://portal.trymaitai.com) under **Settings → API Keys**, then:
48
+
49
+ ```bash
50
+ # Interactive: saves key to ~/.maitai/config
51
+ maitai login --api-key YOUR_MAITAI_API_KEY
52
+
53
+ # Or use environment variable (no login needed)
54
+ export MAITAI_API_KEY="YOUR_MAITAI_API_KEY"
55
+ ```
56
+
57
+ For a custom base URL (e.g. local dev):
58
+
59
+ ```bash
60
+ maitai login --api-key YOUR_KEY --base-url http://localhost:5000/api/v1
61
+ ```
62
+
63
+ ## Usage
64
+
65
+ ```bash
66
+ # Check auth status
67
+ maitai whoami
68
+
69
+ # List resources
70
+ maitai applications --list
71
+ maitai agents --list
72
+ maitai intent-groups --list
73
+ maitai sessions --list
74
+ maitai sentinels --list
75
+ maitai datasets --list
76
+ maitai test-sets --list
77
+ maitai test-runs --list
78
+ maitai models --list
79
+ maitai models --available
80
+ maitai evaluations --list
81
+ maitai finetune-runs --list
82
+ maitai conversation-trees --list
83
+
84
+ # Get by ID
85
+ maitai applications --get 42
86
+ maitai agents --get 1
87
+ maitai intent-groups --get 5
88
+
89
+ # Create application
90
+ maitai applications --create "My App:my-app"
91
+
92
+ # Delete application
93
+ maitai applications --delete 42
94
+
95
+ # Raw API calls (any endpoint)
96
+ maitai api GET /applications
97
+ maitai api GET /applications/42
98
+ maitai api POST /applications -b '{"application_name":"Test","application_ref_name":"test"}'
99
+ maitai api PUT /applications/42 -b '{"application_name":"Updated"}'
100
+ maitai api DELETE /applications/42
101
+ ```
102
+
103
+ ## API Reference
104
+
105
+ The CLI wraps the Maitai Developer API. Full documentation:
106
+
107
+ - **External docs**: [docs.trymaitai.ai](https://docs.trymaitai.ai)
108
+ - **OpenAPI spec**: `docs/external/openapi.yaml` in this repo
109
+ - **Internal docs**: `docs/internal/` in this repo
110
+
111
+ ### Authentication
112
+
113
+ All requests use the `X-Maitai-Api-Key` header. Create keys at [portal.trymaitai.com](https://portal.trymaitai.com) → Settings → API Keys.
114
+
115
+ ### Base URL
116
+
117
+ - Production: `https://api.trymaitai.ai/api/v1`
118
+ - Override with `MAITAI_BASE_URL` or `maitai login --base-url`
119
+
120
+ ### Response Format
121
+
122
+ - Success: `{"data": {...}}`
123
+ - Paginated: `{"data": [...], "pagination": {"total": N, "offset": 0, "limit": 25}}`
124
+ - Error: `{"error": {"status": 401, "message": "..."}}`
125
+
126
+ <!-- GENERATED_ENDPOINTS_START -->
127
+ ## Supported API endpoints
128
+
129
+ The CLI wraps all api/v1 endpoints. Use `maitai api METHOD path` for any endpoint:
130
+
131
+ | Method | Path | Operation |
132
+ |--------|------|-----------|
133
+ | GET | `/agents` | listAgents |
134
+ | POST | `/agents` | createAgent |
135
+ | DELETE | `/agents/actions/{action_id}` | deleteAgentAction |
136
+ | GET | `/agents/actions/{action_id}` | getAgentAction |
137
+ | PUT | `/agents/actions/{action_id}` | updateAgentAction |
138
+ | PUT | `/agents/actions/{action_id}/disable` | disableAction |
139
+ | PUT | `/agents/actions/{action_id}/enable` | enableAction |
140
+ | POST | `/agents/actions/{action_id}/publish` | publishActionVersion |
141
+ | GET | `/agents/actions/{action_id}/versions` | listActionVersions |
142
+ | GET | `/agents/tasks/{task_id}/tree` | getAgentTaskTree |
143
+ | DELETE | `/agents/{agent_id}` | deleteAgent |
144
+ | GET | `/agents/{agent_id}` | getAgent |
145
+ | PUT | `/agents/{agent_id}` | updateAgent |
146
+ | GET | `/agents/{agent_id}/actions` | listAgentActions |
147
+ | POST | `/agents/{agent_id}/actions` | createAgentAction |
148
+ | DELETE | `/agents/{agent_id}/form-fields` | deleteFormFields |
149
+ | GET | `/agents/{agent_id}/form-fields` | getFormFields |
150
+ | PUT | `/agents/{agent_id}/form-fields` | updateFormFields |
151
+ | POST | `/agents/{agent_id}/publish` | publishAgentVersion |
152
+ | GET | `/agents/{agent_id}/releases` | listAgentReleases |
153
+ | DELETE | `/agents/{agent_id}/releases/{name}` | deleteAgentRelease |
154
+ | PUT | `/agents/{agent_id}/releases/{name}` | upsertAgentRelease |
155
+ | GET | `/agents/{agent_id}/routing/config` | getRoutingConfig |
156
+ | PUT | `/agents/{agent_id}/routing/config` | updateRoutingConfig |
157
+ | POST | `/agents/{agent_id}/routing/rules` | createRoutingRule |
158
+ | DELETE | `/agents/{agent_id}/routing/rules/{rule_id}` | deleteRoutingRule |
159
+ | PUT | `/agents/{agent_id}/routing/rules/{rule_id}` | updateRoutingRule |
160
+ | GET | `/agents/{agent_id}/sessions` | listAgentSessions |
161
+ | GET | `/agents/{agent_id}/sessions/{session_id}` | getAgentSessionDetail |
162
+ | GET | `/agents/{agent_id}/sessions/{session_id}/timeline` | getAgentSessionTimeline |
163
+ | GET | `/agents/{agent_id}/subagents` | listSubAgents |
164
+ | POST | `/agents/{agent_id}/subagents` | addSubAgent |
165
+ | DELETE | `/agents/{agent_id}/subagents/{child_agent_id}` | removeSubAgent |
166
+ | PUT | `/agents/{agent_id}/subagents/{child_agent_id}/disable` | disableSubAgent |
167
+ | PUT | `/agents/{agent_id}/subagents/{child_agent_id}/enable` | enableSubAgent |
168
+ | GET | `/agents/{agent_id}/tasks/{task_id}/timeline` | getAgentTaskTimeline |
169
+ | GET | `/agents/{agent_id}/versions` | listAgentVersions |
170
+ | GET | `/agents/{agent_id}/versions/{version}` | getAgentVersion |
171
+ | GET | `/applications` | listApplications |
172
+ | POST | `/applications` | createApplication |
173
+ | DELETE | `/applications/{application_id}` | deleteApplication |
174
+ | GET | `/applications/{application_id}` | getApplication |
175
+ | PUT | `/applications/{application_id}` | updateApplication |
176
+ | GET | `/applications/{application_id}/config` | getApplicationConfig |
177
+ | PUT | `/applications/{application_id}/config` | updateApplicationConfig |
178
+ | GET | `/applications/{application_id}/intents` | listApplicationIntents |
179
+ | GET | `/applications/{application_id}/intents/{intent_id}` | getApplicationIntent |
180
+ | GET | `/applications/{application_id}/intents/{intent_id}/config` | getIntentConfig |
181
+ | PUT | `/applications/{application_id}/intents/{intent_id}/config` | updateIntentConfig |
182
+ | GET | `/applications/{application_id}/models` | listApplicationModels |
183
+ | GET | `/applications/{application_id}/sessions` | listApplicationSessions |
184
+ | GET | `/applications/{application_id}/workflow-runs` | listApplicationWorkflowRuns |
185
+ | GET | `/conversation-trees` | listConversationTrees |
186
+ | DELETE | `/conversation-trees/{tree_id}` | deleteConversationTree |
187
+ | GET | `/conversation-trees/{tree_id}` | getConversationTree |
188
+ | GET | `/conversation-trees/{tree_id}/status` | getConversationTreeStatus |
189
+ | GET | `/conversation-trees/{tree_id}/versions` | listConversationTreeVersions |
190
+ | GET | `/datasets` | listDatasets |
191
+ | POST | `/datasets` | createDataset |
192
+ | DELETE | `/datasets/{dataset_id}` | deleteDataset |
193
+ | GET | `/datasets/{dataset_id}` | getDataset |
194
+ | PUT | `/datasets/{dataset_id}` | updateDataset |
195
+ | DELETE | `/datasets/{dataset_id}/requests` | removeRequestsFromDataset |
196
+ | GET | `/datasets/{dataset_id}/requests` | listDatasetRequests |
197
+ | POST | `/datasets/{dataset_id}/requests` | addRequestsToDataset |
198
+ | GET | `/evaluations` | listEvaluations |
199
+ | POST | `/evaluations` | createEvaluation |
200
+ | GET | `/evaluations/{evaluation_run_id}` | getEvaluation |
201
+ | GET | `/evaluations/{evaluation_run_id}/results` | getEvaluationResults |
202
+ | GET | `/finetune-runs` | listFinetuneRuns |
203
+ | POST | `/finetune-runs` | createFinetuneRun |
204
+ | GET | `/finetune-runs/{run_id}` | getFinetuneRun |
205
+ | POST | `/finetune-runs/{run_id}/cancel` | cancelFinetuneRun |
206
+ | GET | `/finetune-runs/{run_id}/metrics` | getFinetuneRunMetrics |
207
+ | GET | `/intent-groups` | listIntentGroups |
208
+ | GET | `/intent-groups/{intent_group_id}` | getIntentGroup |
209
+ | GET | `/intent-groups/{intent_group_id}/compositions` | listIntentGroupCompositions |
210
+ | GET | `/intent-groups/{intent_group_id}/config` | getIntentGroupConfig |
211
+ | PUT | `/intent-groups/{intent_group_id}/config` | updateIntentGroupConfig |
212
+ | GET | `/intent-groups/{intent_group_id}/datasets` | listIntentGroupDatasets |
213
+ | GET | `/intent-groups/{intent_group_id}/intents` | listIntentsByGroup |
214
+ | GET | `/intent-groups/{intent_group_id}/models` | listIntentGroupModels |
215
+ | GET | `/intent-groups/{intent_group_id}/requests` | listIntentGroupRequests |
216
+ | GET | `/intent-groups/{intent_group_id}/sentinels` | listIntentGroupSentinels |
217
+ | GET | `/intent-groups/{intent_group_id}/test-sets` | listIntentGroupTestSets |
218
+ | GET | `/models` | listModels |
219
+ | GET | `/models/available` | listAvailableModels |
220
+ | POST | `/models/{model_id}/disable` | disableModel |
221
+ | POST | `/models/{model_id}/enable` | enableModel |
222
+ | GET | `/requests` | listRequests |
223
+ | GET | `/requests/{request_id}` | getRequest |
224
+ | PUT | `/requests/{request_id}/response` | updateRequestResponse |
225
+ | GET | `/sentinels` | listSentinels |
226
+ | POST | `/sentinels` | createSentinel |
227
+ | DELETE | `/sentinels/{sentinel_id}` | deleteSentinel |
228
+ | GET | `/sentinels/{sentinel_id}` | getSentinel |
229
+ | PUT | `/sentinels/{sentinel_id}` | updateSentinel |
230
+ | GET | `/sessions` | listSessions |
231
+ | GET | `/sessions/{session_id}` | getSession |
232
+ | POST | `/sessions/{session_id}/feedback` | setSessionFeedback |
233
+ | GET | `/sessions/{session_id}/timeline` | getSessionTimeline |
234
+ | GET | `/test-runs` | listTestRuns |
235
+ | POST | `/test-runs` | createTestRun |
236
+ | DELETE | `/test-runs/{test_run_id}` | deleteTestRun |
237
+ | GET | `/test-runs/{test_run_id}` | getTestRun |
238
+ | GET | `/test-runs/{test_run_id}/progress` | getTestRunProgress |
239
+ | GET | `/test-runs/{test_run_id}/requests` | listTestRunRequests |
240
+ | GET | `/test-sets` | listTestSets |
241
+ | POST | `/test-sets` | createTestSet |
242
+ | DELETE | `/test-sets/{test_set_id}` | deleteTestSet |
243
+ | GET | `/test-sets/{test_set_id}` | getTestSet |
244
+ | PUT | `/test-sets/{test_set_id}` | updateTestSet |
245
+ | DELETE | `/test-sets/{test_set_id}/requests` | removeRequestsFromTestSet |
246
+ | GET | `/test-sets/{test_set_id}/requests` | listTestSetRequests |
247
+ | POST | `/test-sets/{test_set_id}/requests` | addRequestsToTestSet |
248
+
249
+ <!-- GENERATED_ENDPOINTS_END -->
250
+
@@ -0,0 +1,222 @@
1
+ # Maitai CLI
2
+
3
+ Command-line interface for the [Maitai Platform Developer API](https://docs.trymaitai.ai/api-reference) (api/v1).
4
+
5
+ Resource commands (`applications`, `agents`, etc.) are **generated from the OpenAPI spec**. When the API changes, run `python scripts/generate_openapi.py` from the repo root to regenerate the CLI.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ # From the maitai-mono repo (cli directory)
11
+ pip install .
12
+
13
+ # Or install in development mode
14
+ pip install -e .
15
+ ```
16
+
17
+ ## Authenticate
18
+
19
+ Create an API key in the [Portal](https://portal.trymaitai.com) under **Settings → API Keys**, then:
20
+
21
+ ```bash
22
+ # Interactive: saves key to ~/.maitai/config
23
+ maitai login --api-key YOUR_MAITAI_API_KEY
24
+
25
+ # Or use environment variable (no login needed)
26
+ export MAITAI_API_KEY="YOUR_MAITAI_API_KEY"
27
+ ```
28
+
29
+ For a custom base URL (e.g. local dev):
30
+
31
+ ```bash
32
+ maitai login --api-key YOUR_KEY --base-url http://localhost:5000/api/v1
33
+ ```
34
+
35
+ ## Usage
36
+
37
+ ```bash
38
+ # Check auth status
39
+ maitai whoami
40
+
41
+ # List resources
42
+ maitai applications --list
43
+ maitai agents --list
44
+ maitai intent-groups --list
45
+ maitai sessions --list
46
+ maitai sentinels --list
47
+ maitai datasets --list
48
+ maitai test-sets --list
49
+ maitai test-runs --list
50
+ maitai models --list
51
+ maitai models --available
52
+ maitai evaluations --list
53
+ maitai finetune-runs --list
54
+ maitai conversation-trees --list
55
+
56
+ # Get by ID
57
+ maitai applications --get 42
58
+ maitai agents --get 1
59
+ maitai intent-groups --get 5
60
+
61
+ # Create application
62
+ maitai applications --create "My App:my-app"
63
+
64
+ # Delete application
65
+ maitai applications --delete 42
66
+
67
+ # Raw API calls (any endpoint)
68
+ maitai api GET /applications
69
+ maitai api GET /applications/42
70
+ maitai api POST /applications -b '{"application_name":"Test","application_ref_name":"test"}'
71
+ maitai api PUT /applications/42 -b '{"application_name":"Updated"}'
72
+ maitai api DELETE /applications/42
73
+ ```
74
+
75
+ ## API Reference
76
+
77
+ The CLI wraps the Maitai Developer API. Full documentation:
78
+
79
+ - **External docs**: [docs.trymaitai.ai](https://docs.trymaitai.ai)
80
+ - **OpenAPI spec**: `docs/external/openapi.yaml` in this repo
81
+ - **Internal docs**: `docs/internal/` in this repo
82
+
83
+ ### Authentication
84
+
85
+ All requests use the `X-Maitai-Api-Key` header. Create keys at [portal.trymaitai.com](https://portal.trymaitai.com) → Settings → API Keys.
86
+
87
+ ### Base URL
88
+
89
+ - Production: `https://api.trymaitai.ai/api/v1`
90
+ - Override with `MAITAI_BASE_URL` or `maitai login --base-url`
91
+
92
+ ### Response Format
93
+
94
+ - Success: `{"data": {...}}`
95
+ - Paginated: `{"data": [...], "pagination": {"total": N, "offset": 0, "limit": 25}}`
96
+ - Error: `{"error": {"status": 401, "message": "..."}}`
97
+
98
+ <!-- GENERATED_ENDPOINTS_START -->
99
+ ## Supported API endpoints
100
+
101
+ The CLI wraps all api/v1 endpoints. Use `maitai api METHOD path` for any endpoint:
102
+
103
+ | Method | Path | Operation |
104
+ |--------|------|-----------|
105
+ | GET | `/agents` | listAgents |
106
+ | POST | `/agents` | createAgent |
107
+ | DELETE | `/agents/actions/{action_id}` | deleteAgentAction |
108
+ | GET | `/agents/actions/{action_id}` | getAgentAction |
109
+ | PUT | `/agents/actions/{action_id}` | updateAgentAction |
110
+ | PUT | `/agents/actions/{action_id}/disable` | disableAction |
111
+ | PUT | `/agents/actions/{action_id}/enable` | enableAction |
112
+ | POST | `/agents/actions/{action_id}/publish` | publishActionVersion |
113
+ | GET | `/agents/actions/{action_id}/versions` | listActionVersions |
114
+ | GET | `/agents/tasks/{task_id}/tree` | getAgentTaskTree |
115
+ | DELETE | `/agents/{agent_id}` | deleteAgent |
116
+ | GET | `/agents/{agent_id}` | getAgent |
117
+ | PUT | `/agents/{agent_id}` | updateAgent |
118
+ | GET | `/agents/{agent_id}/actions` | listAgentActions |
119
+ | POST | `/agents/{agent_id}/actions` | createAgentAction |
120
+ | DELETE | `/agents/{agent_id}/form-fields` | deleteFormFields |
121
+ | GET | `/agents/{agent_id}/form-fields` | getFormFields |
122
+ | PUT | `/agents/{agent_id}/form-fields` | updateFormFields |
123
+ | POST | `/agents/{agent_id}/publish` | publishAgentVersion |
124
+ | GET | `/agents/{agent_id}/releases` | listAgentReleases |
125
+ | DELETE | `/agents/{agent_id}/releases/{name}` | deleteAgentRelease |
126
+ | PUT | `/agents/{agent_id}/releases/{name}` | upsertAgentRelease |
127
+ | GET | `/agents/{agent_id}/routing/config` | getRoutingConfig |
128
+ | PUT | `/agents/{agent_id}/routing/config` | updateRoutingConfig |
129
+ | POST | `/agents/{agent_id}/routing/rules` | createRoutingRule |
130
+ | DELETE | `/agents/{agent_id}/routing/rules/{rule_id}` | deleteRoutingRule |
131
+ | PUT | `/agents/{agent_id}/routing/rules/{rule_id}` | updateRoutingRule |
132
+ | GET | `/agents/{agent_id}/sessions` | listAgentSessions |
133
+ | GET | `/agents/{agent_id}/sessions/{session_id}` | getAgentSessionDetail |
134
+ | GET | `/agents/{agent_id}/sessions/{session_id}/timeline` | getAgentSessionTimeline |
135
+ | GET | `/agents/{agent_id}/subagents` | listSubAgents |
136
+ | POST | `/agents/{agent_id}/subagents` | addSubAgent |
137
+ | DELETE | `/agents/{agent_id}/subagents/{child_agent_id}` | removeSubAgent |
138
+ | PUT | `/agents/{agent_id}/subagents/{child_agent_id}/disable` | disableSubAgent |
139
+ | PUT | `/agents/{agent_id}/subagents/{child_agent_id}/enable` | enableSubAgent |
140
+ | GET | `/agents/{agent_id}/tasks/{task_id}/timeline` | getAgentTaskTimeline |
141
+ | GET | `/agents/{agent_id}/versions` | listAgentVersions |
142
+ | GET | `/agents/{agent_id}/versions/{version}` | getAgentVersion |
143
+ | GET | `/applications` | listApplications |
144
+ | POST | `/applications` | createApplication |
145
+ | DELETE | `/applications/{application_id}` | deleteApplication |
146
+ | GET | `/applications/{application_id}` | getApplication |
147
+ | PUT | `/applications/{application_id}` | updateApplication |
148
+ | GET | `/applications/{application_id}/config` | getApplicationConfig |
149
+ | PUT | `/applications/{application_id}/config` | updateApplicationConfig |
150
+ | GET | `/applications/{application_id}/intents` | listApplicationIntents |
151
+ | GET | `/applications/{application_id}/intents/{intent_id}` | getApplicationIntent |
152
+ | GET | `/applications/{application_id}/intents/{intent_id}/config` | getIntentConfig |
153
+ | PUT | `/applications/{application_id}/intents/{intent_id}/config` | updateIntentConfig |
154
+ | GET | `/applications/{application_id}/models` | listApplicationModels |
155
+ | GET | `/applications/{application_id}/sessions` | listApplicationSessions |
156
+ | GET | `/applications/{application_id}/workflow-runs` | listApplicationWorkflowRuns |
157
+ | GET | `/conversation-trees` | listConversationTrees |
158
+ | DELETE | `/conversation-trees/{tree_id}` | deleteConversationTree |
159
+ | GET | `/conversation-trees/{tree_id}` | getConversationTree |
160
+ | GET | `/conversation-trees/{tree_id}/status` | getConversationTreeStatus |
161
+ | GET | `/conversation-trees/{tree_id}/versions` | listConversationTreeVersions |
162
+ | GET | `/datasets` | listDatasets |
163
+ | POST | `/datasets` | createDataset |
164
+ | DELETE | `/datasets/{dataset_id}` | deleteDataset |
165
+ | GET | `/datasets/{dataset_id}` | getDataset |
166
+ | PUT | `/datasets/{dataset_id}` | updateDataset |
167
+ | DELETE | `/datasets/{dataset_id}/requests` | removeRequestsFromDataset |
168
+ | GET | `/datasets/{dataset_id}/requests` | listDatasetRequests |
169
+ | POST | `/datasets/{dataset_id}/requests` | addRequestsToDataset |
170
+ | GET | `/evaluations` | listEvaluations |
171
+ | POST | `/evaluations` | createEvaluation |
172
+ | GET | `/evaluations/{evaluation_run_id}` | getEvaluation |
173
+ | GET | `/evaluations/{evaluation_run_id}/results` | getEvaluationResults |
174
+ | GET | `/finetune-runs` | listFinetuneRuns |
175
+ | POST | `/finetune-runs` | createFinetuneRun |
176
+ | GET | `/finetune-runs/{run_id}` | getFinetuneRun |
177
+ | POST | `/finetune-runs/{run_id}/cancel` | cancelFinetuneRun |
178
+ | GET | `/finetune-runs/{run_id}/metrics` | getFinetuneRunMetrics |
179
+ | GET | `/intent-groups` | listIntentGroups |
180
+ | GET | `/intent-groups/{intent_group_id}` | getIntentGroup |
181
+ | GET | `/intent-groups/{intent_group_id}/compositions` | listIntentGroupCompositions |
182
+ | GET | `/intent-groups/{intent_group_id}/config` | getIntentGroupConfig |
183
+ | PUT | `/intent-groups/{intent_group_id}/config` | updateIntentGroupConfig |
184
+ | GET | `/intent-groups/{intent_group_id}/datasets` | listIntentGroupDatasets |
185
+ | GET | `/intent-groups/{intent_group_id}/intents` | listIntentsByGroup |
186
+ | GET | `/intent-groups/{intent_group_id}/models` | listIntentGroupModels |
187
+ | GET | `/intent-groups/{intent_group_id}/requests` | listIntentGroupRequests |
188
+ | GET | `/intent-groups/{intent_group_id}/sentinels` | listIntentGroupSentinels |
189
+ | GET | `/intent-groups/{intent_group_id}/test-sets` | listIntentGroupTestSets |
190
+ | GET | `/models` | listModels |
191
+ | GET | `/models/available` | listAvailableModels |
192
+ | POST | `/models/{model_id}/disable` | disableModel |
193
+ | POST | `/models/{model_id}/enable` | enableModel |
194
+ | GET | `/requests` | listRequests |
195
+ | GET | `/requests/{request_id}` | getRequest |
196
+ | PUT | `/requests/{request_id}/response` | updateRequestResponse |
197
+ | GET | `/sentinels` | listSentinels |
198
+ | POST | `/sentinels` | createSentinel |
199
+ | DELETE | `/sentinels/{sentinel_id}` | deleteSentinel |
200
+ | GET | `/sentinels/{sentinel_id}` | getSentinel |
201
+ | PUT | `/sentinels/{sentinel_id}` | updateSentinel |
202
+ | GET | `/sessions` | listSessions |
203
+ | GET | `/sessions/{session_id}` | getSession |
204
+ | POST | `/sessions/{session_id}/feedback` | setSessionFeedback |
205
+ | GET | `/sessions/{session_id}/timeline` | getSessionTimeline |
206
+ | GET | `/test-runs` | listTestRuns |
207
+ | POST | `/test-runs` | createTestRun |
208
+ | DELETE | `/test-runs/{test_run_id}` | deleteTestRun |
209
+ | GET | `/test-runs/{test_run_id}` | getTestRun |
210
+ | GET | `/test-runs/{test_run_id}/progress` | getTestRunProgress |
211
+ | GET | `/test-runs/{test_run_id}/requests` | listTestRunRequests |
212
+ | GET | `/test-sets` | listTestSets |
213
+ | POST | `/test-sets` | createTestSet |
214
+ | DELETE | `/test-sets/{test_set_id}` | deleteTestSet |
215
+ | GET | `/test-sets/{test_set_id}` | getTestSet |
216
+ | PUT | `/test-sets/{test_set_id}` | updateTestSet |
217
+ | DELETE | `/test-sets/{test_set_id}/requests` | removeRequestsFromTestSet |
218
+ | GET | `/test-sets/{test_set_id}/requests` | listTestSetRequests |
219
+ | POST | `/test-sets/{test_set_id}/requests` | addRequestsToTestSet |
220
+
221
+ <!-- GENERATED_ENDPOINTS_END -->
222
+
@@ -0,0 +1,3 @@
1
+ """Maitai CLI - Command-line interface for the Maitai Platform Developer API."""
2
+
3
+ __version__ = "0.1.1"
@@ -0,0 +1,6 @@
1
+ """Allow running as python -m maitai_cli."""
2
+
3
+ from maitai_cli.main import main
4
+
5
+ if __name__ == "__main__":
6
+ main()
@@ -0,0 +1,90 @@
1
+ """
2
+ API client for the Maitai Platform Developer API (api/v1).
3
+
4
+ API documentation: docs/internal and docs/external in the maitai-mono repo.
5
+ Base URL: https://api.trymaitai.ai/api/v1
6
+ Authentication: X-Maitai-Api-Key header (create keys in Portal → Settings → API Keys).
7
+ """
8
+
9
+ from typing import Any
10
+
11
+ import httpx
12
+ from maitai_cli.config import get_api_key, get_base_url
13
+
14
+
15
+ class APIError(Exception):
16
+ """Raised when an API request fails."""
17
+
18
+ def __init__(self, status_code: int, message: str, details: dict | None = None):
19
+ self.status_code = status_code
20
+ self.message = message
21
+ self.details = details or {}
22
+ super().__init__(f"{status_code}: {message}")
23
+
24
+
25
+ class APIClient:
26
+ """HTTP client for the Maitai Developer API."""
27
+
28
+ def __init__(self, api_key: str | None = None, base_url: str | None = None):
29
+ self.api_key = api_key or get_api_key()
30
+ self.base_url = (base_url or get_base_url()).rstrip("/")
31
+ self._client: httpx.Client | None = None
32
+
33
+ def _get_client(self) -> httpx.Client:
34
+ if self._client is None:
35
+ headers = {}
36
+ if self.api_key:
37
+ headers["X-Maitai-Api-Key"] = self.api_key
38
+ self._client = httpx.Client(
39
+ base_url=self.base_url,
40
+ headers=headers,
41
+ timeout=30.0,
42
+ )
43
+ return self._client
44
+
45
+ def close(self) -> None:
46
+ """Close the HTTP client."""
47
+ if self._client:
48
+ self._client.close()
49
+ self._client = None
50
+
51
+ def _request(
52
+ self,
53
+ method: str,
54
+ path: str,
55
+ *,
56
+ params: dict | None = None,
57
+ json: dict | None = None,
58
+ ) -> dict[str, Any]:
59
+ """Make an API request and return the parsed JSON response."""
60
+ if not self.api_key:
61
+ raise APIError(
62
+ 401, "Not authenticated. Run 'maitai login' or set MAITAI_API_KEY."
63
+ )
64
+ client = self._get_client()
65
+ path = path if path.startswith("/") else f"/{path}"
66
+ r = client.request(method, path, params=params, json=json)
67
+ try:
68
+ body = r.json()
69
+ except Exception:
70
+ body = {}
71
+ if r.status_code >= 400:
72
+ err = body.get("error", {})
73
+ raise APIError(
74
+ r.status_code,
75
+ err.get("message", r.text or str(r.status_code)),
76
+ err.get("details"),
77
+ )
78
+ return body
79
+
80
+ def get(self, path: str, params: dict | None = None) -> dict[str, Any]:
81
+ return self._request("GET", path, params=params)
82
+
83
+ def post(self, path: str, json: dict | None = None) -> dict[str, Any]:
84
+ return self._request("POST", path, json=json)
85
+
86
+ def put(self, path: str, json: dict | None = None) -> dict[str, Any]:
87
+ return self._request("PUT", path, json=json)
88
+
89
+ def delete(self, path: str) -> dict[str, Any]:
90
+ return self._request("DELETE", path)