Communitygithub.com

CounterCall

📞 CALL-E téléphone à un guichet administratif indonésien avant que vous n'y alliez et renvoie une liste de contrôle validée de ce qu'il faut apporter — et laisse la ligne vide quand l'agent ne savait pas.

Qu'est-ce que CounterCall ?

CounterCall est une compétence pour l'agent vocal CALL-E qui automatise les appels téléphoniques vers les guichets administratifs publics en Indonésie (comme les Samsat) pour obtenir une liste à jour et validée des documents requis. Au lieu de faire perdre une journée de salaire à un usager à cause d'informations incomplètes ou obsolètes, le skill passe l'appel, pose les questions structurées et renvoie un résultat formaté en checklist, avec les réponses textuelles de l'agent et les éventuelles limitations (incertitude, non-réponse). Il est conçu pour des appels à faible fréquence mais à fort enjeu personnel, où un humain devrait autrement recomposer sans arrêt. Le skill vérifie rigoureusement que le numéro est en format E.164, refuse de deviner un numéro, et applique des contraintes de sécurité strictes : un seul appel par bureau/procédure/jour, pas d'appels en dehors des heures d'ouverture, et résultat non contraignant juridiquement. Il est idéal pour les plateformes comme CALL-E, et son code inclut une vérification pré-dial du contrat de résultat pour détecter toute dérive du schéma de données.

Compatible avec~Claude Code~Codex CLI~Cursor
npx skills add edycutjong/countercall

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

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ésultatCe que l'utilisateur voit
résultat validela 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_invalidl'appel a abouti mais la réponse ne correspondait pas au contrat. Mis en quarantaine
result_unavailablel'appel a abouti mais n'a produit aucune réponse structurée. Pas de liste
result_failedla 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_failedl'appel n'a pas pu aboutir. Pas de liste
canceledannulé 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.

Skills associés