# AI एजेंट्स की डिबगिंग: वह ऑब्ज़र्वेबिलिटी जो पहले ही दिन हमारे पास होनी चाहिए थी

> एक एजेंट ने उस काम पर 4 डॉलर और 90 टूल-कॉल फूंक दिए जो तीन कॉल में हो जाना चाहिए था, और हम एक खाली टर्मिनल को घूर रहे थे। यह वही इंस्ट्रुमेंटेशन है जिसने अनुमान को दो मिनट की डायग्नोसिस में बदल दिया — Octomind के /info, /report और /context, zstd सेशन लॉग, RUST_LOG ट्रेसिंग, --format jsonl और हर upstream रिक्वेस्ट पकड़ने के लिए आगे OctoHub।

एजेंट छह मिनट से चल रहा था। स्पिनर अब भी घूम रहा था। जब मैंने उसे मारा, तो `/info` ने बिल **$4.18** बताया, और `/report` ने नवासी टूल-कॉल गिने — उस काम पर जिसका मेरा अनुमान तीन कॉल और कुछ सेंट का था। उसने एक ही फाइल ग्यारह बार पढ़ी। उसने एक सिंबल के लिए grep किया, खाली नतीजा मिला, grep को दोबारा लिखा, फिर खाली नतीजा मिला, और यही करता रहा — विनम्रता से, आत्मविश्वास से, महँगे ढंग से — क्योंकि लूप में कुछ भी उसे रुकने को नहीं कह रहा था।

सबसे बुरी बात वे चार डॉलर नहीं थे। बुरा यह था कि मुझे पता ही नहीं था कि _क्यों_, जब तक मैं खोजने नहीं गया। एजेंट गड़बड़ होने पर स्टैक ट्रेस नहीं फेंकता। वह क्रैश नहीं होता। वह बस चुपचाप गलत काम करता है, सफलता की रिपोर्ट देता है, और आपको बिल थमा देता है। बाहर से, एक शानदार रन और एक विनाशकारी रन एक जैसे दिखते हैं: टेक्स्ट बहता हुआ, टूल चलते हुए, अंत में एक जवाब।

