ایجنٹ نتیجے کی JSON ساخت درست ہو مگر ماخذ کی سمجھ غلط ہو سکتی ہے۔ یہ رہنما Python ڈویلپر کو ایک مجاز یادداشت فائل سے مقامی رجسٹر تک پورا راستہ دیتا ہے: متعین نوعیت کا پیداکار نتیجہ، ماخذ اور معنی کی جانچ، عین ہیش پر انسانی منظوری اور گروہ بند Markdown رپورٹ لکھ کر دوبارہ پڑھنے والا صارف۔ اپنے کام کی صریح ذمہ داریوں والی یادداشتیں استعمال کریں۔ تیاری میں حقیقی یادداشت یا ماڈل نتیجہ استعمال نہیں ہوا۔

بڑی تبدیلی

  • کیا بدلا: OpenAI Agents SDK ایک Pydantic output_type قبول کرتا ہے، اس لیے ایپ متعین نتیجہ مانگ کر استعمال سے پہلے دوبارہ جانچ سکتی ہے۔ مثال نتیجے کے ساتھ ماخذ اقتباسات اور ورژن والا معاہدہ جوڑتی ہے۔
  • یہ کیوں اہم ہے: ایجنٹ کو اگلے مرحلے سے جوڑنے والا ڈویلپر خراب ساخت، نامکمل یا بے بنیاد آؤٹ پٹ کو کارروائی فہرست بننے سے پہلے روک سکتا ہے۔ جائزہ کار کو پھر بھی دیکھنا ہو گا کہ اقتباس واقعی ہر کام، ذمہ دار اور تاریخ کو سہارا دیتا ہے اور ماڈل نے کچھ چھوڑا تو نہیں۔
  • کس پر نظر رکھیں: فیصلہ صارف کی سرحد پر ہے۔ یہ طریقہ عین رن، ماخذ اور امیدوار کی منظوری کے بعد ہی مقامی چھانٹی رجسٹر بناتا ہے۔ بعد میں کاموں کے نظام میں درآمد کو اپنے اختیار، دوبارہ کوشش کے اصول اور منزل پر پڑھ کر تصدیق درکار ہو گی۔

ایک مجاز ماخذ تیار کریں

Python 3.12، یادداشتوں کے لیے مجاز OpenAI API اکاؤنٹ، اصل پڑھ سکنے والا جائزہ کار اور اکاؤنٹ میں موجودہ JSON-schema ساختہ آؤٹ پٹ معاونت کا مصدقہ ماڈل چاہیے۔ پیداکار چلانے سے پہلے ڈیٹا شرائط اور موجودہ قیمت دیکھیں۔ یادداشت یا منظوری فائل میں اسناد نہ رکھیں۔ نیچے ماڈل کی واحد کال produce ہے؛ باقی مقامی عمل ہے۔

اصل یادداشتیں UTF-8 میں notes.txt پر رکھیں۔ ان میں اپنے کام کی حقیقی صریح کارروائی ذمہ داریاں ہونی چاہییں۔ اپنے ریکارڈ شناخت کنندہ جیسا مستقل source_id دیں اور جائزے و استعمال تک فائل کا ہر بائٹ یکساں رکھیں۔ پیدا کرنے سے پہلے candidate/ بنائیں؛ امیدوار فائل نئی ہونی چاہیے۔ بعد کی مقامی رپورٹ کے لیے الگ آؤٹ پٹ ڈائریکٹری رکھیں۔

رن سے پہلے ماخذ بائٹس کا ہیش درج کریں:

Terminal
python -c "from pathlib import Path; import hashlib; print(hashlib.sha256(Path('notes.txt').read_bytes()).hexdigest())"

الگ Python 3.12 ماحول میں recipe-requirements.txt بنا کر عین یہ سطریں ڈالیں اور نصب کریں:

Text
openai-agents==0.24.0
pydantic==2.14.1
Terminal
python -m pip install -r recipe-requirements.txt
mkdir candidate

