Przejdź do głównej zawartości

Sterowanie agentami z kodu: Claude Agent SDK, Codex SDK i Cursor SDK

Claude Agent SDK, Codex SDK i Cursor SDK pozwalają, by agenta kodującego uruchamiał program, a nie człowiek: uruchamia go, ogranicza mu narzędzia, odczytuje typowany wynik i później wznawia pracę. SDK wybierz wtedy, gdy kod musi się rozgałęziać na podstawie tego, co znalazł agent; jednorazowy krok CI nadal lepiej obsłuży claude -p albo codex exec.

CI robi się czerwone o 2:10. Zanim ktokolwiek zajrzy, w kolejce czekają trzy kolejne pushe, a pierwsze pół godziny poranka schodzi na czytaniu 4000 linii logu tylko po to, by się dowiedzieć, że znowu zawiódł niestabilny test. Bota już próbowałeś: krok workflow przekazuje log do claude -p i publikuje odpowiedź jako komentarz. To pomaga, ale taki bot nie uruchomi ponownie niestabilnego testu i nie poczeka na wynik, nie otworzy drugiej sesji z prawem zapisu tylko wtedy, gdy werdykt brzmi „regresja”, a nikt nie wie, ile kosztował w zeszłym miesiącu. W tym miejscu przestajesz agenta wyzwalać i zaczynasz nim sterować z kodu.

Ta strona jest dla programistów, którzy budują taką automatyzację, i dla tech leadów, którzy decydują, na jakim SDK zespół się ustandaryzuje. Porównuje trzy SDK w pięciu wymiarach, które przesądzają o wyborze – sesje, narzędzia, uprawnienia, strumieniowanie i koszt – i pokazuje to samo zadanie napisane w każdym z nich.

  • Tabelę decyzyjną „wyzwolić czy oskryptować”, którą zastosujesz do każdego pomysłu na automatyzację.
  • Porównanie trzech SDK pod kątem sesji, narzędzi, uprawnień, strumieniowania, ustrukturyzowanego wyniku i kosztu, sprawdzone na opublikowanych pakietach 26.09.2026.
  • Runner triażu nieudanego przebiegu CI napisany trzy razy – w Claude Agent SDK, Codex SDK i Cursor SDK – ze wspólnym promptem i wspólnym JSON Schema oraz workflow GitHub Actions, który go wywołuje.
  • Bramki, dzięki którym jego wynikowi można ufać bez czytania każdego przebiegu, i błędy, które pojawiają się najpierw.

Większość zadań typu „agent w CI” nigdy nie potrzebuje SDK. Wyzwalacz – GitHub Action, zaplanowana automatyzacja albo pojedyncze wywołanie CLI w trybie headless – przyjmuje prompt i zwraca komentarz, plik albo pull request. SDK uzasadnia dodatkowy kod dopiero wtedy, gdy logika orkiestracji mieszka w twoim programie.

Twoje zadanie wymaga…Wystarczy wyzwalaczSięgnij po SDK
Jeden prompt na wejściu, jeden wynik na wyjściuclaude -p --output-format json, codex exec --json -o out.json, tryb print w Cursorze, anthropics/claude-code-action@v1, openai/codex-action@v1, Cursor Automations—
Typowanego wyniku, który konsumuje skryptclaude -p --json-schema, codex exec --output-schema FILEGdy od wartości zależy następny krok
Różnych kroków zależnie od wyniku (ponowne uruchomienie, etykieta, sesja naprawcza)Tylko przez kruchy klej w shelluTak: rozgałęzienie w kodzie, wznowienie tej samej sesji
Narzędzi, które wołają twoje systemy (zgłoszenia, feature flagi, wewnętrzne API)Serwer MCP, który wdrażasz i utrzymujeszNarzędzia w procesie: createSdkMcpServer w Claude, customTools w Cursorze
Decyzji o uprawnieniu przy każdym wywołaniu („pozwól na git show, zabroń git push, o resztę zapytaj usługę”)Statyczne listy dozwolonych i zabronionychCallback canUseTool i hooki w Claude
Postępu na żywo we własnym interfejsie, bocie albo loguŚledzenie pliku JSONLTypowane strumienie zdarzeń we wszystkich trzech SDK
Rozliczenia kosztu per przebieg, zespół albo klientParsowanie JSON-a z CLIPola kosztu lub zużycia w wyniku
Wielu agentów koordynowanych przez twój kod—Tak; zobacz wzorce orkiestracji wielu agentów