यह पोस्ट वही इंस्ट्रुमेंटेशन है जो काश मैंने उस रन से पहले जोड़ रखा होता, बाद में नहीं। यह सब [Octomind](https://github.com/Muvon/octomind) में आता है — हमारा ओपन-सोर्स Rust एजेंट रनटाइम — और आखिरी सेक्शन उसके आगे [OctoHub](https://github.com/Muvon/octohub) जोड़ता है, ताकि वह एक चीज़ पकड़ी जा सके जो खुद एजेंट नहीं दिखा सकता: वे कच्चे बाइट्स जो असल में मॉडल तक गए।

---

## एजेंट चुपचाप क्यों फेल होते हैं

पारंपरिक सॉफ़्टवेयर ज़ोर से फेल होता है। null deref, 500, फेल हुआ assertion — फेलियर का एक आकार होता है, एक जगह, एक लाइन नंबर। एजेंट फेलियर में इनमें से कुछ नहीं होता, क्योंकि रनटाइम के नज़रिए से कुछ फेल हुआ ही नहीं। हर API कॉल ने 200 लौटाया। हर टूल 0 के साथ बाहर निकला। मॉडल ने हर कदम पर व्याकरण-सम्मत, प्रशंसनीय टेक्स्ट दिया। _समग्र_ व्यवहार गलत था, पर कोई एक अलग ऑपरेशन गलत नहीं था।

व्यवहार में फेलियर चार आकारों में बँटते हैं, और हर एक ठीक उसी पल अदृश्य रहता है जब आप उसे पकड़ना चाहेंगे:

- **गलत टूल, सही आत्मविश्वास।** मॉडल `grep` की ओर बढ़ता है जबकि उसे फाइल पढ़नी चाहिए थी, या किसी जेनरिक shell पर हाथ मारता है जबकि ठीक वहीं एक सटीक टूल मौजूद है। वह झिझकता नहीं — गलत टूल चुनाव बाहर से बिल्कुल सही टूल चुनाव जैसा दिखता है। (इससे लड़ने के लिए टूल-सरफेस को संकरा करने पर हमने एक पूरा लेख लिखा है: [कस्टम MCP आपके रिपो में रहने चाहिए](/blog/custom-mcps-belong-in-your-repo)।)
- **कॉन्टेक्स्ट ट्रंकेशन।** बातचीत विंडो से आगे बढ़ी, कम्प्रेशन चला, और एजेंट को चाहिए वह तथ्य संक्षेप में निचुड़कर खो गया। अब वह क्षतिपूर्ण मेमोरी से तर्क कर रहा है और आपको जोड़ दिखता ही नहीं।
- **बेलगाम लूप।** खाली नतीजा → दोबारा लिखो → खाली नतीजा → दोबारा लिखो। हर टर्न अलग-अलग देखने पर तार्किक है। बग खुद पैटर्न है, और आप उसे सिर्फ़ टूल-कॉल की गिनती से नोटिस करते हैं।
- **टोकन विस्फोट।** किसी टूल ने 200KB की फाइल कॉन्टेक्स्ट में उड़ेल दी, या किसी एक टूल-कॉल आर्गुमेंट का गुब्बारा फूल गया, और अब हर अगला टर्न वह सब दोबारा भेजता है। लागत सुपरलीनियर हो जाती है और एकमात्र लक्षण है इन्वॉइस।

जो आप देख नहीं सकते, उसे डिबग नहीं कर सकते। तो पहला काम है रन को ऑब्ज़र्वेबल बनाना — घटना के बाद भी और दौरान भी।

---

## स्तर 0: `/info` — पैसा गया कहाँ

जवाब देने का सबसे तेज़ सवाल है "इस सेशन की असल लागत कितनी थी, और किस आकार की।" किसी भी इंटरैक्टिव सेशन के भीतर, `/info`:

```
╭ /info
│ session  my-feature-x
│ model       openrouter:anthropic/claude-sonnet-5
│ tokens      214,883 total
│ breakdown   18,402 in · 9,114 out · 184,201 cache rd · 2,890 cache wr · 276 reasoning
│ cost        $4.18661
│ throughput  41.3 tok/s
╰ /info  my-feature-x
```

यहाँ हर फ़ील्ड एक डायग्नोस्टिक है। जिसने मेरे बेलगाम लूप के केस को खोला वह थी **breakdown** पंक्ति। `18,402 in` के मुकाबले `184,201 cache rd` का मतलब है कि वही कॉन्टेक्स्ट लगभग हर टर्न पर दोबारा पढ़ा जा रहा था — उस लूप की पहचान जो जोड़ता रहता है पर कभी हल नहीं होता। जिस टूल-कॉल गिनती ने इसे पुख़्ता किया, वह एक स्तर नीचे `/report` में मिलती है।

`/info` खर्च को मुख्य लूप से आगे भी तोड़ता है — कम्प्रेशन मॉडल के अपने टोकन और लागत, कैश मार्करों की जगह और रीड/राइट योग, कोई भी सब-एजेंट, और सुपरवाइज़र — हरेक को अपना सेक्शन मिलता है — तो जब बिल ऊँचा हो तो देख सकते हैं कि उसे मुख्य बातचीत ने खाया या किसी बैकग्राउंड प्रोसेस ने।

अगर सेशन कभी कम्प्रेस हुआ है, तो `/info` एक **compression** ब्लॉक दिखाता है: कितने कम्प्रेशन चले, कितने मैसेज हटे, कितने टोकन बचे, औसत अनुपात। यह आपका ट्रंकेशन का अग्रिम-चेतावनी संकेत है। अगर एक छोटे सेशन में तीन प्रोजेक्ट-स्तरीय कम्प्रेशन दिखें, तो एजेंट चीज़ें भूलता रहा है, और उसके निष्कर्षों पर भरोसा करने से पहले यह जानना ज़रूरी है।

---

## स्तर 1: `/report` — लागत प्रति रिक्वेस्ट, प्रति सेशन नहीं

`/info` सेशन का कुल जोड़ है। `/report` विस्तृत रसीद है — हर यूज़र रिक्वेस्ट के लिए एक पंक्ति, सेशन लॉग से पुनर्निर्मित:

```
╭ /report
│ #   request                          cost      tools  task     ai       proc
│ ──  ───────────────────────────────  ────────  ─────  ───────  ───────  ───────
│  1  add a health-check endpoint      $0.04120      3   18s      12s      1s
│  2  wire it into the router          $0.02980      2   11s      9s       1s
│  3  why is the test flaky            $3.98120     84   5m 31s   3m 40s   20s
│ ──  ───────────────────────────────  ────────  ─────  ───────  ───────  ───────
│  Σ  3 request(s)                     $4.05220     89   6m 00s   4m 01s   22s
╰ /report  3 request(s) · $4.05220
```

वो रहा। रिक्वेस्ट 3 — "why is the test flaky" — ही पूरा बिल है। एक सवाल के लिए चौरासी टूल-कॉल। दो सुव्यवस्थित रिक्वेस्ट एक आपदा को घेरे हुए हैं, और प्रति-रिक्वेस्ट विभाजन के बिना तीनों एक ही सेशन-कुल में धुंधली हो जाती हैं। `/report` से आप पता लगाते हैं कि _कौन-सा प्रॉम्प्ट_ एजेंट को पटरी से उतारता है, और कुछ भी ठीक करने से पहले असल में आपको यही जवाब चाहिए।

कॉलम `task` समय (पूरी रिक्वेस्ट, शुरू से अंत तक) को `ai` समय (सिर्फ़ मॉडल कॉल) से अलग करते हैं। जब `task`, `ai` से बहुत ज़्यादा हो, तो आपके टूल धीमे हैं। जब दोनों साथ-साथ चलें, तो मॉडल बहुत सारे राउंड-ट्रिप कर रहा है — फिर वही लूप की पहचान।

---

## स्तर 2: `/context` — पढ़िए कि एजेंट असल में किस बारे में सोच रहा है

लागत और गिनती बताती है कि _कुछ_ गलत हुआ। _क्या_ देखने के लिए, आप मैसेज पढ़ते हैं। `/context` जीवंत बातचीत को स्ट्रक्चर्ड JSON के रूप में डंप करता है, फ़िल्टर के साथ:

```
/context              # सब कुछ
/context large        # सिर्फ़ 1000 char से बड़े मैसेज — कॉन्टेक्स्ट के भक्षक को ढूँढो
/context tool         # सिर्फ़ टूल नतीजे — देखो एजेंट को असल में क्या वापस मिला
/context assistant    # सिर्फ़ मॉडल के अपने टर्न
```

`/context large` वही है जिस ओर मैं टोकन विस्फोट पर हाथ बढ़ाता हूँ। यह ठीक वही मैसेज सामने लाता है जो विंडो को फुला रहे हैं — आमतौर पर एक टूल नतीजा जिसने कोई विशाल फाइल या बड़ा JSON ब्लॉब लौटाया — और अब आप जानते हैं किस टूल को पेजिनेट या ट्रंकेट करना सिखाना है। मेरी flaky-टेस्ट आपदा में, `/context tool` ने अस्सी-कुछ `grep` नतीजे दिखाए जो सब खाली थे। मॉडल ने कभी रणनीति नहीं बदली क्योंकि कुछ भी उसे नहीं बता रहा था कि रणनीति काम नहीं कर रही। टूल नतीजे पढ़ने से लूप लगभग पंद्रह सेकंड में साफ़ दिख गया।

---

## स्तर 3: सेशन लॉग — पूर्ण, पुनः-चलाने योग्य रिकॉर्ड

ऊपर का सब कुछ एक ही आर्टिफैक्ट से पढ़ता है: सेशन फाइल। Octomind हर सेशन को यहाँ लिखता है

```
~/.local/share/octomind/sessions/<name>.jsonl.zst
```

यह zstd-कम्प्रेस्ड JSONL है — प्रति लाइन एक JSON ऑब्जेक्ट। ज़्यादातर लाइनें कच्चे बातचीत मैसेज हैं (`role: user|assistant|tool|system`)। इनके बीच टाइप-किए मार्कर हैं जो रनटाइम को रिज़्यूम पर स्टेट पुनर्निर्मित करने के लिए चाहिए:

| मार्कर                                | क्या रिकॉर्ड करता है                                                          |
| ------------------------------------- | ----------------------------------------------------------------------------- |
| `STATS`                               | चालू कुल योग — लागत, API समय, टूल समय — उस बिंदु पर                           |
| `COMPRESSION_POINT`                   | एक कम्प्रेशन चला: प्रकार, हटाए गए मैसेज, बचाए गए टोकन                         |
| `RESTORATION_POINT`                   | एक `/done` चेकपॉइंट — रीलोड पर पिछले मैसेज सिमट जाते हैं                      |
| `KNOWLEDGE_ENTRY`                     | कम्प्रेशन के दौरान निकाला गया तथ्य, रिज़्यूम पर दोबारा इंजेक्ट                |
| `COMMAND`                             | एक रनटाइम कमांड (`/model`, `/role`, `/effort`…), रिज़्यूम पर दोबारा चलाया गया |
| `PLAN_SNAPSHOT` / `SCHEDULE_SNAPSHOT` | सक्रिय प्लान / शेड्यूल, ताकि रीस्टार्ट से बच जाएँ                             |

यह फाइल मूल सत्य है। `/report` शाब्दिक रूप से इसी को डीकम्प्रेस करके और `STATS` व `USER`/`COMMAND` एंट्रीज़ पर चलकर लागत को रिक्वेस्ट के बीच बाँटकर बनती है। वही आप खुद कर सकते हैं:

```bash
zstd -dc ~/.local/share/octomind/sessions/my-feature-x.jsonl.zst \
  | jq -r 'select(.role == "tool") | "\(.content | length)\t\(.name)"' \
  | sort -n | tail
```

वह one-liner टूल नतीजों को आकार के हिसाब से सीधे लॉग से रैंक करता है — आपके टोकन-भक्षक, बिना सेशन खोले भी। चूँकि लॉग append-only JSONL है, यह एक बढ़िया replay आर्टिफैक्ट भी है: `octomind run --resume my-feature-x` से ठीक वही सेशन रिज़्यूम करें, या `--resume-recent` से मौजूदा डायरेक्टरी का सबसे ताज़ा वाला उठाएँ, और रनटाइम इन्हीं लाइनों से स्टेट दोबारा बना देता है।

---

## स्तर 4: `RUST_LOG` — जब आपको रनटाइम के भीतर देखना हो

सेशन लॉग दिखाता है कि _बातचीत क्या थी_। जब आपको देखना हो कि _रनटाइम ने क्या किया_ — कोई MCP सर्वर लोड क्यों नहीं हुआ, कोई टूल क्यों छूटा, प्रोवाइडर ने असल में क्या लौटाया — तो ट्रेसिंग चालू करें। Octomind `tracing` क्रेट पर बना है, मानक `RUST_LOG` एनवायरनमेंट वेरिएबल के पीछे। CLI मोड में जब तक आप न माँगें, **जानबूझकर कोई** ट्रेसिंग subscriber नहीं होता — यूज़र्स को साफ़ रंगीन आउटपुट मिलता है, कोई फ़ायरहोज़ नहीं। `RUST_LOG` सेट करें और फ़ायरहोज़ खुल जाता है:

```bash
# सब कुछ debug पर
RUST_LOG=debug octomind run

# इसे एक मॉड्यूल तक सीमित करें — व्यवहार में कहीं ज़्यादा उपयोगी
RUST_LOG=octomind::mcp=debug octomind run

# कई स्कोप, मिश्रित स्तर
RUST_LOG=octomind::session=debug,octomind::mcp=trace octomind run
```

स्कोप मायने रखता है। व्यस्त सेशन पर `RUST_LOG=debug` अपठनीय है; जब कोई टूल नहीं दिखता तब `RUST_LOG=octomind::mcp=debug` ठीक-ठीक बताता है कौन-सा कैंडिडेट स्वीकार या अस्वीकार हुआ और क्यों। यही वह स्तर है जहाँ "एजेंट को मेरा टूल दिखता ही नहीं" रहस्य रहना बंद कर देता है।

स्ट्रक्चर्ड-आउटपुट मोड में — ACP और WebSocket — stdout और stderr प्रोटोकॉल के लिए आरक्षित हैं, तो ट्रेसिंग फाइलों में जाती है:

```
~/.local/share/octomind/logs/acp-debug.log        ← ACP ट्रेसिंग
~/.local/share/octomind/logs/acp-errors.jsonl     ← ACP त्रुटियाँ, स्ट्रक्चर्ड
~/.local/share/octomind/logs/websocket-debug.log  ← WebSocket ट्रेसिंग
```

अगर आप Octomind को किसी एडिटर के पीछे ACP पर चला रहे हैं और कुछ गड़बड़ है, तो सबूत इन्हीं फाइलों में रहता है।

---

## स्तर 5: `--format jsonl` — रन को अपने ख़ुद के टूलिंग में पाइप करें

अब तक का सब कुछ टर्मिनल पढ़ते इंसान के लिए है। जैसे ही आप एजेंट को CI या पाइपलाइन में डालते हैं, आपको रन एक स्ट्रक्चर्ड इवेंट-स्ट्रीम के रूप में चाहिए जिस पर आप assertion लगा सकें। `octomind run --format jsonl` प्रति लाइन एक JSON ऑब्जेक्ट देता है — वही आंतरिक इवेंट-स्ट्रीम जो WebSocket सर्वर इस्तेमाल करता है — `type` से टैग किया हुआ:

```bash
echo "audit the auth module" | octomind run developer:general --format jsonl
```

हर लाइन एक अलग इवेंट है। जिन वैरिएंट्स की आपको परवाह होगी:

| `type`        | क्या ले जाता है                                                                                                                  |
| ------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `assistant`   | मॉडल के जवाब-टेक्स्ट का एक टुकड़ा                                                                                                |
| `thinking`    | तर्क सामग्री, जवाब से अलग                                                                                                        |
| `tool_use`    | `tool`, `tool_id`, `server`, `params` — एजेंट कार्रवाई करने वाला है                                                              |
| `tool_result` | `tool`, `content`, `success` — जो वापस आया                                                                                       |
| `cost`        | `session_tokens`, `session_cost`, `input_tokens`, `output_tokens`, `cache_read_tokens`, `cache_write_tokens`, `reasoning_tokens` |
| `error`       | एक फेलियर संदेश                                                                                                                  |
| `injected`    | एक ग़ैर-यूज़र टर्न — शेड्यूल्ड टाइमर, बैकग्राउंड एजेंट, skill — अपने `source_kind` के साथ                                        |
| `skill`       | एक skill सक्रिय, उपयोग, या भुलाई गई                                                                                              |

अब फेलियर मोड assertion बन जाते हैं। `tool_use` इवेंट गिनें और बिल्ड तोड़ें अगर कोई एक रिक्वेस्ट किसी सीमा को पार कर जाए — यह आपका बेलगाम-लूप ट्रिपवायर है। `cost` इवेंट के `session_cost` पर नज़र रखें और बजट पार होने पर अलर्ट करें। `tool_result` को `success: false` के लिए छानें। जो एजेंट पहले चुपचाप फेल होता था, अब इस तरह फेल होता है जिसे `jq` पकड़ सकता है:

```bash
echo "run the migration check" \
  | octomind run --format jsonl \
  | jq -c 'select(.type == "tool_use") | .tool' \
  | sort | uniq -c | sort -rn
```

यह पूरे रन के लिए टूल-कॉल का हिस्टोग्राम छापता है। अगर `shell` 60 की गिनती के साथ सबसे ऊपर है, तो आपने अपना लूप तब पकड़ लिया जब उसने आपका बटुआ नहीं पकड़ा था — और यह CI स्टेप में एक one-liner है, स्पिनर देखता कोई इंसान नहीं।

---

## स्तर 6: OctoHub — हर upstream रिक्वेस्ट पकड़ें

एक चीज़ है जो ऊपर का कुछ भी नहीं दिखा सकता, क्योंकि वह एजेंट के नीचे होती है: वे **सटीक बाइट्स** जो Octomind ने प्रोवाइडर को भेजे और वे सटीक बाइट्स जो वापस आए। एजेंट का नज़रिया उसके अपने मैसेज हैं। वह आपको वायर-स्तर रिक्वेस्ट नहीं दिखा सकता — रिज़ॉल्व्ड मॉडल, पूरा सीरियलाइज़्ड पेलोड, प्रोवाइडर का कच्चा जवाब, असली लेटेंसी। जब आपको शक हो कि समस्या ट्रांसलेशन लेयर में है (एक सिस्टम प्रॉम्प्ट जो वह नहीं जो आप सोचते हैं; एक टूल स्कीमा जिसे प्रोवाइडर ने बिगाड़ दिया; एक मॉडल जो वह नहीं जो आपने कॉन्फ़िगर किया) — तो आपको वायर देखना होगा।

[OctoHub](https://github.com/Muvon/octohub) हमारा LLM प्रॉक्सी है, और पूरा रिक्वेस्ट/रिस्पॉन्स लॉगिंग उसके होने की वजह है। Octomind को प्रोवाइडर के बजाय इस पर पॉइंट करें, और हर completion एक डेटाबेस में इनपुट, आउटपुट और मेट्रिक्स के साथ उतरता है। इसे चलाएँ:

```bash
./octohub   # डिफ़ॉल्ट रूप से 127.0.0.1:8080 पर सुनता है
```

यह `POST /v1/completions` (इसका नेटिव आकार) और `POST /v1/chat/completions` (क्लासिक OpenAI, किसी भी OpenAI-संगत क्लाइंट के लिए drop-in) दोनों बोलता है, और दोनों एक ही इंजन पर पड़ते हैं और एक ही `completions` टेबल में एक ही रिकॉर्ड `id` के साथ लिखते हैं। रन के बाद, एडमिन API से कच्चे रिकॉर्ड खींचें:

```bash
curl "http://127.0.0.1:8080/v1/admin/completions?limit=50" \
  -H "Authorization: Bearer <master-key>"
```

हर रिकॉर्ड वही पूरी तस्वीर रखता है जो एजेंट नहीं दे सका:

```json
{
  "id": "cmpl_<uuid>",
  "session_id": "<uuid>",
  "input_model": "my-model",
  "resolved_model": "gpt-5.5",
  "provider": "openai",
  "usage": {
    "input_tokens": 10,
    "output_tokens": 5,
    "total_tokens": 15,
    "cost": 0.0001,
    "request_time_ms": 320
  },
  "input": [...],
  "output": [...],
  "created_at": 1700000000
}
```

अकेला `input_model` बनाम `resolved_model` ही "यह अलग व्यवहार क्यों कर रहा है" बग के पूरे वर्ग को पकड़ लेता है — आपने एक मॉडल माँगा, एक alias किसी और में रिज़ॉल्व हो गया। `input` और `output` एरे शाब्दिक पेलोड हैं, तो जिस टूल स्कीमा पर प्रोवाइडर अटका, वह ठीक वहीं पढ़ने को है। `request_time_ms` प्रोवाइडर की असली लेटेंसी है, Octomind द्वारा जोड़े गए किसी भी चीज़ से अलग। और `GET /v1/admin/usage` यह सब API की और टाइम बकेट के हिसाब से समेटता है — इसी तरह आप "एजेंट महँगा है" से "यह की, यह मॉडल, यह घंटा" तक बिना अनुमान पहुँचते हैं। (अगर आप कई प्रोवाइडर्स के सामने एक साथ एजेंट चलाते हैं, तो प्रॉक्सी ही वह जगह है जहाँ यह समझदारी भरा बनता है — देखें [एक एजेंट, कई मॉडल](/blog/running-one-ai-agent-across-many-models)।)

प्रॉक्सी मॉडल की सीमा को एक अपारदर्शी किनारे से एक लॉग-किए, क्वेरी-योग्य सरफेस में बदल देता है। डिफ़ॉल्ट स्टोरेज SQLite है — `db_url = "sqlite://octohub.db"`, या `OCTOHUB_DB_URL` सेट करें — तो रिक्वेस्ट पढ़ना शुरू करने से पहले कोई इन्फ्रास्ट्रक्चर खड़ा करने की ज़रूरत नहीं।

---

## जब एजेंट X करे, तो Y देखें

पूरा मक़सद है "एजेंट ने कुछ हैरान करने वाला किया" को एक जाने-पहचाने लुकअप में बदलना। यह वह टेबल है जो मेरी मेज़ के ऊपर चिपकी है:

| लक्षण                                  | पहले देखें                                             | क्या ढूँढ रहे हैं                                |
| -------------------------------------- | ------------------------------------------------------ | ------------------------------------------------ |
| कहीं से भी आई सेशन लागत                | `/info`                                                | breakdown पंक्ति में `cache rd` ≫ `in`           |
| एक प्रॉम्प्ट ने सब खर्च कर दिया        | `/report`                                              | बिल ढोने वाली अकेली पंक्ति                       |
| कॉन्टेक्स्ट विंडो भरी / मॉडल "भूल गया" | `/info` का compression ब्लॉक, फिर `/context large`     | कम्प्रेशन गिनती और हद से बड़ा मैसेज              |
| लूप / दोहराई गई टूल-कॉल                | `/report` का tools कॉलम, या `jsonl` + `uniq -c`        | वही टूल, वही आर्ग्स, कोई प्रगति नहीं             |
| टूल एजेंट को उपलब्ध नहीं               | `RUST_LOG=octomind::mcp=debug`                         | कैंडिडेट क्यों छूटा                              |
| टूल नतीजा गलत दिखता है                 | `/context tool`                                        | मॉडल को मिले असली बाइट्स                         |
| किसी और मॉडल जैसा व्यवहार              | OctoHub `GET /v1/admin/completions`                    | `input_model` बनाम `resolved_model`              |
| प्रोवाइडर त्रुटि या अजीब लेटेंसी       | OctoHub रिकॉर्ड का `input`/`output`, `request_time_ms` | कच्चा पेलोड और असली टाइमिंग                      |
| CI में ट्रिपवायर चाहिए                 | `--format jsonl`                                       | `tool_use` गिनें, `cost` पर नज़र, `error` पकड़ें |
| ठीक वही रन दोबारा चलाएँ                | `octomind run --resume <name>`                         | `<name>.jsonl.zst` से replay                     |

---

## दो मिनट की डायग्नोसिस

अगर यह शुरू से जुड़ा होता, तो flaky-टेस्ट आपदा ऐसे गुज़रती — उस छह-मिनट के रहस्य के बजाय जो वह असल में थी।

स्पिनर देर तक चलता है। `/report` — रिक्वेस्ट 3 है $3.98 और 84 टूल-कॉल; बाकी दो ठीक हैं। तो बात उसी प्रॉम्प्ट की है। `/context tool` — अस्सी खाली `grep` नतीजे, मॉडल ने कभी रणनीति नहीं बदली। वो रहा लूप, और वो रही वजह। मूल कारण तक कुल समय: करीब नब्बे सेकंड, बिना चार डॉलर के, क्योंकि असली पाइपलाइन में `jsonl` का टूल-कॉल हिस्टोग्राम एक सीमा पर ट्रिप होकर रन को बीसवीं टूल-कॉल पर मार देता।

इसमें कुछ भी अनोखा नहीं। यह वही प्रवृत्ति है जो किसी भी प्रोडक्शन सिस्टम में लॉगिंग, मेट्रिक्स और ट्रेसिंग — एक ऐसे सिस्टम पर लागू जिसके फेलियर स्वभाव से ही ख़ामोश हैं। एजेंट आपको नहीं बताएगा कि वह खो गया है। पर रन पूरी तरह ऑब्ज़र्वेबल है अगर आप उसे सही तरीके से पूछें: आकार के लिए `/info`, दोषी के लिए `/report`, तर्क के लिए `/context`, रिकॉर्ड के लिए सेशन लॉग, रनटाइम के लिए `RUST_LOG`, मशीन के लिए `--format jsonl`, और वायर के लिए OctoHub।

महँगे रन से पहले इसे जोड़ें, बाद में नहीं।

— Don

---

_[Octomind](https://github.com/Muvon/octomind) और [OctoHub](https://github.com/Muvon/octohub) Apache-2.0 के तहत ओपन सोर्स हैं। अगर आपको चाहिए कोई डिबगिंग सरफेस नहीं है, तो [एक issue खोलें](https://github.com/Muvon/octomind/issues) — इस पोस्ट की ऑब्ज़र्वेबिलिटी काफ़ी हद तक इसलिए मौजूद है क्योंकि हमारे अपने एजेंट हमें चौंकाते ही रहे।_
