# External call budgets जो agent loops रोकते हैं

Autonomous agents को उपयोगी बनने के लिए बाहरी सेवाओं तक असीमित access की जरूरत नहीं होती। उन्हें कोशिश करने, इंतजार करने, दोबारा कोशिश करने और खर्च करने की एक तय सीमा चाहिए, जिसके बाद वे काम वापस सौंप दें। यह सीमा न हो तो खाली search result या देर से चलने वाला job जैसी छोटी अस्पष्टता सैकड़ों requests, दोहराए गए side effects और किसी के अनुमान से बाहर आए bill में बदल सकती है।

External call budget एक agent run के लिए runtime contract है। यह request attempts, बीता हुआ समय और monetary exposure की सीमा तय करता है, फिर कोई भी सीमा खत्म होने पर स्पष्ट रूप से run रोक देता है। इसे agent prompt में लिखे सुझाव की तरह नहीं, operating limit की तरह लें। Task पूरा करने की कोशिश में model prompts को आसानी से अलग तरह से समझ सकता है। Enforcement model के बाहर होनी चाहिए।

## Budget में attempts, time और money अलग-अलग गिने जाने चाहिए

एक सीमा उन सभी तरीकों को नहीं संभाल सकती जिनसे एजेंट resources खर्च करता है। Request count loops पकड़ता है। Elapsed-time limit धीमी polling और retry sleeps पकड़ती है। Spend limit कम संख्या में होने वाली महंगी कार्रवाइयों को पकड़ता है। हर माप एक अलग failure mode दिखाता है और बाकी दो सीमाएँ बची होने पर भी run रोक सकता है।

Successful responses नहीं, **attempts** गिनें। Timeout वाली attempted request provider तक पहुंच चुकी हो सकती है। उसने socket, provider का काम और अक्सर metered API में एक entry इस्तेमाल की। केवल successes गिनेंगे तो एजेंट अपनी पसंद का response मिलने तक अनगिनत failed requests भेज सकता है।

हर run के लिए कम से कम ये values track करें:

- `attempts_used` और `attempts_remaining`, जिसमें retries और वे redirects भी शामिल हों जो नई external request भेजते हैं
- `deadline_at`, जिसमें बीती अवधि के लिए wall time के बजाय monotonic clock इस्तेमाल हो
- `reserved_spend` और `settled_spend`, provider की सबसे छोटी व्यावहारिक billing unit में
- `side_effect_attempts`, write, send, create या purchase करने वाली कार्रवाइयों की अलग गिनती
- `budget_stop_reason`, जो आगे का काम रोकने वाली पहली सीमा दर्ज करे

Request count और spend को हर request की मनगढ़ंत कीमत तय करके एक साथ न मिलाएं। Metadata lookup और model generation endpoint दोनों एक request हो सकते हैं, जबकि उनके invoices में बहुत बड़ा अंतर हो। दूसरी ओर, कोई API ऐसी request के लिए price न बताए जो फिर भी chargeable cloud resource बना दे। Cost estimate उपलब्ध हो तब भी request ceiling रखें।

Known APIs के एक तय समूह से data जुटाने वाले एजेंट के लिए शुरुआती budget में 40 total attempts, 10 मिनट का runtime और एक छोटी fixed reservation हो सकती है। Deployment agent को कम requests लेकिन सख्त side-effect allowance की जरूरत हो सकती है। Discovered URLs follow करने वाले research agent का reachable scope उसके लेखक के शुरुआती प्रस्ताव से काफी छोटा होना चाहिए। ये शुरुआती hypotheses हैं, universal settings नहीं। सामान्य runs को मापें और limits इतनी करीब रखें कि abnormal behavior cleanup job बनने से पहले रुक जाए।

Budget दिन भर के model process का नहीं, एक run का होता है। एजेंट को नया task मिले तो उसे नया run identifier और नया, स्पष्ट allocation दें। Shared daily counter महंगे run को सामान्य काम के बीच छिपा देता है। इससे एक task दूसरे के लिए रखी capacity भी खर्च कर सकता है।