یہ ورژن 20 اکتوبر 2026 کو مقامی Python 3.12.7 ماحول میں ساتھ نصب ہوئے تھے۔ استعمال پر مطابقت اور ماڈل دستیابی کی تصدیق کریں۔ نیچے مکمل سکرپٹ action_register_recipe.py کے نام سے اسی ڈائریکٹری میں رکھیں۔ دو کمانڈ ہیں: produce امیدوار اور رن رسید بناتا ہے؛ consume توثیق اور منظوری کے بعد ہی رپورٹ بناتا ہے۔

متعین نوعیت کا پیداکار چلائیں

معاہدہ Extraction ورژن action-register/v1، حالت ready، partial یا blocked، ماخذ ID اور عین فائل بائٹس کا SHA-256، کارروائیاں اور gap_note مانگتا ہے۔ ہر کارروائی میں متن، عین اقتباس اور 1 سے شروع ماخذ سطروں کی حد، null ہو سکنے والا ذمہ دار و تاریخ، اور complete یا needs_review ثبوت کی حالت چاہیے۔ null ذمہ دار یا تاریخ کا مطلب یادداشت میں ذکر نہیں۔ ماڈل کو دونوں کا قیاس نہ کرنے کی ہدایت ہے۔ ہر خانہ لازم ہے اور اضافی رد ہوتے ہیں۔

ساختہ آؤٹ پٹ ماڈل صاف چنیں۔ اپنا مجاز راستہ اور شناخت دیں:

Terminal
python action_register_recipe.py produce --source-id OWNED-ID --source notes.txt --candidate candidate/actions.json --model YOUR-STRUCTURED-OUTPUT-MODEL

یہ پڑھیں: candidate/actions.json اور ساتھ candidate/actions.run.json۔ دوسری فائل UUID رن ID، ماخذ و امیدوار ہیش، آخری ایجنٹ اور مطلوبہ ماڈل درج کرتی ہے۔ ناکامی پر اس کے بجائے رن ID لاحقے والا .failure.json تشخیصی ریکارڈ بنتا ہے۔ رکاوٹ، None یا سادہ سٹرنگ آخری آؤٹ پٹ، یا غیر متوقع آخری ایجنٹ کامیابی نہیں ہیں۔ کمانڈ SDK کی دوبارہ جاری ہو سکنے والی حالت RunState نہیں رکھتا؛ ناکامی رسید سے رن جاری نہیں ہو سکتا۔ نیا رن مناسب ہے یا نہیں طے کرنے سے پہلے درخواست، امیدوار اور بعد کی حالت دیکھیں۔

معنی جانچ کر عین امیدوار منظور کریں

ایپ سخت اقسام اور لازم خانے، ماخذ شناخت، تیار حالت، کم از کم ایک مکمل کارروائی، جائز سطر حدود، ان میں اقتباس، غیر خالی کام یا ذمہ دار اور معیاری YYYY-MM-DD تاریخیں جانچتی ہے۔ یہ ساخت اور اقتباس کا مقام ثابت کرتا ہے، نہ کہ جملہ واقعی ذمہ داری ہے، نام یا تاریخ وہی معنی رکھتے ہیں یا سب ذمہ داریاں مل گئیں۔

اصل یادداشت اور ہر مجوزہ کارروائی پڑھیں۔ معنی، ذمہ دار، تاریخ، اقتباس اور کمی ملائیں۔ ابہام نئے جائزہ شدہ رن سے حل کریں؛ بے بنیاد، جزوی یا رکے امیدوار منظور نہ کریں۔ غیر بدلی فائل اور امیدوار کا actions.run.json سے میل دیکھ کر approval.json عین ان سات کلیدوں سے لکھیں۔ جانچی رسید سے رن ID اور ہیش لیں۔ جائزہ کار کی حقیقی شناخت اور اصل جانچ کا بامعنی بیان دیں:

JSON
{
  "approved": true,
  "run_id": "COPY-RUN-ID",
  "source_id": "OWNED-ID",
  "source_sha256": "COPY-SOURCE-SHA256",
  "payload_sha256": "COPY-PAYLOAD-SHA256",
  "reviewer": "YOUR-REVIEWER-ID",
  "review_note": "Describe the source, task, owner, date, quotation and omission checks actually performed."
}

