Aller au contenu

Agents

Un agent d'IA qui a besoin d'une adresse canadienne, d'une coordonnée ou d'un itinéraire se heurte au même problème qu'une personne développeuse à son premier jour : il doit apprendre qu'unmap existe, découvrir ce qu'unmap sait faire, obtenir une clé, puis effectuer un appel. Une personne règle cela en lisant. Un agent ne peut pas lire, alors unmap publie ces mêmes réponses sous forme de documents conçus pour les machines, et expose un point de terminaison qu'un agent peut appeler directement.

Cette page couvre (1) les documents qu'un agent lit pour découvrir unmap, (2) la carte d'agent A2A et ce qu'elle promet, (3) les huit compétences que la carte annonce et la façon d'invoquer chacune, (4) les erreurs que le point de terminaison renvoie et leur signification, et (5) les outils que le site enregistre pour un agent qui travaille dans un navigateur. Si vous écrivez du code applicatif ordinaire plutôt qu'un agent, Appeler l'API directement est la page qu'il vous faut ; tout ce qui suit s'appuie sur les points de terminaison qui y sont décrits.

Découverte

Six documents non authentifiés décrivent unmap à une machine. La plupart sont servis depuis https://unmap.dev et depuis https://api.unmap.dev, de sorte qu'un agent partant de l'un ou l'autre hôte trouve le reste.

  • /.well-known/agent-card.json est la carte d'agent A2A : l'identité d'unmap, ses compétences, ses schémas de sécurité et l'adresse du point de terminaison qui les exécute. C'est le point d'entrée pour un cadriciel d'agents. Les deux hôtes en servent les mêmes octets.
  • /openapi.json est une description OpenAPI 3.1 de chaque point de terminaison REST, sur api.unmap.dev uniquement. C'est le point d'entrée pour un générateur de code ou un agent qui préfère du HTTP ordinaire.
  • /.well-known/api-catalog est un jeu de liens RFC 9727 qui nomme l'API et pointe vers les deux documents ci-dessus.
  • /.well-known/oauth-protected-resource est la métadonnée RFC 9728 : ce qu'est cette ressource et comment un identifiant porteur se présente. Elle ne nomme aucun serveur d'autorisation, puisqu'unmap n'en exploite aucun, et chaque 401 y renvoie.
  • /auth.md explique en prose d'où vient une clé. unmap n'exploite aucun serveur d'autorisation OAuth et n'offre pas d'auto-inscription aux agents : une clé est créée par une personne dans le tableau de bord, puis confiée à l'agent. Il est servi depuis api.unmap.dev, et unmap.dev/auth.md y redirige. Voir Authentification.
  • /.well-known/agent-skills/index.json, sur unmap.dev, recense quatre compétences en Markdown qui apprennent à un agent à appeler l'API HTTPS ordinaire, y compris la moitié cartographique que le point de terminaison ci-dessous ne couvre pas.

Le serveur MCP en publie trois autres qui lui sont propres, décrits sur Serveur MCP.

Chaque page de cette documentation est aussi disponible en Markdown. Demandez-la avec un en-tête Accept et vous obtenez la source plutôt que la page rendue :

curl -H "Accept: text/markdown" https://unmap.dev/fr/docs/agents/a2a

La carte d'agent

La carte suit A2A v1.0 et se trouve au chemin bien connu que la spécification nomme :

curl https://unmap.dev/.well-known/agent-card.json
{
  "name": "unmap",
  "description": "Canadian geocoding and routing as an agent-callable service. …",
  "supportedInterfaces": [
    { "url": "https://api.unmap.dev/a2a", "protocolBinding": "JSONRPC", "protocolVersion": "1.0" }
  ],
  "version": "2.0.0",
  "capabilities": { "streaming": false, "pushNotifications": false, "extendedAgentCard": false },
  "skills": [ /* cinq, décrites plus bas */ ]
}