## पहली महंगी call से पहले allowance reserve होना चाहिए

जब system चीज खरीदने के बाद उसकी कीमत जानता है, तब spend caps विफल हो जाते हैं। Call से पहले अधिकतम संभावित charge reserve करें, remaining budget तुरंत घटाएं और provider के actual usage लौटाने पर बाद में हिसाब मिलाएं। Reservation फिट न हो तो call आपकी boundary से बाहर जाने से पहले उसे रोक दें।

मान लें कोई एजेंट hosted build बना सकता है। Provider की request में machine class, region, timeout और artifact size आते हैं, लेकिन exact charge completion के बाद दिखता है। Agent gateway को price table या conservative estimate चाहिए। सुरक्षित निर्णय लेने के लिए perfect accounting जरूरी नहीं है।

Reservation record कुछ ऐसा दिख सकता है:

```json
{
  "run_id": "run_7c1f",
  "budget": {
    "attempts_remaining": 18,
    "deadline_at": "2025-04-21T14:42:00Z",
    "spend_remaining_cents": 1200
  },
  "reservation": {
    "action": "create_build",
    "maximum_cents": 850,
    "provider_reference": "build-request-41"
  },
  "decision": "allow"
}
```

इस reservation के बाद run के पास बाकी हर action के लिए 350 cents बचते हैं। Actual bill 620 cents हो तो 230 cents release करें। Bill 910 cents हो तो overage दर्ज करें, आगे का spend रोकें और पता लगाएं कि estimate क्यों चूका। Final number असुविधाजनक होने पर एजेंट को future budget से खुलकर उधार न लेने दें।

कुछ providers request में price दिखाते हैं या काम शुरू होने से पहले usage estimate लौटाते हैं। उसका इस्तेमाल करें। कुछ ऐसा नहीं करते। ऐसी services के लिए actions को risk के आधार पर वर्गीकृत करें। सस्ते read को सामान्य request budget के भीतर अनुमति दें। ऐसा action जो uncapped resource बना सकता है, paid messages भेज सकता है, order दे सकता है या ऐसी प्रक्रिया शुरू कर सकता है जिसकी लागत सीमित नहीं की जा सकती, उसके लिए explicit approval मांगें।

Teams अक्सर reservations को यह कहकर अस्वीकार कर देती हैं कि estimates imperfect हैं। यह accounting precision को control के साथ मिला देना है। Fire door को बंद होने से पहले आग की exact heat calculate करने की जरूरत नहीं होती। Conservative reservation ऐसा task रोक सकती है जो वास्तव में fit होता, लेकिन agent context के साथ बड़ा allocation मांग सकता है। यह uncapped charge का पता agent के गायब हो जाने के बाद चलने से बेहतर है।

Provider credits और organization-wide quotas को run budget से बाहर रखें। वे backstops हैं, विकल्प नहीं। Monthly quota अक्सर एक run को उसके task के लायक हिस्से से कहीं ज्यादा खर्च करने देती है।

## Retries का allowance पहली कोशिशों से छोटा होना चाहिए

Retries दुर्लभ, सीमित और इस आधार पर वर्गीकृत होनी चाहिए कि request दोहराने से side effect भी दोहर सकता है या नहीं। Errors पर retry करने का सामान्य निर्देश ही temporary outage को महंगे traffic pattern में बदल देता है।

RFC 9110 GET, PUT और DELETE जैसी idempotent methods को उनके intended server effect के आधार पर परिभाषित करता है। यह भी कहता है कि client को non-idempotent request अपने-आप retry नहीं करनी चाहिए, जब तक उसे यह पता न हो कि दोहराना सुरक्षित है। Agents के साथ यह सावधानी और महत्वपूर्ण है: agent attempts के बीच payload बदल सकता है, पहले response को अधूरा मान सकता है और ऐसी request भेज सकता है जो देखने में नई लगती हो।

