Que fait CounterCall ?
Pak Yanto a pris congé le matin, a roulé quarante minutes jusqu'au guichet Samsat, et a été r envoyé parce que sa photocopie était en format folio au lieu de A4. Il a perdu une journée de salaire, et il ne savait toujours pas ce qui manquait d'autre pour demain.
Les guichets des services publics publient des listes de documents requis qui sont incomplètes, obsolètes ou discrètement contredites au guichet. La seule source fiable est la ligne téléphonique du bureau, et cette ligne est occupée, filtrée par serveur vocal interactif, et répondue au quatrième essai. Donc les gens n'appellent pas. Ils se déplacent, ils font la queue, et ils sont r envoyés pour un seul document.
Cette compétence passe l'appel à leur place, et renvoie une liste de contrôle que la personne peut capturer d'écran et emporter avec elle.
Elle correspond bien à la conception de CALL-E : travail téléphonique à faible fréquence, personnel, à enjeux élevés vers un numéro qu'un humain devrait sinon recomposer tout le matin.
Avant de commencer
Cette compétence passe un véritable appel téléphonique vers un véritable bureau public. Confirmez avec l'utilisateur :
- quelle procédure il demande, dans les mots du bureau lui-même
- quel bureau, et le numéro de téléphone au format E.164, à partir de la page officielle du bureau
- qu'il souhaite qu'un appel soit passé maintenant
Ne devinez jamais un numéro de téléphone. Pas à partir d'un annuaire, pas à partir d'un bureau similaire, pas en devinant un indicatif de pays. Un numéro entre dans le flux uniquement lorsqu'un humain l'a lu sur la page officielle du bureau. Appeler le mauvais numéro signifie qu'un appelant automatisé atteint un inconnu, ce qui est la pire chose que cette compétence puisse faire.
Limites de sécurité
Cette compétence recueille uniquement les exigences du guichet.
- Elle ne soumet pas de demande, ne prend pas de rendez-vous, ne paie pas de frais, ni n'engage l'utilisateur à quoi que ce soit. Elle demande et rapporte.
- Elle ne donne pas de conseils juridiques ou d'immigration. Si un agent suggère une voie alternative, rapportez-la textuellement comme quelque chose que l'agent a dit, jamais comme une recommandation.
- La réponse verbale d'un agent est informative, non juridiquement contraignante, et chaque résultat rendu le mentionne. Les exigences changent et les guichets individuels appliquent une certaine discrétion.
- Elle indique clairement au début de l'appel qu'il s'agit d'un assistant automatisé, et pourquoi elle appelle. Si la personne refuse de répondre, elle la remercie et met fin à l'appel. Elle ne persiste pas, ne redemande pas, et ne rappelle pas le même jour.
- Un appel par bureau et par procédure et par jour. Ce sont des lignes de service public gérées par des personnes qui ont une file d'attente devant elles. La clé d'idempotence l'applique ; ne la retirez pas.
- Lorsque l'agent n'est pas sûr, le résultat indique "pas sûr". Elle ne comble jamais un vide avec ce qui est typique, et ne présente jamais une hésitation comme un fait. Une personne peut traverser une ville sur la base de cette réponse.
- Elle appelle les bureaux uniquement pendant leurs heures d'ouverture publiées. Une ligne publique qui sonne à 22h n'est pas une donnée, c'est une nuisance.
Lisez references/safety.md avant d'adapter cette compétence à une nouvelle institution. Certains interlocuteurs
ne sont pas des cibles appropriées pour un appel automatisé.
Ce qui la distingue d'une transcription
La plupart des compétences d'appel renvoient du texte et laissent le lecteur l'interpréter. Celle-ci renvoie un objet validé et épinglé, et refuse de renvoyer autre chose.
Le result_schema du Goal définit additionalProperties: false et contraint quatre champs à des
énumérations — payment_method, appointment_required, originals_or_copies et
clerk_certainty, chacun incluant une valeur pour "l'agent ne savait pas". Si l'appel revient avec une forme différente, le résultat est mis en quarantaine plutôt
que rendu. Une checklist à moitié parsée est pire qu'aucune checklist, car l'utilisateur agit
en fonction d'elle.
Le contrat complet se trouve dans references/result-contract.md.
Workflow
1. Recueillir la demande
Requis : le nom de la procédure, le nom du bureau, le numéro de téléphone du bureau au format E.164, et l'URL de la source publiée d'où provient le numéro.
Validez le numéro avant toute autre chose. E.164 est un plus, un chiffre d'indicatif de pays non nul, puis 7 à 14 chiffres supplémentaires : ^\+[1-9]\d{7,14}$. Rejetez tout autre format et demandez à l'utilisateur. Ne devinez jamais un indicatif de pays. Un numéro au format local atteignant le composeur est ainsi que la mauvaise personne est appelée.
Exécutez scripts/preflight.mjs pour vérifier le numéro et le contrat sans composer.
2. Vérifier que le contrat publié n'a pas dérivé
Avant chaque exécution, lisez l'interface Goal en direct et comparez-la au contrat pour lequel cette compétence a été écrite.
import { diffContract, publishedRunSpec } from './scripts/_lib.mjs';
const goal = await client.goals.get(GOAL_ID);
const drift = diffContract(PINNED_CONTRACT, publishedRunSpec(goal));
if (drift.length) throw new ContractDrift(drift); // refuser de composer
Utilisez l'assistant publishedRunSpec(goal), pas goal.published_run_spec directement. Le format wire et la documentation l'écrivent published_run_spec.result_schema ; le SDK TypeScript le camelCase en publishedRunSpec.resultSchema. Lire uniquement le nom documenté avec le client TS renvoie undefined au lieu de lever une exception — le garde conclut alors "aucune spec publiée" et refuse chaque composition tout en semblant fonctionner. L'assistant lit les deux orthographes. Cela nous a coûté une journée ; c'est documenté dans FEEDBACK.md à la racine du dépôt.
La documentation CALL-E recommande cette comparaison avant de déployer un changement de variable. Le faire à chaque exécution coûte un appel API et transforme un échec silencieux en un refus bruyant. Composer un vrai numéro avec un schéma obsolète produit un résultat qui semble correct mais est discrètement erroné.
3. Passer un seul appel
goals.run avec une Idempotency-Key limitée au bureau, à la procédure et à la date, afin qu'une relance ne double jamais une ligne publique :
countercall:{office}:{procedure}:{yyyy-mm-dd}:v1
4. Interroger jusqu'à un résultat ou une erreur
goals.waitForResult a une règle d'achèvement : s'arrêter lorsque soit result soit error n'est pas nul. Un appel terminé peut brièvement renvoyer les deux nuls pendant que CALL-E analyse le résultat structuré, donc ne traitez pas cette fenêtre comme un échec.
5. Rendre, ou échouer honnêtement
Les huit codes GoalRunError publiés mènent à un résultat distinct. L'ensemble ci-dessous est celui que scripts/render.mjs implémente — gardez-les synchronisés si CALL-E ajoute un code.
| Résultat | Ce que l'utilisateur voit |
|---|---|
| résultat valide | la liste de contrôle, avec la ligne textuelle de l'agent et l'URL source |
no_answer | "la ligne n'a pas répondu". Pas de liste |
declined | "le bureau a refusé de répondre à un appelant automatisé". Pas de liste |
result_invalid | l'appel a abouti mais la réponse ne correspondait pas au contrat. Mis en quarantaine |
result_unavailable | l'appel a abouti mais n'a produit aucune réponse structurée. Pas de liste |
result_failed | la réponse n'a pas pu être transformée en liste de contrôle. Pas de liste |
timed_out | "aucune réponse utilisable" avant la date limite. Pas de liste |
call_failed | l'appel n'a pas pu aboutir. Pas de liste |
canceled | annulé avant d'avoir produit une réponse. Pas de liste |
Aucune branche ne rend une liste partielle. Des exemples travaillés de chacun se trouvent dans references/examples.md.
Exécution
scripts/call.mjs est en mode simulation par défaut. Il affiche la requête exacte qu'il enverrait et ne passe aucun appel. La composition nécessite un --live explicite :
# simulation — affiche la requête, ne compose rien, ne nécessite pas d'identifiants
node scripts/call.mjs --office <id> --procedure "<procedure>"
# fait réellement sonner un téléphone
node scripts/call.mjs --office <id> --procedure "<procedure>" --live
Une compétence qui compose par défaut est une compétence qui compose par accident.
data/offices.json est livré avec son numéro de téléphone masqué (+62XXXXXXXXXX), de sorte que l'entrée initiale ne peut pas composer et que toute commande contre elle se termine par le code 3 avec REFUSING TO DIAL. C'est délibéré : un numéro entre dans le fichier uniquement lorsqu'un humain l'a lu sur la page officielle du bureau et a enregistré source_url et source_checked. Ajoutez votre propre entrée avant d'exécuter quoi que ce soit.
Pour voir immédiatement la sortie de la simulation, le fixture de test porte un numéro fictif valide :
node scripts/call.mjs --offices ../../test/fixtures/offices.test.json \
--office fixture-sourced --procedure "perpanjangan paspor"
Quand ne pas l'utiliser
- Urgences. C'est une recherche de documents avec une latence de plusieurs minutes. Ce n'est pas un moyen de joindre quelqu'un en urgence.
- Bureaux disposant d'une page d'exigences publiée, fiable et à jour. Si le site Web est correct, lisez le site Web. L'appel est justifié uniquement lorsque la réponse publiée est connue pour être incomplète.
- Toute institution qui a demandé à ne pas être appelée par des systèmes automatisés, ou là où la législation locale restreint les appels automatisés. Vérifiez avant d'ajouter un bureau.
- Recherches à grand volume. Un bureau par procédure par jour est le plafond par conception. Si vous avez besoin de volume, vous avez besoin d'un accord de partage de données, pas d'un téléphone.
- Tout ce pour quoi une erreur est sans conséquence. La valeur ici vient du coût d'un voyage inutile. Si l'utilisateur peut simplement y aller et le découvrir, laissez-le faire.
Limites honnêtes
- La couverture est limitée aux bureaux du fichier d'origine, chacun avec une URL de source publiée.
- Les taux de réponse sur les lignes de service public varient selon le bureau et l'heure de la journée, et une grande partie des appels ne seront pas répondus. Cette imprévisibilité est la raison d'être de cette compétence, et elle est rapportée, non cachée.
- Le résultat est la réponse d'un seul agent un seul jour. C'est une preuve, pas une garantie.