La carte déclare une seule interface, et cette interface est un véritable point de terminaison. supportedInterfaces[0].url est l'adresse à laquelle un client A2A envoie SendMessage, et https://api.unmap.dev/a2a y répond. Cela mérite d'être dit clairement, car une carte est une promesse plutôt qu'une description : en publier une qui pointe vers une machinerie inexistante ferait perdre son temps à chaque client qui l'aurait crue.

Trois capacités valent false, chacune pour une raison :

  • streaming : un géocodage ou un itinéraire est un aller-retour qui se termine en quelques millisecondes. Il n'y a rien à diffuser en continu.
  • pushNotifications : unmap ne crée aucune Task A2A. Chaque compétence répond de façon synchrone par un Message, il n'y a donc aucun état asynchrone à signaler par un webhook. Les méthodes de tâches (GetTask, CancelTask) répondent -32001 Task not found, ce qui est exact : il n'y a pas de tâches.
  • extendedAgentCard : un client authentifié voit exactement cette carte. Le document OpenAPI, cette documentation et la tarification sont tous publics, une seconde carte plus riche n'aurait donc rien de plus à contenir.

Authentification

Le point de terminaison accepte la même clé d'API que le reste de l'API, dans un en-tête :

Authorization: Bearer um_live_...

X-API-Key: um_live_... fonctionne également ; la carte présente les deux comme des solutions de rechange l'une de l'autre. La troisième forme acceptée par l'API REST, ?key=, est délibérément absente de la carte. Elle existe parce que MapLibre ne peut pas joindre d'en-têtes aux requêtes qu'il déclenche pour les tuiles, et un client A2A n'a pas cette contrainte. Une clé active dans une URL finit dans les journaux et les référents.

Un appel sans clé reçoit un HTTP 401 accompagné d'un défi WWW-Authenticate, et non un corps d'erreur JSON-RPC, afin que le défi parvienne au client qui en a besoin. Il en va de même pour le 429 (limite de débit ou quota, avec Retry-After) et le 503 (un service encore en démarrage). Obtenez une clé sur unmap.dev/dashboard/keys.

Appeler une compétence

La liaison est JSON-RPC 2.0 sur HTTPS, et le nom de méthode est SendMessage. Une compétence est choisie par une partie de données, un objet dans message.parts portant un champ skill et les paramètres de cette compétence :

curl -X POST https://api.unmap.dev/a2a \
  -H "Authorization: Bearer $UNMAP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "SendMessage",
    "params": {
      "message": {
        "messageId": "1f0c…",
        "role": "ROLE_USER",
        "parts": [{ "data": { "skill": "geocode_search", "query": "rue Sainte-Catherine, Montréal", "limit": 3 } }]
      }
    }
  }'

La réponse est un Message à deux parties : une partie texte qui résume la réponse sous une forme qu'un modèle peut lire sans rien analyser, et une partie de données contenant le JSON de l'API, tel quel. Le résumé est rédigé en anglais quelle que soit la langue demandée ; seuls les noms de lieux suivent language.

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "message": {
      "messageId": "",
      "contextId": "",
      "role": "ROLE_AGENT",
      "parts": [
        { "text": "3 results:\nrue Sainte-Catherine [street] at -73.57…", "mediaType": "text/plain" },
        { "data": [ /* le tableau que /geocode/search renvoie */ ], "mediaType": "application/json" }
      ]
    }
  }
}

Les coordonnées s'écrivent toujours [longitude, latitude] en degrés WGS84, dans cet ordre. La forme chaîne "lng,lat" est également acceptée : [-114.0625, 51.0447] et "-114.0625,51.0447" signifient la même chose.

Les mêmes compétences en MCP

Ce sont les cinq mêmes compétences que le serveur MCP expose comme outils, exécutant le même code : une seule table dans la passerelle alimente cette carte, la réponse tools/list de MCP et la description OpenAPI. Une compétence se comporte de façon identique quelle que soit l'enveloppe empruntée, messages d'erreur compris, et les deux surfaces ne peuvent pas diverger. Si votre cadriciel parle MCP, préférez-le ; A2A est là pour ceux qui parlent A2A. Aucune capacité n'existe sur l'une sans exister sur l'autre.