Reguła praktyczna: jeśli zadanie da się opisać jednym promptem ze stałym wynikiem, zostaw wyzwalacz. Jeśli łapiesz się na pisaniu instrukcji if wokół odpowiedzi agenta, przejdź na SDK. Opcje na poziomie CLI opisują osobno automatyzacja w Claude Code i tryb nieinteraktywny Codeksa.

Czym różnią się Claude Agent SDK, Codex SDK i Cursor SDK?

Dział zatytułowany „Czym różnią się Claude Agent SDK, Codex SDK i Cursor SDK?”

Wszystkie trzy zamykają w bibliotece własnego agenta kodującego dostawcy: te same narzędzia, te same pliki instrukcji projektu i ten sam katalog modeli, których używasz interaktywnie. Różnią się tym, o czym może decydować twój kod. Wszystko poniżej odczytano z opublikowanych pakietów TypeScript 26.09.2026.

Claude Agent SDKCodex SDKCursor SDK
Sprawdzone pakietynpm @anthropic-ai/claude-agent-sdk 0.3.283, PyPI claude-agent-sdk 0.2.160npm @openai/codex-sdk 0.157.1, PyPI openai-codex 0.157.1npm @cursor/sdk 1.0.32, PyPI cursor-sdk 1.0.32
Co działa pod spodemBinarka Claude Code instalowana jako pakiet platformowyCLI codex z @openai/codex, z którym SDK rozmawia przez JSONL na stdin i stdoutAgent lokalny albo agent chmurowy w izolowanej maszynie wirtualnej, gdy przekażesz cloud
ŚrodowiskoNode 18+Node 18+Node 22.13+
Punkt wejściaquery({ prompt, options }), asynchroniczny generator wiadomościnew Codex().startThread(), potem thread.run() albo thread.runStreamed()Agent.create(), potem agent.send() zwracające Run
Sesjesession_id w każdej wiadomości; resume, continue, forkSessionid wątku; codex.resumeThread(id); wątki zapisują się w ~/.codex/sessionsagentId; Agent.resume(id); agenci lokalni zapisują się w magazynie SQLite albo JSONL, ID agentów chmurowych zaczynają się od bc-
Ograniczanie narzędzitools ustala zestaw narzędzi; allowedTools tylko automatycznie zatwierdza; disallowedTools usuwaBrak listy narzędzi; granicę wyznacza tryb sandboksatools i disallowedTools (tylko agenci lokalni)
Własne narzędziaSerwer MCP w procesie przez createSdkMcpServer() i tool(), plus mcpServersSerwery MCP z konfiguracji CodeksaCallbacki customTools (tylko lokalnie), plus mcpServers
UprawnieniapermissionMode (default, acceptEdits, plan, dontAsk, auto, bypassPermissions), callback canUseTool, hooki takie jak PreToolUsesandboxMode (read-only, workspace-write, danger-full-access) plus approvalPolicy (never, on-request, on-failure, untrusted)local.sandboxOptions, local.autoReview (Auto-review Cursora oparty na klasyfikatorze); agenta chmurowego izoluje jego maszyna wirtualna
StrumieniowanieKażda wiadomość na bieżąco; includePartialMessages dodaje przyrosty tokenówrunStreamed() zwraca thread.started, item.*, turn.completed, turn.failed, errorrun.stream() oraz callbacki onStep i onDelta w send()
Ustrukturyzowany wynikoutputFormat: { type: 'json_schema', schema } → structured_output w wynikuoutputSchema dla tury → JSON w finalResponseBrak opcji schematu w 1.0.32; raport przechwytujesz przez własne narzędzie
Limity i kosztmaxTurns, maxBudgetUsd; total_cost_usd w wyniku, opisany w typach jako szacunekusage w tokenach przy turn.completed; brak pola w dolarach i brak limitu kosztu; anulowanie przez AbortSignalagent.getUsage() zwraca tokeny i koszt w centach, który może spóźniać się względem przebiegu; anulowanie przez run.cancel()
ModelDomyślny model Claude Code, chyba że ustawisz modelDomyślny model Codeksa, chyba że ustawisz model; modelReasoningEffortmodel jest wymagany dla agentów lokalnych; listę ID daje Cursor.models.list()

