@proteos/sdk 0.18.1
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.
- package/LICENSE +40 -0
- package/dist/chunk-7RGN4E22.cjs +1185 -0
- package/dist/chunk-7RGN4E22.cjs.map +1 -0
- package/dist/chunk-XJP5WCRZ.js +1125 -0
- package/dist/chunk-XJP5WCRZ.js.map +1 -0
- package/dist/index.cjs +2384 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +5225 -0
- package/dist/index.d.ts +5225 -0
- package/dist/index.js +2146 -0
- package/dist/index.js.map +1 -0
- package/dist/meta/index.cjs +204 -0
- package/dist/meta/index.cjs.map +1 -0
- package/dist/meta/index.d.cts +2 -0
- package/dist/meta/index.d.ts +2 -0
- package/dist/meta/index.js +3 -0
- package/dist/meta/index.js.map +1 -0
- package/dist/types-BNsjfU8N.d.cts +3299 -0
- package/dist/types-BNsjfU8N.d.ts +3299 -0
- package/package.json +86 -0
- package/src/agent/agents.ts +53 -0
- package/src/agent/index.ts +134 -0
- package/src/agent/mcp-servers.ts +102 -0
- package/src/agent/prompts.ts +80 -0
- package/src/agent/session-types.ts +397 -0
- package/src/agent/sessions.ts +197 -0
- package/src/agent/skills.ts +89 -0
- package/src/agent/tools.ts +53 -0
- package/src/agent/types.ts +362 -0
- package/src/auth/index.ts +111 -0
- package/src/auth/me.ts +46 -0
- package/src/auth/organizations.ts +128 -0
- package/src/auth/platform-entities.ts +78 -0
- package/src/auth/roles.ts +213 -0
- package/src/auth/types.ts +294 -0
- package/src/auth/users.ts +226 -0
- package/src/client.ts +441 -0
- package/src/connector/index.ts +120 -0
- package/src/connector/types.ts +150 -0
- package/src/conversation/index.ts +297 -0
- package/src/conversation/types.ts +590 -0
- package/src/conversation/voice.ts +123 -0
- package/src/data/index.ts +53 -0
- package/src/data/queries.ts +66 -0
- package/src/data/records.ts +122 -0
- package/src/data/types.ts +89 -0
- package/src/errors.ts +148 -0
- package/src/events/index.ts +172 -0
- package/src/events/types.ts +77 -0
- package/src/functions/actions.ts +95 -0
- package/src/functions/index.ts +32 -0
- package/src/functions/types.ts +71 -0
- package/src/http/index.ts +2 -0
- package/src/http/query-params.ts +106 -0
- package/src/index.ts +598 -0
- package/src/iterator.ts +183 -0
- package/src/knowledge/graph.ts +35 -0
- package/src/knowledge/index.ts +104 -0
- package/src/knowledge/labels.ts +70 -0
- package/src/knowledge/links.ts +65 -0
- package/src/knowledge/nodes.ts +198 -0
- package/src/knowledge/record-links.ts +66 -0
- package/src/knowledge/types.ts +569 -0
- package/src/meta/apps.ts +107 -0
- package/src/meta/components.ts +124 -0
- package/src/meta/currency/index.ts +202 -0
- package/src/meta/entities.ts +193 -0
- package/src/meta/filters.ts +76 -0
- package/src/meta/index.ts +227 -0
- package/src/meta/layout/common-props.ts +93 -0
- package/src/meta/layout/control-registry.json +70 -0
- package/src/meta/layout/control-registry.ts +92 -0
- package/src/meta/layout/elements.ts +203 -0
- package/src/meta/layout/index.ts +41 -0
- package/src/meta/layout/page-layout.ts +35 -0
- package/src/meta/layout/size-value.ts +27 -0
- package/src/meta/list-views.ts +109 -0
- package/src/meta/lists.ts +104 -0
- package/src/meta/menu-configurations.ts +128 -0
- package/src/meta/modules.ts +159 -0
- package/src/meta/pages.ts +106 -0
- package/src/meta/types.ts +1115 -0
- package/src/meta/variables.ts +98 -0
- package/src/storage/files.ts +183 -0
- package/src/storage/index.ts +33 -0
- package/src/storage/types.ts +70 -0
- package/src/types/common.ts +143 -0
- package/src/types/index.ts +28 -0
- package/src/types/options.ts +95 -0
- package/src/workflow/executions.ts +99 -0
- package/src/workflow/index.ts +109 -0
- package/src/workflow/node-types.ts +50 -0
- package/src/workflow/types.ts +658 -0
- package/src/workflow/workflows.ts +152 -0
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for the agent-service Sessions API — a conversation with a configured
|
|
3
|
+
* Agent.
|
|
4
|
+
*
|
|
5
|
+
* Hand-written mirror of the Go models in `go.proteos.ai/model/agent`
|
|
6
|
+
* (`session.go`, `session-event.go`, `session-event-type.go`, `session-payload.go`,
|
|
7
|
+
* `session-content.go` + `api/session-requests.go`). Field names match the
|
|
8
|
+
* snake_case wire format exactly, including enum values.
|
|
9
|
+
*
|
|
10
|
+
* A Session is a thin mutable parent over an append-only `SessionEvent` log: the
|
|
11
|
+
* events are the source of truth, the session carries only identity, the agent it
|
|
12
|
+
* runs, a title and the latest lifecycle status. A {@link Turn} is a derived
|
|
13
|
+
* projection of the log (never stored).
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import type { AuditFields, ListOptions, UserRef } from '../types/common.js'
|
|
17
|
+
import type { ToolKind } from './types.js'
|
|
18
|
+
|
|
19
|
+
export type { ToolKind } from './types.js'
|
|
20
|
+
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
// Session
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The latest lifecycle state of a session, projected from the `session.status_*`
|
|
27
|
+
* events. `idle` = ready for the next user message; `running` = a turn is in
|
|
28
|
+
* flight; `terminated` = ended; `error` = the last turn failed.
|
|
29
|
+
*/
|
|
30
|
+
export type SessionStatus = 'idle' | 'running' | 'terminated' | 'error'
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The rolled-up token accounting for a session — the sum of every model request's
|
|
34
|
+
* usage plus the request count, projected from the `span.model_request_end` events
|
|
35
|
+
* and kept on the session row so listings/headers can show cost without replaying
|
|
36
|
+
* the log. `total_tokens` is the derived input+output sum.
|
|
37
|
+
*
|
|
38
|
+
* `model` is the model the usage is attributed to. Managed Agents reports no model
|
|
39
|
+
* id on its usage events, so it is seeded once at session create from the agent's
|
|
40
|
+
* configured model and preserved across recomputes (empty on sessions created
|
|
41
|
+
* before usage tracking existed).
|
|
42
|
+
*/
|
|
43
|
+
export interface SessionUsage {
|
|
44
|
+
model: string
|
|
45
|
+
input_tokens: number
|
|
46
|
+
output_tokens: number
|
|
47
|
+
cache_read_input_tokens: number
|
|
48
|
+
cache_creation_input_tokens: number
|
|
49
|
+
total_tokens: number
|
|
50
|
+
request_count: number
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* One conversation with a configured Agent. Surrogate-keyed by `id` (a session is
|
|
55
|
+
* a graph node referenced by every event). `status` is denormalized from the
|
|
56
|
+
* event log for cheap listing; `usage` is the denormalized token total.
|
|
57
|
+
*/
|
|
58
|
+
export interface Session extends AuditFields {
|
|
59
|
+
org_id: string
|
|
60
|
+
id: string
|
|
61
|
+
agent_key: string
|
|
62
|
+
title: string
|
|
63
|
+
status: SessionStatus
|
|
64
|
+
usage: SessionUsage
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// ---------------------------------------------------------------------------
|
|
68
|
+
// Event types (the discriminant)
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* The discriminant of a {@link SessionEvent} — it selects which payload shape the
|
|
73
|
+
* event carries. v1 carries WHOLE events only; the delta/chunk variants
|
|
74
|
+
* (`agent.message.delta`, …) are intentionally absent.
|
|
75
|
+
*/
|
|
76
|
+
export type EventType =
|
|
77
|
+
// User-originated (posted via the API or echoed back by the provider).
|
|
78
|
+
| 'user.message'
|
|
79
|
+
| 'user.interrupt'
|
|
80
|
+
| 'user.tool_confirmation'
|
|
81
|
+
| 'user.tool_result'
|
|
82
|
+
// Agent-originated.
|
|
83
|
+
| 'agent.message'
|
|
84
|
+
| 'agent.reasoning'
|
|
85
|
+
| 'agent.tool_use'
|
|
86
|
+
| 'agent.tool_result'
|
|
87
|
+
| 'agent.context_compacted'
|
|
88
|
+
| 'agent.artifacts'
|
|
89
|
+
// Session lifecycle.
|
|
90
|
+
| 'session.status_running'
|
|
91
|
+
| 'session.status_idle'
|
|
92
|
+
| 'session.status_terminated'
|
|
93
|
+
| 'session.error'
|
|
94
|
+
| 'session.updated'
|
|
95
|
+
// Span (observability).
|
|
96
|
+
| 'span.model_request_start'
|
|
97
|
+
| 'span.model_request_end'
|
|
98
|
+
|
|
99
|
+
/** The client-postable subset (everything else is produced by the runtime). */
|
|
100
|
+
export type ClientEventType =
|
|
101
|
+
| 'user.message'
|
|
102
|
+
| 'user.interrupt'
|
|
103
|
+
| 'user.tool_confirmation'
|
|
104
|
+
| 'user.tool_result'
|
|
105
|
+
|
|
106
|
+
// ---------------------------------------------------------------------------
|
|
107
|
+
// Content blocks (the self-tagged pieces of heterogeneous payloads)
|
|
108
|
+
// ---------------------------------------------------------------------------
|
|
109
|
+
|
|
110
|
+
/** A plain text block. Agent messages are text-only. */
|
|
111
|
+
export interface TextBlock {
|
|
112
|
+
type: 'text'
|
|
113
|
+
text: string
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* A file value object: a reference to a stored File (storage-service) plus light
|
|
118
|
+
* metadata. Embedded inline in a user-message {@link ContentBlock} (`type=file`)
|
|
119
|
+
* and nested under `image` in a tool {@link ResultBlock}.
|
|
120
|
+
*/
|
|
121
|
+
export interface FileBlock {
|
|
122
|
+
file_id?: string
|
|
123
|
+
file_name?: string
|
|
124
|
+
mime_type?: string
|
|
125
|
+
size_in_bytes?: number
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* One block of a user/agent message body. For `type=text` only `text` is set; for
|
|
130
|
+
* `type=file` the {@link FileBlock} fields are promoted inline.
|
|
131
|
+
*/
|
|
132
|
+
export interface ContentBlock extends FileBlock {
|
|
133
|
+
type: 'text' | 'file'
|
|
134
|
+
text?: string
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* One block of a tool result. Unlike message file blocks, an image nests its file
|
|
139
|
+
* under `image`; `json` carries an arbitrary raw object.
|
|
140
|
+
*/
|
|
141
|
+
export interface ResultBlock {
|
|
142
|
+
type: 'text' | 'image' | 'json'
|
|
143
|
+
text?: string
|
|
144
|
+
image?: FileBlock
|
|
145
|
+
json?: unknown
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// ---------------------------------------------------------------------------
|
|
149
|
+
// Event payloads (discriminated by the sibling event `type`)
|
|
150
|
+
// ---------------------------------------------------------------------------
|
|
151
|
+
|
|
152
|
+
/** A user message body (text + file blocks). */
|
|
153
|
+
export interface UserMessagePayload {
|
|
154
|
+
content: ContentBlock[]
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/** An agent message body (text blocks only). */
|
|
158
|
+
export interface AgentMessagePayload {
|
|
159
|
+
content: TextBlock[]
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Files the agent produced in its sandbox this turn (reconciled from the session
|
|
164
|
+
* outputs), surfaced as downloadable attachments on the agent turn. A turn can
|
|
165
|
+
* produce several. Each {@link FileBlock} carries the storage-service `file_id`.
|
|
166
|
+
*/
|
|
167
|
+
export interface AgentArtifactsPayload {
|
|
168
|
+
files: FileBlock[]
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* An agent reasoning ("thinking") block. v1 whole-events carry no text/signature
|
|
173
|
+
* from the provider, so both are typically empty.
|
|
174
|
+
*/
|
|
175
|
+
export interface ReasoningPayload {
|
|
176
|
+
text: string
|
|
177
|
+
signature?: string
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* A tool invocation. `id` is the provider's tool_use event id — the correlation
|
|
182
|
+
* key a matching {@link ToolResultPayload}'s `tool_use_id` points back to.
|
|
183
|
+
* `tool_kind` is the execution location (action | mcp | client).
|
|
184
|
+
*/
|
|
185
|
+
export interface ToolUsePayload {
|
|
186
|
+
id: string
|
|
187
|
+
name: string
|
|
188
|
+
input: unknown
|
|
189
|
+
tool_kind: ToolKind
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/** The result of a tool invocation, linked to its use by `tool_use_id`. */
|
|
193
|
+
export interface ToolResultPayload {
|
|
194
|
+
tool_use_id: string
|
|
195
|
+
result: ResultBlock[]
|
|
196
|
+
/** "success" | "error" (open string for forward-compat). */
|
|
197
|
+
outcome: string
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/** A user's decision on a tool that requested approval. */
|
|
201
|
+
export interface ToolConfirmationPayload {
|
|
202
|
+
tool_use_id: string
|
|
203
|
+
/** "approved" | "denied" (open string for forward-compat). */
|
|
204
|
+
decision: string
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/** Announces that earlier context was summarized. */
|
|
208
|
+
export interface ContextCompactedPayload {
|
|
209
|
+
summary: string
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/** A session-level error. */
|
|
213
|
+
export interface ErrorPayload {
|
|
214
|
+
message: string
|
|
215
|
+
code?: string
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Why a turn went idle. `type` is an open string ("turn_ended" |
|
|
220
|
+
* "user_action_required" | …) so new provider reasons don't break decoding.
|
|
221
|
+
*/
|
|
222
|
+
export interface StopReason {
|
|
223
|
+
type: string
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Emitted when a turn ends. `event_ids` carries the tool_use event ids awaiting a
|
|
228
|
+
* client response when `stop_reason.type` is `user_action_required`.
|
|
229
|
+
*/
|
|
230
|
+
export interface SessionIdlePayload {
|
|
231
|
+
stop_reason: StopReason
|
|
232
|
+
event_ids?: string[]
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* A server-side session metadata change — v1 carries the (often auto-generated)
|
|
237
|
+
* title. Projected onto {@link Session.title}; emitted only when the title changed.
|
|
238
|
+
*/
|
|
239
|
+
export interface SessionUpdatedPayload {
|
|
240
|
+
title?: string
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/** Opens a model-request span. */
|
|
244
|
+
export interface ModelRequestStartPayload {
|
|
245
|
+
model_id: string
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/** Per-request token accounting. */
|
|
249
|
+
export interface ModelUsage {
|
|
250
|
+
input_tokens: number
|
|
251
|
+
output_tokens: number
|
|
252
|
+
cache_read_input_tokens?: number
|
|
253
|
+
cache_creation_input_tokens?: number
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/** Closes a model-request span with usage. */
|
|
257
|
+
export interface ModelRequestEndPayload {
|
|
258
|
+
model_usage: ModelUsage
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* The body of events that carry no fields (`user.interrupt`,
|
|
263
|
+
* `session.status_running`, `session.status_terminated`).
|
|
264
|
+
*/
|
|
265
|
+
export type EmptyPayload = Record<string, never>
|
|
266
|
+
|
|
267
|
+
// ---------------------------------------------------------------------------
|
|
268
|
+
// SessionEvent (the append-only log envelope)
|
|
269
|
+
// ---------------------------------------------------------------------------
|
|
270
|
+
|
|
271
|
+
/** Shared envelope fields carried by every {@link SessionEvent}. */
|
|
272
|
+
export interface SessionEventEnvelope {
|
|
273
|
+
/** Dedupe key: our uuid for user events, the provider's id for agent events. */
|
|
274
|
+
id: string
|
|
275
|
+
session_id: string
|
|
276
|
+
org_id: string
|
|
277
|
+
/** Groups events into user/agent turns. */
|
|
278
|
+
turn_id: string
|
|
279
|
+
/** Per-session monotonic cursor (the SSE frame `id`). */
|
|
280
|
+
seq: number
|
|
281
|
+
created_by: UserRef
|
|
282
|
+
/** Meaningful only for user events: null = queued, timestamp = consumed. */
|
|
283
|
+
processed_at: string | null
|
|
284
|
+
created_at: string
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* One entry of the append-only session log — discriminated by `type`. The same
|
|
289
|
+
* envelope is delivered byte-for-byte over both the durable (REST) and live (SSE)
|
|
290
|
+
* channels, keyed by the same `seq`, so the two merge into one ordered log.
|
|
291
|
+
*/
|
|
292
|
+
export type SessionEvent = SessionEventEnvelope &
|
|
293
|
+
(
|
|
294
|
+
| { type: 'user.message'; payload: UserMessagePayload }
|
|
295
|
+
| { type: 'user.interrupt'; payload: EmptyPayload }
|
|
296
|
+
| { type: 'user.tool_confirmation'; payload: ToolConfirmationPayload }
|
|
297
|
+
| { type: 'user.tool_result'; payload: ToolResultPayload }
|
|
298
|
+
| { type: 'agent.message'; payload: AgentMessagePayload }
|
|
299
|
+
| { type: 'agent.reasoning'; payload: ReasoningPayload }
|
|
300
|
+
| { type: 'agent.tool_use'; payload: ToolUsePayload }
|
|
301
|
+
| { type: 'agent.tool_result'; payload: ToolResultPayload }
|
|
302
|
+
| { type: 'agent.context_compacted'; payload: ContextCompactedPayload }
|
|
303
|
+
| { type: 'agent.artifacts'; payload: AgentArtifactsPayload }
|
|
304
|
+
| { type: 'session.status_running'; payload: EmptyPayload }
|
|
305
|
+
| { type: 'session.status_idle'; payload: SessionIdlePayload }
|
|
306
|
+
| { type: 'session.status_terminated'; payload: EmptyPayload }
|
|
307
|
+
| { type: 'session.error'; payload: ErrorPayload }
|
|
308
|
+
| { type: 'session.updated'; payload: SessionUpdatedPayload }
|
|
309
|
+
| { type: 'span.model_request_start'; payload: ModelRequestStartPayload }
|
|
310
|
+
| { type: 'span.model_request_end'; payload: ModelRequestEndPayload }
|
|
311
|
+
)
|
|
312
|
+
// A closed discriminated union (the v1 event set) so consumers narrow `payload`
|
|
313
|
+
// by `type`. An unrecognized future event type still parses at runtime (it is cast
|
|
314
|
+
// from JSON) — a switch over `type` simply won't match it, which is the intended
|
|
315
|
+
// skip-and-ignore behavior.
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* The `GroupByTurn` projection — NEVER stored, recomputed from the event log.
|
|
319
|
+
* `events` hold the envelopes verbatim, grouped by `turn_id` and ordered by `seq`.
|
|
320
|
+
* The web folds this client-side from the live event stream; this type mirrors the
|
|
321
|
+
* server's `GET /sessions/:id/turns` for completeness.
|
|
322
|
+
*/
|
|
323
|
+
export interface Turn {
|
|
324
|
+
id: string
|
|
325
|
+
role: 'user' | 'agent'
|
|
326
|
+
events: SessionEvent[]
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// ---------------------------------------------------------------------------
|
|
330
|
+
// Requests / query options
|
|
331
|
+
// ---------------------------------------------------------------------------
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* A client tool the launching surface advertises when it opens a session: a custom
|
|
335
|
+
* tool the agent calls but the browser renders/executes, returning the result. Only
|
|
336
|
+
* these three fields cross the wire — the render slot and React component are
|
|
337
|
+
* frontend-only. `input_schema` is a JSON Schema (draft-07) object.
|
|
338
|
+
*/
|
|
339
|
+
export interface ClientToolSchema {
|
|
340
|
+
name: string
|
|
341
|
+
description: string
|
|
342
|
+
input_schema: Record<string, unknown>
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Opens a session against a configured agent. `title` is optional. `client_tools` is
|
|
347
|
+
* the launching surface's client-tool catalog, attached to this session only — a
|
|
348
|
+
* surface that can't render them simply omits the field, so the agent never gets a
|
|
349
|
+
* tool nobody can answer.
|
|
350
|
+
*/
|
|
351
|
+
export interface CreateSessionRequest {
|
|
352
|
+
agent_key: string
|
|
353
|
+
title?: string
|
|
354
|
+
client_tools?: ClientToolSchema[]
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Posts a client event onto a session. Only client-postable `user.*` types are
|
|
359
|
+
* accepted; `payload` is the matching payload for the `type`.
|
|
360
|
+
*/
|
|
361
|
+
export interface AppendEventRequest {
|
|
362
|
+
type: ClientEventType
|
|
363
|
+
/**
|
|
364
|
+
* Optionally supply the turn's id (a UUID) so the client can render the message
|
|
365
|
+
* optimistically under a stable identity that matches the event echoed back
|
|
366
|
+
* over the stream. Omitted, the service mints one.
|
|
367
|
+
*/
|
|
368
|
+
turn_id?: string
|
|
369
|
+
payload?: unknown
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/** List filter for sessions (in addition to pagination/sorting). */
|
|
373
|
+
export interface ListSessionsOptions extends ListOptions {
|
|
374
|
+
/** Filter by the agent the session runs. */
|
|
375
|
+
agent_key?: string
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Forward cursor over the durable event log. `after_seq` is the exclusive lower
|
|
380
|
+
* bound (the last-seen seq); `order` defaults to asc (chronological). `types`
|
|
381
|
+
* restricts the result to specific event types (e.g. `['agent.message']`);
|
|
382
|
+
* omitted, every type is returned.
|
|
383
|
+
*/
|
|
384
|
+
export interface SessionEventsOptions {
|
|
385
|
+
after_seq?: number
|
|
386
|
+
limit?: number
|
|
387
|
+
order?: 'asc' | 'desc'
|
|
388
|
+
types?: EventType[]
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/** Options for opening the live SSE stream. */
|
|
392
|
+
export interface SessionStreamOptions {
|
|
393
|
+
/** Replay from this seq (exclusive) before following live. */
|
|
394
|
+
afterSeq?: number
|
|
395
|
+
/** Abort to tear the stream down. */
|
|
396
|
+
signal?: AbortSignal
|
|
397
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import type { ProteosClient } from '../client.js'
|
|
2
|
+
import { PageIterator } from '../iterator.js'
|
|
3
|
+
import type { ListResult } from '../types/common.js'
|
|
4
|
+
import type {
|
|
5
|
+
AppendEventRequest,
|
|
6
|
+
ContentBlock,
|
|
7
|
+
CreateSessionRequest,
|
|
8
|
+
FileBlock,
|
|
9
|
+
ListSessionsOptions,
|
|
10
|
+
ResultBlock,
|
|
11
|
+
Session,
|
|
12
|
+
SessionEvent,
|
|
13
|
+
SessionEventsOptions,
|
|
14
|
+
SessionStreamOptions,
|
|
15
|
+
Turn,
|
|
16
|
+
} from './session-types.js'
|
|
17
|
+
|
|
18
|
+
const SESSIONS_BASE_PATH = '/agents/v1/sessions'
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Service for managing agent Sessions — a conversation with a configured Agent,
|
|
22
|
+
* backed by an append-only event log. Covers the full agent-service session
|
|
23
|
+
* surface: CRUD, the durable event history, posting client events, the derived
|
|
24
|
+
* turns projection, and the live SSE stream.
|
|
25
|
+
*/
|
|
26
|
+
export interface SessionService {
|
|
27
|
+
/** Lists sessions, auto-paginating. */
|
|
28
|
+
list(options?: ListSessionsOptions): PageIterator<Session, ListSessionsOptions>
|
|
29
|
+
/** Fetches a single page of sessions with pagination metadata. */
|
|
30
|
+
listPage(options?: ListSessionsOptions): Promise<ListResult<Session>>
|
|
31
|
+
/** Gets a single session by id. @throws {ProteosError} 404 if not found. */
|
|
32
|
+
get(id: string): Promise<Session>
|
|
33
|
+
/** Opens a new session against a configured agent. @throws {ProteosError} 400. */
|
|
34
|
+
create(request: CreateSessionRequest): Promise<Session>
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Reads a page of the durable event log (Postgres), a forward `after_seq`
|
|
38
|
+
* cursor ordered ascending by default. The live channel is {@link stream}.
|
|
39
|
+
*/
|
|
40
|
+
events(id: string, options?: SessionEventsOptions): Promise<SessionEvent[]>
|
|
41
|
+
/** Posts a client (`user.*`) event onto a session. @throws {ProteosError} 400/409. */
|
|
42
|
+
appendEvent(id: string, request: AppendEventRequest): Promise<SessionEvent>
|
|
43
|
+
/** The server-side `GroupByTurn` projection of the full event log. */
|
|
44
|
+
turns(id: string): Promise<Turn[]>
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Live-tails the session's event stream over SSE, yielding each
|
|
48
|
+
* {@link SessionEvent} as it arrives. Replays from `afterSeq` (exclusive) then
|
|
49
|
+
* follows live; reconnects resume gap-free. Runs until the `AbortSignal` fires.
|
|
50
|
+
*/
|
|
51
|
+
stream(id: string, options?: SessionStreamOptions): AsyncGenerator<SessionEvent, void, unknown>
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Convenience: appends a `user.message` with a single text block. Pass
|
|
55
|
+
* `turnId` (a UUID) to supply the turn's id so the caller can render the
|
|
56
|
+
* message optimistically under an id matching the echoed event.
|
|
57
|
+
*/
|
|
58
|
+
sendMessage(id: string, text: string, turnId?: string): Promise<SessionEvent>
|
|
59
|
+
/**
|
|
60
|
+
* Convenience: appends a `user.message` built from optional text and file
|
|
61
|
+
* attachments. Each {@link FileBlock} carries the storage-service `file_id`; the
|
|
62
|
+
* backend uploads it to the model provider and mounts it into the agent's sandbox
|
|
63
|
+
* at send time. Pass `turnId` (a UUID) for optimistic rendering. At least one of
|
|
64
|
+
* `text` / `files` should be present.
|
|
65
|
+
*/
|
|
66
|
+
sendUserMessage(
|
|
67
|
+
id: string,
|
|
68
|
+
input: { text?: string; files?: FileBlock[]; turnId?: string },
|
|
69
|
+
): Promise<SessionEvent>
|
|
70
|
+
/** Convenience: appends a `user.interrupt` to halt the running turn. */
|
|
71
|
+
interrupt(id: string): Promise<SessionEvent>
|
|
72
|
+
/**
|
|
73
|
+
* Convenience: appends a `user.tool_result` answering a client tool the agent
|
|
74
|
+
* called (an `agent.tool_use` with `tool_kind: 'client'`). `toolUseId` is that
|
|
75
|
+
* tool-use event's id (carried in the idle event's `event_ids`); the backend
|
|
76
|
+
* relays the result to Anthropic as a `user.custom_tool_result` to resume the turn.
|
|
77
|
+
* `outcome` defaults to `'success'`.
|
|
78
|
+
*/
|
|
79
|
+
submitToolResult(
|
|
80
|
+
id: string,
|
|
81
|
+
input: { toolUseId: string; result: ResultBlock[]; outcome?: 'success' | 'error' },
|
|
82
|
+
): Promise<SessionEvent>
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export class SessionServiceImpl implements SessionService {
|
|
86
|
+
constructor(private readonly client: ProteosClient) {}
|
|
87
|
+
|
|
88
|
+
list(options: ListSessionsOptions = {}): PageIterator<Session, ListSessionsOptions> {
|
|
89
|
+
return new PageIterator((opts) => this.listPage(opts), options)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async listPage(options: ListSessionsOptions = {}): Promise<ListResult<Session>> {
|
|
93
|
+
return this.client.requestWithQuery<ListResult<Session>>('GET', SESSIONS_BASE_PATH, options)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async get(id: string): Promise<Session> {
|
|
97
|
+
return this.client.request<Session>('GET', `${SESSIONS_BASE_PATH}/${id}`)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async create(request: CreateSessionRequest): Promise<Session> {
|
|
101
|
+
return this.client.request<Session>('POST', SESSIONS_BASE_PATH, request)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async events(id: string, options: SessionEventsOptions = {}): Promise<SessionEvent[]> {
|
|
105
|
+
// The backend reads `types` as a single comma-separated query param (a string
|
|
106
|
+
// it splits into a `type IN (...)` filter), so join the array rather than
|
|
107
|
+
// letting the serializer emit repeated `types=` params.
|
|
108
|
+
const { types, ...rest } = options
|
|
109
|
+
const query = {
|
|
110
|
+
...rest,
|
|
111
|
+
...(types && types.length > 0 ? { types: types.join(',') } : {}),
|
|
112
|
+
}
|
|
113
|
+
const response = await this.client.requestWithQuery<{ data: SessionEvent[] }>(
|
|
114
|
+
'GET',
|
|
115
|
+
`${SESSIONS_BASE_PATH}/${id}/events`,
|
|
116
|
+
query,
|
|
117
|
+
)
|
|
118
|
+
return response.data ?? []
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async appendEvent(id: string, request: AppendEventRequest): Promise<SessionEvent> {
|
|
122
|
+
return this.client.request<SessionEvent>('POST', `${SESSIONS_BASE_PATH}/${id}/events`, request)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async turns(id: string): Promise<Turn[]> {
|
|
126
|
+
const response = await this.client.request<{ data: Turn[] }>(
|
|
127
|
+
'GET',
|
|
128
|
+
`${SESSIONS_BASE_PATH}/${id}/turns`,
|
|
129
|
+
)
|
|
130
|
+
return response.data ?? []
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
async *stream(
|
|
134
|
+
id: string,
|
|
135
|
+
options: SessionStreamOptions = {},
|
|
136
|
+
): AsyncGenerator<SessionEvent, void, unknown> {
|
|
137
|
+
const query = options.afterSeq ? `?after_seq=${options.afterSeq}` : ''
|
|
138
|
+
const path = `${SESSIONS_BASE_PATH}/${id}/events/stream${query}`
|
|
139
|
+
const streamOptions = options.signal ? { signal: options.signal } : {}
|
|
140
|
+
for await (const frame of this.client.streamEvents(path, streamOptions)) {
|
|
141
|
+
const event = parseEvent(frame.data)
|
|
142
|
+
if (event) yield event
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async sendMessage(id: string, text: string, turnId?: string): Promise<SessionEvent> {
|
|
147
|
+
return this.sendUserMessage(id, { text, ...(turnId ? { turnId } : {}) })
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
async sendUserMessage(
|
|
151
|
+
id: string,
|
|
152
|
+
input: { text?: string; files?: FileBlock[]; turnId?: string },
|
|
153
|
+
): Promise<SessionEvent> {
|
|
154
|
+
const content: ContentBlock[] = []
|
|
155
|
+
const text = input.text?.trim()
|
|
156
|
+
if (text) content.push({ type: 'text', text })
|
|
157
|
+
for (const file of input.files ?? []) {
|
|
158
|
+
content.push({ type: 'file', ...file })
|
|
159
|
+
}
|
|
160
|
+
return this.appendEvent(id, {
|
|
161
|
+
type: 'user.message',
|
|
162
|
+
...(input.turnId ? { turn_id: input.turnId } : {}),
|
|
163
|
+
payload: { content },
|
|
164
|
+
})
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
async interrupt(id: string): Promise<SessionEvent> {
|
|
168
|
+
return this.appendEvent(id, { type: 'user.interrupt' })
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
async submitToolResult(
|
|
172
|
+
id: string,
|
|
173
|
+
input: { toolUseId: string; result: ResultBlock[]; outcome?: 'success' | 'error' },
|
|
174
|
+
): Promise<SessionEvent> {
|
|
175
|
+
return this.appendEvent(id, {
|
|
176
|
+
type: 'user.tool_result',
|
|
177
|
+
payload: {
|
|
178
|
+
tool_use_id: input.toolUseId,
|
|
179
|
+
result: input.result,
|
|
180
|
+
outcome: input.outcome ?? 'success',
|
|
181
|
+
},
|
|
182
|
+
})
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Parses one SSE frame's `data` into a SessionEvent, returning null for an empty
|
|
188
|
+
* or unparseable frame — a single bad frame is skipped, not fatal to the stream.
|
|
189
|
+
*/
|
|
190
|
+
function parseEvent(data: string): SessionEvent | null {
|
|
191
|
+
if (!data) return null
|
|
192
|
+
try {
|
|
193
|
+
return JSON.parse(data) as SessionEvent
|
|
194
|
+
} catch {
|
|
195
|
+
return null
|
|
196
|
+
}
|
|
197
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { ProteosClient } from '../client.js'
|
|
2
|
+
import { PageIterator } from '../iterator.js'
|
|
3
|
+
import type { ListResult } from '../types/common.js'
|
|
4
|
+
import type { ListSkillsOptions, Skill, SkillVersion } from './types.js'
|
|
5
|
+
|
|
6
|
+
const SKILLS_BASE_PATH = '/agents/v1/skills'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Service for managing Skills — versioned bundles of instructions + files in the
|
|
10
|
+
* Anthropic Agent-Skills shape. Skills are created and updated only via
|
|
11
|
+
* {@link SkillService.deploy} (a multipart bundle upload); there is no JSON
|
|
12
|
+
* create/update.
|
|
13
|
+
*/
|
|
14
|
+
export interface SkillService {
|
|
15
|
+
/** Lists skills, auto-paginating. */
|
|
16
|
+
list(options?: ListSkillsOptions): PageIterator<Skill, ListSkillsOptions>
|
|
17
|
+
/** Fetches a single page of skills with pagination metadata. */
|
|
18
|
+
listPage(options?: ListSkillsOptions): Promise<ListResult<Skill>>
|
|
19
|
+
/** Gets a skill (with its current version + bundle pin) by key. @throws {ProteosError} 404. */
|
|
20
|
+
get(key: string): Promise<Skill>
|
|
21
|
+
/**
|
|
22
|
+
* Deploys a skill bundle (a `.tar.gz` containing `SKILL.md` at the root plus
|
|
23
|
+
* supporting files). The skill's key — its canonical identifier — is read
|
|
24
|
+
* from the bundle's `SKILL.md` frontmatter `name`, so no key is supplied here.
|
|
25
|
+
* Creates the skill on first deploy and a new immutable version each time.
|
|
26
|
+
*
|
|
27
|
+
* @param bundle - The `.tar.gz` bundle bytes.
|
|
28
|
+
* @param options.displayName - Optional human-readable display name.
|
|
29
|
+
* @param options.moduleSlug - Optional owning module slug (tags the skill so it
|
|
30
|
+
* can be filtered + round-tripped by module). Empty for a standalone deploy.
|
|
31
|
+
*/
|
|
32
|
+
deploy(bundle: Blob | File, options?: { displayName?: string; moduleSlug?: string }): Promise<Skill>
|
|
33
|
+
/** Deletes a skill and all its versions. @throws {ProteosError} 404. */
|
|
34
|
+
delete(key: string): Promise<void>
|
|
35
|
+
/** Lists all immutable versions of a skill, newest first. */
|
|
36
|
+
listVersions(key: string): Promise<SkillVersion[]>
|
|
37
|
+
/** Gets a specific immutable version by number. @throws {ProteosError} 404. */
|
|
38
|
+
getVersion(key: string, number: number): Promise<SkillVersion>
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export class SkillServiceImpl implements SkillService {
|
|
42
|
+
constructor(private readonly client: ProteosClient) {}
|
|
43
|
+
|
|
44
|
+
list(options: ListSkillsOptions = {}): PageIterator<Skill, ListSkillsOptions> {
|
|
45
|
+
return new PageIterator((opts) => this.listPage(opts), options)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async listPage(options: ListSkillsOptions = {}): Promise<ListResult<Skill>> {
|
|
49
|
+
return this.client.requestWithQuery<ListResult<Skill>>('GET', SKILLS_BASE_PATH, options)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async get(key: string): Promise<Skill> {
|
|
53
|
+
return this.client.request<Skill>('GET', `${SKILLS_BASE_PATH}/${key}`)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async deploy(
|
|
57
|
+
bundle: Blob | File,
|
|
58
|
+
options?: { displayName?: string; moduleSlug?: string },
|
|
59
|
+
): Promise<Skill> {
|
|
60
|
+
const formData = new FormData()
|
|
61
|
+
const filename = bundle instanceof File ? bundle.name : 'skill.tar.gz'
|
|
62
|
+
formData.append('bundle', bundle, filename)
|
|
63
|
+
if (options?.displayName) {
|
|
64
|
+
formData.append('display_name', options.displayName)
|
|
65
|
+
}
|
|
66
|
+
if (options?.moduleSlug) {
|
|
67
|
+
formData.append('module_slug', options.moduleSlug)
|
|
68
|
+
}
|
|
69
|
+
// Returns a bare Skill (no `{ data }` envelope). The key is derived from the
|
|
70
|
+
// bundle's SKILL.md frontmatter server-side.
|
|
71
|
+
return this.client.requestMultipart<Skill>('POST', `${SKILLS_BASE_PATH}/deploy`, formData)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async delete(key: string): Promise<void> {
|
|
75
|
+
await this.client.request<void>('DELETE', `${SKILLS_BASE_PATH}/${key}`)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async listVersions(key: string): Promise<SkillVersion[]> {
|
|
79
|
+
const response = await this.client.request<{ data: SkillVersion[] }>(
|
|
80
|
+
'GET',
|
|
81
|
+
`${SKILLS_BASE_PATH}/${key}/versions`,
|
|
82
|
+
)
|
|
83
|
+
return response.data
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async getVersion(key: string, number: number): Promise<SkillVersion> {
|
|
87
|
+
return this.client.request<SkillVersion>('GET', `${SKILLS_BASE_PATH}/${key}/versions/${number}`)
|
|
88
|
+
}
|
|
89
|
+
}
|