RFC 6585 HTTP 429, Too Many Requests, को परिभाषित करता है और बताता है कि response में `Retry-After` हो सकता है। Header मौजूद हो तो उसका सम्मान करें। इसे header खत्म होने तक सोने और फिर हमेशा दोबारा शुरू करते रहने की अनुमति न समझें। Retry run का time budget भी खर्च करती है और मूल task शायद इतना इंतजार करने लायक न रहे।

हर repeat से पहले चार सवालों का जवाब देने वाला retry ledger रखें: क्या विफल हुआ, remote action हुआ हो सकता है या नहीं, कितनी देर इंतजार करना है और दूसरी कोशिश का खर्च कौन सा budget उठाएगा। एक व्यावहारिक policy ऐसी हो सकती है:

```yaml
request_classes:
  read:
    max_attempts: 3
    retry_on: [408, 429, 502, 503, 504]
    backoff_seconds: [2, 8]
  idempotent_write:
    max_attempts: 2
    require_idempotency_token: true
    retry_on: [408, 429, 503]
  non_idempotent_write:
    max_attempts: 1
    retry_on: []
```

यह policy एक आम failure रोकती है। Agent `POST /invoices` भेजता है और response मिलने से पहले connection खो देता है। लापरवाह retry दूसरा invoice बना सकती है। Idempotency token सहयोगी provider को duplicate पहचानने देता है, लेकिन तभी जब agent वही token और वही logical operation दोबारा इस्तेमाल करे। दूसरी कोशिश में amount, customer या token बदल जाए तो protection लागू नहीं रहती।

Non-idempotent action के लिए client-generated operation identifier से status lookup करना बेहतर है। Provider idempotency या status retrieval support न करे तो ambiguous timeout को human review वाला मामला मानें। यह automatic retry से धीमा लगता है, जब तक किसी को duplicate transfers, orders या messages वापस न लेने पड़ें।

जब बहुत से agents को एक ही outage मिले, तो jitter महत्वपूर्ण है। Randomized backoff इस्तेमाल करें, ताकि वे एक साथ retry न करें। Schedule इतना छोटा रखें कि run deadline का अर्थ बना रहे। छह घंटे का exponential backoff provider की रक्षा कर सकता है, लेकिन agent session को task की उपयोगिता खत्म होने के बहुत बाद तक खुला रख सकता है।

## Polling loops की अपनी ceiling होनी चाहिए

Asynchronous work का इंतजार करने वाले agent को स्पष्ट poll allowance दें, क्योंकि सामान्य request limits इस pattern को तब तक छिपा देती हैं जब तक वह महंगा न हो जाए। Polling का उचित उपयोग है, लेकिन उसके लिए interval, checks की maximum संख्या और operation से जुड़ी deadline तय होनी चाहिए।

Logs में खराब version आसानी से दिखता है:

```text
14:00:03 POST /exports                 202 accepted
14:00:04 GET  /exports/ea91            202 running
14:00:05 GET  /exports/ea91            202 running
14:00:06 GET  /exports/ea91            202 running
...
14:11:58 GET  /exports/ea91            202 running
```

Agent ने “still running” को फिर से पूछते रहने का निर्देश समझ लिया है। यह persistence नहीं, अनुपस्थित policy है।

Provider की documented guidance से शुरुआत करें। Endpoint `Retry-After` लौटाए तो remaining deadline के भीतर उसका पालन करें। Estimated completion time मिले तो उससे पहले poll न करें। Webhook या callback उपलब्ध हो तो agent run को खुला रखने के बजाय उसका इस्तेमाल करें। External callback बाद में controlled workflow फिर शुरू कर सकता है, लेकिन उसे पुराने authority के साथ expired run को फिर जीवित नहीं करना चाहिए।

Poll budget को job state और transport failure में भी अंतर करना चाहिए। `202 running` बताता है कि job मौजूद है। Timeout से यह पता नहीं चलता कि status request पहुंची या नहीं। दोनों पर एक ही retry allowance खर्च न करें। पहले मामले में अगली scheduled check तक इंतजार किया जा सकता है। दूसरे में ordinary retry limit के अधीन एक retry उचित हो सकती है।