Trzy konsekwencje łatwo przeoczyć w tabeli:

  • Tylko Claude pozwala kodowi decydować o każdym wywołaniu narzędzia. canUseTool i hooki PreToolUse widzą każde wywołanie, zanim się wykona. Codex SDK daje granicę sandboksa zamiast callbacku (w @openai/codex-sdk 0.157.1 nie ma hooka per wywołanie), a Cursor SDK – listy narzędzi i Auto-review.
  • Agent SDK nie startuje w trybie auto. Od Claude Code v2.1.283 (kanał latest) sesje interaktywne startują w trybie auto, ale Agent SDK i claude -p nadal startują w ręcznym trybie uprawnień (default). Zadanie bez nadzoru, które liczy na odpowiedzi na pytania o zgodę, utknie albo dostanie odmowę, więc wybierz dontAsk z jawną listą dozwolonych poleceń.
  • Tylko Cursor SDK potrafi przekazać pracę do maszyny wirtualnej w chmurze. Przekazanie cloud: { repos: [...] } uruchamia agenta na infrastrukturze Cursora, a ten może sam otworzyć pull request (autoCreatePR). Listy narzędzi, własne narzędzia i własny prompt systemowy działają w 1.0.32 tylko lokalnie, a połączenie tools z cloud rzuca ConfigurationError.

Model nie jest powodem wyboru SDK: każde z nich domyślnie używa domyślnego modelu swojego narzędzia. Zacznij od niego i dostrój poziom wysiłku (effort), zanim zmienisz model, a aktualne nazwy i ceny sprawdzaj w przeglądzie modeli.

To samo zadanie trzy razy: triaż nieudanego przebiegu CI

Dział zatytułowany „To samo zadanie trzy razy: triaż nieudanego przebiegu CI”

Zadanie: gdy workflow CI się wyłoży, pobierz log nieudanych kroków, znajdź pierwszy prawdziwy błąd, odtwórz go, uruchom ponownie, by wykluczyć niestabilność, i zapisz triage.json z kategorią (regression, flaky, infra, test-bug), nieudanymi testami, podejrzanym commitem, dowodami i następnym krokiem. Agentowi nie wolno niczego edytować. O tym, co zrobić z werdyktem, decyduje późniejszy krok.

Trzy runnery dzielą jeden prompt i jeden schemat, więc zmiana dostawcy zmienia tylko plik runnera.

ci/triage-spec.ts
export const triageSchema = {
type: 'object',
properties: {
category: { type: 'string', enum: ['regression', 'flaky', 'infra', 'test-bug'] },
failing_tests: { type: 'array', items: { type: 'string' } },
suspect_commit: { type: 'string' },
evidence: { type: 'string' },
next_step: { type: 'string' },
},
required: ['category', 'failing_tests', 'suspect_commit', 'evidence', 'next_step'],
additionalProperties: false,
};
export const triagePrompt = `CI failed on this commit. The job log is in ci-failure.log.
Triage it; do not fix anything and do not edit any file.
1. Find the first real failure in the log (skip cascading errors).
2. Reproduce only the failing test(s) with: npx vitest run <file>.
3. Run it twice more. Passes on a rerun => "flaky".
4. Network, runner, secret or cache errors => "infra".
5. Otherwise read git log -5 and the diff of the suspect commit;
decide "regression" (code broke) or "test-bug" (test is wrong).
Cite log lines and command output as evidence. Use "unknown" for
suspect_commit when you cannot name one.`;

Cursor SDK nie ma opcji schematu wyniku, dlatego runner daje agentowi własne narzędzie submit_triage, którego schemat wejścia to schemat triażu. Argumenty wywołania tego narzędzia są raportem. Agent lokalny wymaga jawnego ID modelu; listę ID dostępnych dla twojego klucza zwraca Cursor.models.list(), a wybrane ID zapisz w CURSOR_MODEL_ID.

