getstack 0.6.0__tar.gz → 0.7.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.
- {getstack-0.6.0 → getstack-0.7.0}/.gitignore +5 -0
- {getstack-0.6.0 → getstack-0.7.0}/PKG-INFO +1 -1
- {getstack-0.6.0 → getstack-0.7.0}/pyproject.toml +1 -1
- {getstack-0.6.0 → getstack-0.7.0}/src/getstack/__init__.py +4 -0
- getstack-0.7.0/src/getstack/_async/missions.py +110 -0
- getstack-0.7.0/src/getstack/missions.py +130 -0
- {getstack-0.6.0 → getstack-0.7.0}/CLAUDE.md +0 -0
- {getstack-0.6.0 → getstack-0.7.0}/LICENSE +0 -0
- {getstack-0.6.0 → getstack-0.7.0}/README.md +0 -0
- {getstack-0.6.0 → getstack-0.7.0}/src/getstack/_async/__init__.py +0 -0
- {getstack-0.6.0 → getstack-0.7.0}/src/getstack/_async/agents.py +0 -0
- {getstack-0.6.0 → getstack-0.7.0}/src/getstack/_async/audit.py +0 -0
- {getstack-0.6.0 → getstack-0.7.0}/src/getstack/_async/credentials.py +0 -0
- {getstack-0.6.0 → getstack-0.7.0}/src/getstack/_async/dropoffs.py +0 -0
- {getstack-0.6.0 → getstack-0.7.0}/src/getstack/_async/identity.py +0 -0
- {getstack-0.6.0 → getstack-0.7.0}/src/getstack/_async/intents.py +0 -0
- {getstack-0.6.0 → getstack-0.7.0}/src/getstack/_async/notifications.py +0 -0
- {getstack-0.6.0 → getstack-0.7.0}/src/getstack/_async/passports.py +0 -0
- {getstack-0.6.0 → getstack-0.7.0}/src/getstack/_async/proxy.py +0 -0
- {getstack-0.6.0 → getstack-0.7.0}/src/getstack/_async/reviews.py +0 -0
- {getstack-0.6.0 → getstack-0.7.0}/src/getstack/_async/scan.py +0 -0
- {getstack-0.6.0 → getstack-0.7.0}/src/getstack/_async/security_events.py +0 -0
- {getstack-0.6.0 → getstack-0.7.0}/src/getstack/_async/services.py +0 -0
- {getstack-0.6.0 → getstack-0.7.0}/src/getstack/_async/skills.py +0 -0
- {getstack-0.6.0 → getstack-0.7.0}/src/getstack/agent_auth.py +0 -0
- {getstack-0.6.0 → getstack-0.7.0}/src/getstack/agents.py +0 -0
- {getstack-0.6.0 → getstack-0.7.0}/src/getstack/audit.py +0 -0
- {getstack-0.6.0 → getstack-0.7.0}/src/getstack/auth.py +0 -0
- {getstack-0.6.0 → getstack-0.7.0}/src/getstack/browser_bootstrap.py +0 -0
- {getstack-0.6.0 → getstack-0.7.0}/src/getstack/client.py +0 -0
- {getstack-0.6.0 → getstack-0.7.0}/src/getstack/credentials.py +0 -0
- {getstack-0.6.0 → getstack-0.7.0}/src/getstack/dropoffs.py +0 -0
- {getstack-0.6.0 → getstack-0.7.0}/src/getstack/errors.py +0 -0
- {getstack-0.6.0 → getstack-0.7.0}/src/getstack/identity.py +0 -0
- {getstack-0.6.0 → getstack-0.7.0}/src/getstack/intents.py +0 -0
- {getstack-0.6.0 → getstack-0.7.0}/src/getstack/notifications.py +0 -0
- {getstack-0.6.0 → getstack-0.7.0}/src/getstack/passports.py +0 -0
- {getstack-0.6.0 → getstack-0.7.0}/src/getstack/proxy.py +0 -0
- {getstack-0.6.0 → getstack-0.7.0}/src/getstack/py.typed +0 -0
- {getstack-0.6.0 → getstack-0.7.0}/src/getstack/reviews.py +0 -0
- {getstack-0.6.0 → getstack-0.7.0}/src/getstack/scan.py +0 -0
- {getstack-0.6.0 → getstack-0.7.0}/src/getstack/security_events.py +0 -0
- {getstack-0.6.0 → getstack-0.7.0}/src/getstack/services.py +0 -0
- {getstack-0.6.0 → getstack-0.7.0}/src/getstack/skills.py +0 -0
- {getstack-0.6.0 → getstack-0.7.0}/src/getstack/types.py +0 -0
|
@@ -60,6 +60,11 @@ scripts/.openapi-cache/
|
|
|
60
60
|
# Local dev screenshots
|
|
61
61
|
*-stripe.png
|
|
62
62
|
|
|
63
|
+
# Root-level scratch images (founder workspace — never commit)
|
|
64
|
+
/*.png
|
|
65
|
+
/*.jpg
|
|
66
|
+
/*.jpeg
|
|
67
|
+
|
|
63
68
|
# YC application session exports (founder voice + redacted creds — never commit)
|
|
64
69
|
docs/yc-q18/
|
|
65
70
|
docs/yc-application-session-preface.md
|
|
@@ -52,6 +52,7 @@ from .security_events import SecurityEventService as SecurityEventSvc
|
|
|
52
52
|
from .skills import SkillService
|
|
53
53
|
from .identity import IdentityService
|
|
54
54
|
from .intents import IntentsService
|
|
55
|
+
from .missions import MissionsService
|
|
55
56
|
from .types import (
|
|
56
57
|
Agent,
|
|
57
58
|
Passport,
|
|
@@ -216,6 +217,7 @@ class Stack:
|
|
|
216
217
|
self.skills = SkillService(self._client)
|
|
217
218
|
self.identity = IdentityService(self._client)
|
|
218
219
|
self.intents = IntentsService(self._client)
|
|
220
|
+
self.missions = MissionsService(self._client)
|
|
219
221
|
|
|
220
222
|
@classmethod
|
|
221
223
|
def from_session(cls, session_token: str, **kwargs) -> Stack:
|
|
@@ -326,6 +328,7 @@ class AsyncStack:
|
|
|
326
328
|
from ._async.skills import AsyncSkillService
|
|
327
329
|
from ._async.identity import AsyncIdentityService
|
|
328
330
|
from ._async.intents import AsyncIntentsService
|
|
331
|
+
from ._async.missions import AsyncMissionsService
|
|
329
332
|
|
|
330
333
|
self.agents = AsyncAgentService(self._client)
|
|
331
334
|
self.passports = AsyncPassportService(self._client)
|
|
@@ -341,6 +344,7 @@ class AsyncStack:
|
|
|
341
344
|
self.skills = AsyncSkillService(self._client)
|
|
342
345
|
self.identity = AsyncIdentityService(self._client)
|
|
343
346
|
self.intents = AsyncIntentsService(self._client)
|
|
347
|
+
self.missions = AsyncMissionsService(self._client)
|
|
344
348
|
|
|
345
349
|
@classmethod
|
|
346
350
|
def from_session(cls, session_token: str, **kwargs) -> AsyncStack:
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"""Async mirror of MissionsService. Same surface, async/await."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from ..client import AsyncHttpClient
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class AsyncMissionsService:
|
|
11
|
+
def __init__(self, client: AsyncHttpClient):
|
|
12
|
+
self._client = client
|
|
13
|
+
|
|
14
|
+
async def open(
|
|
15
|
+
self,
|
|
16
|
+
intent_summary: str,
|
|
17
|
+
*,
|
|
18
|
+
intent_services: list[str] | None = None,
|
|
19
|
+
expected_counterparties: list[str] | None = None,
|
|
20
|
+
baseline_profile: dict[str, Any] | None = None,
|
|
21
|
+
expected_output_shape: dict[str, Any] | None = None,
|
|
22
|
+
max_actions: int | None = None,
|
|
23
|
+
max_dropoff_bytes: int | None = None,
|
|
24
|
+
coverage_cap_cents: int | None = None,
|
|
25
|
+
max_duration_seconds: int | None = None,
|
|
26
|
+
max_concurrent_intents: int | None = None,
|
|
27
|
+
max_actions_per_service: dict[str, int] | None = None,
|
|
28
|
+
cap_behavior: dict[str, str] | None = None,
|
|
29
|
+
expires_in_seconds: int | None = None,
|
|
30
|
+
parent_passport_services: list[str] | None = None,
|
|
31
|
+
) -> dict[str, Any]:
|
|
32
|
+
body: dict[str, Any] = {"intent_summary": intent_summary}
|
|
33
|
+
if intent_services is not None:
|
|
34
|
+
body["intent_services"] = intent_services
|
|
35
|
+
if expected_counterparties is not None:
|
|
36
|
+
body["expected_counterparties"] = expected_counterparties
|
|
37
|
+
if baseline_profile is not None:
|
|
38
|
+
body["baseline_profile"] = baseline_profile
|
|
39
|
+
if expected_output_shape is not None:
|
|
40
|
+
body["expected_output_shape"] = expected_output_shape
|
|
41
|
+
if max_actions is not None:
|
|
42
|
+
body["max_actions"] = max_actions
|
|
43
|
+
if max_dropoff_bytes is not None:
|
|
44
|
+
body["max_dropoff_bytes"] = max_dropoff_bytes
|
|
45
|
+
if coverage_cap_cents is not None:
|
|
46
|
+
body["coverage_cap_cents"] = coverage_cap_cents
|
|
47
|
+
if max_duration_seconds is not None:
|
|
48
|
+
body["max_duration_seconds"] = max_duration_seconds
|
|
49
|
+
if max_concurrent_intents is not None:
|
|
50
|
+
body["max_concurrent_intents"] = max_concurrent_intents
|
|
51
|
+
if max_actions_per_service is not None:
|
|
52
|
+
body["max_actions_per_service"] = max_actions_per_service
|
|
53
|
+
if cap_behavior is not None:
|
|
54
|
+
body["cap_behavior"] = cap_behavior
|
|
55
|
+
if expires_in_seconds is not None:
|
|
56
|
+
body["expires_in_seconds"] = expires_in_seconds
|
|
57
|
+
if parent_passport_services is not None:
|
|
58
|
+
body["parent_passport_services"] = parent_passport_services
|
|
59
|
+
return await self._client.request("POST", "/v1/missions", json=body)
|
|
60
|
+
|
|
61
|
+
async def complete(
|
|
62
|
+
self,
|
|
63
|
+
mission_id: str,
|
|
64
|
+
*,
|
|
65
|
+
output: dict[str, Any] | None = None,
|
|
66
|
+
) -> dict[str, Any]:
|
|
67
|
+
body: dict[str, Any] = {}
|
|
68
|
+
if output is not None:
|
|
69
|
+
body["output"] = output
|
|
70
|
+
return await self._client.request(
|
|
71
|
+
"POST", f"/v1/missions/{mission_id}/complete", json=body
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
async def revoke(
|
|
75
|
+
self,
|
|
76
|
+
mission_id: str,
|
|
77
|
+
*,
|
|
78
|
+
reason: str,
|
|
79
|
+
notes: str | None = None,
|
|
80
|
+
) -> dict[str, Any]:
|
|
81
|
+
body: dict[str, Any] = {"reason": reason}
|
|
82
|
+
if notes is not None:
|
|
83
|
+
body["notes"] = notes
|
|
84
|
+
return await self._client.request(
|
|
85
|
+
"POST", f"/v1/missions/{mission_id}/revoke", json=body
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
async def get(self, mission_id: str) -> dict[str, Any]:
|
|
89
|
+
return await self._client.request("GET", f"/v1/missions/{mission_id}")
|
|
90
|
+
|
|
91
|
+
async def list(
|
|
92
|
+
self,
|
|
93
|
+
*,
|
|
94
|
+
status: str | None = None,
|
|
95
|
+
page: int | None = None,
|
|
96
|
+
limit: int | None = None,
|
|
97
|
+
) -> dict[str, Any]:
|
|
98
|
+
params: dict[str, Any] = {}
|
|
99
|
+
if status is not None:
|
|
100
|
+
params["status"] = status
|
|
101
|
+
if page is not None:
|
|
102
|
+
params["page"] = page
|
|
103
|
+
if limit is not None:
|
|
104
|
+
params["limit"] = limit
|
|
105
|
+
path = "/v1/missions"
|
|
106
|
+
if params:
|
|
107
|
+
from urllib.parse import urlencode
|
|
108
|
+
|
|
109
|
+
path = f"{path}?{urlencode(params)}"
|
|
110
|
+
return await self._client.request("GET", path)
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"""Mission lifecycle — open / complete / revoke / get / list.
|
|
2
|
+
|
|
3
|
+
Phase 5.0 sub-chunk 5.0.8.
|
|
4
|
+
|
|
5
|
+
open() Open a new mission. Returns mission_id (ms_*) + the
|
|
6
|
+
signed mission_open claim_id.
|
|
7
|
+
complete() Mark a mission complete (terminal_state='completed_successful').
|
|
8
|
+
Idempotent; second call returns the prior terminal state.
|
|
9
|
+
revoke() Revoke a mission. reason='adversarial' triggers forward
|
|
10
|
+
cascade (passports bound to the mission also revoke);
|
|
11
|
+
reason='operator_initiated_clean' leaves passports alive.
|
|
12
|
+
get() Fetch full mission view by id.
|
|
13
|
+
list() List missions for the calling operator.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
from typing import Any
|
|
19
|
+
|
|
20
|
+
from .client import HttpClient
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class MissionsService:
|
|
24
|
+
def __init__(self, client: HttpClient):
|
|
25
|
+
self._client = client
|
|
26
|
+
|
|
27
|
+
def open(
|
|
28
|
+
self,
|
|
29
|
+
intent_summary: str,
|
|
30
|
+
*,
|
|
31
|
+
intent_services: list[str] | None = None,
|
|
32
|
+
expected_counterparties: list[str] | None = None,
|
|
33
|
+
baseline_profile: dict[str, Any] | None = None,
|
|
34
|
+
expected_output_shape: dict[str, Any] | None = None,
|
|
35
|
+
max_actions: int | None = None,
|
|
36
|
+
max_dropoff_bytes: int | None = None,
|
|
37
|
+
coverage_cap_cents: int | None = None,
|
|
38
|
+
max_duration_seconds: int | None = None,
|
|
39
|
+
max_concurrent_intents: int | None = None,
|
|
40
|
+
max_actions_per_service: dict[str, int] | None = None,
|
|
41
|
+
cap_behavior: dict[str, str] | None = None,
|
|
42
|
+
expires_in_seconds: int | None = None,
|
|
43
|
+
parent_passport_services: list[str] | None = None,
|
|
44
|
+
) -> dict[str, Any]:
|
|
45
|
+
"""Open a new mission. Returns dict with mission_id, claim_id,
|
|
46
|
+
expires_at."""
|
|
47
|
+
body: dict[str, Any] = {"intent_summary": intent_summary}
|
|
48
|
+
if intent_services is not None:
|
|
49
|
+
body["intent_services"] = intent_services
|
|
50
|
+
if expected_counterparties is not None:
|
|
51
|
+
body["expected_counterparties"] = expected_counterparties
|
|
52
|
+
if baseline_profile is not None:
|
|
53
|
+
body["baseline_profile"] = baseline_profile
|
|
54
|
+
if expected_output_shape is not None:
|
|
55
|
+
body["expected_output_shape"] = expected_output_shape
|
|
56
|
+
if max_actions is not None:
|
|
57
|
+
body["max_actions"] = max_actions
|
|
58
|
+
if max_dropoff_bytes is not None:
|
|
59
|
+
body["max_dropoff_bytes"] = max_dropoff_bytes
|
|
60
|
+
if coverage_cap_cents is not None:
|
|
61
|
+
body["coverage_cap_cents"] = coverage_cap_cents
|
|
62
|
+
if max_duration_seconds is not None:
|
|
63
|
+
body["max_duration_seconds"] = max_duration_seconds
|
|
64
|
+
if max_concurrent_intents is not None:
|
|
65
|
+
body["max_concurrent_intents"] = max_concurrent_intents
|
|
66
|
+
if max_actions_per_service is not None:
|
|
67
|
+
body["max_actions_per_service"] = max_actions_per_service
|
|
68
|
+
if cap_behavior is not None:
|
|
69
|
+
body["cap_behavior"] = cap_behavior
|
|
70
|
+
if expires_in_seconds is not None:
|
|
71
|
+
body["expires_in_seconds"] = expires_in_seconds
|
|
72
|
+
if parent_passport_services is not None:
|
|
73
|
+
body["parent_passport_services"] = parent_passport_services
|
|
74
|
+
return self._client.request("POST", "/v1/missions", json=body)
|
|
75
|
+
|
|
76
|
+
def complete(
|
|
77
|
+
self,
|
|
78
|
+
mission_id: str,
|
|
79
|
+
*,
|
|
80
|
+
output: dict[str, Any] | None = None,
|
|
81
|
+
) -> dict[str, Any]:
|
|
82
|
+
"""Mark a mission complete. Returns dict with mission_id, claim_id,
|
|
83
|
+
terminal_state, completed_at, transitioned."""
|
|
84
|
+
body: dict[str, Any] = {}
|
|
85
|
+
if output is not None:
|
|
86
|
+
body["output"] = output
|
|
87
|
+
return self._client.request(
|
|
88
|
+
"POST", f"/v1/missions/{mission_id}/complete", json=body
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
def revoke(
|
|
92
|
+
self,
|
|
93
|
+
mission_id: str,
|
|
94
|
+
*,
|
|
95
|
+
reason: str,
|
|
96
|
+
notes: str | None = None,
|
|
97
|
+
) -> dict[str, Any]:
|
|
98
|
+
"""Revoke a mission. reason in {'adversarial', 'operator_initiated_clean'}."""
|
|
99
|
+
body: dict[str, Any] = {"reason": reason}
|
|
100
|
+
if notes is not None:
|
|
101
|
+
body["notes"] = notes
|
|
102
|
+
return self._client.request(
|
|
103
|
+
"POST", f"/v1/missions/{mission_id}/revoke", json=body
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
def get(self, mission_id: str) -> dict[str, Any]:
|
|
107
|
+
"""Fetch a mission by id. 404 for unknown or cross-tenant."""
|
|
108
|
+
return self._client.request("GET", f"/v1/missions/{mission_id}")
|
|
109
|
+
|
|
110
|
+
def list(
|
|
111
|
+
self,
|
|
112
|
+
*,
|
|
113
|
+
status: str | None = None,
|
|
114
|
+
page: int | None = None,
|
|
115
|
+
limit: int | None = None,
|
|
116
|
+
) -> dict[str, Any]:
|
|
117
|
+
"""List missions for the calling operator. Returns dict with `items`."""
|
|
118
|
+
params: dict[str, Any] = {}
|
|
119
|
+
if status is not None:
|
|
120
|
+
params["status"] = status
|
|
121
|
+
if page is not None:
|
|
122
|
+
params["page"] = page
|
|
123
|
+
if limit is not None:
|
|
124
|
+
params["limit"] = limit
|
|
125
|
+
path = "/v1/missions"
|
|
126
|
+
if params:
|
|
127
|
+
from urllib.parse import urlencode
|
|
128
|
+
|
|
129
|
+
path = f"{path}?{urlencode(params)}"
|
|
130
|
+
return self._client.request("GET", path)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|