Poll allowance खत्म होने पर terminal action तय करें: last known job state दर्ज करें, remote operation identifier सुरक्षित रखें और resume instruction लौटाएं। Original task में cancellation सुरक्षित न कही गई हो तो अपने-आप cancel न करें। कुछ jobs agent के इंतजार से हार मानने के बाद भी usable result छोड़ती हैं और कुछ cancellation requests के अपने side effects होते हैं।

इस design से delayed work व्यक्ति को साफ दिखता है। “छह checks के बाद भी export चल रहा है; operation ea91 बाद में check किया जा सकता है” उपयोगी handoff है। Hidden background loop के बाद “Agent completed” उपयोगी नहीं है।

## Deadline में waits, tools और queue time शामिल होने चाहिए

Run deadline उस पूरे समय को मापनी चाहिए जिसमें agent external work करा सकता है। इसमें calls के बीच model deliberation, retry sleep, local tool execution, queue delay, DNS stalls और approval के इंतजार का समय भी शामिल होना चाहिए। केवल HTTP client के चारों ओर timer लगाने से बड़े gaps बच जाते हैं, जिनमें loop चलता रह सकता है।

इस limit को लागू करने के लिए monotonic elapsed timer इस्तेमाल करें। Laptop के sleep या resume होने अथवा time correction मिलने पर wall clocks बदल सकती हैं। Audit records के लिए wall-clock timestamps रखें, लेकिन expiry ऐसी elapsed duration से निकालें जो पीछे न जाए।

Remaining time हर operation तक पहुंचाएं। Run में 40 seconds बचे हों तो 90-second client timeout वाली HTTP request शुरू न करें और बिना timeout SSH command न चलाएं। Child operation को उसके local cap और run की remaining duration में से छोटी सीमा दें।

```text
remaining = run_deadline_monotonic - now_monotonic
if remaining <= 0:
    deny("run_deadline_exhausted")
else:
    operation_timeout = min(remaining, endpoint_timeout)
    execute(operation_timeout)
```

Approval waits को सावधानी से संभालें। कोई व्यक्ति पांच मिनट में लौट सकता है, लेकिन agent run में केवल 30 seconds बचे हों। Approval expiry के बाद आए तो action रोकें और कारण दिखाएं। Approval को expired run को revive करने देना loophole बनाता है: agent deadline से पहले मनमाने महंगे actions queue कर सकता है और बाद में cards पर clicks होते ही उन्हें चला सकता है।

Long tasks को अलग ढांचे की जरूरत होती है। उन्हें fresh budgets और recorded state transition वाले checkpoints में बांटें। उदाहरण के लिए, agent एक run में export submit कर सकता है और बाद का run completed export को inspect करके तय कर सकता है कि उसके साथ क्या करना है। हर run को purpose, छोटी authority set और स्पष्ट end time दें। यह एक immortal agent session से कम जादुई है, और इसी वजह से audit करना आसान है।

## Scope limits agent को अपना budget गलत जगह खर्च करने से रोकती हैं

Budget बताता है कि run कितनी external activity कर सकता है। Scope बताता है कि वह कहां और किस चीज को छू सकता है। Scope न हो तो agent उचित request allowance को unrelated hosts probe करने, poisoned link follow करने या task से बाहर के costly endpoint को चुनने में खर्च कर सकता है।

Scope को concrete terms में परिभाषित करें: approved hosts, credential identities, HTTP methods, SSH destinations, allowed paths या command families और maximum request body size। Definition इतनी संकरी रखें कि reviewer उसे समझ सके। हर संभावित condition के लिए miniature programming language लिखने की कोशिश न करें। Complex policy systems exceptions जमा करते जाते हैं, जब तक दबाव के समय कोई उनके परिणाम का अनुमान नहीं लगा पाता।