ci/triage-cursor.ts
import { writeFile } from 'node:fs/promises';
import { Agent, type SDKJsonValue } from '@cursor/sdk';
import { triagePrompt, triageSchema } from './triage-spec.js';
let report: Record<string, SDKJsonValue> | undefined;
const agent = await Agent.create({
apiKey: process.env.CURSOR_API_KEY,
model: { id: process.env.CURSOR_MODEL_ID! }, // required for local agents
disallowedTools: ['edit', 'delete', 'applyAgentDiff'],
local: {
cwd: process.env.GITHUB_WORKSPACE,
settingSources: ['project'],
customTools: {
submit_triage: {
description: 'Submit the final triage report. Call it exactly once, at the end.',
inputSchema: triageSchema,
execute: (args) => {
report = args;
return 'recorded';
},
},
},
},
});
try {
const run = await agent.send(`${triagePrompt}\nFinish by calling submit_triage.`);
const timer = setTimeout(() => void run.cancel(), 10 * 60_000);
for await (const message of run.stream()) {
if (message.type === 'tool_call' && message.status === 'completed') console.log('tool', message.name);
}
const result = await run.wait();
clearTimeout(timer);
if (result.status !== 'finished' || !report) throw new Error(`triage ${result.status}, no report`);
await writeFile('triage.json', JSON.stringify(report, null, 2));
const usage = await agent.getUsage(); // cost can lag the run
console.log(`agent ${agent.agentId}`, usage.usage, usage.cost);
} finally {
agent.close();
}

disallowedTools usuwa narzędzia edycji, ale shell zostaje, a z shella nadal da się zapisać plik. Regułę „bez edycji” egzekwuje dopiero krok git diff --exit-code w workflow poniżej.

Wszystkie trzy pliki przechodzą sprawdzanie typów w TypeScript 5 (strict, NodeNext) z wersjami pakietów z tabeli porównawczej. Uruchamiasz je przez npx tsx ci/triage-<narzędzie>.ts.

Workflow jest taki sam dla wszystkich trzech SDK, z wyjątkiem ostatniej linii run i jej sekretu.

.github/workflows/ci-triage.yml
name: ci-triage
on:
workflow_run:
workflows: [CI]
types: [completed]
permissions:
contents: read
actions: read
jobs:
triage:
# Only failed runs, and never code from a fork: this job holds API keys.
if: >-
github.event.workflow_run.conclusion == 'failure' &&
github.event.workflow_run.head_repository.full_name == github.repository
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.workflow_run.head_sha }}
fetch-depth: 20
- uses: actions/setup-node@v4
with:
node-version: 22 # the Cursor SDK needs 22.13+
- run: npm ci
- run: gh run view ${{ github.event.workflow_run.id }} --log-failed > ci-failure.log
env:
GH_TOKEN: ${{ github.token }}
- run: npx tsx ci/triage-claude.ts # or triage-codex.ts / triage-cursor.ts
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
- run: git diff --exit-code # the triage must leave tracked files untouched
- uses: actions/upload-artifact@v4
with:
name: triage
path: triage.json

Dla runnera Codeksa przekaż CODEX_API_KEY, dla runnera Cursora – CURSOR_API_KEY i CURSOR_MODEL_ID. Zanim wybierzesz poświadczenie, sprawdź w warunkach dostawcy, czy praca bez nadzoru ma iść na kluczu API, czy na logowaniu z subskrypcji.

Rozgałęzienie na werdykcie: tu SDK zaczyna się opłacać

Dział zatytułowany „Rozgałęzienie na werdykcie: tu SDK zaczyna się opłacać”

Do tego miejsca tę samą pracę wykonałoby claude -p --json-schema albo codex exec --output-schema. SDK jest warte swojego kodu wtedy, gdy następny krok zależy od odpowiedzi i korzysta z kontekstu, który agent już zebrał:

  1. Odczytaj triage.json i zwaliduj go względem triageSchema walidatorem JSON Schema. Raport, który nie przejdzie walidacji, oblewa zadanie; nikt na jego podstawie nie działa.

  2. Przy flaky uruchom ponownie nieudane joby (gh run rerun <run-id> --failed; ten krok wymaga actions: write w swoim jobie) i dopisz test do listy kwarantanny. Bez drugiej sesji agenta.

  3. Przy infra wyślij dowody na kanał dyżurny i zakończ.

  4. Przy regression albo test-bug wznów tę samą sesję z prawem zapisu na nowej gałęzi, żeby agent zachował to, co już przeczytał:

    • Claude Agent SDK: query({ prompt, options: { resume: sessionId, tools: { type: 'preset', preset: 'claude_code' }, permissionMode: 'acceptEdits' } }).
    • Codex SDK: codex.resumeThread(threadId, { sandboxMode: 'workspace-write' }), potem thread.run(...).
    • Cursor SDK: agent.send(...) na tym samym agencie albo Agent.resume(agentId) z późniejszego joba; ograniczenia narzędzi nie są zapisywane, więc przekaż je ponownie.
  5. Sesja naprawcza otwiera pull request z raportem triażu jako dowodem i przechodzi przez te same bramki co każda inna zmiana agenta: zobacz pakiet dowodów, który musi nieść pull request agenta.

