AI Update: تایید
This commit is contained in:
@@ -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():
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user