پروڈکشن سیکیور ایجنٹ لوپ کیسے بنایا جائے: ایگزٹ کنڈیشنز سے لے کر آڈٹ ٹریلز تک

جولائی 2025 میں، Claude Code recursive loop 5 گھنٹے میں 16,000 USD اور 50,000 USD کے درمیان جل گیا۔ کوئی کریش یا غلطیاں نہیں تھیں، اور چونکہ کسی نے ہمیں یہ نہیں بتایا کہ کب رکنا ہے، ایجنٹوں نے بالکل ویسا ہی کیا جیسا کہ انہیں بتایا گیا تھا۔

4 مہینوں کے بعد، 4 ایجنٹوں کے ساتھ ایک LangChain لوپ 11 دن تک چلا اور اس کی قیمت 47,000 USD تھی۔ بل آنے تک کسی نے نوٹس نہیں لیا۔ پائپ لائن نے ہمارے ٹیسٹوں میں صحیح کارکردگی کا مظاہرہ کیا اور ایجنٹوں نے بالکل وہی کیا جیسا کہ ہدایت کی گئی تھی۔ ایک ہی پیٹرن.

یہ ٹیوٹوریل غائب کمانڈز کے بارے میں ہے۔

ہم پانچ چھوٹے Python پرائمیٹوز بناتے ہیں جو زیادہ تر ایجنٹ لوپ کی غلطیوں کو جاری ہونے سے پہلے پکڑ لیتے ہیں۔

  • کوئی راستہ نہیں مخصوص مصنف لوپ شروع ہونے سے پہلے انجام دیا جانا ضروری ہے۔

  • کوئی راستہ نہیں سرکٹ بریکر سخت حد سے تجاوز کرنے پر لوپ سے باہر نکلیں۔

  • کوئی راستہ نہیں لیجر صرف ضمیمہ SQLite آڈٹ ٹریل میں ہر چیز کو لاگ کرتا ہے۔

  • نہیں ایجنٹ لوپ جو تینوں کو آپس میں جوڑتا ہے۔

  • کوئی راستہ نہیں سطح کا جائزہ خیال یہ ہے کہ نیچے دھارے کے نظام کو کچھ بھی موصول ہونے سے پہلے انسانی تصدیق پر مجبور کیا جائے۔

آخر کار آپ کے پاس ایک کام کرنے والا ذخیرہ ہوگا جس میں آپ کے تمام ایجنٹ پروجیکٹ جاسکتے ہیں۔ مکمل کوڈ github.com/dannwaneri/production-safe-agent-loop پر ہے۔

انڈیکس

  1. ایسا کیوں ہوتا رہتا ہے؟

  2. شرطیں

  3. مرحلہ 1: تعمیر سے پہلے مکمل کی وضاحت کریں۔

  4. مرحلہ 2: رن ٹائم پر تکمیل کو انجام دیں۔

  5. مرحلہ 3: سب کچھ ریکارڈ کریں۔

  6. مرحلہ 4: حدود کا احترام کرتے ہوئے لوپ

  7. مرحلہ 5: سطح کا جائزہ لیں۔

  8. مرحلہ 6: حقیقی زندگی کی مثال، SEO آڈیٹر

  9. پلگ ایبل ایل ایل ایم کلائنٹ

  10. ٹیسٹ چلائیں

  11. آپ نے کیا بنایا

  12. اگلے اقدامات

ایسا کیوں ہوتا رہتا ہے؟

کمپنی کو مشکل میں ڈالنے والا حساب کتاب آسان تھا۔ ایک چیٹ بوٹ کی قیمت تقریباً $0.04 فی تعامل ہے۔ سکیلڈ ملٹی ایجنٹ ورک فلو لاگت $1.20 ہے۔ یہ ایک 30x ضرب ہے، اور پیداوار کے معیارات سے پتہ چلتا ہے کہ پیچیدہ کاموں کے لیے 70x تک پہنچا جا سکتا ہے۔

مسئلہ یہ نہیں ہے کہ ایجنٹ مہنگے ہیں۔ مسئلہ یہ ہے کہ زیادہ تر ٹیموں نے چیٹ بوٹ کے اخراجات کے لیے بجٹ بنایا ہے اور ایجنٹ کے فن تعمیر کو تعینات کیا ہے۔ گارٹنر نے پایا کہ پائلٹ چیٹ بوٹس اور پروڈکشن ایجنٹ ورک فلو کے درمیان ٹوکن کی کھپت کا فرق 5 سے 30 گنا تک ہے۔ FinOps فاؤنڈیشن کی 2026 اسٹیٹ آف FinOps رپورٹ کے مطابق، 73% کمپنیوں نے کہا کہ ان کی AI کی قیمتیں اصل توقع سے زیادہ تھیں۔

ایک بار جب آپ اسے دیکھیں گے تو طریقہ کار آسان ہے۔ اگر ایجنٹ کسی آپریشن میں ناکام ہو جاتا ہے اور دوبارہ کوشش کرتا ہے، تو یہ نئے سرے سے شروع نہیں ہوتا ہے۔ دوبارہ کوشش کرنے سے پہلے ہر ناکام کوشش کے لیے پوری سیاق و سباق کی ونڈو کو دوبارہ پڑھا جاتا ہے۔ پہلی تکرار کے لیے 100 ٹوکن درکار ہیں۔ 2 تکرار کی لاگت 200 ہے۔ دس دہرانے پر ہزاروں ڈالر خرچ ہو سکتے ہیں۔ آپ ہر ناکامی کی ادائیگی جاری رکھیں گے، ملی سیکنڈ بہ ملی سیکنڈ۔

# This is the entire problem in three lines
while True:
    result = agent.run(task)
    # done when...?

سوالیہ نشان یہ ہے کہ پیسہ کہاں جاتا ہے۔

ایک اور چیز جو چیزوں کو بدتر بناتی ہے وہ یہ ہے کہ ایجنٹ نمایاں طور پر ناکام نہیں ہوتے ہیں۔ موجودہ کوڈ ایک غیر متعینہ حالت تک پہنچ جاتا ہے اور کریش ہو جاتا ہے۔ LLM ابہام کو حل کرنے اور مددگار بننے کی کوشش کرتا ہے۔ براہ کرم دوبارہ کوشش کریں۔ ٹول کال کو دوبارہ فارمیٹ کریں۔ تصدیقی ایجنٹ چلائیں۔ تصدیق کرنے والے ایجنٹ نے کچھ دریافت کیا۔ اصلاحی افسران کو برطرف۔ کسی نے بھی اس بات کی وضاحت نہیں کی کہ "صحیح” کا کیا مطلب ہے۔ آپ کے تمام ڈیش بورڈز پر لوپس خوبصورت نظر آتے ہیں – سرگرمیاں، ٹول کالز، فیصد مکمل، وغیرہ – خاموشی سے اپنا بجٹ کھاتے ہوئے

گارٹنر نے پیش گوئی کی ہے کہ 40% ایجنٹ پروجیکٹس 2027 تک معاشی ناکامی کی وجہ سے ترک کر دیے جائیں گے۔ زیادہ تر ناکامیاں روکی جا سکتی ہیں۔ برطرفی کی شرائط ہیں، بہتر ماڈل نہیں۔

شرطیں

git clone https://github.com/dannwaneri/production-safe-agent-loop
cd production-safe-agent-loop
pip install -r requirements.txt
export ANTHROPIC_API_KEY=sk-...

مرحلہ 1: تعمیر سے پہلے مکمل کی وضاحت کریں۔

ایجنٹ کی ترقی میں سب سے مہنگی غلطی غلط ماڈل کا انتخاب نہ کرنا یا دوبارہ کوشش کی حد کو کھونا ہے۔ تعمیر شروع ہوتی ہے اس سے پہلے کہ آپ ایک جملے میں ایک سوال کا جواب دے سکیں۔

تکمیل کیسی نظر آتی ہے؟

زیادہ تر ٹیمیں اس کا جواب نہیں دے سکتیں۔ یہ اس لیے نہیں کہ میں لاپرواہ ہوں، اس لیے کہ میں ٹرمینل کھولنے سے پہلے کسی چیز پر زبردستی نہیں کرتا۔ مخصوص مصنف فنکشن کو نافذ کرتا ہے۔

