Verarbeiten von Genehmigungen und Benutzereingaben

Verwenden Sie die allowedTools/disallowedTools-Regeln und einen canUseTool-Callback, um zu steuern, welche Tools der Agent verwenden kann und wie mit Berechtigungsanfragen umgegangen wird.

Standardmäßig erzwingt das SDK die Berechtigungen für Tools und umgeht diese nicht. Der canUseTool-Callback gibt Ihnen eine genauere Kontrolle über Berechtigungsanfragen, die noch nicht durch allowedTools/disallowedTools-Regeln oder durch einen expliziten Berechtigungsmodus wie bypassPermissions gelöst sind.

Das SDK bietet standardmäßig keine interaktive Berechtigungsabfrage. Wenn eine auf Berechtigungen geprüfte Anfrage das SDK erreicht und canUseTool nicht angegeben ist, schlägt die Anfrage fehl.

Wie es funktioniert

Wenn Sie einen canUseTool-Callback angeben, ruft das SDK ihn vor jeder Ausführung eines Tools mit Berechtigungsprüfung auf. Ihr Callback entscheidet, was passiert:

  1. Der Agent entscheidet, ein auf Berechtigungen geprüftes Tool zu verwenden.

  2. Das SDK ruft Ihren canUseTool-Callback mit dem Namen des Tools, der Anfrageeingabe und dem Berechtigungskontext auf.

  3. Ihr Callback gibt allow oder deny zurück.

  4. Die Ausführung des Tools wird fortgesetzt oder wird entsprechend blockiert.

Bei vielen normalen Berechtigungsprüfungen für Tools enthält die Callback-Eingabe Felder wie { action, resource }. SDK-geroutete Pseudo-Tools wie AskUserQuestion und ExitPlanMode enthalten toolspezifische Felder.

Wenn canUseTool nicht angegeben ist und eine Anfrage mit Berechtigungsprüfung das SDK erreicht, gibt das SDK einen Fehler zurück, anstatt interaktiv zu fragen.

Grundlegendes Beispiel

import { createCortexCodeSession } from "cortex-code-agent-sdk";

const session = await createCortexCodeSession({
  cwd: process.cwd(),
  canUseTool: async (toolName, input, context) => {
    console.log(`Tool requested: ${toolName}`, input);

    // Allow read-only tools, deny destructive ones
    if (["Read", "Glob", "Grep"].includes(toolName)) {
      return { behavior: "allow" };
    }

    return { behavior: "deny", message: "Only read-only tools are allowed" };
  },
});

await session.send("What files are in this directory?");
for await (const event of session.stream()) {
  if (event.type === "assistant") {
    for (const b of event.content) {
      if (b.type === "text") process.stdout.write(b.text);
    }
  }
  if (event.type === "result") break;
}
await session.close();

Antwortmuster

Tool-Aufruf erlauben

Rückgabe von { behavior: "allow" }, damit das Tool mit seiner ursprünglichen Eingabe ausgeführt wird:

canUseTool: async (toolName, input, context) => {
  return { behavior: "allow" };
}

Tool-Aufruf ablehnen

Rückgabe von { behavior: "deny" } mit einer optionalen Nachricht. Der Agent sieht die Ablehnungsmeldung und kann seine Vorgehensweise anpassen:

canUseTool: async (toolName, input, context) => {
  if (toolName === "Bash") {
    return { behavior: "deny", message: "Bash commands are not allowed in this session" };
  }
  return { behavior: "allow" };
}

Das AskUserQuestion-Tool

Cortex Code verfügt über ein integriertes AskUserQuestion-Tool, das der Agent verwendet, wenn er weitere Angaben vom Benutzer benötigt. Wenn der Agent AskUserQuestion aufruft, routet das SDK dies über Ihren``canUseTool``-Callback, wobei toolName auf "AskUserQuestion" gesetzt ist. Die Eingabe enthält die Fragen des Agenten als strukturierte Mehrfachauswahl-Optionen.

Verarbeitung von Fragen

Suchen Sie nach toolName === "AskUserQuestion" in Ihrem canUseTool-Callback. input enthält ein questions-Array, wobei jede Frage Folgendes enthält:

Feld

Beschreibung

question

Der vollständige Fragetext, der angezeigt werden soll

header

Kurzer Bezeichner für die Frage

options

Array von Auswahlmöglichkeiten, jeweils mit label, description, freeForm (Boolesch) und isCancel (Boolesch)

multiSelect

Wenn true, können Benutzer mehrere Optionen auswählen

Rückgabe von allow mit einem updatedInput, welches die ursprünglichen questions und eine answers-Zuordnung enthält. Jeder Schlüssel ist der Fragetext und jeder Wert ist der Bezeichner der ausgewählten Option. Bei Fragen mit mehreren Auswahlen setzen Sie die Beschriftungen auf den Wert ", ".

