Skip to Content
Guide développeurSDK TypeScript

SDK TypeScript

@qwen-code/sdk

Un SDK TypeScript expérimental minimal pour un accès programmatique à Qwen Code.

N’hésitez pas à soumettre une demande de fonctionnalité, un problème ou une PR.

Installation

npm install @qwen-code/sdk

Prérequis

  • Node.js >= 22.0.0
  • Qwen Code  >= 0.4.0 (stable). Le SDK utilise sa CLI intégrée par défaut ; définissez pathToQwenExecutable uniquement lorsque vous avez besoin d’exécuter un binaire qwen personnalisé ou un bundle CLI.

Démarrage rapide

import { query } from '@qwen-code/sdk'; // Requête à un seul tour const result = query({ prompt: 'Quels fichiers se trouvent dans le répertoire actuel ?', options: { cwd: '/path/to/project', }, }); // Parcourir les messages for await (const message of result) { if (message.type === 'assistant') { console.log('Assistant :', message.message.content); } else if (message.type === 'result') { console.log('Résultat :', message.result); } }

Référence de l’API

query(config)

Crée une nouvelle session de requête avec Qwen Code.

Paramètres

  • prompt: string | AsyncIterable<SDKUserMessage> - Le prompt à envoyer. Utilisez une chaîne pour des requêtes à un seul tour ou un itérateur asynchrone pour des conversations multi-tours.
  • options: QueryOptions - Options de configuration pour la session de requête.

QueryOptions

