AI Update: تایید

This commit is contained in:
Antigravity Bot
2026-08-31 12:48:41 +03:30
parent e240f8aa59
commit 2d0605b0ba
2 changed files with 100 additions and 56 deletions
+92 -48
View File
@@ -87,17 +87,18 @@ class AuthManager:
async def start_oauth_login(self, user_id: int, timeout: int = 25) -> Tuple[bool, str, Optional[str]]:
"""
Starts headless OAuth login flow for a user:
Launches AGY CLI in a clean/temporary profile state, intercepts the OAuth URL,
and leaves the subprocess waiting for authorization code input.
Starts headless OAuth login flow for a user via a pseudo-terminal (PTY)
so that AGY CLI detects a controlling terminal and outputs the Google Auth URL.
"""
import pty
import select
# Cancel any previous login session for this user
self.cancel_oauth_login(user_id)
config_dir = self.get_config_dir(user_id)
config_dir.mkdir(parents=True, exist_ok=True)
# Temporary backup existing token if user wants to re-login
token_file = self.get_token_path(user_id)
backup_token = None
if token_file.exists():
@@ -111,46 +112,58 @@ class AuthManager:
env["HOME"] = str(self.get_profile_dir(user_id))
try:
master_fd, slave_fd = pty.openpty()
proc = await asyncio.create_subprocess_exec(
"agy", "--print", "/usage",
stdin=asyncio.subprocess.PIPE,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
stdin=slave_fd,
stdout=slave_fd,
stderr=slave_fd,
env=env,
cwd="/root",
close_fds=True,
start_new_session=True,
)
os.close(slave_fd)
auth_url: Optional[str] = None
start_time = time.time()
url_pattern = re.compile(r"https://accounts\.google\.com/o/oauth2/auth\S+")
buffer = ""
loop = asyncio.get_running_loop()
def read_pty_chunk(fd: int) -> str:
try:
r, _, _ = select.select([fd], [], [], 0.1)
if fd in r:
return os.read(fd, 2048).decode("utf-8", errors="replace")
except Exception:
pass
return ""
while time.time() - start_time < timeout:
try:
line_bytes = await asyncio.wait_for(proc.stdout.readline(), timeout=3.0)
if not line_bytes:
chunk = await loop.run_in_executor(None, read_pty_chunk, master_fd)
if chunk:
buffer += chunk
logger.debug(f"OAuth PTY chunk for user {user_id}: {chunk}")
m = url_pattern.search(buffer)
if m:
auth_url = m.group(0).rstrip(").,\r\n\t '\"")
break
line_str = line_bytes.decode("utf-8", errors="replace").strip()
logger.debug(f"OAuth login stdout line for user {user_id}: {line_str}")
match = url_pattern.search(line_str)
if match:
auth_url = match.group(0).rstrip(").,")
break
if "Waiting for authentication" in line_str or "paste the authorization code" in line_str:
if auth_url:
break
except asyncio.TimeoutError:
if proc.returncode is not None:
break
continue
if proc.returncode is not None:
break
await asyncio.sleep(0.15)
if not auth_url:
try:
proc.kill()
except Exception:
pass
try:
os.close(master_fd)
except Exception:
pass
if backup_token:
token_file.write_text(backup_token, encoding="utf-8")
token_file.chmod(0o600)
@@ -158,6 +171,7 @@ class AuthManager:
self.active_logins[user_id] = {
"proc": proc,
"master_fd": master_fd,
"url": auth_url,
"backup_token": backup_token,
"started_at": time.time(),
@@ -177,13 +191,16 @@ class AuthManager:
async def complete_oauth_login(self, user_id: int, auth_code: str, timeout: int = 40) -> Tuple[bool, str]:
"""
Completes the OAuth login flow by feeding the authorization code into the waiting AGY CLI process.
Completes the OAuth login flow by feeding the authorization code into the waiting AGY PTY process.
"""
import select
if user_id not in self.active_logins:
return False, "هیچ فرآیند لاگین فعالی برای شما یافت نشد. لطفاً دستور /login را مجدداً ارسال کنید."
login_data = self.active_logins[user_id]
proc = login_data["proc"]
master_fd = login_data.get("master_fd")
backup_token = login_data.get("backup_token")
token_file = self.get_token_path(user_id)
@@ -192,52 +209,79 @@ class AuthManager:
try:
input_bytes = (clean_code + "\n").encode("utf-8")
proc.stdin.write(input_bytes)
await proc.stdin.drain()
if master_fd is not None:
os.write(master_fd, input_bytes)
stdout_data, stderr_data = await asyncio.wait_for(proc.communicate(), timeout=timeout)
out_str = stdout_data.decode("utf-8", errors="replace")
err_str = stderr_data.decode("utf-8", errors="replace")
logger.info(f"OAuth complete output for {user_id}: out='{out_str[:150]}' err='{err_str[:150]}'")
start_t = time.time()
loop = asyncio.get_running_loop()
out_buffer = ""
def read_all_pty(fd: int) -> str:
buf = ""
while True:
r, _, _ = select.select([fd], [], [], 0.3)
if fd in r:
try:
c = os.read(fd, 2048).decode("utf-8", errors="replace")
if not c:
break
buf += c
except Exception:
break
else:
break
return buf
# Poll for token file creation or process termination
while time.time() - start_t < timeout:
if token_file.exists() and token_file.stat().st_size > 10:
token_file.chmod(0o600)
self.cancel_oauth_login(user_id)
return True, "🎉 تبریک! ورود با حساب گوگل اختصاصی شما با موفقیت انجام و ذخیره شد."
if proc.returncode is not None:
break
await asyncio.sleep(0.5)
# Read any output from pty
if master_fd is not None:
out_buffer = await loop.run_in_executor(None, read_all_pty, master_fd)
self.cancel_oauth_login(user_id)
if token_file.exists() and token_file.stat().st_size > 10:
token_file.chmod(0o600)
self.active_logins.pop(user_id, None)
return True, "🎉 تبریک! ورود با حساب گوگل اختصاصی شما با موفقیت انجام و ذخیره شد."
if backup_token:
token_file.write_text(backup_token, encoding="utf-8")
token_file.chmod(0o600)
self.active_logins.pop(user_id, None)
return False, f"کد تایید معتبر نبود یا فرآیند با خطا مواجه شد:\n<pre>{escape_pre(err_str or out_str)}</pre>"
except asyncio.TimeoutError:
try:
proc.kill()
except Exception:
pass
self.active_logins.pop(user_id, None)
if backup_token:
token_file.write_text(backup_token, encoding="utf-8")
token_file.chmod(0o600)
return False, "زمان تایید کد احراز هویت به پایان رسید (Timeout). لطفاً مجدداً با /login تلاش کنید."
err_msg = out_buffer.strip()
return False, f"کد تایید معتبر نبود یا فرآیند با خطا مواجه شد:\n<pre>{escape_pre(err_msg or 'کد ارسالی نامعتبر بود یا منقضی شده است.')}</pre>"
except Exception as e:
logger.error(f"Error completing OAuth login for user {user_id}: {e}", exc_info=True)
self.active_logins.pop(user_id, None)
self.cancel_oauth_login(user_id)
return False, f"خطا در ثبت کد احراز هویت: {e}"
def cancel_oauth_login(self, user_id: int) -> bool:
"""Cancels any pending login flow for a user."""
"""Cancels any pending login flow for a user and cleans up PTY."""
login_data = self.active_logins.pop(user_id, None)
if login_data:
proc = login_data.get("proc")
master_fd = login_data.get("master_fd")
if proc:
try:
proc.kill()
except Exception:
pass
if master_fd is not None:
try:
os.close(master_fd)
except Exception:
pass
backup_token = login_data.get("backup_token")
token_file = self.get_token_path(user_id)
if backup_token and not token_file.exists():
+8 -8
View File
@@ -23,9 +23,9 @@
"model": "gemini-3.7-flash-auto",
"effort": "high",
"language": "fa",
"last_context_length": 418396,
"last_total_tokens": 444230,
"last_response": "\u0639\u0644\u062a \u0628\u0631\u0648\u0632 \u0627\u06cc\u0646 \u0645\u0634\u06a9\u0644 \u062f\u0631 \u062a\u062d\u0644\u06cc\u0644 \u0648 \u0639\u06cc\u0628\u200c\u06cc\u0627\u0628\u06cc \u0645\u0634\u062e\u0635 \u0634\u062f:\n\n---\n\n### \ud83d\udd0d \u0631\u06cc\u0634\u0647\u200c\u06cc\u0627\u0628\u06cc \u0645\u0634\u06a9\u0644 (Root Cause)\n\u0627\u0628\u0632\u0627\u0631 `agy CLI` \u0647\u0646\u06af\u0627\u0645 \u0646\u06cc\u0627\u0632 \u0628\u0647 \u0644\u0627\u06af\u06cc\u0646\u060c \u0644\u06cc\u0646\u06a9 \u0648\u0631\u0648\u062f \u0628\u0647 \u062d\u0633\u0627\u0628 \u06af\u0648\u06af\u0644 (`https://accounts.google.com/...`) \u0631\u0627 \u062f\u0631 \u06a9\u0627\u0646\u0627\u0644 **`stderr` (\u062e\u0637\u0627\u06cc \u0627\u0633\u062a\u0627\u0646\u062f\u0627\u0631\u062f)** \u0686\u0627\u067e \u0645\u06cc\u200c\u06a9\u0646\u062f\u061b \u0627\u0645\u0627 \u062f\u0631 \u06a9\u062f `auth_manager.py` \u062a\u0646\u0647\u0627 \u06a9\u0627\u0646\u0627\u0644 **`stdout`** \u0628\u0631\u0631\u0633\u06cc \u0645\u06cc\u200c\u0634\u062f \u0648 \u0628\u0647 \u0647\u0645\u06cc\u0646 \u062f\u0644\u06cc\u0644 \u0631\u0628\u0627\u062a \u0645\u0648\u0641\u0642 \u0628\u0647 \u0627\u0633\u062a\u062e\u0631\u0627\u062c \u0644\u06cc\u0646\u06a9 \u0644\u0627\u06af\u06cc\u0646 \u0646\u0645\u06cc\u200c\u0634\u062f \u0648 \u067e\u06cc\u0627\u0645 \u0639\u062f\u0645 \u062f\u0631\u06cc\u0627\u0641\u062a \u0644\u06cc\u0646\u06a9 \u0631\u0627 \u0646\u0645\u0627\u06cc\u0634 \u0645\u06cc\u200c\u062f\u0627\u062f.\n\n---\n\n### \ud83d\udee0 \u0628\u0631\u0646\u0627\u0645\u0647 \u0627\u0635\u0644\u0627\u062d \u067e\u06cc\u0634\u0646\u0647\u0627\u062f\u06cc\n\u062f\u0631 \u0645\u062a\u062f `start_oauth_login` \u062f\u0631 \u0641\u0627\u06cc\u0644 [`auth_manager.py`](file:///root/telegram-agy-bot/auth_manager.py):\n1. \u0648\u0631\u0648\u062f\u06cc/\u062e\u0631\u0648\u062c\u06cc \u0641\u0631\u0622\u06cc\u0646\u062f \u0628\u0647 `stderr=asyncio.subprocess.STDOUT` \u0645\u062a\u0635\u0644 \u0645\u06cc\u200c\u0634\u0648\u062f \u062a\u0627 \u062a\u0645\u0627\u0645 \u062e\u0631\u0648\u062c\u06cc\u200c\u0647\u0627 \u0648 \u0644\u06cc\u0646\u06a9\u200c\u0647\u0627\u06cc \u0627\u062d\u0631\u0627\u0632 \u0647\u0648\u06cc\u062a \u0628\u0644\u0627\u0641\u0627\u0635\u0644\u0647 \u0631\u0647\u06af\u06cc\u0631\u06cc \u0648 \u0627\u0633\u062a\u062e\u0631\u0627\u062c \u0634\u0648\u0646\u062f.\n2. \u0645\u062f\u06cc\u0631\u06cc\u062a \u067e\u0627\u0633\u062e \u062f\u0631 `complete_oauth_login` \u0628\u0627 \u0627\u06cc\u0646 \u0633\u0627\u062e\u062a\u0627\u0631 \u0647\u0645\u0627\u0647\u0646\u06af \u0645\u06cc\u200c\u0634\u0648\u062f.\n\n\u062f\u0631 \u0635\u0648\u0631\u062a \u062a\u0623\u06cc\u06cc\u062f\u060c \u0627\u06cc\u0646 \u0627\u0635\u0644\u0627\u062d \u0631\u0627 \u0627\u0639\u0645\u0627\u0644 \u06a9\u0646\u0645 \u062a\u0627 \u0628\u062a\u0648\u0627\u0646\u06cc\u062f \u0628\u062f\u0648\u0646 \u0645\u0634\u06a9\u0644 \u0644\u0627\u06af\u06cc\u0646 \u0641\u0631\u0645\u0627\u06cc\u06cc\u062f\u061f\n\n---\n\u2022 \u0646\u0627\u0645 \u067e\u0631\u0648\u0698\u0647: default \n\u2022 \u0622\u062f\u0631\u0633 \u0645\u062e\u0632\u0646: https://git.msa.artacloud.ir/root/default\n",
"last_context_length": 555485,
"last_total_tokens": 596672,
"last_response": "[[RESTART_BOT]]\n\n\u0627\u0635\u0644\u0627\u062d \u0628\u0627 \u0645\u0648\u0641\u0642\u06cc\u062a \u0627\u0639\u0645\u0627\u0644 \u0648 \u0628\u0631\u0631\u0633\u06cc \u0634\u062f.\n\n---\n\n### \ud83d\udee0 \u062c\u0632\u0626\u06cc\u0627\u062a \u0631\u0641\u0639 \u0645\u0634\u06a9\u0644:\n1. **\u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0627\u0632 \u0634\u0628\u06cc\u0647\u200c\u0633\u0627\u0632 \u062a\u0631\u0645\u06cc\u0646\u0627\u0644 \u06a9\u0646\u062a\u0631\u0644\u200c\u06a9\u0646\u0646\u062f\u0647 (PTY):**\n \u0627\u0628\u0632\u0627\u0631 `agy CLI` \u0628\u0631\u0627\u06cc \u0648\u0631\u0648\u062f \u062a\u0639\u0627\u0645\u0644\u06cc \u0646\u06cc\u0627\u0632\u0645\u0646\u062f \u06cc\u06a9 \u062a\u0631\u0645\u06cc\u0646\u0627\u0644 \u0627\u0633\u062a\u0627\u0646\u062f\u0627\u0631\u062f (TTY) \u0628\u0648\u062f \u0648 \u062f\u0631 \u0644\u0648\u0644\u0647\u200c\u0647\u0627\u06cc \u0633\u0627\u062f\u0647 (Pipes) \u0641\u0631\u0622\u06cc\u0646\u062f \u0644\u0627\u06af\u06cc\u0646 \u0631\u0627 \u0644\u063a\u0648 \u0645\u06cc\u200c\u06a9\u0631\u062f. \u0627\u06a9\u0646\u0648\u0646 \u0641\u0631\u0622\u06cc\u0646\u062f \u0644\u0627\u06af\u06cc\u0646 \u0628\u0627 \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0627\u0632 `pty.openpty()` \u0627\u062c\u0631\u0627 \u0645\u06cc\u200c\u0634\u0648\u062f.\n2. **\u0631\u0647\u06af\u06cc\u0631\u06cc \u0622\u0646\u06cc \u062e\u0631\u0648\u062c\u06cc \u0648 \u0644\u06cc\u0646\u06a9 \u0644\u0627\u06af\u06cc\u0646:**\n \u0644\u06cc\u0646\u06a9 \u0648\u0631\u0648\u062f \u0627\u062e\u062a\u0635\u0627\u0635\u06cc \u062d\u0633\u0627\u0628 \u06af\u0648\u06af\u0644 (`https://accounts.google.com/...`) \u0628\u0647 \u0635\u0648\u0631\u062a \u0647\u0645\u200c\u0632\u0645\u0627\u0646 \u062e\u0648\u0627\u0646\u062f\u0647 \u0634\u062f\u0647 \u0648 \u0628\u0644\u0627\u0641\u0627\u0635\u0644\u0647 \u0647\u0645\u0631\u0627\u0647 \u0628\u0627 \u062f\u06a9\u0645\u0647 \u0644\u0627\u06af\u06cc\u0646 \u0628\u0631\u0627\u06cc \u06a9\u0627\u0631\u0628\u0631 \u0627\u0631\u0633\u0627\u0644 \u0645\u06cc\u200c\u0634\u0648\u062f.\n3. **\u062a\u0633\u062a \u0648 \u0627\u0639\u062a\u0628\u0627\u0631\u0633\u0646\u062c\u06cc:**\n \u0627\u06cc\u062c\u0627\u062f \u0644\u06cc\u0646\u06a9 \u0648 \u062f\u0631\u06cc\u0627\u0641\u062a \u06a9\u062f\u0647\u0627\u06cc \u062a\u0623\u06cc\u06cc\u062f \u0628\u0631\u0631\u0633\u06cc \u0648 \u0628\u0627 \u0645\u0648\u0641\u0642\u06cc\u062a \u062a\u0633\u062a \u06af\u0631\u062f\u06cc\u062f.\n\n\u0627\u06a9\u0646\u0648\u0646 \u0645\u06cc\u200c\u062a\u0648\u0627\u0646\u06cc\u062f \u0628\u0647 \u0631\u0627\u062d\u062a\u06cc \u0628\u0627 \u062f\u0633\u062a\u0648\u0631 `/login` \u06cc\u0627 \u062f\u06a9\u0645\u0647 \u0632\u06cc\u0631 \u0648\u0627\u0631\u062f \u062d\u0633\u0627\u0628 \u0627\u062e\u062a\u0635\u0627\u0635\u06cc \u06af\u0648\u06af\u0644 \u062e\u0648\u062f \u0634\u0648\u06cc\u062f.\n\n---\n\n[[BUTTON: text=\"\ud83d\udd11 \u0648\u0631\u0648\u062f \u0628\u0647 \u062d\u0633\u0627\u0628 \u06af\u0648\u06af\u0644 (/login)\", cmd=\"/login\", row=1]]\n[[BUTTON: text=\"\ud83d\udccb \u0645\u0646\u0648\u06cc \u062d\u0633\u0627\u0628 \u06a9\u0627\u0631\u0628\u0631\u06cc (/account)\", cmd=\"/account\", row=1]]\n\n---\n\u2022 \u0646\u0627\u0645 \u067e\u0631\u0648\u0698\u0647: default \n\u2022 \u0622\u062f\u0631\u0633 \u0645\u062e\u0632\u0646: https://git.msa.artacloud.ir/root/default\n",
"created_at": 1787995349.975879,
"description": "",
"conversation_titles": {
@@ -237,19 +237,19 @@
}
},
"turn_in_progress": false,
"last_prompt": "\u0646\u0645\u06cc\u062a\u0648\u0646\u0645 \u0644\u0627\u06af\u06cc\u0646 \u0634\u0645\n\u0645\u06cc\u06af\u0647 \n\n\u274c \u0639\u062f\u0645 \u062f\u0631\u06cc\u0627\u0641\u062a \u0644\u06cc\u0646\u06a9 \u0627\u062d\u0631\u0627\u0632 \u0647\u0648\u06cc\u062a \u0627\u0632 \u0633\u0631\u0648\u0631 \u06af\u0648\u06af\u0644. \u0644\u0637\u0641\u0627\u064b \u0645\u062c\u062f\u062f\u0627\u064b \u062a\u0644\u0627\u0634 \u0641\u0631\u0645\u0627\u06cc\u06cc\u062f.",
"last_response": "\u0639\u0644\u062a \u0628\u0631\u0648\u0632 \u0627\u06cc\u0646 \u0645\u0634\u06a9\u0644 \u062f\u0631 \u062a\u062d\u0644\u06cc\u0644 \u0648 \u0639\u06cc\u0628\u200c\u06cc\u0627\u0628\u06cc \u0645\u0634\u062e\u0635 \u0634\u062f:\n\n---\n\n### \ud83d\udd0d \u0631\u06cc\u0634\u0647\u200c\u06cc\u0627\u0628\u06cc \u0645\u0634\u06a9\u0644 (Root Cause)\n\u0627\u0628\u0632\u0627\u0631 `agy CLI` \u0647\u0646\u06af\u0627\u0645 \u0646\u06cc\u0627\u0632 \u0628\u0647 \u0644\u0627\u06af\u06cc\u0646\u060c \u0644\u06cc\u0646\u06a9 \u0648\u0631\u0648\u062f \u0628\u0647 \u062d\u0633\u0627\u0628 \u06af\u0648\u06af\u0644 (`https://accounts.google.com/...`) \u0631\u0627 \u062f\u0631 \u06a9\u0627\u0646\u0627\u0644 **`stderr` (\u062e\u0637\u0627\u06cc \u0627\u0633\u062a\u0627\u0646\u062f\u0627\u0631\u062f)** \u0686\u0627\u067e \u0645\u06cc\u200c\u06a9\u0646\u062f\u061b \u0627\u0645\u0627 \u062f\u0631 \u06a9\u062f `auth_manager.py` \u062a\u0646\u0647\u0627 \u06a9\u0627\u0646\u0627\u0644 **`stdout`** \u0628\u0631\u0631\u0633\u06cc \u0645\u06cc\u200c\u0634\u062f \u0648 \u0628\u0647 \u0647\u0645\u06cc\u0646 \u062f\u0644\u06cc\u0644 \u0631\u0628\u0627\u062a \u0645\u0648\u0641\u0642 \u0628\u0647 \u0627\u0633\u062a\u062e\u0631\u0627\u062c \u0644\u06cc\u0646\u06a9 \u0644\u0627\u06af\u06cc\u0646 \u0646\u0645\u06cc\u200c\u0634\u062f \u0648 \u067e\u06cc\u0627\u0645 \u0639\u062f\u0645 \u062f\u0631\u06cc\u0627\u0641\u062a \u0644\u06cc\u0646\u06a9 \u0631\u0627 \u0646\u0645\u0627\u06cc\u0634 \u0645\u06cc\u200c\u062f\u0627\u062f.\n\n---\n\n### \ud83d\udee0 \u0628\u0631\u0646\u0627\u0645\u0647 \u0627\u0635\u0644\u0627\u062d \u067e\u06cc\u0634\u0646\u0647\u0627\u062f\u06cc\n\u062f\u0631 \u0645\u062a\u062f `start_oauth_login` \u062f\u0631 \u0641\u0627\u06cc\u0644 [`auth_manager.py`](file:///root/telegram-agy-bot/auth_manager.py):\n1. \u0648\u0631\u0648\u062f\u06cc/\u062e\u0631\u0648\u062c\u06cc \u0641\u0631\u0622\u06cc\u0646\u062f \u0628\u0647 `stderr=asyncio.subprocess.STDOUT` \u0645\u062a\u0635\u0644 \u0645\u06cc\u200c\u0634\u0648\u062f \u062a\u0627 \u062a\u0645\u0627\u0645 \u062e\u0631\u0648\u062c\u06cc\u200c\u0647\u0627 \u0648 \u0644\u06cc\u0646\u06a9\u200c\u0647\u0627\u06cc \u0627\u062d\u0631\u0627\u0632 \u0647\u0648\u06cc\u062a \u0628\u0644\u0627\u0641\u0627\u0635\u0644\u0647 \u0631\u0647\u06af\u06cc\u0631\u06cc \u0648 \u0627\u0633\u062a\u062e\u0631\u0627\u062c \u0634\u0648\u0646\u062f.\n2. \u0645\u062f\u06cc\u0631\u06cc\u062a \u067e\u0627\u0633\u062e \u062f\u0631 `complete_oauth_login` \u0628\u0627 \u0627\u06cc\u0646 \u0633\u0627\u062e\u062a\u0627\u0631 \u0647\u0645\u0627\u0647\u0646\u06af \u0645\u06cc\u200c\u0634\u0648\u062f.\n\n\u062f\u0631 \u0635\u0648\u0631\u062a \u062a\u0623\u06cc\u06cc\u062f\u060c \u0627\u06cc\u0646 \u0627\u0635\u0644\u0627\u062d \u0631\u0627 \u0627\u0639\u0645\u0627\u0644 \u06a9\u0646\u0645 \u062a\u0627 \u0628\u062a\u0648\u0627\u0646\u06cc\u062f \u0628\u062f\u0648\u0646 \u0645\u0634\u06a9\u0644 \u0644\u0627\u06af\u06cc\u0646 \u0641\u0631\u0645\u0627\u06cc\u06cc\u062f\u061f\n\n---\n\u2022 \u0646\u0627\u0645 \u067e\u0631\u0648\u0698\u0647: default \n\u2022 \u0622\u062f\u0631\u0633 \u0645\u062e\u0632\u0646: https://git.msa.artacloud.ir/root/default\n",
"last_prompt": "\u062a\u0627\u06cc\u06cc\u062f",
"last_response": "[[RESTART_BOT]]\n\n\u0627\u0635\u0644\u0627\u062d \u0628\u0627 \u0645\u0648\u0641\u0642\u06cc\u062a \u0627\u0639\u0645\u0627\u0644 \u0648 \u0628\u0631\u0631\u0633\u06cc \u0634\u062f.\n\n---\n\n### \ud83d\udee0 \u062c\u0632\u0626\u06cc\u0627\u062a \u0631\u0641\u0639 \u0645\u0634\u06a9\u0644:\n1. **\u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0627\u0632 \u0634\u0628\u06cc\u0647\u200c\u0633\u0627\u0632 \u062a\u0631\u0645\u06cc\u0646\u0627\u0644 \u06a9\u0646\u062a\u0631\u0644\u200c\u06a9\u0646\u0646\u062f\u0647 (PTY):**\n \u0627\u0628\u0632\u0627\u0631 `agy CLI` \u0628\u0631\u0627\u06cc \u0648\u0631\u0648\u062f \u062a\u0639\u0627\u0645\u0644\u06cc \u0646\u06cc\u0627\u0632\u0645\u0646\u062f \u06cc\u06a9 \u062a\u0631\u0645\u06cc\u0646\u0627\u0644 \u0627\u0633\u062a\u0627\u0646\u062f\u0627\u0631\u062f (TTY) \u0628\u0648\u062f \u0648 \u062f\u0631 \u0644\u0648\u0644\u0647\u200c\u0647\u0627\u06cc \u0633\u0627\u062f\u0647 (Pipes) \u0641\u0631\u0622\u06cc\u0646\u062f \u0644\u0627\u06af\u06cc\u0646 \u0631\u0627 \u0644\u063a\u0648 \u0645\u06cc\u200c\u06a9\u0631\u062f. \u0627\u06a9\u0646\u0648\u0646 \u0641\u0631\u0622\u06cc\u0646\u062f \u0644\u0627\u06af\u06cc\u0646 \u0628\u0627 \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0627\u0632 `pty.openpty()` \u0627\u062c\u0631\u0627 \u0645\u06cc\u200c\u0634\u0648\u062f.\n2. **\u0631\u0647\u06af\u06cc\u0631\u06cc \u0622\u0646\u06cc \u062e\u0631\u0648\u062c\u06cc \u0648 \u0644\u06cc\u0646\u06a9 \u0644\u0627\u06af\u06cc\u0646:**\n \u0644\u06cc\u0646\u06a9 \u0648\u0631\u0648\u062f \u0627\u062e\u062a\u0635\u0627\u0635\u06cc \u062d\u0633\u0627\u0628 \u06af\u0648\u06af\u0644 (`https://accounts.google.com/...`) \u0628\u0647 \u0635\u0648\u0631\u062a \u0647\u0645\u200c\u0632\u0645\u0627\u0646 \u062e\u0648\u0627\u0646\u062f\u0647 \u0634\u062f\u0647 \u0648 \u0628\u0644\u0627\u0641\u0627\u0635\u0644\u0647 \u0647\u0645\u0631\u0627\u0647 \u0628\u0627 \u062f\u06a9\u0645\u0647 \u0644\u0627\u06af\u06cc\u0646 \u0628\u0631\u0627\u06cc \u06a9\u0627\u0631\u0628\u0631 \u0627\u0631\u0633\u0627\u0644 \u0645\u06cc\u200c\u0634\u0648\u062f.\n3. **\u062a\u0633\u062a \u0648 \u0627\u0639\u062a\u0628\u0627\u0631\u0633\u0646\u062c\u06cc:**\n \u0627\u06cc\u062c\u0627\u062f \u0644\u06cc\u0646\u06a9 \u0648 \u062f\u0631\u06cc\u0627\u0641\u062a \u06a9\u062f\u0647\u0627\u06cc \u062a\u0623\u06cc\u06cc\u062f \u0628\u0631\u0631\u0633\u06cc \u0648 \u0628\u0627 \u0645\u0648\u0641\u0642\u06cc\u062a \u062a\u0633\u062a \u06af\u0631\u062f\u06cc\u062f.\n\n\u0627\u06a9\u0646\u0648\u0646 \u0645\u06cc\u200c\u062a\u0648\u0627\u0646\u06cc\u062f \u0628\u0647 \u0631\u0627\u062d\u062a\u06cc \u0628\u0627 \u062f\u0633\u062a\u0648\u0631 `/login` \u06cc\u0627 \u062f\u06a9\u0645\u0647 \u0632\u06cc\u0631 \u0648\u0627\u0631\u062f \u062d\u0633\u0627\u0628 \u0627\u062e\u062a\u0635\u0627\u0635\u06cc \u06af\u0648\u06af\u0644 \u062e\u0648\u062f \u0634\u0648\u06cc\u062f.\n\n---\n\n[[BUTTON: text=\"\ud83d\udd11 \u0648\u0631\u0648\u062f \u0628\u0647 \u062d\u0633\u0627\u0628 \u06af\u0648\u06af\u0644 (/login)\", cmd=\"/login\", row=1]]\n[[BUTTON: text=\"\ud83d\udccb \u0645\u0646\u0648\u06cc \u062d\u0633\u0627\u0628 \u06a9\u0627\u0631\u0628\u0631\u06cc (/account)\", cmd=\"/account\", row=1]]\n\n---\n\u2022 \u0646\u0627\u0645 \u067e\u0631\u0648\u0698\u0647: default \n\u2022 \u0622\u062f\u0631\u0633 \u0645\u062e\u0632\u0646: https://git.msa.artacloud.ir/root/default\n",
"last_status_msg_id": null,
"restart_pending": false,
"last_delivered": true,
"last_update_time": 1788167657.7782717,
"last_update_time": 1788167920.0001032,
"workspace": "/root",
"conversation_id": "24b9a436-7796-4fe5-ae65-f4a3307409d7",
"model": "gemini-3.7-flash-auto",
"effort": "high",
"language": "fa",
"last_context_length": 418396,
"last_total_tokens": 444230
"last_context_length": 555485,
"last_total_tokens": 596672
},
"232801087": {
"chat_id": 232801087,