10/Documentation
Le protocole filaire durable (expérimental)
Ce qui circule entre Collie et un agent durable, pour les développeurs : les routes, le hello et l'epoch, le cycle de vie d'une demande et les identifiants de requête, les transports par socket et par jeton, les limites et la règle de version, avec un lien vers WIRE.md pour les règles exactes
Expérimental. Le protocole réseau peut changer, ou la fonctionnalité peut être supprimée, dans une version mineure ultérieure. Versions et hello explicatif explique comment une modification vous parvient.
Le protocole réseau durable correspond à la manière dont Collie communique avec un agent durable. Cette page l'explique pour un développeur qui écrit un agent durable sans le SDK, ou souhaite savoir ce que fait le SDK. Les règles exactes se trouvent dans WIRE.md, et en cas de divergence avec cette page, WIRE.md fait foi. Le SDK durable gère l'ensemble pour vous.
Ce qui transite
Collie se connecte et l'agent persistant écoute, et chaque échange consiste en une requête HTTP avec un corps JSON.
L'agent persistant écoute sur un socket Unix privé, ou derrière TLS à une URL (Transports). Collie l'interroge : il n'y a pas de push, pas de WebSocket et pas de flux. Chaque chemin commence par /session/v1, qui est un nom fixe et non la version. Chaque appel sauf le premier hello transmet la version dans l'en-tête X-Collie-Session. Le corps d'une requête est un objet JSON d'au plus 64 Kio, et un corps POST vide équivaut à {}.
| méthode et chemin | description | limite de réponse |
|---|---|---|
GET /hello | Nom de l'agent persistant, plage de versions, époque, état de disponibilité et capacités | 16 Kio |
GET /snapshot | La disposition : espaces de travail, onglets, panneaux avec leur état, tour et demandes ouvertes, ainsi que démarreurs. Transmet un ETag, et renvoie 304 quand rien n'a changé | 4 Mio |
GET /pane/:id/events?after=N&epoch=E | Les événements du panneau après un curseur | 8 Mio |
POST /pane/:id/answer | Une réponse à une demande | 16 Kio |
POST /pane/:id/send | Texte pour le panneau, pour orienter le tour en cours ou attendre le suivant | 16 Kio |
POST /pane/:id/abort | Arrêter le tour en cours | 16 Kio |
POST /pane/:id/action | Un appui sur l'un des boutons de la barre du panneau | 16 Kio |
POST /rename | Un nouveau titre pour un espace de travail ou un onglet | 16 Kio |
POST /close | Fermer un panneau, un onglet ou un espace de travail | 16 Kio |
POST /starter/:id | Exécuter un démarreur. La réponse nomme le nouveau panneau | 16 Kio |
GET /conversations?after=C&limit=N | Les conversations de l'agent persistant, ouvertes et fermées, de la plus récente à la plus ancienne | 1 Mio |
GET /conversation/:id/items?after=C&limit=N | Les éléments d'une conversation, du plus ancien au plus récent | 8 Mio |
POST /reopen | Afficher à nouveau une conversation fermée | 16 Kio |
Chaque erreur est un corps JSON avec un code, comme 409 stale ou 404 no-such-pane. Tout autre chemin renvoie 404 not-found. Une réponse dépassant sa limite n'est pas lue, et un POST dont la réponse est coupée a un résultat indéterminé (Identifiants de requête).
Hello et époque
hello indique l'identité de l'agent persistant, et l'époque indique à quel démarrage de celui-ci Collie s'adresse.
champ de hello | ce qu'elle contient |
|---|---|
service | Exactement collie-durable. Sans lui, Collie considère l'agent persistant comme un autre serveur et n'appelle rien d'autre |
protocol | La plage de versions filaires prises en charge par l'agent persistant, { min, max }. Aujourd'hui { min: 1, max: 1 } |
host.name | Le nom propre de l'agent persistant, texte d'affichage uniquement, au plus 64 octets |
epoch | Nouveau et aléatoire à chaque démarrage de l'agent persistant, au moins 128 bits, jamais réutilisé |
ready | False pendant que l'agent durable dispose ses panneaux après un démarrage |
caps | Ce que l'agent durable peut faire, chacun étant un booléen. Une capacité absente vaut false |
Collie appelle d'abord hello sans l'en-tête de version, choisit la version la plus élevée prise en charge par les deux côtés et l'envoie à chaque appel ultérieur. Tant que ready est false, chaque route sauf hello répond 503 starting, et le téléphone affiche l'agent durable comme étant en cours de démarrage. Un agent durable ne définit ready qu'une fois chaque conversation réaffichée et chaque ask ouvert soulevé à nouveau, de sorte qu'un redémarrage n'affiche jamais une disposition incomplète.
L'ETag du snapshot est "<epoch>-<rev>". rev augmente à chaque modification visible par un lecteur, donc un 304 ne coûte presque rien à l'agent durable. Une nouvelle epoch indique à Collie que l'agent durable a redémarré. Collie continue d'afficher les panneaux dont il dispose jusqu'à ce qu'il lise le nouveau snapshot. Il lit ensuite chaque panneau avec son ancien curseur et obtient la vue actuelle complète du panneau en une seule réponse.
Une lecture échouée après une lecture réussie conserve le dernier snapshot pour cette interrogation. Deux échecs consécutifs affichent l'agent durable comme injoignable. Un chemin de socket qui échoue lors du contrôle de confidentialité est immédiatement injoignable.
Asks et réponses
Un ask est une carte de question, ouverte depuis l'événement ask de l'agent durable jusqu'à son ask-closed.
| état | qui le définit | ce que le téléphone affiche |
|---|---|---|
| Open | L'agent durable soulève l'ask. Le panneau affiche waiting tant qu'un ask est ouvert | Une carte sous « Needs your answer », avec le nom de l'agent durable et le temps restant lorsque l'ask a expiresAt |
| Changed | L'agent durable modifie l'ask sur place, et son revision augmente | La carte se redessine. Un appui sur l'ancien formulaire renvoie 409 stale, et la carte indique « This ask changed. Read it again, then tap an answer. » |
| Taken | Le téléphone répond, et l'agent durable ferme l'ask avec by: "phone" | La carte disparaît, et l'outil s'exécute ou est refusé selon l'option choisie |
| Decided in the durable agent | L'agent durable ferme l'ask lui-même, decidedBy: "program". L'interruption du tour compte | Une ligne dans Chat commençant par « Decided in the durable agent », avec le titre de l'ask |
| Timed out | L'horloge dépasse expiresAt, decidedBy: "timeout" | Une ligne dans Chat commençant par « Timed out before an answer », avec le titre de l'ask |
Un appui survenant après la décision renvoie 409 decided avec le premier résultat, et rien ne s'exécute. La carte indique ensuite qui a décidé en premier : « Decided in the durable agent. », « Timed out before an answer. » ou, après un autre appui, « Already answered. This card goes away on the next update. » Un ask que l'agent durable ne connaît plus renvoie 200 too-late. La carte indique alors « Not taken. The question may show again in a moment. », car après un redémarrage, l'agent durable peut le soulever à nouveau sous le même identifiant.
| règle | pourquoi |
|---|---|
| L'identifiant de l'ask est un hash de l'identifiant du panneau et de l'identifiant de l'appel d'outil | Le même appel d'outil soulevé après un redémarrage a le même identifiant, de sorte qu'une réponse envoyée à travers le redémarrage aboutit |
Une carte permission est construite à partir du nom de l'outil et de ses arguments, jamais à partir des mots du modèle | Un modèle qui veut un oui décrirait l'appel de manière favorable |
Un agent durable derrière TLS ne doit proposer aucun allow-always | Le token est l'unique verrou, donc une réponse de quiconque le détient autoriserait chaque appel ultérieur |
Le téléphone ne propose aucun allow-always sur une carte dont les mots ont été coupés ou nettoyés, ou qui ne nomme aucun outil | L'utilisateur ne peut pas voir ce que couvre l'autorisation |
expiresAt est au format ISO 8601 avec fuseau horaire | Au-delà, la demande est tranchée par timeout, et un instantané ne l'affiche plus comme ouverte |
| L'agent durable conserve le résultat d'au moins ses 500 dernières demandes tranchées par volet | Un appui tardif reçoit decided et le premier résultat, pas un simple too-late |
Une demande est de l'un des quatre types suivants : permission, choice, text ou form. Chacun a sa propre structure de réponse, répertoriée avec le Questions du SDK.
Identifiants de requête
Chaque action provenant du téléphone possède un identifiant de requête, afin de ne s'exécuter qu'une seule fois au maximum.
Le téléphone génère un identifiant de requête par intention, et Collie écrit son propre accusé de réception avant de transmettre l'identifiant. L'agent durable conserve au moins les 500 derniers identifiants de son époque. Une répétition d'un identifiant terminé reçoit à nouveau la première réponse avec replayed: true et n'exécute rien. Le même identifiant avec une charge utile différente reçoit 409 request-id-reused.
Collie ne réessaie jamais un POST de lui-même. Un POST qui expire, perd sa connexion ou reçoit un 5xx a un résultat inconnu. Pour une réponse, la carte indique alors « Not sure the answer arrived. Try again sends it once more. », et Try again renvoie le même identifiant de requête, afin que la mémoire de l'agent durable réponde à une répétition.
Une nouvelle tentative qui trouve la demande fermée ou le tour déplacé ne peut pas savoir si le premier essai a abouti. Collie répond alors au téléphone « maybe applied », la carte indique « May already be applied. Check the chat. », et l'action n'est jamais envoyée une troisième fois.
Transports
Un agent durable utilise l'un des deux transports : un socket privé sur la machine de Collie, ou TLS avec un jeton.
Les octets sont les mêmes sur les deux : les routes, les corps, l'en-tête de version, l'ETag et les codes d'erreur. Seule la liste des personnes autorisées à joindre l'agent durable diffère.
| via le socket | la règle |
|---|---|
| Chemin | Absolu, d'au plus 103 octets. Les deux côtés le lisent depuis COLLIE_DURABLE_SOCKET |
| Modes | Le socket est en mode 0600, dans un dossier en mode 0700. L'agent durable supprime un fichier socket obsolète avant d'écouter |
| Le parcours du chemin | Avant chaque connexion, Collie vérifie chaque segment du chemin avec lstat. Aucun segment n'est un lien symbolique. Le dossier du socket vous appartient avec le mode 0700. Aucun dossier parent n'est accessible en écriture par le groupe ou les autres, sauf s'il possède le sticky bit comme /tmp. Le socket vous appartient, sans droit pour le groupe ou les autres |
| Un parcours en échec | Collie ne se connecte pas et affiche l'agent durable comme injoignable avec socket-not-private et le segment en cause |
| Token | Aucune. Le socket privé sert de barrière |
| Qui peut agir | Tout processus de votre utilisateur. L'agent durable peut refuser ses propres descendants avec 403 caller-refused |
| Délais d'expiration | 1000 ms pour hello, snapshot et events. 3000 ms pour une réponse, un envoi, un arrêt, une action, un renommage ou une fermeture. 30000 ms pour un démarrage |
| Fréquence des requêtes de Collie | Toutes les 1 s lorsqu'un téléphone observe, sinon toutes les 3 s. Un agent durable arrêté est interrogé une fois par intervalle de scrutation |
| Systèmes | Linux et macOS. Windows n'a pas de transport par socket |
| via TLS | la règle |
|---|---|
| URL | https://, ou http://127.0.0.1:<port> ou http://localhost:<port> pour un test local. 2048 octets au maximum, aucun nom d'utilisateur ni mot de passe, aucune requête, aucun fragment. Collie y ajoute /session/v1 |
| Token | Au moins 32 octets, en ASCII imprimable sans espace. Collie envoie Authorization: Bearer <token> à chaque requête, hello inclus |
| La vérification de l'agent durable | Le token d'abord, avant la version, hello et ready, comparé en temps constant. Un token manquant ou incorrect reçoit un simple 401 { "code": "unauthorized" } et rien d'autre |
| Redirections | Collie n'en suit aucune. Un 3xx est transmis comme statut, afin que le token n'atteigne jamais un autre hôte |
| ETag | Un proxy qui compresse une réponse peut affaiblir le tag en W/"<epoch>-<rev>". Les deux côtés le comparent en retirant le W/ |
| Un refus | Un 401 ou un 403 affiche l'agent durable comme injoignable avec token-refused |
| Délais d'expiration | 5000 ms pour chaque lecture et écriture, car un agent durable en veille peut se réveiller à froid. 30000 ms pour un starter |
| Fréquence des requêtes de Collie | Toutes les 2 s lorsqu'un téléphone observe, sinon toutes les 10 s. Un agent durable arrêté ou refusé est interrogé au maximum une fois toutes les 10 s |
Chaque timeout est une échéance pour l'ensemble de l'échange, de la connexion au dernier octet. Via TLS, chaque scrutation est une requête que votre hébergeur peut facturer, 304 inclus.
Limites
Collie coupe ou refuse tout ce qui dépasse ces limites, ainsi un agent durable qui reste en deçà ne perd rien.
| quoi | limite |
|---|---|
| Espaces de travail par snapshot | 64 |
| Onglets par snapshot | 256 |
| Panneaux par snapshot | 256 |
| Demandes ouvertes par panneau | 50, les plus anciennes d'abord |
Options d'un permission | 6 |
Options d'un choice, et d'un champ de choix | 8 |
Champs d'un form | 6 |
| Starters par snapshot | 50 |
| Boutons de ceinture par panneau | 4, un libellé de 16 caractères |
| Un identifiant | 1 à 128 octets, aucun caractère de contrôle, aucun espace, aucun parmi /, ? ou # |
| Un corps de requête | 64 Kio, sinon 413 too-large |
| Réponses | hello 16 Kio, snapshot 4 Mio, events 8 Mio, conversations 1 Mio, items 8 Mio, un POST 16 Kio |
| Événements par réponse | 1000. Un lecteur qui a pris du retard reçoit la vue actuelle, au maximum les 2000 éléments les plus récents |
Texte d'un élément user, reply, thinking ou notice | 64 Kio |
Texte d'un élément markdown ou code | 32 Kio |
| Texte envoyé par le téléphone | 32 Kio |
Un élément link | https:// uniquement, au maximum 2048 caractères |
| Une page d'historique | 100 conversations, ou 1000 éléments |
| Un curseur d'historique | 512 octets d'ASCII imprimable, aucun espace |
Une chaîne dépassant sa limite est tronquée, et ses caractères de contrôle et invisibles sont supprimés. Une liste dépassant sa limite conserve ses premiers éléments. Une page d'historique dépassant sa limite n'est pas lue du tout.
Versions et hello explicatif
Il existe aujourd'hui une seule version de protocole, 1, et Collie utilise 1..1.
À la sortie de la version 2, Collie acceptera la version 1 pendant une version mineure supplémentaire, puis l'abandonnera à la suivante. Un lecteur ignore les champs, les types d'événements, les sortes d'éléments ou les codes qu'il ne connaît pas. Un champ ajouté au sein de la version 1, tel que expiresAt ou decidedBy, est facultatif. Un nouveau champ obligatoire, une nouvelle signification pour un ancien champ, ou un champ supprimé nécessite une nouvelle version.
Une demande d'une sorte inconnue du téléphone s'affiche comme une demande à laquelle il ne peut pas répondre depuis le téléphone, sans boutons.
Lorsque les deux plages ne se recoupent pas, Collie ne lit plus rien de l'agent durable. Une fois par époque de l'agent durable, il envoie un hello supplémentaire, cette fois avec sa propre version, pour que l'agent durable puisse consigner l'incompatibilité de son côté. L'agent durable répond 409 incompatible avec un refusal qui indique les deux plages. C'est le hello explicatif.
Collie écrit une ligne dans ses journaux pour chaque plage qu'il refuse, et collie doctor affiche les deux plages. L'écran d'accueil de l'agent durable sur le téléphone affiche la même phrase, par exemple « The durable agent speaks wire v2, this Collie speaks v1. Update Collie, or the agent's SDK. ». Mettez à jour le composant le plus ancien.
Où trouver les règles exactes
WIRE.md constitue le contrat, avec chaque format, code et règle.
Les décisions associées sont consignées dans le dépôt :
| enregistrement | ce qu'il décide |
|---|---|
| ADR 0099 | Un agent durable est un multiplexeur sans écran |
| ADR 0100 | Une demande circule sous forme de données et reçoit une réponse par identifiant |
| ADR 0101 | Send et stop nomment le tour vu par le téléphone |
| ADR 0102 | Les lanceurs sont des lignes sur la page New |
| ADR 0103 | Les deux transports |
| ADR 0104 | Un agent durable est une session, et la sortie |
| ADR 0105 | Le SDK est un paquet npm |
Modifier cette page sur GitHub