ellipsis-dev 0.43.0__tar.gz → 0.45.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: ellipsis-dev
3
- Version: 0.43.0
3
+ Version: 0.45.0
4
4
  Summary: Python SDK for the Ellipsis agents platform: every /v1 operation, sync and async.
5
5
  Project-URL: Homepage, https://www.ellipsis.dev
6
6
  Project-URL: Documentation, https://www.ellipsis.dev/docs/api
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "ellipsis-dev"
7
- version = "0.43.0"
7
+ version = "0.45.0"
8
8
  description = "Python SDK for the Ellipsis agents platform: every /v1 operation, sync and async."
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -1809,64 +1809,6 @@ class _SyncSessions(SyncSessionsSugar):
1809
1809
  def __init__(self, transport: Transport) -> None:
1810
1810
  self._transport = transport
1811
1811
 
1812
- def analytics(
1813
- self,
1814
- id: str,
1815
- ) -> models.SessionAnalytics:
1816
- """Get Session Analytics
1817
-
1818
- Measured tokens and spend over time, plus estimated content cost.
1819
-
1820
- Token lanes use the request's saved rates. Content attribution
1821
- apportions input/cache spend by text size, counting carried context
1822
- on every request. It is an estimate, not a tool call fee.
1823
- Only the latest 200 retained request bodies are inspected; missing
1824
- or unsupported context remains explicitly unattributed. No raw
1825
- prompts or tool results are returned. Session tokens may read only
1826
- their own session's analytics.
1827
-
1828
- Required permissions: read:sessions.
1829
- API key: Supported.
1830
- CLI user token: Supported.
1831
- Session token: Requires the ellipsis:api scope and the required grants in the token's permissions.ellipsis configuration. Only the token's own session.
1832
- Higher permission levels include lower levels: read < write < delete.
1833
- Grant match patterns can further restrict access to individual resources.
1834
- """
1835
- path = f"/v1/sessions/{_quote(id)}/analytics"
1836
- response = self._transport.request(
1837
- "GET", path, response_model=models.SessionAnalytics
1838
- )
1839
- assert response is not None
1840
- return response
1841
-
1842
- def diff(
1843
- self,
1844
- id: str,
1845
- ) -> models.SessionDiffResponse:
1846
- """Get Session Diff
1847
-
1848
- Return the session's uncommitted changes as a patch.
1849
-
1850
- One unified-diff section per changed file, captured from the
1851
- environment's working tree when the session ended. The per-file
1852
- counts ride on the session itself (`git.repos[].files`); this
1853
- is the text behind them. Empty when the tree was clean. A
1854
- session token may read only its own session's diff.
1855
-
1856
- Required permissions: read:sessions.
1857
- API key: Supported.
1858
- CLI user token: Supported.
1859
- Session token: Requires the ellipsis:api scope and the required grants in the token's permissions.ellipsis configuration. Only the token's own session.
1860
- Higher permission levels include lower levels: read < write < delete.
1861
- Grant match patterns can further restrict access to individual resources.
1862
- """
1863
- path = f"/v1/sessions/{_quote(id)}/diff"
1864
- response = self._transport.request(
1865
- "GET", path, response_model=models.SessionDiffResponse
1866
- )
1867
- assert response is not None
1868
- return response
1869
-
1870
1812
  def download(
1871
1813
  self,
1872
1814
  id: str,
@@ -1927,31 +1869,6 @@ class _SyncSessions(SyncSessionsSugar):
1927
1869
  assert response is not None
1928
1870
  return response
1929
1871
 
1930
- def git(
1931
- self,
1932
- id: str,
1933
- ) -> models.SessionGitResponse:
1934
- """Get Session Git
1935
-
1936
- The session's GitHub-side git view: its commits, and each PR it
1937
- opened joined to the live gh_prs row and reviews. The identity list
1938
- (output_git) rides the session itself over the WebSocket; this is
1939
- the join a "run" notify tells an open pane to refetch.
1940
-
1941
- Required permissions: read:sessions.
1942
- API key: Supported.
1943
- CLI user token: Supported.
1944
- Session token: Requires the ellipsis:api scope and the required grants in the token's permissions.ellipsis configuration.
1945
- Higher permission levels include lower levels: read < write < delete.
1946
- Grant match patterns can further restrict access to individual resources.
1947
- """
1948
- path = f"/v1/sessions/{_quote(id)}/git"
1949
- response = self._transport.request(
1950
- "GET", path, response_model=models.SessionGitResponse
1951
- )
1952
- assert response is not None
1953
- return response
1954
-
1955
1872
  def image(
1956
1873
  self,
1957
1874
  session_id: str,
@@ -2289,6 +2206,35 @@ class _SyncSessions(SyncSessionsSugar):
2289
2206
  assert response is not None
2290
2207
  return response
2291
2208
 
2209
+ def timeline(
2210
+ self,
2211
+ id: str,
2212
+ ) -> models.SessionTimelineResponse:
2213
+ """Get Session Timeline
2214
+
2215
+ What the session did, newest first. Each time its environment
2216
+ started preparing, became ready, fell asleep after its idle window,
2217
+ and woke for the next message, its close, and what it did on
2218
+ GitHub through Ellipsis, such as the repositories it cloned, its pushes,
2219
+ what it did to pull requests and issues, the files it committed
2220
+ through the API, releases, and workflow runs, read from the
2221
+ requests its environment sent. A run of the same GitHub action is
2222
+ one entry.
2223
+
2224
+ Required permissions: read:sessions.
2225
+ API key: Supported.
2226
+ CLI user token: Supported.
2227
+ Session token: Requires the ellipsis:api scope and the required grants in the token's permissions.ellipsis configuration. Only the token's own session.
2228
+ Higher permission levels include lower levels: read < write < delete.
2229
+ Grant match patterns can further restrict access to individual resources.
2230
+ """
2231
+ path = f"/v1/sessions/{_quote(id)}/timeline"
2232
+ response = self._transport.request(
2233
+ "GET", path, response_model=models.SessionTimelineResponse
2234
+ )
2235
+ assert response is not None
2236
+ return response
2237
+
2292
2238
  def update(
2293
2239
  self,
2294
2240
  id: str,
@@ -4757,64 +4703,6 @@ class _AsyncSessions(AsyncSessionsSugar):
4757
4703
  def __init__(self, transport: AsyncTransport) -> None:
4758
4704
  self._transport = transport
4759
4705
 
4760
- async def analytics(
4761
- self,
4762
- id: str,
4763
- ) -> models.SessionAnalytics:
4764
- """Get Session Analytics
4765
-
4766
- Measured tokens and spend over time, plus estimated content cost.
4767
-
4768
- Token lanes use the request's saved rates. Content attribution
4769
- apportions input/cache spend by text size, counting carried context
4770
- on every request. It is an estimate, not a tool call fee.
4771
- Only the latest 200 retained request bodies are inspected; missing
4772
- or unsupported context remains explicitly unattributed. No raw
4773
- prompts or tool results are returned. Session tokens may read only
4774
- their own session's analytics.
4775
-
4776
- Required permissions: read:sessions.
4777
- API key: Supported.
4778
- CLI user token: Supported.
4779
- Session token: Requires the ellipsis:api scope and the required grants in the token's permissions.ellipsis configuration. Only the token's own session.
4780
- Higher permission levels include lower levels: read < write < delete.
4781
- Grant match patterns can further restrict access to individual resources.
4782
- """
4783
- path = f"/v1/sessions/{_quote(id)}/analytics"
4784
- response = await self._transport.request(
4785
- "GET", path, response_model=models.SessionAnalytics
4786
- )
4787
- assert response is not None
4788
- return response
4789
-
4790
- async def diff(
4791
- self,
4792
- id: str,
4793
- ) -> models.SessionDiffResponse:
4794
- """Get Session Diff
4795
-
4796
- Return the session's uncommitted changes as a patch.
4797
-
4798
- One unified-diff section per changed file, captured from the
4799
- environment's working tree when the session ended. The per-file
4800
- counts ride on the session itself (`git.repos[].files`); this
4801
- is the text behind them. Empty when the tree was clean. A
4802
- session token may read only its own session's diff.
4803
-
4804
- Required permissions: read:sessions.
4805
- API key: Supported.
4806
- CLI user token: Supported.
4807
- Session token: Requires the ellipsis:api scope and the required grants in the token's permissions.ellipsis configuration. Only the token's own session.
4808
- Higher permission levels include lower levels: read < write < delete.
4809
- Grant match patterns can further restrict access to individual resources.
4810
- """
4811
- path = f"/v1/sessions/{_quote(id)}/diff"
4812
- response = await self._transport.request(
4813
- "GET", path, response_model=models.SessionDiffResponse
4814
- )
4815
- assert response is not None
4816
- return response
4817
-
4818
4706
  async def download(
4819
4707
  self,
4820
4708
  id: str,
@@ -4875,31 +4763,6 @@ class _AsyncSessions(AsyncSessionsSugar):
4875
4763
  assert response is not None
4876
4764
  return response
4877
4765
 
4878
- async def git(
4879
- self,
4880
- id: str,
4881
- ) -> models.SessionGitResponse:
4882
- """Get Session Git
4883
-
4884
- The session's GitHub-side git view: its commits, and each PR it
4885
- opened joined to the live gh_prs row and reviews. The identity list
4886
- (output_git) rides the session itself over the WebSocket; this is
4887
- the join a "run" notify tells an open pane to refetch.
4888
-
4889
- Required permissions: read:sessions.
4890
- API key: Supported.
4891
- CLI user token: Supported.
4892
- Session token: Requires the ellipsis:api scope and the required grants in the token's permissions.ellipsis configuration.
4893
- Higher permission levels include lower levels: read < write < delete.
4894
- Grant match patterns can further restrict access to individual resources.
4895
- """
4896
- path = f"/v1/sessions/{_quote(id)}/git"
4897
- response = await self._transport.request(
4898
- "GET", path, response_model=models.SessionGitResponse
4899
- )
4900
- assert response is not None
4901
- return response
4902
-
4903
4766
  async def image(
4904
4767
  self,
4905
4768
  session_id: str,
@@ -5237,6 +5100,35 @@ class _AsyncSessions(AsyncSessionsSugar):
5237
5100
  assert response is not None
5238
5101
  return response
5239
5102
 
5103
+ async def timeline(
5104
+ self,
5105
+ id: str,
5106
+ ) -> models.SessionTimelineResponse:
5107
+ """Get Session Timeline
5108
+
5109
+ What the session did, newest first. Each time its environment
5110
+ started preparing, became ready, fell asleep after its idle window,
5111
+ and woke for the next message, its close, and what it did on
5112
+ GitHub through Ellipsis, such as the repositories it cloned, its pushes,
5113
+ what it did to pull requests and issues, the files it committed
5114
+ through the API, releases, and workflow runs, read from the
5115
+ requests its environment sent. A run of the same GitHub action is
5116
+ one entry.
5117
+
5118
+ Required permissions: read:sessions.
5119
+ API key: Supported.
5120
+ CLI user token: Supported.
5121
+ Session token: Requires the ellipsis:api scope and the required grants in the token's permissions.ellipsis configuration. Only the token's own session.
5122
+ Higher permission levels include lower levels: read < write < delete.
5123
+ Grant match patterns can further restrict access to individual resources.
5124
+ """
5125
+ path = f"/v1/sessions/{_quote(id)}/timeline"
5126
+ response = await self._transport.request(
5127
+ "GET", path, response_model=models.SessionTimelineResponse
5128
+ )
5129
+ assert response is not None
5130
+ return response
5131
+
5240
5132
  async def update(
5241
5133
  self,
5242
5134
  id: str,
@@ -117,6 +117,7 @@ def parse_frame(data: str | bytes) -> frames.StreamFrame | None:
117
117
 
118
118
  _FRAME_TYPES: dict[Any, Any] = {
119
119
  "session": frames.SessionFrame,
120
+ "timeline": frames.TimelineFrame,
120
121
  "records": frames.RecordsFrame,
121
122
  "delta": frames.DeltaFrame,
122
123
  "heartbeat": frames.HeartbeatFrame,
@@ -75,12 +75,37 @@ class SessionFrame(EllipsisModel):
75
75
  type: Literal["session"]
76
76
 
77
77
 
78
+ class TimelineFrame(EllipsisModel):
79
+ """The session's whole timeline, newest first: sent after the first session
80
+ frame, and resent whole whenever it changes. The same events
81
+ `GET /v1/sessions/{id}/timeline` returns.
82
+ """
83
+
84
+ events: list[
85
+ Union[
86
+ models.EnvironmentTimelineEvent,
87
+ models.SessionClosedTimelineEvent,
88
+ models.GithubCloneTimelineEvent,
89
+ models.GithubPushTimelineEvent,
90
+ models.GithubCommitTimelineEvent,
91
+ models.GithubPullRequestTimelineEvent,
92
+ models.GithubIssueTimelineEvent,
93
+ models.GithubReleaseTimelineEvent,
94
+ models.GithubWorkflowTimelineEvent,
95
+ models.GithubRefusedTimelineEvent,
96
+ models.GithubOtherTimelineEvent,
97
+ ]
98
+ ] = Field(description="What the session did, newest first.")
99
+ type: Literal["timeline"]
100
+
101
+
78
102
  StreamFrame = Union[
79
103
  DeltaFrame,
80
104
  ErrorFrame,
81
105
  HeartbeatFrame,
82
106
  RecordsFrame,
83
107
  SessionFrame,
108
+ TimelineFrame,
84
109
  ]
85
110
  """One server->client frame. Unknown frame types must be ignored
86
111
  (additive server changes are not a protocol break)."""
@@ -92,5 +117,6 @@ __all__ = [
92
117
  "HeartbeatFrame",
93
118
  "RecordsFrame",
94
119
  "SessionFrame",
120
+ "TimelineFrame",
95
121
  "StreamFrame",
96
122
  ]
@@ -70,6 +70,7 @@ CustomerAuditLogEventType = Literal[
70
70
  "credit_granted",
71
71
  "refund_issued",
72
72
  "auto_recharge_updated",
73
+ "platform_fee_updated",
73
74
  ]
74
75
 
75
76
 
@@ -615,17 +616,6 @@ class CodexConfig_Output(EllipsisModel):
615
616
  )
616
617
 
617
618
 
618
- class Duration_Output(EllipsisModel):
619
- """A duration as explicit units, summed. Set any of `hours`/`minutes`/
620
- `seconds` (at least one). The alternative to the `30m`-style shorthand
621
- string wherever a duration is accepted.
622
- """
623
-
624
- hours: Union[int, None]
625
- minutes: Union[int, None]
626
- seconds: Union[int, None]
627
-
628
-
629
619
  class MemorySize_Output(EllipsisModel):
630
620
  """A memory size as explicit units, summed (binary: 1GB = 1024MB = 1024MiB).
631
621
  Set any of `gb`/`mb` (at least one). The alternative to the `8GB`-style
@@ -637,29 +627,27 @@ class MemorySize_Output(EllipsisModel):
637
627
 
638
628
 
639
629
  class ComputeConfig_Output(EllipsisModel):
640
- """Environment compute sizing. Every field is optional; an omitted field
641
- inherits the platform default (2 vCPU / 4096 MiB / 3600s). A resolved value
642
- outside the platform bounds fails validation loudly (a sync error on the
643
- config) rather than being clamped silently.
630
+ """The size and lifetime of the environment. Every field is optional. An
631
+ omitted field takes the platform default (2 vCPUs, 4096 MiB, a 4h timeout,
632
+ 10m idle). A value outside the platform bounds fails validation.
644
633
 
645
- `memory` and `timeout` each accept a shorthand string ("8GB", "30m") or an
646
- explicit units object ({gb: 8}, {minutes: 30}); the `memory_mib` /
647
- `timeout_seconds` properties resolve either form to the canonical integer
648
- the environment is sized with.
634
+ `memory` accepts a string such as `8GB` or an object such as `{gb: 8}`.
635
+ `timeout` and `idle` accept a duration string such as `30m`, `8h`, or
636
+ `1h30m`.
649
637
 
650
- `timeout` is the max wall-clock the agent may run in one environment before
651
- it is stopped, capped at 1h (equal to the default, so today the knob only
652
- shortens a session; the cap matches the 1-hour validity of the session's
653
- GitHub token).
638
+ `timeout` is the longest one message's work may run before it is stopped,
639
+ 1m to 22h, default 4h. The message ends `stopped` with reason `timeout`.
654
640
 
655
- Compute currently uses a temporary flat one-cent amount each time an
656
- environment is started for a session, subject to the account's existing
657
- free-compute exemptions.
641
+ `idle` is how long the environment stays awake after the agent finishes
642
+ with no message waiting, 10s to 1h, default 10m. Then it pauses, and the
643
+ next message resumes it. Only an interactive session pauses. A session
644
+ that runs once ends when its message ends.
658
645
  """
659
646
 
660
647
  cpu: Union[int, None]
648
+ idle: Union[str, None]
661
649
  memory: Union[str, MemorySize_Output, None]
662
- timeout: Union[str, Duration_Output, None]
650
+ timeout: Union[str, None]
663
651
 
664
652
 
665
653
  class EnvironmentBaseBuild_Output(EllipsisModel):
@@ -1428,17 +1416,6 @@ class CodexConfig_Input(EllipsisModel):
1428
1416
  )
1429
1417
 
1430
1418
 
1431
- class Duration_Input(EllipsisModel):
1432
- """A duration as explicit units, summed. Set any of `hours`/`minutes`/
1433
- `seconds` (at least one). The alternative to the `30m`-style shorthand
1434
- string wherever a duration is accepted.
1435
- """
1436
-
1437
- hours: Union[int, None] = None
1438
- minutes: Union[int, None] = None
1439
- seconds: Union[int, None] = None
1440
-
1441
-
1442
1419
  class MemorySize_Input(EllipsisModel):
1443
1420
  """A memory size as explicit units, summed (binary: 1GB = 1024MB = 1024MiB).
1444
1421
  Set any of `gb`/`mb` (at least one). The alternative to the `8GB`-style
@@ -1450,29 +1427,27 @@ class MemorySize_Input(EllipsisModel):
1450
1427
 
1451
1428
 
1452
1429
  class ComputeConfig_Input(EllipsisModel):
1453
- """Environment compute sizing. Every field is optional; an omitted field
1454
- inherits the platform default (2 vCPU / 4096 MiB / 3600s). A resolved value
1455
- outside the platform bounds fails validation loudly (a sync error on the
1456
- config) rather than being clamped silently.
1430
+ """The size and lifetime of the environment. Every field is optional. An
1431
+ omitted field takes the platform default (2 vCPUs, 4096 MiB, a 4h timeout,
1432
+ 10m idle). A value outside the platform bounds fails validation.
1457
1433
 
1458
- `memory` and `timeout` each accept a shorthand string ("8GB", "30m") or an
1459
- explicit units object ({gb: 8}, {minutes: 30}); the `memory_mib` /
1460
- `timeout_seconds` properties resolve either form to the canonical integer
1461
- the environment is sized with.
1434
+ `memory` accepts a string such as `8GB` or an object such as `{gb: 8}`.
1435
+ `timeout` and `idle` accept a duration string such as `30m`, `8h`, or
1436
+ `1h30m`.
1462
1437
 
1463
- `timeout` is the max wall-clock the agent may run in one environment before
1464
- it is stopped, capped at 1h (equal to the default, so today the knob only
1465
- shortens a session; the cap matches the 1-hour validity of the session's
1466
- GitHub token).
1438
+ `timeout` is the longest one message's work may run before it is stopped,
1439
+ 1m to 22h, default 4h. The message ends `stopped` with reason `timeout`.
1467
1440
 
1468
- Compute currently uses a temporary flat one-cent amount each time an
1469
- environment is started for a session, subject to the account's existing
1470
- free-compute exemptions.
1441
+ `idle` is how long the environment stays awake after the agent finishes
1442
+ with no message waiting, 10s to 1h, default 10m. Then it pauses, and the
1443
+ next message resumes it. Only an interactive session pauses. A session
1444
+ that runs once ends when its message ends.
1471
1445
  """
1472
1446
 
1473
1447
  cpu: Union[int, None] = None
1448
+ idle: Union[str, None] = None
1474
1449
  memory: Union[str, MemorySize_Input, None] = None
1475
- timeout: Union[str, Duration_Input, None] = None
1450
+ timeout: Union[str, None] = None
1476
1451
 
1477
1452
 
1478
1453
  class EnvironmentBaseBuild_Input(EllipsisModel):
@@ -3508,6 +3483,16 @@ Not derivable from the row: `environment_id` says WHICH environment, not
3508
3483
  how it was chosen, and is null for the built-in basic environment."""
3509
3484
 
3510
3485
 
3486
+ class EnvironmentTimelineEvent(EllipsisModel):
3487
+ """The session's environment started preparing, became ready, was paused
3488
+ after its idle window, or was resumed for the next message.
3489
+ """
3490
+
3491
+ action: Literal["started", "ready", "asleep", "awake"]
3492
+ at: datetime
3493
+ type: Literal["environment"]
3494
+
3495
+
3511
3496
  class EnvironmentsListResponse(EllipsisModel):
3512
3497
  """The caller's saved environments."""
3513
3498
 
@@ -3545,6 +3530,7 @@ ErrorReason = Literal[
3545
3530
  "execution_disabled",
3546
3531
  "interrupted",
3547
3532
  "stopped",
3533
+ "timeout",
3548
3534
  ]
3549
3535
  """Why a message failed, was stopped, or was cancelled."""
3550
3536
 
@@ -3912,6 +3898,30 @@ class GithubCheckSuiteEvent(EllipsisModel):
3912
3898
  url: str
3913
3899
 
3914
3900
 
3901
+ class GithubCloneTimelineEvent(EllipsisModel):
3902
+ """A repository cloned into the environment."""
3903
+
3904
+ at: datetime = Field(description="When the last request behind it ended.")
3905
+ ok: bool = Field(description="Whether GitHub did it.")
3906
+ repository: str
3907
+ type: Literal["github.clone"]
3908
+
3909
+
3910
+ class GithubCommitTimelineEvent(EllipsisModel):
3911
+ """Files committed through the API, one entry for each run of commits to
3912
+ the same branch.
3913
+ """
3914
+
3915
+ at: datetime = Field(description="When the last request behind it ended.")
3916
+ branch: Union[str, None] = Field(
3917
+ description="Null when the repository's default branch."
3918
+ )
3919
+ ok: bool = Field(description="Whether GitHub did it.")
3920
+ paths: list[str] = Field(description="The files written or deleted.")
3921
+ repository: str
3922
+ type: Literal["github.commit"]
3923
+
3924
+
3915
3925
  class GithubConfigEllipsis(EllipsisModel):
3916
3926
  """The product namespace of a GitHub routing file, with an explicit kind."""
3917
3927
 
@@ -4024,6 +4034,19 @@ class GithubIssueEvent(EllipsisModel):
4024
4034
  url: str
4025
4035
 
4026
4036
 
4037
+ class GithubIssueTimelineEvent(EllipsisModel):
4038
+ action: Literal["opened", "edited", "commented", "closed", "reopened"]
4039
+ at: datetime = Field(description="When the last request behind it ended.")
4040
+ number: Union[int, None] = Field(
4041
+ description="Null when Ellipsis could not tell which."
4042
+ )
4043
+ ok: bool = Field(description="Whether GitHub did it.")
4044
+ repository: Union[str, None] = Field(
4045
+ description="Null when Ellipsis could not tell which."
4046
+ )
4047
+ type: Literal["github.issue"]
4048
+
4049
+
4027
4050
  class LinkedSlackIdentity(EllipsisModel):
4028
4051
  """The Slack identity linked to a GitHub member."""
4029
4052
 
@@ -4071,6 +4094,19 @@ class GithubMembersListResponse(EllipsisModel):
4071
4094
  )
4072
4095
 
4073
4096
 
4097
+ class GithubOtherTimelineEvent(EllipsisModel):
4098
+ """A change sent to GitHub that none of the other types describe."""
4099
+
4100
+ at: datetime = Field(description="When the last request behind it ended.")
4101
+ method: str
4102
+ ok: bool = Field(description="Whether GitHub did it.")
4103
+ operation: Union[str, None] = Field(
4104
+ description="The GraphQL mutation, for `/api/graphql`."
4105
+ )
4106
+ path: str
4107
+ type: Literal["github.other"]
4108
+
4109
+
4074
4110
  class GithubPullRequestEvent(EllipsisModel):
4075
4111
  action: Union[PullRequestAction, Literal["review_commented"]]
4076
4112
  actor: Union[SessionEventActor, None]
@@ -4082,6 +4118,38 @@ class GithubPullRequestEvent(EllipsisModel):
4082
4118
  url: str
4083
4119
 
4084
4120
 
4121
+ class GithubPullRequestTimelineEvent(EllipsisModel):
4122
+ action: Literal[
4123
+ "opened",
4124
+ "edited",
4125
+ "ready_for_review",
4126
+ "converted_to_draft",
4127
+ "review_requested",
4128
+ "commented",
4129
+ "reviewed",
4130
+ "review_commented",
4131
+ "thread_resolved",
4132
+ "branch_updated",
4133
+ "auto_merge_enabled",
4134
+ "merge_queued",
4135
+ "merged",
4136
+ "closed",
4137
+ "reopened",
4138
+ ]
4139
+ at: datetime = Field(description="When the last request behind it ended.")
4140
+ number: Union[int, None] = Field(
4141
+ description="Null when Ellipsis could not tell which."
4142
+ )
4143
+ ok: bool = Field(description="Whether GitHub did it.")
4144
+ repository: Union[str, None] = Field(
4145
+ description="Null when Ellipsis could not tell which."
4146
+ )
4147
+ review: Union[Literal["approved", "changes_requested", "commented"], None] = Field(
4148
+ description="The review's verdict, for `reviewed`."
4149
+ )
4150
+ type: Literal["github.pull_request"]
4151
+
4152
+
4085
4153
  class GithubPushEvent(EllipsisModel):
4086
4154
  actor: Union[SessionEventActor, None]
4087
4155
  after: str
@@ -4092,6 +4160,31 @@ class GithubPushEvent(EllipsisModel):
4092
4160
  url: str
4093
4161
 
4094
4162
 
4163
+ class GithubPushTimelineEvent(EllipsisModel):
4164
+ """A branch or tag pushed, created, or deleted, over git or through the API."""
4165
+
4166
+ action: Literal["pushed", "created", "deleted"]
4167
+ at: datetime = Field(description="When the last request behind it ended.")
4168
+ branch: Union[str, None] = Field(
4169
+ description="Null for a tag, or when Ellipsis did not record the push's branches."
4170
+ )
4171
+ ok: bool = Field(description="Whether GitHub did it.")
4172
+ repository: str
4173
+ tag: Union[str, None] = Field(description="Null for a branch.")
4174
+ type: Literal["github.push"]
4175
+
4176
+
4177
+ class GithubRefusedTimelineEvent(EllipsisModel):
4178
+ """Requests Ellipsis refused before they reached GitHub, one entry for
4179
+ each run of them.
4180
+ """
4181
+
4182
+ at: datetime = Field(description="When the last request behind it ended.")
4183
+ ok: bool = Field(description="Whether GitHub did it.")
4184
+ reason: str = Field(description="The `reason` on the refused requests.")
4185
+ type: Literal["github.refused"]
4186
+
4187
+
4095
4188
  class GithubReleaseEvent(EllipsisModel):
4096
4189
  action: ReleaseAction
4097
4190
  actor: Union[SessionEventActor, None]
@@ -4103,6 +4196,15 @@ class GithubReleaseEvent(EllipsisModel):
4103
4196
  url: str
4104
4197
 
4105
4198
 
4199
+ class GithubReleaseTimelineEvent(EllipsisModel):
4200
+ action: Literal["created", "edited", "deleted"]
4201
+ at: datetime = Field(description="When the last request behind it ended.")
4202
+ ok: bool = Field(description="Whether GitHub did it.")
4203
+ repository: str
4204
+ tag: Union[str, None]
4205
+ type: Literal["github.release"]
4206
+
4207
+
4106
4208
  class GithubRepository(EllipsisModel):
4107
4209
  """A repository connected to the account's GitHub installation — a valid
4108
4210
  target for `repository` when creating an agent and for the
@@ -4233,6 +4335,20 @@ class GithubWorkflowRunEvent(EllipsisModel):
4233
4335
  url: str
4234
4336
 
4235
4337
 
4338
+ class GithubWorkflowTimelineEvent(EllipsisModel):
4339
+ """A GitHub Actions workflow run, or its logs read."""
4340
+
4341
+ action: Literal["dispatched", "rerun", "cancelled", "logs_read"]
4342
+ at: datetime = Field(description="When the last request behind it ended.")
4343
+ ok: bool = Field(description="Whether GitHub did it.")
4344
+ repository: str
4345
+ run_id: Union[int, None]
4346
+ type: Literal["github.workflow"]
4347
+ workflow: Union[str, None] = Field(
4348
+ description="The workflow file or id, for `dispatched`."
4349
+ )
4350
+
4351
+
4236
4352
  class ValidationError(EllipsisModel):
4237
4353
  ctx: Union[dict[str, Any], None] = None
4238
4354
  input: Union[Any, None] = None
@@ -4976,23 +5092,23 @@ class PullRequest(EllipsisModel):
4976
5092
  """A GitHub pull request. A session's pull requests are read live. A review's is kept as it was when the review ran."""
4977
5093
 
4978
5094
  additions: Union[int, None] = Field(
4979
- default=None, description="Lines added, null until GitHub reports them."
5095
+ description="Lines added, null until GitHub reports them."
4980
5096
  )
4981
5097
  author: GithubAccountSnippet = Field(description="Who opened the pull request.")
4982
5098
  base: PullRequestBranch = Field(description="The branch the changes merge into.")
4983
5099
  changed_files: Union[int, None] = Field(
4984
- default=None, description="Files changed, null until GitHub reports them."
5100
+ description="Files changed, null until GitHub reports them."
4985
5101
  )
4986
5102
  commits: Union[int, None] = Field(
4987
- default=None, description="Commits, null until GitHub reports them."
5103
+ description="Commits, null until GitHub reports them."
4988
5104
  )
4989
5105
  created_at: datetime
4990
5106
  deletions: Union[int, None] = Field(
4991
- default=None, description="Lines deleted, null until GitHub reports them."
5107
+ description="Lines deleted, null until GitHub reports them."
4992
5108
  )
4993
5109
  head: PullRequestBranch = Field(description="The branch with the changes.")
4994
5110
  id: int = Field(description="The pull request's GitHub id.")
4995
- merged_at: Union[datetime, None] = None
5111
+ merged_at: Union[datetime, None]
4996
5112
  number: int
4997
5113
  repository: GithubRepositorySnippet = Field(
4998
5114
  description="The repository the pull request merges into."
@@ -5378,6 +5494,48 @@ class SessionEnvironment(EllipsisModel):
5378
5494
  variables: list[EnvironmentVariable_Output]
5379
5495
 
5380
5496
 
5497
+ class SessionHandler(EllipsisModel):
5498
+ """The saved handler and its display name when the session started."""
5499
+
5500
+ agent_name: str = Field(
5501
+ description="The handler's effective display name when the session started: ellipsis.name, or the service default (Slack, GitHub, Linear, or sentry)."
5502
+ )
5503
+ id: str = Field(description="Identifier of the saved handler.")
5504
+ service: HandlerService = Field(description="The service the handler responds to.")
5505
+ sha: str = Field(
5506
+ description="Content fingerprint of the validated handler configuration used when the session started. This is not the Git commit SHA."
5507
+ )
5508
+
5509
+
5510
+ class SessionOutput(EllipsisModel):
5511
+ """Structured output on the wire: the contract and, when the agent has
5512
+ submitted one, the payload. `result` is None while the session runs and
5513
+ when the agent submitted nothing; it is the agent's own JSON, in the
5514
+ shape of `json_schema`.
5515
+ """
5516
+
5517
+ json_schema: dict[str, Any] = Field(
5518
+ description="JSON Schema the agent's result must satisfy."
5519
+ )
5520
+ result: Union[dict[str, Any], None] = Field(
5521
+ description="The payload the agent submitted, or null until it submits one."
5522
+ )
5523
+
5524
+
5525
+ class SessionParent(EllipsisModel):
5526
+ """The predecessor session this session continues."""
5527
+
5528
+ session_id: Union[str, None] = Field(
5529
+ description="Identifier of the predecessor session this session continues, if any."
5530
+ )
5531
+
5532
+
5533
+ class SessionReview(EllipsisModel):
5534
+ """The code review a reviewer session ran for."""
5535
+
5536
+ id: str = Field(description="Identifier of the code review.")
5537
+
5538
+
5381
5539
  class SessionGitCommit(EllipsisModel):
5382
5540
  """One commit the session created in this repo (everything past the
5383
5541
  provisioning checkout's sha), captured from the environment rather than the
@@ -5398,6 +5556,9 @@ class SessionGitFile(EllipsisModel):
5398
5556
 
5399
5557
  additions: int
5400
5558
  deletions: int
5559
+ patch: Union[str, None] = Field(
5560
+ description="The file's unified diff, `diff --git` header included, exactly as git emitted it. Null when the session's diff passed 100 KB and this file was left out."
5561
+ )
5401
5562
  path: str
5402
5563
  status: str
5403
5564
 
@@ -5412,6 +5573,9 @@ class SessionGitPr(EllipsisModel):
5412
5573
 
5413
5574
  gh_pr_id: Union[int, None]
5414
5575
  number: int
5576
+ pull_request: Union[PullRequest, None] = Field(
5577
+ description="The pull request as GitHub last reported it. Null until Ellipsis has read it from GitHub."
5578
+ )
5415
5579
  title: Union[str, None]
5416
5580
  url: str
5417
5581
 
@@ -5439,46 +5603,12 @@ class SessionGit(EllipsisModel):
5439
5603
  repos: list[SessionGitRepo]
5440
5604
 
5441
5605
 
5442
- class SessionHandler(EllipsisModel):
5443
- """The saved handler and its display name when the session started."""
5606
+ class SessionScm(EllipsisModel):
5607
+ """What the session did in source control, by provider."""
5444
5608
 
5445
- agent_name: str = Field(
5446
- description="The handler's effective display name when the session started: ellipsis.name, or the service default (Slack, GitHub, Linear, or sentry)."
5609
+ github: Union[SessionGit, None] = Field(
5610
+ description="Each GitHub repository in the session's environment and what the session did to it. Null if nothing was ever captured."
5447
5611
  )
5448
- id: str = Field(description="Identifier of the saved handler.")
5449
- service: HandlerService = Field(description="The service the handler responds to.")
5450
- sha: str = Field(
5451
- description="Content fingerprint of the validated handler configuration used when the session started. This is not the Git commit SHA."
5452
- )
5453
-
5454
-
5455
- class SessionOutput(EllipsisModel):
5456
- """Structured output on the wire: the contract and, when the agent has
5457
- submitted one, the payload. `result` is None while the session runs and
5458
- when the agent submitted nothing; it is the agent's own JSON, in the
5459
- shape of `json_schema`.
5460
- """
5461
-
5462
- json_schema: dict[str, Any] = Field(
5463
- description="JSON Schema the agent's result must satisfy."
5464
- )
5465
- result: Union[dict[str, Any], None] = Field(
5466
- description="The payload the agent submitted, or null until it submits one."
5467
- )
5468
-
5469
-
5470
- class SessionParent(EllipsisModel):
5471
- """The predecessor session this session continues."""
5472
-
5473
- session_id: Union[str, None] = Field(
5474
- description="Identifier of the predecessor session this session continues, if any."
5475
- )
5476
-
5477
-
5478
- class SessionReview(EllipsisModel):
5479
- """The code review a reviewer session ran for."""
5480
-
5481
- id: str = Field(description="Identifier of the code review.")
5482
5612
 
5483
5613
 
5484
5614
  SessionSource = Literal["react", "code_review", "web", "api", "cli", "mention", "cron"]
@@ -5593,9 +5723,6 @@ class Session(EllipsisModel):
5593
5723
  gemini: Union[GeminiConfig_Output, None] = Field(
5594
5724
  description="Gemini CLI input and native options. Set exactly one of claude_code, codex, or gemini."
5595
5725
  )
5596
- git: Union[SessionGit, None] = Field(
5597
- description="What the session did to git, one entry per repository in its workspace: the commit and branch it sits on, per-file line counts for its uncommitted changes, and the pull requests it opened. Null if nothing was ever captured."
5598
- )
5599
5726
  handler: Union[SessionHandler, None] = Field(
5600
5727
  description="The saved handler and its effective display name when this session started, frozen at creation. Null for built-in responders, legacy sessions, and sessions started without a handler."
5601
5728
  )
@@ -5615,6 +5742,9 @@ class Session(EllipsisModel):
5615
5742
  review: Union[SessionReview, None] = Field(
5616
5743
  description="The code review this session ran for; null unless the source is `code_review`."
5617
5744
  )
5745
+ scm: SessionScm = Field(
5746
+ description="What the session did in source control, by provider. Per repository: the commit and branch it sits on, its commits, each uncommitted file with its line counts and diff, and the pull requests it opened."
5747
+ )
5618
5748
  skills: list[SkillRef_Output] = Field(
5619
5749
  description="Skills installed for this session."
5620
5750
  )
@@ -5634,116 +5764,12 @@ class Session(EllipsisModel):
5634
5764
  )
5635
5765
 
5636
5766
 
5637
- class SessionSpendItem(EllipsisModel):
5638
- charged: int = 0
5639
- cost: int = 0
5640
- key: str
5641
- label: str
5642
- tokens: int = 0
5643
-
5644
-
5645
- class SessionCostCategory(EllipsisModel):
5646
- charged: int
5647
- items: list[SessionSpendItem]
5648
- key: str
5649
- label: str
5650
-
5651
-
5652
- class SessionToolCount(EllipsisModel):
5653
- calls: int
5654
- name: str
5655
-
5656
-
5657
- class SessionUsageBucket(EllipsisModel):
5658
- cache_read_tokens: int = 0
5659
- cache_write_tokens: int = 0
5660
- charged: int = 0
5661
- date: datetime
5662
- input_tokens: int = 0
5663
- output_tokens: int = 0
5664
- requests: int = 0
5665
-
5666
-
5667
- class SessionAnalytics(EllipsisModel):
5668
- attributed_requests: int
5669
- attribution: list[SessionCostCategory] = Field(
5670
- description="Estimated input content cost by serialized text size, allocated from measured input/cache spend. Repeated context is counted on every request. Output and compute remain separate. These estimates never affect billing."
5671
- )
5672
- attribution_request_limit: int = Field(
5673
- description="Maximum recent stored request bodies inspected. Older, missing, multimodal, or incomplete context is left unattributed."
5674
- )
5675
- bucket_seconds: int
5676
- charged: int
5677
- historical_entries: int = Field(
5678
- description="Carried-forward billing totals without per-request measurements. Included in spend, excluded from the timeline and request counts."
5679
- )
5680
- pending_requests: int
5681
- requests: int
5682
- series: list[SessionUsageBucket]
5683
- spend: list[SessionSpendItem] = Field(
5684
- description="Measured token lanes priced using each request's saved rate card, plus compute. Rounding is reconciled to the ledger."
5685
- )
5686
- tools: list[SessionToolCount] = Field(
5687
- description="Tool invocations from retained session records. These counts are not tool call charges; third-party tool fees are not metered."
5688
- )
5689
- unresolved_requests: int
5690
-
5691
-
5692
- class SessionGitPatchFile(EllipsisModel):
5693
- """One file's patch, split out of `git diff HEAD` at capture time.
5694
-
5695
- Stored per file rather than as one blob because that is how a viewer reads
5696
- it: a row per changed file, opened one at a time. Counts and status are NOT
5697
- repeated here — they live on the matching SessionGitFile in
5698
- `sessions.output_git`, which rides on every session read, so a surface
5699
- lists the changed files (and their +/−) before it fetches a single hunk. The
5700
- join key is (full_name, path).
5701
-
5702
- `patch` is the unified-diff section for this file, `diff --git` header
5703
- included, exactly as git emitted it.
5704
- """
5705
-
5706
- full_name: str
5707
- patch: str
5708
- path: str
5767
+ class SessionClosedTimelineEvent(EllipsisModel):
5768
+ """The session closed."""
5709
5769
 
5710
-
5711
- class SessionDiffResponse(EllipsisModel):
5712
- """A session's uncommitted changes, one patch per file."""
5713
-
5714
- files: list[SessionGitPatchFile] = Field(
5715
- description="One unified-diff section per changed file, `diff --git` header included, exactly as git emitted it. Join to the per-file counts on `git.repos[].files` by (full_name, path). Empty when the tree was clean or no capture ran."
5716
- )
5717
- omitted_paths: list[str] = Field(
5718
- description="Paths whose hunks were dropped to fit the storage cap, so a viewer can name what is missing instead of showing a silently partial diff."
5719
- )
5720
-
5721
-
5722
- class SessionPullRequestReview(EllipsisModel):
5723
- body: Union[str, None]
5724
- html_url: str
5725
- id: int
5726
- state: str
5727
- submitted_at: datetime
5728
- user: Union[GithubAccountSnippet, None]
5729
-
5730
-
5731
- class SessionPrEntry(EllipsisModel):
5732
- number: int
5733
- pull_request: Union[PullRequest, None]
5734
- reviews: list[SessionPullRequestReview]
5735
- url: str
5736
-
5737
-
5738
- class SessionGitRepoEntry(EllipsisModel):
5739
- commits: list[SessionGitCommit]
5740
- commits_total: int
5741
- full_name: str
5742
- prs: list[SessionPrEntry]
5743
-
5744
-
5745
- class SessionGitResponse(EllipsisModel):
5746
- repos: list[SessionGitRepoEntry]
5770
+ action: Literal["closed"]
5771
+ at: datetime
5772
+ type: Literal["session"]
5747
5773
 
5748
5774
 
5749
5775
  class SessionMessageResponse(EllipsisModel):
@@ -5816,6 +5842,24 @@ class SessionResponse(EllipsisModel):
5816
5842
  session: Session = Field(description="The session.")
5817
5843
 
5818
5844
 
5845
+ class SessionTimelineResponse(EllipsisModel):
5846
+ events: list[
5847
+ Union[
5848
+ EnvironmentTimelineEvent,
5849
+ SessionClosedTimelineEvent,
5850
+ GithubCloneTimelineEvent,
5851
+ GithubPushTimelineEvent,
5852
+ GithubCommitTimelineEvent,
5853
+ GithubPullRequestTimelineEvent,
5854
+ GithubIssueTimelineEvent,
5855
+ GithubReleaseTimelineEvent,
5856
+ GithubWorkflowTimelineEvent,
5857
+ GithubRefusedTimelineEvent,
5858
+ GithubOtherTimelineEvent,
5859
+ ]
5860
+ ] = Field(description="Newest first.")
5861
+
5862
+
5819
5863
  class SessionsListResponse(EllipsisModel):
5820
5864
  """A page of sessions in the lean wire shape."""
5821
5865
 
@@ -5830,7 +5874,6 @@ class SessionsListResponse(EllipsisModel):
5830
5874
  default=None,
5831
5875
  description="Pass as `cursor` to fetch the next page. Null on the last page. Opaque — echo it back rather than parsing it.",
5832
5876
  )
5833
- pull_requests: Union[dict[str, PullRequest], None] = None
5834
5877
  sessions: list[Session] = Field(
5835
5878
  description="Lean wire rows — the same shape GET /v1/sessions/{id} and the stream's session frames carry. The heavy blobs (config snapshot, input/output) live on the detail endpoints."
5836
5879
  )
@@ -6447,8 +6490,6 @@ __all__ = [
6447
6490
  "DeveloperBudgetWindow",
6448
6491
  "DeveloperBudgets",
6449
6492
  "DeveloperUsage",
6450
- "Duration_Input",
6451
- "Duration_Output",
6452
6493
  "EffortLevel",
6453
6494
  "EllipsisGrant_Input",
6454
6495
  "EllipsisGrant_Output",
@@ -6474,6 +6515,7 @@ __all__ = [
6474
6515
  "EnvironmentResponse",
6475
6516
  "EnvironmentScript",
6476
6517
  "EnvironmentSource",
6518
+ "EnvironmentTimelineEvent",
6477
6519
  "EnvironmentVariable_Input",
6478
6520
  "EnvironmentVariable_Output",
6479
6521
  "EnvironmentsListResponse",
@@ -6508,21 +6550,29 @@ __all__ = [
6508
6550
  "GithubAccountType",
6509
6551
  "GithubCheckRunEvent",
6510
6552
  "GithubCheckSuiteEvent",
6553
+ "GithubCloneTimelineEvent",
6554
+ "GithubCommitTimelineEvent",
6511
6555
  "GithubConfig",
6512
6556
  "GithubConfigEllipsis",
6513
6557
  "GithubHandler",
6514
6558
  "GithubIntegrationSummary",
6515
6559
  "GithubIssueEvent",
6560
+ "GithubIssueTimelineEvent",
6516
6561
  "GithubMember",
6517
6562
  "GithubMembersListResponse",
6518
6563
  "GithubMentionAudience",
6519
6564
  "GithubMentionAuthors",
6520
6565
  "GithubMentionPolicy",
6566
+ "GithubOtherTimelineEvent",
6521
6567
  "GithubPermissions_Input",
6522
6568
  "GithubPermissions_Output",
6523
6569
  "GithubPullRequestEvent",
6570
+ "GithubPullRequestTimelineEvent",
6524
6571
  "GithubPushEvent",
6572
+ "GithubPushTimelineEvent",
6573
+ "GithubRefusedTimelineEvent",
6525
6574
  "GithubReleaseEvent",
6575
+ "GithubReleaseTimelineEvent",
6526
6576
  "GithubRepositoriesListResponse",
6527
6577
  "GithubRepository",
6528
6578
  "GithubRepositorySnippet",
@@ -6531,6 +6581,7 @@ __all__ = [
6531
6581
  "GithubStatusEvent",
6532
6582
  "GithubUser",
6533
6583
  "GithubWorkflowRunEvent",
6584
+ "GithubWorkflowTimelineEvent",
6534
6585
  "HTTPValidationError",
6535
6586
  "Handler",
6536
6587
  "HandlerMetricsResponse",
@@ -6697,31 +6748,26 @@ __all__ = [
6697
6748
  "SeriesInterval",
6698
6749
  "Session",
6699
6750
  "SessionAgent",
6700
- "SessionAnalytics",
6701
6751
  "SessionArchived",
6702
6752
  "SessionAttribution",
6703
6753
  "SessionBudgetDefault",
6704
6754
  "SessionCapability",
6705
6755
  "SessionClosedPayload",
6706
6756
  "SessionClosedRecord",
6757
+ "SessionClosedTimelineEvent",
6707
6758
  "SessionConfig_Input",
6708
6759
  "SessionConfig_Output",
6709
6760
  "SessionConversation",
6710
6761
  "SessionConversationConfig_Input",
6711
6762
  "SessionConversationConfig_Output",
6712
- "SessionCostCategory",
6713
- "SessionDiffResponse",
6714
6763
  "SessionEnvironment",
6715
6764
  "SessionError",
6716
6765
  "SessionEventActor",
6717
6766
  "SessionGit",
6718
6767
  "SessionGitCommit",
6719
6768
  "SessionGitFile",
6720
- "SessionGitPatchFile",
6721
6769
  "SessionGitPr",
6722
6770
  "SessionGitRepo",
6723
- "SessionGitRepoEntry",
6724
- "SessionGitResponse",
6725
6771
  "SessionHandler",
6726
6772
  "SessionLogSegment",
6727
6773
  "SessionMessage",
@@ -6729,20 +6775,17 @@ __all__ = [
6729
6775
  "SessionMessageResponse",
6730
6776
  "SessionOutput",
6731
6777
  "SessionParent",
6732
- "SessionPrEntry",
6733
6778
  "SessionPrompting",
6734
- "SessionPullRequestReview",
6735
6779
  "SessionRecord",
6736
6780
  "SessionRecordsListResponse",
6737
6781
  "SessionResponse",
6738
6782
  "SessionReview",
6783
+ "SessionScm",
6739
6784
  "SessionSource",
6740
- "SessionSpendItem",
6741
6785
  "SessionStatus",
6742
6786
  "SessionSummary",
6743
6787
  "SessionSummarySource",
6744
- "SessionToolCount",
6745
- "SessionUsageBucket",
6788
+ "SessionTimelineResponse",
6746
6789
  "SessionsListResponse",
6747
6790
  "SettingsRef_Input",
6748
6791
  "SettingsRef_Output",
File without changes
File without changes