const session = await createCortexCodeSession({
  cwd: process.cwd(),
  canUseTool: async (toolName, input, context) => {
    if (toolName === "AskUserQuestion") {
      const answers: Record<string, string> = {};
      for (const q of input.questions) {
        // Present q.question and q.options to the user, collect their choice
        const selected = await promptUser(q.question, q.options);
        answers[q.question] = selected;
      }
      return {
        behavior: "allow",
        updatedInput: { questions: input.questions, answers },
      };
    }
    return { behavior: "allow" };
  },
});

Um eine Frage abzulehnen (die Interaktion abzubrechen), geben Sie deny zurück:

return { behavior: "deny", message: "User cancelled" };

Tipp

AskUserQuestion wird über canUseTool weitergeleitet. Ohne einen Callback kann die Interaktion nicht abgeschlossen werden und die Anfrage schlägt fehl, anstatt im Hintergrund fortzufahren.

Das ExitPlanMode-Tool

Wenn sich eine Sitzung im plan-Modus befindet, bleibt Cortex Code in der Planung, bis der Plan genehmigt wurde. Die Genehmigungsanfrage wird über Ihren canUseTool-Callback weitergeleitet, wobei toolName/tool_name auf "ExitPlanMode" gesetzt ist.

Die Eingabe enthält:

Feld

Beschreibung

plan

Der vorgeschlagene Plan, den der Agent ausführen möchte

question

Optionale zusätzliche Genehmigungsaufforderung durch den Agenten

Genehmigen oder Ablehnen eines Plans

Rückgabe von allow, um den Plan zu genehmigen. Sie können optional updatedInput.message einschließen, um den Überprüfungskontext an den Agenten zurückzugeben, bevor er den Planmodus verlässt.

Rückgabe von deny, um den Plan abzulehnen. Verwenden Sie message, wenn Sie möchten, dass der Agent den Plan mit spezifischem Feedback überarbeitet. Ablehnen von ExitPlanMode behält die aktuelle Wendung im Planmodus bei, sodass der Agent den Plan aktualisieren und erneut fragen kann.

Genehmigen von ExitPlanMode beendet den Planmodus für die aktuelle Runde. Nachfolgende Wendungen setzen das normale Nicht-Plan-Berechtigungsverhalten der Sitzung fort, sodass spätere Tool-Aufrufe so ausgewertet werden wie außerhalb des Plan-Modus.

Beispiel für eine Überprüfungsschleife

Die einfachste Überprüfungsschleife besteht darin, einen schwachen Plan einmal mit spezifischem Feedback abzulehnen und dann den überarbeiteten Plan zu genehmigen:

let rejectedOnce = false;

const session = await createCortexCodeSession({
  cwd: process.cwd(),
  permissionMode: "plan",
  canUseTool: async (toolName, input) => {
    if (toolName === "ExitPlanMode") {
      const plan = String(input.plan ?? "");
      if (!rejectedOnce) {
        rejectedOnce = true;
        return {
          behavior: "deny",
          message: "Add a verification step and say which file you will edit.",
        };
      }
      return {
        behavior: "allow",
        updatedInput: {
          message: `Approved plan: ${plan}`,
        },
      };
    }
    return { behavior: "allow" };
  },
});

Regelbasierte Berechtigungen

Für gängige Berechtigungsmuster können Sie eine regelbasierte Konfiguration verwenden, anstatt Callback-Logik zu schreiben. Mit den Optionen allowedTools und disallowedTools können Sie Listen von Tools definieren, die automatisch zugelassen oder gesperrt werden:

const session = await createCortexCodeSession({
  cwd: process.cwd(),
  allowedTools: ["Read", "Glob", "Grep", "Bash(npm test:*)"],
  disallowedTools: ["Write"],
});

allowedTools-Einträge können Muster enthalten. Beispiel: Bash(npm test:*) genehmigt automatisch jeden Bash-Befehl, der mit diesem Muster übereinstimmt. disallowedTools-Einträge blockieren bestimmte Tools vollständig.

Diese Regeln werden von der CLI vor dem``canUseTool``-Callback ausgewertet. Wenn ein Tool mit einer zulässigen oder unzulässigen Regel übereinstimmt, wird der Callback für dieses Tool nicht aufgerufen.

Kombinieren mit Berechtigungsmodi

Der canUseTool-Callback funktioniert zusätzlich zu den Berechtigungsmodi. Wenn beide eingestellt sind, werden die integrierten Berechtigungsmodus-Filter der CLI zuerst ausgeführt, und Ihr Callback verarbeitet alle verbleibenden Tool-Aufrufe, die eine Genehmigung benötigen.

Die verfügbaren Berechtigungsmodi sind:

Modus

Beschreibung

default

Verwendet Standardberechtigungsprüfungen. In SDK-Sitzungen steuern Sie berechtigungsgeprüfte Tools mit allowedTools, disallowedTools oder canUseTool.

autoAcceptPlans

Genehmigt Plananfragen und Bestätigungen zum Verlassen eines Plans automatisch. Die normalen Tool-Berechtigungen werden nicht umgangen.

plan

Der Agent plant Änderungen, führt sie aber nicht ohne Genehmigung aus. Mit canUseTool werden Genehmigungen im Planmodus über ExitPlanMode weitergeleitet. Wenn Sie diese Anfrage ablehnen, bleibt die Planung aktiv. Wenn Sie sie genehmigen, wird der Planmodus beendet, sodass spätere Turns die normalen Berechtigungen wieder aufnehmen.

