Aller au contenu

Missions en arrière-plan

Une mission en arrière-plan confie un travail à ton serveur Pia et le laisse s’exécuter là-bas : des missions que votre serveur Pia exécute pour vous, à partir des éléments que vous choisissez. Chaque réponse revient sous forme de conversation. Elle survit à la fermeture de l’application, elle n’est pas liée à un tour de conversation, et le rôle du client est d’indiquer exactement ce qui quitte l’appareil, de récupérer le résultat, et de le remettre dans le plan chiffré.

La moitié serveur est le plan de tâches de Pia Mesh : une mission est exécutée par un opérateur qui fait tourner une compétence, et le client ne s’adresse jamais directement à un opérateur — seulement à un nom de compétence que le serveur autorise cet utilisateur à exécuter.

Au chargement, le client interroge GET /api/assignments/skills. Tout ce qui n’est pas une liste renseignée — aucune URL de serveur configurée, aucun jeton d’accès, 401/403/404, ou un tableau vide — se traduit par une interface masquée. Les points d’entrée sont alors absents, pas désactivés : un serveur qui ne propose pas les missions produit un client qui n’en garde aucune trace.

Point d’entrée Affiché quand
Missions dans le panneau de navigation latéral l’interface est disponible et la fenêtre est en mode Assistant
Le bouton fusée dans la ligne d’actions du compositeur de l’assistant — Confier ceci à votre serveur Pia comme mission en arrière-plan l’interface est disponible

Le résultat de l’interrogation porte les compétences accordées aux groupes de cet utilisateur, chacune avec son mode de conversation et son declaredInputTypes. Les deux points d’entrée ouvrent la même boîte de dialogue de consentement ; celui du compositeur préremplit la demande avec ce qui y est déjà tapé et laisse le texte du compositeur intact, car un brouillon appartient à la destination que l’utilisateur confirme, quelle qu’elle soit.

La boîte de dialogue s’intitule Envoyer à votre serveur Pia, et tout ce qui suit tient sur un seul écran — la confirmation se fait là où se trouve la liste de ce qui part, pas une page plus loin.

  • Compétence — un sélecteur uniquement si plusieurs compétences sont accordées ; sinon, la seule disponible s’affiche, avec Mode : indiquant le mode de conversation déclaré par la compétence (Research, Assistant). Le mode est celui du serveur, pas un choix : l’appelant ne peut pas orienter une mission vers un autre mode.
  • Que doit-il faire ? — la demande, avec pour indication Décrivez le travail avec vos propres mots, plafonnée à 4 000 caractères.
  • Éléments à envoyer — le sélecteur, qui ne liste que les types d’éléments déclarés par la compétence choisie.

Trois états remplacent la liste plutôt que d’en afficher une vide :

État Message affiché
La compétence ne déclare aucun type d’élément Cette compétence travaille uniquement à partir de votre demande. Aucun élément n’est envoyé, mais votre demande l’est — en clair.
La compétence déclare des types, mais tu n’as aucun élément de ce type Vous n’avez aucun élément que cette compétence puisse utiliser. Vous pouvez tout de même envoyer votre demande seule, en clair.
La lecture locale a échoué Vos éléments n’ont pas pu être lus ; aucun ne peut donc être répertorié ni envoyé.

Le dernier compte : dire « vous n’avez aucun élément » est une affirmation sur tes données, donc une lecture qui a échoué le dit plutôt que d’y répondre.

Un total s’affiche sous la liste — {selected} sur 20 éléments · {chars} sur 32 000 caractères — et l’action principale Envoyer non chiffré n’est activée que lorsqu’une compétence est sélectionnée, que la demande n’est pas vide et reste dans sa limite, que la sélection respecte les deux plafonds, que le chargement des éléments est terminé, que la case de confirmation Je comprends que ces éléments quittent le chiffrement de bout en bout est cochée, et que rien n’a encore été envoyé.