Runner GitHub Actions jest efemeryczny, więc zapisana na nim sesja znika razem z końcem joba. Żeby wznowić ją w późniejszym jobie, zapisz magazyn sesji (~/.claude/projects, ~/.codex/sessions albo lokalny magazyn Cursora) jako artefakt albo trzymaj cały przepływ w jednym jobie.

Prompt audytowy uruchamiaj na innym modelu albo u innego dostawcy niż runner, żeby autor nigdy nie oceniał sam siebie; jak skalibrować takiego sędziego, opisują kontrole oceniane przez model.

Jak udowodnić, że triaż jest trafny, bez czytania każdego przebiegu?

Dział zatytułowany „Jak udowodnić, że triaż jest trafny, bez czytania każdego przebiegu?”

Traktuj runner jak każdą inną produkcyjną ścieżkę kodu, na której wyniku działa kolejna automatyzacja. Bramki w kolejności, w jakiej się uruchamiają:

  1. Schemat. SDK waliduje kształt wyniku (Claude, Codex) albo ogranicza go schemat wejścia własnego narzędzia (Cursor). Twój krok waliduje go ponownie przed działaniem, bo przebieg, który uderzy w limit, może skończyć się bez raportu.
  2. Brak skutków ubocznych. git diff --exit-code oblewa zadanie, jeśli agent zmienił śledzony plik. Ograniczenia narzędzi zmniejszają ryzyko; diff to udowadnia.
  3. Limity. maxTurns i maxBudgetUsd w Claude, limit czasu w Codeksie i Cursorze oraz timeout-minutes na jobie. Przebieg zatrzymany limitem to przebieg nieudany, nigdy częściowy werdykt.
  4. Złoty zbiór. Zbierz dawne nieudane przebiegi z etykietą, co do której ludzie już się zgodzili, w tym przypadki flaky, infra i regression. Odtwarzaj na nich runner po każdej zmianie SDK, modelu albo promptu i śledź zgodność. Zanim runner zacznie sam uruchamiać joby ponownie albo nadawać etykiety, ustal z góry, jakiej zgodności wymagasz; do tego czasu tylko komentuje.
  5. Niezależny audyt. Prompt audytowy powyżej, uruchomiony na innym modelu, odrzuca werdykty, których dowodów nie ma w logu.
  6. Telemetria. Loguj ID sesji albo wątku, liczbę tur, tokeny i koszt każdego przebiegu i łącz je z ID przebiegu CI. Strona o obserwowalności agentów pokazuje dashboard: odsetek udanych przebiegów, koszt zaakceptowanego werdyktu i odsetek werdyktów odrzuconych przez ludzi.

Kto zatwierdza: dyżurny programista odpowiada za każde działanie proponowane przez runner, dopóki zgodność na złotym zbiorze nie osiągnie progu ustalonego przez tech leada. Potem tech lead zatwierdza poszerzanie uprawnień runnera po jednym działaniu naraz, zaczynając od ponownego uruchamiania niestabilnych testów.