# spec_writer.py
from spec_writer import SpecWriter

spec = SpecWriter(db_path="spec.db").run()

جب آپ کال کرتے ہیں۔ .run()اسے واپس نہیں کیا جائے گا جب تک کہ تین سوالوں کے جواب نہ مل جائیں۔

  1. یہ کیا کرتا ہے؟

  2. یہ کیا نہیں کرتا؟

  3. ایک جملے میں کیا نظر آتا ہے؟

تیسرا سوال اہم ہے۔ یہ سب سے مشکل کام بھی ہے۔ "کسی ایجنٹ سے سائٹ کا آڈٹ کروائیں” جواب نہیں ہے۔ "ایجنٹ ٹارگٹ یو آر ایل کو کرال کرتا ہے اور سب کچھ نکالتا ہے۔ </code> اور <code><meta description=""/></code> ٹیگز، جھنڈا غائب یا زیادہ طوالت، اور سٹاپ” جوابات ہیں۔ ان میں سے ایک سرکٹ بریکر کو نافذ کرنے کے لیے کچھ دیتا ہے۔</p> <p>وضاحتیں SQLite میں محفوظ ہیں۔ <code>SpecResult</code> ڈیٹا کلاس <code>session_id</code>. وہ ID وہ دھاگہ بن جاتا ہے جو وضاحتیں، لیجر کی قطاریں، اور لوپ کے نتائج کو جوڑتا ہے۔ ایک سیشن کو سرے سے آخر تک ٹریک کیا جا سکتا ہے۔</p> <pre><code class="language-python">@dataclass(frozen=True) class SpecResult: what_it_does: str what_it_does_not: str done_looks_like: str session_id: str </code></pre> <p><code>frozen=True</code> یہ ضروری ہے۔ تصریح ایک وعدہ ہے، مسودہ نہیں۔ ایک بار لکھنے کے بعد، ایک لوپ اس پر چلتا ہے. کوئی درمیانی اصلاحات نہیں ہیں۔</p> <p>جانچ کے مقاصد کے لیے، <code>SpecWriter</code> انجیکشن قبول کریں۔ <code>input_fn</code> اور <code>output_fn</code> کال کے قابل۔ کوئی معیاری ان پٹ بندر پیچنگ کی ضرورت نہیں ہے۔ دیکھیں <code>tests/test_spec_writer.py</code> کام کرنے والی مثال کے طور پر – خاندان چھوٹا ہے۔ <code>scripted_input</code> ایک مددگار جو جنریٹر سے جوابات واپس کرتا ہے اور انہیں pytest کے ذریعے ٹیسٹ کے لیے مخصوص SQLite فائل میں لکھتا ہے۔ <code>tmp_path</code> فکسچر SQLite <code>:memory:</code> کیونکہ یہ یہاں محفوظ نہیں ہے۔ <code>SpecWriter</code> فی طریقہ ایک نیا کنکشن کھولتا ہے۔ <code>:memory:</code> کنکشن اس کا اپنا الگ تھلگ ڈیٹا بیس ہوتا ہے۔</p> <h2 id="heading-phase-2-enforce-done-at-runtime">مرحلہ 2: رن ٹائم پر تکمیل کو انجام دیں۔</h2> <p>اپ اسٹریم ختم کرنے کی شرائط کی وضاحت کرنا ایک نظم و ضبط ہے۔ سرکٹ بریکرز اثر میں ہیں۔</p> <pre><code class="language-python"># circuit_breaker.py from circuit_breaker import CircuitBreaker, CircuitBreakerError breaker = CircuitBreaker(turn_limit=5, token_limit=15000) breaker.check(turn_count, accumulated_tokens) # raises on breach </code></pre> <p>دو چھتیں ہیں۔ دونوں مشکل ہیں۔</p> <p><code>turn_limit</code> ایک لوپ LLM کو کال کرنے کی تعداد کو محدود کرتا ہے۔ <code>token_limit</code> تمام موڑ پر کل ٹوکن کی کھپت کو محدود کرتا ہے۔ ٹرپنگ میں سے ایک اٹھاتا ہے <code>CircuitBreakerError</code> فوری طور پر</p> <p>حدود سخت ہیں۔ <code>turn_count == turn_limit</code> اس کی اجازت ہے۔ <code>turn_count == turn_limit + 1</code> سفر کوئی رعایتی مدت یا انتباہ نہیں ہے۔ زبردستی روکنا انسان کو چوکی چلانے پر مجبور کرتا ہے۔</p> <pre><code class="language-python">from dataclasses import dataclass @dataclass class CircuitBreakerError(Exception): reason: str # "turn_ceiling" or "token_ceiling" turn_count: int accumulated_tokens: int def __post_init__(self) -> None: super().__init__( f"circuit breaker tripped: {self.reason} " f"(turn={self.turn_count}, tokens={self.accumulated_tokens})" ) class CircuitBreaker: def __init__(self, turn_limit: int = 5, token_limit: int = 15000) -> None: self.turn_limit = turn_limit self.token_limit = token_limit def check(self, turn_count: int, accumulated_tokens: int) -> None: if turn_count > self.turn_limit: self._trip("turn_ceiling", turn_count, accumulated_tokens) if accumulated_tokens > self.token_limit: self._trip("token_ceiling", turn_count, accumulated_tokens) def _trip(self, reason: str, turn_count: int, accumulated_tokens: int) -> None: print( "\n=== CIRCUIT BREAKER CHECKPOINT ===\n" f"reason : {reason}\n" f"turn_count : {turn_count} / limit {self.turn_limit}\n" f"tokens_used : {accumulated_tokens} / limit {self.token_limit}\n" "action : halt loop, surface to human reviewer\n" "==================================" ) raise CircuitBreakerError( reason=reason, turn_count=turn_count, accumulated_tokens=accumulated_tokens, ) </code></pre> <p><code>CircuitBreakerError</code> یہ ایک استثناء ہے، واپسی کوڈ نہیں۔ یہ جان بوجھ کر ہے۔ واپسی کوڈ کو نظر انداز کیا جا سکتا ہے۔ غیر پکڑے گئے مستثنیات ایسا نہیں کر سکتے۔ ایک خاموش خلاف ورزی ناممکن ہے. ایک انسانی پڑھنے کے قابل چیک پوائنٹ بینر کو معیاری آؤٹ پٹ پر پرنٹ کیا جاتا ہے: <code>_trip()</code> <em>پہلے</em> ایک استثنیٰ ڈالا جاتا ہے، اس لیے اگر کال کرنے والا استثناء کو نگل بھی لے، تب بھی آپریٹر ریاست کو دیکھ سکتا ہے۔</p> <p>اہم اصول: فون <code>.check()</code> <strong>پہلے</strong> کوئی LLM کال، LLM کال کے بعد نہیں۔ پرواز کے بعد کی تصدیق کا مطلب ہے کہ آپ نے اپنے ٹوکنز کو پہلے ہی جلا دیا ہے اس سے پہلے کہ آپ کو معلوم ہو کہ حد سے تجاوز کر گیا ہے۔</p> <pre><code class="language-python"># Wrong — post-flight result = client.messages.create(...) breaker.check(turn_count, accumulated_tokens) # too late # Right — pre-flight breaker.check(turn_count, accumulated_tokens) # raises before any spend result = client.messages.create(...) </code></pre> <p>ڈیفالٹس (5 موڑ، 15,000 ٹوکن) سخت ٹیوٹوریل ڈیمو کے ساتھ مطابقت رکھتے ہیں۔ پیداواری بجٹ مختلف ہیں۔ انسٹی ٹیوٹ پر ایڈجسٹمنٹ:</p> <pre><code class="language-python"># Production example — tighter token budget, more turns breaker = CircuitBreaker(turn_limit=10, token_limit=50000) </code></pre> <h2 id="heading-phase-3-record-everything">مرحلہ 3: سب کچھ ریکارڈ کریں۔</h2> <p>سرکٹ بریکر آپ کے بینک کھاتوں کی حفاظت کرتے ہیں۔ لیجر آپ کی سمجھ کی حفاظت کرتا ہے کہ کیا ہوا ہے۔</p> <p>زیادہ تر ٹیمیں ڈیبگنگ کے لیے لاگ ان کرتی ہیں۔ ایک مسئلہ ہونے کے بعد، آپ جاننا چاہتے ہیں کہ کیا غلط ہوا ہے۔ لیجرز کے مختلف مقاصد ہوتے ہیں۔ یہ گورننس ہے۔ ہر قطار ثابت کرتی ہے کہ آیا لوپ حدود کے اندر رہا، آیا نہیں، اور بالکل کب۔</p> <pre><code class="language-python"># ledger.py from ledger import Ledger ledger = Ledger(db_path="ledger.db") ledger.write( session_id=spec.session_id, turn_count=1, state_origin="llm", input_str=task, token_delta=523, execution_time_ms=1240, pass_fail=True, ) </code></pre> <p>ایک لائن فی موڑ۔ صرف شامل کریں، کوئی اپ ڈیٹ نہیں، کوئی حذف نہیں۔ عدم تغیر کلید ہے۔ جس لیجر میں ترمیم کی جا سکتی ہے وہ نوٹ بک ہے، لیجر نہیں۔</p> <p>سکیما:</p> <pre><code class="language-sql">CREATE TABLE IF NOT EXISTS ledger ( id INTEGER PRIMARY KEY AUTOINCREMENT, session_id TEXT NOT NULL, turn_count INTEGER NOT NULL, state_origin TEXT NOT NULL, input_hash TEXT NOT NULL, token_delta INTEGER NOT NULL, execution_time_ms INTEGER NOT NULL, pass_fail INTEGER NOT NULL, -- 1=pass, 0=fail breach_reason TEXT, -- NULL unless circuit breaker fired created_at TEXT NOT NULL -- ISO 8601, UTC ); CREATE INDEX IF NOT EXISTS idx_ledger_session ON ledger(session_id); </code></pre> <p>جسو بناتا ہے۔ <code>get_session(session_id)</code> – بنیادی پڑھنے کا راستہ – جیسا کہ لیجر بڑھتا ہے مسلسل تلاش۔</p> <p>وضاحت کے قابل تین فیصلے:</p> <ol> <li> <p><code>input_hash</code> <strong>~ نہیں</strong> <code>input_text</code><strong>.</strong> خام ان پٹ سٹرنگز برقرار نہیں ہیں۔ صرف SHA-256 ہیشز قبول کی جاتی ہیں۔ اس کے دو فائدے ہیں: پورے عمل میں ایک ہی ان پٹ کا پتہ لگایا جا سکتا ہے اور آڈٹ ٹریل میں کوئی PII داخل نہیں کیا جاتا ہے۔</p> </li> <li> <p><code>pass_fail</code> <strong>پسند</strong> <code>INTEGER</code> <strong>~ نہیں</strong> <code>BOOLEAN</code><strong>.</strong> SQLite میں کوئی بولین قسم نہیں ہے۔ <code>1</code> اور <code>0</code> یہ سرکاری ہے۔ API کے کنارے پر Python ergonomics کو صاف کریں اور ڈسک پر SQL کی قسمیں ٹھیک کریں۔</p> </li> <li> <p><code>created_at</code> <strong>پسند</strong> <code>datetime.now(timezone.utc).isoformat()</code><strong>.</strong> <code>datetime.utcnow()</code> Python 3.12 میں فرسودہ۔ ٹائم زون سے آگاہ ٹائم اسٹیمپ ٹائم زون کو عبور کرنے والے کسی بھی سسٹم پر فٹگن کو روکتے ہیں۔</p> </li> </ol> <p>سیشن کے لحاظ سے تلاش کریں:</p> <pre><code class="language-python">rows = ledger.get_session(spec.session_id) for row in rows: print(f"Turn {row.turn_count}: {'PASS' if row.pass_fail else 'FAIL'} " f"| {row.token_delta} tokens | {row.execution_time_ms}ms") </code></pre> <h2 id="heading-phase-4-the-loop-that-respects-its-boundaries">مرحلہ 4: حدود کا احترام کرتے ہوئے لوپ</h2> <p>ایجنٹ لوپ تین پرائمیٹوز کو ایک ساتھ جوڑتا ہے۔ یہ واحد جزو ہے جو ایل ایل ایم کہتا ہے۔ باقی سب کچھ مقامی ہے۔</p> <pre><code class="language-python"># agent_loop.py from agent_loop import AgentLoop loop = AgentLoop(spec, breaker, ledger, client) result = loop.run(task) # LoopResult(success, turns, total_tokens, session_id, breach_reason) </code></pre> <p>موڑ کی ساخت کو مندرجہ ذیل ترتیب میں بیان کیا گیا ہے۔</p> <ol> <li> <p><code>circuit_breaker.check(turn_count, accumulated_tokens)</code> – اگر آپ حد سے تجاوز کرتے ہیں تو یہ بڑھ جائے گا۔</p> </li> <li> <p><code>client.messages.create(...)</code> – ایک حقیقی LLM کال</p> </li> <li> <p><code>ledger.write(...)</code> – 1 قطار، صرف شامل کریں۔</p> </li> <li> <p>اگر <code>stop_reason == "end_turn"</code>واپسی ورنہ لوپ.</p> </li> </ol> <p>ہم بغیر کسی استثناء کے ہر LLM کال سے پہلے فلائٹ چیک کرتے ہیں۔</p> <pre><code class="language-python">def run(self, task: str) -> LoopResult: session_id = self.spec.session_id messages: list[dict] = [{"role": "user", "content": task}] turn = 0 total_tokens = 0 try: while True: turn += 1 self.circuit_breaker.check(turn, total_tokens) started = time.perf_counter() response = self.client.messages.create( model=self.model, max_tokens=self.max_tokens, system=self._system_prompt(), messages=messages, ) elapsed_ms = int((time.perf_counter() - started) * 1000) turn_tokens = ( getattr(response.usage, "input_tokens", 0) + getattr(response.usage, "output_tokens", 0) ) total_tokens += turn_tokens text = self._text_from(response) messages.append({"role": "assistant", "content": text}) self.ledger.write( session_id=session_id, turn_count=turn, state_origin="llm", input_str=task, token_delta=turn_tokens, execution_time_ms=elapsed_ms, pass_fail=True, ) if getattr(response, "stop_reason", "end_turn") == "end_turn": return LoopResult( success=True, turns=turn, total_tokens=total_tokens, session_id=session_id, ) messages.append({"role": "user", "content": "continue"}) except CircuitBreakerError as err: self.ledger.write( session_id=session_id, turn_count=turn, state_origin="circuit_breaker", input_str=task, token_delta=0, execution_time_ms=0, pass_fail=False, breach_reason=err.reason, ) return LoopResult( success=False, turns=turn, total_tokens=total_tokens, session_id=session_id, breach_reason=err.reason, ) def _system_prompt(self) -> str: return ( "You are an agent working on a tightly-scoped task.\n\n" f"What this does: {self.spec.what_it_does}\n" f"What this does NOT do: {self.spec.what_it_does_not}\n" f"Done looks like: {self.spec.done_looks_like}\n" ) @staticmethod def _text_from(response) -> str: content = getattr(response, "content", None) if not content: return "" block = content[0] return getattr(block, "text", "") or "" </code></pre> <p>اس متن میں کچھ اختیارات قابل ذکر ہیں:</p> <ul> <li> <p><strong>پوری</strong> <code>while True:</code> <strong>ایک کے طور پر پیک کیا</strong> <code>try/except CircuitBreakerError</code><strong>.</strong> چیک ہر موڑ کے اوپر کیا جاتا ہے، لہذا خلاف ورزی اسی طرح پکڑی جاتی ہے چاہے یہ موڑ 1 پر ہو یا 6 موڑ پر۔</p> </li> <li> <p><code>input_str=task</code> ہر لیجر قطار پر – اصل آپریشن، آخری ثانوی پیغام نہیں۔ کہ <code>input_hash</code> پھر کالم قطاروں کو گروپ کرتا ہے جو پھانسیوں میں ایک ہی ابتدائی ان پٹ کا اشتراک کرتی ہے۔</p> </li> <li> <p><code>pass_fail=True</code> <strong>ہر ایل ایل ایم کی باری واپسی کے لیے</strong>, <code>False</code> صرف خلاف ورزی کی صورت میں۔ پاس/فیل فلیگ اس بات پر نظر رکھتا ہے کہ لوپ چل رہا ہے یا نہیں۔ <em>پہنچ گئے</em> یہ اس بارے میں نہیں ہے کہ آیا ماڈل کا آؤٹ پٹ اچھا ہے یا نہیں، لیکن آیا یہ ایک جائز قطار ہے۔ معیار کی تشخیص ایک الگ تشویش ہے۔</p> </li> <li> <p><code>_system_prompt()</code> <strong>تینوں وضاحتی فیلڈز استعمال کریں۔</strong>ہاں <code>done_looks_like</code>. ماڈل میں منفی رینج ہے (<code>what_it_does_not</code>) کم از کم جہاں تک مثبت حد تک۔</p> </li> <li> <p><code>time.perf_counter()</code> <strong>~ نہیں</strong> <code>time.time()</code> – نیرس اور انٹرمیڈیٹ وال کلاک ایڈجسٹمنٹ سے غیر متاثر۔</p> </li> </ul> <p><code>LoopResult.session_id</code> سے وراثت میں ملا ہے <code>spec.session_id</code>. لیجر کی قطاریں بغیر کسی جوڑ کے تفصیلات سے منسلک ہیں۔ ایک سیشن ID، ایک ٹریس ایبل ایگزیکیوشن، ختم ہونا شروع کریں۔</p> <h2 id="heading-phase-5-the-review-surface">مرحلہ 5: سطح کا جائزہ لیں۔</h2> <p>سرکٹ بریکر آپ کے بینک کھاتوں کی حفاظت کرتے ہیں۔ لیجر ریکارڈ کرتا ہے کہ کیا ہوا۔ لیکن نہ ہی آپ کو یہ بتاتا ہے کہ کیا وہی ہوا جس کا وعدہ کیا گیا تھا۔</p> <p>وہ خلا ہے جہاں غلط لوپ کو قبول کیا جاتا ہے۔ پالش آؤٹ پٹ، گرین ڈیش بورڈ، اپنے وعدوں کو پورا کرنے میں ناکام رہا۔ جائزہ لینے والا نمونے کو دیکھتا ہے، اس کے مناسب ہونے کا تعین کرتا ہے، اور اسے منظور کرتا ہے۔ کسی نے یہ نہیں پوچھا کہ کیا اصل وعدہ پورا ہوا؟</p> <p>اس خلا کو بند کرنے والی سطحوں کا جائزہ لیں۔ SQLite سیشن کو پڑھتا ہے، پانچ عناصر کا ایک فریم جمع کرتا ہے، اور ڈاون اسٹریم کو آؤٹ پٹ حاصل کرنے سے پہلے موازنہ پر مجبور کرتا ہے۔</p> <pre><code class="language-python">from review_surface import ReviewSurface rs = ReviewSurface(spec_db_path="spec.db", ledger_db_path="ledger.db") print(rs.render(session_id)) </code></pre> <p>فریم 5 عناصر پر مشتمل ہے:</p> <ol> <li> <p><strong>اصل وعدہ</strong> — مخصوص جدول سے لیا گیا: یہ کیا کرتا ہے، کیا نہیں کرتا، اور جب یہ ہو جاتا ہے تو کیسا لگتا ہے۔</p> </li> <li> <p><strong>پاس کرنے کا معیار</strong> – <code>done_looks_like</code> واضح بینچ مارکس کے ساتھ پیش کردہ فیلڈز</p> </li> <li> <p><strong>فرق</strong> – پہلا موڑ ان پٹ بمقابلہ آخری باری آؤٹ پٹ، موڑ مکمل، کل ٹوکن، لوپ کی خلاف ورزی یا نہیں</p> </li> <li> <p><strong>ثبوت</strong> — سیشن میں لیجر کی تمام قطاریں: مرحلہ پاس/فیل، ٹوکن ڈیلٹا، عمل درآمد کا وقت</p> </li> <li> <p><strong>غیر حل شدہ مفروضے۔</strong> — خلاف ورزی کرنے والی قطاروں اور ناکام گردشوں سے ماخوذ۔ جب یہ صاف ہو جائے تو اسے خالی چھوڑ دیں۔</p> </li> </ol> <p>جائزہ لینے والے کے اطمینان پر، ہم تصدیق کرتے ہیں کہ:</p> <pre><code class="language-python">attestation = rs.attest( session_id=result.session_id, reviewer="daniel", notes="Output matches spec. Approved." ) print(attestation.frame_hash) </code></pre> <p><code>.attest()</code> کو لکھیں۔ <code>attestations</code> میں میز <code>ledger.db</code>. کہ <code>frame_hash</code> ایک ہی سیشن کی توثیق کرنے والے جائزہ لینے والوں کے درمیان حتمی فریم شدہ ڈیٹا کا SHA-256۔ یہ شکریہ کی رسید ہے۔ اس سے ثابت ہوتا ہے کہ جائزہ لینے والے نے بالکل ٹھیک فریم کو پیش کردہ کے طور پر دیکھا، خلاصہ یا پیرا فریس نہیں۔</p> <p>منظوری اس بات کی تصدیق کرتی ہے کہ عمل مکمل ہو گیا ہے۔ تصدیق اس بات کی تصدیق کرتی ہے کہ جائزہ لینے والے نے وعدے کے ساتھ آؤٹ پٹ کا موازنہ کیا ہے۔ ایک بار جب لوپ کسی ریگولیٹڈ ہستی کو چھوتا ہے، تو یہ ایک مختلف قانونی دستاویز ہوتی ہے۔</p> <pre><code class="language-python">@dataclass(frozen=True) class ReviewFrame: session_id: str original_promise: SpecResult acceptance_criteria: str diff: DiffResult evidence: tuple # tuple[LedgerRow, ...] unresolved_assumptions: tuple # tuple[str, ...] created_at: str </code></pre> <p><code>ReviewFrame</code> اسی وجہ سے اسے منجمد کیا گیا تھا۔ <code>SpecResult</code> – فریم ایک ثبوت ہے، مسودہ نہیں۔ <code>evidence</code> اور <code>unresolved_assumptions</code> فہرستیں ٹیپلز ہیں کیونکہ وہ ہیش ایبل نہیں ہیں اور فکسڈ ڈیٹا کلاسز کو ہیش ایبل فیلڈز کی ضرورت ہوتی ہے۔</p> <p>جائزہ اسکرین کے ذریعے مکمل اختتام سے آخر تک بہاؤ مندرجہ ذیل ہے: <code>examples/review_example.py</code> ریپو سے۔ سیشن مکمل ہونے کے بعد چلتا ہے۔ یہ پانچ عناصر کا فریم پیش کرتا ہے، ثبوت کی درخواست کرتا ہے، اور اگر منظور ہو جائے تو ایک رسید بناتا ہے۔</p> <p>لوپ آپ کی طرف دوڑتا ہے۔ ڈاؤن اسٹریم سسٹم کو اس وقت تک کچھ نہیں ملتا جب تک کوئی دستخط نہ کرے۔</p> <h2 id="heading-phase-6-a-real-example-seo-audit-agent">مرحلہ 6: حقیقی دنیا کی مثالیں — SEO آڈیٹرز</h2> <p>پیٹرن صرف حقیقی مسائل کے لیے معنی رکھتے ہیں۔ یہ میرے SEO-ایجنٹ پروجیکٹ کے پیچھے وہی ایجنٹ فن تعمیر ہے۔</p> <p>SEO آڈٹ کا ایک فطری بہاؤ ہوتا ہے: رینگنا، ٹوٹے ہوئے حصوں کو سرفیس کرنا، انہیں ٹھیک کرنا، اور ان کے دوبارہ انڈیکس ہونے کا انتظار کرنا۔ ایجنٹ کو مسلسل چلانے سے اس کا چکر تبدیل نہیں ہوتا ہے۔ آپ صرف اہم لمحات کے درمیان خالی جگہ پر ٹوکن جلاتے ہیں۔ لوپ میں جکڑے ہوئے کرون جاب ایک ایماندار فن تعمیر ہے۔</p> <pre><code class="language-python"># examples/seo_audit_example.py import requests from bs4 import BeautifulSoup import anthropic from spec_writer import SpecWriter from circuit_breaker import CircuitBreaker from ledger import Ledger from agent_loop import AgentLoop def crawl_url(url: str) -> str: response = requests.get(url, timeout=10) soup = BeautifulSoup(response.text, "html.parser") title = soup.find("title") meta_desc = soup.find("meta", attrs={"name": "description"}) h1_tags = soup.find_all("h1") return ( f"URL: {url}\n" f"Title: {title.text if title else 'MISSING'}\n" f"Meta description: " f"{meta_desc['content'] if meta_desc else 'MISSING'}\n" f"H1 count: {len(h1_tags)}\n" f"H1 tags: {[h.text[:50] for h in h1_tags]}" ) def run_seo_audit(url: str) -> None: # Step 1: Define done before the loop starts spec = SpecWriter(db_path="spec.db").run() # Step 2: Initialise circuit breaker and ledger breaker = CircuitBreaker(turn_limit=5, token_limit=15000) ledger = Ledger(db_path="ledger.db") client = anthropic.Anthropic() # Step 3: Crawl the URL site_data = crawl_url(url) # Step 4: Run the loop # AgentLoop catches CircuitBreakerError internally and returns # LoopResult(success=False, breach_reason=...). Branch on the # result — do NOT wrap loop.run() in try/except CircuitBreakerError. loop = AgentLoop(spec, breaker, ledger, client) result = loop.run( f"Audit this page for SEO issues:\n\n{site_data}" ) # Step 5: Print the ledger print(f"\nResult: {'SUCCESS' if result.success else 'BREACH'}") if not result.success: print(f"Breach reason: {result.breach_reason}") print(f"Turns: {result.turns} | Tokens: {result.total_tokens}") print("\nAudit trail:") for row in ledger.get_session(result.session_id): status = "PASS" if row.pass_fail else "FAIL" print(f" Turn {row.turn_count}: {status} | " f"{row.token_delta} tokens | {row.execution_time_ms}ms") if __name__ == "__main__": import sys run_seo_audit(sys.argv[1] if len(sys.argv) > 1 else "https://example.com") </code></pre> <p>چلائیں:</p> <pre><code class="language-bash">python examples/seo_audit_example.py https://yourdomain.com </code></pre> <p>مخصوص مصنف ایک پیغام دکھاتا ہے۔ لوپ چلتا ہے، حد سے تجاوز کرنے پر سرکٹ بریکر ٹرپ کرتا ہے، اور لیجر ہر گردش کو ریکارڈ کرتا ہے۔ آؤٹ پٹ آپ کے سامنے آتا ہے اور آپ فیصلہ کرتے ہیں کہ کیا ٹھیک کرنا ہے۔</p> <p>لوپ آپ کی طرف دوڑتا ہے، جگہ نہیں۔</p> <h2 id="heading-pluggable-llm-client">پلگ ایبل ایل ایل ایم کلائنٹ</h2> <p>لوپ ان تمام کلائنٹس پر کام کرتا ہے جو مطمئن ہیں: <code>LLMClient</code> پروٹوکول (بذریعہ ڈیفالٹ اینتھروپک)۔ ~20 لائن اڈاپٹر کے ساتھ اپنا اپنا لائیں۔</p> <pre><code class="language-python"># agent_loop.py from typing import Protocol, runtime_checkable @runtime_checkable class MessagesEndpoint(Protocol): def create(self, *, model: str, max_tokens: int, system: str, messages: list) -> object: ... @runtime_checkable class LLMClient(Protocol): messages: MessagesEndpoint </code></pre> <p><code>messages</code> یہ ایک مثالی خاصیت ہے (گھروں والی کلاس نہیں) کیونکہ اس طرح اصل اینتھروپک SDK اسے بے نقاب کرتا ہے۔ <code>anthropic.Anthropic().messages.create(...)</code>. اسے نیسٹڈ کلاس کے طور پر ماڈلنگ کرنے کا مطلب ہے کہ اصل کلائنٹ پروٹوکول کو مطمئن نہیں کرتا ہے۔ کہ <code>@runtime_checkable</code> ڈیکوریٹر آپ کو مطابقت برقرار رکھنے کو یقینی بنانے کی اجازت دیتے ہیں۔ <code>isinstance(client, LLMClient)</code>ریپوزٹری کا ٹیسٹ سویٹ اس دعوے کو بالکل ٹھیک استعمال کرتا ہے۔ <code>FakeClient</code> ڈبل ٹیسٹ۔</p> <p>ذیل میں اوپن اے آئی اڈاپٹر کی ایک مثال دی گئی ہے (صرف مثالی مقاصد کے لیے؛ پروڈکشن اڈاپٹر اسٹریمنگ، ٹولنگ، اور غلطی کی اقسام کا نقشہ بھی بناتا ہے):</p> <pre><code class="language-python"># openai_adapter.py — illustrative pseudocode, not production-ready. from openai import OpenAI as _OpenAI class _MessagesAdapter: def __init__(self, client): self._client = client def create(self, *, model, max_tokens, system, messages): completion = self._client.chat.completions.create( model=model, max_tokens=max_tokens, messages=[{"role": "system", "content": system}] + messages, ) # Reshape OpenAI's response into the Anthropic-shaped surface # AgentLoop reads: response.usage.{input,output}_tokens, # response.content[0].text, response.stop_reason. return _adapt_response(completion) class OpenAIAdapter: def __init__(self, api_key: str): self._client = _OpenAI(api_key=api_key) self.messages = _MessagesAdapter(self._client) # instance attr, not a nested class </code></pre> <p>اڈاپٹر پیٹرن واضح طور پر سکھانے کے قابل ہے. فراہم کنندہ APIs ظاہری شکل کا اشتراک نہیں کرتے ہیں۔ انسانیت کے پاؤں <code>system</code> اعلیٰ ترین سطح پر۔ OpenAI اسے ایک پیغام کی صف میں رکھتا ہے۔ اڈاپٹر شیم ~ 20 لائنیں لمبا ہے اور اسے کسی بھی چیز کو دوبارہ لکھے بغیر لوپ فراہم کنندہ کو اجناسٹک بنا دیتا ہے۔ براہ کرم اس کا حوالہ دیں۔ <code>self.messages</code> کو تفویض کیا جاتا ہے۔ <code>__init__</code> لہذا یہ ہر اڈاپٹر مثال کی اصل خصوصیات ہیں اور اصل SDK جیسی ظاہری شکل ہے۔</p> <h2 id="heading-running-the-tests">ٹیسٹ چلائیں</h2> <pre><code class="language-bash">python -m pytest tests/ </code></pre> <p>لاگو علاقہ:</p> <pre><code class="language-bash">python -m coverage run --source=circuit_breaker,ledger,spec_writer,agent_loop,review_surface -m pytest tests/ python -m coverage report -m </code></pre> <p>80 ٹیسٹ، تمام 5 بنیادی ماڈیولز کی 100% کوریج۔ لوپ اس کے لیے چلتا ہے: <code>FakeClient</code> ڈبل ٹیسٹ کی وضاحت ان لائن <code>tests/test_agent_loop.py</code>. یہ مندرجہ ذیل کو مطمئن کرتا ہے: <code>LLMClient</code> بتھ ٹائپنگ کے ذریعے پروٹوکول: <code>messages</code> پر مقرر ہے <code>self</code>تو <code>client.messages.create(...)</code> یہ ایک ہی شے کی طرف واپس جاتا ہے اور ہر ٹیسٹ کے منظر نامے کے لیے اسکرپٹ شدہ جوابات فراہم کرتا ہے۔ ذخیرہ کلون کریں اور اسے چلائیں۔ <code>pytest</code> دیکھیں کہ کیا تمام 80 ٹیسٹ نیٹ ورک کو چھوئے بغیر یا API کلید کی ضرورت کے بغیر پاس ہو جاتے ہیں۔</p> <p><code>circuit_breaker.py</code> 100% کوریج ہے اور کوئی بھی راستہ بغیر ٹیسٹ شدہ نہیں ہے۔ یہ مالیاتی حفاظت کا حصہ ہے۔ جو بھی راستہ اس سے گزرتا ہے اسے پھانسی دی جاتی ہے۔</p> <h2 id="heading-what-youve-built">آپ نے کیا بنایا</h2> <p>اس ٹیوٹوریل میں، ہم نے پانچ چھوٹے پرائمیٹوز بنائے ہیں، جن میں سے ہر ایک کو آزادانہ طور پر استعمال کیا جا سکتا ہے۔</p> <table> <thead> <tr> <th>ماڈیول</th> <th>کردار</th> <th>سموچ</th> </tr> </thead> <tbody> <tr> <td><code>spec_writer.py</code></td> <td>لوپ چلنے سے پہلے تین جوابات پر مجبور کرتا ہے۔</td> <td>104</td> </tr> <tr> <td><code>circuit_breaker.py</code></td> <td>موڑ اور ٹوکن پر سخت چھت</td> <td>41</td> </tr> <tr> <td><code>ledger.py</code></td> <td>صرف SQLite آڈٹ ٹریل شامل کریں۔</td> <td>113</td> </tr> <tr> <td><code>agent_loop.py</code></td> <td>ایک لوپ جو دونوں کا احترام کرتا ہے۔</td> <td>128</td> </tr> <tr> <td><code>review_surface.py</code></td> <td>پانچ عناصر کے فریم کو جمع کریں اور انسانی گواہی کو ریکارڈ کریں۔</td> <td>114</td> </tr> </tbody> </table> <p>پیٹرن: اپ اسٹریم ڈسپلن حدود کی وضاحت کرتے ہیں۔ ڈاؤن اسٹریم نفاذ سرکٹ کو توڑ دیتا ہے۔ نہ ہی خود پولیس کو ماڈل پر بھروسہ کرتا ہے۔</p> <p>ایک لوپ جو باہر نکلنے کی شرط کے بغیر چلتا ہے وہ خود مختار نہیں ہے۔ ادائیگی کی تقریب کا انتظار ہے۔</p> <p>شروع کرنے سے پہلے، وضاحت کریں کہ تیار شدہ شکل کیسی ہوگی۔ یہ وہی ہے، اور یہ ہمیشہ ایسا ہی رہا ہے۔</p> <h2 id="heading-next-steps">اگلے اقدامات</h2> <p>ذخیرہ github.com/dannwaneri/production-safe-agent-loop پر ہے۔</p> <p>اگر آپ مزید جانا چاہتے ہیں تو، تین قدرتی توسیعات ہیں:</p> <h3 id="heading-1-graduation-to-distributed-systems">1. تقسیم شدہ نظاموں میں گریجویشن</h3> <p>SQLite لیجرز الگ تھلگ ترتیب وار لوپس پر کام کرتے ہیں۔ جس لمحے آپ مشترکہ ریاست پر ایک سے زیادہ ایجنٹ چلاتے ہیں، آپ کو سیریلائزبل آئسولیشن کی ضرورت ہوتی ہے۔ اس کا مطلب یہ ہے کہ فلیٹ JSON کو کنکرنٹ رائٹ خود بخود ٹوٹ جاتی ہیں۔ README تین اہم موڑ کو دستاویز کرتا ہے جہاں سے ایک فلیٹ لیجر کو گریجویٹ ہونا ضروری ہے:</p> <h3 id="heading-2-cryptographic-signing">2. کرپٹوگرافک دستخط</h3> <p>تعمیل پیمانے کے نظام کے لیے جہاں لوپ کے چلنے پر کوئی آڈیٹر موجود نہیں تھا، اکیلے SQLite قطاریں کافی نہیں ہوں گی۔ ڈیٹا بیس ایڈمنسٹریٹر چلا سکتے ہیں: <code>UPDATE</code> سوال Ed25519 دستخط ہر لیجر کی قطار کو ایک رسید میں لپیٹتا ہے جو ثابت کرتا ہے کہ لاگ ان کو پھانسی کے بعد سے تبدیل نہیں کیا گیا ہے۔ لیکن یہ ایک مختلف ٹیوٹوریل ہے۔</p> <h3 id="heading-wiring-a-cron-job">کرون جاب کنکشن</h3> <p>SEO آڈٹ ایجنٹ کا دیانت دار فن تعمیر خود مختار 24/7 آپریشن نہیں ہے۔ ایک کرون جاب جو ایک شیڈول پر چلتی ہے، کسی بھی بدعنوانی کو ڈھونڈتی ہے، اور پھر اسے روک دیتی ہے۔ <code>0 3 * * 2 python examples/seo_audit_example.py https://yourdomain.com</code> بس۔ لوپ آپ کی طرف دوڑتا ہے، جگہ نہیں۔</p> <p>اگر آپ کو اپنے اسٹیک (سرکٹ بریکرز، آڈٹ ٹریلز، پروڈکشن سیفٹی ایجنٹ لوپس) کے لیے بنائے گئے اس فن تعمیر کی ضرورت ہے تو کچھ فری لانس کام کریں۔ dannwaneri.com/ai-agents/</p> </p></div> </div><!-- .entry-content .clear --> </div> </article><!-- #post-## --> <nav class="navigation post-navigation" aria-label="Posts" data-no-translation-aria-label=""> <div class="nav-links"><div class="nav-previous"><a title="Verizon نے کیریئر سوئچ کو راغب کرنے کے لیے نئے سبسکرائبرز کے لیے ڈسکاؤنٹ پلان شروع کیا۔" href="https://umang.pk/en_us/2026/06/16/verizon-%d9%86%db%92-%da%a9%db%8c%d8%b1%db%8c%d8%a6%d8%b1-%d8%b3%d9%88%d8%a6%da%86-%da%a9%d9%88-%d8%b1%d8%a7%d8%ba%d8%a8-%da%a9%d8%b1%d9%86%db%92-%da%a9%db%92-%d9%84%db%8c%db%92-%d9%86%d8%a6%db%92/" rel="prev"><span class="ast-post-nav" aria-hidden="true"><span aria-hidden="true" class="ahfb-svg-iconset ast-inline-flex svg-baseline"><svg xmlns='http://www.w3.org/2000/svg' viewbox='0 0 448 512'><path d='M134.059 296H436c6.627 0 12-5.373 12-12v-56c0-6.627-5.373-12-12-12H134.059v-46.059c0-21.382-25.851-32.09-40.971-16.971L7.029 239.029c-9.373 9.373-9.373 24.569 0 33.941l86.059 86.059c15.119 15.119 40.971 4.411 40.971-16.971V296z'></path></svg></span> Previous</span> <p> Verizon نے کیریئر سوئچ کو راغب کرنے کے لیے نئے سبسکرائبرز کے لیے ڈسکاؤنٹ پلان شروع کیا۔ </p></a></div><div class="nav-next"><a title="پرائم ڈے کا انتظار کیوں؟ 'شاندار' نتھنگ فون (3) پہلے ہی ایمیزون پر ریکارڈ چھوٹ دیکھ چکا ہے۔" href="https://umang.pk/en_us/2026/06/16/%d9%be%d8%b1%d8%a7%d8%a6%d9%85-%da%88%db%92-%da%a9%d8%a7-%d8%a7%d9%86%d8%aa%d8%b8%d8%a7%d8%b1-%da%a9%db%8c%d9%88%da%ba%d8%9f-%d8%b4%d8%a7%d9%86%d8%af%d8%a7%d8%b1-%d9%86%d8%aa%da%be%d9%86%da%af/" rel="next"><span class="ast-post-nav" aria-hidden="true">Next <span aria-hidden="true" class="ahfb-svg-iconset ast-inline-flex svg-baseline"><svg xmlns='http://www.w3.org/2000/svg' viewbox='0 0 448 512'><path d='M313.941 216H12c-6.627 0-12 5.373-12 12v56c0 6.627 5.373 12 12 12h301.941v46.059c0 21.382 25.851 32.09 40.971 16.971l86.059-86.059c9.373-9.373 9.373-24.569 0-33.941l-86.059-86.059c-15.119-15.119-40.971-4.411-40.971 16.971V216z'></path></svg></span></span> <p> پرائم ڈے کا انتظار کیوں؟ ‘شاندار’ نتھنگ فون (3) پہلے ہی ایمیزون پر ریکارڈ چھوٹ دیکھ چکا ہے۔ </p></a></div></div> </nav><div class="ast-single-related-posts-container ast-container--"><div class="ast-related-posts-title-section"> <h2 class="ast-related-posts-title"> Related Posts </h2> </div><div class="ast-related-posts-wrapper"> <article class="ast-related-post post-15675 post type-post status-publish format-standard has-post-thumbnail hentry category-blog tag-apple tag-apple-ios tag-apple-ios-10 tag-apple-iphone-ios-10 tag-ios tag-ios-10 tag-ios-10-adoption tag-iphone tag-iphone-ios-10"> <div class="ast-related-posts-inner-section"> <div class="ast-related-post-content"> <div class="ast-related-post-featured-section post-has-thumb"></div> <header class="entry-header related-entry-header"> <h3 class="ast-related-post-title entry-title"> <a href="https://umang.pk/en_us/2016/09/15/apple-ios-10-surpasses-ios-9-in-early-adoption-in-just-24-hours/" target="_self" rel="bookmark noopener noreferrer">Apple iOS 10 surpasses iOS 9 in early adoption in just 24 hours</a> </h3> <div class="entry-meta ast-related-cat-style--none ast-related-tag-style--none"> <span class="comments-link"> <a href="https://umang.pk/en_us/2016/09/15/apple-ios-10-surpasses-ios-9-in-early-adoption-in-just-24-hours/#respond" data-no-translation="" data-trp-gettext="">Leave a Comment</a> </span> / <span class="ast-taxonomy-container cat-links default"><a href="https://umang.pk/en_us/category/blog/" rel="category tag">Blog</a></span> / By <span class="posted-by vcard author" itemtype="https://schema.org/Person" itemscope="itemscope" itemprop="author"> <a title="View all posts by admin" href="https://umang.pk/en_us/author/admin/" rel="author" class="url fn n" itemprop="url" data-no-translation-title="" > <span class="author-name" itemprop="name" > admin </span> </a> </span> </div> </header> <div class="entry-content clear"> </div> </div> </div> </article> <article class="ast-related-post post-1579 post type-post status-publish format-standard hentry category-blog tag-bollywood tag-outsider tag-pannu tag-tap"> <div class="ast-related-posts-inner-section"> <div class="ast-related-post-content"> <div class="ast-related-post-featured-section ast-no-thumb"></div> <header class="entry-header related-entry-header"> <h3 class="ast-related-post-title entry-title"> <a href="https://umang.pk/en_us/2017/03/02/taapsee-pannu-on-being-an-outsider-in-bollywood/" target="_self" rel="bookmark noopener noreferrer">Taapsee Pannu on being an outsider in Bollywood</a> </h3> <div class="entry-meta ast-related-cat-style--none ast-related-tag-style--none"> <span class="comments-link"> <a href="https://umang.pk/en_us/2017/03/02/taapsee-pannu-on-being-an-outsider-in-bollywood/#respond" data-no-translation="" data-trp-gettext="">Leave a Comment</a> </span> / <span class="ast-taxonomy-container cat-links default"><a href="https://umang.pk/en_us/category/blog/" rel="category tag">Blog</a></span> / By <span class="posted-by vcard author" itemtype="https://schema.org/Person" itemscope="itemscope" itemprop="author"> <a title="View all posts by admin" href="https://umang.pk/en_us/author/admin/" rel="author" class="url fn n" itemprop="url" data-no-translation-title="" > <span class="author-name" itemprop="name" > admin </span> </a> </span> </div> </header> <div class="entry-content clear"> </div> </div> </div> </article> </div> </div> </main><!-- #main --> </div><!-- #primary --> </div> <!-- ast-container --> </div><!-- #content --> <footer class="site-footer" id="colophon" itemtype="https://schema.org/WPFooter" itemscope="itemscope" itemid="#colophon"> <div class="site-below-footer-wrap ast-builder-grid-row-container site-footer-focus-item ast-builder-grid-row-full ast-builder-grid-row-tablet-full ast-builder-grid-row-mobile-full ast-footer-row-stack ast-footer-row-tablet-stack ast-footer-row-mobile-stack" data-section="section-below-footer-builder"> <div class="ast-builder-grid-row-container-inner"> <div class="ast-builder-footer-grid-columns site-below-footer-inner-wrap ast-builder-grid-row"> <div class="site-footer-below-section-1 site-footer-section site-footer-section-1"> <div class="ast-builder-layout-element ast-flex site-footer-focus-item ast-footer-copyright" data-section="section-footer-builder"> <div class="ast-footer-copyright"><p>Copyright © 2026 Umang</p> </div> </div> </div> </div> </div> </div> </footer><!-- #colophon --> </div><!-- #page --> <template id="tp-language" data-tp-language="en_US"></template><script type="speculationrules"> {"prefetch":[{"source":"document","where":{"and":[{"href_matches":"/en_us/*"},{"not":{"href_matches":["/wp-*.php","/wp-admin/*","/wp-content/uploads/*","/wp-content/*","/wp-content/plugins/*","/wp-content/themes/astra/*","/en_us/*\\?(.+)"]}},{"not":{"selector_matches":"a[rel~=\"nofollow\"]"}},{"not":{"selector_matches":".no-prefetch, .no-prefetch a"}}]},"eagerness":"conservative"}]} </script> <div id="ast-scroll-top" tabindex="0" class="ast-scroll-top-icon ast-scroll-to-top-right" data-on-devices="both"> <span class="ast-icon icon-arrow"><svg class="ast-arrow-svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" width="26px" height="16.043px" viewbox="57 35.171 26 16.043" enable-background="new 57 35.171 26 16.043" xml:space="preserve"> <path d="M57.5,38.193l12.5,12.5l12.5-12.5l-2.5-2.5l-10,10l-10-10L57.5,38.193z" /> </svg></span> <span class="screen-reader-text" data-no-translation="" data-trp-gettext="">Scroll to Top</span> </div> <script> /(trident|msie)/i.test(navigator.userAgent)&&document.getElementById&&window.addEventListener&&window.addEventListener("hashchange",function(){var t,e=location.hash.substring(1);/^[A-z0-9_-]+$/.test(e)&&(t=document.getElementById(e))&&(/^(?:a|select|input|button|textarea)$/i.test(t.tagName)||(t.tabIndex=-1),t.focus())},!1); </script> <script id="trp-dynamic-translator-js-extra"> var trp_data = {"trp_custom_ajax_url":"https://umang.pk/wp-content/plugins/translatepress-multilingual/includes/trp-ajax.php","trp_wp_ajax_url":"https://umang.pk/wp-admin/admin-ajax.php","trp_language_to_query":"en_US","trp_original_language":"ur","trp_current_language":"en_US","trp_skip_selectors":["[data-no-translation]","[data-no-dynamic-translation]","[data-trp-translate-id-innertext]","script","style","head","trp-span","translate-press","[data-trp-translate-id]","[data-trpgettextoriginal]","[data-trp-post-slug]"],"trp_base_selectors":["data-trp-translate-id","data-trpgettextoriginal","data-trp-post-slug"],"trp_attributes_selectors":{"text":{"accessor":"outertext","attribute":false},"block":{"accessor":"innertext","attribute":false},"image_src":{"selector":"img[src]","accessor":"src","attribute":true},"submit":{"selector":"input[type='submit'],input[type='button'], input[type='reset']","accessor":"value","attribute":true},"placeholder":{"selector":"input[placeholder],textarea[placeholder]","accessor":"placeholder","attribute":true},"title":{"selector":"[title]","accessor":"title","attribute":true},"a_href":{"selector":"a[href]","accessor":"href","attribute":true},"button":{"accessor":"outertext","attribute":false},"option":{"accessor":"innertext","attribute":false},"aria_label":{"selector":"[aria-label]","accessor":"aria-label","attribute":true},"video_src":{"selector":"video[src]","accessor":"src","attribute":true},"video_poster":{"selector":"video[poster]","accessor":"poster","attribute":true},"video_source_src":{"selector":"video source[src]","accessor":"src","attribute":true},"audio_src":{"selector":"audio[src]","accessor":"src","attribute":true},"audio_source_src":{"selector":"audio source[src]","accessor":"src","attribute":true},"picture_image_src":{"selector":"picture image[src]","accessor":"src","attribute":true},"picture_source_srcset":{"selector":"picture source[srcset]","accessor":"srcset","attribute":true}},"trp_attributes_accessors":["outertext","innertext","src","value","placeholder","title","href","aria-label","poster","srcset"],"gettranslationsnonceregular":"4683644d81","showdynamiccontentbeforetranslation":"","skip_strings_from_dynamic_translation":[],"skip_strings_from_dynamic_translation_for_substrings":{"href":["amazon-adsystem","googleads","g.doubleclick"]},"duplicate_detections_allowed":"100","trp_translate_numerals_opt":"no","trp_no_auto_translation_selectors":["[data-no-auto-translation]"]}; //# sourceURL=trp-dynamic-translator-js-extra </script> <script id="trp-dynamic-translator-js" src="https://umang.pk/wp-content/plugins/translatepress-multilingual/assets/js/trp-translate-dom-changes.js?ver=3.2.1"></script> <script id="astra-theme-js-js-extra"> var astra = {"break_point":"921","isRtl":"","is_scroll_to_id":"1","is_scroll_to_top":"1","is_header_footer_builder_active":"1","responsive_cart_click":"flyout","is_dark_palette":""}; //# sourceURL=astra-theme-js-js-extra </script> <script id="astra-theme-js-js" src="https://umang.pk/wp-content/themes/astra/assets/js/minified/frontend.min.js?ver=4.13.4"></script> <script id="wp-emoji-settings" type="application/json"> {"baseUrl":"https://s.w.org/images/core/emoji/17.0.2/72x72/","ext":".png","svgUrl":"https://s.w.org/images/core/emoji/17.0.2/svg/","svgExt":".svg","source":{"concatemoji":"https://umang.pk/wp-includes/js/wp-emoji-release.min.js?ver=7.0"}} </script> <script type="module"> /*! This file is auto-generated */ const a=JSON.parse(document.getElementById("wp-emoji-settings").textContent),o=(window._wpemojiSettings=a,"wpEmojiSettingsSupports"),s=["flag","emoji"];function i(e){try{var t={supportTests:e,timestamp:(new Date).valueOf()};sessionStorage.setItem(o,JSON.stringify(t))}catch(e){}}function c(e,t,n){e.clearRect(0,0,e.canvas.width,e.canvas.height),e.fillText(t,0,0);t=new Uint32Array(e.getImageData(0,0,e.canvas.width,e.canvas.height).data);e.clearRect(0,0,e.canvas.width,e.canvas.height),e.fillText(n,0,0);const a=new Uint32Array(e.getImageData(0,0,e.canvas.width,e.canvas.height).data);return t.every((e,t)=>e===a[t])}function p(e,t){e.clearRect(0,0,e.canvas.width,e.canvas.height),e.fillText(t,0,0);var n=e.getImageData(16,16,1,1);for(let e=0;e<n.data.length;e++)if(0!==n.data[e])return!1;return!0}function u(e,t,n,a){switch(t){case"flag":return n(e,"\ud83c\udff3\ufe0f\u200d\u26a7\ufe0f","\ud83c\udff3\ufe0f\u200b\u26a7\ufe0f")?!1:!n(e,"\ud83c\udde8\ud83c\uddf6","\ud83c\udde8\u200b\ud83c\uddf6")&&!n(e,"\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc65\udb40\udc6e\udb40\udc67\udb40\udc7f","\ud83c\udff4\u200b\udb40\udc67\u200b\udb40\udc62\u200b\udb40\udc65\u200b\udb40\udc6e\u200b\udb40\udc67\u200b\udb40\udc7f");case"emoji":return!a(e,"\ud83e\u1fac8")}return!1}function f(e,t,n,a){let r;const o=(r="undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?new OffscreenCanvas(300,150):document.createElement("canvas")).getContext("2d",{willReadFrequently:!0}),s=(o.textBaseline="top",o.font="600 32px Arial",{});return e.forEach(e=>{s[e]=t(o,e,n,a)}),s}function r(e){var t=document.createElement("script");t.src=e,t.defer=!0,document.head.appendChild(t)}a.supports={everything:!0,everythingExceptFlag:!0},new Promise(t=>{let n=function(){try{var e=JSON.parse(sessionStorage.getItem(o));if("object"==typeof e&&"number"==typeof e.timestamp&&(new Date).valueOf()<e.timestamp+604800&&"object"==typeof e.supportTests)return e.supportTests}catch(e){}return null}();if(!n){if("undefined"!=typeof Worker&&"undefined"!=typeof OffscreenCanvas&&"undefined"!=typeof URL&&URL.createObjectURL&&"undefined"!=typeof Blob)try{var e="postMessage("+f.toString()+"("+[JSON.stringify(s),u.toString(),c.toString(),p.toString()].join(",")+"));",a=new Blob([e],{type:"text/javascript"});const r=new Worker(URL.createObjectURL(a),{name:"wpTestEmojiSupports"});return void(r.onmessage=e=>{i(n=e.data),r.terminate(),t(n)})}catch(e){}i(n=f(s,u,c,p))}t(n)}).then(e=>{for(const n in e)a.supports[n]=e[n],a.supports.everything=a.supports.everything&&a.supports[n],"flag"!==n&&(a.supports.everythingExceptFlag=a.supports.everythingExceptFlag&&a.supports[n]);var t;a.supports.everythingExceptFlag=a.supports.everythingExceptFlag&&!a.supports.flag,a.supports.everything||((t=a.source||{}).concatemoji?r(t.concatemoji):t.wpemoji&&t.twemoji&&(r(t.twemoji),r(t.wpemoji)))}); //# sourceURL=https://umang.pk/wp-includes/js/wp-emoji-loader.min.js </script> <nav class="trp-language-switcher trp-floating-switcher trp-ls-dropdown trp-switcher-position-top trp-opposite-language" style="--bg:#ffffff;--bg-hover:#0000000d;--text:#143852;--text-hover:#1d2327;--border:1px solid #1438521a;--border-radius:0px 0px 8px 8px;--flag-radius:2px;--flag-size:18px;--aspect-ratio:4/3;--font-size:14px;--switcher-width:auto;--switcher-padding:10px 0;--transition-duration:0.2s;--top:0px;--right:10vw" role="navigation" aria-label="Website language selector" data-no-translation > <div class="trp-language-switcher-inner"> <a href="https://umang.pk/ur/2026/06/16/%d9%be%d8%b1%d9%88%da%88%da%a9%d8%b4%d9%86-%d8%b3%db%8c%da%a9%db%8c%d9%88%d8%b1-%d8%a7%db%8c%d8%ac%d9%86%d9%b9-%d9%84%d9%88%d9%be-%da%a9%db%8c%d8%b3%db%92-%d8%a8%d9%86%d8%a7%db%8c%d8%a7-%d8%ac%d8%a7/" class="trp-language-item" title="اردو" data-no-translation><img src="https://umang.pk/wp-content/plugins/translatepress-multilingual/assets/flags/4x3/ur.svg" class="trp-flag-image" alt="" role="presentation" loading="lazy" decoding="async" width="18" height="14" /><span class="trp-language-item-name">اردو</span></a> <div class="trp-switcher-dropdown-list" id="trp-switcher-dropdown-list" role="group" aria-label="Available languages" hidden inert > </div> </div> </nav> </body> </html> <!-- Page cached by LiteSpeed Cache 7.8.1 on 2026-06-16 21:25:29 -->