Le vocabulaire se limite au contenu rédigé par l’utilisateur. Les fournisseurs, les paramètres, les certificats, les plugins et leurs préférences n’en font pas partie, et aucune compétence n’a de raison de les lire.

Dans la boîte de dialogue entityType de l’enveloppe Source locale Ce qui est envoyé comme texte de l’élément
Conversation assistantChat Conversations de l’assistant Chaque message sous la forme role: content, du plus ancien au plus récent
Session session Historique Optimiser Le texte d’origine et le résultat, les deux moitiés
Mémoire memory Coffre de Mémoire Le libellé et l’entrée
Tâche todo Todos Le titre et ses notes
Modèle template Modèles personnalisés La description et le prompt

Les modèles intégrés sont exclus : ce sont des constantes côté client qui ne se synchronisent jamais et qui ne sont pas l’écriture de l’utilisateur, donc ce n’est pas à lui de consentir à leur envoi. Le sélecteur propose jusqu’à 50 éléments récents de chaque type déclaré — l’enveloppe n’en prend de toute façon que 20 au maximum — et un type qu’un serveur plus récent déclare mais que cette version ne sait pas lire n’apporte rien plutôt que de faire échouer la boîte de dialogue.

Le client refuse selon les mêmes constantes que celles imposées par le serveur, afin qu’une sélection trop volumineuse ne se transforme jamais en 400 que l’utilisateur ne peut pas traiter.

Plafond Valeur
Éléments par mission 20
Caractères par élément 8 000
Caractères sur l’ensemble des éléments 32 000
Demande 4 000

Un élément dépassant le plafond est listé comme non envoyable — Au-delà de la limite de 8 000 caractères pour un seul élément : il ne peut pas être envoyé. — et jamais tronqué : un utilisateur qui confirme l’envoi d’un élément et n’en envoie qu’un cinquième n’a pas répondu à la question qu’on lui a posée. Cocher un élément de trop, ou un élément qui ferait dépasser 32 000 caractères au total, est refusé avec une raison explicite plutôt qu’une troncature silencieuse.

Trois affirmations, textuellement, parce que ce sont celles sur lesquelles porte la confirmation :

Cela quitte le chiffrement de bout en bout. Les éléments ci-dessous sont envoyés en clair à votre serveur Pia et y sont stockés non chiffrés pendant le travail.

Le texte en clair est supprimé au plus tard 72 heures après la fin de l’exécution, que cet appareil récupère le résultat ou non. Ce qui subsiste plus longtemps, ce sont les métadonnées de l’exécution — état, nombre d’étapes et jetons consommés —, qui ne contiennent aucun de vos contenus.

Tant qu’il s’y trouve, toute personne ayant accès à votre serveur Pia peut le lire.

Après Envoyer non chiffré, une ligne indique ce qui s’est passé :

Résultat Message
Démarrée La mission a démarré. Sa réponse arrivera sous forme de conversation une fois l’exécution terminée.
Pas de reçu, ou un reçu qui ne correspond pas à la sélection Rien n’a été envoyé : cette sélection n’a pas été confirmée.
Au-delà d’un plafond Rien n’a été envoyé : la sélection dépasse une limite de taille.
Le serveur l’a refusée, ou n’a pas pu être joint Rien n’a été envoyé : votre serveur Pia a refusé la mission.
La boîte de dialogue n’a pas pu être menée à son terme Rien n’a été envoyé : la mission n’a pas pu démarrer.

Missions en arrière-plan répertorie les exécutions de cet utilisateur : la propre page du serveur (GET /api/assignments, 50 lignes) associée au journal local de cet appareil. Le serveur sait dans quel état se trouve une exécution ; seul cet appareil sait ce qui a été demandé et quelle conversation contient la réponse.