Credential boundary और budget boundary का अंतर महत्वपूर्ण है। Credential boundary तय करती है कि agent secret का इस्तेमाल करके service को call कर सकता है या नहीं। Budget boundary तय करती है कि permission मिलने के बाद यह run एक और call कर सकता है या नहीं। Teams अक्सर पहली boundary लगाकर मान लेती हैं कि दूसरी भी मिल गई। ऐसा नहीं है। पूरी तरह सुरक्षित API token भी हजारों अनावश्यक requests को fund कर सकता है।

HTTP में approved host set से बाहर जाने वाले redirects को अस्वीकार करें, जब तक किसी व्यक्ति ने destination की explicit अनुमति न दी हो। Redirect handling अक्सर छूट जाती है, क्योंकि कई clients redirects अपने-आप follow करते हैं। Approved URL से शुरू हुई request किसी दूसरे host पर पहुंच सकती है, headers ले जा सकती है या ऐसे service पर budget खर्च कर सकती है जिसका task में नाम ही नहीं था।

SSH के लिए केवल इसलिए general shell न दें कि पहला job एक command से जुड़ा है। जहां संभव हो destination और command interface सीमित करें। Command timeout तय करें और हर connection attempt गिनें। Failed connection loop भी external activity है, भले ही authentication कभी न हो।

Read scopes और write scopes अलग रखें। Data collection task को read endpoints के बड़े set की जरूरत हो सकती है, लेकिन records बनाने की अनुमति नहीं। Change task को एक write endpoint और संकरी preflight read की जरूरत हो सकती है। यह विभाजन budget को अधिक अर्थपूर्ण बनाता है, क्योंकि request count अकेले harmless repetition और repeated side effects में अंतर नहीं कर सकता।

## Denials में loop को फिर से बनाने के लिए पर्याप्त evidence होना चाहिए

Budget stop तभी उपयोगी है जब बाद में समझाया जा सके कि क्या हुआ। External call शुरू होने से पहले हर decision दर्ज करें, खत्म होने के बाद outcome दर्ज करें और denials को successful calls जितनी सावधानी से लिखें। वरना missing event blocked request जैसा दिख सकता है।

Model messages, local tools, HTTP requests, SSH connections, approvals और audit records में एक ही immutable run identifier इस्तेमाल करें। हर external attempt में sequence number हो। Retry होने पर उसे मूल logical operation से जोड़ें और बताएं कि action idempotent, ambiguous या confirmed absent था।

एक compact event record में sensitive payloads रखे बिना investigation के लिए पर्याप्त जानकारी हो सकती है:

```json
{
  "run_id": "run_7c1f",
  "attempt": 17,
  "logical_operation": "fetch_export_status:ea91",
  "channel": "http",
  "destination_class": "approved-export-api",
  "outcome": "denied",
  "reason": "poll_allowance_exhausted",
  "attempts_remaining": 0,
  "elapsed_ms": 598244,
  "reserved_spend_cents": 0
}
```

Bearer tokens, passwords, private keys या complete request bodies को default रूप से log न करें। Budget audit के लिए identifiers, classes, जहां उपयोगी हो hashes और decision context पर्याप्त हैं। जिस credential को बचाने की कोशिश की, उसी से भरा दूसरा secret store बनाने की जरूरत नहीं है।

Event sequence को tamper-evident बनाएं। Hash chain हर record को उससे पहले वाले record पर निर्भर बनाती है, इसलिए हटाने या बदलने पर verification टूट जाती है। जहां संभव हो verification material को live agent से अलग रखें। जो agent अपना history लिख सकता है, उसे उस record को edit करने में सक्षम नहीं होना चाहिए जो साबित करता है कि उसने budget पार किया।

Sallyport agent sessions और individual calls दोनों को write-blind encrypted, hash-chained audit log में दर्ज करता है। उसका `sp audit verify` command ciphertext पर offline chain verify कर सकता है। Budget enforcement के लिए यह design उपयोगी है, क्योंकि denied action evidence का हिस्सा बना रहता है और internal decision की तरह गायब नहीं होता।

## Human approval हर read पर नहीं, exceptions पर होना चाहिए

