@flowy-agent-store/protocol 0.1.0-beta.3 → 0.1.0-beta.5
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/dist/index.cjs +393 -1
- package/dist/index.d.cts +839 -7
- package/dist/index.d.mts +839 -7
- package/dist/index.mjs +374 -2
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -5,7 +5,59 @@
|
|
|
5
5
|
* The chat surface uses only opaque public conversation/message IDs. Internal
|
|
6
6
|
* execution/session/step/attempt IDs never appear in this module.
|
|
7
7
|
*/
|
|
8
|
-
|
|
8
|
+
/**
|
|
9
|
+
* A contract **fingerprint**, not a version number: it must differ from the
|
|
10
|
+
* previous value on any wire change at all, additive included. The shape is
|
|
11
|
+
* `fp-<n>` — a plain counter, so a bump just increments it and no value is ever
|
|
12
|
+
* reused by accident.
|
|
13
|
+
*
|
|
14
|
+
* So it is a **label, not a version**: neither a release number nor a date.
|
|
15
|
+
* Until `fp-1` the values were date stamps (kept below as history), and those
|
|
16
|
+
* dates were **not** the day of the change: consecutive changes advanced the
|
|
17
|
+
* stamp a day each, so they ran ahead of the calendar. The list below is keyed
|
|
18
|
+
* by *value* — read it as "which wire change is this?", never as "when did this
|
|
19
|
+
* ship".
|
|
20
|
+
*
|
|
21
|
+
* `2026-09-16` carried `StoreItem.published_at`; `2026-09-17` added the two MCP
|
|
22
|
+
* declaration write methods (`config/set-mcp`, `config/set-mcp-enabled`);
|
|
23
|
+
* `2026-09-18` adds `config/get-mcp`, the file editor's read of the same file;
|
|
24
|
+
* `2026-09-19` adds the `conversation/list-changed` notification; `2026-09-20`
|
|
25
|
+
* adds the Skill **file tree** read face (`skill/files`, `skill/file`) so a
|
|
26
|
+
* Skill's companion files are readable, not just its bounded manifest summary;
|
|
27
|
+
* `2026-09-21` adds the connector **call proxy** (`connector/call`), so a third
|
|
28
|
+
* party can run an installed MCP tool while the connection and its credentials
|
|
29
|
+
* stay on the host. **`fp-1` changes the shape only** (date stamp → counter): a
|
|
30
|
+
* `2026-…` value invites being read as a release date, and no wire behaviour
|
|
31
|
+
* changed with the rename. **`fp-2` carries the tools' parameters**
|
|
32
|
+
* (`ConnectorTool.input_schema`, plus `tools_truncated` on `ConnectorDetail`
|
|
33
|
+
* and `ConnectorProbeResult`): a caller that must *name* a tool to be granted it
|
|
34
|
+
* should be able to read what that tool takes. It is the counterpart of the
|
|
35
|
+
* host's `[connector_proxy]` grant moving from one tool at a time to the
|
|
36
|
+
* connector (doc `26`). **`fp-3` makes a Skill selectable per turn**:
|
|
37
|
+
* `conversation/send` gains an optional `mentions` list whose only honoured kind
|
|
38
|
+
* is `skill`, so one turn can mount a Skill's instructions without rewriting the
|
|
39
|
+
* conversation's create-time snapshot (doc `27` 阶段 1). **`fp-4` lets a
|
|
40
|
+
* conversation be created as an installed expert**: `conversation/create` gains
|
|
41
|
+
* an optional `agent_id`, whose Definition supplies the chat's preset identity
|
|
42
|
+
* plus its own Skill and Connector fences — frozen at creation, since none of
|
|
43
|
+
* those keys is mutable afterwards (doc `27` 阶段 2a). **`fp-5` opens a Team's
|
|
44
|
+
* Leader the same way**: an optional `team_id` runs the `team/run` orchestration
|
|
45
|
+
* (members, template, fences) but stops before the goal turn, so the client
|
|
46
|
+
* speaks first; `agent_id` and `team_id` are mutually exclusive (阶段 2b).
|
|
47
|
+
* **`fp-6` makes the model and the reasoning level selectable per call**:
|
|
48
|
+
* `conversation/send` and `agent/run` each gain an optional `model` and
|
|
49
|
+
* `reasoning_effort`. The scope is deliberately the **conversation** (send) and
|
|
50
|
+
* the **run** (agent/run), not "just this turn": the Nomi runtime is built from
|
|
51
|
+
* the persisted row, so a send-carried value is a sticky switch that takes
|
|
52
|
+
* effect on that very turn (doc `29` §4). `ConversationView` also gains
|
|
53
|
+
* `reasoning_effort`, because a setting that can be written by three methods but
|
|
54
|
+
* read back by none is not a setting a client can honour (doc `29` §5.5).
|
|
55
|
+
* **`fp-7` adds the `zip` marketplace source kind**: `market/add` accepts
|
|
56
|
+
* `source_kind: "zip"`, one archive whose root *is* the market root. The
|
|
57
|
+
* official bundles move to it because the old `url` form made a first fetch
|
|
58
|
+
* mirror 14,714 files (611 MiB) for `experts` alone (doc `30`).
|
|
59
|
+
*/
|
|
60
|
+
export declare const APP_SERVER_PROTOCOL_VERSION = "fp-7";
|
|
9
61
|
export interface JsonRpcRequest {
|
|
10
62
|
jsonrpc: "2.0";
|
|
11
63
|
id: number | string;
|
|
@@ -49,7 +101,24 @@ export interface ConversationResyncRequiredNotification {
|
|
|
49
101
|
reason: string;
|
|
50
102
|
};
|
|
51
103
|
}
|
|
52
|
-
|
|
104
|
+
/**
|
|
105
|
+
* 会话**列表**投影变更(`conversation/list-changed`,2026-09-19 加入)。
|
|
106
|
+
*
|
|
107
|
+
* 与 `conversation/event` 是两件事:那些是某条被订阅会话的转写帧、带 `sequence`;
|
|
108
|
+
* 这一条改的是侧栏那一整份列表(自动标题、重命名、删除),所以:
|
|
109
|
+
* - 不要求订阅该会话(用户此刻可能正看着另一个会话);
|
|
110
|
+
* - **不带 `sequence`**,客户端不得据此推进 `lastSeenSequence`;
|
|
111
|
+
* - 尽力而为:丢一条只是让界面晚一步刷新,`conversation/list` 始终是权威。
|
|
112
|
+
*/
|
|
113
|
+
export interface ConversationListChangedNotification {
|
|
114
|
+
jsonrpc: "2.0";
|
|
115
|
+
method: "conversation/list-changed";
|
|
116
|
+
params: {
|
|
117
|
+
conversation_id: string;
|
|
118
|
+
action: "created" | "updated" | "deleted";
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
export type ServerNotification = JsonRpcEventNotification | ResyncRequiredNotification | ConversationEventNotification | ConversationResyncRequiredNotification | ConversationListChangedNotification;
|
|
53
122
|
export interface WireError {
|
|
54
123
|
code: string;
|
|
55
124
|
message: string;
|
|
@@ -96,7 +165,25 @@ export interface Capabilities {
|
|
|
96
165
|
teams: boolean;
|
|
97
166
|
team_runtime: boolean;
|
|
98
167
|
skills: boolean;
|
|
168
|
+
/**
|
|
169
|
+
* The Skill **file tree** read face (`skill/files` / `skill/file`).
|
|
170
|
+
*
|
|
171
|
+
* Separate from `skills` on purpose: a host can wire the catalog without the
|
|
172
|
+
* file provider, so `skills: true` alone does not mean `skill/files` will
|
|
173
|
+
* answer. Check this before offering file access.
|
|
174
|
+
*/
|
|
175
|
+
skill_files: boolean;
|
|
99
176
|
connectors: boolean;
|
|
177
|
+
/**
|
|
178
|
+
* The connector **call proxy** (`connector/call`, doc 24 §5).
|
|
179
|
+
*
|
|
180
|
+
* Separate from `connectors` on purpose: the catalog can be wired without the
|
|
181
|
+
* proxy, and a host may wire the proxy while its `[connector_proxy]` table is
|
|
182
|
+
* absent or disabled, in which case every call answers `policy_denied`. This
|
|
183
|
+
* flag says the *method* exists, not that any tool is callable; the host
|
|
184
|
+
* operator's own config decides that (doc `26` §4).
|
|
185
|
+
*/
|
|
186
|
+
connector_calls: boolean;
|
|
100
187
|
run_notifications: boolean;
|
|
101
188
|
approvals: boolean;
|
|
102
189
|
artifacts: boolean;
|
|
@@ -151,6 +238,22 @@ export interface BrowseDirectoryResult {
|
|
|
151
238
|
truncated: boolean;
|
|
152
239
|
isRoot?: boolean | null;
|
|
153
240
|
}
|
|
241
|
+
/** `POST /api/fs/list` — one flat file entry under a workspace root (host file service). */
|
|
242
|
+
export interface WorkspaceFlatFile {
|
|
243
|
+
name: string;
|
|
244
|
+
full_path: string;
|
|
245
|
+
relative_path: string;
|
|
246
|
+
}
|
|
247
|
+
/** `POST /api/fs/metadata` response (host file service). */
|
|
248
|
+
export interface FileMetadata {
|
|
249
|
+
name: string;
|
|
250
|
+
path: string;
|
|
251
|
+
size: number;
|
|
252
|
+
/** Server-reported MIME type. */
|
|
253
|
+
type: string;
|
|
254
|
+
last_modified: number;
|
|
255
|
+
is_directory?: boolean | null;
|
|
256
|
+
}
|
|
154
257
|
export type RunStatus = "planning" | "running" | "completed" | "completed_with_failures" | "failed" | "cancelled" | "paused" | "waiting_input" | "awaiting_approval" | "recovery_required";
|
|
155
258
|
export type MentionKind = "agent" | "skill" | "connector";
|
|
156
259
|
export interface MentionRef {
|
|
@@ -170,6 +273,13 @@ export interface AgentRunInput {
|
|
|
170
273
|
idempotencyKey?: string;
|
|
171
274
|
/** Structured `@` mentions resolved by the composer (docs/agent-store/05 §4.7). */
|
|
172
275
|
mentions?: MentionRef[];
|
|
276
|
+
/**
|
|
277
|
+
* Run-scoped model (doc `29` §6.1). Wins over the preset's own model **and**
|
|
278
|
+
* over the host default: explicit > preset > `~/.agent-store/config.toml`.
|
|
279
|
+
*/
|
|
280
|
+
model?: ProviderWithModel;
|
|
281
|
+
/** Run-scoped OpenAI-style reasoning effort (doc `29` §6.1); applies to every attempt of the run. */
|
|
282
|
+
reasoningEffort?: ReasoningEffort | string;
|
|
173
283
|
}
|
|
174
284
|
export interface AgentRunRequestWire {
|
|
175
285
|
agent_id: string;
|
|
@@ -182,6 +292,8 @@ export interface AgentRunRequestWire {
|
|
|
182
292
|
command_id?: string;
|
|
183
293
|
idempotency_key?: string;
|
|
184
294
|
mentions?: MentionRef[];
|
|
295
|
+
model?: ProviderWithModel;
|
|
296
|
+
reasoning_effort?: string;
|
|
185
297
|
}
|
|
186
298
|
export interface RunReceipt {
|
|
187
299
|
run_id: string;
|
|
@@ -190,6 +302,44 @@ export interface RunReceipt {
|
|
|
190
302
|
preset_revision: number;
|
|
191
303
|
content_digest: string;
|
|
192
304
|
}
|
|
305
|
+
/**
|
|
306
|
+
* `team/run` — Leader Conversation + planned delegation (docs/agent-store/05
|
|
307
|
+
* §5.2, `16` §7 决策 3).
|
|
308
|
+
*
|
|
309
|
+
* There is deliberately **no** `planning` field: member pool, concurrency
|
|
310
|
+
* ceiling, routing constraints and authority come from the bound Team template
|
|
311
|
+
* and server policy. The wire DTO is `deny_unknown_fields`, so sending one is
|
|
312
|
+
* `invalid_request` rather than a silently ignored parameter.
|
|
313
|
+
*/
|
|
314
|
+
export interface TeamRunInput {
|
|
315
|
+
teamId: string;
|
|
316
|
+
teamVersion?: string;
|
|
317
|
+
goal?: string;
|
|
318
|
+
input?: {
|
|
319
|
+
text?: string;
|
|
320
|
+
} | Record<string, unknown>;
|
|
321
|
+
workspaceId?: string;
|
|
322
|
+
commandId?: string;
|
|
323
|
+
idempotencyKey?: string;
|
|
324
|
+
}
|
|
325
|
+
export interface TeamRunRequestWire {
|
|
326
|
+
team_id: string;
|
|
327
|
+
team_version?: string;
|
|
328
|
+
goal?: string;
|
|
329
|
+
input?: unknown;
|
|
330
|
+
workspace?: WorkspaceRef;
|
|
331
|
+
command_id?: string;
|
|
332
|
+
idempotency_key?: string;
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Deliberately **not** `RunReceipt`: a Team Run has no lead preset to report a
|
|
336
|
+
* revision/digest for — its authority is the Team's mutable execution template.
|
|
337
|
+
* Only what the server can honestly answer is on the wire.
|
|
338
|
+
*/
|
|
339
|
+
export interface TeamRunReceipt {
|
|
340
|
+
run_id: string;
|
|
341
|
+
status: RunStatus;
|
|
342
|
+
}
|
|
193
343
|
export interface RunView {
|
|
194
344
|
run_id: string;
|
|
195
345
|
status: RunStatus;
|
|
@@ -213,11 +363,44 @@ export interface SteerRunInput {
|
|
|
213
363
|
commandId?: string;
|
|
214
364
|
idempotencyKey?: string;
|
|
215
365
|
}
|
|
366
|
+
export type AnswerDecisionInput = {
|
|
367
|
+
runId: string;
|
|
368
|
+
stepId: string;
|
|
369
|
+
attemptId: string;
|
|
370
|
+
answer: string;
|
|
371
|
+
/**
|
|
372
|
+
* The engine's three-way CAS tokens. They are mandatory: an answer that does
|
|
373
|
+
* not name the exact execution/step/attempt version it was written against is
|
|
374
|
+
* refused with a `Conflict` instead of being applied. `run/events` projects
|
|
375
|
+
* the current three onto every pending `approval.requested`, so a client
|
|
376
|
+
* echoes those rather than inventing versions.
|
|
377
|
+
*/
|
|
378
|
+
expectedExecutionVersion: number;
|
|
379
|
+
expectedStepVersion: number;
|
|
380
|
+
expectedAttemptVersion: number;
|
|
381
|
+
};
|
|
382
|
+
/**
|
|
383
|
+
* One projected run event.
|
|
384
|
+
*
|
|
385
|
+
* `step_id` / `attempt_id` are present when the engine scoped the event to an
|
|
386
|
+
* attempt (notably `approval.requested`). A pending decision additionally
|
|
387
|
+
* carries the three CAS versions an accepted answer must echo; they are read
|
|
388
|
+
* from the authoritative rows when the event is projected, so an answer built
|
|
389
|
+
* from them races safely (a concurrent change turns it into a `Conflict`).
|
|
390
|
+
*
|
|
391
|
+
* There is deliberately no `always_allow` counterpart on the wire: answering a
|
|
392
|
+
* decision never widens a tool policy.
|
|
393
|
+
*/
|
|
216
394
|
export interface RunEvent {
|
|
217
395
|
run_id: string;
|
|
218
396
|
sequence: number;
|
|
219
397
|
event_type: string;
|
|
220
398
|
payload: Record<string, unknown>;
|
|
399
|
+
step_id?: string | null;
|
|
400
|
+
attempt_id?: string | null;
|
|
401
|
+
expected_execution_version?: number | null;
|
|
402
|
+
expected_step_version?: number | null;
|
|
403
|
+
expected_attempt_version?: number | null;
|
|
221
404
|
}
|
|
222
405
|
export interface RunEventsQuery {
|
|
223
406
|
runId: string;
|
|
@@ -227,6 +410,53 @@ export interface RunEventsQuery {
|
|
|
227
410
|
export interface RunSubscriptionParams {
|
|
228
411
|
run_id: string;
|
|
229
412
|
}
|
|
413
|
+
/**
|
|
414
|
+
* W4 / W6 (doc 16 R10/R11, resolves D-W6-1): the authoritative plan snapshot.
|
|
415
|
+
*
|
|
416
|
+
* `run/events` is an append-only log of markers — step titles, failure reasons
|
|
417
|
+
* and timings never appear there. This projection reads the engine's own rows,
|
|
418
|
+
* so each step exists once with its current facts. Internal participant ids are
|
|
419
|
+
* deliberately not on the wire: member attribution is `role` + `model`.
|
|
420
|
+
*/
|
|
421
|
+
export interface RunPlan {
|
|
422
|
+
run_id: string;
|
|
423
|
+
status: RunStatus;
|
|
424
|
+
version: number;
|
|
425
|
+
steps: RunPlanStep[];
|
|
426
|
+
dependencies: RunPlanDependency[];
|
|
427
|
+
}
|
|
428
|
+
export interface RunPlanStep {
|
|
429
|
+
step_id: string;
|
|
430
|
+
title: string;
|
|
431
|
+
kind: string;
|
|
432
|
+
status: string;
|
|
433
|
+
role?: string | null;
|
|
434
|
+
model?: string | null;
|
|
435
|
+
introduced_in_revision: number;
|
|
436
|
+
superseded_in_revision?: number | null;
|
|
437
|
+
created_at: number;
|
|
438
|
+
updated_at: number;
|
|
439
|
+
attempts: RunPlanAttempt[];
|
|
440
|
+
}
|
|
441
|
+
export interface RunPlanAttempt {
|
|
442
|
+
attempt_id: string;
|
|
443
|
+
attempt_no: number;
|
|
444
|
+
status: string;
|
|
445
|
+
trigger_reason: string;
|
|
446
|
+
role?: string | null;
|
|
447
|
+
model?: string | null;
|
|
448
|
+
question?: string | null;
|
|
449
|
+
error?: string | null;
|
|
450
|
+
output_summary?: string | null;
|
|
451
|
+
output_files: string[];
|
|
452
|
+
tokens?: number | null;
|
|
453
|
+
started_at?: number | null;
|
|
454
|
+
finished_at?: number | null;
|
|
455
|
+
}
|
|
456
|
+
export interface RunPlanDependency {
|
|
457
|
+
blocker_step_id: string;
|
|
458
|
+
blocked_step_id: string;
|
|
459
|
+
}
|
|
230
460
|
export interface ProviderWithModel {
|
|
231
461
|
provider_id: string;
|
|
232
462
|
model: string;
|
|
@@ -237,6 +467,8 @@ export interface ConversationCreateInput {
|
|
|
237
467
|
model?: ProviderWithModel;
|
|
238
468
|
workspaceId?: string;
|
|
239
469
|
reasoningEffort?: string;
|
|
470
|
+
agentId?: string;
|
|
471
|
+
teamId?: string;
|
|
240
472
|
}
|
|
241
473
|
export interface ConversationUpdateInput {
|
|
242
474
|
name?: string;
|
|
@@ -248,6 +480,15 @@ export interface ConversationModelOption {
|
|
|
248
480
|
name: string;
|
|
249
481
|
display_name?: string | null;
|
|
250
482
|
context_limit?: number | null;
|
|
483
|
+
/**
|
|
484
|
+
* models.dev catalog facts (W9 / R14). All of them are **absent** when the
|
|
485
|
+
* registry has no entry for this provider+model (an unmapped platform, e.g.
|
|
486
|
+
* the bundled `mimo`, never gets zeros standing in for "unknown").
|
|
487
|
+
*/
|
|
488
|
+
cost_input?: number | null;
|
|
489
|
+
cost_output?: number | null;
|
|
490
|
+
catalog_context_window?: number | null;
|
|
491
|
+
supports_vision?: boolean | null;
|
|
251
492
|
}
|
|
252
493
|
export interface ProviderModelOption {
|
|
253
494
|
name: string;
|
|
@@ -266,6 +507,12 @@ export interface ConversationView {
|
|
|
266
507
|
conversation_id: string;
|
|
267
508
|
name: string;
|
|
268
509
|
model: ProviderWithModel;
|
|
510
|
+
/**
|
|
511
|
+
* The conversation's current reasoning effort (doc `29` §5.5). Absent = not
|
|
512
|
+
* specified. `create` / `update` / `send` can all write it, so the view has to
|
|
513
|
+
* say what it is — otherwise the setting is write-only.
|
|
514
|
+
*/
|
|
515
|
+
reasoning_effort?: string | null;
|
|
269
516
|
status: string;
|
|
270
517
|
created_at: number;
|
|
271
518
|
modified_at: number;
|
|
@@ -280,9 +527,33 @@ export interface ContextUsage {
|
|
|
280
527
|
used_tokens: number;
|
|
281
528
|
window_tokens: number;
|
|
282
529
|
percent?: number | null;
|
|
530
|
+
/**
|
|
531
|
+
* W9 / R14 ③: the runtime's own per-turn report for the **most recent**
|
|
532
|
+
* completed turn, persisted server-side next to the gauge so a reloaded
|
|
533
|
+
* WebUI can still show last turn's tokens (and catalog-priced cost). Both are
|
|
534
|
+
* absent when the runtime reported nothing — never a `0` standing in for
|
|
535
|
+
* "unknown". They are not occupancy: `used_tokens` is the last request's
|
|
536
|
+
* prompt size and must never be substituted for these.
|
|
537
|
+
*/
|
|
538
|
+
last_turn_input_tokens?: number | null;
|
|
539
|
+
last_turn_output_tokens?: number | null;
|
|
283
540
|
updated_at: number;
|
|
284
541
|
source: "measured" | string;
|
|
285
542
|
}
|
|
543
|
+
/**
|
|
544
|
+
* Per-turn token accounting for ONE completed turn (W9 / R14, additive).
|
|
545
|
+
*
|
|
546
|
+
* The runtime's own report (`TurnCompleted`), projected onto the conversation
|
|
547
|
+
* event stream — field names mirror the Run-side `TurnUsage` so one vocabulary
|
|
548
|
+
* covers both surfaces. It is **not** context occupancy: `ContextUsage` is a
|
|
549
|
+
* gauge (the last request's prompt size) and cannot express what one turn
|
|
550
|
+
* cost. Absent whenever the runtime reported nothing (never a zero).
|
|
551
|
+
*/
|
|
552
|
+
export interface TurnUsage {
|
|
553
|
+
input_tokens: number;
|
|
554
|
+
output_tokens: number;
|
|
555
|
+
total_tokens: number;
|
|
556
|
+
}
|
|
286
557
|
export interface ConversationDeleteResult {
|
|
287
558
|
conversation_id: string;
|
|
288
559
|
deleted: boolean;
|
|
@@ -310,10 +581,20 @@ export interface ConversationSendReceipt {
|
|
|
310
581
|
result_error_code?: string | null;
|
|
311
582
|
result_error_retryable?: boolean | null;
|
|
312
583
|
}
|
|
584
|
+
/**
|
|
585
|
+
* The closed set of conversation event kinds the server emits (`05` §4).
|
|
586
|
+
*
|
|
587
|
+
* Deliberately **not** widened with `| string` (doc `16` R1): the escape made
|
|
588
|
+
* the union collapse to `string`, so exhaustive switches and type guards were
|
|
589
|
+
* impossible. A newer server kind reaches a client as a runtime value the
|
|
590
|
+
* switch does not match — which is handled by falling through — and widening
|
|
591
|
+
* this union is the deliberate, reviewable act that changes the contract.
|
|
592
|
+
*/
|
|
593
|
+
export type ConversationEventType = "message.created" | "message.delta" | "message.thinking" | "message.tips" | "message.tool" | "message.error" | "message.activity" | "turn.status" | "context.usage";
|
|
313
594
|
export interface ConversationEvent {
|
|
314
595
|
conversation_id: string;
|
|
315
596
|
sequence: number;
|
|
316
|
-
event_type:
|
|
597
|
+
event_type: ConversationEventType;
|
|
317
598
|
payload: Record<string, unknown>;
|
|
318
599
|
}
|
|
319
600
|
export interface ConversationMessagesQuery {
|
|
@@ -337,16 +618,253 @@ export interface SkillSummary {
|
|
|
337
618
|
description?: string | null;
|
|
338
619
|
version: string;
|
|
339
620
|
source: string;
|
|
621
|
+
/**
|
|
622
|
+
* Finer on-disk owner than `source` (`16` R17 / W12): `user` | `shared` |
|
|
623
|
+
* `companion` | `draft` | `marketplace` | `builtin` | `unmanaged`.
|
|
624
|
+
*
|
|
625
|
+
* `source` alone cannot separate a user skill from an installed marketplace
|
|
626
|
+
* product — both are `custom`.
|
|
627
|
+
*
|
|
628
|
+
* Optional so a client compiled against this package keeps working against a
|
|
629
|
+
* host that predates the field; treat a missing value as "unknown owner".
|
|
630
|
+
*/
|
|
631
|
+
origin?: SkillOrigin;
|
|
632
|
+
/**
|
|
633
|
+
* Whether the store's write face accepts `skill/update` / `skill/delete` for
|
|
634
|
+
* this skill — `origin === "user"` and the directory is the canonical one.
|
|
635
|
+
* Absent means unknown, so a UI must not offer a write action on `!== true`.
|
|
636
|
+
*/
|
|
637
|
+
writable?: boolean;
|
|
340
638
|
compatibility_status: CompatibilityStatus;
|
|
341
639
|
enabled: boolean;
|
|
342
640
|
required_connectors: string[];
|
|
641
|
+
/**
|
|
642
|
+
* Marketplace icon URL for a product installed from a marketplace
|
|
643
|
+
* (`/api/app-server/store/{mkt}/entries/{entry}/assets/…`). Absent for
|
|
644
|
+
* builtin / user skills and for markets that ship no icon for the entry.
|
|
645
|
+
*/
|
|
646
|
+
avatar_url?: string | null;
|
|
343
647
|
}
|
|
648
|
+
/** Where a skill lives on the host (`SkillSummary.origin`). */
|
|
649
|
+
export type SkillOrigin = "user" | "shared" | "companion" | "draft" | "marketplace" | "builtin" | "unmanaged";
|
|
344
650
|
/** `skill/get` — the raw SKILL.md body and internal routing rules are never returned. */
|
|
345
651
|
export interface SkillDetail extends SkillSummary {
|
|
346
652
|
mode: string;
|
|
347
653
|
invocation_policy: string;
|
|
348
654
|
instructions_summary?: string | null;
|
|
349
655
|
}
|
|
656
|
+
/**
|
|
657
|
+
* One file inside a Skill directory (`skill/files`, doc 24 §4).
|
|
658
|
+
*
|
|
659
|
+
* A Skill is a *directory*, not a single document: `SKILL.md` plus whatever it
|
|
660
|
+
* ships alongside (`references/`, `scripts/`, `templates/`, `assets/`).
|
|
661
|
+
* `SkillDetail.instructions_summary` is a bounded summary of the manifest, so
|
|
662
|
+
* this is the read face for everything else.
|
|
663
|
+
*/
|
|
664
|
+
export interface SkillFile {
|
|
665
|
+
/** Path relative to the skill directory, POSIX-separated. */
|
|
666
|
+
path: string;
|
|
667
|
+
size: number;
|
|
668
|
+
/** Single-file sha256, lowercase hex. */
|
|
669
|
+
digest: string;
|
|
670
|
+
}
|
|
671
|
+
/** `skill/files` response: the readable inventory of one Skill. */
|
|
672
|
+
export interface SkillFileList {
|
|
673
|
+
skill_id: string;
|
|
674
|
+
/** Sorted by `path`; directories are not listed. */
|
|
675
|
+
files: SkillFile[];
|
|
676
|
+
/**
|
|
677
|
+
* Tree digest of **this skill directory** (sorted relative paths + per-file
|
|
678
|
+
* sha256).
|
|
679
|
+
*
|
|
680
|
+
* Deliberately **not** the snapshot's `content_digest`, which covers the
|
|
681
|
+
* whole imported source tree — the two coincide only when the snapshot holds
|
|
682
|
+
* exactly this directory. Do not compare it against `import/get`.
|
|
683
|
+
*/
|
|
684
|
+
content_digest: string;
|
|
685
|
+
/** The inventory hit its ceiling and is incomplete. Never silently truncated. */
|
|
686
|
+
truncated: boolean;
|
|
687
|
+
}
|
|
688
|
+
/**
|
|
689
|
+
* `skill/file` over the WebSocket binding: base64, because JSON has no byte
|
|
690
|
+
* string. The HTTP binding returns the raw body with a `content-type` header
|
|
691
|
+
* instead, so prefer `skills.readFile()` (HTTP) for bytes and this shape only
|
|
692
|
+
* when you are already on a socket.
|
|
693
|
+
*/
|
|
694
|
+
export interface SkillFileContent {
|
|
695
|
+
skill_id: string;
|
|
696
|
+
path: string;
|
|
697
|
+
content_type: string;
|
|
698
|
+
encoding: "base64";
|
|
699
|
+
content: string;
|
|
700
|
+
}
|
|
701
|
+
/**
|
|
702
|
+
* Request/response shapes for the six **host-management** methods:
|
|
703
|
+
* `config/get` · `config/set` · `skill/create` · `skill/update` ·
|
|
704
|
+
* `skill/delete` · `skill/copy`.
|
|
705
|
+
*
|
|
706
|
+
* They live here because this package is the wire contract's single source of
|
|
707
|
+
* truth: a method that exists on the wire has a shape, and a caller that speaks
|
|
708
|
+
* the protocol must be able to type-check it whether or not the curated
|
|
709
|
+
* `@flowy-agent-store/client` surface offers a typed method for it. Declaring
|
|
710
|
+
* them only in the host app made that claim false.
|
|
711
|
+
*
|
|
712
|
+
* **Not a stability promise.** These are the most volatile methods in the
|
|
713
|
+
* protocol — they track the host's own settings file and its skills directory,
|
|
714
|
+
* and are the ones most likely to change without notice during beta
|
|
715
|
+
* (`16` D10=A: no backward-compatibility promise before release). The client
|
|
716
|
+
* package deliberately ships no typed method for them; call them through
|
|
717
|
+
* `transport.request` if you need them, and expect churn. What is *not* the
|
|
718
|
+
* reason is access control: `transport` is public and the server enforces
|
|
719
|
+
* writability from the on-disk origin, so this is a discoverability boundary,
|
|
720
|
+
* not a security one.
|
|
721
|
+
*/
|
|
722
|
+
/**
|
|
723
|
+
* `config/get` / `config/set` view of the host's `~/.agent-store/config.toml`.
|
|
724
|
+
*
|
|
725
|
+
* Never carries a credential: the file's `[providers.<name>]` tables hold
|
|
726
|
+
* `api_key` or `base_url`, so a credential cannot reach the front end through
|
|
727
|
+
* this face.
|
|
728
|
+
*/
|
|
729
|
+
export interface AgentStoreConfigView {
|
|
730
|
+
/** The file exists on this host; a save creates it when it does not. */
|
|
731
|
+
exists: boolean;
|
|
732
|
+
/** Declared `default_model`; explicit `null` = none declared in the file. */
|
|
733
|
+
default_model: string | null;
|
|
734
|
+
/** `[providers.<name>]` tables as declared in the file. */
|
|
735
|
+
providers: AgentStoreConfigProvider[];
|
|
736
|
+
/**
|
|
737
|
+
* `[memory]` table; `null` when the file declares no such table (so the UI
|
|
738
|
+
* can say "not configured" instead of inventing "off"). Additive field.
|
|
739
|
+
*/
|
|
740
|
+
memory: AgentStoreConfigMemory | null;
|
|
741
|
+
/**
|
|
742
|
+
* `~/.agent-store/mcp.json` as the host read it (`20` §7.9 / `21` D14);
|
|
743
|
+
* `null` when there is no readable declaration file. Additive field, and the
|
|
744
|
+
* **only** read surface for a declared server: declarations never become
|
|
745
|
+
* `mcp_servers` rows, so they do not appear in `connector/*`.
|
|
746
|
+
*/
|
|
747
|
+
mcp: AgentStoreConfigMcp | null;
|
|
748
|
+
}
|
|
749
|
+
/** One `mcpServers` entry the host accepted. */
|
|
750
|
+
export interface AgentStoreConfigMcpServer {
|
|
751
|
+
/** The `mcpServers` key — the `<server>` segment of `mcp__<server>__*`. */
|
|
752
|
+
name: string;
|
|
753
|
+
/** `stdio` | `http` | `sse` (already a label, not a discriminant to branch on). */
|
|
754
|
+
transport: string;
|
|
755
|
+
/** `enabled = false` keeps the entry declared but out of every session. */
|
|
756
|
+
enabled: boolean;
|
|
757
|
+
}
|
|
758
|
+
/** One `mcpServers` entry the host refused, and why. */
|
|
759
|
+
export interface AgentStoreConfigMcpRejection {
|
|
760
|
+
name: string;
|
|
761
|
+
/**
|
|
762
|
+
* The parser's own reason ("a field on the wrong transport", "an out-of-range
|
|
763
|
+
* timeout", …). Server-authored prose, not an i18n key.
|
|
764
|
+
*/
|
|
765
|
+
reason: string;
|
|
766
|
+
}
|
|
767
|
+
/**
|
|
768
|
+
* The `mcp.json` projection. A refusal is reported rather than silently
|
|
769
|
+
* dropped: an ignored `enabledTools` would leave tools the user believes
|
|
770
|
+
* excluded still callable, which is why this half has to be visible.
|
|
771
|
+
*/
|
|
772
|
+
export interface AgentStoreConfigMcp {
|
|
773
|
+
/**
|
|
774
|
+
* The declaration file is present. The host only sends this view after it has
|
|
775
|
+
* read the file, so this is `true` whenever `mcp` is not `null`; it is kept
|
|
776
|
+
* because the wire carries it, not because a branch should read it.
|
|
777
|
+
*/
|
|
778
|
+
exists: boolean;
|
|
779
|
+
/**
|
|
780
|
+
* Whether **this host** feeds the file into agent sessions, as the launcher
|
|
781
|
+
* reported at startup. Omitted when the host did not say — `undefined` is
|
|
782
|
+
* "cannot tell", which is not the same answer as `false` ("this host does not
|
|
783
|
+
* read the file"). `servers` describes the file; this describes the host.
|
|
784
|
+
*/
|
|
785
|
+
adopted?: boolean;
|
|
786
|
+
/** Accepted entries, ordered by server key. Never a credential value. */
|
|
787
|
+
servers: AgentStoreConfigMcpServer[];
|
|
788
|
+
/** Refused entries, with the reason the user has to fix. */
|
|
789
|
+
rejected: AgentStoreConfigMcpRejection[];
|
|
790
|
+
/**
|
|
791
|
+
* Why the **whole file** could not be read as declarations (invalid JSON,
|
|
792
|
+
* wrong top level). Omitted when the file parsed — without it a broken file
|
|
793
|
+
* and an empty one look the same.
|
|
794
|
+
*/
|
|
795
|
+
error?: string;
|
|
796
|
+
}
|
|
797
|
+
/**
|
|
798
|
+
* `config/get-mcp`: the declaration file's own text, for the file editor.
|
|
799
|
+
*
|
|
800
|
+
* The only read that returns a declaration's values, and the reason it is a
|
|
801
|
+
* method of its own: `AgentStoreConfigMcp` describes the file's *verdict* and
|
|
802
|
+
* carries no `env` / `headers` value, while an editor cannot edit what it
|
|
803
|
+
* cannot see. `exists: false` (with `source` absent) is the normal answer for a
|
|
804
|
+
* host that never created the file; the text comes back whether or not it
|
|
805
|
+
* parses, because editing a broken file is the point.
|
|
806
|
+
*/
|
|
807
|
+
export interface McpSourceView {
|
|
808
|
+
exists: boolean;
|
|
809
|
+
source?: string | null;
|
|
810
|
+
}
|
|
811
|
+
/** `[memory]` in the host settings file, as far as the wire exposes it. */
|
|
812
|
+
export interface AgentStoreConfigMemory {
|
|
813
|
+
/** `null` = the table exists without the key (upstream default applies). */
|
|
814
|
+
distill_enabled: boolean | null;
|
|
815
|
+
}
|
|
816
|
+
/** One provider table from the file (never a registered-provider row). */
|
|
817
|
+
export interface AgentStoreConfigProvider {
|
|
818
|
+
/** `[providers.<name>]` key — the left half of a `default_model`. */
|
|
819
|
+
name: string;
|
|
820
|
+
/** `enabled = false` in the file; `true` when the key is absent. */
|
|
821
|
+
enabled: boolean;
|
|
822
|
+
/** Model names declared for this provider in the file. */
|
|
823
|
+
models: string[];
|
|
824
|
+
}
|
|
825
|
+
/** The only keys `config/set` accepts (the server rejects anything else). */
|
|
826
|
+
export interface AgentStoreConfigPatch {
|
|
827
|
+
default_model?: string;
|
|
828
|
+
/** Writes `[memory] distill_enabled` — the switch the host reads at startup. */
|
|
829
|
+
memory?: {
|
|
830
|
+
distill_enabled: boolean;
|
|
831
|
+
};
|
|
832
|
+
}
|
|
833
|
+
/** `skill/create` — structured fields; the server assembles the frontmatter. */
|
|
834
|
+
export interface SkillCreateInput {
|
|
835
|
+
/** Becomes the skill's public id and its directory name. */
|
|
836
|
+
name: string;
|
|
837
|
+
description: string;
|
|
838
|
+
when_to_use?: string;
|
|
839
|
+
allowed_tools?: string;
|
|
840
|
+
paths?: string;
|
|
841
|
+
body?: string;
|
|
842
|
+
}
|
|
843
|
+
/**
|
|
844
|
+
* `skill/update` — a field-level patch.
|
|
845
|
+
*
|
|
846
|
+
* An absent field is left alone (`undefined`, not empty string). An **empty
|
|
847
|
+
* string** on one of the optional keys clears that key; `description` may not
|
|
848
|
+
* be emptied (`invalid_request`). There is deliberately no `name`.
|
|
849
|
+
*/
|
|
850
|
+
export interface SkillUpdateInput {
|
|
851
|
+
skill_id: string;
|
|
852
|
+
description?: string;
|
|
853
|
+
when_to_use?: string;
|
|
854
|
+
allowed_tools?: string;
|
|
855
|
+
paths?: string;
|
|
856
|
+
/** Replaces the body wholesale — the read face never returned it, so an edit
|
|
857
|
+
* can only ever *replace* prose, not append to what it never saw. */
|
|
858
|
+
body?: string;
|
|
859
|
+
}
|
|
860
|
+
/** `skill/delete` — what the id resolves to after the delete. */
|
|
861
|
+
export interface SkillDeleteResult {
|
|
862
|
+
skill_id: string;
|
|
863
|
+
deleted: boolean;
|
|
864
|
+
/** Present when the id now resolves to another origin (e.g. a built-in the
|
|
865
|
+
* user skill was shadowing); absent when nothing is visible there any more. */
|
|
866
|
+
revealed_origin?: SkillOrigin | null;
|
|
867
|
+
}
|
|
350
868
|
export type ConnectorStatus = "installed" | "configured" | "authorization_required" | "authenticated" | "connected" | "degraded" | "error" | "reauthorization_required";
|
|
351
869
|
export interface ConnectorSummary {
|
|
352
870
|
id: string;
|
|
@@ -357,10 +875,23 @@ export interface ConnectorSummary {
|
|
|
357
875
|
auth_mode: string;
|
|
358
876
|
enabled: boolean;
|
|
359
877
|
status: ConnectorStatus;
|
|
878
|
+
/**
|
|
879
|
+
* Marketplace icon URL for a connector installed from a marketplace.
|
|
880
|
+
* Absent for builtin hosts and for markets that ship no icon for the entry.
|
|
881
|
+
*/
|
|
882
|
+
avatar_url?: string | null;
|
|
360
883
|
}
|
|
361
884
|
export interface ConnectorTool {
|
|
362
885
|
name: string;
|
|
363
886
|
description?: string | null;
|
|
887
|
+
/**
|
|
888
|
+
* The upstream `tools/list` `inputSchema`, **verbatim** (doc `26` §5).
|
|
889
|
+
*
|
|
890
|
+
* Absent when the server published none, or when it was omitted to stay
|
|
891
|
+
* inside the host's tools budget — see `tools_truncated` on the response. It
|
|
892
|
+
* carries no transport, header or env value: only the tool's own parameters.
|
|
893
|
+
*/
|
|
894
|
+
input_schema?: unknown;
|
|
364
895
|
}
|
|
365
896
|
export interface OAuthStatusView {
|
|
366
897
|
state: "authenticated" | "not_authenticated" | "reauthorization_required" | string;
|
|
@@ -370,6 +901,12 @@ export interface OAuthStatusView {
|
|
|
370
901
|
export interface ConnectorDetail extends ConnectorSummary {
|
|
371
902
|
tool_filter?: string | null;
|
|
372
903
|
tools: ConnectorTool[];
|
|
904
|
+
/**
|
|
905
|
+
* Some `input_schema` values were omitted to stay inside the host's tools
|
|
906
|
+
* budget. Names and descriptions are always kept, and a schema is only ever
|
|
907
|
+
* carried whole — never truncated. `false` also means "nothing was omitted".
|
|
908
|
+
*/
|
|
909
|
+
tools_truncated: boolean;
|
|
373
910
|
auth_status?: OAuthStatusView | null;
|
|
374
911
|
source: string;
|
|
375
912
|
compatibility_status: CompatibilityStatus;
|
|
@@ -384,6 +921,8 @@ export interface ConnectorProbeResult {
|
|
|
384
921
|
connector_id: string;
|
|
385
922
|
success: boolean;
|
|
386
923
|
tools?: ConnectorTool[] | null;
|
|
924
|
+
/** Same rule as `ConnectorDetail.tools_truncated`: an honest omission. */
|
|
925
|
+
tools_truncated: boolean;
|
|
387
926
|
error?: string | null;
|
|
388
927
|
code?: string | null;
|
|
389
928
|
}
|
|
@@ -392,6 +931,28 @@ export interface OAuthStartResult {
|
|
|
392
931
|
state: "started" | "error" | string;
|
|
393
932
|
error?: string | null;
|
|
394
933
|
}
|
|
934
|
+
/**
|
|
935
|
+
* `connector/call` (doc 24 §5.2): the result of running one MCP tool on the
|
|
936
|
+
* host's connection.
|
|
937
|
+
*
|
|
938
|
+
* **A tool-level failure is a result, not a rejection.** When the server
|
|
939
|
+
* answers `isError: true` the promise still resolves, with `is_error` set; only
|
|
940
|
+
* transport, protocol and budget failures reject. Branch on `is_error` to tell
|
|
941
|
+
* "the tool said no" from "we never reached the tool".
|
|
942
|
+
*/
|
|
943
|
+
export interface ConnectorCallResult {
|
|
944
|
+
/** The upstream `isError` flag (`false` when the server omitted it). */
|
|
945
|
+
is_error: boolean;
|
|
946
|
+
/**
|
|
947
|
+
* The upstream `tools/call` result object, **verbatim** — `content`,
|
|
948
|
+
* `structuredContent` and anything a newer server adds all survive.
|
|
949
|
+
*
|
|
950
|
+
* It carries no transport, header or env value: the connection and its
|
|
951
|
+
* credentials stay on the host. That is the whole point of a proxy — there is
|
|
952
|
+
* deliberately no `connector/export`.
|
|
953
|
+
*/
|
|
954
|
+
result: unknown;
|
|
955
|
+
}
|
|
395
956
|
export interface ConnectorQueryParams {
|
|
396
957
|
connector_id: string;
|
|
397
958
|
}
|
|
@@ -472,17 +1033,46 @@ export interface InstallResult {
|
|
|
472
1033
|
skipped: string[];
|
|
473
1034
|
warnings: string[];
|
|
474
1035
|
errors: string[];
|
|
1036
|
+
/** Per-component outcome. Absent on a host that predates the field — read a
|
|
1037
|
+
* missing value as "no detail available", never as "nothing ran". */
|
|
1038
|
+
outcomes?: InstallOutcome[];
|
|
475
1039
|
}
|
|
476
1040
|
export interface InstallStatus {
|
|
477
1041
|
snapshot_id: string;
|
|
478
1042
|
components: InstallComponent[];
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
1043
|
+
/** Per-component outcome of the mutation that produced this projection
|
|
1044
|
+
* (`install/uninstall` · `install/disable` · `install/enable`). Empty for a
|
|
1045
|
+
* plain `install/status` read. */
|
|
1046
|
+
outcomes?: InstallOutcome[];
|
|
1047
|
+
/** Human-readable failures; mirrors the `ok: false` outcomes. */
|
|
1048
|
+
errors?: string[];
|
|
1049
|
+
}
|
|
1050
|
+
/** What happened to one component during install / uninstall / enable / disable. */
|
|
1051
|
+
export type InstallOutcomeAction = "created" | "reused" | "enabled" | "disabled" |
|
|
1052
|
+
/** The flag moved but the runtime did not: the documented `skill` case, since
|
|
1053
|
+
* the skill corpus has no enable state (docs `05` §4.5). */
|
|
1054
|
+
"marked" | "removed" | "skipped" | "failed";
|
|
1055
|
+
export interface InstallOutcome {
|
|
1056
|
+
component_id: string;
|
|
1057
|
+
kind: string;
|
|
1058
|
+
action: InstallOutcomeAction;
|
|
1059
|
+
/** `false` only when the requested state was **not** reached. A component
|
|
1060
|
+
* that was already in the requested state reports `ok: true`. */
|
|
1061
|
+
ok: boolean;
|
|
1062
|
+
/**
|
|
1063
|
+
* Stable, documented token to branch on (`docs/agent-store/05` §4.5 lists the
|
|
1064
|
+
* closed set). `message` is for humans and nothing parses it — the field
|
|
1065
|
+
* exists so callers never have to match on prose.
|
|
1066
|
+
*/
|
|
1067
|
+
code?: string;
|
|
1068
|
+
message?: string;
|
|
1069
|
+
}
|
|
1070
|
+
/** Wire-marketplace source kinds (Phase A: directory only; `zip` since `fp-7`). */
|
|
1071
|
+
export type MarketplaceSourceKind = "directory" | "github" | "git" | "url" | "zip";
|
|
482
1072
|
export interface MarketplaceAddRequest {
|
|
483
1073
|
name?: string;
|
|
484
1074
|
source_kind: MarketplaceSourceKind;
|
|
485
|
-
/** Local directory path / owner/repo / Git URL / HTTP URL. */
|
|
1075
|
+
/** Local directory path / owner/repo / Git URL / HTTP URL / archive URL. */
|
|
486
1076
|
source: string;
|
|
487
1077
|
}
|
|
488
1078
|
export interface MarketplaceSummary {
|
|
@@ -495,6 +1085,26 @@ export interface MarketplaceSummary {
|
|
|
495
1085
|
enabled: boolean;
|
|
496
1086
|
entry_count: number;
|
|
497
1087
|
added_at: number;
|
|
1088
|
+
/** Last resolved source revision (git commit / freshness marker). */
|
|
1089
|
+
resolved_revision?: string | null;
|
|
1090
|
+
/** Last successful freshness check (epoch ms); absent before the first one. */
|
|
1091
|
+
last_checked_at?: number | null;
|
|
1092
|
+
}
|
|
1093
|
+
/**
|
|
1094
|
+
* Snapshot produced by importing this entry, plus how much of it is installed.
|
|
1095
|
+
* Projected server-side on `market/get` (doc 16 D-W13-1 ①) so a client never
|
|
1096
|
+
* has to re-derive "what would a cascade removal take out?" from the store
|
|
1097
|
+
* listing.
|
|
1098
|
+
*/
|
|
1099
|
+
export interface MarketplaceEntrySnapshot {
|
|
1100
|
+
snapshot_id: string;
|
|
1101
|
+
name: string;
|
|
1102
|
+
version: string;
|
|
1103
|
+
status: string;
|
|
1104
|
+
component_count: number;
|
|
1105
|
+
/** Components installed from this snapshot; `0` = imported but untouched. */
|
|
1106
|
+
installed_count: number;
|
|
1107
|
+
imported_at: number;
|
|
498
1108
|
}
|
|
499
1109
|
export interface MarketplaceEntry {
|
|
500
1110
|
name: string;
|
|
@@ -504,6 +1114,25 @@ export interface MarketplaceEntry {
|
|
|
504
1114
|
description?: string | null;
|
|
505
1115
|
keywords: string[];
|
|
506
1116
|
category?: string | null;
|
|
1117
|
+
/**
|
|
1118
|
+
* Localized `<field>_<lang>` variants carried verbatim by the market
|
|
1119
|
+
* manifest (`description_zh`, `name_en`, `tags_zh`, `legacy_tags_en`, …).
|
|
1120
|
+
* Resolve with `pickEntryText` / `pickEntryTags` (doc 18 §4, D8=A);
|
|
1121
|
+
* absent when the manifest declared none.
|
|
1122
|
+
*/
|
|
1123
|
+
localized?: Record<string, string | string[]> | null;
|
|
1124
|
+
/**
|
|
1125
|
+
* The entry's declared `strict` (doc `02` §8): `true` requires the plugin
|
|
1126
|
+
* source to carry its own `.codebuddy-plugin/plugin.json`. Absent = `false`.
|
|
1127
|
+
*/
|
|
1128
|
+
strict?: boolean | null;
|
|
1129
|
+
/**
|
|
1130
|
+
* Why this entry cannot be imported (doc `02` §11.1), when discovery can
|
|
1131
|
+
* already tell. Present = listed for transparency, but not installable.
|
|
1132
|
+
*/
|
|
1133
|
+
blocked_reason?: string | null;
|
|
1134
|
+
/** Absent until the entry has been imported from this marketplace. */
|
|
1135
|
+
snapshot?: MarketplaceEntrySnapshot | null;
|
|
507
1136
|
}
|
|
508
1137
|
export interface MarketplaceDetail extends MarketplaceSummary {
|
|
509
1138
|
entries: MarketplaceEntry[];
|
|
@@ -542,6 +1171,15 @@ export interface StoreItem {
|
|
|
542
1171
|
* Treat as optional: `item.tags ?? []`. */
|
|
543
1172
|
tags?: LocalizedText[] | null;
|
|
544
1173
|
quick_prompts?: LocalizedText[] | null;
|
|
1174
|
+
/**
|
|
1175
|
+
* The market entry's own `publishedAt`, `YYYY-MM-DD` (`18` §3).
|
|
1176
|
+
*
|
|
1177
|
+
* A calendar date the *market* declared, never a derived one: absent means
|
|
1178
|
+
* "this market declares no date", so a client must not substitute the import
|
|
1179
|
+
* time or render a placeholder. The host normalizes it on the way in and
|
|
1180
|
+
* drops anything that is not a calendar date.
|
|
1181
|
+
*/
|
|
1182
|
+
published_at?: string | null;
|
|
545
1183
|
/** Public avatar URL (store asset endpoint); relative to the API host. */
|
|
546
1184
|
avatar_url?: string | null;
|
|
547
1185
|
version: string;
|
|
@@ -550,9 +1188,18 @@ export interface StoreItem {
|
|
|
550
1188
|
update_available: boolean;
|
|
551
1189
|
snapshot_id?: string | null;
|
|
552
1190
|
installed_version?: string | null;
|
|
1191
|
+
/**
|
|
1192
|
+
* Why this item cannot be installed (doc `02` §11.1), re-derived from the
|
|
1193
|
+
* live source tree. Present = the item stays listed so the reason can be
|
|
1194
|
+
* read, but install must not be offered.
|
|
1195
|
+
*/
|
|
1196
|
+
blocked_reason?: string | null;
|
|
553
1197
|
}
|
|
554
1198
|
export interface StoreList {
|
|
555
1199
|
items: StoreItem[];
|
|
1200
|
+
/** `true` while the builtin default marketplaces are still registering in the
|
|
1201
|
+
* background (D-SDK-1 ①) — the catalog may be incomplete. */
|
|
1202
|
+
markets_pending?: boolean;
|
|
556
1203
|
}
|
|
557
1204
|
/** One model in the public catalog (`models/list`, REQ-PAR-05b). Provider
|
|
558
1205
|
* credentials, base URLs and health internals never cross this projection. */
|
|
@@ -579,6 +1226,10 @@ export interface StoreInstallResult {
|
|
|
579
1226
|
installed_count: number;
|
|
580
1227
|
warnings: string[];
|
|
581
1228
|
errors: string[];
|
|
1229
|
+
/** Per-component outcome, forwarded from the installer's own report so a
|
|
1230
|
+
* store install is as branchable as a direct `install/run`. Absent on a host
|
|
1231
|
+
* that predates the field. */
|
|
1232
|
+
outcomes?: InstallOutcome[];
|
|
582
1233
|
}
|
|
583
1234
|
export interface LocalizedText {
|
|
584
1235
|
en?: string | null;
|
|
@@ -633,6 +1284,12 @@ export interface TeamDetail extends TeamSummary {
|
|
|
633
1284
|
routing_constraints: string[];
|
|
634
1285
|
workflow_limits: Record<string, unknown>;
|
|
635
1286
|
team_runtime_capabilities: string[];
|
|
1287
|
+
/**
|
|
1288
|
+
* MCP server ids this Team's own snapshot installed **and** left enabled on
|
|
1289
|
+
* this host — the only Connector surface a Team Run may bind. Member Agents'
|
|
1290
|
+
* `mcpServers` are recorded, not mapped to grants (docs/agent-store/02 §5.1).
|
|
1291
|
+
*/
|
|
1292
|
+
connectors: string[];
|
|
636
1293
|
}
|
|
637
1294
|
//#endregion
|
|
638
1295
|
//#region src/errors.d.ts
|
|
@@ -678,4 +1335,179 @@ export declare function formatError(error: unknown): string;
|
|
|
678
1335
|
/** Whether the caught error is retryable — used by UI surfaces to append a
|
|
679
1336
|
* localized "(可重试)" hint without baking wording into this lib. */
|
|
680
1337
|
export declare function isRetryableError(error: unknown): boolean;
|
|
1338
|
+
//#endregion
|
|
1339
|
+
//#region src/localized.d.ts
|
|
1340
|
+
/** The two languages the store ships display text for. */
|
|
1341
|
+
export type LocalizedLang = "zh" | "en";
|
|
1342
|
+
/** The other language, i.e. the second link of every fallback chain. */
|
|
1343
|
+
export declare function otherLocalizedLang(lang: LocalizedLang): LocalizedLang;
|
|
1344
|
+
/**
|
|
1345
|
+
* Map an i18n language tag (`zh-CN`, `en-US`, `en`) to a variant language.
|
|
1346
|
+
* Anything that is not English resolves to `zh`, matching the app default.
|
|
1347
|
+
*/
|
|
1348
|
+
export declare function toLocalizedLang(language: string | null | undefined): LocalizedLang;
|
|
1349
|
+
/** `{field}_{lang}` → `{field}_{other}` → `""`. */
|
|
1350
|
+
export declare function pickLocalized(text: LocalizedText | null | undefined, lang: LocalizedLang): string;
|
|
1351
|
+
/** Resolve a list of localized values, dropping the ones that resolve empty. */
|
|
1352
|
+
export declare function pickLocalizedList(list: readonly (LocalizedText | null | undefined)[] | null | undefined, lang: LocalizedLang): string[];
|
|
1353
|
+
/**
|
|
1354
|
+
* The `<field>_<lang>` variants of one `market/get` entry.
|
|
1355
|
+
*
|
|
1356
|
+
* Values are either a string (`description_zh`) or a list of strings
|
|
1357
|
+
* (`tags_en`, `legacy_tags_zh`, `examples_zh`).
|
|
1358
|
+
*/
|
|
1359
|
+
export type LocalizedVariants = Readonly<Record<string, string | readonly string[] | null | undefined>> | null | undefined;
|
|
1360
|
+
/** `{field}_{lang}` → `{field}_{other}` as a string, when either carries text. */
|
|
1361
|
+
export declare function pickVariantText(variants: LocalizedVariants, field: string, lang: LocalizedLang): string | undefined;
|
|
1362
|
+
/** `{field}_{lang}` → `{field}_{other}` as a string list, when either is non-empty. */
|
|
1363
|
+
export declare function pickVariantList(variants: LocalizedVariants, field: string, lang: LocalizedLang): string[] | undefined;
|
|
1364
|
+
/**
|
|
1365
|
+
* Market entry tags. Per D8=A `tags_{lang}` outranks `legacy_tags_{lang}` —
|
|
1366
|
+
* the legacy field only fills in when the current one is absent, in either
|
|
1367
|
+
* language.
|
|
1368
|
+
*/
|
|
1369
|
+
export declare function pickEntryTags(variants: LocalizedVariants, lang: LocalizedLang): string[] | undefined;
|
|
1370
|
+
/**
|
|
1371
|
+
* A market entry text field: variant first, then the baseline field
|
|
1372
|
+
* (`entry.description`, `entry.name`, …) as the last link of the chain.
|
|
1373
|
+
*/
|
|
1374
|
+
export declare function pickEntryText(variants: LocalizedVariants, field: string, lang: LocalizedLang, baseline?: string | null): string | undefined;
|
|
1375
|
+
//#endregion
|
|
1376
|
+
//#region src/conversation-events.d.ts
|
|
1377
|
+
export type ThinkingData = {
|
|
1378
|
+
content: string;
|
|
1379
|
+
subject: string | null;
|
|
1380
|
+
status: string | null;
|
|
1381
|
+
duration: number | null;
|
|
1382
|
+
};
|
|
1383
|
+
export type TipsData = {
|
|
1384
|
+
content: string;
|
|
1385
|
+
tipType: string;
|
|
1386
|
+
};
|
|
1387
|
+
export type ToolCallData = {
|
|
1388
|
+
name: string | null;
|
|
1389
|
+
args?: unknown;
|
|
1390
|
+
output?: unknown;
|
|
1391
|
+
status: string | null;
|
|
1392
|
+
};
|
|
1393
|
+
/**
|
|
1394
|
+
* One plan step's status.
|
|
1395
|
+
*
|
|
1396
|
+
* The producer declares exactly these three (`nomi-tools/src/update_plan.rs`
|
|
1397
|
+
* `StepStatus`), and its doc comment names the frontend as the reason for the
|
|
1398
|
+
* snake_case spelling — so this mirrors a stated contract rather than guessing
|
|
1399
|
+
* at a vocabulary.
|
|
1400
|
+
*/
|
|
1401
|
+
export type PlanStepStatus = "pending" | "in_progress" | "completed";
|
|
1402
|
+
export type PlanEntry = {
|
|
1403
|
+
content: string;
|
|
1404
|
+
status: PlanStepStatus;
|
|
1405
|
+
};
|
|
1406
|
+
/** Shape a plan body (`message_type` `plan`): the step list. */
|
|
1407
|
+
export type PlanData = {
|
|
1408
|
+
entries: PlanEntry[];
|
|
1409
|
+
};
|
|
1410
|
+
export declare function stringValue(value: unknown): string | null;
|
|
1411
|
+
export declare function numberValue(value: unknown): number | null;
|
|
1412
|
+
export declare function isRecord(value: unknown): value is Record<string, unknown>;
|
|
1413
|
+
/**
|
|
1414
|
+
* Strict boolean reader: a wire value that is not a real boolean reads as
|
|
1415
|
+
* `null` (unknown) rather than being coerced — "retryable" must never be
|
|
1416
|
+
* guessed from a truthy string.
|
|
1417
|
+
*/
|
|
1418
|
+
export declare function booleanValue(value: unknown): boolean | null;
|
|
1419
|
+
/** Flatten a message/activity body to plain text, JSON-encoding anything else. */
|
|
1420
|
+
export declare function contentToText(value: unknown): string;
|
|
1421
|
+
/** Shape a thinking body (`message.thinking`, or `message.activity` kind `thinking`). */
|
|
1422
|
+
export declare function thinkingData(value: unknown): ThinkingData;
|
|
1423
|
+
/** Shape a tips body; `type` is accepted as an alias of `tip_type`. */
|
|
1424
|
+
export declare function tipsData(value: unknown): TipsData;
|
|
1425
|
+
/** Shape a tool-call body; `null` when the body carries nothing tool-shaped. */
|
|
1426
|
+
export declare function toolCallData(value: unknown): ToolCallData | null;
|
|
1427
|
+
/**
|
|
1428
|
+
* Shape a plan body; `null` when there is no usable step list.
|
|
1429
|
+
*
|
|
1430
|
+
* `step` is accepted as an alias of `content`: the tool's own argument is named
|
|
1431
|
+
* `step`, and the producer normalizes it to `content` for the plan row — a row
|
|
1432
|
+
* written before that normalization (or by a producer that skipped it) would
|
|
1433
|
+
* otherwise render as an empty plan.
|
|
1434
|
+
*/
|
|
1435
|
+
export declare function planData(value: unknown): PlanData | null;
|
|
1436
|
+
/** Shape a `context.usage` payload; `null` when nothing was actually measured. */
|
|
1437
|
+
export declare function parseContextUsage(value: unknown): ContextUsage | null;
|
|
1438
|
+
/**
|
|
1439
|
+
* Shape a per-turn `usage` body (W9 / R14); `null` when the runtime reported
|
|
1440
|
+
* nothing usable.
|
|
1441
|
+
*
|
|
1442
|
+
* A missing side is **unknown**, not zero: half a bill is not a bill, so a
|
|
1443
|
+
* frame that only carries `input_tokens` decodes to `null` rather than to a
|
|
1444
|
+
* total that silently drops the output side. Same rule for an all-zero report —
|
|
1445
|
+
* "no tokens reported" must never render as "this turn was free".
|
|
1446
|
+
*/
|
|
1447
|
+
export declare function parseTurnUsage(value: unknown): TurnUsage | null;
|
|
1448
|
+
/**
|
|
1449
|
+
* One decoded conversation event, discriminated by `kind`.
|
|
1450
|
+
*
|
|
1451
|
+
* `messageId` is the id the *server* supplied (`null` when it sent none) — a
|
|
1452
|
+
* consumer that needs a stable row for an id-less event applies its own
|
|
1453
|
+
* default, because that default is presentation, not protocol.
|
|
1454
|
+
*
|
|
1455
|
+
* `unknown` is the honest fall-through for a newer server kind: the raw
|
|
1456
|
+
* `eventType` is preserved so a caller can log or forward it instead of
|
|
1457
|
+
* silently dropping the frame.
|
|
1458
|
+
*/
|
|
1459
|
+
type MessageFrameBase = {
|
|
1460
|
+
event: ConversationEvent;
|
|
1461
|
+
/** The id the server supplied; `null` when it sent none (consumer picks a default row). */
|
|
1462
|
+
messageId: string | null;
|
|
1463
|
+
/** Server timestamp when the payload carried one. */
|
|
1464
|
+
createdAt: number | null;
|
|
1465
|
+
};
|
|
1466
|
+
export type DecodedConversationEvent = ({
|
|
1467
|
+
kind: "message.created";
|
|
1468
|
+
content: unknown;
|
|
1469
|
+
} & MessageFrameBase) | ({
|
|
1470
|
+
kind: "message.delta";
|
|
1471
|
+
delta: string;
|
|
1472
|
+
replace: boolean;
|
|
1473
|
+
} & MessageFrameBase) | ({
|
|
1474
|
+
kind: "message.thinking";
|
|
1475
|
+
thinking: ThinkingData;
|
|
1476
|
+
replace: boolean;
|
|
1477
|
+
} & MessageFrameBase) | ({
|
|
1478
|
+
kind: "message.tool";
|
|
1479
|
+
tool: ToolCallData | null;
|
|
1480
|
+
} & MessageFrameBase) | ({
|
|
1481
|
+
kind: "message.tips";
|
|
1482
|
+
tips: TipsData;
|
|
1483
|
+
} & MessageFrameBase) | ({
|
|
1484
|
+
kind: "message.error";
|
|
1485
|
+
message: string | null;
|
|
1486
|
+
code: string | null;
|
|
1487
|
+
retryable: boolean | null;
|
|
1488
|
+
} & MessageFrameBase) | ({
|
|
1489
|
+
kind: "message.activity";
|
|
1490
|
+
activityKind: string;
|
|
1491
|
+
content: unknown;
|
|
1492
|
+
usage: TurnUsage | null;
|
|
1493
|
+
} & MessageFrameBase) | {
|
|
1494
|
+
kind: "turn.status";
|
|
1495
|
+
event: ConversationEvent;
|
|
1496
|
+
running: boolean;
|
|
1497
|
+
} | {
|
|
1498
|
+
kind: "context.usage";
|
|
1499
|
+
event: ConversationEvent;
|
|
1500
|
+
usage: ContextUsage | null;
|
|
1501
|
+
} | {
|
|
1502
|
+
kind: "unknown";
|
|
1503
|
+
event: ConversationEvent;
|
|
1504
|
+
eventType: string;
|
|
1505
|
+
};
|
|
1506
|
+
/**
|
|
1507
|
+
* Decode one `conversation/event` frame into a typed body.
|
|
1508
|
+
*
|
|
1509
|
+
* An activity frame whose `kind` is `thinking` is normalized to
|
|
1510
|
+
* `message.thinking` (the server has two spellings for the same thing).
|
|
1511
|
+
*/
|
|
1512
|
+
export declare function decodeConversationEvent(event: ConversationEvent): DecodedConversationEvent;
|
|
681
1513
|
//#endregion
|