approved JSON بولین true ہونا چاہیے، متن یا نمبر نہیں۔ باقی قدریں سٹرنگ ہوں؛ جائزہ کار اور نوٹ خالی نہیں ہو سکتے۔ اضافی خانے ناکام ہوتے ہیں۔ منظوری ایک امیدوار اور ماخذ ترمیم کو باندھتی ہے، مستقبل کی ہر بازنویسی کو نہیں۔

استعمال کر کے رپورٹ دوبارہ پڑھیں

Terminal
python action_register_recipe.py consume --source-id OWNED-ID --source notes.txt --candidate candidate/actions.json --approval approval.json --out private-output

صارف قبول کارروائیوں کو Assigned with dates، Needs an owner اور Needs a date میں بانٹتا ہے۔ ہر اندراج میں کام، ذمہ دار/تاریخ حالت، اقتباس اور ماخذ سطریں ہیں۔ یہ action-register-<payload-hash-prefix>.md اور ساتھ .receipt.json لکھتا ہے، جن میں رن، ماخذ، امیدوار و رپورٹ کے ہیش ہیں۔ دونوں کھولیں، اقتباس شدہ کارروائیاں یادداشت سے ملائیں اور report_sha256 کو Markdown بائٹس کے خلاف جانچیں۔ درست رسید صرف مقامی فائل بننے اور دوبارہ پڑھنے کو بتاتی ہے، بیرونی کاموں کے نظام میں لکھنے کی منظوری نہیں۔

استعمال کا کمانڈ رپورٹ اور رسید کے حقیقی راستے دکھاتا ہے۔ بائٹ جانچ میں وہی استعمال کریں:

Terminal
python -c "from pathlib import Path; import hashlib,json,sys; report=Path(sys.argv[1]); receipt=json.loads(Path(sys.argv[2]).read_text(encoding='utf-8')); assert hashlib.sha256(report.read_bytes()).hexdigest()==receipt['report_sha256']; print('report hash matches receipt')" PATH-PRINTED-FOR-REPORT PATH-PRINTED-FOR-RECEIPT

امیدوار کے بعد واضح مصنوعی ساختی نمونے سے رد کی راہ جانچیں۔ JSON الگ فائل میں نقل کریں، پہلی کارروائی سے کوئی لازم خانہ ہٹائیں اور consume کو اس خراب فائل اور نئی خالی آؤٹ پٹ ڈائریکٹری کے ساتھ چلائیں۔ فائل بنانے سے پہلے ناکام ہونا چاہیے۔ نمونے کو حقیقی استخراج نہ سمجھیں اور منظور نہ کریں۔ مثلاً نیچے مقامی جانچ نقل سے evidence_quote ہٹاتی ہے:

Terminal
python -c "import json; from pathlib import Path; p=json.loads(Path('candidate/actions.json').read_text(encoding='utf-8')); p['actions'][0].pop('evidence_quote'); Path('candidate/SYNTHETIC-malformed.json').write_text(json.dumps(p), encoding='utf-8')"
python action_register_recipe.py consume --source-id OWNED-ID --source notes.txt --candidate candidate/SYNTHETIC-malformed.json --approval approval.json --out synthetic-rejection-output

دوسرا کمانڈ ناکام اور آؤٹ پٹ ڈائریکٹری غیر موجود رہنی چاہیے۔ حقیقی امیدوار کی پہلی کارروائی نہ ہو تو نمونہ استعمال نہ کریں؛ وہ پہلے ہی صارف کے لیے نامکمل ہے۔ لکھائی غیر یقینی ہو تو تکرار سے پہلے متعین رپورٹ اور رسید دیکھیں۔ موجودہ یکساں بائٹس پھر استعمال ہو سکتے ہیں؛ مختلف بائٹس عمل ملاپ کے لیے روکتے ہیں۔ ماخذ یا سکیما ورژن بدلنے پر نیا جائزہ چاہیے۔ صرف مقامی صارف کا جواب غیر واضح ہونے پر ماڈل کال نہ دہرائیں۔