Colonne Remarques
Compétence Le nom d’affichage de la compétence issu de l’interrogation des compétences, avec repli sur son nom technique
Statut En attente, En cours, Terminée, Échouée, Annulée — le vocabulaire du serveur lui-même — plus Inconnue pour une valeur que cette version ne reconnaît pas
Étapes Étapes : {n}, affiché dès qu’une exécution en a franchi une. La progression est un nombre d’étapes, jamais un pourcentage : une compétence à une seule étape est honnêtement juste en cours d’exécution, et une fraction inventée à partir d’un nombre d’étapes devient un mensonge dès que le nombre de passes d’une compétence change
Durée écoulée moins d’une minute, {n} min, {h} h {m} min, mesurée entre la création de la ligne et sa fin ou maintenant

Les lignes proviennent du serveur, donc une exécution lancée sur un autre appareil apparaît quand même — sans sa demande ni de conversation à ouvrir, marquée Lancée depuis un autre appareil : sa demande et sa réponse ne sont pas sur celui-ci. Son résultat est allé dans le magasin de conversations de cet autre appareil.

  • Ouvrir la conversation apparaît une fois que l’exécution a été récupérée sur cet appareil.
  • Annuler apparaît tant qu’une exécution est En attente ou En cours. Le retour est Votre serveur Pia a été invité à arrêter cette exécution., ou Votre serveur Pia n’a pas arrêté cette exécution : elle était peut-être déjà terminée. quand le serveur n’avait rien à annuler, ou Cette exécution n’a pas pu être annulée. en cas d’erreur. Une exécution annulée atterrit malgré tout dans un état terminal, donc son résultat est quand même stocké et quand même récupéré — annuler arrête le travail, ça n’abandonne pas le texte en clair.
  • Actualiser est manuel, et la vue interroge aussi le serveur toutes les 10 secondes tant qu’elle est affichée. Quitter la vue arrête l’interrogation ; une liste que personne ne regarde n’en maintient pas une en vie.
  • Une lecture qui échoue ne vide jamais la liste. Elle affiche Votre serveur Pia n’a pas pu être joint ; cette liste n’est donc peut-être pas à jour. et laisse les lignes telles quelles, parce qu’une lecture restée sans réponse ne doit pas être présentée comme « rien n’a été lancé ».
  • S’il n’y a aucune exécution du tout : Rien n’a encore été lancé. Démarrez une mission : sa réponse apparaîtra ici, et en conversation, dès que l’exécution sera terminée.

Un passage en arrière-plan s’exécute au démarrage de l’application, puis toutes les 20 secondes. Il lit d’abord un fichier local mis en cache, donc un passage sans rien en attente ne coûte rien et ne touche jamais le réseau — ce n’est pas une interrogation d’un serveur que l’utilisateur n’a peut-être même pas. Le passage au démarrage est tout l’intérêt de la manœuvre : fermer l’application en pleine exécution ferait sinon perdre le résultat silencieusement, puisque le serveur supprime le texte en clair, que quelqu’un revienne le chercher ou non.

Pour chaque exécution terminée, l’ordre est fixe et n’est pas affaire de goût :

  1. Lire la mission, y compris son résultat.
  2. L’écrire localement comme une conversation d’assistant ordinaire.
  3. Alors seulement POST /api/assignments/{id}/collect, qui supprime la copie en clair du serveur.

La récupération (collect) est irréversible, c’est pourquoi elle vient en dernier : accuser réception d’abord puis échouer à l’écriture locale détruirait le résultat sans plus rien à récupérer. Si l’écriture échoue, l’entrée en attente survit et le passage suivant réessaie. L’identifiant de la conversation est créé avant que l’exécution ne démarre, de sorte qu’une nouvelle tentative écrase sa propre conversation au lieu d’en créer une seconde.

La conversation porte la demande comme message de l’utilisateur et le résultat comme message de l’assistant, avec un titre tiré de la première ligne de la demande (60 caractères). Une exécution qui s’est terminée sans résultat — échouée ou annulée — produit quand même la conversation, en l’indiquant avec le code d’erreur ou l’état de l’exécution, de sorte qu’un résultat n’est jamais simplement absent.

