You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(protocol)!: narrow the supported scope to sixteen events (#3)
`session:input_state`, `session:required_action` and `session:task_ready` leave
the supported surface. All three continue to be emitted by the server and to
reach callers unchanged; the SDK no longer models them and makes no commitment
about them.
## Why each one goes
`session:input_state` described whether the composer accepts input. It was also
the SDK's signal that a turn had ended, and recording a live session showed why
that does not hold: the event arrives twice at the very start of a turn, before
the agent has said anything. A turn ending on it truncates the reply.
`session:required_action` restated in a dedicated event what other events
already carry.
`session:task_ready` reports what a task will cost. The server computes
`confirmed` from the balance and, when it is sufficient, starts the task itself
— so the event asks nothing of a client and its absence costs a client nothing.
## What a client keeps
A session stopped on its credit balance is still visible: `session:state` is in
scope and its values include `credits_exhausted` and `task_paused`. Together
with `session:restriction` and `session:error` — and `is_stale` over REST for an
expired session — every condition that halts a session remains reportable except
one.
The exception is an outstanding phone verification, which is a provisioning
prerequisite with no in-session remedy and now no in-session signal. The README
says so rather than leaving it implicit.
`session:task_ready` was also counted towards the SDK's judgement that an agent
had responded, which governs how long a turn waits between events. Removing it
narrows that set — an accurate narrowing, since a cost estimate is not a reply.
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: README.md
+26-19Lines changed: 26 additions & 19 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -72,9 +72,7 @@ payloads, and semantics change compatibly or with notice.
72
72
| Event | What it is for |
73
73
|---|---|
74
74
|`session:state`| Where the task stands in its lifecycle |
75
-
|`session:input_state`| Whether input is accepted, and the reason when it is not. This is where a blocked session says why |
76
75
|`session:message_status`| What became of a message you sent — the only way to tell a rejected or rate-limited one from one still being worked on |
77
-
|`session:required_action`| Whether the session is waiting on you |
78
76
|`session:update_title`| The session title, as the agent revises it |
79
77
|`session:restriction`| An account restriction. The only statement that a task will not complete |
80
78
@@ -88,7 +86,6 @@ payloads, and semantics change compatibly or with notice.
88
86
89
87
| Event | What it is for |
90
88
|---|---|
91
-
|`session:task_ready`| What the task will cost in credits, and whether it is authorised. When the balance covers it the server starts the task itself and this is informational; when it does not, the session waits |
92
89
|`session:task_finished`| The result. `completion.result_title`, `result_description` and `outcome_narrative` carry the text; `completion.summary` is quantified, and `brief` is its only prose |
93
90
|`session:tool_status`| The record of one asynchronous operation. An outbound call reports here: the number, the duration, the credits, and `summary.text`. It updates in place, reusing its `message_id`, so expect several with the same one |
94
91
@@ -170,26 +167,35 @@ has stopped.
170
167
`rebuild()` returns messages of every type, including unsupported ones.
171
168
Filtering them is yours to do.
172
169
173
-
## Blocked sessions
170
+
## When a session cannot proceed
174
171
175
-
When the composer is disabled, `session:input_state` carries the reason. Read it
176
-
from there rather than inferring it from which events did or did not arrive.
172
+
`session:state` reports where the task stands, and several of its values say
173
+
that nothing further will arrive until something changes outside the session:
177
174
178
175
```python
179
-
from pine_assistant importInputState, S2CEvent
180
-
181
-
if event.type == S2CEvent.SESSION_INPUT_STATE:
182
-
state =InputState.model_validate(event.data)
183
-
if state.awaiting_credits:
184
-
...#cost is on session:task_ready; retry once the balance is restored
185
-
if state.needs_phone_verification:
186
-
...#no in-session remedy
176
+
from pine_assistant import S2CEvent
177
+
178
+
if event.type == S2CEvent.SESSION_STATE:
179
+
state = (event.dataor {}).get("content")
180
+
if statein ("credits_exhausted", "task_paused"):
181
+
...#waiting on the account, not on the agent
182
+
if statein ("task_finished", "task_cancelled"):
183
+
...#the task is over
187
184
```
188
185
189
-
An expired session has no reason code of its own — it presents only as a
190
-
disabled composer. Expiry is the `is_stale` field on the session object, over
191
-
REST. On finding one expired, create a new session and reference the old one in
192
-
your first message:
186
+
Two more events state a stop outright:
187
+
188
+
```python
189
+
if event.type == S2CEvent.SESSION_RESTRICTION:
190
+
...# an account restriction — the task will not complete
191
+
if event.type == S2CEvent.SESSION_ERROR:
192
+
...# the only channel for server-reported failures
193
+
```
194
+
195
+
An expired session is read over REST, from the `is_stale` field on the session
196
+
object — expiry is a property of the session, not one of its states. On finding
197
+
one expired, create a new session and reference the old one in your first
198
+
message:
193
199
194
200
```python
195
201
new =await client.sessions.create()
@@ -202,7 +208,8 @@ Two conditions have no remedy once a session is running:
202
208
203
209
-**Metered billing.** The account must be billed against a credit balance. On
204
210
the alternative path a session halts at a payment step the SDK cannot answer.
205
-
-**Phone verification.** Must be completed at provisioning time.
211
+
-**Phone verification.** Must be completed at provisioning time. It has no
0 commit comments