OptionTypeDéfautDescription
cwdstringprocess.cwd()Le répertoire de travail pour la session de requête. Détermine le contexte dans lequel les opérations sur les fichiers et les commandes sont exécutées.
modelstring-Le modèle IA à utiliser (ex. 'qwen-max', 'qwen-plus', 'qwen-turbo'). Prédomine sur les variables d’environnement OPENAI_MODEL et QWEN_MODEL.
pathToQwenExecutablestringCLI intégréeChemin vers l’exécutable Qwen Code. Prend en charge plusieurs formats : 'qwen' (binaire natif depuis le PATH), '/path/to/qwen' (chemin explicite), '/path/to/cli.js' (bundle Node.js), 'node:/path/to/cli.js' (forcer l’exécution Node.js), 'bun:/path/to/cli.js' (forcer l’exécution Bun). S’il n’est pas fourni, le SDK utilise la CLI intégrée incluse dans le package.
permissionMode'default' | 'plan' | 'auto-edit' | 'auto' | 'yolo''default'Mode de permission contrôlant l’approbation d’exécution des outils. Voir Modes de permission pour plus de détails.
canUseToolCanUseTool-Gestionnaire de permission personnalisé pour l’approbation d’exécution des outils. Invoqué lorsqu’un outil nécessite une confirmation. Doit répondre dans les 60 secondes, sinon la demande est automatiquement refusée. Voir Gestionnaire de permission personnalisé.
envRecord<string, string>-Variables d’environnement à transmettre au processus Qwen Code. Fusionnées avec l’environnement du processus actuel.
systemPromptstring | QuerySystemPromptPreset-Configuration du prompt système pour la session principale. Utilisez une chaîne pour remplacer complètement le prompt système intégré de Qwen Code, ou un objet preset pour conserver le prompt intégré et ajouter des instructions supplémentaires.
mcpServersRecord<string, McpServerConfig>-Serveurs MCP (Model Context Protocol) à connecter. Prend en charge les serveurs externes (stdio/SSE/HTTP) et les serveurs intégrés au SDK. Les serveurs externes sont configurés avec des options de transport comme command, args, url, httpUrl, etc. Les serveurs SDK utilisent { type: 'sdk', name: string, instance: Server }.
abortControllerAbortController-Contrôleur pour annuler la session de requête. Appelez abortController.abort() pour terminer la session et libérer les ressources.
debugbooleanfalseActive le mode débogage pour une journalisation détaillée du processus CLI.
maxSessionTurnsnumber-1 (illimité)Nombre maximum de tours de conversation avant que la session ne se termine automatiquement. Doit être un entier. Un tour consiste en un message utilisateur et une réponse de l’assistant.
coreToolsstring[]-Utilise l’ancienne sémantique coreTools / liste d’autorisation CLI --core-tools. Si spécifié, seuls les outils de base correspondants sont enregistrés pour la session. Il s’agit de la seule option de type liste d’autorisation qui restreint l’enregistrement des outils intégrés ; une règle permissions.deny / excludeTools portant sur un outil entier (et tools.disabled dans settings.json) supprime également un outil du registre. permissions.allow dans settings.json est de l’auto-approbation pure et ne supprime, ne rétrograde ni ne masque jamais un outil (#10075). Pour exclure le schéma d’un outil de la requête initiale au modèle, utilisez tools.eager dans settings.json (nécessite un redémarrage, #9827) — tool_search, structured_output, les outils du cycle de vie du mode plan, task_stop, les outils mcp__* et computer_use__* sont exemptés de cette liste d’autorisation et conservent leur chargement normal ; pour le supprimer entièrement, utilisez une règle excludeTools / permissions.deny portant sur un outil entier — une règle avec un spécificateur (comme 'Bash(rm *)') ne refuse que les invocations correspondantes au runtime. Les outils MCP sont exemptés de la suppression par refus : masquez-les plutôt avec les filtres excludeTools / tools.disabled par serveur (le refus bloque toujours leurs appels au runtime). Exemple : ['read_file', 'edit', 'run_shell_command'].
excludeToolsstring[]-Équivalent à permissions.deny dans settings.json. Les outils exclus retournent immédiatement une erreur de permission. Priorité la plus élevée sur tous les autres paramètres de permission. Prend en charge les alias de noms d’outils et la correspondance de motifs : nom d’outil ('write_file'), préfixe de commande shell ('Bash(rm *)'), ou motifs de chemin ('Read(.env)', 'Edit(/src/**)').
allowedToolsstring[]-Équivalent à permissions.allow dans settings.json pour l’auto-approbation. Les outils correspondants contournent le callback canUseTool et s’exécutent automatiquement. S’applique uniquement lorsque l’outil nécessite une confirmation. Comme permissions.allow, il s’agit d’auto-approbation pure et cela n’affecte jamais les outils enregistrés ni les schémas envoyés (#10075). Prend en charge la même correspondance de motifs que excludeTools. Exemple : ['Bash(git status)', 'Bash(npm test)'].
authType'openai' | 'anthropic' | 'qwen-oauth' | 'gemini' | 'vertex-ai'-Type d’authentification pour le service IA. Lorsqu’il est fourni, le SDK le transmet à la CLI en tant que --auth-type.
agentsSubagentConfig[]-Configuration des sous-agents pouvant être invoqués pendant la session. Les sous-agents sont des IA spécialisées pour des tâches ou domaines spécifiques.
includePartialMessagesbooleanfalseLorsque true, le SDK émet les messages incomplets au fur et à mesure qu’ils sont générés, permettant un streaming en temps réel de la réponse de l’IA.
resumestring-Reprendre une session précédente en fournissant son ID de session. Équivalent au drapeau --resume du CLI.
sessionIdstring-Spécifie un ID de session pour la nouvelle session. Garantit que le SDK et le CLI utilisent le même ID sans reprendre l’historique. Équivalent au drapeau --session-id du CLI.

[!note] Pour coreTools, les alias comme Read, Edit et Bash fonctionnent également, mais les spécificateurs d’invocation tels que Bash(git *) sont supprimés. coreTools restreint l’enregistrement des outils, pas les motifs d’invocation.

Timeouts

Le SDK applique les timeouts par défaut suivants :

TimeoutDéfautDescription
canUseTool1 minDurée maximale pour la réponse du callback canUseTool. Si dépassée, la demande d’outil est automatiquement refusée.
mcpRequest1 minDurée maximale pour la complétion des appels d’outils MCP du SDK.
controlRequest1 minDurée maximale pour les opérations de contrôle comme initialize(), setModel(), setPermissionMode(), getContextUsage(), et interrupt().
streamClose1 minDurée maximale d’attente pour la fin de l’initialisation avant de fermer l’entrée standard du CLI en mode multi-tours avec serveurs MCP du SDK.

Vous pouvez personnaliser ces timeouts via l’option timeout :

import { query } from '@qwen-code/sdk'; const q = query({ prompt: 'Votre prompt', options: { timeout: { canUseTool: 60000, // 60 secondes pour le callback de permission mcpRequest: 600000, // 10 minutes pour les appels d'outils MCP controlRequest: 60000, // 60 secondes pour les requêtes de contrôle streamClose: 15000, // 15 secondes pour l'attente de fermeture du flux }, }, });

Types de messages

Le SDK fournit des gardes de type pour identifier les différents types de messages :

import { isSDKUserMessage, isSDKAssistantMessage, isSDKSystemMessage, isSDKResultMessage, isSDKPartialAssistantMessage, } from '@qwen-code/sdk'; for await (const message of result) { if (isSDKAssistantMessage(message)) { // Gérer un message de l'assistant } else if (isSDKResultMessage(message)) { // Gérer un message de résultat } }

Méthodes de l’instance Query

L’instance Query retournée par query() propose plusieurs méthodes :

const q = query({ prompt: 'Bonjour', options: {} }); // Obtenir l'ID de session const sessionId = q.getSessionId(); // Vérifier si fermée const closed = q.isClosed(); // Interrompre l'opération en cours await q.interrupt(); // Changer le mode de permission en cours de session await q.setPermissionMode('yolo'); // Changer le modèle en cours de session await q.setModel('qwen-max'); // Obtenir la répartition de l'utilisation de la fenêtre de contexte (nombre de tokens par catégorie) const usage = await q.getContextUsage(); // Passer true pour indiquer que les détails par élément doivent être affichés const detail = await q.getContextUsage(true); // Fermer la session await q.close();

interrupt() annule uniquement le tour actif. Pour une requête multi-tours créée avec un prompt itérable asynchrone, la requête et son flux d’entrée restent ouverts, donc les messages ultérieurs de l’itérable sont traités normalement. Utilisez close() ou abortez le AbortController configuré lorsque vous souhaitez terminer la session entière.

IDs de session fournis par l’appelant du démon

DaemonClient.createOrAttachSession accepte un sessionId optionnel pour les appelants qui doivent persister une identité avant la création de session :

import { DaemonClient } from '@qwen-code/sdk'; const daemon = new DaemonClient({ baseUrl: 'http://127.0.0.1:4170' }); const session = await daemon.createOrAttachSession({ workspaceCwd: '/path/to/project', sessionId: '550E8400-E29B-41D4-A716-446655440000', }); console.log(session.sessionId); // 550e8400-e29b-41d4-a716-446655440000

Le SDK exige la capacité session_id_override du démon avant d’envoyer la mutation. En mode REST, sessionId est sérialisé directement ; un adaptateur ACP actif le mappe vers session/new._meta["qwen-code/sessionId"]. Le SDK vérifie la réponse de succès et lève DaemonSessionIdProtocolError si le démon retourne un ID différent.

Cette option crée toujours une nouvelle session thread et n’est pas un attach idempotent. Si le résultat de création est ambigu, utilisez l’ID connu avec load ou resume. Omettre l’option préserve le comportement existant de create-or-attach.

Communication avec les sessions en cours

@qwen-code/sdk/peer permet à un programme qui n’est pas une session Qwen Code de rejoindre les sessions exécutées par le même utilisateur sur la même machine — un front-end vocal, un relais, un watcher de build. Le programme apparaît dans qwen sessions ps, et dans le list_agents de chaque session qui a agents.crossSessionMessaging activé — ce qui permet également à ces sessions de lui envoyer des messages par son nom avec send_message. Il peut leur répondre. Il fonctionne uniquement sur Node et n’a besoin de rien d’autre que Node lui-même.

import { PeerEndpoint } from '@qwen-code/sdk/peer'; const endpoint = await PeerEndpoint.start({ name: 'voice-bridge', onMessage: (message) => console.log(`${message.fromName}: ${message.content}`), }); const [session] = await endpoint.list(); if (session) { const sent = await endpoint.send({ to: session.address, content: 'Sur quoi travaillez-vous ?', }); if (sent.kind === 'sent') { const receipt = await endpoint.awaitReceipt(sent.msgId, { final: true }); console.log(receipt?.status); // delivered, denied, refused, ... } } await endpoint.close();

Un message comme celui-ci est mis en attente pour que l’utilisateur de la session puisse l’examiner. Pour diriger une session sans cet examen, créez un controller token avec qwen sessions controllers add --label voice-bridge, donnez-le à l’endpoint, et marquez les envois qui doivent le présenter :

const endpoint = await PeerEndpoint.start({ name: 'voice-bridge', controllerToken: process.env['QWEN_CONTROLLER_TOKEN'], }); await endpoint.send({ to: 'my-app-3f', content: 'exécute les tests', controller: true, });

Points à connaître :

  • Une session n’a une boîte de réception que lorsque son paramètre agents.crossSessionMessaging est activé, et ce paramètre est désactivé par défaut. Sans cela, la session n’apparaît pas dans list(), et ses propres list_agents et send_message ne peuvent pas non plus voir ou atteindre le programme. qwen sessions ps liste le programme dans tous les cas.
  • Un message est livré sans examen dans exactement deux cas : l’envoi présente un controller token (controller: true), ou son fromMode nomme la classe de review de la session destinataire. fromMode est une revendication que rien n’authentifie, donc un programme qui n’est pas une session de codage devrait l’omettre. Rien dans l’enregistrement — ni kind, ni name — ne garantit la livraison. Le paramètre agents.crossSessionInbound de la session destinataire l’emporte sur les deux : hold ou refuse à cet endroit gagne sur un controller token.
  • Marquez uniquement les envois destinés à diriger une session. Les adresses sont résolues à partir d’enregistrements que n’importe quel programme exécuté par vous peut écrire, donc un envoi controller présente le token à l’enregistrement du processus qui répond à cette adresse. Un envoi controller vers un autre peer endpoint est supprimé sans être lu, car la boîte de réception d’un endpoint n’accepte que son propre token.
  • La boîte de réception de l’endpoint n’applique aucune des protections qu’une session Qwen Code applique à la sienne : pas de rate limit, pas de holds, et pas de fenêtre de doublon au-delà des 200 derniers messages auxquels il a répondu. Chaque message reçoit une réponse delivered et est transmis à onMessage à son arrivée, donc appliquez vos propres limites à cet endroit si vous en avez besoin. Sans onMessage, chaque message reçoit une réponse refused.
  • Appelez close() avant de quitter, y compris depuis vos propres gestionnaires de signaux. Un processus tué sans fermeture laisse son enregistrement derrière lui jusqu’à ce qu’une session Qwen Code liste le répertoire et voie que le processus a disparu.
  • Sockets de domaine UNIX uniquement : Windows n’est pas encore pris en charge.

Le schéma d’enregistrement, le format de transmission et les états de reçu sont documentés dans Cross-Session Protocol.

Modes de permission

Le SDK prend en charge différents modes de permission pour contrôler l’exécution des outils :

  • default : Les outils d’écriture sont refusés sauf approbation via le callback canUseTool ou s’ils sont dans allowedTools. Les outils en lecture seule s’exécutent sans confirmation.
  • plan : Bloque tous les outils d’écriture, en demandant à l’IA de présenter d’abord un plan.
  • auto-edit : Approuve automatiquement les outils d’édition (edit, write_file, notebook_edit) tandis que les autres outils nécessitent une confirmation.
  • auto : Utilise le classificateur intégré pour approuver automatiquement les appels d’outils sûrs et bloquer les risqués, avec un fallback vers l’approbation manuelle après des blocages répétés par la politique ou des pannes du classificateur.
  • yolo : Tous les outils s’exécutent automatiquement sans confirmation.

Chaîne de priorité des permissions

Priorité de décision (la plus élevée en premier) : deny > ask > allow > (comportement par défaut/mode interactif)

La première règle correspondante l’emporte.

  1. excludeTools / permissions.deny - Bloque complètement les outils (retourne une erreur de permission)
  2. permissions.ask - Nécessite toujours une confirmation utilisateur
  3. permissionMode: 'plan' - Bloque tous les outils non en lecture seule
  4. permissionMode: 'yolo' - Approuve automatiquement tous les outils
  5. allowedTools / permissions.allow - Approuve automatiquement les outils correspondants
  6. permissionMode: 'auto' - Approbation via classificateur pour les outils restants
  7. Callback canUseTool - Logique d’approbation personnalisée (si fourni, non appelé pour les outils autorisés)
  8. Comportement par défaut - Refus automatique en mode SDK (les outils d’écriture nécessitent une approbation explicite)

Exemples

Conversation multi-tours

import { query, type SDKUserMessage } from '@qwen-code/sdk'; async function* generateMessages(): AsyncIterable<SDKUserMessage> { yield { type: 'user', session_id: 'ma-session', message: { role: 'user', content: 'Crée un fichier hello.txt' }, parent_tool_use_id: null, }; // Attendre une condition ou une entrée utilisateur yield { type: 'user', session_id: 'ma-session', message: { role: 'user', content: 'Maintenant, lis le fichier' }, parent_tool_use_id: null, }; } const result = query({ prompt: generateMessages(), options: { permissionMode: 'auto-edit', }, }); for await (const message of result) { console.log(message); }

Gestionnaire de permission personnalisé

import { query, type CanUseTool } from '@qwen-code/sdk'; const canUseTool: CanUseTool = async (toolName, input, { signal }) => { // Autoriser toutes les opérations de lecture if (toolName.startsWith('read_')) { return { behavior: 'allow', updatedInput: input }; } // Demander à l'utilisateur pour les opérations d'écriture (dans une vraie application) const userApproved = await promptUser(`Autoriser ${toolName} ?`); if (userApproved) { return { behavior: 'allow', updatedInput: input }; } return { behavior: 'deny', message: 'L\'utilisateur a refusé l\'opération' }; }; const result = query({ prompt: 'Crée un nouveau fichier', options: { canUseTool, }, });

Avec des serveurs MCP externes

import { query } from '@qwen-code/sdk'; const result = query({ prompt: 'Utilise l\'outil personnalisé de mon serveur MCP', options: { mcpServers: { 'mon-serveur': { command: 'node', args: ['chemin/vers/mcp-server.js'], env: { PORT: '3000' }, }, }, }, });

Remplacer le prompt système

import { query } from '@qwen-code/sdk'; const result = query({ prompt: 'Dis bonjour en une phrase.', options: { systemPrompt: 'Tu es un assistant concis. Réponds exactement en une phrase.', }, });

Ajouter au prompt système intégré

import { query } from '@qwen-code/sdk'; const result = query({ prompt: 'Examine le répertoire actuel.', options: { systemPrompt: { type: 'preset', preset: 'qwen_code', append: 'Sois concis et concentre-toi sur les constats concrets.', }, }, });

Avec les serveurs MCP intégrés au SDK

Le SDK fournit tool et createSdkMcpServer pour créer des serveurs MCP qui s’exécutent dans le même processus que votre application SDK. Cela est utile lorsque vous souhaitez exposer des outils personnalisés à l’IA sans lancer de processus serveur séparé.

tool(name, description, inputSchema, handler)

Crée une définition d’outil avec inférence de type via le schéma Zod.

ParamètreTypeDescription
namestringNom de l’outil (1 à 64 caractères, commence par une lettre, alphanumérique et tirets bas)
descriptionstringDescription lisible par un humain de ce que fait l’outil
inputSchemaZodRawShapeObjet de schéma Zod définissant les paramètres d’entrée de l’outil
handler(args, extra) => Promise<Result>Fonction asynchrone qui exécute l’outil et renvoie des blocs de contenu MCP

Le handler doit renvoyer un objet CallToolResult avec la structure suivante :

{ content: Array< | { type: 'text'; text: string } | { type: 'image'; data: string; mimeType: string } | { type: 'resource'; uri: string; mimeType?: string; text?: string } >; isError?: boolean; }

createSdkMcpServer(options)

Crée une instance de serveur MCP intégrée au SDK.

OptionTypeValeur par défautDescription
namestringRequisNom unique pour le serveur MCP
versionstring'1.0.0'Version du serveur
toolsSdkMcpToolDefinition[]-Tableau d’outils créés avec tool()

Renvoie un objet McpSdkServerConfigWithInstance qui peut être passé directement à l’option mcpServers.

Exemple

import { z } from 'zod'; import { query, tool, createSdkMcpServer } from '@qwen-code/sdk'; // Définir un outil avec le schéma Zod const calculatorTool = tool( 'calculate_sum', 'Add two numbers', { a: z.number(), b: z.number() }, async (args) => ({ content: [{ type: 'text', text: String(args.a + args.b) }], }), ); // Créer le serveur MCP const server = createSdkMcpServer({ name: 'calculator', tools: [calculatorTool], }); // Utiliser le serveur dans une requête const result = query({ prompt: 'Combien font 42 + 17 ?', options: { permissionMode: 'yolo', mcpServers: { calculator: server, }, }, }); for await (const message of result) { console.log(message); }

Annuler une requête

import { query, isAbortError } from '@qwen-code/sdk'; const abortController = new AbortController(); const result = query({ prompt: 'Tâche de longue durée...', options: { abortController, }, }); // Annuler après 5 secondes setTimeout(() => abortController.abort(), 5000); try { for await (const message of result) { console.log(message); } } catch (error) { if (isAbortError(error)) { console.log('La requête a été annulée'); } else { throw error; } }

Gestion des erreurs

Le SDK fournit une classe AbortError pour gérer les requêtes annulées :

import { AbortError, isAbortError } from '@qwen-code/sdk'; try { // ... opérations de requête } catch (error) { if (isAbortError(error)) { // Gérer l'annulation } else { // Gérer les autres erreurs } }
Last updated on