अनाथ agent subprocesses credentials को चालू रख सकती हैं
टाइमआउट के बाद अनाथ agent subprocesses credentials और connections को चालू रख सकती हैं। Process-group cleanup, run-state revocation और audit methods के बारे में जानें।

टाइमआउट हुआ AI एजेंट जरूरी नहीं कि रुक गया हो। अगर टाइमआउट शुरू होने से पहले उसके shell wrapper, compiler, HTTP helper या SSH command ने कोई child process बना दी, तो वह parent PID खत्म होने के बाद भी चल सकती है। अगर उसे इस्तेमाल करने लायक credential या पहले से authenticated connection मिला हुआ था, तो टाइमआउट ने उस अधिकार को खत्म नहीं किया जिसे आप रद्द समझ रहे थे।
मैंने ऐसी incident notes देखी हैं जो «एजेंट को 14:03 पर खत्म कर दिया गया» से शुरू होती हैं और 14:11 पर हुई API call पर खत्म होती हैं। आमतौर पर किसी ने कोई चतुर exploit नहीं खोजा था। रनर ने एक process खत्म की, जबकि उपयोगी काम पहले ही दूसरी process में जा चुका था। जब तक कोई autonomous agent production credentials इस्तेमाल न कर सके, process cleanup मामूली सिस्टम काम लगता है। उसके बाद यही काम security boundary का हिस्सा बन जाता है।
पैरेंट की मौत से काम खत्म नहीं होता
कोई child process अपने parent से ज्यादा समय तक चल सकती है, क्योंकि kernel processes को स्वतंत्र रूप से ट्रैक करता है, उन्हें shell command के अस्थायी विस्तार के रूप में नहीं। जब parent बाहर निकलता है, तो operating system उसकी children को किसी system reaper या supervisor से जोड़ देता है। child का अपना PID, memory, file descriptors, sockets, current directory और अक्सर अपना environment बना रहता है।
यह व्यवहार वैध है। Build systems इसका इस्तेमाल करते हैं। Terminal multiplexers भी। Service managers इस पर निर्भर करते हैं। गलती तब होती है जब agent run की execution boundary के रूप में parent PID को मान लिया जाता है।
एक आम chain देखें:
agent-runner (PID 4102)
shell tool wrapper (PID 4131)
deployment script (PID 4140)
ssh helper (PID 4144)
रनर अपनी deadline पर पहुंचकर PID 4102 को signal भेजता है। अगर shell या deployment script उसके साथ बाहर नहीं निकली, तो बाकी chain चलती रह सकती है। ज्यादा पेचीदा स्थिति तब आती है जब script & के साथ background job शुरू करती है, nohup इस्तेमाल करती है, किसी service manager को call करती है या remote host से काम शुरू करने को कहती है। Parent ठीक से खत्म हो सकता है, जबकि child पहले ही अपने लिए स्वतंत्र रास्ता बना चुकी हो।
इसीलिए orphaned agent subprocess केवल बची हुई CPU खपत नहीं है। वह उस फैसले का बिना निगरानी जारी रहना है जिसे किसी इंसान या scheduler ने खत्म मान लिया था। नुकसान इस बात पर निर्भर करता है कि process अब भी किस चीज तक पहुंच सकती है, लेकिन विफलता इससे पहले शुरू हो जाती है: runner ने रोकने के लिए गलत इकाई चुनी।
POSIX अपने process और job-control interfaces में इस व्यवहार के पीछे के आधार बताता है। Process group संबंधित processes का ऐसा समूह है जिसका एक process-group ID होता है। Signal एक सदस्य के बजाय पूरे group को भेजे जा सकते हैं। Session में एक या अधिक process groups होते हैं और आमतौर पर उसका controlling terminal से संबंध होता है। ये kernel की अलग-अलग अवधारणाएं हैं। इनके नामों को एक-दूसरे का पर्याय मानने से cleanup code कमजोर बनता है।
टाइमआउट को containment unit खत्म करनी चाहिए
टाइमआउट तभी सुरक्षित है जब agent शुरू होने से पहले कोई containment unit तय की गई हो। Local command tree के लिए यह आमतौर पर dedicated process group होता है। Runner तुरंत group ID दर्ज करता है और deadline खत्म होने पर उसी group को signal भेजता है।
क्रम मायने रखता है। Children खोजने के लिए cleanup तक इंतजार न करें। तब तक मूल parent खत्म हो चुका हो सकता है, PPID संबंध भ्रामक हो सकता है और कोई दूसरा run शुरू हो चुका हो सकता है।
एक व्यावहारिक timeout path में पांच काम होते हैं:
- Agent शुरू करने से पहले dedicated group या supervisor के नियंत्रण वाला job बनाएं।
- Run ID, PID, PGID, start time, command और deadline को एक ही record में दर्ज करें।
- Timeout पर signal भेजने से पहले run को expired चिह्नित करें, ताकि नई actions को स्वीकृत काम न समझ लिया जाए।
- दर्ज की गई containment unit को
TERMभेजें, थोड़ी तय grace period तक प्रतीक्षा करें, फिर केवल बची हुई processes कोKILLभेजें। - परिणाम का snapshot लें और signal times, exit state तथा बची हुई PIDs सुरक्षित रखें।
Record पहले इसलिए आता है क्योंकि तेज process exit और cleanup के बीच race हो सकती है। अगर आपके log में केवल «killed agent» लिखा है, तो वह यह नहीं बता सकता कि आपने कौन-सी process खत्म की, कौन-सी children उसके group में थीं या signal भेजे जाने से पहले कोई child बाहर निकल गई थी।
macOS पर process tree display पर भरोसा करने के बजाय identifiers देखें। यह command उन fields को दिखाती है जो अधिकतर timeout failures समझाने के लिए काफी होती हैं:
ps -axo pid,ppid,pgid,sid,lstart,etime,command
Cleanup से पहले किसी expired run का output इस तरह दिख सकता है:
PID PPID PGID SID STARTED ELAPSED COMMAND
4102 3988 4102 4102 Thu Jul 24 14:00:02 2026 00:31 agent-runner ...
4131 4102 4102 4102 Thu Jul 24 14:00:02 2026 00:31 /bin/sh -c ...
4144 4131 4102 4102 Thu Jul 24 14:00:04 2026 00:29 ssh ...
ये values केवल उदाहरण हैं, इन्हें hard-code करने का pattern न मानें। उपयोगी बात यह है कि run का PGID 4102 के रूप में ज्ञात है। Cleanup केवल PID 4102 को नहीं, उस पूरे group को signal भेजता है। kill को negative target देने पर वह process group को signal भेजता है:
kill -TERM -4102
आप जिस language runtime और operating system का इस्तेमाल करते हैं, उनके लिए syntax की पुष्टि करें। कुछ wrappers negative numbers को ठीक से parse नहीं करते या अतिरिक्त argument को command option समझ लेते हैं। जिस command line को आपने वास्तविक timeout के दौरान चलाकर नहीं देखा, उसके आधार पर security boundary न बनाएं।
Group signal की भी सीमा होती है। कोई child setsid call कर सकती है, नया process group बना सकती है, काम किसी दूसरी service को सौंप सकती है या remote machine पर process शुरू कर सकती है। Group discipline सामान्य local escape को रोकता है, हर संभावित escape को नहीं। Runner को इन transitions को अलग cancellation और audit व्यवस्था वाले स्पष्ट handoff के रूप में संभालना चाहिए।
Process groups, sessions और credentials अलग समस्याएं हल करते हैं
Process group आपको local signal target देता है। Session एक व्यापक boundary दे सकता है और terminal job control को अलग कर सकता है। इनमें से कोई भी ऐसी credential को रद्द नहीं करता जिसे process ने memory में कॉपी कर लिया हो या disk पर लिख दिया हो। ये अलग controls हैं और इनके लिए अलग evidence चाहिए।
यह फर्क अक्सर धुंधला हो जाता है, क्योंकि failure एक ही घटना जैसा दिखता है: agent timeout होता है और बाद में कोई call सफल हो जाती है। Cleanup layer पूछती है, «कौन-सी local processes रुकनी चाहिए?» Credential handling पूछता है, «कौन-सी process अब भी इस बाहरी action को authorize कर सकती है?» Audit पूछता है, «क्या हम साबित कर सकते हैं कि approval खत्म होने के बाद कौन-सी action हुई?» Process group केवल पहले सवाल का जवाब देता है।
Environment variables गलत handoff का सबसे आम उदाहरण हैं। अगर runner API_TOKEN export करता है, तो हर descendant को वह मिल जाता है, जब तक बाद की कोई process environment को साफ न कर दे। कोई child token को कॉपी कर सकती है, किसी दूसरी program को दे सकती है या authenticated connection खुला रख सकती है। Parent शुरू होने के बाद environment variable बदलने से पहले से inherit हुए bytes वापस नहीं आते।
Files और sockets भी उतने ही महत्वपूर्ण हैं। कोई process ऐसा open file descriptor inherit कर सकती है जो credential file, session state वाले connected HTTPS socket या SSH agent socket की ओर इशारा करता हो। Parent के बाहर निकलने के बाद भी background process उस descriptor का इस्तेमाल कर सकती है। close-on-exec नए exec के दौरान accidental inheritance रोकने में मदद करता है, लेकिन जब child के पास descriptor पहले से हो या program जानबूझकर उसे आगे भेजे, तब यह कुछ नहीं करता।
SSH में खास सावधानी चाहिए। Local helper में लोड की गई private key, SSH agent socket, multiplexed control connection और remote command, ये चार अलग-अलग lifetimes हैं। Local parent को खत्म करने से मौजूदा connection या remote command चलती रह सकती है। अगर agent arbitrary SSH चला सकता है, तो runner को यह पता होना चाहिए कि उसने local helper invocation, authenticated channel या remote job में से किसे authorize किया था। इन तीनों को «SSH command» कहना उस boundary को छिपा देता है जिसे आपको नियंत्रित करना है।
ज्यादा सुरक्षित तरीका raw secret देने के बजाय action request भेजता है। Process किसी authority component से खास HTTP request या SSH operation करने को कहती है। वह component secret अपने पास रखता है, तय करता है कि मौजूदा run उसे इस्तेमाल कर सकता है या नहीं, action करता है और result लौटाता है। Escaped child तब भी requests दोहरा सकती है जब तक उसका run authorized है, इसलिए authority component को expiry और revocation भी समझनी चाहिए।
Sallyport अपने supported HTTP और SSH channels में यही separation अपनाता है: agent अपने MCP shim के जरिए अनुरोध करता है, जबकि app API या SSH material अपने पास रखकर action को खुद पूरा करता है, secret agent process में नहीं भेजता। इससे process cleanup की जरूरत खत्म नहीं होती, लेकिन credential inheritance का सबसे आसान रास्ता बंद हो जाता है।
Backgrounding escape hatch है, harmless shell detail नहीं
Cleanup की सबसे आम failure shell की सुविधा से शुरू होती है। कोई command & लिखता है, pipe शुरू करता है, nohup इस्तेमाल करता है या ऐसा language runtime चलाता है जो workers बनाता है। Parent command खत्म दिखती है या timeout हो जाती है, और worker चलती रहती है।
Shell pipeline पर खास ध्यान दें। Runner /bin/sh -c 'generator | uploader' चला सकता है और shell PID दर्ज कर सकता है। Pipeline के दोनों हिस्सों के लिए shell की child processes होती हैं। Runner ने group कैसे बनाया है, उसके आधार पर केवल shell को खत्म करने से generator या uploader चलते रह सकते हैं। अगर uploader के पास credential और network connection है, तो वही वह process है जिसे आपको रोकना था।
nohup जितना लोग मानते हैं, उससे ज्यादा खतरनाक है। यह process को hangup signal मिलने से रोकता है, process को trustworthy नहीं बनाता और runner को इसकी जानकारी नहीं देता। Automation में इसका मतलब आमतौर पर है कि कोई काम terminal या parent exit के बाद भी जारी रखना चाहता है। Managed service के लिए यह सही हो सकता है, लेकिन तब काम ऐसे supervisor के पास जाना चाहिए जो job का मालिक हो और उसका lifecycle दर्ज करे। यह किसी agent tool call के अंदर गलती से नहीं रहना चाहिए।
Detached children एक अलग तरह की समस्या पैदा करती हैं। Node.js में spawn के साथ detached: true Unix-जैसे systems पर child को जानबूझकर नया process group और session देता है। Desktop application को अपने launcher के बाद भी चलाना हो तो यह उपयोगी हो सकता है। Agent executor के अंदर यह खराब default है, क्योंकि इससे executor का सामान्य group kill बेअसर हो जाता है।
import { spawn } from "node:child_process";
const child = spawn("/bin/sh", ["-c", "sleep 600"], {
detached: true,
stdio: "ignore"
});
child.unref();
यह snippet cleanup test case है, agent runner में कॉपी करने लायक execution pattern नहीं। इससे ऐसी child बनती है जो parent के सामान्य process group में नहीं रहती। अगर कोई tool framework इस तरह का code चला सकता है, तो केवल process-group cleanup पूरी guarantee नहीं दे सकता। Detached execution को सीमित करें, tool boundary पर इसे रोकें या tool को मजबूत operating-system containment में चलाएं।
«बस process tree को kill कर दें» वाली लोकप्रिय सलाह भी तब विफल होती है जब उसका मतलब PPID को बार-बार देखकर tree बनाना हो। PPID किसी क्षण की स्थिति बताता है, स्थायी membership boundary नहीं। Reparenting उसे बदल देती है। आपके walk और signal के बीच कोई child fork कर सकती है। कोई descendant tree से बाहर जा सकता है। Launch के समय group या job identity दर्ज करें और उस identity से बाहर निकलने को जानबूझकर किया गया, audit योग्य operation बनाएं।
Command name से cleanup न करें
pkill और broad name matching आकर्षक लगते हैं, क्योंकि वे छोटे होते हैं। Concurrent agent runs के लिए वे खराब विकल्प हैं। pkill ssh कोई असंबंधित interactive connection खत्म कर सकता है। pkill python किसी developer का local tool बंद कर सकता है। Argument string से matching ऐसी process को छोड़ सकती है जिसने अपने arguments बदल लिए हों या दूसरे run में false match कर सकती है।
Command name को केवल जांच के संकेत के रूप में इस्तेमाल करें। Enforcement के लिए ownership boundary इस्तेमाल करें।
जिस runner को process group पता है, वह पहले उसके members देख सकता है। macOS पर दर्ज किए गए number से process table filter करें, अनुमानित executable name से नहीं:
ps -axo pid,ppid,pgid,sid,etime,command | awk '$3 == 4102 || NR == 1'
इस command layout में पहला column PID, दूसरा PPID और तीसरा PGID है। Production code में human-oriented text parse करने से बचें, जब आपकी language native process APIs call कर सकती हो। Operator terminal के लिए यह output signal चुनने से पहले तेज और साफ जांच देता है।
फिर group को signal भेजें और दोबारा जांचें:
kill -TERM -4102
sleep 2
ps -axo pid,ppid,pgid,sid,etime,command | awk '$3 == 4102 || NR == 1'
अगर members बचे रहें, तो तुरंत KILL भेजने से पहले कारण समझें। Uninterruptible kernel work में अटकी process की जांच उस process से अलग होगी जिसने TERM को नजरअंदाज किया। अलग PGID वाली process आपके signal से संयोगवश नहीं बची, वह boundary पार कर चुकी है। यह किसी design decision, framework behavior या malicious tool का evidence है।
तय grace period के बाद, दर्ज किए गए group में बची local processes को KILL भेजना उचित है, अगर उन्हें खत्म होना चाहिए और उन्हें जारी नहीं रहना चाहिए। Agent के authority window से आगे निकल जाने पर graceful cleanup का वादा न करें। Grace का उद्देश्य files बंद करना और status दर्ज करना है, बाहरी काम को अनिश्चित समय तक जारी रखना नहीं।
जब execution environment आपके नियंत्रण में हो, तो containers और service managers raw process group से बेहतर ownership दे सकते हैं। macOS desktop agent workflows को अपने आप Linux cgroups नहीं मिलते, इसलिए cgroup की सलाह को बिना बदलाव के लागू न मानें। Mac पर dedicated child process group, सीमित tool permissions और स्पष्ट remote-job contract अक्सर baseline होते हैं। Resource ceilings या descendants का पूरा containment चाहिए, तो ऐसा execution environment इस्तेमाल करें जो वास्तव में ये controls देता हो।
Audit को parent के बाद भी बचा रहना चाहिए
Agent के अंतिम text से escaped action को दोबारा नहीं बनाया जा सकता। Parent logs flush करने से पहले खत्म हो सकता है और चलती हुई child के पास वापस report करने की कोई वजह नहीं होती। Audit को ऐसे immutable events पर आधारित बनाएं जिन्हें agent process के बाहर observe किया गया हो।
External work की अनुमति देने से पहले हर run में कम से कम ये fields दर्ज करें:
{
"run_id": "run-7f3c",
"started_at": "2026-07-24T14:00:02Z",
"deadline_at": "2026-07-24T14:00:32Z",
"parent_pid": 4102,
"process_group": 4102,
"approval_identity": "signed agent process identity",
"state": "active"
}
Action record में run ID, action sequence, gateway द्वारा उसे स्वीकार करने का समय, channel, target identity और outcome होना चाहिए। Bearer values, private keys, authorization headers या पूरी request bodies को default रूप से कभी log न करें। Credential को दिखाते हुए उसका इस्तेमाल document करने वाला record एक दूसरी incident पैदा कर सकता है।
Timeout होने पर signal भेजने से पहले state transition जोड़ें:
{
"run_id": "run-7f3c",
"event": "deadline_expired",
"observed_at": "2026-07-24T14:00:32Z",
"process_group": 4102,
"signal": "TERM"
}
अब आपकी जांच का एक कठिन सवाल और उसका स्पष्ट जवाब है: क्या deadline_expired के बाद कोई external action शुरू हुई? अगर gateway उस event के बाद action स्वीकार करता है, तो या तो उसने run state लागू नहीं की या caller के पास वह identity नहीं थी जिसकी gateway को उम्मीद थी। अगर action expiry से पहले शुरू हुई लेकिन बाद में पूरी हुई, तो इसे साफ-साफ लिखें। शुरू होने और पूरा होने के समय अलग होते हैं। उन्हें एक मानने से सामान्य in-flight work भी escape जैसा दिखता है।
एक मशीन के भीतर events का क्रम तय करने के लिए wall-clock time और monotonic elapsed value दोनों रखें। Synchronization या manual adjustment से wall clock बदल सकती है। Incident के दौरान timekeeping पर लंबा व्याख्यान नहीं चाहिए, इतना data चाहिए कि clocks के अलग होने पर आप यह गलत दावा न करें कि action parent की मौत के बाद हुई।
Sallyport के Sessions और Activity journals run view को individual calls से अलग रखते हैं। इसकी encrypted hash-chained log को sp audit verify से offline जांचा जा सकता है। Parent गायब हो जाने के बाद यह उपयोगी है, क्योंकि audit trail agent के अपनी history बताने पर निर्भर नहीं होती।
Audit trail evidence है, containment नहीं। यह बताता है कि call हुई और बाद की review में मदद करता है। यह local orphan को खत्म नहीं करता, उसे पहले से मिला data वापस नहीं लेता और cancellation path के बिना remote command को रद्द नहीं करता। इन सभी को अलग जिम्मेदारियां मानें और run record में हर एक को स्पष्ट रूप से दिखाएं।
Failure को सही क्रम में दोबारा बनाएं
जब कोई संदिग्ध orphan मिले, तो scene साफ करने से पहले facts सुरक्षित करें। हानिकारक काम रोकने के लिए जल्द kill -9 भेजना जरूरी हो सकता है, लेकिन इससे वे process relationships मिट सकती हैं जिन्हें runner ठीक करने के लिए आपको देखना है। स्थिति अनुमति दे तो पहले process snapshot लें।
Expired run record से शुरुआत करें। उसका parent PID, PGID या job identity, start time, deadline और भेजे गए हर signal को नोट करें। फिर वर्तमान process snapshot लें। macOS पर PID, PPID, PGID, SID, elapsed time और command की तुलना करें। Orphan का PPID अक्सर 1 या किसी supervisor में बदल जाता है, लेकिन इसे अपनी एकमात्र जांच न बनाएं। PPID कहीं और इशारा करते हुए भी process जोखिम बनी रह सकती है।
इसके बाद देखें कि क्या बचकर निकला:
- Original PGID में मौजूद process अपेक्षित signal के बाद भी बची रही।
- Process का नया PGID या SID है और इसलिए वह local रूप से detach हो गई।
- Local process ने remote start request की और remote job चलती रही।
- Run expire होने के बाद भी कोई credential या authenticated channel इस्तेमाल करने लायक रहा।
हर class की repair अलग होगी। पहली signal handling या cleanup timing की ओर इशारा करती है। दूसरी unapproved detach mechanism की ओर। तीसरे के लिए remote job ID और cancellation protocol चाहिए। चौथे के लिए action authority को parent process के व्यवहार पर भरोसा करने के बजाय requests को current run से जोड़ना होगा।
अब action records को timeline से मिलाएं। Agent transcripts पढ़कर शुरुआत न करें। Expiry के बाद स्वीकार की गई requests, मूल instruction से अलग targets, batch जारी रखने वाली repeat calls और ऐसी calls खोजें जिन्हें parent report नहीं कर सकता था क्योंकि वह पहले ही बाहर निकल चुका था। Transcript बाद में intent समझा सकता है। यह साबित नहीं कर सकता कि network request हुई या नहीं।
अंत में तय करें कि credential को rotate या revoke करना है या नहीं। अगर raw secret agent में गया ही नहीं और action gateway ने expiry के बाद की calls अस्वीकार कर दीं, तो बाकी जोखिम शायद पहले से पूरे हो चुके data या changes तक सीमित हो। अगर child को bearer token, private key, SSH agent access या connected administrative channel मिल गया था, तो मानें कि वह तब तक कार्रवाई कर सकती है जब तक आपने वह authority बंद न कर दी हो। यहीं teams इस बहस में समय गंवाती हैं कि process ने «शायद» कुछ किया होगा। अगर आप यह साबित नहीं कर सकते कि उसकी access खत्म हो गई, तो access हटा दें।
Failure test से orphan साफ दिखाई देनी चाहिए
Timeout harness में ऐसा test होना चाहिए जो child के बचने पर जोर से विफल हो। केवल यह test करना कि parent timeout लौटाता है, लगभग कुछ साबित नहीं करता।
एक fixture बनाएं जो एक ही दर्ज किए गए group में parent और child शुरू करे। Child इतनी देर तक wait करे कि harness parent को timeout कर सके। Parent block होने से पहले child की PID और group report करे। Timeout के बाद assert करें कि दोनों processes मौजूद न हों और test action log में expiry record के बाद कोई accepted call न हो।
यह shell fixture समस्या का ढांचा दिखाती है:
#!/bin/sh
(
trap 'exit 0' TERM INT
sleep 600 &
child=$!
printf 'parent=%s child=%s pgid=' "$$" "$child"
ps -o pgid= -p "$$" | tr -d ' '
wait "$child"
)
इसे interactive terminal से नहीं, उसी launch code के तहत चलाएं जिसका आपका agent executor इस्तेमाल करता है। Interactive terminal चुपचाप अलग job-control behavior दे सकता है। Printed IDs capture करें, deadline force करें और process table जांचें। अगर child बची रहती है, तो आपको खास जानकारी मिली है: या तो launch ने वह group बनाया ही नहीं जिसे आपने माना था या timeout signal उस तक पहुंचा ही नहीं।
इसे उन tools के लिए दोहराएं जिन्हें आपके agents वास्तव में call करते हैं। Shell wrappers, Node child-process APIs, Python subprocess calls, package managers, compilers और SSH helpers groups, descriptors और signal forwarding के बारे में अलग-अलग फैसले लेते हैं। आपको सैकड़ों tests की जरूरत नहीं। हर उस launcher pattern के लिए एक destructive test चाहिए जो descendants बना सकता है।
एक दूसरा fixture जोड़ें जो detach करने की कोशिश करे। Test session बनाने वाली call या detached child बनाने वाला runtime option इस्तेमाल कर सकता है। Expected result rejection, supervisor ownership या explicit registration event होना चाहिए। चुपचाप सफल होना defect है, क्योंकि इससे agent को पता चलता है कि वह काम को timeout boundary के बाहर ले जा सकता है।
Local PIDs पर न रुकें। अगर आपका agent remote work शुरू कर सकता है, तो remote side से job identifier लौटवाएं और local timeout के बाद cancellation test करें। Desired state यह नहीं है कि «SSH client बाहर निकल गया»। Desired state यह है कि «इस run से जुड़ा remote job बंद है या उसके बाकी काम का owner दर्ज है»।
Approval को process से पहले खत्म होना चाहिए
Agent run के लिए human approval का मतलब कम हो जाता है अगर कोई child run को dead घोषित किए जाने के बाद भी उस approval का इस्तेमाल कर सके। External action authority को run identity और उस state से जोड़ें जिसे authority component हर request पर जांचता है। Runner run को expired mark करे, तो उस run की नई actions fail होनी चाहिए, भले ही कोई local orphan अब भी CPU इस्तेमाल कर रही हो।
इस design का मतलब यह नहीं कि हर shell command पर इंसान से prompt दिखाया जाए। मतलब यह है कि authority खर्च करने वाला component जानता हो कि run कब खत्म हुआ। वह run को short-lived handle दे सकता है, revocation के बाद उसे अस्वीकार कर सकता है और refusal दर्ज कर सकता है। Process-group kill तब local नुकसान सीमित करता है, जबकि action boundary cleanup race के परिणाम सीमित करती है।
जिन operations के लिए per-action approval चाहिए, वहां उसे बनाए रखें, लेकिन approval को supervision न समझें। User session की शुरुआत में signed agent process को approve कर सकता है। अगर agent के बाहर निकलने के बाद descendant चलती रहती है, तो उसने approved execution lifetime पार कर ली है, भले ही उसे वही local context मिला हो। आपका system इस स्थिति को लागू करने योग्य बनाए, child के शिष्ट व्यवहार पर निर्भर न रहे।
Runner को run cancel करने और external effect cancel करने में भी फर्क रखना चाहिए। Canceled request शायद API तक पहुंच चुकी हो। Terminated SSH client remote command शुरू कर चुका हो सकता है। Cancellation request, observed local exit और external system से मिले confirmation को अलग-अलग events के रूप में दर्ज करें। यह भाषा «canceled» कहने से कम सुकून देती है, लेकिन operators को बताती है कि वे वास्तव में क्या जानते हैं।
Agent executor में मैं सबसे पहले एक छोटा और साधारण सुधार करूंगा: launch के समय dedicated process group बनाकर दर्ज करना, timeout path में उसी group को खत्म करना और failure test में परिणाम की जांच करना। इसके साथ ऐसी action boundary जोड़ें जो expiry के बाद run को अस्वीकार कर दे। जब ये दोनों बातें सच हों, तो orphan ऐसी incident बन जाती है जिसे contain और explain किया जा सकता है, न कि यह धुंधला डर कि शायद कुछ अब भी चल रहा है।
सामान्य प्रश्न
AI एजेंट रन में अनाथ सबप्रोसेस क्या होती है?
अनाथ प्रोसेस वह होती है जिसका मूल पैरेंट बाहर निकल चुका हो, इसलिए ऑपरेटिंग सिस्टम उसे किसी दूसरे पैरेंट से जोड़ देता है। वह चलती रह सकती है, नेटवर्क कनेक्शन खुले रख सकती है और पहले से मिली क्रेडेंशियल सामग्री का इस्तेमाल कर सकती है। पैरेंट का टाइमआउट केवल यह साबित करता है कि एक PID खत्म हुआ।
क्या AI एजेंट को खत्म करने से उसकी चाइल्ड प्रोसेस भी खत्म हो जाती हैं?
सिर्फ तब, जब रनर एजेंट को अलग प्रोसेस ग्रुप या किसी समान कंटेनमेंट सीमा में शुरू करे और पूरी सीमा को बंद करे। केवल पैरेंट PID को खत्म करने से स्वतंत्र रूप से बनाई गई चाइल्ड प्रोसेस चलती रहती हैं। इसका परीक्षण ऐसे चाइल्ड प्रोसेस से करें जो पैरेंट के बाहर निकलने के बाद भी सोती रहे।
एजेंट टाइमआउट के लिए प्रोसेस ग्रुप या सेशन में से किसका इस्तेमाल करना चाहिए?
स्थानीय macOS कमांड ट्री के लिए प्रोसेस ग्रुप इस्तेमाल करें और समयसीमा के बाद नेगेटिव प्रोसेस-ग्रुप ID को सिग्नल भेजें। सेशन एक व्यापक सीमा दे सकता है, जबकि सर्विस मैनेजर या कंटेनर संसाधनों पर अधिक मजबूत नियंत्रण दे सकता है। कोई एक सीमा चुनें और काम शुरू होने से पहले उसका आइडेंटिफायर दर्ज करें।
क्या एजेंट के खत्म होने के बाद भी कोई अनाथ प्रोसेस API key का इस्तेमाल कर सकती है?
SSH कंट्रोल सॉकेट, खुला हुआ ऑथेंटिकेटेड कनेक्शन, विरासत में मिला फाइल डिस्क्रिप्टर या लंबे समय तक चलने वाला bearer token पैरेंट के खत्म होने के बाद भी काम कर सकता है। कच्ची क्रेडेंशियल एजेंट प्रोसेस को न दें और हर बाहरी कार्रवाई को सीमित अवधि दें। रिवोकेशन में केवल चैट सेशन नहीं, कार्रवाई का पूरा रास्ता शामिल होना चाहिए।
macOS पर टाइमआउट वाले एजेंट की बची हुई चाइल्ड प्रोसेस कैसे खोजें?
macOS पर सिग्नल भेजने से पहले ps की मदद से PID, PPID, PGID, SID, बीता समय और कमांड लाइन देखें। ऐसी प्रोसेस खोजें जिसका PPID 1 या किसी दूसरे सुपरवाइज़र में बदल गया हो और जिसका PGID अब भी समाप्त हुए रन से मेल खाता हो। अगर घटना का रिकॉर्ड रखना हो, तो सफाई से पहले यह स्नैपशॉट सुरक्षित कर लें।
क्या टाइमआउट वाले AI एजेंट की सफाई के लिए pkill सुरक्षित है?
नहीं। नाम से मिलान करने पर कोई असंबंधित एडिटर, टेस्ट रनर या दूसरा एजेंट रन खत्म हो सकता है। साथ ही, जिस चाइल्ड ने अपना एक्जीक्यूटेबल नाम बदल लिया हो, वह छूट सकती है। इसके बजाय दर्ज किए गए प्रोसेस ग्रुप या सुपरवाइज़र के नियंत्रण वाले जॉब को सिग्नल भेजें।
AI एजेंट के एक्जीक्यूशन ऑडिट में क्या दर्ज होना चाहिए?
सबसे पहले समयसीमा, प्रोसेस ग्रुप या जॉब आइडेंटिफायर, पैरेंट PID, स्वीकृत एक्शन आइडेंटिटी और मोनोटोनिक क्लॉक के टाइमस्टैम्प दर्ज करें। हर बाहरी कॉल, एग्जिट स्टेटस और सफाई के सिग्नल भी जोड़ें। सीमा का आइडेंटिफायर न हो तो बाद में यह तय करना अनुमान बन जाता है कि कौन-सी कार्रवाई किस रन ने की।
क्या एक्शन गेटवे अनाथ प्रोसेस से होने वाले क्रेडेंशियल लीक को रोक सकता है?
यह तभी मदद करता है जब गेटवे क्रेडेंशियल को एजेंट से बाहर रखे और एजेंट के अपने आउटपुट से स्वतंत्र रूप से कार्रवाई लॉग करे। फिर भी ऑपरेटिंग सिस्टम स्तर का कंटेनमेंट जरूरी है, क्योंकि कोई अनाथ प्रोसेस पहले से मिली फाइलों, CPU, सॉकेट और डेटा का इस्तेमाल कर सकती है। गेटवे यह दर्ज करता है कि उसकी सीमा से क्या गुजरा, लेकिन खराब प्रोसेस ट्री को खत्म नहीं कर सकता।
अनाथ एजेंट प्रोसेस मिलने के बाद मुझे क्या करना चाहिए?
पहले दर्ज किए गए ग्रुप को खत्म करें, थोड़ी देर प्रतीक्षा करें और केवल बची हुई प्रोसेस पर आगे की कार्रवाई करें। फिर बची प्रोसेस का स्नैपशॉट लें और उनके शुरू होने का समय, ग्रुप, खुले नेटवर्क कनेक्शन और एक्शन रिकॉर्ड मिलाएं। अगर आप यह साबित नहीं कर सकते कि बची हुई प्रोसेस की पहुंच खत्म हो गई है, तो क्रेडेंशियल बदलें या उसकी अनुमति रद्द करें।
ऑटोनॉमस कोडिंग एजेंट के टाइमआउट क्लीनअप का परीक्षण कैसे करें?
CI में एक जानबूझकर विफलता वाला टेस्ट चलाएं: पैरेंट को चाइल्ड बनाने दें, पैरेंट को टाइमआउट से आगे चलने दें, फिर जांचें कि दोनों PID मौजूद न हों और समाप्ति रिकॉर्ड के बाद कोई कार्रवाई स्वीकार न हुई हो। इसे shell wrapper, language runtime और SSH helper के लिए दोहराएं, क्योंकि हर परत नई प्रोसेस जोड़ सकती है। जिस सफाई प्रक्रिया का परीक्षण नहीं हुआ, वह केवल उम्मीद है।