مکمل Python طریقہ

یہ سکرپٹ بعینہٖ action_register_recipe.py میں نقل کریں:

Python
"""Private, bounded recipe. No model call occurs unless `produce` is explicitly run."""

import argparse
import hashlib
import json
import uuid
from datetime import date
from pathlib import Path
from typing import Literal

from pydantic import BaseModel, ConfigDict, StrictInt, StrictStr, ValidationError


class StrictModel(BaseModel):
    model_config = ConfigDict(extra="forbid", strict=True)


class Action(StrictModel):
    action_text: StrictStr
    evidence_quote: StrictStr
    line_start: StrictInt
    line_end: StrictInt
    owner: StrictStr | None
    due_date: StrictStr | None
    evidence_status: Literal["complete", "needs_review"]


class Extraction(StrictModel):
    schema_version: Literal["action-register/v1"]
    status: Literal["ready", "partial", "blocked"]
    source_id: StrictStr
    source_sha256: StrictStr
    actions: list[Action]
    gap_note: StrictStr | None


def digest(data: bytes) -> str:
    return hashlib.sha256(data).hexdigest()


def canonical(payload: Extraction) -> bytes:
    return json.dumps(payload.model_dump(mode="json"), sort_keys=True, ensure_ascii=False, separators=(",", ":")).encode("utf-8")


def check(payload: Extraction, source_id: str, source: bytes) -> None:
    if payload.source_id != source_id or payload.source_sha256 != digest(source):
        raise ValueError("source identity or revision mismatch")
    lines = source.decode("utf-8").splitlines()
    if payload.status == "ready" and (not payload.actions or payload.gap_note is not None):
        raise ValueError("ready requires actions and no gap")
    if payload.status != "ready":
        raise ValueError("partial or blocked result cannot reach consumer")
    for index, item in enumerate(payload.actions, 1):
        if item.evidence_status != "complete":
            raise ValueError(f"action {index}: evidence needs review")
        if not item.action_text.strip() or not item.evidence_quote.strip():
            raise ValueError(f"action {index}: empty task or evidence")
        if not 1 <= item.line_start <= item.line_end <= len(lines):
            raise ValueError(f"action {index}: invalid source line range")
        segment = "\n".join(lines[item.line_start - 1:item.line_end])
        if item.evidence_quote not in segment:
            raise ValueError(f"action {index}: quotation absent from source span")
        if item.owner is not None and not item.owner.strip():
            raise ValueError(f"action {index}: blank owner")
        if item.due_date is not None:
            try:
                if date.fromisoformat(item.due_date).isoformat() != item.due_date:
                    raise ValueError()
            except ValueError as exc:
                raise ValueError(f"action {index}: due date must be YYYY-MM-DD") from exc


def report(payload: Extraction) -> str:
    """Application consumer: a triage register grouped by missing ownership/date."""
    groups = [
        ("Assigned with dates", lambda x: x.owner is not None and x.due_date is not None),
        ("Needs an owner", lambda x: x.owner is None),
        ("Needs a date", lambda x: x.owner is not None and x.due_date is None),
    ]
    rows = ["# Action register for " + payload.source_id, "", "Review artifact; source meaning was approved separately.", ""]
    for heading, predicate in groups:
        rows += ["## " + heading, ""]
        matches = [(n, a) for n, a in enumerate(payload.actions, 1) if predicate(a)]
        for number, action in matches:
            rows += [f"{number}. {action.action_text}", f"   Owner: {action.owner or 'Unspecified'}; due: {action.due_date or 'Unspecified'}", f"   Source lines {action.line_start}-{action.line_end}: {action.evidence_quote}", ""]
        if not matches:
            rows += ["None.", ""]
    return "\n".join(rows)


def load_payload(path: Path) -> Extraction:
    return Extraction.model_validate_json(path.read_bytes(), strict=True)


