10/Documentation
Das Übertragungsprotokoll für persistente Agenten (experimentell)
Der Datenaustausch zwischen Collie und einem persistenten Agenten für Entwickler: Routen, Hello und Epoche, der Ablauf einer Anfrage samt Anfrage-IDs, Übertragung per Socket und Token, Grenzwerte und Versionsregeln, mit einem Verweis auf WIRE.md für die genauen Vorgaben
Experimentell. Die Leitung kann sich in einem späteren Minor-Release ändern oder das Feature kann entfernt werden. Versionen und das aussagekräftige Hello beschreibt, wie Sie eine Änderung erreicht.
Die Durable-Leitung ist die Art und Weise, wie Collie mit einem Durable-Agenten kommuniziert. Diese Seite erklärt sie für Entwickler, die einen Durable-Agenten ohne das SDK schreiben oder wissen möchten, was das SDK tut. Die genauen Regeln stehen in WIRE.md, und wo sich diese Seite und jene Datei unterscheiden, gilt WIRE.md. Das Durable-SDK übernimmt das alles für Sie.
Was übertragen wird
Collie wählt an und der langlebige Agent lauscht, und jeder Austausch ist eine HTTP-Anfrage mit einem JSON-Body.
Der langlebige Agent lauscht an einem privaten Unix-Socket oder hinter TLS unter einer URL (Transportwege). Collie pollt ihn: Es gibt keinen Push, kein WebSocket und keinen Stream. Jeder Pfad beginnt mit /session/v1, was ein fester Name ist, nicht die Version. Jeder Aufruf außer dem ersten hello überträgt die Version im Header X-Collie-Session. Ein Anfrage-Body ist ein einzelnes JSON-Objekt von höchstens 64 KiB, und ein leerer POST-Body liest sich als {}.
| Methode und Pfad | Funktion | Antwortbegrenzung |
|---|---|---|
GET /hello | Name, Versionsbereich, Epoche, Betriebsbereitschaft und Fähigkeiten des langlebigen Agenten | 16 KiB |
GET /snapshot | Das Layout: Arbeitsbereiche, Tabs, Bereiche mit ihrem Zustand, Durchlauf und offenen Anfragen sowie Starter. Überträgt ein ETag und antwortet mit 304, wenn sich nichts geändert hat | 4 MiB |
GET /pane/:id/events?after=N&epoch=E | Die Ereignisse des Bereichs nach einem Cursor | 8 MiB |
POST /pane/:id/answer | Eine Antwort auf eine Anfrage | 16 KiB |
POST /pane/:id/send | Text für den Bereich, um den laufenden Durchlauf zu steuern oder auf den nächsten zu warten | 16 KiB |
POST /pane/:id/abort | Den laufenden Durchlauf anhalten | 16 KiB |
POST /pane/:id/action | Ein Klick auf eine der Gürtelschaltflächen des Bereichs | 16 KiB |
POST /rename | Ein neuer Titel für einen Arbeitsbereich oder einen Tab | 16 KiB |
POST /close | Einen Bereich, einen Tab oder einen Arbeitsbereich schließen | 16 KiB |
POST /starter/:id | Einen Starter ausführen. Die Antwort benennt den neuen Bereich | 16 KiB |
GET /conversations?after=C&limit=N | Die Konversationen des langlebigen Agenten, offen und geschlossen, neueste zuerst | 1 MiB |
GET /conversation/:id/items?after=C&limit=N | Die Elemente einer Konversation, älteste zuerst | 8 MiB |
POST /reopen | Eine geschlossene Konversation wieder anzeigen | 16 KiB |
Jeder Fehler ist ein JSON-Body mit einem code, wie etwa 409 stale oder 404 no-such-pane. Jeder andere Pfad antwortet mit 404 not-found. Eine Antwort über ihrem Limit wird nicht gelesen, und ein POST, dessen Antwort abgeschnitten wird, hat ein unbekanntes Ergebnis (Anfrage-IDs).
Hello und Epoche
hello gibt an, wer der langlebige Agent ist, und die Epoche gibt an, mit welchem Start von ihm Collie spricht.
Feld von hello | was er enthält |
|---|---|
service | Exakt collie-durable. Ohne diesen Wert interpretiert Collie den langlebigen Agenten als einen anderen Server und ruft nichts Weiteres auf |
protocol | Der Bereich der Protokollversionen, die der langlebige Agent spricht, { min, max }. Heute { min: 1, max: 1 } |
host.name | Der eigene Name des langlebigen Agenten, nur Anzeigetext, höchstens 64 Bytes |
epoch | Neu und zufällig bei jedem Start des langlebigen Agenten, mindestens 128 Bits, niemals wiederverwendet |
ready | False, während der Durable Agent nach einem Start seine Bereiche anordnet |
caps | Fähigkeiten des Durable Agents, jeweils als boolescher Wert. Eine fehlende Fähigkeit ist false |
Collie ruft zuerst hello ohne den Versions-Header auf, wählt die höchste von beiden Seiten unterstützte Version und sendet sie bei jedem späteren Aufruf mit. Solange ready false ist, antwortet jede Route außer hello mit 503 starting, und das Telefon zeigt den Durable Agent als startend an. Ein Durable Agent setzt ready erst, wenn jede Konversation wieder angezeigt und jede offene Anfrage erneut gestellt wurde, sodass ein Neustart niemals ein halbes Layout anzeigt.
Der ETag des Snapshots ist "<epoch>-<rev>". rev erhöht sich bei jeder für Leser sichtbaren Änderung, sodass ein 304 den Durable Agent fast nichts kostet. Eine neue Epoche signalisiert Collie, dass der Durable Agent neu gestartet wurde. Collie zeigt die vorhandenen Bereiche weiter an, bis der neue Snapshot gelesen wird. Danach liest es jeden Bereich mit seinem alten Cursor und erhält die gesamte aktuelle Ansicht des Bereichs in einer einzigen Antwort.
Ein einzelner Lesefehler nach einem erfolgreichen Lesevorgang behält den letzten Snapshot für diese Abfrage bei. Zwei aufeinanderfolgende Fehler zeigen den Durable Agent als nicht erreichbar an. Ein Socket-Pfad, der die Berechtigungsprüfung nicht besteht, ist sofort nicht erreichbar.
Anfragen und Antworten
Eine Anfrage ist eine Fragekarte und bleibt vom ask-Ereignis des Durable Agents bis zu dessen ask-closed offen.
| Status | Wer es setzt | was das Telefon anzeigt |
|---|---|---|
| Offen | Der Durable Agent stellt die Anfrage. Der Bereich zeigt waiting, solange eine Anfrage offen ist | Eine Karte unter "Erfordert Ihre Antwort", mit dem Namen des Durable Agents und der verbleibenden Zeit, wenn die Anfrage expiresAt hat |
| Geändert | Der Durable Agent ändert die Anfrage direkt, und ihr revision erhöht sich | Die Karte baut sich neu auf. Ein Tippen auf das alte Formular liefert 409 stale, und die Karte meldet "Diese Anfrage wurde geändert. Lesen Sie sie erneut und tippen Sie dann auf eine Antwort." |
| Angenommen | Das Telefon antwortet und der Durable Agent schließt die Anfrage mit by: "phone" | Die Karte verschwindet und das Werkzeug wird ausgeführt oder abgelehnt, wie in der Option festgelegt |
| Im Durable Agent entschieden | Der Durable Agent schließt die Anfrage selbst, decidedBy: "program". Das Beenden des Zugs zählt dazu | Eine Zeile im Chat, die mit "Im Durable Agent entschieden" beginnt, zusammen mit dem Titel der Anfrage |
| Zeit abgelaufen | Die Uhr überschreitet expiresAt, decidedBy: "timeout" | Eine Zeile im Chat, die mit "Zeit vor einer Antwort abgelaufen" beginnt, zusammen mit dem Titel der Anfrage |
Ein Tippen nach der Entscheidung liefert 409 decided mit dem ersten Ergebnis, und nichts wird ausgeführt. Die Karte zeigt dann an, wer zuerst entschieden hat: "Im Durable Agent entschieden.", "Zeit vor einer Antwort abgelaufen." oder nach einem weiteren Tippen "Bereits beantwortet. Diese Karte verschwindet bei der nächsten Aktualisierung." Eine Anfrage, die der Durable Agent nicht mehr kennt, liefert 200 too-late. Die Karte zeigt dann "Nicht angenommen. Die Frage wird möglicherweise gleich wieder angezeigt.", da der Durable Agent sie nach einem Neustart unter derselben ID erneut stellen kann.
| Regel | warum |
|---|---|
| Die Anfrage-ID ist ein Hash aus der Bereichs-ID und der Werkzeugaufruf-ID | Derselbe nach einem Neustart gestellte Werkzeugaufruf hat dieselbe ID, sodass eine über den Neustart hinweg gesendete Antwort ankommt |
Eine permission-Karte wird aus dem Namen des Werkzeugs und seinen Argumenten erstellt, niemals aus den Worten des Modells | Ein Modell, das eine Zustimmung will, würde den Aufruf wohlwollend beschreiben |
Ein Durable Agent hinter TLS sollte kein allow-always anbieten | Das Token ist die einzige Schranke, sodass eine einzige Antwort von dessen Inhaber jeden späteren Aufruf durchlassen würde |
Das Smartphone bietet kein allow-always auf einer Karte, deren Text gekürzt oder bereinigt wurde oder die kein Werkzeug benennt | Die Person kann nicht sehen, was die Freigabe abdeckt |
expiresAt ist ISO 8601 mit Zeitzone | Danach wird die Anfrage per timeout entschieden, und ein Snapshot führt sie nicht mehr als offen auf |
| Der Durable Agent behält das Ergebnis von mindestens den letzten 500 entschiedenen Anfragen pro Bereich | Ein spätes Tippen erhält decided und das erste Ergebnis, kein einfaches too-late |
Eine Anfrage ist eine von vier Arten: permission, choice, text oder form. Jede hat ihr eigenes Antwortformat, aufgeführt bei Fragen des SDK.
Anfrage-IDs
Jede Aktion vom Smartphone hat eine Anforderungs-ID, sodass sie höchstens einmal ausgeführt wird.
Das Smartphone erzeugt eine Anforderungs-ID pro Absicht, und Collie schreibt eine eigene Quittung, bevor es die ID weitergibt. Der Durable Agent behält mindestens die letzten 500 IDs seiner Epoche. Eine Wiederholung einer abgeschlossenen ID erhält die erste Antwort erneut mit replayed: true und führt nichts aus. Dieselbe ID mit einer anderen Nutzlast erhält 409 request-id-reused.
Collie wiederholt einen POST niemals von selbst. Ein POST mit Zeitüberschreitung, Verbindungsabbruch oder einem 5xx-Fehler hat ein unbekanntes Ergebnis. Bei einer Antwort meldet die Karte dann: "Not sure the answer arrived. Try again sends it once more.", und "Try again" sendet dieselbe Anforderungs-ID, sodass der Speicher des Durable Agent eine Wiederholung beantwortet.
Ein Wiederholungsversuch, der die Anfrage geschlossen oder den Spielzug weitergerückt vorfindet, kann nicht feststellen, ob der erste Versuch ankam. Collie antwortet dem Smartphone dann "maybe applied", die Karte meldet "May already be applied. Check the chat.", und die Aktion wird kein drittes Mal gesendet.
Transportwege
Ein Durable Agent verwendet einen von zwei Transportwegen: einen privaten Socket auf dem Rechner von Collie oder TLS mit einem Token.
Die Bytes sind bei beiden identisch: die Routen, die Nachrichtenkörper, der Versions-Header, das ETag und die Fehlercodes. Nur wer den Durable Agent erreichen darf, unterscheidet sich.
| über den Socket | die Regel |
|---|---|
| Pfad | Absolut, höchstens 103 Bytes. Beide Seiten lesen ihn aus COLLIE_DURABLE_SOCKET |
| Modi | Der Socket hat den Modus 0600, in einem Ordner mit Modus 0700. Der Durable Agent entfernt eine verwaiste Socket-Datei, bevor er lauscht |
| Die Pfaddurchquerung | Vor jedem Verbindungsaufbau prüft Collie jeden Teil des Pfads mit lstat. Kein Teil ist ein symbolischer Link. Der Ordner des Sockets gehört Ihnen mit Modus 0700. Kein Ordner darüber ist für Gruppe oder Andere beschreibbar, außer ein Sticky-Ordner wie /tmp. Der Socket gehört Ihnen, ohne Berechtigungen für Gruppe oder Andere |
| Eine fehlgeschlagene Durchquerung | Collie verbindet sich nicht und zeigt den Durable Agent mit socket-not-private und dem fehlgeschlagenen Teil als unerreichbar an |
| Token | Keine. Der private Socket ist das Zugangstor |
| Wer agieren kann | Jeder Prozess Ihres Benutzers. Der Durable Agent kann eigene Nachkommen mit 403 caller-refused ablehnen |
| Zeitüberschreitungen | 1000 ms für hello, snapshot und events. 3000 ms für Antwort, Senden, Stopp, Aktion, Umbenennen oder Schließen. 30000 ms für einen Starter |
| Wie oft Collie anfragt | Alle 1 s, während ein Smartphone zusieht, sonst alle 3 s. Ein Durable Agent, der offline ist, wird einmal pro Abfrageintervall angefragt |
| Systeme | Linux und macOS. Windows hat keinen Socket-Transport |
| über TLS | die Regel |
|---|---|
| URL | https://, oder http://127.0.0.1:<port> oder http://localhost:<port> für einen lokalen Test. Maximal 2048 Bytes, kein Benutzername oder Passwort, keine Query, kein Fragment. Collie hängt /session/v1 an |
| Token | Mindestens 32 Bytes, druckbares ASCII ohne Leerzeichen. Collie sendet Authorization: Bearer <token> bei jeder Anfrage, inklusive hello |
| Die Prüfung des Durable Agent | Das Token zuerst, vor der Version, hello und ready, verglichen in konstanter Zeit. Ein fehlendes oder falsches Token erhält ein einfaches 401 { "code": "unauthorized" } und nichts weiter |
| Weiterleitungen | Collie folgt keinen Weiterleitungen. Ein 3xx-Status wird nach oben weitergereicht, damit das Token niemals einen anderen Host erreicht |
| ETag | Ein Proxy, der eine Antwort komprimiert, schwächt das Tag eventuell zu W/"<epoch>-<rev>" ab. Beide Seiten vergleichen es ohne das W/ |
| Eine Verweigerung | Ein 401 oder 403 zeigt den Durable Agent mit token-refused als nicht erreichbar an |
| Zeitüberschreitungen | 5000 ms für jeden Lese- und Schreibvorgang, da ein Durable Agent nach dem Ruhezustand kalt aufwachen kann. 30000 ms für einen Starter |
| Wie oft Collie anfragt | Alle 2 s, während ein Telefon zuschaut, sonst alle 10 s. Ein Durable Agent, der offline ist oder verweigert wird, wird maximal einmal alle 10 s abgefragt |
Jeder Timeout ist eine Frist für den gesamten Austausch, vom Verbindungsaufbau bis zum letzten Byte. Über TLS ist jedes Polling eine Anfrage, die Ihr Host eventuell abrechnet, inklusive eines 304.
Einschränkungen
Collie schneidet alles ab oder lehnt alles ab, was über diesen Grenzen liegt. Ein Durable Agent, der innerhalb der Grenzen bleibt, verliert nichts.
| was | Limit |
|---|---|
| Arbeitsbereiche pro Snapshot | 64 |
| Tabs pro Snapshot | 256 |
| Bereiche pro Snapshot | 256 |
| Offene Fragen pro Bereich | 50, die ältesten zuerst |
Optionen eines permission | 6 |
Optionen eines choice und eines Auswahlfelds | 8 |
Felder eines form | 6 |
| Starter pro Snapshot | 50 |
| Belt-Schaltflächen pro Bereich | 4, eine Beschriftung von 16 Zeichen |
| Eine ID | 1 bis 128 Bytes, kein Steuerzeichen, kein Leerraumzeichen, keines von /, ? oder # |
| Ein Anfragekörper | 64 KiB, sonst 413 too-large |
| Antworten | hello 16 KiB, snapshot 4 MiB, events 8 MiB, conversations 1 MiB, items 8 MiB, ein POST 16 KiB |
| Ereignisse pro Antwort | 1000. Ein Reader, der in Rückstand geraten ist, erhält die aktuelle Ansicht, maximal die neuesten 2000 Elemente |
Text eines user-, reply-, thinking- oder notice-Elements | 64 KiB |
Text eines markdown- oder code-Elements | 32 KiB |
| Text, den das Telefon sendet | 32 KiB |
Ein link-Element | Nur https://, maximal 2048 Zeichen |
| Eine Verlaufsseite | 100 Unterhaltungen oder 1000 Elemente |
| Ein Verlaufscursor | 512 Bytes druckbares ASCII, kein Leerzeichen |
Eine Zeichenkette, die ihr Limit überschreitet, wird gekürzt, und ihre Steuerzeichen sowie unsichtbaren Zeichen werden entfernt. Eine Liste, die ihr Limit überschreitet, behält ihre ersten Einträge. Eine Verlaufsseite, die ihr Limit überschreitet, wird gar nicht erst gelesen.
Versionen und das aussagekräftige Hello
Aktuell gibt es eine Übertragungsversion, 1, und Collie spricht 1..1.
Wenn Version 2 erscheint, akzeptiert Collie Version 1 noch für ein Minor-Release danach; das darauffolgende Minor-Release entfernt die Unterstützung. Ein Reader ignoriert Felder, Ereignistypen, Elementarten oder Codes, die er nicht kennt. Ein innerhalb von Version 1 hinzugefügtes Feld wie expiresAt oder decidedBy ist optional. Ein neues Pflichtfeld, eine neue Bedeutung für ein bestehendes Feld oder ein entferntes Feld erfordert eine neue Version.
Eine Anfrage einer Art, die das Telefon nicht kennt, wird als eine Anfrage dargestellt, die nicht vom Telefon aus beantwortet werden kann, ohne Schaltflächen.
Wenn die beiden Bereiche sich nicht überschneiden, liest Collie nichts mehr vom persistenten Agenten. Einmal pro Epoche des persistenten Agenten sendet es ein weiteres hello, diesmal mit seiner eigenen Version, damit der persistente Agent die Diskrepanz auf seiner Seite protokollieren kann. Der persistente Agent antwortet mit 409 incompatible und einem refusal, das beide Bereiche benennt. Dies ist das aufschlussreiche Hello.
Collie schreibt für jeden abgelehnten Bereich eine Zeile in sein Protokoll, und collie doctor zeigt beide Bereiche an. Die Startansicht des persistenten Agenten auf dem Telefon zeigt denselben Satz, zum Beispiel „Der persistente Agent spricht Übertragungsversion v2, dieses Collie spricht v1. Aktualisieren Sie Collie oder das SDK des Agenten.“ Aktualisieren Sie die ältere Seite.
Fundort der genauen Regeln
WIRE.md ist der Vertrag mit jeder Form, jedem Code und jeder Regel.
Die Entscheidungen dahinter sind Datensätze im Repository:
| Datensatz | was er entscheidet |
|---|---|
| ADR 0099 | Ein durable agent ist ein Multiplexer ohne Bildschirm |
| ADR 0100 | Ein Ask reist als Daten und wird per ID beantwortet |
| ADR 0101 | Send und Stop benennen den Turn, den das Telefon gesehen hat |
| ADR 0102 | Starter sind Zeilen auf der New-Seite |
| ADR 0103 | Die zwei Transporte |
| ADR 0104 | Ein durable agent ist eine Sitzung und der Exit |
| ADR 0105 | Das SDK ist ein npm-Paket |
Diese Seite auf GitHub bearbeiten