Human approval उन consequence या scope changes को संभालना चाहिए जिन्हें numeric budget नहीं परख सकता। इसे routine calls के लिए rubber stamp न बनने दें। यदि व्यक्ति को हर request के लिए approval card दिखेगा, तो दसवीं prompt को वह पहली prompt जितने ध्यान से मंजूर नहीं करेगा।

जब action नया payee बनाए, reservation से अधिक खर्च करे, production system में लिखे, externally visible communication भेजे, approved destination set बदले या task input में महत्वपूर्ण बदलाव के बाद resume करे, तब approval मांगें। Approval में action को सरल भाषा में, destination, budget impact और मांगने वाले process की identity के साथ दिखाएं।

Weak budget का इलाज approval को न मानें। Distracted person खराब action को authorize कर सकता है और unattended run को शायद response कभी न मिले। Approval के इंतजार में भी budget खत्म होना चाहिए। Task अभी भी उपयोगी हो तो व्यक्ति नए run के लिए fresh allocation दे सकता है।

लोगों से context के बिना “continue” मंजूर करने को न कहें। Continue क्या? किस service के विरुद्ध? अनुमानित charge कितना है? Run ने अब तक कितनी calls की हैं? अच्छी approval request ये तथ्य स्पष्ट दिखाती है। अस्पष्ट request reviewer को agent के summary पर भरोसा करने को मजबूर करती है, जबकि काम जारी रखने का प्रोत्साहन उसी agent के पास है।

काम का उपयोगी बंटवारा है। Gateway fixed limits को लगातार लागू करता है। व्यक्ति तय करता है कि exceptional action अधिक authority के लायक है या नहीं। इन जिम्मेदारियों को अलग रखें, ताकि किसी को दूसरे का काम हल करने का दिखावा न करना पड़े।

## Budget खत्म होने पर resumable handoff मिलना चाहिए

जब कोई limit run रोकती है, तो agent को एक छोटा state record लौटाना चाहिए, जिससे व्यक्ति या बाद का run सुरक्षित तरीके से आगे बढ़ सके। अस्पष्ट failure message किसी को पूरा task फिर से चलाने के लिए प्रेरित करता है, जिससे पूरी हो चुकी calls दोहर सकती हैं और side effects भी दोहर सकते हैं।

Handoff में task objective, पूरे किए गए operation identifiers, pending remote work, exact stop reason और अगले allocation की recommendation होनी चाहिए। यह भी बताना चाहिए कि retry सुरक्षित है या नहीं। Action ambiguous state में खत्म हुआ हो तो उसे कभी न छिपाएं।

उदाहरण:

```text
Stopped: elapsed-time budget exhausted.
Completed: submitted export job ea91; downloaded no files.
Last observed state: running at 14:09:58 UTC.
External attempts: 14 of 14; spend reserved: 0 cents.
Safe resume: check status of ea91 once after 14:20 UTC.
Unsafe action: do not submit another export request.
```

यह message recovery के सबसे महंगे रूप को रोकता है: क्या हुआ यह न पता होने पर शुरुआत से शुरू करना। इससे budget tuning भी संभव होती है। यदि कई सामान्य runs एक status check के बाद रुकते हैं, तो allowed duration बहुत छोटी है। यदि runs अक्सर बिना progress के searches पर पूरा allowance खर्च करते हैं, तो task decomposition या scope गलत है।

Exhaustion के बाद budget अपने-आप replenish न करें। Replenishment rule अलग increments में लिखा unlimited budget ही है, जब तक कोई अलग authority यह तय न करे कि वह कब लागू होगा। नया run या explicit human action जरूरी करें, पुराना record सुरक्षित रखें और अगली कोशिश से कारण बताने को कहें कि उसे अधिक जगह क्यों चाहिए।

Enforce करने लायक पहली policy सरल है: हर autonomous run को finite request count, hard deadline और external service तक पहुंचने से पहले spend reservation दें। इसके तुरंत बाद scope restrictions और अच्छे records जोड़ें। Agent को पता चल जाए कि वह हमेशा कोशिश करता नहीं रह सकता, तो उसकी failures overnight incidents के बजाय सीमित work items बन जाती हैं।