def consume(source_id: str, source_path: Path, payload_path: Path, approval_path: Path, out_dir: Path) -> tuple[Path, Path]:
    source = source_path.read_bytes()
    payload = load_payload(payload_path)
    check(payload, source_id, source)
    run = json.loads(payload_path.with_suffix(".run.json").read_text(encoding="utf-8"))
    payload_hash = digest(canonical(payload))
    if run.get("source_id") != source_id or run.get("source_sha256") != digest(source) or run.get("payload_sha256") != payload_hash or run.get("last_agent") != "Owned-source action extractor" or not str(run.get("run_id", "")).strip():
        raise ValueError("producer receipt does not match accepted candidate")
    approval = json.loads(approval_path.read_text(encoding="utf-8"))
    if (type(approval) is not dict
            or set(approval) != {"approved", "run_id", "source_id", "source_sha256", "payload_sha256", "reviewer", "review_note"}
            or approval["approved"] is not True
            or any(type(approval[key]) is not str for key in ("run_id", "source_id", "source_sha256", "payload_sha256", "reviewer", "review_note"))
            or not approval["reviewer"].strip() or not approval["review_note"].strip()
            or approval["run_id"] != run["run_id"]
            or approval["source_id"] != source_id
            or approval["source_sha256"] != digest(source)
            or approval["payload_sha256"] != payload_hash):
        raise ValueError("human source/meaning approval must bind exact source and payload hashes")
    body = report(payload).encode("utf-8")
    stem = "action-register-" + payload_hash[:16]
    out_dir.mkdir(parents=True, exist_ok=True)
    target = out_dir / (stem + ".md")
    receipt = out_dir / (stem + ".receipt.json")
    record = {"run_id": run["run_id"], "source_id": source_id, "source_sha256": digest(source), "payload_sha256": payload_hash, "report_sha256": digest(body), "reviewer": approval["reviewer"], "operation": "local action-triage register"}
    encoded = (json.dumps(record, indent=2) + "\n").encode("utf-8")
    for path, data in [(target, body), (receipt, encoded)]:
        if path.exists():
            if path.read_bytes() != data:
                raise ValueError(f"uncertain prior output differs: {path}; inspect before retry")
        else:
            with path.open("xb") as handle:
                handle.write(data)
        if path.read_bytes() != data:
            raise IOError(f"readback failed: {path}")
    return target, receipt


def produce(source_id: str, source_path: Path, candidate_path: Path, model: str) -> None:
    from agents import Agent, Runner

    source = source_path.read_bytes()
    source_text = source.decode("utf-8")
    if not source_text.strip() or candidate_path.exists() or not candidate_path.parent.is_dir():
        raise ValueError("source must contain text; candidate must be new and its parent directory must already exist")
    run_id = str(uuid.uuid4())
    agent = Agent(
        name="Owned-source action extractor",
        model=model,
        instructions=("Extract only explicit action commitments from the supplied numbered source. "
                      "Return action-register/v1. Copy an exact quote with matching 1-based line span. "
                      "Use null for an unstated owner or due date; never infer them. "
                      "Use partial and needs_review for ambiguous evidence; blocked for unusable input. "
                      "Do not use tools or hand off."),
        output_type=Extraction,
    )
    numbered = "\n".join(f"{n}: {line}" for n, line in enumerate(source_text.splitlines(), 1))
    try:
        result = Runner.run_sync(agent, f"Source ID: {source_id}\nSHA-256: {digest(source)}\nNumbered source:\n{numbered}")
        if result.interruptions or result.last_agent is not agent or not isinstance(result.final_output, Extraction):
            raise ValueError("run interrupted, unfinished, or finished by unexpected agent; this CLI does not persist resumable RunState, so do not resume from its failure receipt")
        output = result.final_output
        if output.source_id != source_id or output.source_sha256 != digest(source):
            raise ValueError("producer returned wrong source identity")
        candidate = canonical(output)
        with candidate_path.open("xb") as handle:
            handle.write(candidate)  # Candidate only; consumer still requires review.
        receipt = {"run_id": run_id, "source_id": source_id, "source_sha256": digest(source), "payload_sha256": digest(candidate), "last_agent": result.last_agent.name, "model": model}
        with candidate_path.with_suffix(".run.json").open("x", encoding="utf-8") as handle:
            handle.write(json.dumps(receipt, indent=2) + "\n")
    except Exception as exc:
        failure = {"run_id": run_id, "source_id": source_id, "source_sha256": digest(source), "error_type": type(exc).__name__, "error": str(exc), "state": "unknown_or_blocked; inspect run and destination before retry"}
        with candidate_path.with_name(candidate_path.stem + "." + run_id + ".failure.json").open("x", encoding="utf-8") as handle:
            handle.write(json.dumps(failure, indent=2) + "\n")
        raise


