@robota-sdk/agent-transport 3.0.0-beta.82 → 3.0.0-beta.84
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/CHANGELOG.md +795 -0
- package/README.md +80 -118
- package/dist/browser/client.d.ts +2 -2
- package/dist/browser/client.js +1 -1
- package/dist/browser/index.d.ts +87 -13
- package/dist/browser/index.d.ts.map +1 -1
- package/dist/browser/index.js +1 -1
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/observer-messages-CEeisRaF.js +2 -0
- package/dist/browser/observer-messages-CEeisRaF.js.map +1 -0
- package/dist/browser/observer-messages-Dnff2Tdb.d.ts +471 -0
- package/dist/browser/observer-messages-Dnff2Tdb.d.ts.map +1 -0
- package/dist/node/index.cjs +1 -1
- package/dist/node/index.d.cts +308 -16
- package/dist/node/index.d.cts.map +1 -1
- package/dist/node/index.d.ts +308 -16
- package/dist/node/index.d.ts.map +1 -1
- package/dist/node/index.js +1 -1
- package/dist/node/index.js.map +1 -1
- package/dist/node/node.cjs +1 -1
- package/dist/node/node.d.cts +69 -1
- package/dist/node/node.d.cts.map +1 -1
- package/dist/node/node.d.ts +70 -2
- package/dist/node/node.d.ts.map +1 -1
- package/dist/node/node.js +1 -1
- package/dist/node/node.js.map +1 -1
- package/package.json +17 -14
- package/src/__tests__/bearer-resource-gate.test.ts +120 -0
- package/src/__tests__/history-attached-budget.test.ts +216 -0
- package/src/__tests__/message-decoders.test.ts +496 -6
- package/src/__tests__/project-read-messages.test.ts +118 -0
- package/src/__tests__/session-detail-loop-status.test.ts +169 -0
- package/src/__tests__/session-directory-messages.test.ts +322 -0
- package/src/__tests__/session-error-classification.test.ts +113 -0
- package/src/__tests__/session-history-wire.test.ts +342 -0
- package/src/__tests__/session-message-handler-observe.test.ts +217 -0
- package/src/__tests__/session-message-handler.test.ts +139 -4
- package/src/__tests__/settings-messages.test.ts +193 -0
- package/src/__tests__/ws-broadcast-events.test.ts +10 -0
- package/src/client.ts +9 -1
- package/src/index.ts +18 -2
- package/src/loop-control-messages.ts +34 -0
- package/src/message-decoders.ts +238 -6
- package/src/node/bearer-resource-gate.ts +291 -0
- package/src/node/index.ts +13 -0
- package/src/observer-messages.ts +47 -0
- package/src/open-prompts.ts +76 -0
- package/src/outbound-delivery.ts +11 -2
- package/src/project-read-messages.ts +74 -0
- package/src/protocol-session.ts +23 -1
- package/src/session-directory-messages.ts +162 -0
- package/src/session-error-classification.ts +91 -0
- package/src/session-events.ts +100 -19
- package/src/session-message-handler.ts +110 -15
- package/src/session-query-messages.ts +123 -5
- package/src/session-resume-bridge.ts +8 -0
- package/src/settings-messages.ts +103 -0
- package/src/wire-messages.ts +238 -11
- package/dist/browser/message-decoders-BB8n-H2X.d.ts +0 -252
- package/dist/browser/message-decoders-BB8n-H2X.d.ts.map +0 -1
- package/dist/browser/message-decoders-CDmDoZPR.js +0 -2
- package/dist/browser/message-decoders-CDmDoZPR.js.map +0 -1
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import type { TOutboundDeliver } from './outbound-delivery.js';
|
|
2
|
+
import type { IProtocolSession } from './protocol-session.js';
|
|
3
|
+
import type { TClientMessage } from './wire-messages.js';
|
|
4
|
+
import type { TCommandSurfaceLocality } from '@robota-sdk/agent-interface-command';
|
|
5
|
+
import type { ISettingsSnapshot, TSettingsPatch } from '@robota-sdk/agent-interface-session';
|
|
6
|
+
|
|
7
|
+
type TSettingsMessage = Extract<TClientMessage, { type: 'get-settings' | 'update-settings' }>;
|
|
8
|
+
|
|
9
|
+
export function isSettingsMessage(msg: TClientMessage): msg is TSettingsMessage {
|
|
10
|
+
return msg.type === 'get-settings' || msg.type === 'update-settings';
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** What applying a patch did: the fresh snapshot, or why nothing was written. */
|
|
14
|
+
export type TSettingsUpdateOutcome =
|
|
15
|
+
| { readonly ok: true; readonly settings: ISettingsSnapshot }
|
|
16
|
+
| {
|
|
17
|
+
readonly ok: false;
|
|
18
|
+
readonly code: 'not_available' | 'invalid' | 'refused' | 'update_failed';
|
|
19
|
+
readonly message: string;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* #3282 §4a: host-owned read/write for the Settings screen, supplied by the composition root the
|
|
24
|
+
* same way `IUsageQueryReporters` supplies usage reads — this package only correlates the request
|
|
25
|
+
* and carries the result. `updateSettings` applies through the SAME function the matching slash
|
|
26
|
+
* command uses (issue #3282 §4: "one code path, so the behavior matches the TUI"), so whatever a
|
|
27
|
+
* command would refuse on this surface is refused here too.
|
|
28
|
+
*/
|
|
29
|
+
export interface ISettingsReporter {
|
|
30
|
+
getSettings(
|
|
31
|
+
session: IProtocolSession,
|
|
32
|
+
locality?: TCommandSurfaceLocality,
|
|
33
|
+
): ISettingsSnapshot | Promise<ISettingsSnapshot>;
|
|
34
|
+
/**
|
|
35
|
+
* Applies through the SAME function the matching slash command uses. `locality` (#3282 §4 part
|
|
36
|
+
* b-2) is forwarded to that command exactly as the transport received it, so a command that
|
|
37
|
+
* refuses a remote surface (installing a plugin) refuses identically here.
|
|
38
|
+
*/
|
|
39
|
+
updateSettings(
|
|
40
|
+
session: IProtocolSession,
|
|
41
|
+
patch: TSettingsPatch,
|
|
42
|
+
locality?: TCommandSurfaceLocality,
|
|
43
|
+
): TSettingsUpdateOutcome | Promise<TSettingsUpdateOutcome>;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function handleSettingsMessage(
|
|
47
|
+
session: IProtocolSession,
|
|
48
|
+
deliver: TOutboundDeliver,
|
|
49
|
+
msg: TSettingsMessage,
|
|
50
|
+
reporter: ISettingsReporter | undefined,
|
|
51
|
+
locality?: TCommandSurfaceLocality,
|
|
52
|
+
): void {
|
|
53
|
+
if (!reporter) {
|
|
54
|
+
deliverSettingsError(
|
|
55
|
+
deliver,
|
|
56
|
+
msg.requestId,
|
|
57
|
+
'not_available',
|
|
58
|
+
'Settings are not available on this host.',
|
|
59
|
+
);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
try {
|
|
63
|
+
if (msg.type === 'get-settings') {
|
|
64
|
+
void Promise.resolve(reporter.getSettings(session, locality)).then(
|
|
65
|
+
(settings) => deliver({ type: 'settings', requestId: msg.requestId, settings }),
|
|
66
|
+
(error) =>
|
|
67
|
+
deliverSettingsError(deliver, msg.requestId, 'update_failed', failureMessage(error)),
|
|
68
|
+
);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
void Promise.resolve(reporter.updateSettings(session, msg.patch, locality)).then(
|
|
72
|
+
(outcome) => {
|
|
73
|
+
if (outcome.ok) {
|
|
74
|
+
deliver({ type: 'settings', requestId: msg.requestId, settings: outcome.settings });
|
|
75
|
+
} else {
|
|
76
|
+
deliverSettingsError(deliver, msg.requestId, outcome.code, outcome.message);
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
(error) =>
|
|
80
|
+
deliverSettingsError(deliver, msg.requestId, 'update_failed', failureMessage(error)),
|
|
81
|
+
);
|
|
82
|
+
} catch (error) {
|
|
83
|
+
deliverSettingsError(
|
|
84
|
+
deliver,
|
|
85
|
+
msg.requestId,
|
|
86
|
+
'update_failed',
|
|
87
|
+
failureMessage(error instanceof Error ? error : String(error)),
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function deliverSettingsError(
|
|
93
|
+
deliver: TOutboundDeliver,
|
|
94
|
+
requestId: string,
|
|
95
|
+
code: 'not_available' | 'invalid' | 'refused' | 'update_failed',
|
|
96
|
+
message: string,
|
|
97
|
+
): void {
|
|
98
|
+
deliver({ type: 'settings_error', requestId, code, message });
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function failureMessage(error: Error | string): string {
|
|
102
|
+
return error instanceof Error ? error.message : String(error);
|
|
103
|
+
}
|
package/src/wire-messages.ts
CHANGED
|
@@ -3,9 +3,15 @@ import type {
|
|
|
3
3
|
IPersonalUsageRequest,
|
|
4
4
|
IUsageBySourceReport,
|
|
5
5
|
} from '@robota-sdk/agent-interface-analytics';
|
|
6
|
-
import type {
|
|
6
|
+
import type {
|
|
7
|
+
ICommandListEntry,
|
|
8
|
+
ICommandResult,
|
|
9
|
+
ICommandSkillListEntry,
|
|
10
|
+
} from '@robota-sdk/agent-interface-command';
|
|
7
11
|
import type {
|
|
8
12
|
IBackgroundJobGroupState,
|
|
13
|
+
IExecutionDetailCursor,
|
|
14
|
+
IExecutionDetailPage,
|
|
9
15
|
IExecutionWorkspaceSnapshot,
|
|
10
16
|
TBackgroundJobGroupEvent,
|
|
11
17
|
} from '@robota-sdk/agent-interface-execution';
|
|
@@ -22,27 +28,103 @@ import type {
|
|
|
22
28
|
IBranchEvent,
|
|
23
29
|
IExecutionResult,
|
|
24
30
|
IContextFileRefreshedEvent,
|
|
31
|
+
IModelListGroup,
|
|
25
32
|
IPermissionRequestEvent,
|
|
26
33
|
IPromptResolvedEvent,
|
|
27
34
|
IPlanApprovalEvent,
|
|
28
35
|
ISessionRenamedEvent,
|
|
36
|
+
ISettingsSnapshot,
|
|
29
37
|
IToolState,
|
|
38
|
+
ISessionListing,
|
|
39
|
+
ISessionStatusSnapshot,
|
|
40
|
+
ISessionSwitchedEvent,
|
|
41
|
+
TSessionChangeRefusalCode,
|
|
42
|
+
TSessionDeleteRefusalCode,
|
|
43
|
+
TSettingsPatch,
|
|
30
44
|
IUiIntentEvent,
|
|
31
45
|
TPermissionResultValue,
|
|
46
|
+
TProjectDiffRead,
|
|
47
|
+
TProjectMemoryRead,
|
|
48
|
+
TProjectStatusRead,
|
|
49
|
+
TWaitingLoopStopOutcome,
|
|
50
|
+
} from '@robota-sdk/agent-interface-session';
|
|
51
|
+
import type {
|
|
52
|
+
ISessionConversationRead,
|
|
53
|
+
TDriverId,
|
|
54
|
+
TTurnSource,
|
|
32
55
|
} from '@robota-sdk/agent-interface-session';
|
|
33
|
-
import type { ISessionConversationRead, TDriverId } from '@robota-sdk/agent-interface-session';
|
|
34
56
|
import type { TActionResponse } from '@robota-sdk/agent-interface-transport';
|
|
35
57
|
|
|
36
58
|
export type TBackgroundControlAction = 'cancel' | 'close' | 'send';
|
|
37
59
|
|
|
60
|
+
type THistoryEntry = ReturnType<ISessionConversationRead['getFullHistory']>[number];
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* #3282 §4: one agent the switcher can offer. `definedIn` is a plain-words location — a discovered
|
|
64
|
+
* file's path, or "Built-in" — never a raw internal id.
|
|
65
|
+
*/
|
|
66
|
+
export interface IWireAgentDefinitionSummary {
|
|
67
|
+
name: string;
|
|
68
|
+
description: string;
|
|
69
|
+
definedIn: string;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* #3189: one entry of the session's full history as it crosses the wire. The same record the session
|
|
74
|
+
* keeps, except that `timestamp` is an ISO 8601 string: a `Date` does not survive JSON, and a
|
|
75
|
+
* declared `Date` that arrives as a string would let a client call `Date` methods on a string.
|
|
76
|
+
*/
|
|
77
|
+
export interface IWireHistoryEntry extends Omit<THistoryEntry, 'timestamp'> {
|
|
78
|
+
/** ISO 8601. */
|
|
79
|
+
timestamp: string;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* #3189: a turn's result as it crosses the wire. The session's whole history stays behind: it only
|
|
84
|
+
* grows, so a client reads it in bounded pages with `get-history` instead.
|
|
85
|
+
*/
|
|
86
|
+
export type TWireExecutionResult = Omit<IExecutionResult, 'history'>;
|
|
87
|
+
|
|
38
88
|
/** Inbound message from client to server. */
|
|
39
89
|
export type TClientMessage =
|
|
40
90
|
| { type: 'submit'; prompt: string }
|
|
41
|
-
|
|
91
|
+
// `requestId` is echoed on the command's `command_result` or `protocol_error`, so a client with
|
|
92
|
+
// several commands in flight knows which one each answer settles.
|
|
93
|
+
| { type: 'command'; name: string; args?: string; requestId?: string }
|
|
42
94
|
| { type: 'abort' }
|
|
43
95
|
| { type: 'cancel-queue' }
|
|
44
96
|
| { type: 'get-messages' }
|
|
97
|
+
// #3189: the session's full history — what a client that renders the whole session (the TUI) shows —
|
|
98
|
+
// one bounded page at a time, from `fromIndex` (default 0). The client asks for the next page
|
|
99
|
+
// after the previous one arrived, so replies never pile up in the connection.
|
|
100
|
+
| { type: 'get-history'; fromIndex?: number }
|
|
101
|
+
// #3189: the permission and ask prompts open now, each sent again as the frame that asked it: a
|
|
102
|
+
// client that attached after a prompt was asked has not seen it.
|
|
103
|
+
| { type: 'get-prompts' }
|
|
45
104
|
| { type: 'get-context' }
|
|
105
|
+
// #3186: what every client needs beside the conversation — the commands and skills it can offer
|
|
106
|
+
// (a `/` menu), and the session's status (model, permission mode, effort, context).
|
|
107
|
+
| { type: 'get-commands' }
|
|
108
|
+
| { type: 'get-status' }
|
|
109
|
+
// #3282 §2: the models the GUI's model menu offers, grouped by configured provider profile — so
|
|
110
|
+
// the GUI never scrapes `/model`'s picker text. Choosing one sends `command` with `name: 'model'`,
|
|
111
|
+
// the SAME path `/model <id>` runs; this message only reads the choices.
|
|
112
|
+
| { type: 'list-models'; requestId: string }
|
|
113
|
+
// #3282 §4: the agent switcher's roster and its currently-selected default — so the GUI never
|
|
114
|
+
// scrapes `/agent`'s text. Choosing one sends `command` with `name: 'agent'`, the SAME path
|
|
115
|
+
// `/agent <name>` runs; this message only reads the roster and the current selection.
|
|
116
|
+
| { type: 'get-agent-definitions'; requestId: string }
|
|
117
|
+
// #3189: the host's sessions — list them, start a new one, make another current. A refused change
|
|
118
|
+
// answers `session_change_failed` with the same `requestId`.
|
|
119
|
+
| { type: 'list-sessions'; requestId: string }
|
|
120
|
+
| { type: 'new-session'; requestId?: string }
|
|
121
|
+
| { type: 'switch-session'; sessionId: string; requestId?: string }
|
|
122
|
+
// #3289 §1: rename a session from the list — current or not. Answered by `session_renamed_in_list`
|
|
123
|
+
// or `session_rename_failed`, both carrying the same `requestId`.
|
|
124
|
+
| { type: 'rename-session'; sessionId: string; name: string; requestId: string }
|
|
125
|
+
// #3289 §1: remove a stored session's record for good. Answered by `session_deleted` or
|
|
126
|
+
// `session_delete_failed`, both carrying the same `requestId`.
|
|
127
|
+
| { type: 'delete-session'; sessionId: string; requestId: string }
|
|
46
128
|
// SELFHOST-004: request the assembled trace/cost read-model (spans + cost-by-source) for the run.
|
|
47
129
|
| { type: 'get-usage-report' }
|
|
48
130
|
| {
|
|
@@ -55,6 +137,26 @@ export type TClientMessage =
|
|
|
55
137
|
| { type: 'get-executing' }
|
|
56
138
|
| { type: 'get-pending' }
|
|
57
139
|
| { type: 'get-execution-workspace' }
|
|
140
|
+
// One page of what a workspace entry recorded, from `cursor` (the previous page's `nextCursor`).
|
|
141
|
+
// Answered by `execution_detail` or `execution_detail_error` with the same `requestId`.
|
|
142
|
+
| {
|
|
143
|
+
type: 'read-execution-detail';
|
|
144
|
+
requestId: string;
|
|
145
|
+
entryId: string;
|
|
146
|
+
cursor?: IExecutionDetailCursor;
|
|
147
|
+
}
|
|
148
|
+
// Stop the self-paced loop that is waiting for its next wake; answered by `waiting_loop_stop`.
|
|
149
|
+
| { type: 'stop-waiting-loop'; requestId: string }
|
|
150
|
+
// #3282 §4c: the Project panel's "Changes" section — this workspace's git status. Answered by
|
|
151
|
+
// `project_status`, echoing `requestId`.
|
|
152
|
+
| { type: 'project-status'; requestId: string }
|
|
153
|
+
// The Project panel's "File diff" section for one file `project_status` reported — `path` exactly
|
|
154
|
+
// as reported (workspace-relative; the server re-checks it stays inside the workspace). Answered by
|
|
155
|
+
// `project_diff`.
|
|
156
|
+
| { type: 'project-diff'; requestId: string; path: string }
|
|
157
|
+
// The Project panel's "Memory" section — project memory as readable text. Answered by
|
|
158
|
+
// `project_memory`.
|
|
159
|
+
| { type: 'project-memory'; requestId: string }
|
|
58
160
|
| { type: 'get-background-tasks'; filter?: IBackgroundTaskListFilter }
|
|
59
161
|
| { type: 'get-background-task'; taskId: string }
|
|
60
162
|
| { type: 'get-background-job-groups' }
|
|
@@ -70,7 +172,12 @@ export type TClientMessage =
|
|
|
70
172
|
// REMOTE-013 E4 session-resume: `resume` asks the host to replay the tail after `lastSeq` (the last seq the
|
|
71
173
|
// client applied); `ack` lets the host free its un-acked buffer up to `seq`. Only meaningful post-E3-accept.
|
|
72
174
|
| { type: 'resume'; lastSeq: number }
|
|
73
|
-
| { type: 'ack'; seq: number }
|
|
175
|
+
| { type: 'ack'; seq: number }
|
|
176
|
+
// #3282 §4a: the GUI Settings screen. A snapshot fetch and a discriminated single-field patch,
|
|
177
|
+
// never command text — the server applies a patch through the same function its slash command
|
|
178
|
+
// uses, so the two paths cannot drift. Answered by `settings` or `settings_error`.
|
|
179
|
+
| { type: 'get-settings'; requestId: string }
|
|
180
|
+
| { type: 'update-settings'; requestId: string; patch: TSettingsPatch };
|
|
74
181
|
|
|
75
182
|
/** Outbound message from server to client. */
|
|
76
183
|
export type TServerMessage =
|
|
@@ -82,18 +189,116 @@ export type TServerMessage =
|
|
|
82
189
|
| { type: 'tool_start'; state: IToolState; driverId?: TDriverId }
|
|
83
190
|
| { type: 'tool_end'; state: IToolState; driverId?: TDriverId }
|
|
84
191
|
| { type: 'thinking'; isThinking: boolean; driverId?: TDriverId }
|
|
85
|
-
| { type: 'complete'; result:
|
|
86
|
-
| { type: 'interrupted'; result:
|
|
87
|
-
| {
|
|
192
|
+
| { type: 'complete'; result: TWireExecutionResult; driverId?: TDriverId }
|
|
193
|
+
| { type: 'interrupted'; result: TWireExecutionResult; driverId?: TDriverId }
|
|
194
|
+
| {
|
|
195
|
+
type: 'error';
|
|
196
|
+
/** The raw failure text — kept for a "Details" disclosure; never the whole story on its own. */
|
|
197
|
+
message: string;
|
|
198
|
+
/**
|
|
199
|
+
* What kind of failure this was, when it's known — so a renderer can say what happened and
|
|
200
|
+
* what to do next in plain words instead of showing `message` verbatim (#3289 §3). Additive:
|
|
201
|
+
* absent for a session error this classification does not recognize (unchanged behavior).
|
|
202
|
+
*/
|
|
203
|
+
code?: 'auth' | 'rate_limit' | 'model_unavailable' | 'network' | 'provider';
|
|
204
|
+
/** The provider/profile name the failure came from, when `code` names one. */
|
|
205
|
+
provider?: string;
|
|
206
|
+
/** For `code: 'rate_limit'`, how long until a retry may succeed, when the provider said so. */
|
|
207
|
+
retryAfterSeconds?: number;
|
|
208
|
+
/**
|
|
209
|
+
* For `code: 'model_unavailable'`, the model the failed request tried — captured at the moment
|
|
210
|
+
* of failure so a renderer never has to fall back to whatever model is live by the time it
|
|
211
|
+
* draws this notice (which may already be a different one the person switched to).
|
|
212
|
+
*/
|
|
213
|
+
model?: string;
|
|
214
|
+
driverId?: TDriverId;
|
|
215
|
+
}
|
|
88
216
|
| {
|
|
89
217
|
type: 'command_result';
|
|
90
218
|
name: string;
|
|
91
219
|
message: string;
|
|
92
220
|
success: boolean;
|
|
93
221
|
data?: ICommandResult['data'];
|
|
222
|
+
/** The `requestId` of the `command` this answers, when it carried one. */
|
|
223
|
+
requestId?: string;
|
|
224
|
+
}
|
|
225
|
+
| {
|
|
226
|
+
type: 'messages';
|
|
227
|
+
messages: ReturnType<ISessionConversationRead['getMessages']>;
|
|
228
|
+
/**
|
|
229
|
+
* #3288 §2: the SAME history, projected into display segments (text runs and finished tool
|
|
230
|
+
* calls, diffs included) — so a reload/reconnect/resume replay shows tool rows instead of bare
|
|
231
|
+
* text. Optional so an older host that has not grown `getMessagesDisplay()` yet still sends a
|
|
232
|
+
* valid frame; a client without this field falls back to `messages`-only (text bubbles), the
|
|
233
|
+
* same as before this existed.
|
|
234
|
+
*/
|
|
235
|
+
display?: ReturnType<ISessionConversationRead['getMessagesDisplay']>;
|
|
236
|
+
/**
|
|
237
|
+
* #3289 §3: this connection's own server-assigned driver id, carried on the first frame every
|
|
238
|
+
* connection already gets — so a client can tell its OWN turns from a co-driver's instead of
|
|
239
|
+
* treating everything but the literal `'owner'` id as someone else (REMOTE-014 E5 display-only).
|
|
240
|
+
*/
|
|
241
|
+
driverId?: TDriverId;
|
|
94
242
|
}
|
|
95
|
-
|
|
243
|
+
// #3189: one page of the full history. `entries` start at `startIndex` of the `total` the session
|
|
244
|
+
// holds now, and stop before a page grows past a bounded size (a single larger entry is sent alone).
|
|
245
|
+
| { type: 'history'; startIndex: number; total: number; entries: IWireHistoryEntry[] }
|
|
246
|
+
// Sent in reply to `get-context`, and pushed whenever the session's context window changes.
|
|
96
247
|
| { type: 'context'; state: ReturnType<ISessionConversationRead['getContextState']> }
|
|
248
|
+
// #3189: the full history gained entries that no streamed frame carries (a compaction, a skill
|
|
249
|
+
// activation, a memory event). A client that shows the full history re-reads it with `get-history`.
|
|
250
|
+
| { type: 'history_changed' }
|
|
251
|
+
// #3189: where the turn now starting came from (the user, a wake-up, a peer, an external event).
|
|
252
|
+
| { type: 'turn_source'; source: TTurnSource }
|
|
253
|
+
| { type: 'commands'; commands: ICommandListEntry[]; skills: ICommandSkillListEntry[] }
|
|
254
|
+
// Sent in reply to `get-status`, and pushed whenever the session's status changes.
|
|
255
|
+
| { type: 'session_status'; status: ISessionStatusSnapshot }
|
|
256
|
+
// #3282 §2: reply to `list-models`, echoing its `requestId`. `groups` is current-profile first;
|
|
257
|
+
// `currentProfile` is absent only when no provider profile is configured at all.
|
|
258
|
+
| {
|
|
259
|
+
type: 'model_list';
|
|
260
|
+
requestId: string;
|
|
261
|
+
groups: readonly IModelListGroup[];
|
|
262
|
+
currentProfile?: string;
|
|
263
|
+
currentModel: string;
|
|
264
|
+
}
|
|
265
|
+
// #3282 §4: reply to `get-agent-definitions`, echoing its `requestId`. `current` is always one of
|
|
266
|
+
// `agents`' names (the fallback default when nothing was ever selected).
|
|
267
|
+
| {
|
|
268
|
+
type: 'agent_definitions';
|
|
269
|
+
requestId: string;
|
|
270
|
+
agents: readonly IWireAgentDefinitionSummary[];
|
|
271
|
+
current: string;
|
|
272
|
+
}
|
|
273
|
+
| { type: 'sessions'; requestId: string; listing: ISessionListing }
|
|
274
|
+
| {
|
|
275
|
+
type: 'sessions_error';
|
|
276
|
+
requestId: string;
|
|
277
|
+
code: 'not_available' | 'list_failed';
|
|
278
|
+
message: string;
|
|
279
|
+
}
|
|
280
|
+
// This client's session is now another one; it re-reads what it shows. A host that binds each
|
|
281
|
+
// client to its own session sends it only to the client that moved.
|
|
282
|
+
| { type: 'session_switched'; event: ISessionSwitchedEvent }
|
|
283
|
+
// #3189: a new-session or switch-session was refused; `code` says why without parsing `message`.
|
|
284
|
+
| {
|
|
285
|
+
type: 'session_change_failed';
|
|
286
|
+
code: TSessionChangeRefusalCode;
|
|
287
|
+
message: string;
|
|
288
|
+
requestId?: string;
|
|
289
|
+
}
|
|
290
|
+
// #3289 §1: a `rename-session` succeeded (current session or not); the client refreshes its listing.
|
|
291
|
+
| { type: 'session_renamed_in_list'; requestId: string; sessionId: string; name: string }
|
|
292
|
+
| { type: 'session_rename_failed'; requestId: string; message: string }
|
|
293
|
+
// #3289 §1: a `delete-session` succeeded; the client refreshes its listing and, if it was showing
|
|
294
|
+
// the deleted session, re-reads what it now shows (the host has already switched it away).
|
|
295
|
+
| { type: 'session_deleted'; requestId: string; sessionId: string }
|
|
296
|
+
| {
|
|
297
|
+
type: 'session_delete_failed';
|
|
298
|
+
requestId: string;
|
|
299
|
+
code: TSessionDeleteRefusalCode;
|
|
300
|
+
message: string;
|
|
301
|
+
}
|
|
97
302
|
// SELFHOST-004 (P5, TC-08): carry the assembled trace/cost read-model (per-op span timeline +
|
|
98
303
|
// cost-by-source) across the sidecar boundary — no existing variant carries per-op `durationMs` or
|
|
99
304
|
// per-source `costUsd`. The GUI renders it renderer-side.
|
|
@@ -119,8 +324,20 @@ export type TServerMessage =
|
|
|
119
324
|
message: string;
|
|
120
325
|
}
|
|
121
326
|
| { type: 'executing'; executing: boolean }
|
|
122
|
-
|
|
327
|
+
// The next queued prompt and how many wait. Sent in reply to `get-pending`, and to a `submit` once
|
|
328
|
+
// the host has taken the prompt (queued it behind a running turn, or run it).
|
|
329
|
+
| { type: 'pending'; pending: string | null; pendingCount?: number }
|
|
123
330
|
| { type: 'execution_workspace_event'; snapshot: IExecutionWorkspaceSnapshot }
|
|
331
|
+
| { type: 'execution_detail'; requestId: string; page: IExecutionDetailPage }
|
|
332
|
+
| { type: 'execution_detail_error'; requestId: string; message: string }
|
|
333
|
+
| { type: 'waiting_loop_stop'; requestId: string; outcome: TWaitingLoopStopOutcome }
|
|
334
|
+
// #3282 §4c: the Project panel's reads. Each result crosses the wire UNCHANGED as the session
|
|
335
|
+
// method's own return value (same convention as `waiting_loop_stop`'s `outcome` above) — the
|
|
336
|
+
// `kind` discriminant carries the non-repository / outside-workspace / unavailable / failed cases,
|
|
337
|
+
// so there is no separate `_error` sibling to keep in sync with these.
|
|
338
|
+
| { type: 'project_status'; requestId: string; result: TProjectStatusRead }
|
|
339
|
+
| { type: 'project_diff'; requestId: string; result: TProjectDiffRead }
|
|
340
|
+
| { type: 'project_memory'; requestId: string; result: TProjectMemoryRead }
|
|
124
341
|
| { type: 'background_task_event'; event: TBackgroundTaskEvent }
|
|
125
342
|
| { type: 'background_job_group_event'; event: TBackgroundJobGroupEvent }
|
|
126
343
|
| { type: 'plan_event'; event: IPlanApprovalEvent }
|
|
@@ -151,10 +368,20 @@ export type TServerMessage =
|
|
|
151
368
|
success: boolean;
|
|
152
369
|
message?: string;
|
|
153
370
|
}
|
|
154
|
-
|
|
371
|
+
// `requestId` names the `command` whose failure this reports; a refusal of anything else has none.
|
|
372
|
+
| { type: 'protocol_error'; message: string; requestId?: string }
|
|
155
373
|
// REMOTE-013 E4: sent instead of a replay when the client's `lastSeq` predates the host's retained buffer
|
|
156
374
|
// (overrun) — the client must do a full `get-messages` refresh rather than accept a silent gap.
|
|
157
|
-
| { type: 'resume_gap' }
|
|
375
|
+
| { type: 'resume_gap' }
|
|
376
|
+
// #3282 §4a: the Settings screen's snapshot, in reply to `get-settings` or `update-settings`. The
|
|
377
|
+
// same type answers both, the way `session_status` answers `get-status` and a status change alike.
|
|
378
|
+
| { type: 'settings'; requestId: string; settings: ISettingsSnapshot }
|
|
379
|
+
| {
|
|
380
|
+
type: 'settings_error';
|
|
381
|
+
requestId: string;
|
|
382
|
+
code: 'not_available' | 'invalid' | 'refused' | 'update_failed';
|
|
383
|
+
message: string;
|
|
384
|
+
};
|
|
158
385
|
|
|
159
386
|
/**
|
|
160
387
|
* REMOTE-013 E4: a server message stamped with its monotonic session sequence number (added by the
|
|
@@ -1,252 +0,0 @@
|
|
|
1
|
-
import { IPersonalUsageReport, IPersonalUsageRequest, IUsageBySourceReport } from "@robota-sdk/agent-interface-analytics";
|
|
2
|
-
import { ICommandResult } from "@robota-sdk/agent-interface-command";
|
|
3
|
-
import { IBackgroundJobGroupState, IBackgroundTaskInput, IBackgroundTaskListFilter, IBackgroundTaskLogCursor, IBackgroundTaskLogPage, IBackgroundTaskState, IExecutionWorkspaceSnapshot, TBackgroundJobGroupEvent, TBackgroundTaskEvent } from "@robota-sdk/agent-interface-execution";
|
|
4
|
-
import { IAskRequestEvent, IBranchEvent, IContextFileRefreshedEvent, IExecutionResult, IPermissionRequestEvent, IPlanApprovalEvent, IPromptResolvedEvent, ISessionConversationRead, ISessionRenamedEvent, IToolState, IUiIntentEvent, TDriverId, TPermissionResultValue } from "@robota-sdk/agent-interface-session";
|
|
5
|
-
import { TActionResponse } from "@robota-sdk/agent-interface-transport";
|
|
6
|
-
//#region src/wire-messages.d.ts
|
|
7
|
-
type TBackgroundControlAction = 'cancel' | 'close' | 'send';
|
|
8
|
-
/** Inbound message from client to server. */
|
|
9
|
-
type TClientMessage = {
|
|
10
|
-
type: 'submit';
|
|
11
|
-
prompt: string;
|
|
12
|
-
} | {
|
|
13
|
-
type: 'command';
|
|
14
|
-
name: string;
|
|
15
|
-
args?: string;
|
|
16
|
-
} | {
|
|
17
|
-
type: 'abort';
|
|
18
|
-
} | {
|
|
19
|
-
type: 'cancel-queue';
|
|
20
|
-
} | {
|
|
21
|
-
type: 'get-messages';
|
|
22
|
-
} | {
|
|
23
|
-
type: 'get-context';
|
|
24
|
-
} | {
|
|
25
|
-
type: 'get-usage-report';
|
|
26
|
-
} | {
|
|
27
|
-
type: 'get-personal-usage-report';
|
|
28
|
-
requestId: string;
|
|
29
|
-
period: IPersonalUsageRequest['period'];
|
|
30
|
-
timezone: string;
|
|
31
|
-
} | {
|
|
32
|
-
type: 'get-stored-session-usage-report';
|
|
33
|
-
requestId: string;
|
|
34
|
-
sessionId: string;
|
|
35
|
-
} | {
|
|
36
|
-
type: 'get-executing';
|
|
37
|
-
} | {
|
|
38
|
-
type: 'get-pending';
|
|
39
|
-
} | {
|
|
40
|
-
type: 'get-execution-workspace';
|
|
41
|
-
} | {
|
|
42
|
-
type: 'get-background-tasks';
|
|
43
|
-
filter?: IBackgroundTaskListFilter;
|
|
44
|
-
} | {
|
|
45
|
-
type: 'get-background-task';
|
|
46
|
-
taskId: string;
|
|
47
|
-
} | {
|
|
48
|
-
type: 'get-background-job-groups';
|
|
49
|
-
} | {
|
|
50
|
-
type: 'get-background-job-group';
|
|
51
|
-
groupId: string;
|
|
52
|
-
} | {
|
|
53
|
-
type: 'wait-background-job-group';
|
|
54
|
-
groupId: string;
|
|
55
|
-
} | {
|
|
56
|
-
type: 'cancel-background-task';
|
|
57
|
-
taskId: string;
|
|
58
|
-
reason?: string;
|
|
59
|
-
} | {
|
|
60
|
-
type: 'close-background-task';
|
|
61
|
-
taskId: string;
|
|
62
|
-
} | {
|
|
63
|
-
type: 'send-background-task';
|
|
64
|
-
taskId: string;
|
|
65
|
-
input: IBackgroundTaskInput;
|
|
66
|
-
} | {
|
|
67
|
-
type: 'read-background-task-log';
|
|
68
|
-
taskId: string;
|
|
69
|
-
cursor?: IBackgroundTaskLogCursor;
|
|
70
|
-
} | {
|
|
71
|
-
type: 'permission-response';
|
|
72
|
-
id: string;
|
|
73
|
-
result: TPermissionResultValue;
|
|
74
|
-
} | {
|
|
75
|
-
type: 'ask-response';
|
|
76
|
-
id: string;
|
|
77
|
-
response: TActionResponse;
|
|
78
|
-
} | {
|
|
79
|
-
type: 'resume';
|
|
80
|
-
lastSeq: number;
|
|
81
|
-
} | {
|
|
82
|
-
type: 'ack';
|
|
83
|
-
seq: number;
|
|
84
|
-
};
|
|
85
|
-
/** Outbound message from server to client. */
|
|
86
|
-
type TServerMessage = {
|
|
87
|
-
type: 'text_delta';
|
|
88
|
-
delta: string;
|
|
89
|
-
driverId?: TDriverId;
|
|
90
|
-
} | {
|
|
91
|
-
type: 'user_message';
|
|
92
|
-
content: string;
|
|
93
|
-
driverId?: TDriverId;
|
|
94
|
-
} | {
|
|
95
|
-
type: 'tool_start';
|
|
96
|
-
state: IToolState;
|
|
97
|
-
driverId?: TDriverId;
|
|
98
|
-
} | {
|
|
99
|
-
type: 'tool_end';
|
|
100
|
-
state: IToolState;
|
|
101
|
-
driverId?: TDriverId;
|
|
102
|
-
} | {
|
|
103
|
-
type: 'thinking';
|
|
104
|
-
isThinking: boolean;
|
|
105
|
-
driverId?: TDriverId;
|
|
106
|
-
} | {
|
|
107
|
-
type: 'complete';
|
|
108
|
-
result: IExecutionResult;
|
|
109
|
-
driverId?: TDriverId;
|
|
110
|
-
} | {
|
|
111
|
-
type: 'interrupted';
|
|
112
|
-
result: IExecutionResult;
|
|
113
|
-
driverId?: TDriverId;
|
|
114
|
-
} | {
|
|
115
|
-
type: 'error';
|
|
116
|
-
message: string;
|
|
117
|
-
driverId?: TDriverId;
|
|
118
|
-
} | {
|
|
119
|
-
type: 'command_result';
|
|
120
|
-
name: string;
|
|
121
|
-
message: string;
|
|
122
|
-
success: boolean;
|
|
123
|
-
data?: ICommandResult['data'];
|
|
124
|
-
} | {
|
|
125
|
-
type: 'messages';
|
|
126
|
-
messages: ReturnType<ISessionConversationRead['getMessages']>;
|
|
127
|
-
} | {
|
|
128
|
-
type: 'context';
|
|
129
|
-
state: ReturnType<ISessionConversationRead['getContextState']>;
|
|
130
|
-
} | {
|
|
131
|
-
type: 'usage_report';
|
|
132
|
-
report: IUsageBySourceReport;
|
|
133
|
-
} | {
|
|
134
|
-
type: 'personal_usage_report';
|
|
135
|
-
requestId: string;
|
|
136
|
-
report: IPersonalUsageReport;
|
|
137
|
-
} | {
|
|
138
|
-
type: 'personal_usage_report_error';
|
|
139
|
-
requestId: string;
|
|
140
|
-
code: 'not_available' | 'report_failed';
|
|
141
|
-
message: string;
|
|
142
|
-
} | {
|
|
143
|
-
type: 'stored_session_usage_report';
|
|
144
|
-
requestId: string;
|
|
145
|
-
sessionId: string;
|
|
146
|
-
report: IUsageBySourceReport;
|
|
147
|
-
} | {
|
|
148
|
-
type: 'stored_session_usage_report_error';
|
|
149
|
-
requestId: string;
|
|
150
|
-
sessionId: string;
|
|
151
|
-
code: 'not_available' | 'report_failed';
|
|
152
|
-
message: string;
|
|
153
|
-
} | {
|
|
154
|
-
type: 'executing';
|
|
155
|
-
executing: boolean;
|
|
156
|
-
} | {
|
|
157
|
-
type: 'pending';
|
|
158
|
-
pending: string | null;
|
|
159
|
-
} | {
|
|
160
|
-
type: 'execution_workspace_event';
|
|
161
|
-
snapshot: IExecutionWorkspaceSnapshot;
|
|
162
|
-
} | {
|
|
163
|
-
type: 'background_task_event';
|
|
164
|
-
event: TBackgroundTaskEvent;
|
|
165
|
-
} | {
|
|
166
|
-
type: 'background_job_group_event';
|
|
167
|
-
event: TBackgroundJobGroupEvent;
|
|
168
|
-
} | {
|
|
169
|
-
type: 'plan_event';
|
|
170
|
-
event: IPlanApprovalEvent;
|
|
171
|
-
} | {
|
|
172
|
-
type: 'context_file_refreshed';
|
|
173
|
-
event: IContextFileRefreshedEvent;
|
|
174
|
-
} | {
|
|
175
|
-
type: 'branch_event';
|
|
176
|
-
event: IBranchEvent;
|
|
177
|
-
} | {
|
|
178
|
-
type: 'background_tasks';
|
|
179
|
-
tasks: IBackgroundTaskState[];
|
|
180
|
-
} | {
|
|
181
|
-
type: 'background_task';
|
|
182
|
-
taskId: string;
|
|
183
|
-
task: IBackgroundTaskState | null;
|
|
184
|
-
} | {
|
|
185
|
-
type: 'background_job_groups';
|
|
186
|
-
groups: IBackgroundJobGroupState[];
|
|
187
|
-
} | {
|
|
188
|
-
type: 'background_job_group';
|
|
189
|
-
groupId: string;
|
|
190
|
-
group: IBackgroundJobGroupState | null;
|
|
191
|
-
} | {
|
|
192
|
-
type: 'background_task_log';
|
|
193
|
-
taskId: string;
|
|
194
|
-
page: IBackgroundTaskLogPage;
|
|
195
|
-
} | {
|
|
196
|
-
type: 'permission_request';
|
|
197
|
-
event: IPermissionRequestEvent;
|
|
198
|
-
} | {
|
|
199
|
-
type: 'ask_request';
|
|
200
|
-
event: IAskRequestEvent;
|
|
201
|
-
} | {
|
|
202
|
-
type: 'prompt_resolved';
|
|
203
|
-
event: IPromptResolvedEvent;
|
|
204
|
-
} | {
|
|
205
|
-
type: 'ui_intent';
|
|
206
|
-
event: IUiIntentEvent;
|
|
207
|
-
} | {
|
|
208
|
-
type: 'session_renamed';
|
|
209
|
-
event: ISessionRenamedEvent;
|
|
210
|
-
} | {
|
|
211
|
-
type: 'history_cleared';
|
|
212
|
-
} | {
|
|
213
|
-
type: 'background_task_control_result';
|
|
214
|
-
action: TBackgroundControlAction;
|
|
215
|
-
taskId: string;
|
|
216
|
-
success: boolean;
|
|
217
|
-
message?: string;
|
|
218
|
-
} | {
|
|
219
|
-
type: 'protocol_error';
|
|
220
|
-
message: string;
|
|
221
|
-
} | {
|
|
222
|
-
type: 'resume_gap';
|
|
223
|
-
};
|
|
224
|
-
/**
|
|
225
|
-
* REMOTE-013 E4: a server message stamped with its monotonic session sequence number (added by the
|
|
226
|
-
* {@link SessionResumeBridge} on the reconnectable WebRTC path). Intersecting over the union distributes the
|
|
227
|
-
* `seq` field onto every variant. The WS localhost path never stamps it (a `type`-dispatching client ignores
|
|
228
|
-
* an absent/extra `seq`).
|
|
229
|
-
*/
|
|
230
|
-
type TSeqServerMessage = TServerMessage & {
|
|
231
|
-
seq: number;
|
|
232
|
-
};
|
|
233
|
-
//#endregion
|
|
234
|
-
//#region src/message-decoders.d.ts
|
|
235
|
-
type TMessageDecodeResult<TMessage> = {
|
|
236
|
-
readonly ok: true;
|
|
237
|
-
readonly message: TMessage;
|
|
238
|
-
} | {
|
|
239
|
-
readonly ok: false;
|
|
240
|
-
readonly reason: string;
|
|
241
|
-
};
|
|
242
|
-
/** Serialized frames larger than this are refused before any parse (a bounded inbound budget). */
|
|
243
|
-
declare const MAX_INBOUND_FRAME_BYTES: number;
|
|
244
|
-
/** Total decode of a parsed client frame. */
|
|
245
|
-
declare function decodeClientMessage(value: unknown): TMessageDecodeResult<TClientMessage>;
|
|
246
|
-
/** Variant-level decode of a parsed server frame (foreign-owned payloads as records, see header). */
|
|
247
|
-
declare function decodeServerMessage(value: unknown): TMessageDecodeResult<TServerMessage>;
|
|
248
|
-
/** `raw string → JSON → owner decoder`, the one path a carrier implements. */
|
|
249
|
-
declare function decodeFrame<TMessage>(data: string, decode: (value: unknown) => TMessageDecodeResult<TMessage>): TMessageDecodeResult<TMessage>;
|
|
250
|
-
//#endregion
|
|
251
|
-
export { decodeServerMessage as a, TServerMessage as c, decodeFrame as i, TMessageDecodeResult as n, TClientMessage as o, decodeClientMessage as r, TSeqServerMessage as s, MAX_INBOUND_FRAME_BYTES as t };
|
|
252
|
-
//# sourceMappingURL=message-decoders-BB8n-H2X.d.ts.map
|