Repository navigation
Expand file tree
/
Copy pathapi-openapi.json
More file actions
10241 lines (10241 loc) · 477 KB
/
Copy pathapi-openapi.json
File metadata and controls
10241 lines (10241 loc) · 477 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
{
"openapi": "3.1.0",
"info": {
"title": "vinga-server configuration API",
"description": "The domain half of one vinga-server deployment's configuration: providers, MCP servers, agents, devices, and the credentials they use. Every request carries a bearer token, whose value is the environment variable `server.api.secret_env` names.\n\nA read of one entity is a write of it. The `entity` half of the envelope an addressed read answers is resubmittable as it stands: a PUT replaces the model-shaped half and never the credentials stored beside it, so an edit is read it, change it, send the whole of it back, and the fields a read leaves out are the ones that mean absence and mean the same absence on the way back. An environment reference reads back as itself and resubmits as itself. A value shown as the mask, `********`, resubmits as keep the stored value, which is substituted before the fragment is validated; that mask written where nothing is stored is refused, naming the field where the field is one this API declares. An unchanged stored secret needs no action at all: the envelope's `secrets` mapping is informational, and rotating a credential is the secret PUT, which is the one door a plaintext value enters by. Everything else a read answers is display-only, and named here so the writable category has a stated boundary: that `secrets` mapping; the identity keys of every listing, which address the target URL rather than belonging in a body; both halves of the whole-configuration read, which has no PUT of its own; the pending-device listing, which is the running server's state; and everything under `/runtime`, `/sessions` and `/conversations`, which is not stored configuration at all. The writable shapes are that one `entity` and the three bodies this document describes as arguments rather than as entities: a device's `agents`, the default agent's `name`, and a credential's `secret`.\n\nA write is stored, and when it reaches a running server depends on the kind. What a server is serving of this half is a generation: an immutable snapshot, validated whole, built entirely before anything binds it. There is more than one over the life of a process, and applying a change installs the next one rather than editing the one in place, so a conversation goes on speaking the world it opened in and new work binds the world that is current. The one part of a deployment's configuration that is genuinely read once is the server section, which is this process's own file: the port, the directories, the limits. Nothing this API writes is in it.\n\nSo a write converges at one of two boundaries here, and sometimes at both. Device bindings are read as a device asks for them, so binding or unbinding a device applies at that device's next OTA check or connection with nothing asked of the server, and the default agent is read by the next claim that names no agent; that exception ends where the agent does, since a binding naming an agent this server is not serving resolves to nothing until the reload that installs it, which is what such a write's acknowledgement says. Everything else, which is the whole of the rest of this half, is applied by `POST /runtime/config/reload`, without a restart and without dropping a conversation. Every write says which boundaries it is waiting at, in `applies`, a set of the closed tokens the comparison read publishes: `check-in` for the two kinds a device is answered as it asks, `reload` for the whole of the rest of this half, `restart` for the server section this API does not write, and `store-boot` for a write to a server serving a configuration it was handed rather than one it read from a store, which nothing it is running reads. A set rather than a token because a binding naming an agent this server is not serving yet is waiting at two of them at once, and it carries both. That is the half to branch on. The `notice` beside it says the same thing as a sentence, for a reader rather than for a program, and it names no command: which command crosses a boundary is a fact of a client's grammar, and this server neither ships nor versions the client that will read this.\n\nA device with no binding of its own is answered at its configuration check with a six-digit activation code, which it shows on its screen and speaks, whether or not a default agent is set: an unbound device only pairs. `/devices/pending` lists the devices showing one, keyed by the code, and posting to `/devices/pending/{code}` binds the device showing it, to the agents the body names or else to the default agent, which is vinga, the built-in agent, when none is set. That listing is the running server's own state rather than stored configuration: a restart forgets it, and the devices come back with fresh codes.\n\nThe `/runtime` namespace is the running server's own state as well, and is kept apart from the entity namespaces because an entity may legally be named after any word a route might want. `/runtime/mcp-servers` says what each configured MCP server is doing right now: connected or down, since when, what it published, and which agents may reach it. Nothing there is read from the database, so it cannot disagree with what is running.\n\n`GET /runtime/info` is the read that says which deployment is answering: the version and the revision of the build that is running, whether the short onboarding path is served, and, when it is, the URL to type into a device's captive portal with the provenance of the origin in it. That URL is the one credential this API answers to a read: its last segment is a key derived from the device-auth secret and it stands in front of the token issuer, which is why the startup banner prints the origin without it. What protects it is the gate every request here passes and nothing else is asked to: the bearer token already grants every secret write this API serves, so a read of the URL widens nothing it does not hold. The response carries `Cache-Control: no-store` so that no cache between the two ends retains it, which is the same reason the whole API belongs on a loopback connection or behind TLS. With onboarding off the URL and its provenance are null: devices are configured at the path `server.ota_path` names, and that segment is this deployment's secret rather than a substitute the read could offer instead.\n\n`POST /runtime/invites` is an action in that namespace, and it answers a credential. It issues an invite link, a page a browser opens to join this deployment as a device bound before its first word to the agents the request body names, or to the default agent when it names none: `page` is the page's path with a single-use token in its fragment, and `origin` is the configured `server.public_url` when that opens a secure context in a browser and null otherwise. The token is held in the running server's memory for `lifetime_s` seconds or until a restart, together with the agents it binds, is spent by the first browser that opens the link, and travels in a fragment so that opening the link puts it in no access log; the response carries `Cache-Control: no-store` for the reason the identity read does. No link is issued while device onboarding is off, while the server serves a configuration no store describes, while a named agent is not one this deployment has or not one this server is serving, while this server is not serving the default agent (vinga, the built-in agent, when none is set) for an invite that names none, or while as many links are waiting as the server holds.\n\n`GET /runtime/agents/{name}/prompt` is the other read there: the system prompt a session opening now as that agent would be sent, block by block, with the provenance and the character count of each and the total. It is assembled from the loaded agents, the running MCP slice and the memory store rather than from the database, so it cannot disagree with what a session would get, and it is a preview of a new session rather than a readback of a running one: a conversation already in progress holds the half it assembled at its own activation.\n\n`GET /runtime/config/diff` is the third read there, and the one that spans both sides: what the database holds that this server is not serving, kind by kind, as the entity names added, removed and changed, each kind carrying the boundary its changes converge at. `reload` is what the apply below puts in place, which is every kind of this half; `check-in` is the device bindings and the default agent, which a device is answered as it asks and which are therefore never pending, so they carry the label alone and no lists. `restart` is declared and unused here, for the server section this API does not write. An agent entry converges at three different moments inside the one reload, so their kind carries three entries of its own beside its own lists: `grants`, `prompt` and `filler`, each labelled `reload`, and each a breakdown of `changed` rather than an exception to it. Changed means the stored state differs from the comparison baseline rather than that something was written: an edit changed back before anyone looked produces no diff, and a rewritten stored secret counts as different, because what is compared is an opaque mark over the ciphertext and it moves even when the plaintext may not have. Entity names and those labels are the whole of the answer: no bodies, no values and no marks cross it. The MCP half is compared against the entries running now rather than the ones this process booted with, so a change a reload has already applied is not reported as pending. What an answer does not say is that applying what it lists would succeed: it compares configuration and connects nothing, while the reload below goes on to build a server for every entry an agent references and can still refuse on one of those.\n\n`GET /runtime/events` is the fourth, and the only one that does not end: the structured events as this server emits them, streamed as Server-Sent Events. One `data:` line per event, carrying the catalogued fields of that event plus two the stream owns: `ts`, the wall-clock instant it was emitted at, and `level`, its level's name. Those are the fields the retained JSON log carries too, under the same names; the log's own record-keeping beside them, the channel and the rendered sentence, is not repeated here. It is live and nothing but: there is no buffer behind it and no `since`, so a reader that reconnects rejoins the present and reads what happened before from the conversation store, where a deployment enabled one. Three query filters narrow it, applied as the events arrive: `device`, a MAC in either separator and any case; `session`, a session's uuid hex; and `level`, a threshold over the four level names in any case, which defaults to `INFO` because that is what the retained log carries. An event naming no device or no session passes such a filter only when none is set. A reader that falls behind loses its oldest events rather than slowing the server down and is told so by a `dropped` event carrying how many went; an idle stream sends a comment line so a proxy does not close it; and the stream ends when the client goes away or when the server shuts down. Nothing that is not on the events is on it, which is the whole of what makes a live view of a conversation safe to open: what was said is in the conversation store, and these are metadata.\n\n`POST /runtime/config/reload` is the action in that namespace that applies configuration, and unlike device bindings it is asked for rather than noticed. It re-reads the stored configuration and applies the whole domain half: the `providers` entries and the `mcp_servers` entries with the secrets stored on them, the agents' `mcp` grant lists, the shared prompt fragments, the agents themselves and the `agent_defaults` layer under them. Entries are started, restarted, stopped or left alone, and no conversation is dropped. Nothing is swapped, stopped or started until the whole new world has been composed, validated and built, so a refusal has changed nothing at all. When a live conversation meets the result depends on which half moved. The tools it may reach are snapshotted per reply, so a started, restarted or stopped entry is picked up on its next utterance. Prompt text is assembled at an activation and cached for it, so an agent's prompt, a fragment it includes and an entry's `instructions` alike reach a conversation at its next activation, which is a new session or an agent switch, and never a reply of one already running; `GET /runtime/agents/{name}/prompt` previews what a session opening now would be sent. Filled pauses are synthesized during the apply and bound by a conversation when it opens, so an edited filler section reaches the next conversation and never changes what one already open is masking with. An agent is synthesized again when any field of its effective `filler` section moved or when the voice that speaks it did, and its clips are carried over as they are otherwise: the whole section is the unit of comparison, so an edit to `delay_ms` alone is a round of text-to-speech work at the configured provider even though the audio it produces is identical, and rewriting the provider entry an agent speaks through is another, since that is the voice moving; an edit that reaches neither, a prompt or a fragment, is none. An agent whose synthesis failed applies with no clip and runs unmasked rather than refusing the reload, which the answer's `fillers` section reports. The engines are the same clock and a different cost: an entry whose definition and stored credential are unchanged is carried into the new world as the object it already was, so an edit to a prompt reloads no model at all, while a rewritten entry is built before anything is swapped and the conversations that open after that speak through it. One that a conversation is still speaking through is released when that conversation ends, so an apply that changes a local model briefly holds two, and one whose engines would not build refuses with nothing changed. The agent set moves with the rest: an agent the store has added is one a device can be bound to and reach at its next check-in, and one it has deleted is one no session can be opened as from the moment this answers, while a conversation already talking as it finishes on the world it was built from. The answer's `agents` section names both, and says whether `agent_defaults` moved.\n\nThe `/sessions` and `/conversations` namespaces are not stored configuration either: they read the conversation store, the record of what was said, which `server.conversations.enabled` switches on. They are two readings of one set of rows rather than two stores, because a turn names both the session it was spoken in and the conversation it belongs to: the turns of one session can belong to several threads, and one thread's turns can come from several sessions. `/sessions` answers one connection episode at a time, which is what a session is: the session list newest first, one session whole, and one session's turns oldest first with the calls each turn made nested under it. `/conversations` answers the durable thread, which belongs to exactly one agent and outlives any single session: the thread list most recently active first and filterable by agent, one thread whole, and one thread's dialogue oldest first. Both namespaces erase as well as read, and the two erasures are asymmetric on purpose: `DELETE /sessions/{session}` and the selector purge take a session's turns wherever their threads are, while `DELETE /conversations/{conversation}` takes a thread's turns out of whatever sessions they were spoken in and leaves those sessions and their telemetry alone, with a gap in them. Three of the four listings are cursor-paginated on monotonic row ids that are never reused; the thread listing orders on activity, which moves, so it pages on the pair `cursor_active` and `cursor_id`, sent together or not at all. The two singular reads take neither `limit` nor `cursor`. A deployment that never recorded answers the empty shapes rather than a refusal, because the schema is migrated at every boot; one that recorded and has since switched recording off still serves what it recorded, because switching recording off stops the writer and not the reader. Content columns come back as they were stored, which is null where text storage was off, and every session says which way its switches were set.\n\n`/metrics` is the third reading of those same rows, and it answers about days rather than about a session or a thread: the named aggregates over the record, which are views in the store's own schema and add nothing to what is stored. `GET /metrics` lists them, each with the question it answers, the denominator its numbers are counted against, what telemetry storage being off does to that view in particular, and the columns a row of it carries; `GET /metrics/{view}` answers one of them over a window of whole UTC days, named by `since` and `until`, both included in it, defaulting to the current UTC day and the thirty before it and spanning at most three hundred and sixty-six. A wider window is refused rather than narrowed. Rows come newest day first and then by the columns a row of that view is unique by, which is a total order, and an empty list is an ordinary answer: a window with nothing in it and a deployment that never recorded are the same answer here for the reason the two namespaces above give. The word in the path is the last segment of a path this document lists and resolves through a closed mapping, so a name nothing answers to is refused rather than looked for. Every answer carries the statements that hold for all of these views beside the numbers, because what a number here cannot be made to say is the half a reader is most likely to be missing: a rate whose denominator is zero is null and not zero, a rate read outside the events' own retention window is a floor rather than a measurement, and a missing measurement has more than one cause that the store writes identically. This namespace exists for the readers that cannot speak SQL. A dashboard with a Postgres connection is a SQL client and reads the views directly, and the spelling `/metrics` shares with a scrape endpoint is a coincidence: nothing here is a Prometheus exposition, and it sits behind the same bearer token as everything else.\n\nA provider entry carries whatever options its `type` takes. The types that declare an option model, as stage and type, are: llm openai_compatible, asr faster_whisper, asr openai, tts elevenlabs. Their options are checked when the entry is written and refused by name, they are printed by `vinga schema provider <stage> <type>`, and the reference lists their fields under the provider section. Every other type has its options passed through rather than declared, so no schema can list those, and until the rest are typed (#88) they are documented in the example fragments under `vinga-server/examples/`, which is also where the measured numbers behind each default are kept.",
"version": "1"
},
"servers": [
{
"url": "/api"
}
],
"paths": {
"/config": {
"get": {
"summary": "Read Config",
"description": "The whole domain configuration, masked, with the location of\nevery stored secret beside it.",
"operationId": "read_config_config_get",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ConfigDocument"
}
}
}
},
"401": {
"description": "The request carried no bearer token, or not the one this server was given.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"409": {
"description": "Something this request needs is held by another one: the configuration database's write lock, the activation code a concurrent claim is already binding, or a reload of the MCP servers that is already running. Nothing was changed and the request can be retried.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"500": {
"description": "The stored configuration cannot be read, or the request failed for a reason that is not the caller's. The server's log names the class of what failed, and nothing else of it.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
}
}
}
},
"/providers": {
"get": {
"summary": "Read Providers",
"description": "Every provider, by stage and then by name: a provider is\naddressed by the two together, since two stages may hold one\nname.",
"operationId": "read_providers_providers_get",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"additionalProperties": {
"additionalProperties": {
"$ref": "#/components/schemas/Envelope"
},
"type": "object"
},
"type": "object",
"title": "Response Read Providers Providers Get"
}
}
}
},
"401": {
"description": "The request carried no bearer token, or not the one this server was given.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"409": {
"description": "Something this request needs is held by another one: the configuration database's write lock, the activation code a concurrent claim is already binding, or a reload of the MCP servers that is already running. Nothing was changed and the request can be retried.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"500": {
"description": "The stored configuration cannot be read, or the request failed for a reason that is not the caller's. The server's log names the class of what failed, and nothing else of it.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
}
}
}
},
"/providers/{stage}/{name}": {
"get": {
"summary": "Read Provider",
"description": "One provider.",
"operationId": "read_provider_providers__stage___name__get",
"parameters": [
{
"name": "stage",
"in": "path",
"required": true,
"schema": {
"type": "string",
"title": "Stage"
}
},
{
"name": "name",
"in": "path",
"required": true,
"schema": {
"type": "string",
"title": "Name"
}
}
],
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Envelope"
}
}
}
},
"401": {
"description": "The request carried no bearer token, or not the one this server was given.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"404": {
"description": "Nothing of that identity exists.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"409": {
"description": "Something this request needs is held by another one: the configuration database's write lock, the activation code a concurrent claim is already binding, or a reload of the MCP servers that is already running. Nothing was changed and the request can be retried.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"422": {
"description": "The request names something that cannot be addressed, such as a stage that is not a provider stage or a MAC address that is not one.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"500": {
"description": "The stored configuration cannot be read, or the request failed for a reason that is not the caller's. The server's log names the class of what failed, and nothing else of it.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
}
}
},
"put": {
"summary": "Write Provider",
"description": "Create or replace one provider from a fragment in the shape the YAML section had. The running server builds it again at the next reload, and the conversations that open after that speak through the new one.\n\nThe options a fragment may carry beyond the fields of `ProviderConfig` are whatever its `type` takes. This body is validated by the server rather than described as a discriminated schema here, so the types that declare their options state them as components of their own, named for the stage and the type: an entry in the `llm` stage with `type: openai_compatible` carries `LlmOpenaiCompatibleOptions`, an entry in the `asr` stage with `type: faster_whisper` carries `AsrFasterWhisperOptions`, an entry in the `asr` stage with `type: openai` carries `AsrOpenaiOptions`, an entry in the `tts` stage with `type: elevenlabs` carries `TtsElevenlabsOptions`. Every other type passes its options through undeclared, and the example fragments shipped with the server document those.",
"operationId": "write_provider_providers__stage___name__put",
"parameters": [
{
"name": "stage",
"in": "path",
"required": true,
"schema": {
"type": "string",
"title": "Stage"
}
},
{
"name": "name",
"in": "path",
"required": true,
"schema": {
"type": "string",
"title": "Name"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProviderConfig"
}
}
}
},
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Acknowledgement"
}
}
}
},
"401": {
"description": "The request carried no bearer token, or not the one this server was given.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"409": {
"description": "Something this request needs is held by another one: the configuration database's write lock, the activation code a concurrent claim is already binding, or a reload of the MCP servers that is already running. Nothing was changed and the request can be retried.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"422": {
"description": "The request names something that cannot be addressed, such as a stage that is not a provider stage or a MAC address that is not one.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"500": {
"description": "The stored configuration cannot be read, or the request failed for a reason that is not the caller's. The server's log names the class of what failed, and nothing else of it.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
}
}
},
"delete": {
"summary": "Remove Provider",
"description": "Delete one provider, and the secrets stored on it. Refused\nwhile an agent or the agent defaults still name it.",
"operationId": "remove_provider_providers__stage___name__delete",
"parameters": [
{
"name": "stage",
"in": "path",
"required": true,
"schema": {
"type": "string",
"title": "Stage"
}
},
{
"name": "name",
"in": "path",
"required": true,
"schema": {
"type": "string",
"title": "Name"
}
}
],
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Acknowledgement"
}
}
}
},
"401": {
"description": "The request carried no bearer token, or not the one this server was given.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"404": {
"description": "Nothing of that identity exists.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"409": {
"description": "Something this request needs is held by another one: the configuration database's write lock, the activation code a concurrent claim is already binding, or a reload of the MCP servers that is already running. Nothing was changed and the request can be retried.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"422": {
"description": "The request names something that cannot be addressed, such as a stage that is not a provider stage or a MAC address that is not one.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"500": {
"description": "The stored configuration cannot be read, or the request failed for a reason that is not the caller's. The server's log names the class of what failed, and nothing else of it.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
}
}
}
},
"/mcp-servers": {
"get": {
"summary": "Read Mcp Servers",
"description": "Every MCP server, by name.",
"operationId": "read_mcp_servers_mcp_servers_get",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"additionalProperties": {
"$ref": "#/components/schemas/Envelope"
},
"type": "object",
"title": "Response Read Mcp Servers Mcp Servers Get"
}
}
}
},
"401": {
"description": "The request carried no bearer token, or not the one this server was given.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"409": {
"description": "Something this request needs is held by another one: the configuration database's write lock, the activation code a concurrent claim is already binding, or a reload of the MCP servers that is already running. Nothing was changed and the request can be retried.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"500": {
"description": "The stored configuration cannot be read, or the request failed for a reason that is not the caller's. The server's log names the class of what failed, and nothing else of it.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
}
}
}
},
"/mcp-servers/{name}": {
"get": {
"summary": "Read Mcp Server",
"description": "One MCP server.",
"operationId": "read_mcp_server_mcp_servers__name__get",
"parameters": [
{
"name": "name",
"in": "path",
"required": true,
"schema": {
"type": "string",
"title": "Name"
}
}
],
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Envelope"
}
}
}
},
"401": {
"description": "The request carried no bearer token, or not the one this server was given.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"404": {
"description": "Nothing of that identity exists.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"409": {
"description": "Something this request needs is held by another one: the configuration database's write lock, the activation code a concurrent claim is already binding, or a reload of the MCP servers that is already running. Nothing was changed and the request can be retried.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"422": {
"description": "The request names something that cannot be addressed, such as a stage that is not a provider stage or a MAC address that is not one.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"500": {
"description": "The stored configuration cannot be read, or the request failed for a reason that is not the caller's. The server's log names the class of what failed, and nothing else of it.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
}
}
},
"put": {
"summary": "Write Mcp Server",
"description": "Create or replace one MCP server. The running server applies\nit at the next reload, with no restart.",
"operationId": "write_mcp_server_mcp_servers__name__put",
"parameters": [
{
"name": "name",
"in": "path",
"required": true,
"schema": {
"type": "string",
"title": "Name"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/McpServerConfig"
}
}
}
},
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Acknowledgement"
}
}
}
},
"401": {
"description": "The request carried no bearer token, or not the one this server was given.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"409": {
"description": "Something this request needs is held by another one: the configuration database's write lock, the activation code a concurrent claim is already binding, or a reload of the MCP servers that is already running. Nothing was changed and the request can be retried.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"422": {
"description": "The request names something that cannot be addressed, such as a stage that is not a provider stage or a MAC address that is not one.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"500": {
"description": "The stored configuration cannot be read, or the request failed for a reason that is not the caller's. The server's log names the class of what failed, and nothing else of it.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
}
}
},
"delete": {
"summary": "Remove Mcp Server",
"description": "Delete one MCP server, and the secrets stored on it. The\nrunning server stops it at the next reload.",
"operationId": "remove_mcp_server_mcp_servers__name__delete",
"parameters": [
{
"name": "name",
"in": "path",
"required": true,
"schema": {
"type": "string",
"title": "Name"
}
}
],
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Acknowledgement"
}
}
}
},
"401": {
"description": "The request carried no bearer token, or not the one this server was given.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"404": {
"description": "Nothing of that identity exists.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"409": {
"description": "Something this request needs is held by another one: the configuration database's write lock, the activation code a concurrent claim is already binding, or a reload of the MCP servers that is already running. Nothing was changed and the request can be retried.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"422": {
"description": "The request names something that cannot be addressed, such as a stage that is not a provider stage or a MAC address that is not one.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"500": {
"description": "The stored configuration cannot be read, or the request failed for a reason that is not the caller's. The server's log names the class of what failed, and nothing else of it.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
}
}
}
},
"/prompt-fragments": {
"get": {
"summary": "Read Prompt Fragments",
"description": "Every shared prompt fragment, by name.",
"operationId": "read_prompt_fragments_prompt_fragments_get",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"additionalProperties": {
"$ref": "#/components/schemas/Envelope"
},
"type": "object",
"title": "Response Read Prompt Fragments Prompt Fragments Get"
}
}
}
},
"401": {
"description": "The request carried no bearer token, or not the one this server was given.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"409": {
"description": "Something this request needs is held by another one: the configuration database's write lock, the activation code a concurrent claim is already binding, or a reload of the MCP servers that is already running. Nothing was changed and the request can be retried.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"500": {
"description": "The stored configuration cannot be read, or the request failed for a reason that is not the caller's. The server's log names the class of what failed, and nothing else of it.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
}
}
}
},
"/prompt-fragments/{name}": {
"get": {
"summary": "Read Prompt Fragment",
"description": "One shared prompt fragment, with its text as it was written:\nit is what the model is given, and there is nothing in it to\nmask.",
"operationId": "read_prompt_fragment_prompt_fragments__name__get",
"parameters": [
{
"name": "name",
"in": "path",
"required": true,
"schema": {
"type": "string",
"title": "Name"
}
}
],
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Envelope"
}
}
}
},
"401": {
"description": "The request carried no bearer token, or not the one this server was given.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"404": {
"description": "Nothing of that identity exists.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"409": {
"description": "Something this request needs is held by another one: the configuration database's write lock, the activation code a concurrent claim is already binding, or a reload of the MCP servers that is already running. Nothing was changed and the request can be retried.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"422": {
"description": "The request names something that cannot be addressed, such as a stage that is not a provider stage or a MAC address that is not one.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"500": {
"description": "The stored configuration cannot be read, or the request failed for a reason that is not the caller's. The server's log names the class of what failed, and nothing else of it.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
}
}
},
"put": {
"summary": "Write Prompt Fragment",
"description": "Create or replace one shared prompt fragment.\n\nIt carries the reload sentence: a fragment is prompt text, the\nreload re-reads the whole `prompt_fragments` kind, and prompt\ntext is assembled at an activation, so the new words reach every\nagent that includes this fragment at that agent's next\nactivation. Which agents those are is whichever layer names it,\nand both layers are the same reload's: an agent's own\n`prompt_includes`, and the `agent_defaults.prompt_includes` that\nevery agent naming no list of its own inherits.",
"operationId": "write_prompt_fragment_prompt_fragments__name__put",
"parameters": [
{
"name": "name",
"in": "path",
"required": true,
"schema": {
"type": "string",
"title": "Name"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PromptFragmentConfig"
}
}
}
},
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Acknowledgement"
}
}
}
},
"401": {
"description": "The request carried no bearer token, or not the one this server was given.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"409": {
"description": "Something this request needs is held by another one: the configuration database's write lock, the activation code a concurrent claim is already binding, or a reload of the MCP servers that is already running. Nothing was changed and the request can be retried.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"422": {
"description": "The request names something that cannot be addressed, such as a stage that is not a provider stage or a MAC address that is not one.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"500": {
"description": "The stored configuration cannot be read, or the request failed for a reason that is not the caller's. The server's log names the class of what failed, and nothing else of it.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
}
}
},
"delete": {
"summary": "Remove Prompt Fragment",
"description": "Delete one shared prompt fragment. Refused while any layer\nstill includes it.",
"operationId": "remove_prompt_fragment_prompt_fragments__name__delete",
"parameters": [
{
"name": "name",
"in": "path",
"required": true,
"schema": {
"type": "string",
"title": "Name"
}
}
],
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Acknowledgement"
}
}
}
},
"401": {
"description": "The request carried no bearer token, or not the one this server was given.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"404": {
"description": "Nothing of that identity exists.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"409": {
"description": "Something this request needs is held by another one: the configuration database's write lock, the activation code a concurrent claim is already binding, or a reload of the MCP servers that is already running. Nothing was changed and the request can be retried.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"422": {
"description": "The request names something that cannot be addressed, such as a stage that is not a provider stage or a MAC address that is not one.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"500": {
"description": "The stored configuration cannot be read, or the request failed for a reason that is not the caller's. The server's log names the class of what failed, and nothing else of it.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
}
}
}
},
"/agents": {
"get": {
"summary": "Read Agents",
"description": "Every agent, by name.",
"operationId": "read_agents_agents_get",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"additionalProperties": {
"$ref": "#/components/schemas/Envelope"
},
"type": "object",
"title": "Response Read Agents Agents Get"
}
}
}
},
"401": {
"description": "The request carried no bearer token, or not the one this server was given.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"409": {
"description": "Something this request needs is held by another one: the configuration database's write lock, the activation code a concurrent claim is already binding, or a reload of the MCP servers that is already running. Nothing was changed and the request can be retried.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Problem"
}
}
}
},
"500": {