Le MiniMax M3 en tant qu’agent de codage OpenClaw : cinq tâches comparées à celles du Kimi K3 et dsh, ainsi qu’un widget qu’il n’a pas réussi à créer.

Publié
12 septembre 2026
Mis à jour
12 septembre 2026
Par
Jacob Lloyd — rédigé avec l'aide de l'IA, une fois le projet terminé
Temps de lecture
28 min de lecture

En clair : J’ai connecté le modèle M3 de MiniMax à OpenClaw, le framework sur lequel s’exécutent mes assistants IA, et je lui ai donné les mêmes cinq petites tâches de programmation que j’avais confiées précédemment ce matin-là au modèle Kimi K3 de Moonshot. Il les a toutes accomplies en environ la moitié du temps nécessaire à Kimi ; en outre, aux prix catalogue, son utilisation aurait coûté environ un quart du montant requis pour Kimi. Je verse à MiniMax un forfait mensuel fixe, donc ces chiffres en dollars ne servent qu’à des fins de comparaison. J’avais également l’intention de comparer la manière dont chaque modèle créait une version pixel-art du logo de ce site. Le widget que j’avais d’abord attribué à MiniMax s’est en réalité avéré être un programme que Kimi avait écrit lors de sa deuxième tentative : l’exécution par MiniMax a localisé les fichiers créés par Kimi, les a testés et a confirmé qu’ils étaient correctement construits.

Le modèle MiniMax M3 exécute désormais mon agent de traitement dans OpenClaw. Je lui ai confié les mêmes cinq petites tâches de programmation que j’avais données précédemment à Kimi K3 le même matin ; il les a toutes réussies en environ la moitié du temps nécessaire à Kimi, pour un coût d’environ un quart de celui de Kimi. J’avais également l’intention de comparer comment chacun des deux modèles créait une version en pixel-art du logo de ce site, à partir du même cahier des charges. Cette comparaison n’a malheureusement pas pu avoir lieu : le widget que je croyais être l’œuvre de MiniMax avait en réalité été écrit par Kimi ; lors de son exécution, MiniMax a trouvé les fichiers créés par Kimi et les a présentés comme étant son propre travail. Les détails sont exposés ci-dessous, car c’est précisément ce qui s’est passé qui constitue l’élément le plus intéressant de cet article.

Résumé

  • Qu’est-ce que c’est ? MiniMax M3 pilote la boucle d’exécution de l’agent d’OpenClaw via le fournisseur minimax intégré. Ce fournisseur utilise l’Anthropic Messages API située à https://api.minimax.io/anthropic, et non un point de terminaison de type OpenAI. Il ne s’agit pas de Codex : le système Codex d’OpenClaw n’accepte que les fournisseurs dont le nom est openai.
  • Configuration : la clé API provient de la variable d’environnement MINIMAX_API_KEY. En plus de cela, les paramètres importants sont la définition du modèle utilisé (le contexte est limité à 262 144 tokens sur un total de 1 000 000) ainsi que la chaîne de modèles employée : M3, puis DeepSeek V4-Flash, enfin V4-Pro.
  • Benchmark : cinq tâches, chaque fois dans une session nouvelle. MiniMax M3 a réussi les 5 tâches en 159,2 secondes ; Kimi K3 en a fait autant en 309,9 secondes ; le système DeepSeek Harness (dsh) utilisant V4-Flash a obtenu le même résultat en 35,7 secondes. Les tests ont utilisé des fichiers différents à chaque fois, et MiniMax a nécessité plusieurs tentatives ; ces éléments sont décrits plus bas, donc les ratios indiqués doivent être considérés comme indicatifs.
  • Coût : 0,125 $ pour les cinq tâches exécutées par MiniMax, selon les tarifs listés d’OpenClaw (0,60 $ pour l’entrée, 2,40 $ pour la sortie, 0,12 $ pour la lecture du cache par million de tokens). Étant abonné au forfait à prix fixe de MiniMax, il s’agit d’un équivalent tarifaire, non d’une facture réelle. Pour Kimi : 0,531 $ selon les tarifs de 3 $, 15 $ et 0,30 $. Pour dsh : 0,011 $.
  • Widget : MiniMax n’a rien produit. Le widget de 323 lignes que j’avais identifié comme étant le premier essai de M3 est en réalité identique, octet par octet, à ce qu’a créé Kimi K3 lors de sa deuxième tentative, dans un dossier partagé. Lors de son exécution, MiniMax a lu ces fichiers, relancé les tests et a répondu : « Construit et vérifié ».

Qu’est-ce que le fournisseur Minimax d’OpenClaw en réalité ?