Un message uniquement textuel

Si un message ne porte aucune partie de données, son texte est lu comme une requête de géocodage, et rien d'autre :

{ "role": "ROLE_USER", "parts": [{ "text": "Iqaluit" }] }

C'est la seule inférence qu'unmap fait, et elle se défend parce que du texte libre est littéralement ce que prend le géocodeur plein texte. Ce n'est pas une compréhension de la phrase. unmap n'exploite aucun modèle de langue : « comment aller à Banff » est donc cherché comme un nom de lieu plutôt que calculé comme un itinéraire, et la réponse le dit dans sa partie texte. Pour atteindre les sept autres compétences, envoyez une partie de données.

Les huit compétences

CompétenceObligatoiresFacultatifs
geocode_searchquerylanguage, limit, bbox
geocode_reversecoordinatelanguage, limit
geocode_nearbycategories, nearradius, limit, language
routefrom, tomode, gabarits de camion
isochronecenter, minutesmode, gabarits de camion
identifycoordinatelayers, geometry
data_querylayer, bboxlimit, geometry
list_layersaddon

identify répond quels polygones du catalogue contiennent un point, une question différente des lieux nommés les plus proches que donne geocode_reverse. data_query prend une couche à la fois. list_layers n'exige aucun argument et lit le catalogue, licence et lacunes connues comprises : à appeler avant d'affirmer à un utilisateur qu'une couche le couvre, puisque plusieurs ne couvrent qu'une province.

coordinate, near, from, to et center sont tous des paires [longitude, latitude]. categories et minutes sont des tableaux. mode vaut auto, car, bicycle, pedestrian ou truck, et les gabarits de camion (height, width, length, weight, axle_load, axle_count, hazmat, use_truck_route) ne s'appliquent que si mode vaut truck. Le schéma JSON complet de chaque compétence est renvoyé par le tools/list du serveur MCP, sur une connexion vivante ; /openapi.json nomme les compétences et l'enveloppe qui les entoure. Le comportement sous-jacent est documenté sur les pages API de géocodage et API d'itinéraires.

Quelques remarques sur ce qui figure ici et ce qui n'y figure pas :

  • L'autocomplétion n'est pas une compétence. Elle sert à classer un préfixe à demi saisi pour une personne qui regarde une liste déroulante. Un agent dispose déjà de la chaîne complète, et geocode_search est le point de terminaison réglé pour en tirer la meilleure réponse.
  • Les tuiles et les styles ne sont pas des compétences. Une tuile vectorielle et un document de style MapLibre sont destinés à un moteur de rendu, et ni l'un ni l'autre ne survit au passage dans un message A2A. La seule chose utile à renvoyer serait une URL de style contenant votre clé d'API, c'est-à-dire un identifiant à faire fuiter plutôt qu'une compétence à appeler. Si votre agent doit afficher une carte, construisez l'URL à partir de l'API de cartes.

Un appel A2A est facturé comme une requête, imputée au service que la compétence a réellement utilisé : un geocode_search compte comme un géocodage, exactement comme GET /geocode/search et exactement comme l'outil MCP. Un appel qui n'exécute aucune compétence coûte tout de même une requête. Voir Forfaits et limites.

Erreurs

Il y a deux sortes d'échec, et elles arrivent différemment, à dessein.

Une compétence qui échoue revient comme un résultat réussi. Le Message porte l'échec dans sa partie texte et positionne metadata.isError. C'est délibéré : une erreur JSON-RPC est invisible pour un modèle, qui ne peut donc pas la lire et tenter autre chose, tandis qu'un résultat lisible est quelque chose sur quoi il peut agir. « Aucun itinéraire entre ces points », « catégorie inconnue » et « to must be [longitude, latitude] » arrivent tous ainsi, avec la formulation qu'ils ont en MCP.

{
  "jsonrpc": "2.0", "id": 1,
  "result": { "message": {
    "role": "ROLE_AGENT",
    "parts": [{ "text": "to must be [longitude, latitude]", "mediaType": "text/plain" }],
    "metadata": { "isError": true }
  }}
}