bypassPermissions

Überspringt alle Berechtigungsprüfungen. Erfordert allowDangerouslySkipPermissions: true (TypeScript) oder allow_dangerously_skip_permissions=True (Python) als Sicherheitsflag.

Ändern des Berechtigungsmodus während einer Sitzung

Sie können den Berechtigungsmodus nach Beginn der Sitzung ändern. TypeScript stellt setPermissionMode() für beide Query und CortexCodeSession zur Verfügung. Python stellt set_permission_mode() unter CortexCodeSDKClient zur Verfügung.

Der aktualisierte Modus gilt für spätere Runden, nachdem die Steuerungsanforderung verarbeitet wurde. Ein bereits ausgeführter Tool-Aufruf wird nicht rückwirkend geändert.

const session = await createCortexCodeSession({
  cwd: process.cwd(),
});

await session.setPermissionMode("plan");
await session.send("Review the repo and propose a plan before editing.");

await session.setPermissionMode("default");
await session.send("Now implement the approved change.");

Hooks

Mit Hooks können Sie die Ausführung von Tools in verschiedenen Lebenszyklusstufen abfangen. Im Gegensatz zu canUseTool, das nur steuert, ob ein Tool ausgeführt wird, können Hooks die Ergebnisse des Tools überprüfen, den Kontext einfügen und den Agentenfluss steuern.

import { createCortexCodeSession } from "cortex-code-agent-sdk";

const session = await createCortexCodeSession({
  cwd: process.cwd(),
  hooks: {
    PreToolUse: [
      {
        matcher: "Bash",
        hooks: [
          async (input, toolUseId, context) => {
            console.log(`About to run Bash: ${input.tool_input?.command}`);
            return {};  // Allow execution to proceed
          },
        ],
      },
    ],
    PostToolUse: [
      {
        hooks: [
          async (input, toolUseId, context) => {
            console.log(`Tool ${input.tool_name} completed`);
            return {};
          },
        ],
      },
    ],
  },
});

Hook-Ereignisse

Ereignis

Wann es ausgelöst wird

PreToolUse

Bevor ein Tool ausgeführt wird. Kann die Ausführung blockieren oder die Eingabe ändern.

PostToolUse

Nachdem ein Tool erfolgreich abgeschlossen wurde.

UserPromptSubmit

Wenn eine Benutzer-Eingabeaufforderung gesendet wird.

Stop

Wenn der Agent stoppt.

SubagentStop

Wenn ein Subagent stoppt.

Notification

Wenn der Agent eine Benachrichtigung ausgibt.

PermissionRequest

Wenn eine Berechtigungsanforderung für ein Tool erfolgt.

PreCompact

Vor der Kontextkomprimierung.

Das Feld matcher bei einem Hook-Eintrag ist optional. Wenn bereitgestellt, wird nach dem Übereinstimmungswert des Ereignisses gefiltert: Tool-Name für PreToolUse, PostToolUse und PermissionRequest; Benachrichtigungstyp für Notification und Trigger für PreCompact. Wenn dies weggelassen wird, wird der Hook für alle Werte dieses Ereignisses ausgelöst.

Siehe TypeScript SDK-Referenz und Python SDK-Referenz für die vollständigen Definitionen der Hook-Eingabe- und Ausgabetypen.

Auswählen eines Ansatzes

Ansatz

Einsatzszenarios

permissionMode: "bypassPermissions" mit Sicherheitsflag

Sandbox-Umgebungen, CI-Pipelines oder vollständig vertrauenswürdige Szenarios, in denen Sie die Tool-Aufrufe nicht überprüfen müssen. Erfordert allowDangerouslySkipPermissions: true (TypeScript) oder allow_dangerously_skip_permissions=True (Python).

allowedTools / disallowedTools

Wenn Sie Ihre Berechtigungsrichtlinie als statische Liste von zulässigen oder blockierten Tools ausdrücken können

canUseTool-Callback

Produktionssysteme, bei denen Sie Tool-Aufrufe vor der Ausführung überprüfen, filtern oder ändern müssen

Nur Berechtigungsmodus (kein Callback)

Wenn autoAcceptPlans ausreichend ist und Sie keine kundenspezifische Verarbeitung des Callbacks benötigen

Hooks

Wenn Sie die Ergebnisse von Tools beobachten oder darauf reagieren müssen, Kontext einfügen und den Agentenfluss über Zulassen/Ablehnen-Entscheidungen hinaus steuern möchten.

Bemerkung

Das SDK umgeht standardmäßig keine Berechtigungen oder fordert Sie interaktiv auf. Wenn eine auf Berechtigungen geprüfte Anfrage das SDK erreicht und canUseTool nicht angegeben ist, schlägt die Anfrage fehl. Um Berechtigungen zu umgehen, müssen Sie explizit permissionMode: "bypassPermissions" mit dem entsprechenden Sicherheitsflag festlegen.