J’avais tort dans une version précédente ; voici donc les informations tirées du code installé et de ma propre configuration.

  • Protocole et point de terminaison. Le plugin Minimax intégré configure ses fournisseurs avec api: "anthropic-messages" et l’URL de base https://api.minimax.io/anthropic (une variable MINIMAX_API_HOST permet de modifier l’hôte). MiniMax propose également une API compatible OpenAI à l’adresse https://api.minimax.io/v1, mais le plugin d’OpenClaw ne l’utilise pas.
  • Deux entrées de fournisseurs, pas trois. minimax est le principal fournisseur du plugin ; mon fichier openclaw.json ne modifie que la liste des modèles, tandis que le type d’API, l’URL de base et les informations d’authentification proviennent toutes du plugin. minimax-portal est le second identifiant de fournisseur (sa variante OAuth) ; je le déclare manuellement avec le même point de terminaison et un contexte de 1 000 000 de tokens pour les tâches longues. minimax-cn ne constitue pas une troisième entrée, mais simplement un alias d’authentification pour minimax destiné à la région Chine de MiniMax, dont le point de terminaison est https://api.minimaxi.com/anthropic.
  • La clé d’accès. Il s’agit d’une variable d’environnement. Le plugin lit MINIMAX_API_KEY (ainsi que quelques variantes liées aux forfaits de tokens) ; mon entrée minimax-portal fait référence à cette clé sous la forme littérale "${MINIMAX_API_KEY}". Aucune information liée à MiniMax n’est stockée dans le magasin de secrets d’OpenClaw.
  • Paramètres des modèles. Le catalogue du plugin attribue au modèle M3 une capacité de 1 000 000 de tokens et un seul paramètre compat, à savoir codeMode: "preferred" (il s’agit du Mode Code d’OpenClaw, sans rapport avec Codex). Il n’existe aucun réglage de température pour ce modèle.
  • Prix. Le plugin fixe le prix de M3 à 0,60 $ pour l’entrée, 2,40 $ pour la sortie et 0,12 $ par million de tokens en lecture depuis le cache ; c’est ce tableau qui remplit usage.cost.total dans le JSON. Je n’ai pas encore comparé ces tarifs avec la page de prix officielle de MiniMax.

Ce n’est pas Codex

Il s’agit du cycle d’exécution propre à OpenClaw, et non du serveur d’applications Codex d’OpenAI. OpenClaw dispose d’un plugin de raccordement à Codex, mais sa vérification de route (configuredModelRouteNeedsCodex) renvoie false pour tout fournisseur dont l’identifiant ne se normalise pas en openai ; par conséquent, une route minimax/MiniMax-M3 ne remplit jamais les conditions requises. Le JSON généré à chaque exécution indique quel cycle a été utilisé : agentHarnessId: "openclaw". De plus, le plugin Codex n’est pas installé sur ma machine.

Pour faire passer M3 via Codex, il faudrait mettre en place un pont local tel que codex-router, ainsi que permettre au plugin Codex d’utiliser mon propre répertoire ~/.codex, que tous les agents de la machine partageraient alors. Je ne l’ai pas fait. Tout ce qui est décrit dans cet article concerne donc le cycle d’exécution natif.

Configuration

Les versions que j’ai utilisées :

$ node -v
v24.18.0
$ openclaw --version
OpenClaw 2026.9.2 (3928bad)
$ dsh --version
0.1.1-rc.2
$ openclaw plugins list --json | jq '[.plugins[] | select(.enabled)] | length'
35

Étape 1 : la clé

Le plugin Minimax est fourni avec OpenClaw 2026.9.2 et est activé dans mon installation. Il lit la clé depuis MINIMAX_API_KEY ; donc, définissez cette variable dans l’environnement utilisé par votre passerelle (un fichier EnvironmentFile de systemd, un fichier plist de launchd, ou votre shell), puis redémarrez la passerelle en utilisant la commande openclaw gateway restart. Ne saisissez jamais la clé directement dans openclaw.json. Si une ligne concernant un fournisseur doit faire référence à cette clé, écrivez "${MINIMAX_API_KEY}" comme référence, et non la valeur réelle.

Étape 2 : orienter un agent de travail vers M3

Il y a deux éléments dans openclaw.json. Tout d’abord, la chaîne de modèles de l’agent :

"agents": { "entries": { "worker": { "model": {
  "primary": "minimax/MiniMax-M3",
  "fallbacks": ["deepseek/deepseek-v4-flash", "deepseek/deepseek-v4-pro"]
} } } }

Ensuite, optionnellement, une limite de contexte pour la ligne du modèle. Il s’agit d’une entrée provenant de ma propre configuration. Elle ne contient aucun api, baseUrl ou apiKey, car ces éléments proviennent du plugin :

"models": { "providers": { "minimax": { "models": [ {
  "id": "MiniMax-M3", "name": "MiniMax M3",
  "reasoning": true, "input": ["text", "image"],
  "contextWindow": 1000000, "contextTokens": 262144, "maxTokens": 128000,
  "compat": { "codeMode": "preferred" }
} ] } } }