Une requête malformée est une erreur JSON-RPC, avec un HTTP 200, comme l'exige la spécification. Les échecs de transport arrivent tels quels.

CodeSignification
-32700Le corps n'était pas du JSON valide.
-32600Ce n'est pas un objet de requête JSON-RPC 2.0 unique. Les lots sont refusés.
-32601Méthode inconnue. unmap met en œuvre SendMessage.
-32602L'enveloppe n'a pas pu être lue comme un appel de compétence : aucun skill nommé, compétence inconnue, ou aucune partie exploitable.
-32001Tâche introuvable. unmap ne crée aucune tâche.
-32003Les notifications poussées ne sont pas prises en charge.
-32004La diffusion en continu n'est pas prise en charge.
-32007Aucune carte d'agent étendue n'est configurée.
HTTP 401Clé absente ou refusée, avec un défi WWW-Authenticate.
HTTP 429Limite de débit, quota ou plafond de dépenses, avec Retry-After lorsqu'attendre sert à quelque chose.
HTTP 503Un service est encore en démarrage. Réessayable.

L'authentification, la limitation de débit et les quotas sont traités au niveau du transport plutôt qu'à l'intérieur d'un 200, car un défi enfoui dans un corps JSON-RPC est un défi sur lequel votre client ne peut pas agir.

Dans le navigateur

Tout ce qui précède suppose un agent qui fait ses propres requêtes HTTP. Un agent qui pilote un navigateur (une extension, ou un assistant qui travaille dans l'onglet qu'une personne a sous les yeux) dispose d'une seconde possibilité : unmap.dev enregistre des outils WebMCP auprès du contexte de modèle du navigateur sur chaque page, afin que le site puisse être utilisé plutôt que moissonné.

outilce qu'il fait
search_unmap_docsRecherche plein texte dans cette documentation. Retourne les sections classées avec leur URL et un extrait.
read_unmap_pageN'importe quelle page d'unmap.dev en Markdown, les octets que retourne l'en-tête Accept ci-dessus.
navigate_unmap_siteOuvre une page du site dans l'onglet courant.
list_unmap_map_stylesLes douze styles de fond de carte en clair et en sombre, avec la valeur flavor qui demande chacun.

Aucun ne requiert de clé et aucun n'appelle l'API : la recherche s'exécute sur un index statique dans le navigateur, et les trois autres lisent des pages que le site sert déjà. Tout ce qui coûte un appel (un géocodage, un itinéraire, une tuile) en est délibérément absent ; c'est le rôle de la carte d'agent et des points de terminaison REST ci-dessus.

WebMCP est un brouillon, et l'API a occupé deux emplacements : l'aperçu anticipé de Chrome l'expose sur navigator, tandis que la spécification la définit désormais sur Document. unmap s'enregistre sur celui dont dispose le navigateur. Un navigateur qui n'a ni l'un ni l'autre n'est pas affecté : rien n'est polyfillé et aucun global n'est modifié.

WebMCP est la référence de ces quatre outils : les arguments de chacun, ce qu'il renvoie et ce qu'il refuse.

Couverture

unmap couvre le Canada. Le corpus de géocodage regroupe des adresses et des lieux canadiens, et le graphe d'itinéraires s'arrête à la frontière : un trajet qui passe aux États-Unis n'a donc pas de réponse plutôt qu'une réponse partielle. Les noms sont portés en anglais, en français et, lorsque les données sources les contiennent, en langues autochtones sur la même fiche, et une requête écrite en syllabique trouve sa correspondance. La couverture des noms autochtones est une lacune d'approvisionnement en données et non du moteur : le corpus ne porte un nom en inuktitut que pour un nombre restreint de communautés.

Prochaines étapes

  • Le serveur MCP expose les mêmes capacités via le Model Context Protocol.
  • La référence des API pour chaque point de terminaison accessible à un agent.
  • Erreurs pour ce que renvoie un appel d'outil en échec.