ObjawPrzyczynaWyjście z sytuacji
Przebieg Claude kończy się error_max_budget_usd albo error_max_turns bez raportuLimit jest za niski przy rozmiarze logów repozytorium albo agent kręci się w zaszumionym loguPrzytnij log do nieudanego kroku przed przebiegiem (--log-failed już w tym pomaga), potem podnoś po jednym limicie i zapisz nowy koszt w przebiegu na złotym zbiorze
Przebieg Codeksa wisi do limitu czasuPolecenie czekało na wejście albo na sieć przy networkAccessEnabled: falsePrzeczytaj ostatni element command_execution w strumieniowanym logu; dopisz w prompcie flagę nieinteraktywną do polecenia odtwarzającego
Każdy werdykt Codeksa to „infra”Sandbox read-only, a runner testów musi zapisać cachePrzełącz na workspace-write i zachowaj bramkę diffu
Agent.create w Cursorze rzuca ConfigurationErrortools, disallowedTools albo systemPrompt w połączeniu z cloud (a customTools też działa tylko lokalnie)Uruchom triaż jako agenta lokalnego albo usuń te opcje dla agenta chmurowego i ogranicz go promptem oraz dostępem do repozytorium, jaki mu dajesz
Cursor zgłasza finished, ale report jest pustyAgent odpowiedział tekstem i nigdy nie wywołał submit_triageTraktuj to jako porażkę (runner już rzuca wyjątek); powtórz na końcu promptu polecenie wywołania narzędzia i wyślij na tym samym agencie jedną wiadomość z prośbą o wywołanie
Brakuje kosztu w odczycie zużycia z CursoraDane rozliczeniowe spóźniają się względem przebieguOdczytaj agent.getUsage() ponownie w późniejszym kroku albo połącz eksport zużycia po ID agenta
Wznowiona w późniejszym jobie sesja jest „not found”Sesja żyła na poprzednim, efemerycznym runnerzeWgraj magazyn sesji jako artefakt albo trzymaj triaż i naprawę w jednym jobie
SDK i globalnie zainstalowane CLI zachowują się inaczejSDK steruje własną przypiętą binarką, a twoje globalne CLI ma inną wersjęPrzypnij wersję SDK w package.json i aktualizuj świadomie; Claude Agent SDK przyjmuje pathToClaudeCodeExecutable, gdy musisz użyć konkretnej binarki

Na którym SDK zespół powinien się ustandaryzować?

Dział zatytułowany „Na którym SDK zespół powinien się ustandaryzować?”

Wybieraj według tego, gdzie zespół już pracuje, i kontroli, jakiej wymaga zadanie, a nie według modelu: każde SDK steruje agentem swojego dostawcy i jego domyślnym modelem.

  • Wybierz Claude Agent SDK, gdy zadanie potrzebuje w jednym miejscu decyzji o uprawnieniach przy każdym wywołaniu, hooków, narzędzi w procesie i twardego limitu w dolarach. Ma najszerszą powierzchnię kontroli z całej trójki.
  • Wybierz Codex SDK, gdy zespół już pracuje z Codeksem, a kontrolą, której ufasz, jest granica sandboksa. To najcieńsza nakładka, a schemat per tura ułatwia wieloetapowe potoki na jednym wątku.
  • Wybierz Cursor SDK, gdy agent ma pracować na maszynach wirtualnych Cursora w chmurze i sam otwierać pull request albo gdy reguły i skille zespołu już mieszkają w Cursorze.

Dla leada decyzja o standardzie dotyczy głównie części wspólnych: jednego pliku z promptem i schematem na zadanie, jednego zestawu bramek, jednego złotego zbioru i jednego dashboardu kosztów. Gdy to masz, wymiana pliku runnera jest drobną zmianą, co pokazują trzy zakładki powyżej.

Najczęstsze pytania

Kiedy użyć SDK agenta zamiast claude -p albo codex exec?

CLI wystarczy, gdy zadanie to jeden prompt na wejściu i jeden wynik na wyjściu. SDK jest potrzebne, gdy twój kod rozgałęzia się na podstawie wyniku agenta, wznawia tę samą sesję, rejestruje narzędzia działające w procesie, decyduje o uprawnieniach dla każdego wywołania narzędzia albo strumieniuje postęp do własnego interfejsu.

Które SDK agentów zwracają ustrukturyzowany wynik zgodny z JSON Schema?

Claude Agent SDK (outputFormat z typem json_schema) i Codex SDK (outputSchema dla każdej tury). Cursor SDK 1.0.32 nie ma opcji schematu; ten sam efekt daje lokalne narzędzie własne, które dostaje raport jako argumenty.

Jak ograniczyć wydatki agenta sterowanego przez SDK?

Claude Agent SDK ma maxBudgetUsd i maxTurns. Codex SDK nie ma limitu kosztu, więc przekaż AbortSignal z limitem czasu. Cursor SDK też go nie ma: anuluj przebieg po czasie i odczytaj potem agent.getUsage().