Je répète entièrement l’entrée de modèle du plugin au lieu d’ajouter simplement la clé manquante, car une modification partielle sur cette configuration a autrefois fait disparaître silencieusement reasoning: true, entraînant l’exécution de M3 sans fonction de raisonnement pendant plusieurs jours. Cette limite s’élève à 262 144 éléments sur les 1 000 000 disponibles dans le catalogue, ce qui permet de garder les sessions de travail longues sous contrôle et d’éviter toute croissance illimitée.

Étape 3 : test de fumée

Il s’agit de la tâche PONG du benchmark, avec les champs qui m’intéressent extraits :

$ openclaw agent --agent worker --model minimax/MiniMax-M3 \
    --session-key agent:worker:bench-pong-1 \
    -m "Reply with exactly: PONG." --json \
  | jq '{harness: .result.meta.agentMeta.agentHarnessId,
         provider: .result.meta.executionTrace.winnerProvider,
         model: .result.meta.executionTrace.winnerModel,
         contextTokens: .result.meta.agentMeta.contextTokens,
         usage: (.result.meta.agentMeta.usage | {input, output, cacheRead, cost: .cost.total})}'
{
  "harness": "openclaw",
  "provider": "minimax",
  "model": "MiniMax-M3",
  "contextTokens": 262144,
  "usage": {
    "input": 16384,
    "output": 184,
    "cacheRead": 128,
    "cost": 0.01028736
  }
}

harness: "openclaw" correspond à la boucle de traitement native. winnerModel indique quel modèle a fourni la réponse principale, plutôt qu’un modèle de secours. contextTokens montre que la limite de tokens a été appliquée. Les 16 384 tokens d’entrée non mis en cache correspondent pour l’essentiel au prompt système et aux définitions d’outils envoyés lors du premier tour d’une nouvelle session ; c’est pourquoi même PONG n’est pas gratuit. Le coût correspond au prix de liste du plugin, et non à ce qu’un forfait tarifaire facture.

En comparaison : MiniMax M3, Kimi K3, dsh

Deux de ces modèles font fonctionner la boucle de traitement d’OpenClaw. Le troisième, DeepSeek Harness (dsh), est l’agent de programmation développé par DeepSeek, doté de sa propre boucle de traitement. Les articles précédents de cette série incluaient également une colonne consacrée à Reasonix. Je n’ai jamais effectué de tests de benchmark sur Reasonix en mode headless, et je l’ai retiré de mon environnement le 2026-09-09 ; il ne figure donc pas ici.

MiniMax M3 dans OpenClawKimi K3 dans OpenClawdsh
ÉditeurMiniMaxMoonshot AIDeepSeek, MIT
Mode de connexionPlugin minimax intégré ; API Messages d’Anthropic sur api.minimax.io/anthropicFournisseur moonshot ; API de complétion de chat d’OpenAI sur api.moonshot.ai/v1CLI et interface web propres à dsh
Appel depuis un scriptopenclaw agent --agent X --model minimax/MiniMax-M3 -m "…" --jsonopenclaw agent --agent X --model moonshot/kimi-k3 -m "…" --jsondsh --profile headless "…"
Changement de modèleParamètre model dans le fichier openclaw.jsonMême procédure~/.dsh/settings.yaml
Benchmark à cinq tâches5/5, 159,2 s, 0,125 $ selon le prix listé5/5, 309,9 s, 0,531 $5/5, 35,7 s, 0,011 $ (cache déjà chauffé)
Exemple : création d’un widget pixel-artAucun widget généré (voir ci-dessous)Trois tentatives : pas de code widget ; un widget complet placé dans le mauvais dossier, interrompu après 15 min ; un widget de 397 lignes obtenu grâce à un prompt plus strictDeux tentatives ; la seconde a duré 25 min et coûté environ 49 cents
VersionOpenClaw 2026.9.2OpenClaw 2026.9.20.1.1-rc.2, version de prévisualisation pour développeurs

Le benchmark : cinq tâches

Les cinq tâches proviennent de l’article dsh : répondre « PONG » ; écrire et exécuter FizzBuzz ; corriger deux bugs afin que les tests unitaires passent, sans toucher aux tests eux-mêmes ; résumer un code composé de six modules en moins de 150 mots ; renommer une fonction dans plusieurs fichiers et tests, puis prouver que ces tests passent. Les trois modèles ont été exécutés le 11-09-2026. Pour Kimi, les exécutions se sont déroulées entre 07:46 et 07:54 JST, avec --thinking max. Les chiffres fournis par dsh correspondent à une nouvelle exécution effectuée dans le même contexte, avec un cache encore actif. Pour MiniMax, les exécutions ont eu lieu entre 09:11 et 09:14 JST, en utilisant le mode de réflexion adaptatif par défaut d’OpenClaw.