Une fois qu’une exécution est stockée et acquittée, le client la signale une fois : une carte Flow persistante — Mission en arrière-plan, Terminé — appuyez pour consulter ou Non terminé — appuyez pour consulter — plus une notification dans l’application quand la fenêtre de l’assistant est au premier plan, ou une notification Windows (toast) sinon (Votre mission est terminée — la réponse se trouve dans une conversation / Votre mission ne s’est pas terminée — la conversation indique ce qui est revenu). Chacune propose Ouvrir la conversation.

Si le serveur cesse de répondre pour une exécution — la ligne a été supprimée, ou la fenêtre de texte en clair est passée — le client l’abandonne 7 jours après son démarrage. Rien n’est perdu pour autant : passé la fenêtre de texte en clair, l’entrée et le résultat ont tous deux disparu, donc il n’y avait de toute façon plus rien à récupérer.

Quoi Valeur
Actualisation de la liste des missions Client, uniquement pendant que la vue est affichée 10 s
Passage de récupération Client, dès le démarrage ; inactif quand rien n’est en attente 20 s
Abandon d’une exécution à laquelle le serveur ne répond plus Client 7 jours après son démarrage
Le serveur supprime l’entrée, le résultat et le texte d’erreur Serveur, Operators:PlaintextRetentionHours 72 h après la fin de l’exécution (par défaut)
Une exécution récupérée reste dans le journal local Client 30 jours
La ligne du serveur et ses événements sont supprimés Serveur, Operators:RetentionDays 30 jours (par défaut)

La limite d’abandon du client se situe délibérément au-delà de la fenêtre de texte en clair du serveur, pour qu’un ordinateur portable resté fermé un long week-end récupère quand même son résultat, et largement en deçà de la propre rétention de la ligne, moment auquel il ne reste de toute façon plus rien à récupérer.

Fichier Contient
%LOCALAPPDATA%\Pia\ConsentAudit\assignments.jsonl Une ligne JSON en ajout seul par confirmation : identifiant de l’enregistrement, horodatage, compétence, mode, nombre d’éléments, total de caractères, et pour chaque élément son type d’entité, son identifiant et son nombre de caractères. Métadonnées uniquement — aucun titre, aucun contenu
%APPDATA%\Pia\pending-assignments.json Une entrée par exécution démarrée ici : identifiant de la mission, identifiant de la conversation, compétence, demande, heure de démarrage, et l’heure de récupération une fois qu’elle en a une

Le fichier en attente est conservé après récupération plutôt que supprimé, parce que c’est la seule chose qui puisse encore indiquer quelle conversation contient la réponse d’une exécution donnée : la demande voyage à l’intérieur de l’entrée que le serveur supprime, et la projection de la liste ne l’a jamais portée.

  • Rien de headless ne peut démarrer une exécution. Le chemin d’envoi prend un reçu de consentement comme argument obligatoire, et seul le magasin de consentement — en écrivant l’enregistrement et en attendant le disque — peut en créer un. Un reçu est limité à la session, donc un reçu qui a survécu au processus dans lequel il a été accordé ne prouve rien. Le blocage est aussi une question de direction des dépendances plutôt qu’une vérification à l’exécution : un test garantit qu’aucun point d’entrée en arrière-plan ne prend l’orchestrateur en dépendance.
  • Une décision de consentement n’est jamais mémorisée, et un reçu n’autorise exactement que la sélection pour laquelle il a été accordé : la compétence et l’ensemble des éléments sont revérifiés avant toute lecture.
  • Une exécution démarrée sur un autre appareil ne peut pas être récupérée ici. Son résultat est allé dans le magasin de conversations de cet autre appareil, et sa demande n’a jamais été sur celui-ci.
  • Une mission terminée ne peut pas être relancée ni modifiée depuis la liste. Une nouvelle exécution est une nouvelle décision de consentement.
  • Après la récupération, le résultat n’existe plus que dans la conversation locale. La copie du serveur a disparu, et plaintextDroppedAt sur la ligne enregistre qu’elle est partie.