@hearthscale/app 0.0.0-stage → 0.1.0
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 +25 -0
- package/README.md +90 -2
- package/dist/index.d.ts +3230 -0
- package/package.json +32 -3
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,3230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The platform half of the contract, generated from the Rust types of
|
|
3
|
+
* the `contract` crate by `npm run contract` in `apps/platform/scripts`.
|
|
4
|
+
* Do not edit: change the Rust types and run the command again.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* One line of a session log: the body its `type` names, and the envelope
|
|
9
|
+
* every entry shares. Tree entries carry `parent`; the others are out of
|
|
10
|
+
* the tree and apply to the whole session.
|
|
11
|
+
*/
|
|
12
|
+
type Entry = {
|
|
13
|
+
seq: number;
|
|
14
|
+
id: string;
|
|
15
|
+
at: string;
|
|
16
|
+
session: string;
|
|
17
|
+
by: PrincipalRef;
|
|
18
|
+
origin: Origin;
|
|
19
|
+
} & ({
|
|
20
|
+
app: string;
|
|
21
|
+
appVersion: string;
|
|
22
|
+
agent: string;
|
|
23
|
+
authoritySession: string;
|
|
24
|
+
project?: string;
|
|
25
|
+
forkedFrom?: ForkPoint;
|
|
26
|
+
spawnedBy?: SpawnPoint;
|
|
27
|
+
startedBy?: PrincipalRef;
|
|
28
|
+
type: 'session.created';
|
|
29
|
+
} | {
|
|
30
|
+
title: string;
|
|
31
|
+
type: 'session.title';
|
|
32
|
+
} | {
|
|
33
|
+
turn: string;
|
|
34
|
+
result: Structured;
|
|
35
|
+
type: 'session.result';
|
|
36
|
+
} | {
|
|
37
|
+
type: 'session.closed';
|
|
38
|
+
} | {
|
|
39
|
+
project: string | null;
|
|
40
|
+
pinned: boolean;
|
|
41
|
+
archived: boolean;
|
|
42
|
+
rank: number;
|
|
43
|
+
type: 'session.filing';
|
|
44
|
+
} | {
|
|
45
|
+
model?: string | null;
|
|
46
|
+
type: 'session.settings';
|
|
47
|
+
} | {
|
|
48
|
+
to: string | null;
|
|
49
|
+
type: 'session.leaf';
|
|
50
|
+
} | {
|
|
51
|
+
attached: SessionRoot[];
|
|
52
|
+
type: 'session.roots';
|
|
53
|
+
} | {
|
|
54
|
+
turn: string;
|
|
55
|
+
model: string;
|
|
56
|
+
provider: string;
|
|
57
|
+
location: ModelLocation;
|
|
58
|
+
revision: string;
|
|
59
|
+
type: 'turn.started';
|
|
60
|
+
} | {
|
|
61
|
+
turn: string;
|
|
62
|
+
stopReason: StopReason;
|
|
63
|
+
type: 'turn.finished';
|
|
64
|
+
} | {
|
|
65
|
+
parent: string | null;
|
|
66
|
+
parts: UserPart[];
|
|
67
|
+
type: 'user.message';
|
|
68
|
+
} | {
|
|
69
|
+
parent: string | null;
|
|
70
|
+
turn: string;
|
|
71
|
+
parts: AgentPart[];
|
|
72
|
+
toolCalls?: ToolCall[];
|
|
73
|
+
usage?: Usage;
|
|
74
|
+
stop: AgentStop;
|
|
75
|
+
model: string;
|
|
76
|
+
provider: string;
|
|
77
|
+
error?: string;
|
|
78
|
+
type: 'agent.message';
|
|
79
|
+
} | {
|
|
80
|
+
turn: string;
|
|
81
|
+
partId: string;
|
|
82
|
+
text: string;
|
|
83
|
+
type: 'agent.part';
|
|
84
|
+
} | {
|
|
85
|
+
callId: string;
|
|
86
|
+
turn: string;
|
|
87
|
+
/**
|
|
88
|
+
* The call this one runs under; absent for a call of the turn.
|
|
89
|
+
*/
|
|
90
|
+
under?: string;
|
|
91
|
+
name: string;
|
|
92
|
+
/**
|
|
93
|
+
* JSON-encoded, as the model emitted them.
|
|
94
|
+
*/
|
|
95
|
+
arguments: string;
|
|
96
|
+
context: CallContext;
|
|
97
|
+
pin?: string;
|
|
98
|
+
/**
|
|
99
|
+
* Absent for a core tool, and for a name that named no tool.
|
|
100
|
+
*/
|
|
101
|
+
label?: CallLabel;
|
|
102
|
+
type: 'call.prepared';
|
|
103
|
+
} | {
|
|
104
|
+
callId: string;
|
|
105
|
+
turn: string;
|
|
106
|
+
under?: string;
|
|
107
|
+
executor: Executor;
|
|
108
|
+
type: 'call.dispatched';
|
|
109
|
+
} | {
|
|
110
|
+
/**
|
|
111
|
+
* The tree parent; a call under another call has none and stays
|
|
112
|
+
* out of the tree.
|
|
113
|
+
*/
|
|
114
|
+
parent?: string | null;
|
|
115
|
+
turn: string;
|
|
116
|
+
callId: string;
|
|
117
|
+
under?: string;
|
|
118
|
+
content: Content[];
|
|
119
|
+
structured?: Structured;
|
|
120
|
+
/**
|
|
121
|
+
* Values for the view that renders the result; they never reach a
|
|
122
|
+
* model.
|
|
123
|
+
*/
|
|
124
|
+
meta?: {
|
|
125
|
+
[k: string]: unknown;
|
|
126
|
+
};
|
|
127
|
+
isError: boolean;
|
|
128
|
+
outcome: ToolOutcome;
|
|
129
|
+
/**
|
|
130
|
+
* The provider's view that renders the result, as its manifest
|
|
131
|
+
* declares it for the tool.
|
|
132
|
+
*/
|
|
133
|
+
view?: ViewRef;
|
|
134
|
+
/**
|
|
135
|
+
* The paths the call changed, and the ones it read.
|
|
136
|
+
*/
|
|
137
|
+
wrote?: string[];
|
|
138
|
+
read?: string[];
|
|
139
|
+
/**
|
|
140
|
+
* The model tokens the body spent through `models.complete`.
|
|
141
|
+
*/
|
|
142
|
+
usage?: Usage;
|
|
143
|
+
type: 'tool.result';
|
|
144
|
+
} | {
|
|
145
|
+
turn: string;
|
|
146
|
+
callId: string;
|
|
147
|
+
decision: Decision;
|
|
148
|
+
decidedBy: DecisionBy;
|
|
149
|
+
review?: ReviewRecord;
|
|
150
|
+
ask?: string;
|
|
151
|
+
grant?: Grant;
|
|
152
|
+
reason?: string;
|
|
153
|
+
type: 'consent.decision';
|
|
154
|
+
} | {
|
|
155
|
+
cell: number;
|
|
156
|
+
callId: string;
|
|
157
|
+
turn: string;
|
|
158
|
+
type: 'cell.started';
|
|
159
|
+
} | {
|
|
160
|
+
cell: number;
|
|
161
|
+
callId: string;
|
|
162
|
+
outcome: CellOutcome;
|
|
163
|
+
/**
|
|
164
|
+
* Why a program failed, in words.
|
|
165
|
+
*/
|
|
166
|
+
error?: string;
|
|
167
|
+
/**
|
|
168
|
+
* The tail of the program's output.
|
|
169
|
+
*/
|
|
170
|
+
output: string;
|
|
171
|
+
type: 'cell.ended';
|
|
172
|
+
} | {
|
|
173
|
+
process: number;
|
|
174
|
+
callId: string;
|
|
175
|
+
turn: string;
|
|
176
|
+
command: string;
|
|
177
|
+
pid: number;
|
|
178
|
+
startedAt: string;
|
|
179
|
+
type: 'process.started';
|
|
180
|
+
} | {
|
|
181
|
+
process: number;
|
|
182
|
+
callId: string;
|
|
183
|
+
outcome: ProcessOutcome;
|
|
184
|
+
/**
|
|
185
|
+
* The exit code of a command that exited.
|
|
186
|
+
*/
|
|
187
|
+
code?: number;
|
|
188
|
+
/**
|
|
189
|
+
* Why a command was stopped, in words.
|
|
190
|
+
*/
|
|
191
|
+
reason?: string;
|
|
192
|
+
/**
|
|
193
|
+
* The tail of the command's output.
|
|
194
|
+
*/
|
|
195
|
+
output: string;
|
|
196
|
+
type: 'process.ended';
|
|
197
|
+
} | {
|
|
198
|
+
ask: Ask;
|
|
199
|
+
type: 'ask.opened';
|
|
200
|
+
} | {
|
|
201
|
+
ask: string;
|
|
202
|
+
outcome: AskOutcome;
|
|
203
|
+
answeredBy?: PrincipalRef;
|
|
204
|
+
option?: string;
|
|
205
|
+
allow?: boolean;
|
|
206
|
+
grant?: Grant;
|
|
207
|
+
/**
|
|
208
|
+
* The person's own words, answering a question.
|
|
209
|
+
*/
|
|
210
|
+
text?: string;
|
|
211
|
+
type: 'ask.closed';
|
|
212
|
+
} | {
|
|
213
|
+
parent: string | null;
|
|
214
|
+
app: string;
|
|
215
|
+
kind: string;
|
|
216
|
+
data: unknown;
|
|
217
|
+
/**
|
|
218
|
+
* Text the model sees for the entry; absent, it is display only.
|
|
219
|
+
*/
|
|
220
|
+
context?: string;
|
|
221
|
+
type: 'app.entry';
|
|
222
|
+
} | {
|
|
223
|
+
asset: string;
|
|
224
|
+
model: string | null;
|
|
225
|
+
/**
|
|
226
|
+
* The name the model that read the picture shows under.
|
|
227
|
+
*/
|
|
228
|
+
label?: string;
|
|
229
|
+
text?: string;
|
|
230
|
+
reason?: DescriptionFailure;
|
|
231
|
+
usage?: Usage;
|
|
232
|
+
type: 'asset.described';
|
|
233
|
+
} | {
|
|
234
|
+
watermark: string;
|
|
235
|
+
rounds: number;
|
|
236
|
+
type: 'compaction.cleared';
|
|
237
|
+
} | {
|
|
238
|
+
tailStart: string;
|
|
239
|
+
summary: string;
|
|
240
|
+
sections: {
|
|
241
|
+
[k: string]: string;
|
|
242
|
+
};
|
|
243
|
+
kept: string[];
|
|
244
|
+
tokensBefore: number;
|
|
245
|
+
tokensAfter: number;
|
|
246
|
+
model: string;
|
|
247
|
+
provider: string;
|
|
248
|
+
location: ModelLocation;
|
|
249
|
+
usage?: Usage;
|
|
250
|
+
type: 'compaction.folded';
|
|
251
|
+
} | {
|
|
252
|
+
reason: string;
|
|
253
|
+
model: string;
|
|
254
|
+
type: 'compaction.failed';
|
|
255
|
+
} | {
|
|
256
|
+
parent: string | null;
|
|
257
|
+
turn: string;
|
|
258
|
+
what: BudgetWhat;
|
|
259
|
+
type: 'budget.reached';
|
|
260
|
+
} | {
|
|
261
|
+
parent: string | null;
|
|
262
|
+
turn: string;
|
|
263
|
+
calls: string[];
|
|
264
|
+
type: 'repair.interrupted';
|
|
265
|
+
});
|
|
266
|
+
/**
|
|
267
|
+
* Who acts. A surface is one attachment of a client; an app is a package;
|
|
268
|
+
* a view is an app's view hosted by another app; the core is the daemon
|
|
269
|
+
* itself, which appears only as the author of entries it writes.
|
|
270
|
+
*/
|
|
271
|
+
type PrincipalRef = {
|
|
272
|
+
id: string;
|
|
273
|
+
kind: 'surface';
|
|
274
|
+
} | {
|
|
275
|
+
id: string;
|
|
276
|
+
kind: 'app';
|
|
277
|
+
} | {
|
|
278
|
+
id: string;
|
|
279
|
+
host: string;
|
|
280
|
+
kind: 'view';
|
|
281
|
+
} | {
|
|
282
|
+
kind: 'core';
|
|
283
|
+
};
|
|
284
|
+
/**
|
|
285
|
+
* Where a message or a call came from: the person, the person while a
|
|
286
|
+
* turn ran, an app's backend, an agent, a view, or a window's own act
|
|
287
|
+
* outside any conversation.
|
|
288
|
+
*/
|
|
289
|
+
type Origin = 'user' | 'steer' | 'app' | 'agent' | 'view' | 'surface';
|
|
290
|
+
type MountMode = 'read' | 'read-write';
|
|
291
|
+
type RootKind = 'home' | 'workspace' | 'project' | 'memory' | 'skill' | 'folder' | 'file';
|
|
292
|
+
type ModelLocation = 'local' | 'lan' | 'cloud';
|
|
293
|
+
type StopReason = ('end_turn' | 'length' | 'budget' | 'cancelled' | 'error' | 'refused' | 'app_disabled' | 'app_update' | 'interrupted') | 'no_result';
|
|
294
|
+
/**
|
|
295
|
+
* A part of a user message.
|
|
296
|
+
*/
|
|
297
|
+
type UserPart = {
|
|
298
|
+
text: string;
|
|
299
|
+
kind: 'text';
|
|
300
|
+
} | {
|
|
301
|
+
asset: string;
|
|
302
|
+
name: string;
|
|
303
|
+
mediaType: string;
|
|
304
|
+
kind: 'asset';
|
|
305
|
+
} | {
|
|
306
|
+
root: string;
|
|
307
|
+
path: string;
|
|
308
|
+
kind: 'file';
|
|
309
|
+
} | {
|
|
310
|
+
name: string;
|
|
311
|
+
kind: 'skill';
|
|
312
|
+
} | {
|
|
313
|
+
app: string;
|
|
314
|
+
item: MentionItem;
|
|
315
|
+
kind: 'mention';
|
|
316
|
+
} | {
|
|
317
|
+
app: string;
|
|
318
|
+
title?: string;
|
|
319
|
+
content: Content;
|
|
320
|
+
kind: 'context';
|
|
321
|
+
};
|
|
322
|
+
/**
|
|
323
|
+
* What a tool result carries: a closed union, never a bare string. A
|
|
324
|
+
* result's one structured value travels beside its content.
|
|
325
|
+
*/
|
|
326
|
+
type Content = {
|
|
327
|
+
text: string;
|
|
328
|
+
kind: 'text';
|
|
329
|
+
} | {
|
|
330
|
+
asset: string;
|
|
331
|
+
mediaType: string;
|
|
332
|
+
name?: string;
|
|
333
|
+
kind: 'asset';
|
|
334
|
+
} | {
|
|
335
|
+
uri: string;
|
|
336
|
+
name?: string;
|
|
337
|
+
kind: 'resource_link';
|
|
338
|
+
};
|
|
339
|
+
/**
|
|
340
|
+
* A part of an agent message.
|
|
341
|
+
*/
|
|
342
|
+
type AgentPart = {
|
|
343
|
+
text: string;
|
|
344
|
+
kind: 'text';
|
|
345
|
+
} | {
|
|
346
|
+
text: string;
|
|
347
|
+
kind: 'reasoning';
|
|
348
|
+
};
|
|
349
|
+
type AgentStop = 'end_turn' | 'tool_calls' | 'length' | 'cancelled' | 'error' | 'refused' | 'interrupted';
|
|
350
|
+
/**
|
|
351
|
+
* A transcript mark an app's manifest names for a tool.
|
|
352
|
+
*/
|
|
353
|
+
type ChatIconRole = 'back' | 'brain' | 'camera' | 'check' | 'chevron-down' | 'alert' | 'clock' | 'code' | 'eye' | 'globe' | 'hammer' | 'image' | 'keyboard' | 'click' | 'scroll' | 'search' | 'pen' | 'terminal' | 'x' | 'compact' | 'agent' | 'lightbulb' | 'music' | 'speech' | 'transcript' | 'connector' | 'question' | 'view';
|
|
354
|
+
type SourceKind = 'app' | 'connector';
|
|
355
|
+
type ToolOutcome = 'completed' | 'failed' | 'cancelled' | 'skipped' | 'unknown';
|
|
356
|
+
type Decision = 'run' | 'refused';
|
|
357
|
+
/**
|
|
358
|
+
* Who or what let a call run, or refused it.
|
|
359
|
+
*/
|
|
360
|
+
type DecisionBy = 'level' | 'silent' | 'grant' | 'fence' | 'judge' | 'review' | 'person' | 'floor';
|
|
361
|
+
type Risk = 'low' | 'high' | 'too_destructive';
|
|
362
|
+
type Authorisation = 'explicitly_no' | 'neutral' | 'explicitly_yes';
|
|
363
|
+
/**
|
|
364
|
+
* The rights a grant may hold; a closed list.
|
|
365
|
+
*/
|
|
366
|
+
type Right = 'fs.read' | 'fs.write' | 'net.host' | 'connector' | 'capability' | 'sessions.create' | 'terminal' | 'reader';
|
|
367
|
+
/**
|
|
368
|
+
* How a program ended: at its end, with an error or a limit, stopped, or
|
|
369
|
+
* lost with a daemon that did not stop cleanly.
|
|
370
|
+
*/
|
|
371
|
+
type CellOutcome = 'finished' | 'failed' | 'stopped' | 'lost';
|
|
372
|
+
/**
|
|
373
|
+
* How a background command ended: it exited, it was stopped, or it was
|
|
374
|
+
* lost with a daemon that did not stop cleanly.
|
|
375
|
+
*/
|
|
376
|
+
type ProcessOutcome = 'exited' | 'stopped' | 'lost';
|
|
377
|
+
/**
|
|
378
|
+
* What a card asks about. One `tool` kind covers a core tool, an app's
|
|
379
|
+
* own tool, a connector tool and another app's capability; an app's own
|
|
380
|
+
* question is `app:<id>/<kind>`.
|
|
381
|
+
*/
|
|
382
|
+
type AskKind = CoreAskKind | AppAskKind;
|
|
383
|
+
/**
|
|
384
|
+
* What a card asks about, besides an app's own question.
|
|
385
|
+
*/
|
|
386
|
+
type CoreAskKind = ('tool' | 'root' | 'connector.tools' | 'connector.login' | 'app.login' | 'terminal' | 'app.dev' | 'sandbox.violation') | 'question' | 'elicitation';
|
|
387
|
+
/**
|
|
388
|
+
* An app's own question kind, `app:<id>/<kind>`.
|
|
389
|
+
*/
|
|
390
|
+
type AppAskKind = `app:${string}`;
|
|
391
|
+
type PathShape = 'folder' | 'file';
|
|
392
|
+
type GrantScope = 'session' | 'always';
|
|
393
|
+
type AskOutcome = 'answered' | 'expired' | 'closed' | 'covered';
|
|
394
|
+
/**
|
|
395
|
+
* Why an image has no description in place of one.
|
|
396
|
+
*/
|
|
397
|
+
type DescriptionFailure = 'over_budget' | 'vision_model_absent' | 'engine_failed';
|
|
398
|
+
type BudgetWhat = 'tokens' | 'rounds';
|
|
399
|
+
type EnvironmentKind = 'process' | 'vm';
|
|
400
|
+
/**
|
|
401
|
+
* The tab commands a tool body may send to the session's executor
|
|
402
|
+
* surface. A command drives the page of the app's first surface, in the
|
|
403
|
+
* manifest's order, placed in the rail or a tab: a `web` surface's own
|
|
404
|
+
* page, or the web page of a view's tab. `navigate` loads an address in
|
|
405
|
+
* the session's tab, opening it when the session has none, hidden for a
|
|
406
|
+
* view's tab; `evaluate` runs a script and answers its value;
|
|
407
|
+
* `screenshot` answers the page as an asset; `show` puts the tab in front
|
|
408
|
+
* of the person; `close` ends it.
|
|
409
|
+
*/
|
|
410
|
+
type SurfaceOp = 'navigate' | 'evaluate' | 'screenshot' | 'show' | 'close';
|
|
411
|
+
/**
|
|
412
|
+
* One setting's value.
|
|
413
|
+
*/
|
|
414
|
+
type SettingValue = string | number | boolean;
|
|
415
|
+
/**
|
|
416
|
+
* The kinds a job runs on: every kind but chat.
|
|
417
|
+
*/
|
|
418
|
+
type JobKind = 'embedding' | 'image' | 'music' | 'speech' | 'transcription';
|
|
419
|
+
type JobStatus = 'queued' | 'running' | 'completed' | 'failed' | 'cancelled';
|
|
420
|
+
type SessionStatus = 'idle' | 'running' | 'requires_action' | 'terminated';
|
|
421
|
+
/**
|
|
422
|
+
* One picture for both colour schemes, or one per scheme.
|
|
423
|
+
*/
|
|
424
|
+
type Schemed = ServedPicture | SchemePair;
|
|
425
|
+
/**
|
|
426
|
+
* A picture the platform lets out of the package beside its page:
|
|
427
|
+
* `icon.svg`, `icon.png` or a path under `assets/`.
|
|
428
|
+
*/
|
|
429
|
+
type ServedPicture = string;
|
|
430
|
+
/**
|
|
431
|
+
* What an app is for: one to three per listing, from this list and no
|
|
432
|
+
* other.
|
|
433
|
+
*/
|
|
434
|
+
type Category = 'chat' | 'writing' | 'coding' | 'research' | 'notes' | 'productivity' | 'communication' | 'data' | 'finance' | 'design' | 'audio' | 'video' | 'games' | 'education' | 'health' | 'lifestyle' | 'automation' | 'utilities';
|
|
435
|
+
/**
|
|
436
|
+
* What a listing discloses about money, never a price: nothing is paid,
|
|
437
|
+
* something behind it is, or the whole of it is.
|
|
438
|
+
*/
|
|
439
|
+
type PaymentKind = 'free' | 'optional' | 'paid';
|
|
440
|
+
/**
|
|
441
|
+
* An entry of `environment.network`.
|
|
442
|
+
*/
|
|
443
|
+
type NetworkEntry = string;
|
|
444
|
+
type Lifetime = 'service';
|
|
445
|
+
/**
|
|
446
|
+
* The kinds a model card answers on.
|
|
447
|
+
*/
|
|
448
|
+
type ModelKind = 'chat' | 'embedding' | 'image' | 'music' | 'speech' | 'transcription';
|
|
449
|
+
type Reasoning = 'none' | 'auto' | 'high';
|
|
450
|
+
/**
|
|
451
|
+
* A relative path inside the package, forward slashes, never leaving it.
|
|
452
|
+
*/
|
|
453
|
+
type PackagePath = string;
|
|
454
|
+
/**
|
|
455
|
+
* The well-known roots an agent may name; a project adds `project` on its
|
|
456
|
+
* own.
|
|
457
|
+
*/
|
|
458
|
+
type AgentRoot = 'home' | 'workspace' | 'memory';
|
|
459
|
+
/**
|
|
460
|
+
* Who may call a tool, as MCP Apps names them: `model`, the agents;
|
|
461
|
+
* `app`, the app's own views.
|
|
462
|
+
*/
|
|
463
|
+
type ToolVisibility = 'model' | 'app';
|
|
464
|
+
/**
|
|
465
|
+
* The namespaces `uses` may name: the backend's channel namespaces, the
|
|
466
|
+
* view extensions, and `files.open`. A backend and a view reach `store`,
|
|
467
|
+
* `events`, `models`, `jobs` and `peers` alike, each only when its app
|
|
468
|
+
* names it here. An agent's core tools need no namespace here.
|
|
469
|
+
*/
|
|
470
|
+
type Uses = 'sessions' | 'sessions.create' | 'secrets' | 'notifications' | 'readers' | 'roots' | 'exec' | 'catalogue' | 'oauth' | 'surface' | 'store' | 'events' | 'models' | 'jobs' | 'terminals' | 'files.open' | 'surfaces.open' | 'peers';
|
|
471
|
+
/**
|
|
472
|
+
* What a surface is: `view`, an MCP Apps document in a sandboxed frame,
|
|
473
|
+
* which may reserve slots for the chat the shell draws for the app's own
|
|
474
|
+
* agent; `web`, a web page on the app's own partition.
|
|
475
|
+
*/
|
|
476
|
+
type SurfaceDeclaration = {
|
|
477
|
+
id: string;
|
|
478
|
+
title: string;
|
|
479
|
+
/**
|
|
480
|
+
* The mark of the surface's tab and launcher row; absent, they show
|
|
481
|
+
* the app's icon.
|
|
482
|
+
*/
|
|
483
|
+
icon?: Schemed;
|
|
484
|
+
/**
|
|
485
|
+
* @minItems 1
|
|
486
|
+
*/
|
|
487
|
+
placements: Placement[];
|
|
488
|
+
/**
|
|
489
|
+
* @minItems 1
|
|
490
|
+
*/
|
|
491
|
+
quickActions?: QuickAction[];
|
|
492
|
+
/**
|
|
493
|
+
* The view's document: a file in the package, or a `ui://` resource
|
|
494
|
+
* of one of the app's MCP servers.
|
|
495
|
+
*/
|
|
496
|
+
entry: string;
|
|
497
|
+
/**
|
|
498
|
+
* The tool the host calls when the surface opens, with `{}`, or with
|
|
499
|
+
* the `FileInput` of the file it opens; its result is the view's first
|
|
500
|
+
* tool result. Absent, the view receives the tool input alone.
|
|
501
|
+
*/
|
|
502
|
+
tool?: string;
|
|
503
|
+
/**
|
|
504
|
+
* The file extensions the view opens, in a tab, in place of the
|
|
505
|
+
* system's own app; with `https:` and `http:`, the web addresses of
|
|
506
|
+
* those schemes, each as the web page of a new tab of the view, which
|
|
507
|
+
* makes the app one the person may pick as their browser.
|
|
508
|
+
*
|
|
509
|
+
* @minItems 1
|
|
510
|
+
*/
|
|
511
|
+
opens?: Opened[];
|
|
512
|
+
/**
|
|
513
|
+
* What the view shows at an address. A file a turn changed opens in
|
|
514
|
+
* the one usable app whose view shows its change when the working
|
|
515
|
+
* tree of its repository holds one, and in the one whose view shows
|
|
516
|
+
* files when it does not; the window first gives that app read
|
|
517
|
+
* access to the repository or the file's folder.
|
|
518
|
+
*
|
|
519
|
+
* @minItems 1
|
|
520
|
+
*/
|
|
521
|
+
shows?: Shown[];
|
|
522
|
+
kind: 'view';
|
|
523
|
+
} | {
|
|
524
|
+
id: string;
|
|
525
|
+
title: string;
|
|
526
|
+
/**
|
|
527
|
+
* The mark of the surface's tab and launcher row; absent, they show
|
|
528
|
+
* the app's icon.
|
|
529
|
+
*/
|
|
530
|
+
icon?: Schemed;
|
|
531
|
+
/**
|
|
532
|
+
* @minItems 1
|
|
533
|
+
*/
|
|
534
|
+
placements: Placement[];
|
|
535
|
+
/**
|
|
536
|
+
* @minItems 1
|
|
537
|
+
*/
|
|
538
|
+
quickActions?: QuickAction[];
|
|
539
|
+
/**
|
|
540
|
+
* The page the surface opens on: an `https:` address, or `http:` on
|
|
541
|
+
* this machine, whose host `environment.network` covers.
|
|
542
|
+
*/
|
|
543
|
+
entry: string;
|
|
544
|
+
/**
|
|
545
|
+
* Local storage the page finds at each load: on the origin of
|
|
546
|
+
* `entry`, each key holds its value before the page's own scripts
|
|
547
|
+
* run, so a setting the site keeps there, such as its theme, is the
|
|
548
|
+
* app's.
|
|
549
|
+
*/
|
|
550
|
+
storage?: {
|
|
551
|
+
[k: string]: string;
|
|
552
|
+
};
|
|
553
|
+
kind: 'web';
|
|
554
|
+
};
|
|
555
|
+
/**
|
|
556
|
+
* Where a surface appears: `rail` gives the app its rail button, which
|
|
557
|
+
* opens the surface in the focused tile; `tab` lists it in the launcher as
|
|
558
|
+
* a tab of a tile; `inline` draws it in a transcript, under the result of
|
|
559
|
+
* each of the app's tools whose `view` names it; `modal` draws it over a
|
|
560
|
+
* tile of its app when a view of the app opens it with
|
|
561
|
+
* `hearthscale/ui/open-modal`.
|
|
562
|
+
*/
|
|
563
|
+
type Placement = 'rail' | 'tab' | 'inline' | 'modal';
|
|
564
|
+
/**
|
|
565
|
+
* What a view surface opens: a file extension, or a scheme of web
|
|
566
|
+
* addresses.
|
|
567
|
+
*/
|
|
568
|
+
type Opened = string;
|
|
569
|
+
/**
|
|
570
|
+
* What a view surface shows at an address the window opens it on,
|
|
571
|
+
* `/?path=<absolute path>` with the path percent-encoded: `file`, a file
|
|
572
|
+
* of this machine in its folder; `change`, a file's change in the working
|
|
573
|
+
* tree of its git repository.
|
|
574
|
+
*/
|
|
575
|
+
type Shown = 'file' | 'change';
|
|
576
|
+
/**
|
|
577
|
+
* The literal `object`, the type of a settings schema.
|
|
578
|
+
*/
|
|
579
|
+
type ObjectType = 'object';
|
|
580
|
+
/**
|
|
581
|
+
* One setting as a JSON Schema property.
|
|
582
|
+
*/
|
|
583
|
+
type SettingDeclaration = {
|
|
584
|
+
/**
|
|
585
|
+
* The setting's label.
|
|
586
|
+
*/
|
|
587
|
+
title: string;
|
|
588
|
+
/**
|
|
589
|
+
* The tooltip of the setting's row.
|
|
590
|
+
*/
|
|
591
|
+
description?: string;
|
|
592
|
+
/**
|
|
593
|
+
* The value the platform holds until the person changes it.
|
|
594
|
+
*/
|
|
595
|
+
default: boolean;
|
|
596
|
+
type: 'boolean';
|
|
597
|
+
} | {
|
|
598
|
+
/**
|
|
599
|
+
* The setting's label.
|
|
600
|
+
*/
|
|
601
|
+
title: string;
|
|
602
|
+
/**
|
|
603
|
+
* The tooltip of the setting's row.
|
|
604
|
+
*/
|
|
605
|
+
description?: string;
|
|
606
|
+
/**
|
|
607
|
+
* @minItems 1
|
|
608
|
+
*/
|
|
609
|
+
enum?: string[];
|
|
610
|
+
minLength?: number;
|
|
611
|
+
maxLength?: number;
|
|
612
|
+
pattern?: string;
|
|
613
|
+
/**
|
|
614
|
+
* The value the platform holds until the person changes it.
|
|
615
|
+
*/
|
|
616
|
+
default: string;
|
|
617
|
+
type: 'string';
|
|
618
|
+
} | {
|
|
619
|
+
/**
|
|
620
|
+
* The setting's label.
|
|
621
|
+
*/
|
|
622
|
+
title: string;
|
|
623
|
+
/**
|
|
624
|
+
* The tooltip of the setting's row.
|
|
625
|
+
*/
|
|
626
|
+
description?: string;
|
|
627
|
+
minimum?: number;
|
|
628
|
+
maximum?: number;
|
|
629
|
+
multipleOf?: number;
|
|
630
|
+
/**
|
|
631
|
+
* The value the platform holds until the person changes it.
|
|
632
|
+
*/
|
|
633
|
+
default: number;
|
|
634
|
+
type: 'number';
|
|
635
|
+
} | {
|
|
636
|
+
/**
|
|
637
|
+
* The setting's label.
|
|
638
|
+
*/
|
|
639
|
+
title: string;
|
|
640
|
+
/**
|
|
641
|
+
* The tooltip of the setting's row.
|
|
642
|
+
*/
|
|
643
|
+
description?: string;
|
|
644
|
+
minimum?: number;
|
|
645
|
+
maximum?: number;
|
|
646
|
+
multipleOf?: number;
|
|
647
|
+
/**
|
|
648
|
+
* The value the platform holds until the person changes it.
|
|
649
|
+
*/
|
|
650
|
+
default: number;
|
|
651
|
+
type: 'integer';
|
|
652
|
+
};
|
|
653
|
+
/**
|
|
654
|
+
* One row of a settings group: a setting by its name, or a button that
|
|
655
|
+
* calls one of the app's tools with `{}`. A tool whose result names a view
|
|
656
|
+
* opens that view in a modal over the settings; any other shows its text
|
|
657
|
+
* in a tooltip of the button.
|
|
658
|
+
*/
|
|
659
|
+
type SettingsItem = {
|
|
660
|
+
property: string;
|
|
661
|
+
kind: 'property';
|
|
662
|
+
} | {
|
|
663
|
+
tool: string;
|
|
664
|
+
title: string;
|
|
665
|
+
kind: 'tool';
|
|
666
|
+
};
|
|
667
|
+
/**
|
|
668
|
+
* One MCP server the app brings. Its tools, `ui://` views and resources
|
|
669
|
+
* are the app's.
|
|
670
|
+
*/
|
|
671
|
+
type McpServerDeclaration = RemoteMcpServer | BundledMcpServer;
|
|
672
|
+
/**
|
|
673
|
+
* The device capabilities a view may ask for, each a consent fact, as the
|
|
674
|
+
* MCP Apps sandbox permissions name them.
|
|
675
|
+
*/
|
|
676
|
+
type ViewPermission = 'camera' | 'microphone' | 'geolocation' | 'clipboard-write';
|
|
677
|
+
/**
|
|
678
|
+
* The card a request runs on, or the reason in words that none can.
|
|
679
|
+
*/
|
|
680
|
+
type EffectiveModel = {
|
|
681
|
+
card: string;
|
|
682
|
+
source: ModelSource;
|
|
683
|
+
} | {
|
|
684
|
+
card: null;
|
|
685
|
+
reason: string;
|
|
686
|
+
};
|
|
687
|
+
/**
|
|
688
|
+
* Where a chosen card comes from: the session's own model, the card the
|
|
689
|
+
* person gave the app, the role of its kind, or the daemon's rule.
|
|
690
|
+
*/
|
|
691
|
+
type ModelSource = 'session' | 'app' | 'role' | 'automatic';
|
|
692
|
+
/**
|
|
693
|
+
* One frame of a streamed completion.
|
|
694
|
+
*/
|
|
695
|
+
type CompletionDelta = {
|
|
696
|
+
text: string;
|
|
697
|
+
reasoning?: boolean;
|
|
698
|
+
} | {
|
|
699
|
+
done: true;
|
|
700
|
+
toolCalls?: ToolCall[];
|
|
701
|
+
usage?: Usage;
|
|
702
|
+
stop: CompletionStop;
|
|
703
|
+
error?: string;
|
|
704
|
+
};
|
|
705
|
+
type CompletionStop = 'end_turn' | 'tool_calls' | 'length' | 'cancelled' | 'error';
|
|
706
|
+
type ChatRole = 'system' | 'user' | 'assistant' | 'tool';
|
|
707
|
+
type ChatContent = string | ChatContentPart[];
|
|
708
|
+
/**
|
|
709
|
+
* A part of a message's content: text, or a picture by its asset, which
|
|
710
|
+
* the model registry turns into its data URL.
|
|
711
|
+
*/
|
|
712
|
+
type ChatContentPart = {
|
|
713
|
+
text: string;
|
|
714
|
+
type: 'text';
|
|
715
|
+
} | {
|
|
716
|
+
asset: string;
|
|
717
|
+
mediaType: string;
|
|
718
|
+
type: 'image';
|
|
719
|
+
};
|
|
720
|
+
/**
|
|
721
|
+
* A frame on `GET /terminals/:id/stream`: the snapshot once, then the
|
|
722
|
+
* bytes as they come, then the exit.
|
|
723
|
+
*/
|
|
724
|
+
type TerminalFrame = {
|
|
725
|
+
snapshot: TerminalSnapshot;
|
|
726
|
+
type: 'snapshot';
|
|
727
|
+
} | {
|
|
728
|
+
data: string;
|
|
729
|
+
type: 'output';
|
|
730
|
+
} | {
|
|
731
|
+
exitCode: number;
|
|
732
|
+
type: 'exited';
|
|
733
|
+
};
|
|
734
|
+
type TerminalStatus = 'running' | 'exited';
|
|
735
|
+
/**
|
|
736
|
+
* What a view's `openai/resources/write` of an opened file did: saved
|
|
737
|
+
* with the new version's ETag; nothing written because the version on
|
|
738
|
+
* disk is another, which `etag` names; or nothing written because the
|
|
739
|
+
* bytes exceed `max_bytes`.
|
|
740
|
+
*/
|
|
741
|
+
type ResourceWriteResult = {
|
|
742
|
+
etag: string;
|
|
743
|
+
outcome: 'saved';
|
|
744
|
+
} | {
|
|
745
|
+
etag: string;
|
|
746
|
+
outcome: 'conflict';
|
|
747
|
+
} | {
|
|
748
|
+
maxBytes: number;
|
|
749
|
+
outcome: 'too-large';
|
|
750
|
+
};
|
|
751
|
+
/**
|
|
752
|
+
* What a patch compares: the working tree with the index, the index with
|
|
753
|
+
* `HEAD`, or the current branch with a base.
|
|
754
|
+
*/
|
|
755
|
+
type VcsScope = 'working' | 'staged' | 'branch';
|
|
756
|
+
/**
|
|
757
|
+
* What one job takes.
|
|
758
|
+
*/
|
|
759
|
+
type JobInput = ImageJobInput | MusicJobInput | SpeechJobInput | TranscriptionJobInput | EmbeddingJobInput;
|
|
760
|
+
/**
|
|
761
|
+
* How a sign-in reaches the person: `loopback` opens their browser and
|
|
762
|
+
* comes back to this computer; `device` shows a code to enter on any
|
|
763
|
+
* device.
|
|
764
|
+
*/
|
|
765
|
+
type OAuthGrant = 'loopback' | 'device';
|
|
766
|
+
interface ForkPoint {
|
|
767
|
+
session: string;
|
|
768
|
+
leaf: string;
|
|
769
|
+
}
|
|
770
|
+
interface SpawnPoint {
|
|
771
|
+
session: string;
|
|
772
|
+
callId: string;
|
|
773
|
+
}
|
|
774
|
+
/**
|
|
775
|
+
* A tool's structured value: the object its declared output schema
|
|
776
|
+
* describes.
|
|
777
|
+
*/
|
|
778
|
+
interface Structured {
|
|
779
|
+
[k: string]: unknown;
|
|
780
|
+
}
|
|
781
|
+
/**
|
|
782
|
+
* One folder a session's tools reach, by the handle the model names.
|
|
783
|
+
*/
|
|
784
|
+
interface SessionRoot {
|
|
785
|
+
handle: string;
|
|
786
|
+
path: string;
|
|
787
|
+
mode: MountMode;
|
|
788
|
+
kind: RootKind;
|
|
789
|
+
}
|
|
790
|
+
/**
|
|
791
|
+
* One item of the composer's `@` list, as an MCP resource link: the
|
|
792
|
+
* address the app resolves it by, its name, and the words the list shows
|
|
793
|
+
* in place of the name.
|
|
794
|
+
*/
|
|
795
|
+
interface MentionItem {
|
|
796
|
+
uri: string;
|
|
797
|
+
name: string;
|
|
798
|
+
title?: string;
|
|
799
|
+
mimeType?: string;
|
|
800
|
+
}
|
|
801
|
+
interface ToolCall {
|
|
802
|
+
id: string;
|
|
803
|
+
name: string;
|
|
804
|
+
/**
|
|
805
|
+
* JSON-encoded arguments exactly as the model emitted them.
|
|
806
|
+
*/
|
|
807
|
+
arguments: string;
|
|
808
|
+
}
|
|
809
|
+
/**
|
|
810
|
+
* Token counts as the runtime reported them, or as the shared estimator
|
|
811
|
+
* counted them with `estimated: true`.
|
|
812
|
+
*/
|
|
813
|
+
interface Usage {
|
|
814
|
+
input: number;
|
|
815
|
+
output: number;
|
|
816
|
+
estimated?: true;
|
|
817
|
+
}
|
|
818
|
+
/**
|
|
819
|
+
* What every tool call, session write and job carries: who acts, where
|
|
820
|
+
* the words came from, and the chain of principals the call crossed,
|
|
821
|
+
* outermost first.
|
|
822
|
+
*/
|
|
823
|
+
interface CallContext {
|
|
824
|
+
principal: PrincipalRef;
|
|
825
|
+
origin: Origin;
|
|
826
|
+
chain: PrincipalRef[];
|
|
827
|
+
session?: string;
|
|
828
|
+
turn?: string;
|
|
829
|
+
call?: string;
|
|
830
|
+
authoritySession?: string;
|
|
831
|
+
}
|
|
832
|
+
/**
|
|
833
|
+
* How the transcript shows a call of a tool an app or a connector
|
|
834
|
+
* declares, as the tool was when the call was prepared.
|
|
835
|
+
*/
|
|
836
|
+
interface CallLabel {
|
|
837
|
+
title: string;
|
|
838
|
+
icon?: ChatIconRole;
|
|
839
|
+
/**
|
|
840
|
+
* The app or the connector that declares the tool, and the name the
|
|
841
|
+
* person knows it by.
|
|
842
|
+
*/
|
|
843
|
+
source: CallSource;
|
|
844
|
+
}
|
|
845
|
+
interface CallSource {
|
|
846
|
+
kind: SourceKind;
|
|
847
|
+
id: string;
|
|
848
|
+
name: string;
|
|
849
|
+
}
|
|
850
|
+
interface Executor {
|
|
851
|
+
principal: PrincipalRef;
|
|
852
|
+
instance: string;
|
|
853
|
+
}
|
|
854
|
+
/**
|
|
855
|
+
* The provider's view that renders a result: the provider and the view's
|
|
856
|
+
* id.
|
|
857
|
+
*/
|
|
858
|
+
interface ViewRef {
|
|
859
|
+
app: string;
|
|
860
|
+
id: string;
|
|
861
|
+
}
|
|
862
|
+
interface ReviewRecord {
|
|
863
|
+
risk: Risk;
|
|
864
|
+
authorisation: Authorisation;
|
|
865
|
+
reason: string;
|
|
866
|
+
model: string;
|
|
867
|
+
/**
|
|
868
|
+
* The `user` and `steer` entries the reviewer read as authorisation.
|
|
869
|
+
*/
|
|
870
|
+
authorisedBy: string[];
|
|
871
|
+
}
|
|
872
|
+
/**
|
|
873
|
+
* One durable allowance. `fs.write` implies `fs.read`. A grant with
|
|
874
|
+
* `session` belongs to that session and its helpers, and ends with it.
|
|
875
|
+
* `pin` is the hash of a tool's name, description, schemas and flags.
|
|
876
|
+
*/
|
|
877
|
+
interface Grant {
|
|
878
|
+
principal: PrincipalRef;
|
|
879
|
+
right: Right;
|
|
880
|
+
subject: string;
|
|
881
|
+
label: string;
|
|
882
|
+
createdAt: string;
|
|
883
|
+
pin?: string;
|
|
884
|
+
session?: string;
|
|
885
|
+
}
|
|
886
|
+
interface Ask {
|
|
887
|
+
id: string;
|
|
888
|
+
kind: AskKind;
|
|
889
|
+
principal: PrincipalRef;
|
|
890
|
+
/**
|
|
891
|
+
* The principals the call crossed, outermost first.
|
|
892
|
+
*/
|
|
893
|
+
chain: PrincipalRef[];
|
|
894
|
+
session?: string;
|
|
895
|
+
/**
|
|
896
|
+
* The root of the session's tree of helpers: where a helper's card is
|
|
897
|
+
* drawn, and the scope a session answer covers.
|
|
898
|
+
*/
|
|
899
|
+
authoritySession?: string;
|
|
900
|
+
turn?: string;
|
|
901
|
+
callId?: string;
|
|
902
|
+
facts: AskFacts;
|
|
903
|
+
options: AskOption[];
|
|
904
|
+
openedAt: string;
|
|
905
|
+
/**
|
|
906
|
+
* Absolute; absent on a parked ask, which waits for a window.
|
|
907
|
+
*/
|
|
908
|
+
deadline?: string;
|
|
909
|
+
}
|
|
910
|
+
/**
|
|
911
|
+
* The facts a card draws, as the core established them.
|
|
912
|
+
*/
|
|
913
|
+
interface AskFacts {
|
|
914
|
+
/**
|
|
915
|
+
* The tool's name; `source` names where it comes from when it is not
|
|
916
|
+
* a core tool, and `sourceName` is that app's or connector's name.
|
|
917
|
+
*/
|
|
918
|
+
tool?: string;
|
|
919
|
+
source?: string;
|
|
920
|
+
sourceName?: string;
|
|
921
|
+
/**
|
|
922
|
+
* The names of the apps a call made inside other calls went through,
|
|
923
|
+
* after the conversation's app and before the tool's source.
|
|
924
|
+
*/
|
|
925
|
+
via?: string[];
|
|
926
|
+
/**
|
|
927
|
+
* The words the card names the act by: a tool's manifest title, or an
|
|
928
|
+
* app question's title from its manifest.
|
|
929
|
+
*/
|
|
930
|
+
title?: string;
|
|
931
|
+
/**
|
|
932
|
+
* The agent's question, on a `question` card; its options are the
|
|
933
|
+
* choices it offers.
|
|
934
|
+
*/
|
|
935
|
+
question?: string;
|
|
936
|
+
/**
|
|
937
|
+
* The label of the control the person pressed in a view, as the view
|
|
938
|
+
* reported it.
|
|
939
|
+
*/
|
|
940
|
+
label?: string;
|
|
941
|
+
arguments?: string;
|
|
942
|
+
/**
|
|
943
|
+
* The absolute path a file call would touch.
|
|
944
|
+
*/
|
|
945
|
+
path?: string;
|
|
946
|
+
command?: string;
|
|
947
|
+
/**
|
|
948
|
+
* No fence holds the command.
|
|
949
|
+
*/
|
|
950
|
+
unfenced?: true;
|
|
951
|
+
/**
|
|
952
|
+
* A fenced run tripped over these; `stderr` holds the lines that said
|
|
953
|
+
* so.
|
|
954
|
+
*/
|
|
955
|
+
paths?: string[];
|
|
956
|
+
hosts?: string[];
|
|
957
|
+
stderr?: string;
|
|
958
|
+
/**
|
|
959
|
+
* The command still runs, and the fence holds its connection to the
|
|
960
|
+
* hosts until the answer.
|
|
961
|
+
*/
|
|
962
|
+
running?: true;
|
|
963
|
+
/**
|
|
964
|
+
* What a backend wants a folder for, on a `root` card it raised.
|
|
965
|
+
*/
|
|
966
|
+
purpose?: string;
|
|
967
|
+
/**
|
|
968
|
+
* On a `root` card: whether it is about a folder or one file.
|
|
969
|
+
*/
|
|
970
|
+
shape?: PathShape;
|
|
971
|
+
/**
|
|
972
|
+
* An app's own question, or an elicitation's message: the app's words.
|
|
973
|
+
*/
|
|
974
|
+
text?: string;
|
|
975
|
+
/**
|
|
976
|
+
* On an elicitation card: the form, as the JSON Schema object the
|
|
977
|
+
* server sent.
|
|
978
|
+
*/
|
|
979
|
+
schema?: {
|
|
980
|
+
[k: string]: unknown;
|
|
981
|
+
};
|
|
982
|
+
/**
|
|
983
|
+
* A connector card: the connector, and the tools waiting on a bulk
|
|
984
|
+
* card, or the sign-in's issuer, or the device code the person types
|
|
985
|
+
* at the verification address. An app's sign-in card carries the
|
|
986
|
+
* issuer, the scopes, and the code or the sign-in a window starts
|
|
987
|
+
* with the authorization endpoint its browser opens.
|
|
988
|
+
*/
|
|
989
|
+
connector?: string;
|
|
990
|
+
tools?: ToolSummary[];
|
|
991
|
+
issuer?: string;
|
|
992
|
+
userCode?: string;
|
|
993
|
+
verificationUri?: string;
|
|
994
|
+
scopes?: string[];
|
|
995
|
+
login?: string;
|
|
996
|
+
authorizationEndpoint?: string;
|
|
997
|
+
}
|
|
998
|
+
interface ToolSummary {
|
|
999
|
+
name: string;
|
|
1000
|
+
description: string;
|
|
1001
|
+
}
|
|
1002
|
+
/**
|
|
1003
|
+
* One answer a card offers, with the grant the core computed for it.
|
|
1004
|
+
*/
|
|
1005
|
+
interface AskOption {
|
|
1006
|
+
id: string;
|
|
1007
|
+
label: string;
|
|
1008
|
+
/**
|
|
1009
|
+
* The option is a pick: the person chooses a folder or a file, and the
|
|
1010
|
+
* answer carries its path.
|
|
1011
|
+
*/
|
|
1012
|
+
pick?: PathShape;
|
|
1013
|
+
grant?: OptionGrant;
|
|
1014
|
+
}
|
|
1015
|
+
/**
|
|
1016
|
+
* The grant the core computed for one answer of a card.
|
|
1017
|
+
*/
|
|
1018
|
+
interface OptionGrant {
|
|
1019
|
+
principal: PrincipalRef;
|
|
1020
|
+
right: Right;
|
|
1021
|
+
subject: string;
|
|
1022
|
+
scope: GrantScope;
|
|
1023
|
+
pin?: string;
|
|
1024
|
+
}
|
|
1025
|
+
/**
|
|
1026
|
+
* What the chips of a view hold from its last `ui/update-model-context`:
|
|
1027
|
+
* the id the host gave that update, and its blocks.
|
|
1028
|
+
*/
|
|
1029
|
+
interface ModelContextState {
|
|
1030
|
+
updateId: string;
|
|
1031
|
+
/**
|
|
1032
|
+
* The MCP content blocks of the update.
|
|
1033
|
+
*/
|
|
1034
|
+
content?: {
|
|
1035
|
+
[k: string]: unknown;
|
|
1036
|
+
}[];
|
|
1037
|
+
structuredContent?: {
|
|
1038
|
+
[k: string]: unknown;
|
|
1039
|
+
};
|
|
1040
|
+
}
|
|
1041
|
+
/**
|
|
1042
|
+
* Every setting's value, by its name.
|
|
1043
|
+
*/
|
|
1044
|
+
interface SettingValues {
|
|
1045
|
+
[k: string]: SettingValue;
|
|
1046
|
+
}
|
|
1047
|
+
/**
|
|
1048
|
+
* One room an app of this platform is in. A member is a platform in the
|
|
1049
|
+
* room, named by its peer id, which is new for each room and stays the
|
|
1050
|
+
* member's while it keeps its place: through a dropped connection and a
|
|
1051
|
+
* restart of its platform, until it leaves or the room ends.
|
|
1052
|
+
*/
|
|
1053
|
+
interface Room {
|
|
1054
|
+
/**
|
|
1055
|
+
* The same on every member's platform.
|
|
1056
|
+
*/
|
|
1057
|
+
id: string;
|
|
1058
|
+
app: string;
|
|
1059
|
+
/**
|
|
1060
|
+
* What a person passes on to another computer to join the room: a
|
|
1061
|
+
* `hearthscale://join?app=<id>&ticket=<…>` link, which opens the
|
|
1062
|
+
* client's join sheet with the ticket filled in, and which the sheet
|
|
1063
|
+
* also takes pasted.
|
|
1064
|
+
*/
|
|
1065
|
+
ticket: string;
|
|
1066
|
+
/**
|
|
1067
|
+
* This platform's peer id in the room.
|
|
1068
|
+
*/
|
|
1069
|
+
me: string;
|
|
1070
|
+
/**
|
|
1071
|
+
* The member that opened the room: the room ends when it leaves.
|
|
1072
|
+
*/
|
|
1073
|
+
opener: string;
|
|
1074
|
+
/**
|
|
1075
|
+
* The other members this platform is with now, in the order they
|
|
1076
|
+
* came. A member that is with no one is out of reach of the opener
|
|
1077
|
+
* and dials it again.
|
|
1078
|
+
*/
|
|
1079
|
+
peers: string[];
|
|
1080
|
+
}
|
|
1081
|
+
/**
|
|
1082
|
+
* One job as `POST /models/jobs` answers it and `job.progress` frames it.
|
|
1083
|
+
* The result is one asset per output: a picture, a WAV, a text or a JSON
|
|
1084
|
+
* document, owned by the session the job ran for or else by the app.
|
|
1085
|
+
*/
|
|
1086
|
+
interface Job {
|
|
1087
|
+
id: string;
|
|
1088
|
+
kind: JobKind;
|
|
1089
|
+
app: string;
|
|
1090
|
+
session?: string;
|
|
1091
|
+
/**
|
|
1092
|
+
* The tool call that submitted it, for a job a tool started.
|
|
1093
|
+
*/
|
|
1094
|
+
callId?: string;
|
|
1095
|
+
card: string;
|
|
1096
|
+
status: JobStatus;
|
|
1097
|
+
submittedAt: string;
|
|
1098
|
+
/**
|
|
1099
|
+
* Why the job has not started on the machine that runs it, such as
|
|
1100
|
+
* busy models holding the memory it needs.
|
|
1101
|
+
*/
|
|
1102
|
+
waiting?: string;
|
|
1103
|
+
progress?: JobProgress;
|
|
1104
|
+
result?: string[];
|
|
1105
|
+
error?: string;
|
|
1106
|
+
finishedAt?: string;
|
|
1107
|
+
}
|
|
1108
|
+
interface JobProgress {
|
|
1109
|
+
fraction?: number;
|
|
1110
|
+
}
|
|
1111
|
+
/**
|
|
1112
|
+
* A program of a session that runs now.
|
|
1113
|
+
*/
|
|
1114
|
+
interface SessionCell {
|
|
1115
|
+
cell: number;
|
|
1116
|
+
callId: string;
|
|
1117
|
+
}
|
|
1118
|
+
/**
|
|
1119
|
+
* A command of a session that runs in the background now.
|
|
1120
|
+
*/
|
|
1121
|
+
interface SessionProcess {
|
|
1122
|
+
process: number;
|
|
1123
|
+
callId: string;
|
|
1124
|
+
}
|
|
1125
|
+
interface Manifest {
|
|
1126
|
+
/**
|
|
1127
|
+
* The address of this schema, for an editor's completion; nothing in
|
|
1128
|
+
* Hearthscale reads it.
|
|
1129
|
+
*/
|
|
1130
|
+
$schema?: string;
|
|
1131
|
+
id: string;
|
|
1132
|
+
name: string;
|
|
1133
|
+
/**
|
|
1134
|
+
* Semver, shown and never interpreted.
|
|
1135
|
+
*/
|
|
1136
|
+
version: string;
|
|
1137
|
+
api: 6;
|
|
1138
|
+
description: string;
|
|
1139
|
+
icon?: Schemed;
|
|
1140
|
+
license?: string;
|
|
1141
|
+
/**
|
|
1142
|
+
* One to three categories, each once.
|
|
1143
|
+
*
|
|
1144
|
+
* @minItems 1
|
|
1145
|
+
* @maxItems 3
|
|
1146
|
+
*/
|
|
1147
|
+
categories?: Category[];
|
|
1148
|
+
payment?: PaymentKind;
|
|
1149
|
+
author?: string;
|
|
1150
|
+
environment?: Environment;
|
|
1151
|
+
agent?: AgentDefinition;
|
|
1152
|
+
agents?: {
|
|
1153
|
+
[k: string]: AgentDefinition;
|
|
1154
|
+
};
|
|
1155
|
+
models?: {
|
|
1156
|
+
chat?: ModelNeed;
|
|
1157
|
+
embedding?: ModelNeed;
|
|
1158
|
+
image?: ModelNeed;
|
|
1159
|
+
music?: ModelNeed;
|
|
1160
|
+
speech?: ModelNeed;
|
|
1161
|
+
transcription?: ModelNeed;
|
|
1162
|
+
};
|
|
1163
|
+
tools?: ToolDeclaration[];
|
|
1164
|
+
capabilities?: Capabilities;
|
|
1165
|
+
/**
|
|
1166
|
+
* The questions the app's backend raises from inside a tool call, by
|
|
1167
|
+
* kind, each with the title its card shows: a sign-in, a handoff.
|
|
1168
|
+
*/
|
|
1169
|
+
asks?: AskDeclaration[];
|
|
1170
|
+
/**
|
|
1171
|
+
* The file formats the app's backend turns into text for the read
|
|
1172
|
+
* tool, each an id and the extensions it claims.
|
|
1173
|
+
*/
|
|
1174
|
+
formats?: FormatDeclaration[];
|
|
1175
|
+
uses?: Uses[];
|
|
1176
|
+
recommends?: string[];
|
|
1177
|
+
onboarding?: Onboarding;
|
|
1178
|
+
/**
|
|
1179
|
+
* What the app shows in tiles, in the rail and in transcripts.
|
|
1180
|
+
*
|
|
1181
|
+
* @minItems 1
|
|
1182
|
+
*/
|
|
1183
|
+
surfaces?: SurfaceDeclaration[];
|
|
1184
|
+
settings?: SettingsDeclaration;
|
|
1185
|
+
/**
|
|
1186
|
+
* The tool that answers the composer's `@` list with the app's items:
|
|
1187
|
+
* it takes `MentionSearch` and answers `MentionResult` as its
|
|
1188
|
+
* structured result. A consent fact: the person's `@` runs it at
|
|
1189
|
+
* every level.
|
|
1190
|
+
*/
|
|
1191
|
+
mentions?: Mentions;
|
|
1192
|
+
/**
|
|
1193
|
+
* @minItems 1
|
|
1194
|
+
*/
|
|
1195
|
+
mcp?: McpServerDeclaration[];
|
|
1196
|
+
/**
|
|
1197
|
+
* @minItems 1
|
|
1198
|
+
*/
|
|
1199
|
+
permissions?: ViewPermission[];
|
|
1200
|
+
/**
|
|
1201
|
+
* Sample prompts the app's Marketplace listing shows.
|
|
1202
|
+
*
|
|
1203
|
+
* @minItems 1
|
|
1204
|
+
*/
|
|
1205
|
+
examples?: string[];
|
|
1206
|
+
}
|
|
1207
|
+
interface SchemePair {
|
|
1208
|
+
light: ServedPicture;
|
|
1209
|
+
dark: ServedPicture;
|
|
1210
|
+
}
|
|
1211
|
+
interface Environment {
|
|
1212
|
+
kind: EnvironmentKind;
|
|
1213
|
+
/**
|
|
1214
|
+
* The hosts the app reaches: its backend through the relay, its views
|
|
1215
|
+
* and its web surfaces. Each is a consent fact.
|
|
1216
|
+
*/
|
|
1217
|
+
network?: NetworkEntry[];
|
|
1218
|
+
lifetime?: Lifetime;
|
|
1219
|
+
}
|
|
1220
|
+
interface AgentDefinition {
|
|
1221
|
+
name: string;
|
|
1222
|
+
description?: string;
|
|
1223
|
+
model: ModelRequirement;
|
|
1224
|
+
prompt?: PackagePath[];
|
|
1225
|
+
compaction?: Compaction;
|
|
1226
|
+
skills?: PackagePath[];
|
|
1227
|
+
tools?: string[];
|
|
1228
|
+
roots?: AgentRoot[];
|
|
1229
|
+
budget?: Budget;
|
|
1230
|
+
projects?: boolean;
|
|
1231
|
+
/**
|
|
1232
|
+
* The result a session of this agent answers through `finish`, when a
|
|
1233
|
+
* helper's parent or an app started it: an object schema.
|
|
1234
|
+
*/
|
|
1235
|
+
result?: {
|
|
1236
|
+
[k: string]: unknown;
|
|
1237
|
+
};
|
|
1238
|
+
}
|
|
1239
|
+
interface ModelRequirement {
|
|
1240
|
+
kind: ModelKind;
|
|
1241
|
+
tools?: boolean;
|
|
1242
|
+
vision?: boolean;
|
|
1243
|
+
/**
|
|
1244
|
+
* Models the author knows the agent runs well on, as a catalogue
|
|
1245
|
+
* spells them; a preference in the pick, never a requirement.
|
|
1246
|
+
*/
|
|
1247
|
+
recommend?: string[];
|
|
1248
|
+
sampling?: Sampling;
|
|
1249
|
+
reasoning?: Reasoning;
|
|
1250
|
+
}
|
|
1251
|
+
interface Sampling {
|
|
1252
|
+
temperature?: number;
|
|
1253
|
+
topP?: number;
|
|
1254
|
+
maxTokens?: number;
|
|
1255
|
+
}
|
|
1256
|
+
interface Compaction {
|
|
1257
|
+
focus: string;
|
|
1258
|
+
}
|
|
1259
|
+
interface Budget {
|
|
1260
|
+
tokens?: number;
|
|
1261
|
+
rounds?: number;
|
|
1262
|
+
}
|
|
1263
|
+
/**
|
|
1264
|
+
* The kinds of model a package needs, each marked as required or not, in
|
|
1265
|
+
* the order the manifest names them.
|
|
1266
|
+
*/
|
|
1267
|
+
interface ModelNeed {
|
|
1268
|
+
required: boolean;
|
|
1269
|
+
}
|
|
1270
|
+
interface ToolDeclaration {
|
|
1271
|
+
name: string;
|
|
1272
|
+
title: string;
|
|
1273
|
+
description: string;
|
|
1274
|
+
input: {
|
|
1275
|
+
[k: string]: unknown;
|
|
1276
|
+
};
|
|
1277
|
+
output?: {
|
|
1278
|
+
[k: string]: unknown;
|
|
1279
|
+
};
|
|
1280
|
+
mutating: boolean;
|
|
1281
|
+
outbound: boolean;
|
|
1282
|
+
timeoutMs?: number;
|
|
1283
|
+
/**
|
|
1284
|
+
* The view that renders the tool's result: a view surface placed
|
|
1285
|
+
* `inline`.
|
|
1286
|
+
*/
|
|
1287
|
+
view?: string;
|
|
1288
|
+
icon?: ChatIconRole;
|
|
1289
|
+
/**
|
|
1290
|
+
* Who may call the tool. Absent, both.
|
|
1291
|
+
*
|
|
1292
|
+
* @minItems 1
|
|
1293
|
+
*/
|
|
1294
|
+
visibility?: ToolVisibility[];
|
|
1295
|
+
}
|
|
1296
|
+
interface Capabilities {
|
|
1297
|
+
tools?: string[];
|
|
1298
|
+
skills?: PackagePath[];
|
|
1299
|
+
}
|
|
1300
|
+
interface AskDeclaration {
|
|
1301
|
+
kind: string;
|
|
1302
|
+
title: string;
|
|
1303
|
+
}
|
|
1304
|
+
interface FormatDeclaration {
|
|
1305
|
+
id: string;
|
|
1306
|
+
/**
|
|
1307
|
+
* @minItems 1
|
|
1308
|
+
*/
|
|
1309
|
+
extensions: string[];
|
|
1310
|
+
}
|
|
1311
|
+
interface Onboarding {
|
|
1312
|
+
version: number;
|
|
1313
|
+
/**
|
|
1314
|
+
* @minItems 1
|
|
1315
|
+
*/
|
|
1316
|
+
cards: OnboardingCard[];
|
|
1317
|
+
}
|
|
1318
|
+
interface OnboardingCard {
|
|
1319
|
+
title: string;
|
|
1320
|
+
text?: string;
|
|
1321
|
+
image?: ServedPicture;
|
|
1322
|
+
rows?: OnboardingRow[];
|
|
1323
|
+
/**
|
|
1324
|
+
* A model this computer's engine can pull, by the id its device row
|
|
1325
|
+
* gives it.
|
|
1326
|
+
*/
|
|
1327
|
+
download?: string;
|
|
1328
|
+
}
|
|
1329
|
+
interface OnboardingRow {
|
|
1330
|
+
icon: ChatIconRole;
|
|
1331
|
+
title: string;
|
|
1332
|
+
text: string;
|
|
1333
|
+
}
|
|
1334
|
+
/**
|
|
1335
|
+
* A right-click entry of the app's rail button: a call of one of the
|
|
1336
|
+
* app's tools with these arguments, `{}` when absent. A result that names
|
|
1337
|
+
* a view opens that view as a tab of the focused tile.
|
|
1338
|
+
*/
|
|
1339
|
+
interface QuickAction {
|
|
1340
|
+
title: string;
|
|
1341
|
+
tool: string;
|
|
1342
|
+
args?: {
|
|
1343
|
+
[k: string]: unknown;
|
|
1344
|
+
};
|
|
1345
|
+
}
|
|
1346
|
+
/**
|
|
1347
|
+
* The app's settings: a JSON Schema object of booleans, strings and
|
|
1348
|
+
* numbers, which the platform stores and hands to the app's backend and
|
|
1349
|
+
* views, and the groups the settings page draws them in. With `layout`,
|
|
1350
|
+
* every setting sits in exactly one group; without it, the settings show
|
|
1351
|
+
* in the order the schema declares them.
|
|
1352
|
+
*/
|
|
1353
|
+
interface SettingsDeclaration {
|
|
1354
|
+
schema: SettingsSchema;
|
|
1355
|
+
/**
|
|
1356
|
+
* @minItems 1
|
|
1357
|
+
*/
|
|
1358
|
+
layout?: SettingsGroup[];
|
|
1359
|
+
}
|
|
1360
|
+
interface SettingsSchema {
|
|
1361
|
+
type: ObjectType;
|
|
1362
|
+
properties: {
|
|
1363
|
+
[k: string]: SettingDeclaration;
|
|
1364
|
+
};
|
|
1365
|
+
}
|
|
1366
|
+
interface SettingsGroup {
|
|
1367
|
+
title: string;
|
|
1368
|
+
/**
|
|
1369
|
+
* @minItems 1
|
|
1370
|
+
*/
|
|
1371
|
+
items: SettingsItem[];
|
|
1372
|
+
}
|
|
1373
|
+
interface Mentions {
|
|
1374
|
+
tool: string;
|
|
1375
|
+
}
|
|
1376
|
+
/**
|
|
1377
|
+
* A remote MCP server, by its address.
|
|
1378
|
+
*/
|
|
1379
|
+
interface RemoteMcpServer {
|
|
1380
|
+
url: string;
|
|
1381
|
+
}
|
|
1382
|
+
/**
|
|
1383
|
+
* A JavaScript file in the package the platform runs in the app's
|
|
1384
|
+
* environment, with the environment variables it reads, each a secret the
|
|
1385
|
+
* person enters.
|
|
1386
|
+
*/
|
|
1387
|
+
interface BundledMcpServer {
|
|
1388
|
+
entry: string;
|
|
1389
|
+
env?: string[];
|
|
1390
|
+
}
|
|
1391
|
+
/**
|
|
1392
|
+
* What `net.fetch` takes.
|
|
1393
|
+
*/
|
|
1394
|
+
interface FetchParams {
|
|
1395
|
+
url: string;
|
|
1396
|
+
method?: string;
|
|
1397
|
+
headers?: {
|
|
1398
|
+
[k: string]: string;
|
|
1399
|
+
};
|
|
1400
|
+
body?: string;
|
|
1401
|
+
}
|
|
1402
|
+
/**
|
|
1403
|
+
* What `net.fetch` answers.
|
|
1404
|
+
*/
|
|
1405
|
+
interface FetchAnswer {
|
|
1406
|
+
status: number;
|
|
1407
|
+
headers: {
|
|
1408
|
+
[k: string]: string;
|
|
1409
|
+
};
|
|
1410
|
+
body: string;
|
|
1411
|
+
}
|
|
1412
|
+
/**
|
|
1413
|
+
* The body of `POST /models/complete` and of one model call of a turn.
|
|
1414
|
+
*/
|
|
1415
|
+
interface CompletionRequest {
|
|
1416
|
+
messages: ChatMessage[];
|
|
1417
|
+
tools?: ToolDefinition[];
|
|
1418
|
+
/**
|
|
1419
|
+
* JSON against this schema, sent to the runtime as its structured
|
|
1420
|
+
* output request; a runtime without the feature refuses with its own
|
|
1421
|
+
* reason.
|
|
1422
|
+
*/
|
|
1423
|
+
format?: CompletionFormat;
|
|
1424
|
+
sampling?: Sampling;
|
|
1425
|
+
reasoning?: Reasoning;
|
|
1426
|
+
/**
|
|
1427
|
+
* Asks for the same answer to the same request as far as the runtime
|
|
1428
|
+
* allows: a fixed seed, and on a Hearthscale Server the whole prompt
|
|
1429
|
+
* read again rather than partly from an earlier request's cache.
|
|
1430
|
+
*/
|
|
1431
|
+
repeatable?: true;
|
|
1432
|
+
}
|
|
1433
|
+
/**
|
|
1434
|
+
* One message of a request, in the OpenAI v1 roles.
|
|
1435
|
+
*/
|
|
1436
|
+
interface ChatMessage {
|
|
1437
|
+
role: ChatRole;
|
|
1438
|
+
content: ChatContent;
|
|
1439
|
+
toolCalls?: ToolCall[];
|
|
1440
|
+
toolCallId?: string;
|
|
1441
|
+
}
|
|
1442
|
+
/**
|
|
1443
|
+
* One tool as a model sees it.
|
|
1444
|
+
*/
|
|
1445
|
+
interface ToolDefinition {
|
|
1446
|
+
name: string;
|
|
1447
|
+
description: string;
|
|
1448
|
+
/**
|
|
1449
|
+
* JSON Schema for the arguments object.
|
|
1450
|
+
*/
|
|
1451
|
+
parameters: {
|
|
1452
|
+
[k: string]: unknown;
|
|
1453
|
+
};
|
|
1454
|
+
}
|
|
1455
|
+
/**
|
|
1456
|
+
* The structured output a request asks for.
|
|
1457
|
+
*/
|
|
1458
|
+
interface CompletionFormat {
|
|
1459
|
+
name?: string;
|
|
1460
|
+
schema: {
|
|
1461
|
+
[k: string]: unknown;
|
|
1462
|
+
};
|
|
1463
|
+
}
|
|
1464
|
+
/**
|
|
1465
|
+
* What a conversation's requests have spent, by the log.
|
|
1466
|
+
*/
|
|
1467
|
+
interface SpentTokens {
|
|
1468
|
+
tokens: number;
|
|
1469
|
+
rounds: number;
|
|
1470
|
+
}
|
|
1471
|
+
/**
|
|
1472
|
+
* An icon as a data URL per scheme.
|
|
1473
|
+
*/
|
|
1474
|
+
interface SchemedIcon {
|
|
1475
|
+
light: string;
|
|
1476
|
+
dark: string;
|
|
1477
|
+
}
|
|
1478
|
+
/**
|
|
1479
|
+
* One folder or file an app's backend reaches, by the handle its channel
|
|
1480
|
+
* names.
|
|
1481
|
+
*/
|
|
1482
|
+
interface Mount {
|
|
1483
|
+
handle: string;
|
|
1484
|
+
path: string;
|
|
1485
|
+
mode: MountMode;
|
|
1486
|
+
}
|
|
1487
|
+
/**
|
|
1488
|
+
* A project: one folder under its app's workspace and the instructions
|
|
1489
|
+
* its sessions read.
|
|
1490
|
+
*/
|
|
1491
|
+
interface ProjectRecord {
|
|
1492
|
+
id: string;
|
|
1493
|
+
app: string;
|
|
1494
|
+
name: string;
|
|
1495
|
+
instructions: string;
|
|
1496
|
+
rank: number;
|
|
1497
|
+
createdAt: string;
|
|
1498
|
+
folder: string;
|
|
1499
|
+
}
|
|
1500
|
+
/**
|
|
1501
|
+
* A file opened in an app, by an address only the host resolves.
|
|
1502
|
+
*/
|
|
1503
|
+
interface OpenedFile {
|
|
1504
|
+
name: string;
|
|
1505
|
+
resourceUri: string;
|
|
1506
|
+
}
|
|
1507
|
+
/**
|
|
1508
|
+
* One folder as `GET /fs/list` answers it.
|
|
1509
|
+
*/
|
|
1510
|
+
interface FsListing {
|
|
1511
|
+
path: string;
|
|
1512
|
+
/**
|
|
1513
|
+
* The drive or volume the path sits on, where walking up ends.
|
|
1514
|
+
*/
|
|
1515
|
+
root: string;
|
|
1516
|
+
dirs: string[];
|
|
1517
|
+
files: string[];
|
|
1518
|
+
}
|
|
1519
|
+
/**
|
|
1520
|
+
* The head of one file as `GET /fs/read` answers it.
|
|
1521
|
+
*/
|
|
1522
|
+
interface FsRead {
|
|
1523
|
+
path: string;
|
|
1524
|
+
size: number;
|
|
1525
|
+
binary: boolean;
|
|
1526
|
+
text?: string;
|
|
1527
|
+
}
|
|
1528
|
+
/**
|
|
1529
|
+
* What one repository answers about itself.
|
|
1530
|
+
*/
|
|
1531
|
+
interface VcsRepo {
|
|
1532
|
+
root: string;
|
|
1533
|
+
/**
|
|
1534
|
+
* The checked-out branch, empty where HEAD is detached.
|
|
1535
|
+
*/
|
|
1536
|
+
branch: string;
|
|
1537
|
+
}
|
|
1538
|
+
interface VcsRefs {
|
|
1539
|
+
current: string;
|
|
1540
|
+
branches: string[];
|
|
1541
|
+
}
|
|
1542
|
+
/**
|
|
1543
|
+
* One scope's patch.
|
|
1544
|
+
*/
|
|
1545
|
+
interface VcsDiff {
|
|
1546
|
+
patch: string;
|
|
1547
|
+
/**
|
|
1548
|
+
* The cap cut the patch; what came back is whole files up to the cut.
|
|
1549
|
+
*/
|
|
1550
|
+
truncated: boolean;
|
|
1551
|
+
/**
|
|
1552
|
+
* How many changed files the patch leaves out because they lie in the
|
|
1553
|
+
* deny-read set.
|
|
1554
|
+
*/
|
|
1555
|
+
hidden: number;
|
|
1556
|
+
}
|
|
1557
|
+
/**
|
|
1558
|
+
* One file whole, as a scope's new side holds it.
|
|
1559
|
+
*/
|
|
1560
|
+
interface VcsFile {
|
|
1561
|
+
text: string;
|
|
1562
|
+
}
|
|
1563
|
+
/**
|
|
1564
|
+
* One terminal as `POST /terminals` answers it and as its stream's first
|
|
1565
|
+
* frame carries it.
|
|
1566
|
+
*/
|
|
1567
|
+
interface TerminalSnapshot {
|
|
1568
|
+
id: string;
|
|
1569
|
+
/**
|
|
1570
|
+
* The app whose window the terminal was opened in.
|
|
1571
|
+
*/
|
|
1572
|
+
app: string;
|
|
1573
|
+
/**
|
|
1574
|
+
* The folder the shell started in.
|
|
1575
|
+
*/
|
|
1576
|
+
cwd: string;
|
|
1577
|
+
/**
|
|
1578
|
+
* The shell's own name: PowerShell, zsh, bash.
|
|
1579
|
+
*/
|
|
1580
|
+
shell: string;
|
|
1581
|
+
status: TerminalStatus;
|
|
1582
|
+
/**
|
|
1583
|
+
* The scrollback, capped at the line ring.
|
|
1584
|
+
*/
|
|
1585
|
+
history: string;
|
|
1586
|
+
exitCode: number | null;
|
|
1587
|
+
}
|
|
1588
|
+
/**
|
|
1589
|
+
* One session as `GET /sessions` lists it: its record, its agent's display
|
|
1590
|
+
* name, its own name else the app's, and the card its next turn runs on
|
|
1591
|
+
* by the daemon's rule.
|
|
1592
|
+
*/
|
|
1593
|
+
interface Session {
|
|
1594
|
+
id: string;
|
|
1595
|
+
app: string;
|
|
1596
|
+
appVersion: string;
|
|
1597
|
+
agent: string;
|
|
1598
|
+
project?: string;
|
|
1599
|
+
startedBy?: PrincipalRef;
|
|
1600
|
+
title: string;
|
|
1601
|
+
preview: string;
|
|
1602
|
+
/**
|
|
1603
|
+
* The card the next turn uses, when a person chose one.
|
|
1604
|
+
*/
|
|
1605
|
+
model?: string;
|
|
1606
|
+
createdAt: string;
|
|
1607
|
+
updatedAt: string;
|
|
1608
|
+
status: SessionStatus;
|
|
1609
|
+
stopReason?: StopReason;
|
|
1610
|
+
leaf: string | null;
|
|
1611
|
+
entries: number;
|
|
1612
|
+
bytes: number;
|
|
1613
|
+
pinned: boolean;
|
|
1614
|
+
archived: boolean;
|
|
1615
|
+
rank: number;
|
|
1616
|
+
forkedFrom?: string;
|
|
1617
|
+
spawnedBy?: string;
|
|
1618
|
+
/**
|
|
1619
|
+
* On a helper: the parent's `spawn_agent` call that started it.
|
|
1620
|
+
*/
|
|
1621
|
+
spawnedByCall?: string;
|
|
1622
|
+
authoritySession: string;
|
|
1623
|
+
spent: SpentTokens;
|
|
1624
|
+
roots: SessionRoot[];
|
|
1625
|
+
lastTurn?: LastTurn;
|
|
1626
|
+
/**
|
|
1627
|
+
* The programs running now, each with the `exec` call that started
|
|
1628
|
+
* it.
|
|
1629
|
+
*/
|
|
1630
|
+
cells: SessionCell[];
|
|
1631
|
+
/**
|
|
1632
|
+
* The commands running in the background now, each with the `bash`
|
|
1633
|
+
* call that started it.
|
|
1634
|
+
*/
|
|
1635
|
+
processes: SessionProcess[];
|
|
1636
|
+
agentName: string;
|
|
1637
|
+
effective: EffectiveModel;
|
|
1638
|
+
}
|
|
1639
|
+
/**
|
|
1640
|
+
* The turn a session ended last, and why.
|
|
1641
|
+
*/
|
|
1642
|
+
interface LastTurn {
|
|
1643
|
+
id: string;
|
|
1644
|
+
stopReason: StopReason;
|
|
1645
|
+
}
|
|
1646
|
+
/**
|
|
1647
|
+
* `GET /vcs/diff`: one scope's patch of a repository.
|
|
1648
|
+
*/
|
|
1649
|
+
interface VcsDiffQuery {
|
|
1650
|
+
root: string;
|
|
1651
|
+
scope: VcsScope;
|
|
1652
|
+
/**
|
|
1653
|
+
* The ref a `branch` scope compares the current branch against.
|
|
1654
|
+
*/
|
|
1655
|
+
base?: string;
|
|
1656
|
+
/**
|
|
1657
|
+
* Root-relative pathspecs the patch is narrowed to.
|
|
1658
|
+
*/
|
|
1659
|
+
paths?: string[];
|
|
1660
|
+
}
|
|
1661
|
+
/**
|
|
1662
|
+
* `GET /vcs/file`: one file whole, as a scope's new side holds it, which
|
|
1663
|
+
* the diff panel's unmodified runs are read from: the working tree's copy
|
|
1664
|
+
* for `working`, the index's for `staged` and `HEAD`'s for `branch`.
|
|
1665
|
+
*/
|
|
1666
|
+
interface VcsFileQuery {
|
|
1667
|
+
root: string;
|
|
1668
|
+
scope: VcsScope;
|
|
1669
|
+
/**
|
|
1670
|
+
* Relative to the repository's top, as the patch names it.
|
|
1671
|
+
*/
|
|
1672
|
+
path: string;
|
|
1673
|
+
}
|
|
1674
|
+
/**
|
|
1675
|
+
* What one job of each kind takes, by kind. Audio and images cross as
|
|
1676
|
+
* assets.
|
|
1677
|
+
*/
|
|
1678
|
+
interface JobInputs {
|
|
1679
|
+
image: ImageJobInput;
|
|
1680
|
+
music: MusicJobInput;
|
|
1681
|
+
speech: SpeechJobInput;
|
|
1682
|
+
transcription: TranscriptionJobInput;
|
|
1683
|
+
embedding: EmbeddingJobInput;
|
|
1684
|
+
}
|
|
1685
|
+
interface ImageJobInput {
|
|
1686
|
+
prompt: string;
|
|
1687
|
+
size?: string;
|
|
1688
|
+
}
|
|
1689
|
+
interface MusicJobInput {
|
|
1690
|
+
prompt: string;
|
|
1691
|
+
seconds: number;
|
|
1692
|
+
lyrics?: string;
|
|
1693
|
+
}
|
|
1694
|
+
interface SpeechJobInput {
|
|
1695
|
+
text: string;
|
|
1696
|
+
voice?: string;
|
|
1697
|
+
}
|
|
1698
|
+
/**
|
|
1699
|
+
* `audio` is an asset.
|
|
1700
|
+
*/
|
|
1701
|
+
interface TranscriptionJobInput {
|
|
1702
|
+
audio: string;
|
|
1703
|
+
language?: string;
|
|
1704
|
+
}
|
|
1705
|
+
interface EmbeddingJobInput {
|
|
1706
|
+
texts: string[];
|
|
1707
|
+
}
|
|
1708
|
+
/**
|
|
1709
|
+
* The executor's answer to a command: what the command answers the body,
|
|
1710
|
+
* or the error it met.
|
|
1711
|
+
*/
|
|
1712
|
+
interface SurfaceResult {
|
|
1713
|
+
id: string;
|
|
1714
|
+
url?: string;
|
|
1715
|
+
title?: string;
|
|
1716
|
+
result?: unknown;
|
|
1717
|
+
asset?: string;
|
|
1718
|
+
shown?: boolean;
|
|
1719
|
+
error?: string;
|
|
1720
|
+
}
|
|
1721
|
+
/**
|
|
1722
|
+
* A path inside a mount, as the backend names files: the mount's handle
|
|
1723
|
+
* and the path under it.
|
|
1724
|
+
*/
|
|
1725
|
+
interface MountPath {
|
|
1726
|
+
root: string;
|
|
1727
|
+
path: string;
|
|
1728
|
+
}
|
|
1729
|
+
/**
|
|
1730
|
+
* What a tool body answers: content for the model and the view that
|
|
1731
|
+
* renders the result.
|
|
1732
|
+
*/
|
|
1733
|
+
interface ToolAnswer {
|
|
1734
|
+
content: Content[];
|
|
1735
|
+
structured?: Structured;
|
|
1736
|
+
/**
|
|
1737
|
+
* Values for the view that renders the result, as MCP's result
|
|
1738
|
+
* `_meta`; they never reach a model.
|
|
1739
|
+
*/
|
|
1740
|
+
meta?: {
|
|
1741
|
+
[k: string]: unknown;
|
|
1742
|
+
};
|
|
1743
|
+
view?: string;
|
|
1744
|
+
/**
|
|
1745
|
+
* The model tokens the body spent through `models.complete`, summed
|
|
1746
|
+
* by the core.
|
|
1747
|
+
*/
|
|
1748
|
+
usage?: Usage;
|
|
1749
|
+
}
|
|
1750
|
+
/**
|
|
1751
|
+
* What a surface command answers a body: the page's address and title
|
|
1752
|
+
* after the command, a script's value, a screenshot's asset, and whether
|
|
1753
|
+
* the tab is in the conversation's panel, where the person sees it, which
|
|
1754
|
+
* every answer but `close`'s carries.
|
|
1755
|
+
*/
|
|
1756
|
+
interface SurfaceAnswer {
|
|
1757
|
+
url?: string;
|
|
1758
|
+
title?: string;
|
|
1759
|
+
result?: unknown;
|
|
1760
|
+
asset?: string;
|
|
1761
|
+
shown?: boolean;
|
|
1762
|
+
}
|
|
1763
|
+
/**
|
|
1764
|
+
* One session as `sessions.list` lists it.
|
|
1765
|
+
*/
|
|
1766
|
+
interface SessionListing {
|
|
1767
|
+
id: string;
|
|
1768
|
+
app: string;
|
|
1769
|
+
title: string;
|
|
1770
|
+
createdAt: string;
|
|
1771
|
+
updatedAt: string;
|
|
1772
|
+
}
|
|
1773
|
+
/**
|
|
1774
|
+
* One session with its entries, as `sessions.open` answers it.
|
|
1775
|
+
*/
|
|
1776
|
+
interface OpenedSession {
|
|
1777
|
+
id: string;
|
|
1778
|
+
title: string;
|
|
1779
|
+
entries: Entry[];
|
|
1780
|
+
}
|
|
1781
|
+
/**
|
|
1782
|
+
* A conversation `sessions.create` starts: in this app, or in another app
|
|
1783
|
+
* under the `sessions.create` grant, for a named agent and in a project.
|
|
1784
|
+
*/
|
|
1785
|
+
interface SessionCreate {
|
|
1786
|
+
app?: string;
|
|
1787
|
+
agent?: string;
|
|
1788
|
+
project?: string;
|
|
1789
|
+
title?: string;
|
|
1790
|
+
message?: string;
|
|
1791
|
+
/**
|
|
1792
|
+
* A chat card `models.for` lists for the app.
|
|
1793
|
+
*/
|
|
1794
|
+
model?: string;
|
|
1795
|
+
}
|
|
1796
|
+
/**
|
|
1797
|
+
* A session's last turn: how it ended, its last reply, and the result its
|
|
1798
|
+
* agent answered through `finish`.
|
|
1799
|
+
*/
|
|
1800
|
+
interface TurnOutcome {
|
|
1801
|
+
turn: string;
|
|
1802
|
+
stopReason: StopReason;
|
|
1803
|
+
text: string;
|
|
1804
|
+
result?: Structured;
|
|
1805
|
+
}
|
|
1806
|
+
/**
|
|
1807
|
+
* One enabled app as `apps.list` lists it.
|
|
1808
|
+
*/
|
|
1809
|
+
interface AppListing {
|
|
1810
|
+
id: string;
|
|
1811
|
+
name: string;
|
|
1812
|
+
description: string;
|
|
1813
|
+
/**
|
|
1814
|
+
* The icon's file in the app's package per colour scheme, which a page
|
|
1815
|
+
* loads from `/apps/<id>/ui/<file>`; null when it has none.
|
|
1816
|
+
*/
|
|
1817
|
+
icon: SchemedIcon | null;
|
|
1818
|
+
agent: boolean;
|
|
1819
|
+
capabilities: string[];
|
|
1820
|
+
}
|
|
1821
|
+
/**
|
|
1822
|
+
* One chat card an app's sessions may run on, as `models.for` lists it.
|
|
1823
|
+
*/
|
|
1824
|
+
interface ModelListing {
|
|
1825
|
+
id: string;
|
|
1826
|
+
name: string;
|
|
1827
|
+
provider: string;
|
|
1828
|
+
}
|
|
1829
|
+
/**
|
|
1830
|
+
* One project as `projects.list` lists it.
|
|
1831
|
+
*/
|
|
1832
|
+
interface ProjectListing {
|
|
1833
|
+
id: string;
|
|
1834
|
+
name: string;
|
|
1835
|
+
folder: string;
|
|
1836
|
+
}
|
|
1837
|
+
/**
|
|
1838
|
+
* An app's own question to the person during a tool call: a choice, a
|
|
1839
|
+
* sign-in, a handoff; `kind` is one the manifest's `asks` declares. It
|
|
1840
|
+
* widens nothing.
|
|
1841
|
+
*/
|
|
1842
|
+
interface AppQuestion {
|
|
1843
|
+
kind: string;
|
|
1844
|
+
text: string;
|
|
1845
|
+
}
|
|
1846
|
+
/**
|
|
1847
|
+
* The person's answer to an app's question.
|
|
1848
|
+
*/
|
|
1849
|
+
interface AppAnswer {
|
|
1850
|
+
allow: boolean;
|
|
1851
|
+
option?: string;
|
|
1852
|
+
}
|
|
1853
|
+
/**
|
|
1854
|
+
* A durable entry in one of the app's own sessions, or a transient event
|
|
1855
|
+
* for the app's views.
|
|
1856
|
+
*/
|
|
1857
|
+
interface AppEvent {
|
|
1858
|
+
name: string;
|
|
1859
|
+
session?: string;
|
|
1860
|
+
data: unknown;
|
|
1861
|
+
durable: boolean;
|
|
1862
|
+
context?: string;
|
|
1863
|
+
}
|
|
1864
|
+
/**
|
|
1865
|
+
* An OS notification an app asks for.
|
|
1866
|
+
*/
|
|
1867
|
+
interface AppNotice {
|
|
1868
|
+
title: string;
|
|
1869
|
+
body: string;
|
|
1870
|
+
session?: string;
|
|
1871
|
+
}
|
|
1872
|
+
/**
|
|
1873
|
+
* A sign-in to an online service of the app's own, with the app's own
|
|
1874
|
+
* client registered at that service.
|
|
1875
|
+
*/
|
|
1876
|
+
interface OAuthLogin {
|
|
1877
|
+
/**
|
|
1878
|
+
* The authorization server's identifier, an https address without a
|
|
1879
|
+
* query or a fragment; its metadata names the endpoints unless
|
|
1880
|
+
* `endpoints` does.
|
|
1881
|
+
*/
|
|
1882
|
+
issuer: string;
|
|
1883
|
+
/**
|
|
1884
|
+
* Absent when the server registers clients itself (RFC 7591).
|
|
1885
|
+
*/
|
|
1886
|
+
clientId?: string;
|
|
1887
|
+
/**
|
|
1888
|
+
* For a server that demands one even from a desktop client.
|
|
1889
|
+
*/
|
|
1890
|
+
clientSecret?: string;
|
|
1891
|
+
scopes?: string[];
|
|
1892
|
+
/**
|
|
1893
|
+
* The RFC 8707 resource the token is for.
|
|
1894
|
+
*/
|
|
1895
|
+
resource?: string;
|
|
1896
|
+
endpoints?: OAuthEndpoints;
|
|
1897
|
+
grant?: OAuthGrant;
|
|
1898
|
+
/**
|
|
1899
|
+
* The server's own fields on the authorization address, such as
|
|
1900
|
+
* `access_type`.
|
|
1901
|
+
*/
|
|
1902
|
+
params?: {
|
|
1903
|
+
[k: string]: string;
|
|
1904
|
+
};
|
|
1905
|
+
}
|
|
1906
|
+
/**
|
|
1907
|
+
* The endpoints of an authorization server that publishes no metadata.
|
|
1908
|
+
*/
|
|
1909
|
+
interface OAuthEndpoints {
|
|
1910
|
+
authorization?: string;
|
|
1911
|
+
token: string;
|
|
1912
|
+
device?: string;
|
|
1913
|
+
}
|
|
1914
|
+
|
|
1915
|
+
/**
|
|
1916
|
+
* The view bridge: what a view, an app's UI in a sandboxed frame, and its
|
|
1917
|
+
* host say to each other beyond the MCP Apps standard the view speaks.
|
|
1918
|
+
* Every method is a JSON-RPC request over the MCP Apps transport, and
|
|
1919
|
+
* every result is an object, as that protocol requires.
|
|
1920
|
+
*
|
|
1921
|
+
* Where OpenAI's MCP extensions name a key or a method, the bridge uses
|
|
1922
|
+
* that name, so a view written for ChatGPT runs unchanged; `hearthscale/*`
|
|
1923
|
+
* names only what those extensions have no name for.
|
|
1924
|
+
*
|
|
1925
|
+
* The host fills the standard capabilities of `ui/initialize` as follows:
|
|
1926
|
+
* `updateModelContext` and `message` take text, image, resource link and
|
|
1927
|
+
* embedded resource blocks, and `updateModelContext` also structured
|
|
1928
|
+
* content; `sampling` is offered when the app names `models` in `uses`,
|
|
1929
|
+
* and answers on the card the app's chat runs on; `downloadFile` saves
|
|
1930
|
+
* through the system's save dialog; `sandbox.permissions` holds the
|
|
1931
|
+
* manifest's `permissions` (`clipboard-write` as `clipboardWrite`), and
|
|
1932
|
+
* `sandbox.csp` the hosts of `environment.network` for connections,
|
|
1933
|
+
* resources and frames alike. Under `experimental`, the keys
|
|
1934
|
+
* `openai/modelContext`, `openai/message` and `openai/resource` each hold
|
|
1935
|
+
* `{}`, `openai/files` holds `{}` when the app names `files.open` in
|
|
1936
|
+
* `uses`, and `hearthscale` holds `HearthscaleHostCapability`. In the host
|
|
1937
|
+
* context, `displayMode` and `availableDisplayModes` follow
|
|
1938
|
+
* `MCP_DISPLAY_MODES` and the surface's placements, and
|
|
1939
|
+
* `containerDimensions` is the size of the view's frame, `width` and
|
|
1940
|
+
* `height` in a tab or a modal and `width` and `maxHeight` under a
|
|
1941
|
+
* result, sent again on each change.
|
|
1942
|
+
*
|
|
1943
|
+
* Every block a view sends with `ui/update-model-context` shows as a
|
|
1944
|
+
* removable chip above the composer of each chat on screen in the same
|
|
1945
|
+
* window, and rides the next message sent there as a `context` part; no
|
|
1946
|
+
* block reaches a model without a chip, whatever its
|
|
1947
|
+
* `annotations.audience` says.
|
|
1948
|
+
*/
|
|
1949
|
+
|
|
1950
|
+
/** The extensions a view calls as `hearthscale/<extension>/…`, each only
|
|
1951
|
+
* when its app names it in `uses`: the app's own conversations and
|
|
1952
|
+
* projects, its store, its backend's events, its folders, its models,
|
|
1953
|
+
* its jobs, its terminals, opening a surface, and its rooms. Opening a
|
|
1954
|
+
* file is OpenAI's `openai/files/open`, which `files.open` in `uses`
|
|
1955
|
+
* gates. */
|
|
1956
|
+
declare const VIEW_EXTENSIONS: readonly ["sessions", "store", "events", "roots", "models", "jobs", "terminals", "surfaces.open", "peers"];
|
|
1957
|
+
type ViewExtension = (typeof VIEW_EXTENSIONS)[number];
|
|
1958
|
+
/** `hostCapabilities.experimental.hearthscale`: the extensions this view
|
|
1959
|
+
* may call. The `hearthscale/ui/*` methods are offered to every view. */
|
|
1960
|
+
interface HearthscaleHostCapability {
|
|
1961
|
+
extensions: ViewExtension[];
|
|
1962
|
+
}
|
|
1963
|
+
/** The keys the host adds to the MCP Apps host context, set when the view
|
|
1964
|
+
* starts and changed by `ui/notifications/host-context-changed`. */
|
|
1965
|
+
interface ViewHostContext {
|
|
1966
|
+
/** The look the host wears, as one style sheet of `@layer` bodies. */
|
|
1967
|
+
'hearthscale/appearance': string;
|
|
1968
|
+
/** The app's settings; absent for an app that declares none. */
|
|
1969
|
+
'hearthscale/settings'?: SettingValues;
|
|
1970
|
+
/** What the view's chips hold from its last `ui/update-model-context`;
|
|
1971
|
+
* null once no chip of it is left. */
|
|
1972
|
+
'openai/modelContext': ModelContextState | null;
|
|
1973
|
+
/** The state the view last saved with `hearthscale/ui/set-widget-state`,
|
|
1974
|
+
* given back when the host loads a discarded view again; null before
|
|
1975
|
+
* the first save. */
|
|
1976
|
+
'hearthscale/widgetState': unknown;
|
|
1977
|
+
/** The app-relative address, with its query, that a deep link or
|
|
1978
|
+
* `hearthscale/surfaces/open` opened the surface on; absent for a
|
|
1979
|
+
* surface opened without one. The link is
|
|
1980
|
+
* `hearthscale://open?app=<id>&surface=<id>&path=<address>`, the
|
|
1981
|
+
* address percent-encoded and starting with `/`. */
|
|
1982
|
+
'openai/deepLink'?: {
|
|
1983
|
+
url: string;
|
|
1984
|
+
};
|
|
1985
|
+
}
|
|
1986
|
+
/** The `_meta` of a text or image block of `ui/update-model-context` or
|
|
1987
|
+
* `ui/message`. `openai/title` is the label of the block's chip: in a
|
|
1988
|
+
* message, a titled block becomes a chip and an untitled text block
|
|
1989
|
+
* becomes the message's text. */
|
|
1990
|
+
interface ContentBlockMeta {
|
|
1991
|
+
'openai/title'?: string;
|
|
1992
|
+
}
|
|
1993
|
+
/** `_meta['openai/modelContext']` on the result of
|
|
1994
|
+
* `ui/update-model-context`. Each update replaces the view's last. */
|
|
1995
|
+
interface ModelContextAnswer {
|
|
1996
|
+
updateId: string;
|
|
1997
|
+
}
|
|
1998
|
+
/** `_meta['openai/message']` on a `ui/message` request. */
|
|
1999
|
+
interface MessageOptions {
|
|
2000
|
+
/** `active`, also when absent: the conversation whose transcript shows
|
|
2001
|
+
* the view; for a view that fills a tab, the conversation of its app
|
|
2002
|
+
* that its first `chat` or `composer` slot shows, made there by the
|
|
2003
|
+
* message when the slot shows a new one. `new`: a new conversation of
|
|
2004
|
+
* that app, which the slot then shows. A view that fills a tab and
|
|
2005
|
+
* shows no such slot sends no message, and drafts its words in the
|
|
2006
|
+
* composer of the conversation on screen. */
|
|
2007
|
+
target?: 'active' | 'new';
|
|
2008
|
+
/** True, also when absent, sends the message; false leaves it in the
|
|
2009
|
+
* composer for the person to send. */
|
|
2010
|
+
send?: boolean;
|
|
2011
|
+
}
|
|
2012
|
+
/** The tool input a view gets when its surface opens a file. */
|
|
2013
|
+
interface FileInput {
|
|
2014
|
+
file: OpenedFile;
|
|
2015
|
+
}
|
|
2016
|
+
/** `_meta['openai/resource']` on a `resources/read` of an opened file:
|
|
2017
|
+
* whether its bytes come as text or as a base64 blob; absent, by the
|
|
2018
|
+
* file's kind. The host answers the read, the subscription and its
|
|
2019
|
+
* `notifications/resources/updated` itself. */
|
|
2020
|
+
interface ResourceReadOptions {
|
|
2021
|
+
representation: 'text' | 'blob';
|
|
2022
|
+
}
|
|
2023
|
+
/** `_meta['openai/resource']` on the content a read of an opened file
|
|
2024
|
+
* answers: the version read, and whether `openai/resources/write` may
|
|
2025
|
+
* replace it. */
|
|
2026
|
+
interface ResourceVersion {
|
|
2027
|
+
etag: string;
|
|
2028
|
+
writable: boolean;
|
|
2029
|
+
}
|
|
2030
|
+
/** `_meta['openai/resource']` the host adds to a tool call a view showing
|
|
2031
|
+
* an opened file makes to its app's MCP server: the file's absolute path
|
|
2032
|
+
* on the platform's machine, which the view never sees. */
|
|
2033
|
+
interface ResourcePath {
|
|
2034
|
+
path: string;
|
|
2035
|
+
}
|
|
2036
|
+
/** Replaces an opened file's bytes, when the version is still `ifMatch`
|
|
2037
|
+
* or `ifMatch` is absent. */
|
|
2038
|
+
type ResourceWrite = {
|
|
2039
|
+
uri: string;
|
|
2040
|
+
ifMatch?: string;
|
|
2041
|
+
} & ({
|
|
2042
|
+
text: string;
|
|
2043
|
+
}
|
|
2044
|
+
/** Base64. */
|
|
2045
|
+
| {
|
|
2046
|
+
blob: string;
|
|
2047
|
+
});
|
|
2048
|
+
/** What the shell draws in a rectangle a view reserves: `chat`, the
|
|
2049
|
+
* transcript and the composer; `composer`, the composer alone; `cards`,
|
|
2050
|
+
* the requests of the view's app alone, for a view that has no composer;
|
|
2051
|
+
* `terminal`, the person's own live shell, which the window opens with
|
|
2052
|
+
* its own authority and the view never reads or types into; `web`, the
|
|
2053
|
+
* tab's web page on the app's own partition, which reaches only the hosts
|
|
2054
|
+
* the app declares, and which the view drives with `hearthscale/web/*`.
|
|
2055
|
+
* A view reserves at most one `web` slot. */
|
|
2056
|
+
declare const HOST_SLOT_KINDS: readonly ["chat", "composer", "cards", "terminal", "web"];
|
|
2057
|
+
type HostSlotKind = (typeof HOST_SLOT_KINDS)[number];
|
|
2058
|
+
/** The distances, in the view's CSS pixels, from each edge of the view to
|
|
2059
|
+
* the same edge of a slot. The shell anchors the slot by them in its own
|
|
2060
|
+
* layout, so a slot follows a change of its tile's size in the same frame. */
|
|
2061
|
+
interface SlotInsets {
|
|
2062
|
+
left: number;
|
|
2063
|
+
top: number;
|
|
2064
|
+
right: number;
|
|
2065
|
+
bottom: number;
|
|
2066
|
+
}
|
|
2067
|
+
/** One rectangle a view reserves for the shell's trusted parts. */
|
|
2068
|
+
interface HostSlot {
|
|
2069
|
+
/** The view's own name for the slot, unique among its slots. */
|
|
2070
|
+
id: string;
|
|
2071
|
+
kind: HostSlotKind;
|
|
2072
|
+
/** On a `chat` or `composer` slot: the conversation of the view's app
|
|
2073
|
+
* it shows. Null or absent, it shows a new conversation, which the
|
|
2074
|
+
* first message creates in `project` when one is named, and
|
|
2075
|
+
* `hearthscale/ui/slot-session` tells the view its id. */
|
|
2076
|
+
session?: string | null;
|
|
2077
|
+
project?: string;
|
|
2078
|
+
/** On a `terminal` slot: the folder its shell starts in, inside a folder
|
|
2079
|
+
* the person gave the view's app. The slot's id, letters, digits, `-`
|
|
2080
|
+
* and `_`, names the shell in the view's tab: the same id takes up the
|
|
2081
|
+
* shell it opened while the platform holds it, and the shell ends with
|
|
2082
|
+
* the tab. */
|
|
2083
|
+
cwd?: string;
|
|
2084
|
+
insets: SlotInsets;
|
|
2085
|
+
}
|
|
2086
|
+
/** The notifications the host sends every view that reserved a slot. */
|
|
2087
|
+
type HostSlotNotification =
|
|
2088
|
+
/** The height the composer or the cards in the slot take now. They lie
|
|
2089
|
+
* on the slot's bottom edge and grow upward, past the slot's top edge
|
|
2090
|
+
* when they need to; the view may make room for them. */
|
|
2091
|
+
{
|
|
2092
|
+
method: 'hearthscale/ui/slot-size';
|
|
2093
|
+
params: {
|
|
2094
|
+
id: string;
|
|
2095
|
+
height: number;
|
|
2096
|
+
};
|
|
2097
|
+
}
|
|
2098
|
+
/** The chat or the composer in the slot shows another conversation of
|
|
2099
|
+
* the app: the one its first message created, a fork, or a helper. The
|
|
2100
|
+
* shell shows it at once; the view's next report of the slot names it. */
|
|
2101
|
+
| {
|
|
2102
|
+
method: 'hearthscale/ui/slot-session';
|
|
2103
|
+
params: {
|
|
2104
|
+
id: string;
|
|
2105
|
+
session: string;
|
|
2106
|
+
};
|
|
2107
|
+
}
|
|
2108
|
+
/** The tab's web page changed: its address, title, icon, load, history
|
|
2109
|
+
* or zoom. Sent once when the view starts and at each change. */
|
|
2110
|
+
| {
|
|
2111
|
+
method: 'hearthscale/web/page';
|
|
2112
|
+
params: WebPageState;
|
|
2113
|
+
}
|
|
2114
|
+
/** The matches of the last `hearthscale/web/find`. */
|
|
2115
|
+
| {
|
|
2116
|
+
method: 'hearthscale/web/found';
|
|
2117
|
+
params: {
|
|
2118
|
+
active: number;
|
|
2119
|
+
total: number;
|
|
2120
|
+
};
|
|
2121
|
+
}
|
|
2122
|
+
/** A download of the app's pages started or moved; each view tab of the
|
|
2123
|
+
* app hears it, and `mine` is set for the tab whose page started it. */
|
|
2124
|
+
| {
|
|
2125
|
+
method: 'hearthscale/web/download';
|
|
2126
|
+
params: WebDownload & {
|
|
2127
|
+
mine: boolean;
|
|
2128
|
+
};
|
|
2129
|
+
}
|
|
2130
|
+
/** The tab's page sent a password with a sign-in form, which the host
|
|
2131
|
+
* holds for ten minutes and keeps in the system's keychain once the
|
|
2132
|
+
* view asks with `hearthscale/web/password-save`. */
|
|
2133
|
+
| {
|
|
2134
|
+
method: 'hearthscale/web/password';
|
|
2135
|
+
params: {
|
|
2136
|
+
id: string;
|
|
2137
|
+
} & WebLogin;
|
|
2138
|
+
};
|
|
2139
|
+
/** The web page of a view's tab as the view hears it. The page lives as
|
|
2140
|
+
* long as the tab, whether or not the view reserves its `web` slot, and
|
|
2141
|
+
* it lies over the slot unless the view covers it. */
|
|
2142
|
+
type WebPageState = {
|
|
2143
|
+
/** The address the page shows; null for a tab that has loaded none. */
|
|
2144
|
+
url: string | null;
|
|
2145
|
+
title: string;
|
|
2146
|
+
/** The page's own icon, an address; absent while it names none. */
|
|
2147
|
+
icon?: string;
|
|
2148
|
+
loading: boolean;
|
|
2149
|
+
canGoBack: boolean;
|
|
2150
|
+
canGoForward: boolean;
|
|
2151
|
+
/** The page's zoom factor, 1 at 100 %. */
|
|
2152
|
+
zoom: number;
|
|
2153
|
+
};
|
|
2154
|
+
type Empty = Record<never, never>;
|
|
2155
|
+
/** The host methods beyond MCP Apps that every view may call. */
|
|
2156
|
+
interface ViewHostMethods {
|
|
2157
|
+
/** Reserves rectangles of a view that fills a tab, each for a part the
|
|
2158
|
+
* shell draws and answers there: the chat, the composer or the cards.
|
|
2159
|
+
* The list replaces the last one; an empty list gives every rectangle
|
|
2160
|
+
* back, and a new document of the view starts with none. A slot is cut
|
|
2161
|
+
* to the view. A slot below `SLOT_MIN_WIDTH` or `SLOT_MIN_HEIGHT`, or
|
|
2162
|
+
* one that names a conversation of another app, is not drawn. The view
|
|
2163
|
+
* never receives what the person types there. Requests of the app dock
|
|
2164
|
+
* on the composer of its slot or in its `cards` slot, and a press on a
|
|
2165
|
+
* card counts only once the slot has kept its place for a moment. A
|
|
2166
|
+
* view in a transcript reserves none. */
|
|
2167
|
+
'hearthscale/ui/slots': {
|
|
2168
|
+
params: {
|
|
2169
|
+
slots: HostSlot[];
|
|
2170
|
+
};
|
|
2171
|
+
result: Empty;
|
|
2172
|
+
};
|
|
2173
|
+
/** Gives the keyboard focus to the composer of a `chat` or `composer`
|
|
2174
|
+
* slot, right after the person's own click or key press in the view. */
|
|
2175
|
+
'hearthscale/ui/focus-slot': {
|
|
2176
|
+
params: {
|
|
2177
|
+
id: string;
|
|
2178
|
+
};
|
|
2179
|
+
result: Empty;
|
|
2180
|
+
};
|
|
2181
|
+
/** Names the tab a view fills, in its lane and its hover card: `title`
|
|
2182
|
+
* its title, at most `TAB_TITLE_CHARS` characters, and `icon` its mark,
|
|
2183
|
+
* a picture as a `data:` address of at most `TAB_ICON_CHARS`
|
|
2184
|
+
* characters. A field left out stays as it is; null gives back the
|
|
2185
|
+
* tab's own: the surface's title or its conversation's, and the
|
|
2186
|
+
* surface's mark or its app's. The tab keeps its name through a
|
|
2187
|
+
* restart. A result's view names the tab it moves into, whenever it
|
|
2188
|
+
* moves. */
|
|
2189
|
+
'hearthscale/ui/set-tab': {
|
|
2190
|
+
params: {
|
|
2191
|
+
title?: string | null;
|
|
2192
|
+
icon?: string | null;
|
|
2193
|
+
};
|
|
2194
|
+
result: Empty;
|
|
2195
|
+
};
|
|
2196
|
+
/** Shows a view surface of the same app that its manifest places in
|
|
2197
|
+
* `modal` over the asking view's tile, on a click inside the view. The
|
|
2198
|
+
* tile dims under the modal, and the modal's view fills the tile on a
|
|
2199
|
+
* clear plate and draws its own box. It takes `input` as its tool
|
|
2200
|
+
* input, `{}` when absent, and the tool its surface names is called
|
|
2201
|
+
* with it. One modal per tile: another replaces it. The app's
|
|
2202
|
+
* requests draw above the modal. */
|
|
2203
|
+
'hearthscale/ui/open-modal': {
|
|
2204
|
+
params: {
|
|
2205
|
+
surface: string;
|
|
2206
|
+
input?: Record<string, unknown>;
|
|
2207
|
+
};
|
|
2208
|
+
result: Empty;
|
|
2209
|
+
};
|
|
2210
|
+
/** Closes the modal the calling view is in. */
|
|
2211
|
+
'hearthscale/ui/close-modal': {
|
|
2212
|
+
params: Empty;
|
|
2213
|
+
result: Empty;
|
|
2214
|
+
};
|
|
2215
|
+
/** Keeps a JSON value for this view's tab, which the host gives back in
|
|
2216
|
+
* `hearthscale/widgetState`; it never reaches a model. The value takes
|
|
2217
|
+
* at most 64 KiB as JSON text. */
|
|
2218
|
+
'hearthscale/ui/set-widget-state': {
|
|
2219
|
+
params: {
|
|
2220
|
+
state: unknown;
|
|
2221
|
+
};
|
|
2222
|
+
result: Empty;
|
|
2223
|
+
};
|
|
2224
|
+
/** Lets the person pick files with the system's dialog, on a click
|
|
2225
|
+
* inside the view and at every level, filtered by extension (`.png`),
|
|
2226
|
+
* media type (`image/png`) or a family of types (`image/*`); the files
|
|
2227
|
+
* read through `resources/read`, as files the app opened. A cancelled
|
|
2228
|
+
* dialog answers none. */
|
|
2229
|
+
'hearthscale/ui/select-files': {
|
|
2230
|
+
params: {
|
|
2231
|
+
accept?: string[];
|
|
2232
|
+
multiple?: boolean;
|
|
2233
|
+
};
|
|
2234
|
+
result: {
|
|
2235
|
+
files: OpenedFile[];
|
|
2236
|
+
};
|
|
2237
|
+
};
|
|
2238
|
+
/** Stores `blob`, base64 of at most 64 MiB, as an
|
|
2239
|
+
* asset of the conversation the view belongs to, else of its app; the
|
|
2240
|
+
* view reads it back as `hearthscale-asset://<asset>` and hands `asset`
|
|
2241
|
+
* to its tools. */
|
|
2242
|
+
'hearthscale/ui/upload-file': {
|
|
2243
|
+
params: {
|
|
2244
|
+
name: string;
|
|
2245
|
+
mediaType: string;
|
|
2246
|
+
blob: string;
|
|
2247
|
+
};
|
|
2248
|
+
result: {
|
|
2249
|
+
asset: string;
|
|
2250
|
+
};
|
|
2251
|
+
};
|
|
2252
|
+
'openai/resources/write': {
|
|
2253
|
+
params: ResourceWrite;
|
|
2254
|
+
result: ResourceWriteResult;
|
|
2255
|
+
};
|
|
2256
|
+
/** Loads an `https:` or `http:` address in the tab's web page, which
|
|
2257
|
+
* starts with the first one. A host the app does not declare in
|
|
2258
|
+
* `environment.network` is refused before it leaves the machine. */
|
|
2259
|
+
'hearthscale/web/navigate': {
|
|
2260
|
+
params: {
|
|
2261
|
+
url: string;
|
|
2262
|
+
};
|
|
2263
|
+
result: Empty;
|
|
2264
|
+
};
|
|
2265
|
+
/** Steps the page back or forward in its history, loads it again, or
|
|
2266
|
+
* stops its load. */
|
|
2267
|
+
'hearthscale/web/go': {
|
|
2268
|
+
params: {
|
|
2269
|
+
to: 'back' | 'forward' | 'reload' | 'stop';
|
|
2270
|
+
};
|
|
2271
|
+
result: Empty;
|
|
2272
|
+
};
|
|
2273
|
+
/** Finds text in the page, the next match with `next`, backwards
|
|
2274
|
+
* unless `forward`; empty text ends the find and clears its marks. The
|
|
2275
|
+
* matches arrive as `hearthscale/web/found`. */
|
|
2276
|
+
'hearthscale/web/find': {
|
|
2277
|
+
params: {
|
|
2278
|
+
text: string;
|
|
2279
|
+
forward?: boolean;
|
|
2280
|
+
next?: boolean;
|
|
2281
|
+
};
|
|
2282
|
+
result: Empty;
|
|
2283
|
+
};
|
|
2284
|
+
/** Sets the page's zoom factor, between 0.25 and 5. */
|
|
2285
|
+
'hearthscale/web/zoom': {
|
|
2286
|
+
params: {
|
|
2287
|
+
factor: number;
|
|
2288
|
+
};
|
|
2289
|
+
result: Empty;
|
|
2290
|
+
};
|
|
2291
|
+
/** Opens the system's print dialog for the page; needs a click. */
|
|
2292
|
+
'hearthscale/web/print': {
|
|
2293
|
+
params: Empty;
|
|
2294
|
+
result: Empty;
|
|
2295
|
+
};
|
|
2296
|
+
/** A picture of the page as it shows, a PNG in base64. */
|
|
2297
|
+
'hearthscale/web/capture': {
|
|
2298
|
+
params: Empty;
|
|
2299
|
+
result: {
|
|
2300
|
+
png: string;
|
|
2301
|
+
};
|
|
2302
|
+
};
|
|
2303
|
+
/** Lays the page under the view while `covered`, so a menu or a mark the
|
|
2304
|
+
* view draws over the slot shows above it; the page shows through
|
|
2305
|
+
* where the view is transparent and takes no pointer. Uncovered, the
|
|
2306
|
+
* page lies over its slot. */
|
|
2307
|
+
'hearthscale/web/cover': {
|
|
2308
|
+
params: {
|
|
2309
|
+
covered: boolean;
|
|
2310
|
+
};
|
|
2311
|
+
result: Empty;
|
|
2312
|
+
};
|
|
2313
|
+
/** Opens a new tab of the calling view's surface in its tile, after its
|
|
2314
|
+
* tab, with its page on `url` when one is given, and its view starting
|
|
2315
|
+
* from `state` as the state it saved; needs a click. */
|
|
2316
|
+
'hearthscale/web/open-tab': {
|
|
2317
|
+
params: {
|
|
2318
|
+
url?: string;
|
|
2319
|
+
state?: unknown;
|
|
2320
|
+
};
|
|
2321
|
+
result: Empty;
|
|
2322
|
+
};
|
|
2323
|
+
/** Draws the page as a device's screen draws it, or as the slot's own
|
|
2324
|
+
* size with null. */
|
|
2325
|
+
'hearthscale/web/device': {
|
|
2326
|
+
params: {
|
|
2327
|
+
device: WebDevice | null;
|
|
2328
|
+
};
|
|
2329
|
+
result: Empty;
|
|
2330
|
+
};
|
|
2331
|
+
/** The element of the page at a point of the slot, in the view's CSS
|
|
2332
|
+
* pixels from the slot's top left; null where the page shows none. */
|
|
2333
|
+
'hearthscale/web/inspect': {
|
|
2334
|
+
params: {
|
|
2335
|
+
x: number;
|
|
2336
|
+
y: number;
|
|
2337
|
+
};
|
|
2338
|
+
result: {
|
|
2339
|
+
element: WebElement | null;
|
|
2340
|
+
};
|
|
2341
|
+
};
|
|
2342
|
+
/** Clears what the app's pages keep: their cookies and site storage,
|
|
2343
|
+
* and their cached files; needs a click. */
|
|
2344
|
+
'hearthscale/web/clear': {
|
|
2345
|
+
params: {
|
|
2346
|
+
cookies: boolean;
|
|
2347
|
+
cache: boolean;
|
|
2348
|
+
};
|
|
2349
|
+
result: Empty;
|
|
2350
|
+
};
|
|
2351
|
+
/** Whether a download of the app's pages asks where to save it, with
|
|
2352
|
+
* the system's dialog, or goes to the system's downloads folder. */
|
|
2353
|
+
'hearthscale/web/downloads': {
|
|
2354
|
+
params: {
|
|
2355
|
+
ask: boolean;
|
|
2356
|
+
};
|
|
2357
|
+
result: Empty;
|
|
2358
|
+
};
|
|
2359
|
+
/** The origins and accounts the system's keychain keeps passwords of
|
|
2360
|
+
* the app's pages for. No view reads a password: the host fills a
|
|
2361
|
+
* sign-in form of a page with the password of the page's own origin
|
|
2362
|
+
* when the person reaches for one of its fields. */
|
|
2363
|
+
'hearthscale/web/passwords': {
|
|
2364
|
+
params: Empty;
|
|
2365
|
+
result: {
|
|
2366
|
+
logins: WebLogin[];
|
|
2367
|
+
};
|
|
2368
|
+
};
|
|
2369
|
+
/** Keeps a password a page sent in the system's keychain; needs a
|
|
2370
|
+
* click. */
|
|
2371
|
+
'hearthscale/web/password-save': {
|
|
2372
|
+
params: {
|
|
2373
|
+
id: string;
|
|
2374
|
+
};
|
|
2375
|
+
result: Empty;
|
|
2376
|
+
};
|
|
2377
|
+
/** Removes a kept password; needs a click. */
|
|
2378
|
+
'hearthscale/web/password-remove': {
|
|
2379
|
+
params: WebLogin;
|
|
2380
|
+
result: Empty;
|
|
2381
|
+
};
|
|
2382
|
+
/** Keeps the passwords of a passwords export file (a CSV with the
|
|
2383
|
+
* columns url, username and password, as Chrome writes it) that the
|
|
2384
|
+
* person picks with the system's dialog; answers how many, or null
|
|
2385
|
+
* for a cancelled pick. Needs a click. */
|
|
2386
|
+
'hearthscale/web/passwords-import': {
|
|
2387
|
+
params: Empty;
|
|
2388
|
+
result: {
|
|
2389
|
+
count: number | null;
|
|
2390
|
+
};
|
|
2391
|
+
};
|
|
2392
|
+
/** Whether Hearthscale blocks ads in the person's browser's pages; null
|
|
2393
|
+
* for an app that is not the person's browser. */
|
|
2394
|
+
'hearthscale/web/ad-blocking': {
|
|
2395
|
+
params: Empty;
|
|
2396
|
+
result: {
|
|
2397
|
+
enabled: boolean | null;
|
|
2398
|
+
};
|
|
2399
|
+
};
|
|
2400
|
+
/** Turns ad blocking in the person's browser on or off; needs a click. */
|
|
2401
|
+
'hearthscale/web/set-ad-blocking': {
|
|
2402
|
+
params: {
|
|
2403
|
+
enabled: boolean;
|
|
2404
|
+
};
|
|
2405
|
+
result: Empty;
|
|
2406
|
+
};
|
|
2407
|
+
/** Whether the person's browser draws its pages dark; null for an app
|
|
2408
|
+
* that is not the person's browser. */
|
|
2409
|
+
'hearthscale/web/dark-pages': {
|
|
2410
|
+
params: Empty;
|
|
2411
|
+
result: {
|
|
2412
|
+
enabled: boolean | null;
|
|
2413
|
+
};
|
|
2414
|
+
};
|
|
2415
|
+
/** Turns dark pages in the person's browser on or off; needs a click. */
|
|
2416
|
+
'hearthscale/web/set-dark-pages': {
|
|
2417
|
+
params: {
|
|
2418
|
+
enabled: boolean;
|
|
2419
|
+
};
|
|
2420
|
+
result: Empty;
|
|
2421
|
+
};
|
|
2422
|
+
/** Opens a finished download in the system's app for its kind, shows it
|
|
2423
|
+
* in its folder, or cancels one under way; needs a click. */
|
|
2424
|
+
'hearthscale/web/download': {
|
|
2425
|
+
params: {
|
|
2426
|
+
id: string;
|
|
2427
|
+
action: 'open' | 'show' | 'cancel';
|
|
2428
|
+
};
|
|
2429
|
+
result: Empty;
|
|
2430
|
+
};
|
|
2431
|
+
}
|
|
2432
|
+
/** A screen a page is drawn at: its size in CSS pixels, its device pixel
|
|
2433
|
+
* ratio, and whether it is a phone's or a tablet's, which draws the page
|
|
2434
|
+
* with a mobile viewport. */
|
|
2435
|
+
type WebDevice = {
|
|
2436
|
+
width: number;
|
|
2437
|
+
height: number;
|
|
2438
|
+
scale: number;
|
|
2439
|
+
mobile: boolean;
|
|
2440
|
+
};
|
|
2441
|
+
/** An element of a page as the person points at it. */
|
|
2442
|
+
type WebElement = {
|
|
2443
|
+
/** The tag, with its id and classes, as a CSS selector names it. */
|
|
2444
|
+
selector: string;
|
|
2445
|
+
/** Its text, its label, or its address, cut to a line. */
|
|
2446
|
+
text: string;
|
|
2447
|
+
/** Its box in the slot, in the view's CSS pixels. */
|
|
2448
|
+
box: {
|
|
2449
|
+
x: number;
|
|
2450
|
+
y: number;
|
|
2451
|
+
width: number;
|
|
2452
|
+
height: number;
|
|
2453
|
+
};
|
|
2454
|
+
};
|
|
2455
|
+
/** An account a page signs in with: its page's origin and its name. */
|
|
2456
|
+
type WebLogin = {
|
|
2457
|
+
origin: string;
|
|
2458
|
+
username: string;
|
|
2459
|
+
};
|
|
2460
|
+
/** A download of one of the app's pages, as its tab's view hears it. */
|
|
2461
|
+
type WebDownload = {
|
|
2462
|
+
id: string;
|
|
2463
|
+
url: string;
|
|
2464
|
+
/** The file's name as it is saved. */
|
|
2465
|
+
name: string;
|
|
2466
|
+
state: 'progressing' | 'completed' | 'cancelled' | 'interrupted';
|
|
2467
|
+
received: number;
|
|
2468
|
+
/** The size in bytes; 0 while it is unknown. */
|
|
2469
|
+
total: number;
|
|
2470
|
+
};
|
|
2471
|
+
/** The methods gated by `uses`, each with the entry its app must name
|
|
2472
|
+
* before the host answers it. A view acts as its app: what it reads and
|
|
2473
|
+
* changes is its app's own, a terminal line it types goes at its app's
|
|
2474
|
+
* level as one a page types, and the platform's log names the app. An
|
|
2475
|
+
* act that sends the person's words, deletes what cannot come back,
|
|
2476
|
+
* opens something on the person's screen or puts the app in a room runs
|
|
2477
|
+
* only on a click inside the view. */
|
|
2478
|
+
interface ViewExtensionMethods {
|
|
2479
|
+
/** The app's own conversations, newest first; archived ones only when
|
|
2480
|
+
* asked. Without `spawnedBy` the list holds the conversations no helper
|
|
2481
|
+
* call started; with it, the helpers that conversation started. */
|
|
2482
|
+
'hearthscale/sessions/list': {
|
|
2483
|
+
uses: 'sessions';
|
|
2484
|
+
params: {
|
|
2485
|
+
archived?: boolean;
|
|
2486
|
+
spawnedBy?: string;
|
|
2487
|
+
};
|
|
2488
|
+
result: {
|
|
2489
|
+
sessions: Session[];
|
|
2490
|
+
};
|
|
2491
|
+
};
|
|
2492
|
+
/** A new conversation of the app, with `agent` or the app's own agent;
|
|
2493
|
+
* `message`, sent as its first message, needs a click. */
|
|
2494
|
+
'hearthscale/sessions/create': {
|
|
2495
|
+
uses: 'sessions';
|
|
2496
|
+
params: {
|
|
2497
|
+
agent?: string;
|
|
2498
|
+
project?: string;
|
|
2499
|
+
title?: string;
|
|
2500
|
+
message?: string;
|
|
2501
|
+
};
|
|
2502
|
+
result: {
|
|
2503
|
+
session: Session;
|
|
2504
|
+
};
|
|
2505
|
+
};
|
|
2506
|
+
/** Renames a conversation, files it in a project or none, pins,
|
|
2507
|
+
* archives or orders it. */
|
|
2508
|
+
'hearthscale/sessions/update': {
|
|
2509
|
+
uses: 'sessions';
|
|
2510
|
+
params: {
|
|
2511
|
+
id: string;
|
|
2512
|
+
title?: string;
|
|
2513
|
+
project?: string | null;
|
|
2514
|
+
pinned?: boolean;
|
|
2515
|
+
archived?: boolean;
|
|
2516
|
+
rank?: number;
|
|
2517
|
+
};
|
|
2518
|
+
result: {
|
|
2519
|
+
session: Session;
|
|
2520
|
+
};
|
|
2521
|
+
};
|
|
2522
|
+
/** Deletes a conversation and the helpers it started; needs a click. */
|
|
2523
|
+
'hearthscale/sessions/delete': {
|
|
2524
|
+
uses: 'sessions';
|
|
2525
|
+
params: {
|
|
2526
|
+
id: string;
|
|
2527
|
+
};
|
|
2528
|
+
result: Empty;
|
|
2529
|
+
};
|
|
2530
|
+
/** A copy of a conversation from its current leaf, as a new
|
|
2531
|
+
* conversation of the app. */
|
|
2532
|
+
'hearthscale/sessions/fork': {
|
|
2533
|
+
uses: 'sessions';
|
|
2534
|
+
params: {
|
|
2535
|
+
id: string;
|
|
2536
|
+
};
|
|
2537
|
+
result: {
|
|
2538
|
+
session: Session;
|
|
2539
|
+
};
|
|
2540
|
+
};
|
|
2541
|
+
/** Sends the person's words as the conversation's next message; needs
|
|
2542
|
+
* a click. */
|
|
2543
|
+
'hearthscale/sessions/send': {
|
|
2544
|
+
uses: 'sessions';
|
|
2545
|
+
params: {
|
|
2546
|
+
id: string;
|
|
2547
|
+
text: string;
|
|
2548
|
+
};
|
|
2549
|
+
result: Empty;
|
|
2550
|
+
};
|
|
2551
|
+
'hearthscale/sessions/entries': {
|
|
2552
|
+
uses: 'sessions';
|
|
2553
|
+
params: {
|
|
2554
|
+
id: string;
|
|
2555
|
+
};
|
|
2556
|
+
result: {
|
|
2557
|
+
entries: Entry[];
|
|
2558
|
+
};
|
|
2559
|
+
};
|
|
2560
|
+
'hearthscale/sessions/projects/list': {
|
|
2561
|
+
uses: 'sessions';
|
|
2562
|
+
params: Empty;
|
|
2563
|
+
result: {
|
|
2564
|
+
projects: ProjectRecord[];
|
|
2565
|
+
};
|
|
2566
|
+
};
|
|
2567
|
+
'hearthscale/sessions/projects/create': {
|
|
2568
|
+
uses: 'sessions';
|
|
2569
|
+
params: {
|
|
2570
|
+
name: string;
|
|
2571
|
+
};
|
|
2572
|
+
result: {
|
|
2573
|
+
project: ProjectRecord;
|
|
2574
|
+
};
|
|
2575
|
+
};
|
|
2576
|
+
'hearthscale/sessions/projects/update': {
|
|
2577
|
+
uses: 'sessions';
|
|
2578
|
+
params: {
|
|
2579
|
+
id: string;
|
|
2580
|
+
name?: string;
|
|
2581
|
+
instructions?: string;
|
|
2582
|
+
rank?: number;
|
|
2583
|
+
};
|
|
2584
|
+
result: {
|
|
2585
|
+
project: ProjectRecord;
|
|
2586
|
+
};
|
|
2587
|
+
};
|
|
2588
|
+
/** Deletes a project; its conversations stay, filed under none. Needs a
|
|
2589
|
+
* click. */
|
|
2590
|
+
'hearthscale/sessions/projects/delete': {
|
|
2591
|
+
uses: 'sessions';
|
|
2592
|
+
params: {
|
|
2593
|
+
id: string;
|
|
2594
|
+
};
|
|
2595
|
+
result: Empty;
|
|
2596
|
+
};
|
|
2597
|
+
/** The store the app's backend shares; `value` is null for a key that
|
|
2598
|
+
* holds nothing. */
|
|
2599
|
+
'hearthscale/store/get': {
|
|
2600
|
+
uses: 'store';
|
|
2601
|
+
params: {
|
|
2602
|
+
key: string;
|
|
2603
|
+
};
|
|
2604
|
+
result: {
|
|
2605
|
+
value: unknown;
|
|
2606
|
+
};
|
|
2607
|
+
};
|
|
2608
|
+
'hearthscale/store/set': {
|
|
2609
|
+
uses: 'store';
|
|
2610
|
+
params: {
|
|
2611
|
+
key: string;
|
|
2612
|
+
value: unknown;
|
|
2613
|
+
};
|
|
2614
|
+
result: Empty;
|
|
2615
|
+
};
|
|
2616
|
+
'hearthscale/store/delete': {
|
|
2617
|
+
uses: 'store';
|
|
2618
|
+
params: {
|
|
2619
|
+
key: string;
|
|
2620
|
+
};
|
|
2621
|
+
result: Empty;
|
|
2622
|
+
};
|
|
2623
|
+
'hearthscale/roots/list': {
|
|
2624
|
+
uses: 'roots';
|
|
2625
|
+
params: Empty;
|
|
2626
|
+
result: {
|
|
2627
|
+
mounts: Mount[];
|
|
2628
|
+
};
|
|
2629
|
+
};
|
|
2630
|
+
/** Opens the system's picker right after the person's own click or key
|
|
2631
|
+
* press; the pick becomes a grant and a mount. */
|
|
2632
|
+
'hearthscale/roots/request': {
|
|
2633
|
+
uses: 'roots';
|
|
2634
|
+
params: {
|
|
2635
|
+
purpose: string;
|
|
2636
|
+
shape: 'folder' | 'file';
|
|
2637
|
+
mode: 'read' | 'read-write';
|
|
2638
|
+
};
|
|
2639
|
+
result: {
|
|
2640
|
+
mount: Mount | null;
|
|
2641
|
+
};
|
|
2642
|
+
};
|
|
2643
|
+
/** A folder's folders and files by name, hidden ones left out. Every
|
|
2644
|
+
* path of `hearthscale/fs/*` and `hearthscale/vcs/*` is absolute on the
|
|
2645
|
+
* platform's machine and lies inside a folder or file the person gave
|
|
2646
|
+
* the app; one outside, or in a folder that holds credentials, is
|
|
2647
|
+
* refused in words. Each reads and never writes. */
|
|
2648
|
+
'hearthscale/fs/list': {
|
|
2649
|
+
uses: 'roots';
|
|
2650
|
+
params: {
|
|
2651
|
+
path: string;
|
|
2652
|
+
};
|
|
2653
|
+
result: FsListing;
|
|
2654
|
+
};
|
|
2655
|
+
/** A file's size, and its head as text unless it is binary. */
|
|
2656
|
+
'hearthscale/fs/read': {
|
|
2657
|
+
uses: 'roots';
|
|
2658
|
+
params: {
|
|
2659
|
+
path: string;
|
|
2660
|
+
};
|
|
2661
|
+
result: FsRead;
|
|
2662
|
+
};
|
|
2663
|
+
/** A whole file of at most 64 MiB, in base64, with the media type of
|
|
2664
|
+
* its extension. */
|
|
2665
|
+
'hearthscale/fs/raw': {
|
|
2666
|
+
uses: 'roots';
|
|
2667
|
+
params: {
|
|
2668
|
+
path: string;
|
|
2669
|
+
};
|
|
2670
|
+
result: {
|
|
2671
|
+
data: string;
|
|
2672
|
+
mediaType: string;
|
|
2673
|
+
};
|
|
2674
|
+
};
|
|
2675
|
+
/** The system's icon of a file's kind, or of a folder when `folder` is
|
|
2676
|
+
* set, as a PNG `data:` address; null where the system draws none. */
|
|
2677
|
+
'hearthscale/fs/icon': {
|
|
2678
|
+
uses: 'roots';
|
|
2679
|
+
params: {
|
|
2680
|
+
path: string;
|
|
2681
|
+
folder?: boolean;
|
|
2682
|
+
};
|
|
2683
|
+
result: {
|
|
2684
|
+
icon: string | null;
|
|
2685
|
+
};
|
|
2686
|
+
};
|
|
2687
|
+
/** The repository a folder belongs to and its branch, or null where it
|
|
2688
|
+
* belongs to none. A repository that reaches past what the person gave
|
|
2689
|
+
* the app is refused, because `git` reads all of it. */
|
|
2690
|
+
'hearthscale/vcs/repo': {
|
|
2691
|
+
uses: 'roots';
|
|
2692
|
+
params: {
|
|
2693
|
+
path: string;
|
|
2694
|
+
};
|
|
2695
|
+
result: {
|
|
2696
|
+
repo: VcsRepo | null;
|
|
2697
|
+
};
|
|
2698
|
+
};
|
|
2699
|
+
/** The branches a comparison may use, and the one checked out. */
|
|
2700
|
+
'hearthscale/vcs/refs': {
|
|
2701
|
+
uses: 'roots';
|
|
2702
|
+
params: {
|
|
2703
|
+
root: string;
|
|
2704
|
+
};
|
|
2705
|
+
result: VcsRefs;
|
|
2706
|
+
};
|
|
2707
|
+
/** One scope's patch. */
|
|
2708
|
+
'hearthscale/vcs/diff': {
|
|
2709
|
+
uses: 'roots';
|
|
2710
|
+
params: VcsDiffQuery;
|
|
2711
|
+
result: VcsDiff;
|
|
2712
|
+
};
|
|
2713
|
+
/** One file whole, as the scope's new side holds it. */
|
|
2714
|
+
'hearthscale/vcs/file': {
|
|
2715
|
+
uses: 'roots';
|
|
2716
|
+
params: VcsFileQuery;
|
|
2717
|
+
result: VcsFile;
|
|
2718
|
+
};
|
|
2719
|
+
/** One streaming completion on the app's chat card or the chat role;
|
|
2720
|
+
* the frames arrive as `hearthscale/models/delta` with `stream`, and
|
|
2721
|
+
* the call answers once the stream has ended. */
|
|
2722
|
+
'hearthscale/models/complete': {
|
|
2723
|
+
uses: 'models';
|
|
2724
|
+
params: {
|
|
2725
|
+
stream: string;
|
|
2726
|
+
request: CompletionRequest;
|
|
2727
|
+
};
|
|
2728
|
+
result: Empty;
|
|
2729
|
+
};
|
|
2730
|
+
'hearthscale/models/cancel': {
|
|
2731
|
+
uses: 'models';
|
|
2732
|
+
params: {
|
|
2733
|
+
stream: string;
|
|
2734
|
+
};
|
|
2735
|
+
result: Empty;
|
|
2736
|
+
};
|
|
2737
|
+
'hearthscale/jobs/submit': {
|
|
2738
|
+
uses: 'jobs';
|
|
2739
|
+
params: {
|
|
2740
|
+
kind: JobKind;
|
|
2741
|
+
input: JobInput;
|
|
2742
|
+
};
|
|
2743
|
+
result: {
|
|
2744
|
+
job: Job;
|
|
2745
|
+
};
|
|
2746
|
+
};
|
|
2747
|
+
'hearthscale/jobs/get': {
|
|
2748
|
+
uses: 'jobs';
|
|
2749
|
+
params: {
|
|
2750
|
+
id: string;
|
|
2751
|
+
};
|
|
2752
|
+
result: {
|
|
2753
|
+
job: Job;
|
|
2754
|
+
};
|
|
2755
|
+
};
|
|
2756
|
+
'hearthscale/jobs/cancel': {
|
|
2757
|
+
uses: 'jobs';
|
|
2758
|
+
params: {
|
|
2759
|
+
id: string;
|
|
2760
|
+
};
|
|
2761
|
+
result: {
|
|
2762
|
+
job: Job;
|
|
2763
|
+
};
|
|
2764
|
+
};
|
|
2765
|
+
/** Opens the person's own shell in a folder, at the app's level as a
|
|
2766
|
+
* page opens one, or takes up the one this window holds under the same
|
|
2767
|
+
* id; its snapshot and output arrive as `hearthscale/terminals/frame`.
|
|
2768
|
+
* The id is the view's own. Each line the view writes goes at the app's
|
|
2769
|
+
* level before it reaches the shell. */
|
|
2770
|
+
'hearthscale/terminals/open': {
|
|
2771
|
+
uses: 'terminals';
|
|
2772
|
+
params: {
|
|
2773
|
+
id: string;
|
|
2774
|
+
cwd: string;
|
|
2775
|
+
cols: number;
|
|
2776
|
+
rows: number;
|
|
2777
|
+
};
|
|
2778
|
+
result: {
|
|
2779
|
+
terminal: TerminalSnapshot;
|
|
2780
|
+
};
|
|
2781
|
+
};
|
|
2782
|
+
'hearthscale/terminals/write': {
|
|
2783
|
+
uses: 'terminals';
|
|
2784
|
+
params: {
|
|
2785
|
+
id: string;
|
|
2786
|
+
data: string;
|
|
2787
|
+
};
|
|
2788
|
+
result: Empty;
|
|
2789
|
+
};
|
|
2790
|
+
'hearthscale/terminals/resize': {
|
|
2791
|
+
uses: 'terminals';
|
|
2792
|
+
params: {
|
|
2793
|
+
id: string;
|
|
2794
|
+
cols: number;
|
|
2795
|
+
rows: number;
|
|
2796
|
+
};
|
|
2797
|
+
result: Empty;
|
|
2798
|
+
};
|
|
2799
|
+
'hearthscale/terminals/close': {
|
|
2800
|
+
uses: 'terminals';
|
|
2801
|
+
params: {
|
|
2802
|
+
id: string;
|
|
2803
|
+
};
|
|
2804
|
+
result: Empty;
|
|
2805
|
+
};
|
|
2806
|
+
/** Opens a file by its absolute path on the platform's machine in the
|
|
2807
|
+
* surface that opens its extension, else in the system's own app when
|
|
2808
|
+
* the system shows its kind without running it; and shows a folder of
|
|
2809
|
+
* the app's own, one the person gave it, its data folder or a folder of
|
|
2810
|
+
* one of its projects, in the system's file manager. Needs a click. */
|
|
2811
|
+
'openai/files/open': {
|
|
2812
|
+
uses: 'files.open';
|
|
2813
|
+
params: {
|
|
2814
|
+
path: string;
|
|
2815
|
+
};
|
|
2816
|
+
result: Empty;
|
|
2817
|
+
};
|
|
2818
|
+
/** Opens a surface of this app, or of `app`, that its manifest places
|
|
2819
|
+
* in the rail or a tab, beside the view's tile; `session` is a
|
|
2820
|
+
* conversation of that app a chat opens on, `path` the address a view
|
|
2821
|
+
* opens on, as a deep link gives it. With `session` and no `surface`,
|
|
2822
|
+
* the conversation opens in its own app, as a notification's click
|
|
2823
|
+
* opens it; `app`, when given, must be that app. Needs a click. */
|
|
2824
|
+
'hearthscale/surfaces/open': {
|
|
2825
|
+
uses: 'surfaces.open';
|
|
2826
|
+
params: {
|
|
2827
|
+
app?: string;
|
|
2828
|
+
surface?: string;
|
|
2829
|
+
session?: string;
|
|
2830
|
+
path?: string;
|
|
2831
|
+
};
|
|
2832
|
+
result: Empty;
|
|
2833
|
+
};
|
|
2834
|
+
/** The rooms the app is in. */
|
|
2835
|
+
'hearthscale/peers/rooms': {
|
|
2836
|
+
uses: 'peers';
|
|
2837
|
+
params: Empty;
|
|
2838
|
+
result: {
|
|
2839
|
+
rooms: Room[];
|
|
2840
|
+
};
|
|
2841
|
+
};
|
|
2842
|
+
/** Opens a new room of the app, whose ticket the view shows the person
|
|
2843
|
+
* to pass on. Needs a click. */
|
|
2844
|
+
'hearthscale/peers/create': {
|
|
2845
|
+
uses: 'peers';
|
|
2846
|
+
params: Empty;
|
|
2847
|
+
result: {
|
|
2848
|
+
room: Room;
|
|
2849
|
+
};
|
|
2850
|
+
};
|
|
2851
|
+
/** Asks the person for the ticket of a room in a sheet the host draws,
|
|
2852
|
+
* at every level, and joins that room; null when the person cancels.
|
|
2853
|
+
* The view never names the ticket. Needs a click. */
|
|
2854
|
+
'hearthscale/peers/join': {
|
|
2855
|
+
uses: 'peers';
|
|
2856
|
+
params: Empty;
|
|
2857
|
+
result: {
|
|
2858
|
+
room: Room | null;
|
|
2859
|
+
};
|
|
2860
|
+
};
|
|
2861
|
+
/** Sends `data`, at most 64 KiB as JSON, to every other
|
|
2862
|
+
* member of a room of the app; each member's app hears it as
|
|
2863
|
+
* `hearthscale/peers/message`, its views and its backend alike. */
|
|
2864
|
+
'hearthscale/peers/send': {
|
|
2865
|
+
uses: 'peers';
|
|
2866
|
+
params: {
|
|
2867
|
+
room: string;
|
|
2868
|
+
data: unknown;
|
|
2869
|
+
};
|
|
2870
|
+
result: Empty;
|
|
2871
|
+
};
|
|
2872
|
+
/** Takes the app out of a room; a room it opened ends for every member. */
|
|
2873
|
+
'hearthscale/peers/leave': {
|
|
2874
|
+
uses: 'peers';
|
|
2875
|
+
params: {
|
|
2876
|
+
room: string;
|
|
2877
|
+
};
|
|
2878
|
+
result: Empty;
|
|
2879
|
+
};
|
|
2880
|
+
}
|
|
2881
|
+
type ViewExtensionMethod = keyof ViewExtensionMethods;
|
|
2882
|
+
/** The notifications the host sends a view, each only to a view whose app
|
|
2883
|
+
* names the extension in `uses`: a conversation of the app changed or
|
|
2884
|
+
* went, a project of any app changed, the app's backend emitted an
|
|
2885
|
+
* event, a completion or a terminal of the view moved, a job of the app
|
|
2886
|
+
* moved, a room of the app changed, ended or carried a message. */
|
|
2887
|
+
type ViewExtensionNotification = {
|
|
2888
|
+
method: 'hearthscale/sessions/changed';
|
|
2889
|
+
params: {
|
|
2890
|
+
session: string;
|
|
2891
|
+
};
|
|
2892
|
+
} | {
|
|
2893
|
+
method: 'hearthscale/sessions/deleted';
|
|
2894
|
+
params: {
|
|
2895
|
+
id: string;
|
|
2896
|
+
};
|
|
2897
|
+
} | {
|
|
2898
|
+
method: 'hearthscale/sessions/projects/changed';
|
|
2899
|
+
params: Empty;
|
|
2900
|
+
}
|
|
2901
|
+
/** A transient event the app's backend emitted. */
|
|
2902
|
+
| {
|
|
2903
|
+
method: 'hearthscale/events/event';
|
|
2904
|
+
params: {
|
|
2905
|
+
name: string;
|
|
2906
|
+
session?: string;
|
|
2907
|
+
data: unknown;
|
|
2908
|
+
};
|
|
2909
|
+
} | {
|
|
2910
|
+
method: 'hearthscale/models/delta';
|
|
2911
|
+
params: {
|
|
2912
|
+
stream: string;
|
|
2913
|
+
delta: CompletionDelta;
|
|
2914
|
+
};
|
|
2915
|
+
} | {
|
|
2916
|
+
method: 'hearthscale/jobs/progress';
|
|
2917
|
+
params: {
|
|
2918
|
+
job: Job;
|
|
2919
|
+
};
|
|
2920
|
+
} | {
|
|
2921
|
+
method: 'hearthscale/terminals/frame';
|
|
2922
|
+
params: {
|
|
2923
|
+
id: string;
|
|
2924
|
+
frame: TerminalFrame;
|
|
2925
|
+
};
|
|
2926
|
+
}
|
|
2927
|
+
/** The app entered a room, or a member came to it or left it. */
|
|
2928
|
+
| {
|
|
2929
|
+
method: 'hearthscale/peers/changed';
|
|
2930
|
+
params: {
|
|
2931
|
+
room: Room;
|
|
2932
|
+
};
|
|
2933
|
+
}
|
|
2934
|
+
/** The app is out of a room. */
|
|
2935
|
+
| {
|
|
2936
|
+
method: 'hearthscale/peers/ended';
|
|
2937
|
+
params: {
|
|
2938
|
+
room: string;
|
|
2939
|
+
};
|
|
2940
|
+
} | {
|
|
2941
|
+
method: 'hearthscale/peers/message';
|
|
2942
|
+
params: {
|
|
2943
|
+
room: string;
|
|
2944
|
+
from: string;
|
|
2945
|
+
data: unknown;
|
|
2946
|
+
};
|
|
2947
|
+
};
|
|
2948
|
+
|
|
2949
|
+
/**
|
|
2950
|
+
* The types a view imports: the methods every view may call
|
|
2951
|
+
* (`ViewHostMethods`), the `hearthscale/*` extensions and
|
|
2952
|
+
* `openai/files/open`, which it calls through its MCP Apps `App`, each
|
|
2953
|
+
* answered only when its app names the method's entry in `uses`, the
|
|
2954
|
+
* notifications the host sends it, the keys the host adds to the host
|
|
2955
|
+
* context, the `_meta` of the standard messages, and the tool input of a
|
|
2956
|
+
* view that opens a file (`FileInput`). The host lists what
|
|
2957
|
+
* the view may call in `getHostCapabilities().experimental.hearthscale`.
|
|
2958
|
+
*/
|
|
2959
|
+
|
|
2960
|
+
/** One extension call, typed by its method: the request's params in, its
|
|
2961
|
+
* result out. A refusal rejects with the host's words. */
|
|
2962
|
+
type ViewExtensionCall = <M extends ViewExtensionMethod>(method: M, params: ViewExtensionMethods[M]['params']) => Promise<ViewExtensionMethods[M]['result']>;
|
|
2963
|
+
|
|
2964
|
+
/**
|
|
2965
|
+
* `@hearthscale/app`: the types an app's backend and its views import,
|
|
2966
|
+
* and the type of its manifest, `app.json` (`Manifest`). The
|
|
2967
|
+
* running implementation lives in the app host, which serves this import
|
|
2968
|
+
* from itself, so an app bundles nothing of the platform. Everything here
|
|
2969
|
+
* is wire-shaped: every method is asynchronous, every value is JSON, files
|
|
2970
|
+
* are handles inside mounts, and no callable crosses to the core.
|
|
2971
|
+
*/
|
|
2972
|
+
|
|
2973
|
+
/** A relayed TCP or TLS stream. Bytes have no message boundaries; the
|
|
2974
|
+
* protocol on top is the app's. */
|
|
2975
|
+
interface Connection {
|
|
2976
|
+
readonly id: string;
|
|
2977
|
+
readonly state: 'plain' | 'tls';
|
|
2978
|
+
write(bytes: Uint8Array | string): Promise<void>;
|
|
2979
|
+
/** Upgrades the same socket to TLS after the app's protocol exchange. */
|
|
2980
|
+
startTls(): Promise<void>;
|
|
2981
|
+
close(): Promise<void>;
|
|
2982
|
+
on(event: 'data', fn: (bytes: Uint8Array) => void): () => void;
|
|
2983
|
+
on(event: 'end' | 'closed', fn: () => void): () => void;
|
|
2984
|
+
on(event: 'error', fn: (error: {
|
|
2985
|
+
code: string;
|
|
2986
|
+
message: string;
|
|
2987
|
+
}) => void): () => void;
|
|
2988
|
+
}
|
|
2989
|
+
/** A sandboxed run of one program in the app's environment. */
|
|
2990
|
+
interface Run {
|
|
2991
|
+
readonly id: string;
|
|
2992
|
+
wait(): Promise<{
|
|
2993
|
+
exitCode: number;
|
|
2994
|
+
output: string;
|
|
2995
|
+
}>;
|
|
2996
|
+
cancel(): Promise<void>;
|
|
2997
|
+
on(event: 'output', fn: (output: string) => void): () => void;
|
|
2998
|
+
}
|
|
2999
|
+
/** What a backend reaches. A namespace the manifest's `uses` does not
|
|
3000
|
+
* name is absent from this object. */
|
|
3001
|
+
interface AppContext {
|
|
3002
|
+
readonly app: {
|
|
3003
|
+
id: string;
|
|
3004
|
+
version: string;
|
|
3005
|
+
};
|
|
3006
|
+
readonly api: number;
|
|
3007
|
+
/** The folders the host reaches, by handle. */
|
|
3008
|
+
readonly mounts: Mount[];
|
|
3009
|
+
/** Aborts when the host is disposed. */
|
|
3010
|
+
readonly signal: AbortSignal;
|
|
3011
|
+
log(level: 'debug' | 'info' | 'warn' | 'error', message: string): Promise<void>;
|
|
3012
|
+
roots?: {
|
|
3013
|
+
list(): Promise<Mount[]>;
|
|
3014
|
+
/** Raises the folder card; the person's pick becomes a mount, which
|
|
3015
|
+
* the request answers. The host restarts with it once its calls and
|
|
3016
|
+
* folder requests in flight have ended, so the mount works from the
|
|
3017
|
+
* next call; asked outside any call, the answer comes first. */
|
|
3018
|
+
request(purpose: string, shape: 'folder' | 'file'): Promise<Mount | null>;
|
|
3019
|
+
};
|
|
3020
|
+
fs?: {
|
|
3021
|
+
read(path: MountPath, options?: {
|
|
3022
|
+
offset?: number;
|
|
3023
|
+
limit?: number;
|
|
3024
|
+
}): Promise<string>;
|
|
3025
|
+
list(path: MountPath): Promise<{
|
|
3026
|
+
dirs: string[];
|
|
3027
|
+
files: string[];
|
|
3028
|
+
}>;
|
|
3029
|
+
write(path: MountPath, text: string): Promise<void>;
|
|
3030
|
+
edit(path: MountPath, oldText: string, newText: string): Promise<void>;
|
|
3031
|
+
/** Copies an asset's bytes to a path inside a read-write mount. */
|
|
3032
|
+
export(asset: string, path: MountPath): Promise<void>;
|
|
3033
|
+
};
|
|
3034
|
+
assets: {
|
|
3035
|
+
get(id: string, range?: {
|
|
3036
|
+
offset: number;
|
|
3037
|
+
length: number;
|
|
3038
|
+
}): Promise<{
|
|
3039
|
+
bytes: Uint8Array;
|
|
3040
|
+
mediaType: string;
|
|
3041
|
+
}>;
|
|
3042
|
+
put(bytes: Uint8Array | string, mediaType: string, name?: string): Promise<string>;
|
|
3043
|
+
/** Copies a file from a mount into the store, in the core. */
|
|
3044
|
+
import(path: MountPath, mediaType: string): Promise<string>;
|
|
3045
|
+
release(id: string): Promise<void>;
|
|
3046
|
+
};
|
|
3047
|
+
net?: {
|
|
3048
|
+
fetch(params: FetchParams): Promise<FetchAnswer>;
|
|
3049
|
+
connect(host: string, port: number, tls: boolean): Promise<Connection>;
|
|
3050
|
+
};
|
|
3051
|
+
exec?: {
|
|
3052
|
+
run(argv: string[], cwd: MountPath, options?: {
|
|
3053
|
+
wall?: number;
|
|
3054
|
+
}): Promise<Run>;
|
|
3055
|
+
};
|
|
3056
|
+
surface?: {
|
|
3057
|
+
/** A tab command on the session's executor surface, from inside a
|
|
3058
|
+
* body whose tool is declared outbound: on the page of the app's
|
|
3059
|
+
* first surface placed in the rail or a tab, a `web` surface's own
|
|
3060
|
+
* page or the web page of a view's tab; `show` reaches no network and
|
|
3061
|
+
* runs from any body. Rejects with the error the window met. */
|
|
3062
|
+
command(op: SurfaceOp, args?: Record<string, unknown>): Promise<SurfaceAnswer>;
|
|
3063
|
+
};
|
|
3064
|
+
store?: {
|
|
3065
|
+
get(key: string): Promise<unknown>;
|
|
3066
|
+
set(key: string, value: unknown): Promise<void>;
|
|
3067
|
+
delete(key: string): Promise<void>;
|
|
3068
|
+
};
|
|
3069
|
+
secrets?: {
|
|
3070
|
+
get(name: string): Promise<string | null>;
|
|
3071
|
+
set(name: string, value: string): Promise<void>;
|
|
3072
|
+
delete(name: string): Promise<void>;
|
|
3073
|
+
};
|
|
3074
|
+
oauth?: {
|
|
3075
|
+
/** True once a token for the issuer covers the scopes: at once when
|
|
3076
|
+
* one is held, else after the person's sign-in card and the grant;
|
|
3077
|
+
* false when the person or the service said no. Rejects with the
|
|
3078
|
+
* reason when the request, the manifest's `network` or the service
|
|
3079
|
+
* does not allow a sign-in. A sign-in replaces the scopes held, so
|
|
3080
|
+
* each call names every scope the app needs. */
|
|
3081
|
+
login(request: OAuthLogin): Promise<boolean>;
|
|
3082
|
+
/** The access token, refreshed when it is past half its lifetime;
|
|
3083
|
+
* null when the app must sign in again. A token the service revoked
|
|
3084
|
+
* early still comes back: after a 401, `logout` and `login` again. */
|
|
3085
|
+
token(issuer: string): Promise<string | null>;
|
|
3086
|
+
/** Forgets the tokens for the issuer, revoked at the service where
|
|
3087
|
+
* its metadata names a revocation endpoint. Null, or the words when
|
|
3088
|
+
* the service did not confirm the revocation and may still hold the
|
|
3089
|
+
* access. */
|
|
3090
|
+
logout(issuer: string): Promise<string | null>;
|
|
3091
|
+
};
|
|
3092
|
+
events?: {
|
|
3093
|
+
emit(event: AppEvent): Promise<void>;
|
|
3094
|
+
};
|
|
3095
|
+
notify?(notice: AppNotice): Promise<void>;
|
|
3096
|
+
/** Drawn in the conversation at every level, from inside a tool body. */
|
|
3097
|
+
ask(question: AppQuestion): Promise<AppAnswer>;
|
|
3098
|
+
sessions?: {
|
|
3099
|
+
/** This app's sessions and the ones it started in other apps. */
|
|
3100
|
+
list(): Promise<SessionListing[]>;
|
|
3101
|
+
open(id: string): Promise<OpenedSession>;
|
|
3102
|
+
create(body: SessionCreate): Promise<{
|
|
3103
|
+
id: string;
|
|
3104
|
+
}>;
|
|
3105
|
+
send(id: string, text: string): Promise<void>;
|
|
3106
|
+
wait(id: string): Promise<TurnOutcome>;
|
|
3107
|
+
on(event: 'deleted', fn: (id: string) => void): () => void;
|
|
3108
|
+
on(event: 'finished', fn: (result: {
|
|
3109
|
+
session: string;
|
|
3110
|
+
turn: string;
|
|
3111
|
+
stopReason: string;
|
|
3112
|
+
}) => void): () => void;
|
|
3113
|
+
};
|
|
3114
|
+
apps: {
|
|
3115
|
+
/** The enabled apps. */
|
|
3116
|
+
list(): Promise<AppListing[]>;
|
|
3117
|
+
/** Called when the set of enabled apps changed. */
|
|
3118
|
+
on(event: 'changed', fn: () => void): () => void;
|
|
3119
|
+
};
|
|
3120
|
+
/** The settings the manifest declares, which the platform keeps. */
|
|
3121
|
+
settings: {
|
|
3122
|
+
/** Every setting, with the value the person set or its default;
|
|
3123
|
+
* rejects for an app that declares no settings. */
|
|
3124
|
+
get(): Promise<SettingValues>;
|
|
3125
|
+
/** Called with every setting's value when the person changed one. */
|
|
3126
|
+
on(event: 'changed', fn: (values: SettingValues) => void): () => void;
|
|
3127
|
+
};
|
|
3128
|
+
models?: {
|
|
3129
|
+
/** One streaming completion on the card this app runs chat on, or
|
|
3130
|
+
* the chat role; `format` asks for JSON against a schema. A call
|
|
3131
|
+
* inside a tool body counts against the budget of the turn that
|
|
3132
|
+
* made the call. */
|
|
3133
|
+
complete(request: CompletionRequest, signal?: AbortSignal): AsyncIterable<CompletionDelta>;
|
|
3134
|
+
/** The chat cards an app's sessions may run on: this app's, or
|
|
3135
|
+
* another app's under the `sessions.create` grant. */
|
|
3136
|
+
for(app?: string): Promise<ModelListing[]>;
|
|
3137
|
+
/** The card an app runs a kind on, and where the choice came from, or
|
|
3138
|
+
* the reason none can: this app's, or another app's under the
|
|
3139
|
+
* `sessions.create` grant. */
|
|
3140
|
+
effective(kind: ModelKind, app?: string): Promise<EffectiveModel>;
|
|
3141
|
+
};
|
|
3142
|
+
/** With `sessions.create`: the projects of an app this one may start
|
|
3143
|
+
* conversations in. */
|
|
3144
|
+
projects?: {
|
|
3145
|
+
list(app?: string): Promise<ProjectListing[]>;
|
|
3146
|
+
};
|
|
3147
|
+
/** With `catalogue`: the bus. A search reads the catalogue, never
|
|
3148
|
+
* asks, and answers the whole definition of each match; a call runs
|
|
3149
|
+
* another app's offered tool or an attached connector's tool, with this
|
|
3150
|
+
* app as the caller. A call made inside a tool body runs under that
|
|
3151
|
+
* call, in its conversation and at its level, and ends with it; the
|
|
3152
|
+
* signal cancels it earlier. A refused or failed call rejects with the
|
|
3153
|
+
* words. */
|
|
3154
|
+
capabilities?: {
|
|
3155
|
+
search(queries: string | string[], limit?: number): Promise<string>;
|
|
3156
|
+
call(name: string, input?: Record<string, unknown>, options?: {
|
|
3157
|
+
signal?: AbortSignal;
|
|
3158
|
+
}): Promise<CapabilityAnswer>;
|
|
3159
|
+
};
|
|
3160
|
+
/** With `readers`: a reader for a format the manifest declares under
|
|
3161
|
+
* `formats`; the read tool hands it the file's bytes. */
|
|
3162
|
+
readers?: {
|
|
3163
|
+
register(format: string, read: (bytes: Uint8Array, name: string) => Promise<string> | string): () => void;
|
|
3164
|
+
};
|
|
3165
|
+
jobs?: {
|
|
3166
|
+
/** One job on the card this app runs that kind on. */
|
|
3167
|
+
submit(kind: JobKind, input: JobInput): Promise<Job>;
|
|
3168
|
+
get(id: string): Promise<Job>;
|
|
3169
|
+
cancel(id: string): Promise<Job>;
|
|
3170
|
+
on(event: 'progress', fn: (job: Job) => void): () => void;
|
|
3171
|
+
};
|
|
3172
|
+
/** With `peers`: the rooms the app is in. The person opens or joins a
|
|
3173
|
+
* room through a view of the app; a backend sends to the room's other
|
|
3174
|
+
* members, hears their messages, and may leave. While the app is in a
|
|
3175
|
+
* room, an event of it starts the backend when it is not up. */
|
|
3176
|
+
peers?: {
|
|
3177
|
+
list(): Promise<Room[]>;
|
|
3178
|
+
/** Sends `data`, at most 64 KiB as JSON, to every other
|
|
3179
|
+
* member; inside a tool body, the tool is declared outbound. */
|
|
3180
|
+
send(room: string, data: unknown): Promise<void>;
|
|
3181
|
+
leave(room: string): Promise<void>;
|
|
3182
|
+
on(event: 'message', fn: (message: {
|
|
3183
|
+
room: string;
|
|
3184
|
+
from: string;
|
|
3185
|
+
data: unknown;
|
|
3186
|
+
}) => void): () => void;
|
|
3187
|
+
/** The app entered a room, or a member came to it or left it. */
|
|
3188
|
+
on(event: 'changed', fn: (room: Room) => void): () => void;
|
|
3189
|
+
/** The app is out of a room. */
|
|
3190
|
+
on(event: 'ended', fn: (room: string) => void): () => void;
|
|
3191
|
+
};
|
|
3192
|
+
}
|
|
3193
|
+
/** What a tool body runs with. */
|
|
3194
|
+
interface ToolRun {
|
|
3195
|
+
readonly callId: string;
|
|
3196
|
+
readonly context: CallContext;
|
|
3197
|
+
readonly signal: AbortSignal;
|
|
3198
|
+
/** A snapshot of the output so far, drawn under the tool's row. */
|
|
3199
|
+
progress(output: string): void;
|
|
3200
|
+
}
|
|
3201
|
+
/** What a capability call answers: its text, its structured object when
|
|
3202
|
+
* the tool answered one, and the files it answered, which this app
|
|
3203
|
+
* holds until it releases them. */
|
|
3204
|
+
interface CapabilityAnswer {
|
|
3205
|
+
text: string;
|
|
3206
|
+
structured?: Structured;
|
|
3207
|
+
assets: {
|
|
3208
|
+
id: string;
|
|
3209
|
+
mediaType: string;
|
|
3210
|
+
name?: string;
|
|
3211
|
+
}[];
|
|
3212
|
+
}
|
|
3213
|
+
/** A tool body: the input the model sent, checked against the tool's
|
|
3214
|
+
* input schema before the body runs, and the answer: text, content,
|
|
3215
|
+
* content with its structured object and a view, or one structured
|
|
3216
|
+
* object alone. An object whose `content` is an array is read as content
|
|
3217
|
+
* with its structured object, so a structured result that holds such a
|
|
3218
|
+
* field answers `{ content: [], structured }`. A tool that declares
|
|
3219
|
+
* `output` answers a structured object that matches it. */
|
|
3220
|
+
type ToolBody = (input: unknown, run: ToolRun) => Promise<string | Content[] | ToolAnswer | Structured> | string | Content[] | ToolAnswer | Structured;
|
|
3221
|
+
/** What `backend.js` exports. `activate` has five seconds; a body a
|
|
3222
|
+
* manifest tool lacks, or a manifest tool with no body, fails activation
|
|
3223
|
+
* with the name. */
|
|
3224
|
+
interface Backend {
|
|
3225
|
+
activate?(ctx: AppContext): Promise<void> | void;
|
|
3226
|
+
deactivate?(): Promise<void> | void;
|
|
3227
|
+
tools?: Record<string, ToolBody>;
|
|
3228
|
+
}
|
|
3229
|
+
|
|
3230
|
+
export type { AppAnswer, AppContext, AppEvent, AppListing, AppNotice, AppQuestion, Backend, CallContext, CapabilityAnswer, ChatContentPart, ChatMessage, CompletionDelta, CompletionRequest, CompletionStop, Connection, Content, ContentBlockMeta, EffectiveModel, FetchAnswer, FetchParams, FileInput, HearthscaleHostCapability, HostSlot, HostSlotKind, HostSlotNotification, Job, JobInput, JobInputs, JobKind, Manifest, MessageOptions, ModelContextAnswer, ModelKind, ModelListing, ModelSource, Mount, MountPath, OAuthLogin, OpenedSession, Origin, PrincipalRef, ProjectListing, ResourcePath, ResourceReadOptions, ResourceVersion, Room, Run, Sampling, Session, SessionCell, SessionCreate, SessionListing, SessionProcess, SessionRoot, SessionStatus, SettingValues, SlotInsets, StopReason, Structured, SurfaceAnswer, SurfaceOp, SurfaceResult, TerminalFrame, TerminalSnapshot, ToolAnswer, ToolBody, ToolCall, ToolDefinition, ToolRun, TurnOutcome, Usage, ViewExtension, ViewExtensionCall, ViewExtensionMethod, ViewExtensionMethods, ViewExtensionNotification, ViewHostContext, ViewHostMethods, WebPageState };
|