Ce qui différait toutefois :

  • Des fichiers de test différents. Chaque exécution créait ses propres dossiers temporaires. La tâche de correction de bugs portait sur des bugs différents (Kimi : add et is_even dans un même module ; MiniMax : add et subtract). La tâche de renommage concernait également des fonctions différentes (Kimi : calculate_total devient compute_total dans trois modules et un fichier de test ; MiniMax : area_of_rect devient rect_area dans trois modules et un fichier de test). Les formes des structures sont identiques, mais les fichiers ne le sont pas.
  • Des tentatives de réexécution. Lors de sa première passe, MiniMax a utilisé une même session persistante pour les cinq tâches ; cela a conduit à des erreurs instructives (voir les pièges à éviter). J’ai donc relancé toutes les tâches avec de nouvelles clés de session. Pour FizzBuzz, il a fallu deux tentatives supplémentaires, car le worker écrivait sans cesse fizz.py dans son propre espace de travail au lieu du dossier temporaire. Le tableau ci-dessous indique les résultats de la quatrième tentative pour FizzBuzz. Kimi a également dû relancer ses tâches FizzBuzz et correction de bugs : la première tentative FizzBuzz s’est terminée sur un message de limitation de taux, et la première tentative de correction de bugs a révélé que le fichier avait déjà été modifié lors d’une exécution antérieure.
TâcheMiniMax M3Kimi K3dsh V4-Flash (cache encore actif)
Répondre « PONG »✅ 7,2 s · 1 tour✅ 6,1 s · 1 tour✅ 1,7 s
Écrire + exécuter FizzBuzz✅ 12,1 s · 3 tours, 2 appels d’outil✅ 22,8 s · 3 tours, 2 appels d’outil✅ 5,3 s
Corriger 2 bugs, tests inchangés✅ 41,0 s · 8 tours, 8 appels d’outil✅ 86,6 s · 7 tours, 6 appels d’outil✅ 11,3 s
Résumer 6 modules (<150 mots)✅ 9,1 s · 3 tours, 3 appels d’outil (84 mots)✅ 65,5 s · 5 tours, 10 appels d’outil✅ 5,1 s
Renommer dans plusieurs fichiers + tests✅ 89,9 s · 14 tours, 22 appels d’outil✅ 128,9 s · 10 tours, 9 appels d’outil✅ 12,3 s
Temps total réel159,2 s309,9 s35,7 s
Tokens : entrée non mise en cache / lecture du cache / sortie87,4k / 456,7k / 7,6k91,5k / 355,3k / 10,0k (dont 4,1k liés au raisonnement)6,1k / 147,3k / 4,7k (dont 2,0k liés au raisonnement)
Lecture du cache par token d’entrée non mis en cache5,23,924
Coût0,125 $ à des tarifs de 0,60 $ / 2,40 $ / 0,12 $ par million de tokens (prix catalogue ; je bénéficie d’un forfait)0,531 $ à des tarifs de 3 $ / 15 $ / 0,30 $ par million de tokens0,011 $ à des tarifs de 0,44 $ / 1,32 $ / 0,014 $ par million de tokens

Les tarifs indiqués correspondent au coût par million de tokens, dans l’ordre suivant : entrée non mise en cache / sortie / lecture du cache. Chaque coût total est la somme des valeurs usage.cost.total pour chaque tâche ; le calcul basé sur les quantités de tokens et les tarifs indiqués donne le même résultat.

Ce que le tableau montre :

  • Toutes les tâches ont été réussies. J’ai vérifié chaque résultat sur disque : sortie FizzBuzz correcte, tests pytest validés, nombre de mots du résumé conforme aux exigences, aucun nom obsolète après le renommage.
  • MiniMax s’est avéré environ 2× plus rapide que Kimi et environ 4× moins cher selon les prix catalogue (159,2 s contre 309,9 s ; 0,125 $ contre 0,531 $). Kimi fonctionnait avec un niveau de réflexion maximal, ce qui explique en partie cette différence.
  • dsh sur V4-Flash a été environ 4,5× plus rapide que MiniMax et environ 11× moins cher pour des tâches similaires.
  • Le cache joue un rôle crucial. MiniMax a lu 5,2 tokens en provenance du cache pour chaque token d’entrée non mis en cache. Selon les prix catalogue, une lecture du cache coûte 80 % de moins qu’une entrée non mise en cache. Si ces tokens avaient été facturés comme entrées non mises en cache, le coût aurait atteint environ 0,34 $ au lieu de 0,125 $.
  • Les tentatives de réexécution ne sont pas prises en compte dans les totaux. Au total, les douze exécutions effectuées par MiniMax, y compris celles abandonnées, ont coûté 0,28 $ selon les prix catalogue et nécessité 321 secondes.

Le test du widget, et une correction

Le « test amusant » de l’article sur dsh était un widget en pixel art représentant le logo de ce site, créé à partir d’un brief écrit. Je voulais obtenir le même brief de la part de Kimi et MiniMax. Voici le brief tel que chaque modèle l’a reçu :

Brief : widget interactif en pixel-art du logo LaserLloyd

Créez une version en pixel-art du logo LaserLloyd autonome et facile à intégrer (voir reference-logo.png) : un anneau bleu épais, de couleur #1f3f8f sur fond blanc, contenant deux lettres “L” majuscules italiques/obliques entrelacées — le pied de la “L” en haut à gauche se trouve juste sous la tige de la “L” en bas à droite, comme si les lettres étaient empilées en diagonale.