def main() -> None:
    parser = argparse.ArgumentParser()
    sub = parser.add_subparsers(dest="command", required=True)
    for name in ("produce", "consume"):
        p = sub.add_parser(name)
        p.add_argument("--source-id", required=True)
        p.add_argument("--source", type=Path, required=True)
        if name == "produce":
            p.add_argument("--candidate", type=Path, required=True)
            p.add_argument("--model", required=True)
        else:
            p.add_argument("--candidate", type=Path, required=True)
            p.add_argument("--approval", type=Path, required=True)
            p.add_argument("--out", type=Path, required=True)
    args = parser.parse_args()
    if args.command == "produce":
        produce(args.source_id, args.source, args.candidate, args.model)
    else:
        print(*consume(args.source_id, args.source, args.candidate, args.approval, args.out), sep="\n")


if __name__ == "__main__":
    main()

حدیں اور ماخذ

سکرپٹ معاہدہ اور مقامی صارف پانچ آف لائن ٹیسٹ اور سات مصنوعی پیداکار یا دوبارہ کوشش کے واقعات سے جانچے گئے۔ سخت سکیما بنانا، فائل سے پہلے رد، گروہ بندی، ہیش اور ناکامی سنبھالنا آزمائے گئے۔ فراہم کنندہ کو سکیما نہیں بھیجا، ماڈل کال نہیں ہوئی، حقیقی یادداشتیں نہیں نکالی گئیں، حقیقی انسانی منظوری نہیں لی گئی، حقیقی ماخذ رپورٹ نہیں بنی اور بل یا معیار نہیں ناپا گیا۔ API فیس اکاؤنٹ کے مطابق ہے؛ ماخذ بھیجنے سے پہلے مطابقت، قیمت اور ڈیٹا اجازت دیکھیں۔

متعلقہ سیاق کے لیے BIG CHANGE کا اپنے کام سے AI کام چننے کا رہنما پہلے فیصلہ بتاتا ہے کہ کیا آزمانا ہے۔ یہ رہنما منتخب مجاز استخراج سے شروع ہو کر متعین نوعیت کا ایک نتیجہ جانچے مقامی صارف کو دیتا ہے۔

ماخذ اور مزید مطالعہ

  • OpenAI Agents SDK: Agents Pydantic کے output_type کو بیان کرتا ہے۔ اس طریقے کی انسانی منظوری یا مقامی صارف نہیں دیتا۔
  • OpenAI Agents SDK: Results ان کو بیان کرتا ہے: final_output، last_agent، رکاوٹیں اور to_state()۔ یہ CLI دوبارہ جاری کرنے کی حالت نہیں رکھتا۔
  • OpenAI Agents SDK: Quickstart تنصیب اور API کی ترتیب بتاتا ہے۔ کلید ماخذ اور رسید سے باہر رکھیں۔
  • OpenAI Structured Outputs سخت سکیما اصول اور ماڈل معاونت بتاتا ہے۔ منتخب ماڈل کی معاونت پکی کریں۔
  • Pydantic ConfigDict سخت توثیق اور اضافی خانوں کی ممانعت بیان کرتا ہے۔
  • OpenAI Agents SDK 0.24.0 اور Pydantic 2.14.1 مقامی نصب شدہ مقید ورژن بتاتے ہیں۔ فراہم کنندہ کی قبولیت جانچی نہیں گئی۔