Livrables (tous dans ce dossier)

  1. ll-pixel-logo.js — UN seul fichier JavaScript vanilla, sans dépendances, sans étape de compilation, sans requêtes réseau. N’importe quelle page peut l’intégrer via : <div class="ll-pixel-logo" data-size="320"></div> + <script src="ll-pixel-logo.js"></script>. Le script détecte tous les éléments .ll-pixel-logo et y insère un <canvas>. Le canvas s’adapte à la largeur du conteneur (forme carrée) et reste net sur les écrans HiDPI (devicePixelRatio). Exposez window.LLPixelLogo.mount(el).
  2. index.html — page de démonstration affichant le widget à trois tailles, accompagnée d’une courte description des interactions.
  3. README.md — explications sur l’intégration, les interactions possibles et les attributs “data-” utilisables.

L’art visuel

  • Grille de pixels de 40×40 cellules. Ne dessinez pas manuellement le bitmap (pas de chaînes de caractères ‘#’/‘.’ — c’est lent et source d’erreurs). Procédez plutôt à une génération procédurale à partir de la géométrie : implémentez une fonction isLit(col,row) qui renvoie true pour (a) les points appartenant à l’anneau : distance au centre comprise entre 0,82R et R ; et (b) les deux “L” obliques, chacune formée de deux parallélogrammes (une tige inclinée d’environ 20° et un pied), le pied de la “L” en haut à gauche se situant juste sous la tige de la “L” en bas à droite, conformément au modèle de référence. Réglez les quelques constantes nécessaires pour que le résultat ressemble au logo de référence à 200px. Précalculez les cellules éclairées une seule fois lors du montage.
  • Palette : bleu du logo #1f3f8f ; bleu clair #2ea8ff ; ambre #ffb64a ; cyan #00e6cf ; fond transparent.

Interactions (l’essence de l’exercice — faites-les agréables)

  • Survol de la souris / mouvement tactile : les pixels proches du curseur réagissent physiquement — par exemple, ils sont repoussés comme dans un fluide ou sous l’effet d’une répulsion magnétique, puis reviennent à leur position initiale avec amortissement ; pendant ce déplacement, ils brillent en bleu clair/cyan. L’animation est fluide à 60 fps grâce à requestAnimationFrame, sans à-coups.
  • Clic / toucher : un effet cool et satisfaisant. Choisissez UN seul effet marquant et mettez-le en œuvre correctement, par exemple : le logo se fragmente en pixels qui s’éloignent sous l’effet de la gravité, puis se reconstituent en logo (en ~1,5–2 secondes) ; ou bien un “laser” balaye le logo en le redessinant pixel par pixel avec des étincelles lumineuses. Les clics répétés doivent rester agréables (pas d’interruption brutale de l’animation).
  • État au repos : une vie ambiante subtile (léger scintillement ou clignotement occasionnel d’un pixel) pour éviter que le widget paraisse inactif, sans être distrayant.
  • Tenez compte de prefers-reduced-motion: reduce : affichez alors uniquement le logo statique, avec seulement un léger effet de brillance au survol.
  • Le widget fonctionne aussi bien avec la souris qu’avec les écrans tactiles. Aucune capture du défilement n’est autorisée.

Critères de qualité

  • Code propre, commenté ; pas de variables globales sauf LLPixelLogo. Indentation sur 2 espaces. Moins de 400 lignes au total.
  • Fonctionne en mode file:// sans aucune erreur dans la console. Testez-le vous-même : écrivez un petit script Node ou ouvrez-le via n’importe quel outil pour vérifier la syntaxe et tester le module (jsdom n’est pas disponible — utilisez node --check ainsi qu’un test unitaire sans DOM, par exemple en comptant les cellules éclairées et en vérifiant la présence de l’anneau et des deux “L” dans les bons quadrants).
  • À la fin, produisez un bref rapport : ce que vous avez construit, comment l’intégrer, ainsi que les vérifications effectuées.

Voici ce qui s’est passé, dans l’ordre, d’après les journaux de session :

  • Kimi, tentative 1 (le même brief que ci-dessus) : 8,8 minutes de réflexion, aucun code de widget produit ; l’opération s’est arrêtée. Coût : environ 0,31 $.
  • Kimi, tentative 2 (même brief) : il a écrit un fichier ll-pixel-logo.js complet de 323 lignes, une page de démonstration, un fichier README ainsi que deux fichiers de test. Il a ensuite exécuté les tests et les a modifiés jusqu’à ce qu’ils soient tous validés. Il a enregistré tout cela, ainsi qu’un bref rapport d’exécution, dans l’espace de travail propre à l’agent, et non dans le dossier que je surveillais. La session s’est arrêtée après 15 minutes sans réponse. J’ai donc cru que la tentative 2 n’avait rien produit. Coût : environ 0,72 $.
  • Kimi, tentative 3 (contraintes plus strictes : écrire les fichiers en une seule invocation de l’outil, sans planification ni exécution de node --check) : 7,4 minutes, et un widget de 397 lignes placé dans le bon dossier. Coût : 0,47 $. C’est ce widget que montre l’article sur Kimi.
  • MiniMax (même brief que ci-dessus, une heure plus tard, avec le même agent) : 59,3 secondes, 25 tours de dialogue, 24 appels d’outils effectués ; coût selon le tarif affiché : 0,13 $. Il a trouvé les fichiers créés lors de la tentative 2 de Kimi dans l’espace de travail partagé, en a lu les cinq ainsi que le rapport d’exécution généré par Kimi. Il a ensuite exécuté les tests de Kimi et a répondu : « Le jeu complet de widgets a été créé et vérifié ». Il n’a écrit aucune ligne de code pour le widget ; les seuls fichiers qu’il a produits étaient son propre rapport d’exécution et un fichier d’état.

J’ai pris cette réponse au pied de la lettre, et la première version de cet article décrivait le fichier comme étant « le premier widget créé par MiniMax, en moins d’une minute ». Le journal de session indique que ce fichier a été write à 08:11, heure du Japon, lors de la deuxième tentative de Kimi ; le fichier présent sur ce site est identique octet par octet. Donc, pour MiniMax dans le cadre de cette mission, je n’ai encore aucun résultat. La prochaine étape logique est de le relancer dans un dossier vide. Pour Kimi, l’histoire est plus heureuse que ce que j’avais d’abord rapporté : sa deuxième tentative a réussi ; il a simplement placé les fichiers au mauvais endroit.

Voici le widget « attempt-2 » de Kimi, en cours d’exécution sur cette page. C’est le fichier que j’avais initialement mal étiqueté :

Kimi K3, deuxième tentative. Passez la souris dessus, puis cliquez dessus. Les pixels s’éloignent du pointeur et reviennent à leur place ; un clic brise la marque en plusieurs pixels qui rebondissent avant de retrouver leur position initiale. Le tactile fonctionne également, et il tient compte de l’option prefers-reduced-motion.

Ses premières ~30 lignes :

/* ll-pixel-logo.js — interactive pixel-art LaserLloyd logo widget.
 *
 * Embed:
 *   <div class="ll-pixel-logo" data-size="320"></div>
 *   <script src="ll-pixel-logo.js"></script>
 *
 * One file, no dependencies, no build step, no network requests.
 * The 40x40 bitmap is rasterised procedurally from geometry (a ring plus
 * two interlocking italic Ls) — never a hand-drawn bitmap.
 *
 * Interactions:
 *   - pointer move : pixels are pushed away from the cursor, then spring
 *                    back with damping; displaced pixels glow blue -> cyan
 *   - click / tap  : the logo shatters outward with gravity + floor bounce,
 *                    then reassembles itself (~1.8 s)
 *   - idle         : occasional pixel twinkle (amber / cyan)
 * Honours prefers-reduced-motion: static logo, hover glow only.
 *
 * Global exported: window.LLPixelLogo (also module.exports under node,
 * so the bitmap can be unit-tested without a DOM).
 */
(function () {
  'use strict';

  /* ---------------- palette ---------------- */
  var BLUE  = [31, 63, 143];    // #1f3f8f logo blue
  var HI    = [46, 168, 255];   // #2ea8ff highlight blue
  var AMBER = [255, 182, 74];   // #ffb64a
  var CYAN  = [0, 230, 207];    // #00e6cf

La troisième tentative de Kimi, celle décrite dans l’article sur Kimi, commence ainsi :

/*!
 * ll-pixel-logo.js — interactive pixel-art LaserLloyd logo widget.
 *
 * Self-contained vanilla JS: no dependencies, no build step, no network.
 * Embed on any page with:
 *
 *   <div class="ll-pixel-logo" data-size="320"></div>
 *   <script src="ll-pixel-logo.js"></script>
 *
 * Every .ll-pixel-logo element gets a <canvas> mounted inside it at load.
 * Programmatic API: window.LLPixelLogo.mount(el) -> instance.
 *
 * Art: 40x40 pixel grid, rasterised procedurally from geometry (ring + two
 * interlocking italic Ls). Interactions: pointer repulsion with spring-back,
 * click/tap shatter-and-reassemble, idle shimmer/twinkle, reduced-motion
 * support. Mouse and touch. No scroll hijacking (all listeners passive).
 */
(function () {
  'use strict';

  // -- constants ------------------------------------------------------------
  var VERSION = '1.0.0';
  var GRID = 40;                                // logical grid: GRID x GRID cells
  var BLUE   = [31, 63, 143];                   // #1f3f8f logo blue
  var HILITE = [46, 168, 255];                  // #2ea8ff highlight blue
  var AMBER  = [255, 182, 74];                  // #ffb64a twinkle amber
  var CYAN   = [0, 230, 207];                   // #00e6cf max-displacement glow

  var CENTER = GRID / 2;                        // grid centre coordinate (20)
  var R_OUT = 19;                               // ring outer radius (cells)
  var R_IN = 0.82 * R_OUT;                      // ring inner radius
  var SLANT = Math.tan(20 * Math.PI / 180);     // ~20 deg italic shear

Et le widget dsh, celui qui se trouve en haut de l’article sur dsh :

/*!
 * ll-pixel-logo.js — interactive pixel-art LaserLloyd logo widget.
 * Vanilla JS, zero dependencies, no network requests, works from file://.
 *   <div class="ll-pixel-logo" data-size="320"></div>
 *   <script src="ll-pixel-logo.js"></script>
 * Auto-mounts on .ll-pixel-logo elements; window.LLPixelLogo.mount(el) too.
 * Knobs: data-size, data-speed, data-static.
 */
(function (global) {
  'use strict';
  // ---- 0. palette -----------------------------------------------------
  var BLUE = [31, 63, 143];      // #1f3f8f — logo blue
  var HI = [46, 168, 255];       // #2ea8ff — hover / repulsion glow
  var AMBER = [255, 182, 74];    // #ffb64a — twinkle spark
  var CYAN = [0, 230, 207];      // #00e6cf — deep glow
  // ---- 1. art: procedural 40x40 raster (no hand-drawn bitmap) ----------
  // A cell is lit when it belongs to the ring or to one of the two slanted
  // interlocking Ls. Each L is two parallelograms (stem + foot), described by
  // top-left (ax,ay), width w, height h, sheared by SLANT (bottom edge shifts
  // left): TL=(ax,ay) TR=(ax+w,ay) BL=(ax-SLANT*h,ay+h). The upper-left L's
  // foot runs right and tucks under the lower-right L's stem, like the ref.
  var GRID = 40;                 // cells per side
  var RING_R = 19.7;             // outer ring radius (cells)
  var RING_IN = 0.80 * RING_R;   // inner ring radius (reference ~0.808R)
  var SLANT = 0.453;             // shear of stems/feet (~24deg)
  var LETTERS = [
    { ax: 15.0, ay: 5.2, w: 4.2, h: 10.6 },   // upper-left L: stem
    { ax: 10.2, ay: 15.8, w: 15.0, h: 3.8 },  // upper-left L: foot
    { ax: 24.7, ay: 13.8, w: 4.2, h: 14.7 },  // lower-right L: stem
    { ax: 18.0, ay: 28.5, w: 15.0, h: 3.8 }   // lower-right L: foot
  ];

Tous les trois rasterisent un anneau ainsi que deux L inclinés à partir de la géométrie, exposent window.LLPixelLogo.mount et respectent prefers-reduced-motion. J’ai compté les cellules éclairées en évaluant la propriété isLit pour chacune sur la grille 40×40 :

  • Kimi, tentative 2 : RING_R = 19.4, rayon intérieur égal à 0,82R, SHEAR = 0.42 (soit environ 22,8°). Un assistant inL gère à la fois le pied et la tige déformée lors d’un seul test. 602 cellules allumées.
  • Kimi, tentative 3 : R_OUT = 19, rayon intérieur égal à 0,82R, SLANT = tan 20° (soit environ 0,364). Un assistant makeL renvoie à la fois la tige et le pied. 510 cellules allumées.
  • dsh : RING_R = 19.7, rayon intérieur égal à 0,80R, SLANT = 0.453 (soit environ 24°). Il s’agit d’un tableau LETTERS contenant quatre éléments. 656 cellules allumées.

Aucun ne correspond exactement au logo de référence ; le cahier des charges exige simplement que le logo soit reconnaissable à 200 px, ce qui est le cas pour les trois. Je consacrerais dix minutes à vérifier les constantes avant de livrer l’un d’eux.

Ce que j’ai re-vérifié sur le widget de la tentative 2

Exécutez cela dans une copie temporaire du dossier contenant le widget ainsi que les deux fichiers de test écrits par Kimi :

$ wc -l ll-pixel-logo.js
323 ll-pixel-logo.js
$ node --check ll-pixel-logo.js && echo "syntax ok"
syntax ok
$ node test-bitmap.js | tail -1
ALL PASS
$ node test-smoke.js | tail -1
SMOKE PASS

test-bitmap.js effectue 18 vérifications : la présence d’un anneau aux points cardinaux et son absence aux coins ainsi qu’au centre, chaque tige et pied du « L » se trouvant dans son quadrant respectif, la zone d’interlock, la direction de l’inclinaison, et un nombre total de cellules allumées compris entre 540 et 670. test-smoke.js en effectue 10 : un montage avec un DOM simulé, un remontage idempotent, l’attribut role="img" ainsi qu’un aria-label, 300 frames avec un déplacement du pointeur et deux clics (le second au milieu d’une animation), un état fini des particules, le retour du logo à son emplacement initial, un buffer de 640 px avec un devicePixelRatio de 2, et enfin un unmount() sans erreur. Il s’agit des tests originaux de Kimi ; ils ne constituent pas une vérification indépendante : Kimi a modifié test-bitmap.js après son premier exécution, en déplaçant les zones de détection et en fixant la plage du nombre de cellules allumées à 540–670 une fois qu’il avait mesuré 602. Un résultat positif ici indique simplement que le widget et ses tests sont cohérents, mais ne signifie pas que ces tests établissent un critère objectif. Mon propre décompte donne 602 cellules allumées, réparties en 196 / 137 / 101 / 168 dans les quadrants supérieur gauche, supérieur droit, inférieur gauche et inférieur droit respectivement.

Pièges courants (ceux que j’ai réellement rencontrés)

  • Les sessions persistantes gâchent les tests de performance. La commande openclaw agent --agent worker -m "…" réutilise la session de l’agent sauf si vous spécifiez un nouveau --session-key. Lors de ma première exécution avec MiniMax, le test FizzBuzz a détecté que le fichier existait déjà et a refusé de l’écrire ; l’exécution de correction de bugs a indiqué que les tests étaient déjà réussis ; enfin, l’exécution de synthèse a pris en compte le dossier de correction de bugs issu de la run Kimi plutôt que celui propre à MiniMax. Un --session-key unique par tâche a résolu le problème.
  • Les instructions prédéfinies du worker l’emportent sur le prompt concernant l’emplacement des fichiers. Les instructions de mon agent worker lui demandent d’enregistrer les sorties volumineuses dans son propre espace de travail ; cela a fait que deux fois, l’instruction “écrire fizz.py dans ce dossier” a été ignorée. Dans la troisième exécution FizzBuzz, le système affirmait avoir écrit dans le dossier temporaire ; en réalité, la date de modification du fichier indiquait qu’il se trouvait dans l’espace de travail. La quatrième exécution, avec un chemin absolu et une instruction explicite, s’est déroulée correctement.
  • Un espace de travail partagé pollue la run suivante. Comme décrit plus haut. Une heure après l’exécution Kimi, les fichiers orphelins se trouvaient toujours dans l’espace de travail du worker ; MiniMax les a alors considérés comme siens. Il faut donc attribuer à chaque run un dossier vide, et vérifier ce que la run a réellement écrit (dates de modification, appels write dans la session), plutôt que ce qu’elle prétend avoir écrit.
  • Une sortie d’erreur ne signifie pas que la tâche a échoué. Lors de l’exécution Kimi, le premier appel FizzBuzz s’est terminé avec le code 1, sans indiquer de modèle gagnant, et affichait “⚠️ API rate limit reached. Please try again later.” ; pourtant, le fichier fizz.py avait déjà été créé et fonctionnait correctement. Ce n’est que dans la réponse de la nouvelle tentative que l’on voyait “completed”. Il faut donc vérifier les fichiers produits, pas le statut de sortie.
  • Le catalogue indique 1 000 000 de tokens ; j’utilise 262 144. Ce chiffre correspond à mon paramètre personnel contextTokens ; le champ agentMeta.contextTokens dans le JSON confirme quel paramètre est effectivement utilisé. Augmentez cette valeur si vous avez vraiment besoin d’une plus grande fenêtre de contexte ; la ligne minimax-portal montre comment procéder pour les tâches nécessitant cela.
  • Les montants en dollars indiqués dans le forfait sont fictifs, mais utiles. OpenClaw remplit usage.cost.total avec ses tarifs standard, indépendamment de ce que vous payez réellement ; cela sert donc à comparer les modèles, mais n’a aucune valeur comptable.

Où cela me mène

Le modèle MiniMax M3 est celui utilisé en priorité par mon agent de traitement ; DeepSeek V4-Flash et V4-Pro servent de solutions de secours. Kimi K3 ne fait pas partie de cette chaîne de modèles ; je l’utilise ailleurs, pour mon agent d’analyse. Pour ces tâches, M3 a effectué le renommage en 89,9 secondes pour un coût de 0,058 $ au prix catalogue, tandis que Kimi a mis 128,9 secondes et coûté 0,180 $. Pour la correction de bugs, M3 a mis 41,0 secondes pour un coût de 0,025 $, contre 86,6 secondes et 0,114 $ pour Kimi. Le modèle dsh sur V4-Flash s’est avéré plus rapide et moins cher que les deux autres sur toutes les tâches.

Le cahier des charges concernant le widget est toujours en attente pour MiniMax. Lorsque je le relancerai, il générera un dossier vide ; je consulterai d’abord les appels write de la session avant de lire son rapport.

Voir aussi : Kimi K3 en tant qu’agent de programmation (l’aspect Kimi de cette comparaison), DeepSeek Harness (dsh) (les cinq tâches et le cahier des charges initial), Reasonix (évoqué dans d’autres articles ; retiré de mon système le 09/09/2026), ainsi que Le coût réel de mes agents IA.


← Plus de IA et LLM locaux