tg-agent 1.1.2 → 1.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +14 -14
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,17 +1,17 @@
1
- import b from"node:path";import B from"node:fs/promises";import te from"node-telegram-bot-api";import{discoverAuthStorage as ne,discoverModels as oe}from"@mariozechner/pi-coding-agent";import{getOAuthProviders as re}from"@mariozechner/pi-ai";import{config as m,assertConfig as se}from"./config.js";import{resolveApiKeyForProvider as ie,resolveProxyInfo as ae}from"./auth.js";import{applyFetchProxy as ce}from"./proxy.js";import{runPiAgentPrompt as le}from"./piAgentRunner.js";import{readCodexOAuth as ue}from"./codexAuth.js";import{formatMcpTarget as de,freezeMcpCatalog as F,getMcpCatalog as q,loadMcpServers as me,loadMcpServersSync as fe,probeMcpServer as ge,refreshMcpCatalog as pe}from"./mcp.js";import{appendMessage as W,closeSession as we,createSession as L,deleteSessionFile as k,getActiveSession as x,listSessions as he,loadUserState as H,pruneExpiredSessions as X,resetSession as ye,saveUserState as w,setActiveSession as $e}from"./sessionStore.js";import{chunkText as ve,createQueueMap as Se,createSemaphore as Me,ensureDir as U,nowMs as C}from"./utils.js";se();const y=new te(m.telegramToken,{polling:!0}),_e=Se(),Ae=Me(m.maxConcurrent),O=new Map;function Pe(e,t){O.set(e,t)}function Te(e){O.delete(e)}function xe(e){const t=e.trim();if(t){if(t==="Markdown"||t==="MarkdownV2"||t==="HTML")return t;console.warn(`[tg-agent] invalid TELEGRAM_PARSE_MODE=${t}, ignoring`)}}const Ee="image/jpeg";function Re(){return b.join(m.agentDir,"uploads")}function ke(e){return e.length===0?null:e.reduce((t,n)=>{const o=t.file_size??t.width*t.height;return(n.file_size??n.width*n.height)>o?n:t})}function Ce(e){return!!e?.startsWith("image/")}function De(e){switch(b.extname(e).toLowerCase()){case".png":return"image/png";case".jpg":case".jpeg":return"image/jpeg";case".webp":return"image/webp";case".gif":return"image/gif";default:return}}function be(e){if(!Number.isFinite(e)||e<=0)return"0 B";const t=["B","KB","MB","GB"];let n=e,o=0;for(;n>=1024&&o<t.length-1;)n/=1024,o+=1;return`${n.toFixed(n>=10||o===0?0:1)} ${t[o]}`}function Le(e){return e.length===0?"":e.map(t=>{const n=[];t.mimeType&&n.push(t.mimeType),t.bytes>0&&n.push(be(t.bytes));const o=n.length>0?` (${n.join(", ")})`:"";return`Attachment saved: ${t.path}${o}`}).join(`
2
- `)}function Ue(e){const t=[];if(e.photo&&e.photo.length>0){const n=ke(e.photo);n&&t.push({kind:"photo",fileId:n.file_id,fileSize:n.file_size})}return e.document&&t.push({kind:"document",fileId:e.document.file_id,fileName:e.document.file_name,mimeType:e.document.mime_type,fileSize:e.document.file_size}),t}async function Oe(e){if(e.length===0)return{resolved:[],images:[]};const t=Re();await U(t);const n=[],o=[];for(const s of e)try{const a=await y.downloadFile(s.fileId,t),r=await B.stat(a),c=s.fileName??b.basename(a),u=s.mimeType??De(a),i=s.kind==="photo"||Ce(u),d={path:a,name:c,mimeType:u,bytes:r.size,isImage:i};if(n.push(d),i){const f=await B.readFile(a);o.push({type:"image",data:f.toString("base64"),mimeType:u??Ee})}}catch(a){console.warn("[tg-agent] attachment download failed",a)}return{resolved:n,images:o}}const ze=new Set(["_","*","[","]","(",")","~","`",">","#","+","-","=","|","{","}",".","!"]);function E(e,t){let n=0;for(let o=0;o<e.length;o+=1){const s=e[o];if(s==="\\"){o+=1;continue}s===t&&(n+=1)}return n}function Ne(e){if(E(e,"*")%2!==0||E(e,"_")%2!==0||E(e,"`")%2!==0)return!1;const s=E(e,"["),a=E(e,"]");return s===a}function je(e){for(let t=0;t<e.length;t+=1){const n=e[t];if(n==="\\"){t+=1;continue}if(ze.has(n))return!1}return!0}function V(e){const t=xe(m.telegramParseMode);return t?[t]:je(e)?["MarkdownV2","Markdown"]:Ne(e)?["Markdown"]:[]}const Be=600*1e3,S=new Map,z=new Set,Fe=new Map([["codex","openai-codex"],["antigravity","google-antigravity"],["gemini","google-gemini-cli"],["gemini-cli","google-gemini-cli"]]),qe={"codex-mini-latest":"gpt-5.1-codex-mini","codex-max-latest":"gpt-5.1-codex-max","codex-latest":"gpt-5.2-codex"};function A(e){const t=e.trim().toLowerCase();return Fe.get(t)??t}function We(e,t){return e!=="openai-codex"?t:qe[t]??t}async function P(){await U(m.agentDir);const e=ne(m.agentDir),t=ue();t&&e.setRuntimeApiKey("openai-codex",t.accessToken);const n=oe(e,m.agentDir);return{authStorage:e,modelRegistry:n}}function K(e){const t=S.get(e);t&&(clearTimeout(t.timeoutId),S.delete(e))}function He(e,t){const n=S.get(e);n&&(clearTimeout(n.timeoutId),S.delete(e),n.reject(new Error(t)))}async function G(e,t,n){if(S.has(e))throw new Error("Login is already awaiting input.");const o=n.placeholder?`${n.message} (${n.placeholder})`:n.message;return await l(t,o),await new Promise((s,a)=>{const r=setTimeout(()=>{S.delete(e),a(new Error("Login prompt timed out."))},Be);S.set(e,{resolve:s,reject:a,timeoutId:r,chatId:t})})}async function Xe(e,t){const n=O.get(t);if(!n){await l(e,"No active request to stop.");return}n.cancelRequested=!0,n.abortRequested=!0,n.status&&n.status.update("Cancelled by user.",!0),n.abort&&n.abort(),(!n.status||n.chatId!==e)&&await l(e,"Stopping current request...")}function Ve(){const e={https_proxy:process.env.https_proxy??process.env.HTTPS_PROXY??"",http_proxy:process.env.http_proxy??process.env.HTTP_PROXY??"",all_proxy:process.env.all_proxy??process.env.ALL_PROXY??"",no_proxy:process.env.no_proxy??process.env.NO_PROXY??""},t={NODE_EXTRA_CA_CERTS:process.env.NODE_EXTRA_CA_CERTS??"",NODE_TLS_REJECT_UNAUTHORIZED:process.env.NODE_TLS_REJECT_UNAUTHORIZED??""};console.log(`[tg-agent] modelProvider=${m.modelProvider} modelRef=${m.modelRef} sessionDir=${m.sessionDir} maxConcurrent=${m.maxConcurrent}`),console.log(`[tg-agent] agentDir=${m.agentDir} workspaceDir=${m.workspaceDir}`);const n=fe(m.agentDir),o=n.length>0?`on (${n.length})`:"off";console.log(`[tg-agent] tools fetchMaxBytes=${m.fetchMaxBytes} fetchTimeoutMs=${m.fetchTimeoutMs} mcp=${o}`),console.log(`[tg-agent] proxy https=${e.https_proxy||"(empty)"} http=${e.http_proxy||"(empty)"} all=${e.all_proxy||"(empty)"} no=${e.no_proxy||"(empty)"}`),console.log(`[tg-agent] tls extra_ca=${t.NODE_EXTRA_CA_CERTS||"(empty)"} reject_unauthorized=${t.NODE_TLS_REJECT_UNAUTHORIZED||"(empty)"}`);try{const{source:a}=ie(m.modelProvider);console.log(`[tg-agent] authSource=${a}`)}catch(a){const r=a instanceof Error?a.message:String(a);console.warn(`[tg-agent] authSource=missing (${r})`)}const s=ae();console.log(s?`[tg-agent] proxyUrl=${s.url} kind=${s.kind} source=${s.source}`:"[tg-agent] proxyUrl=(none)")}Ve(),U(m.agentDir).catch(e=>{console.warn(`[tg-agent] ensure agentDir failed: ${e instanceof Error?e.message:String(e)}`)}),(async()=>{try{await q(m.agentDir,{timeoutMs:3e3,maxBytes:m.fetchMaxBytes,maxChars:2e3}),F()}catch(e){const t=e instanceof Error?e.message:String(e);console.warn(`[tg-agent] mcp catalog warmup failed: ${t}`)}})();const D=ce();console.log(D?`[tg-agent] fetchProxy=${D.url} kind=${D.kind} source=${D.source}`:"[tg-agent] fetchProxy=(none)");function J(e){if(!e.startsWith("/"))return null;const t=e.trim(),[n,...o]=t.split(" ");return{command:n.split("@")[0].slice(1).toLowerCase(),args:o.join(" ").trim()}}async function Y(e,t){let n=x(e);return n||(n=L(e,""),await w(e),await l(t,`Created session ${n.id}.`)),n}function Ke(e,t){const n=e.getAll(),o=new Map;for(const a of n){const r=o.get(a.provider)??{count:0,auth:t.hasAuth(a.provider)};r.count+=1,o.set(a.provider,r)}return o.size===0?"No providers found.":["Providers:",...Array.from(o.entries()).sort((a,r)=>a[0].localeCompare(r[0])).map(([a,r])=>`- /provider ${a} (models: ${r.count}, auth: ${r.auth?"ok":"missing"})`),"","Use /models <provider> to list models."].join(`
3
- `)}function Ge(e,t,n){const o=e.getAll().filter(a=>a.provider===t);if(o.length===0)return`No models found for provider ${t}.`;const s=o.map(a=>`- /model ${t}/${a.id} | ${a.name}`);return[`Models for ${t} (auth: ${n?"ok":"missing"}):`,...s].join(`
4
- `)}function Je(e){const t=e.trim();if(!t)return null;if(t.includes("/")){const[n,o]=t.split("/",2);return!n||!o?null:{provider:A(n),modelId:o.trim()}}return{modelId:t}}const Ye=6e4,Z=new Map;function Ze(e,t){const n=Date.now(),o=Z.get(e)??0;n-o<Ye||(Z.set(e,n),console.warn(`[tg-agent] unauthorized user=${e} chat=${t}`))}function Qe(e){const t=m.telegramAllowedUsers;return!t||t.size===0?!0:t.has(e)}function Ie(e){return e.length===0?"No sessions found.":["Sessions:",...e.map(n=>{const o=new Date(n.updatedAt).toISOString();return`- ${n.id} | ${n.title} | updated ${o}`})].join(`
5
- `)}async function Q(e,t,n){return n?await y.sendMessage(e,t,{parse_mode:n}):await y.sendMessage(e,t)}async function I(e,t,n,o){if(o){await y.editMessageText(n,{chat_id:e,message_id:t,parse_mode:o});return}await y.editMessageText(n,{chat_id:e,message_id:t})}async function ee(e,t){let n;for(const o of t)try{return await e(o)}catch(s){n=s;const a=s instanceof Error?s.message:String(s);console.warn(`[tg-agent] parse_mode ${o} failed, trying fallback: ${a}`)}try{return await e(void 0)}catch(o){if(n){const s=o instanceof Error?o.message:String(o);console.warn(`[tg-agent] parse_mode fallback to plain failed: ${s}`)}throw o}}async function et(e,t){return await ee(n=>Q(e,t,n),V(t))}async function tt(e,t,n){await ee(o=>I(e,t,n,o),V(n))}async function l(e,t){const n=ve(t,3900);for(const o of n)await et(e,o)}const nt=3900,ot=1200;function N(e,t=nt){return e.length<=t?{text:e,truncated:!1}:{text:`${e.slice(0,Math.max(0,t-15))}...
1
+ import N from"node:path";import W from"node:fs/promises";import me from"node-telegram-bot-api";import{discoverAuthStorage as fe,discoverModels as ge}from"@mariozechner/pi-coding-agent";import{getOAuthProviders as pe}from"@mariozechner/pi-ai";import{config as m,assertConfig as we}from"./config.js";import{resolveApiKeyForProvider as he,resolveProxyInfo as ye}from"./auth.js";import{applyFetchProxy as $e}from"./proxy.js";import{runPiAgentPrompt as ve}from"./piAgentRunner.js";import{readCodexOAuth as Me}from"./codexAuth.js";import{formatMcpTarget as Se,freezeMcpCatalog as X,getMcpCatalog as H,loadMcpServers as _e,loadMcpServersSync as Ae,probeMcpServer as Pe,refreshMcpCatalog as Te}from"./mcp.js";import{appendMessage as K,closeSession as xe,createSession as O,deleteSessionFile as b,getActiveSession as C,listSessions as V,loadUserState as q,pruneExpiredSessions as G,resetSession as Ee,saveUserState as y,setActiveSession as Ce}from"./sessionStore.js";import{chunkText as ke,createQueueMap as Re,createSemaphore as be,ensureDir as U,nowMs as _,shortId as Q}from"./utils.js";we();const p=new me(m.telegramToken,{polling:!0}),J=Re(),De=be(m.maxConcurrent),z=new Map;function Le(e,t){z.set(e,t)}function Ne(e){z.delete(e)}function Oe(e){const t=e.trim();if(t){if(t==="Markdown"||t==="MarkdownV2"||t==="HTML")return t;console.warn(`[tg-agent] invalid TELEGRAM_PARSE_MODE=${t}, ignoring`)}}const Ue="image/jpeg";function ze(){return N.join(m.agentDir,"uploads")}function je(e){return e.length===0?null:e.reduce((t,n)=>{const o=t.file_size??t.width*t.height;return(n.file_size??n.width*n.height)>o?n:t})}function Be(e){return!!e?.startsWith("image/")}function Fe(e){switch(N.extname(e).toLowerCase()){case".png":return"image/png";case".jpg":case".jpeg":return"image/jpeg";case".webp":return"image/webp";case".gif":return"image/gif";default:return}}function We(e){if(!Number.isFinite(e)||e<=0)return"0 B";const t=["B","KB","MB","GB"];let n=e,o=0;for(;n>=1024&&o<t.length-1;)n/=1024,o+=1;return`${n.toFixed(n>=10||o===0?0:1)} ${t[o]}`}function Xe(e){return e.length===0?"":e.map(t=>{const n=[];t.mimeType&&n.push(t.mimeType),t.bytes>0&&n.push(We(t.bytes));const o=n.length>0?` (${n.join(", ")})`:"";return`Attachment saved: ${t.path}${o}`}).join(`
2
+ `)}function He(e){const t=[];if(e.photo&&e.photo.length>0){const n=je(e.photo);n&&t.push({kind:"photo",fileId:n.file_id,fileSize:n.file_size})}return e.document&&t.push({kind:"document",fileId:e.document.file_id,fileName:e.document.file_name,mimeType:e.document.mime_type,fileSize:e.document.file_size}),t}async function Ke(e){if(e.length===0)return{resolved:[],images:[]};const t=ze();await U(t);const n=[],o=[];for(const r of e)try{const a=await p.downloadFile(r.fileId,t),s=await W.stat(a),i=r.fileName??N.basename(a),l=r.mimeType??Fe(a),c=r.kind==="photo"||Be(l),u={path:a,name:i,mimeType:l,bytes:s.size,isImage:c};if(n.push(u),c){const f=await W.readFile(a);o.push({type:"image",data:f.toString("base64"),mimeType:l??Ue})}}catch(a){console.warn("[tg-agent] attachment download failed",a)}return{resolved:n,images:o}}const Ve=new Set(["_","*","[","]","(",")","~","`",">","#","+","-","=","|","{","}",".","!"]);function k(e,t){let n=0;for(let o=0;o<e.length;o+=1){const r=e[o];if(r==="\\"){o+=1;continue}r===t&&(n+=1)}return n}function qe(e){if(k(e,"*")%2!==0||k(e,"_")%2!==0||k(e,"`")%2!==0)return!1;const r=k(e,"["),a=k(e,"]");return r===a}function Ge(e){for(let t=0;t<e.length;t+=1){const n=e[t];if(n==="\\"){t+=1;continue}if(Ve.has(n))return!1}return!0}function Y(e){const t=Oe(m.telegramParseMode);return t?[t]:Ge(e)?["MarkdownV2","Markdown"]:qe(e)?["Markdown"]:[]}const Qe=600*1e3,S=new Map,j=new Set,Je=new Map([["codex","openai-codex"],["antigravity","google-antigravity"],["gemini","google-gemini-cli"],["gemini-cli","google-gemini-cli"]]),Ye={"codex-mini-latest":"gpt-5.1-codex-mini","codex-max-latest":"gpt-5.1-codex-max","codex-latest":"gpt-5.2-codex"};function T(e){const t=e.trim().toLowerCase();return Je.get(t)??t}function Ze(e,t){return e!=="openai-codex"?t:Ye[t]??t}async function x(){await U(m.agentDir);const e=fe(m.agentDir),t=Me();t&&e.setRuntimeApiKey("openai-codex",t.accessToken);const n=ge(e,m.agentDir);return{authStorage:e,modelRegistry:n}}function Z(e){const t=S.get(e);t&&(clearTimeout(t.timeoutId),S.delete(e))}function Ie(e,t){const n=S.get(e);n&&(clearTimeout(n.timeoutId),S.delete(e),n.reject(new Error(t)))}async function I(e,t,n){if(S.has(e))throw new Error("Login is already awaiting input.");const o=n.placeholder?`${n.message} (${n.placeholder})`:n.message;return await d(t,o),await new Promise((r,a)=>{const s=setTimeout(()=>{S.delete(e),a(new Error("Login prompt timed out."))},Qe);S.set(e,{resolve:r,reject:a,timeoutId:s,chatId:t})})}async function ee(e,t){const n=z.get(t);if(!n){await d(e,"No active request to stop.");return}n.cancelRequested=!0,n.abortRequested=!0,n.status&&n.status.update("Cancelled by user.",!0),n.abort&&n.abort(),(!n.status||n.chatId!==e)&&await d(e,"Stopping current request...")}function et(){const e={https_proxy:process.env.https_proxy??process.env.HTTPS_PROXY??"",http_proxy:process.env.http_proxy??process.env.HTTP_PROXY??"",all_proxy:process.env.all_proxy??process.env.ALL_PROXY??"",no_proxy:process.env.no_proxy??process.env.NO_PROXY??""},t={NODE_EXTRA_CA_CERTS:process.env.NODE_EXTRA_CA_CERTS??"",NODE_TLS_REJECT_UNAUTHORIZED:process.env.NODE_TLS_REJECT_UNAUTHORIZED??""};console.log(`[tg-agent] modelProvider=${m.modelProvider} modelRef=${m.modelRef} sessionDir=${m.sessionDir} maxConcurrent=${m.maxConcurrent}`),console.log(`[tg-agent] agentDir=${m.agentDir} workspaceDir=${m.workspaceDir}`);const n=Ae(m.agentDir),o=n.length>0?`on (${n.length})`:"off";console.log(`[tg-agent] tools fetchMaxBytes=${m.fetchMaxBytes} fetchTimeoutMs=${m.fetchTimeoutMs} mcp=${o}`),console.log(`[tg-agent] proxy https=${e.https_proxy||"(empty)"} http=${e.http_proxy||"(empty)"} all=${e.all_proxy||"(empty)"} no=${e.no_proxy||"(empty)"}`),console.log(`[tg-agent] tls extra_ca=${t.NODE_EXTRA_CA_CERTS||"(empty)"} reject_unauthorized=${t.NODE_TLS_REJECT_UNAUTHORIZED||"(empty)"}`);try{const{source:a}=he(m.modelProvider);console.log(`[tg-agent] authSource=${a}`)}catch(a){const s=a instanceof Error?a.message:String(a);console.warn(`[tg-agent] authSource=missing (${s})`)}const r=ye();console.log(r?`[tg-agent] proxyUrl=${r.url} kind=${r.kind} source=${r.source}`:"[tg-agent] proxyUrl=(none)")}et(),U(m.agentDir).catch(e=>{console.warn(`[tg-agent] ensure agentDir failed: ${e instanceof Error?e.message:String(e)}`)}),(async()=>{try{await H(m.agentDir,{timeoutMs:3e3,maxBytes:m.fetchMaxBytes,maxChars:2e3}),X()}catch(e){const t=e instanceof Error?e.message:String(e);console.warn(`[tg-agent] mcp catalog warmup failed: ${t}`)}})();const D=$e();console.log(D?`[tg-agent] fetchProxy=${D.url} kind=${D.kind} source=${D.source}`:"[tg-agent] fetchProxy=(none)");function B(e){if(!e.startsWith("/"))return null;const t=e.trim(),[n,...o]=t.split(" ");return{command:n.split("@")[0].slice(1).toLowerCase(),args:o.join(" ").trim()}}async function te(e,t){let n=C(e);return n||(n=O(e,""),await y(e),await d(t,`Created session ${n.id}.`)),n}function tt(e,t){const n=e.getAll(),o=new Map;for(const r of n){const a=o.get(r.provider)??{count:0,auth:t.hasAuth(r.provider)};a.count+=1,o.set(r.provider,a)}return Array.from(o.entries()).sort((r,a)=>r[0].localeCompare(a[0])).map(([r,a])=>({label:`${r} (${a.count}, ${a.auth?"ok":"no auth"})`,command:`/provider ${r}`}))}function nt(e,t,n=[]){const o=e.getAll().filter(i=>i.provider===t).sort((i,l)=>i.id.localeCompare(l.id));if(n.length===0)return o.map(i=>({label:i.id,command:`/model ${t}/${i.id}`}));const r=new Map(o.map(i=>[i.id,i])),a=new Set,s=[];for(const i of n){const l=r.get(i);!l||a.has(l.id)||(a.add(l.id),s.push(l))}for(const i of o)a.has(i.id)||s.push(i);return s.map(i=>({label:i.id,command:`/model ${t}/${i.id}`}))}function ot(e,t,n=3){const o=new Set,r=[],a=V(e);for(const s of a){if(s.modelProvider!==t)continue;const i=s.modelId;if(!(!i||o.has(i))&&(o.add(i),r.push(i),r.length>=n))break}return r}function rt(e){const t=e.trim();if(!t)return null;if(t.includes("/")){const[n,o]=t.split("/",2);return!n||!o?null:{provider:T(n),modelId:o.trim()}}return{modelId:t}}const st=6e4,ne=new Map;function oe(e,t){const n=Date.now(),o=ne.get(e)??0;n-o<st||(ne.set(e,n),console.warn(`[tg-agent] unauthorized user=${e} chat=${t}`))}function re(e){const t=m.telegramAllowedUsers;return!t||t.size===0?!0:t.has(e)}function it(e){return e.length===0?"No sessions found.":["Sessions:",...e.map(n=>{const o=new Date(n.updatedAt).toISOString();return`- ${n.id} | ${n.title} | updated ${o}`})].join(`
3
+ `)}async function se(e,t,n){return n?await p.sendMessage(e,t,{parse_mode:n}):await p.sendMessage(e,t)}async function ie(e,t,n,o){if(o){await p.editMessageText(n,{chat_id:e,message_id:t,parse_mode:o});return}await p.editMessageText(n,{chat_id:e,message_id:t})}async function ae(e,t){let n;for(const o of t)try{return await e(o)}catch(r){n=r;const a=r instanceof Error?r.message:String(r);console.warn(`[tg-agent] parse_mode ${o} failed, trying fallback: ${a}`)}try{return await e(void 0)}catch(o){if(n){const r=o instanceof Error?o.message:String(o);console.warn(`[tg-agent] parse_mode fallback to plain failed: ${r}`)}throw o}}async function at(e,t){return await ae(n=>se(e,t,n),Y(t))}async function ct(e,t,n){await ae(o=>ie(e,t,n,o),Y(n))}async function d(e,t){const n=ke(t,3900);for(const o of n)await at(e,o)}const ce=1800*1e3,le=2e3,lt=60,$=new Map;function dt(){const e=_()-ce;for(const[o,r]of $)r.createdAt<e&&$.delete(o);if($.size<=le)return;const t=Array.from($.entries()).sort((o,r)=>o[1].createdAt-r[1].createdAt),n=$.size-le;for(let o=0;o<n;o+=1)$.delete(t[o][0])}function ut(e){dt();let t=Q();for(;$.has(t);)t=Q();return $.set(t,{command:e,createdAt:_()}),t}function mt(e){if(!e.startsWith("cmd:"))return null;const t=e.slice(4),n=$.get(t);return n?_()-n.createdAt>ce?($.delete(t),null):n.command:null}function ft(e,t){if(e.length<=t)return[e];const n=[];for(let o=0;o<e.length;o+=t)n.push(e.slice(o,o+t));return n}function gt(e,t){const n=[];let o=[];for(const r of e){const a=ut(r.command);o.push({text:r.label,callback_data:`cmd:${a}`}),o.length>=t&&(n.push(o),o=[])}return o.length>0&&n.push(o),n}async function pt(e,t,n){return await p.sendMessage(e,t,{reply_markup:{inline_keyboard:n}})}async function de(e,t,n,o){const r=o?.perRow??1,a=o?.pageSize??lt,s=o?.footer,i=ft(n,a);for(let l=0;l<i.length;l+=1){const c=i[l],u=i.length>1?` (page ${l+1}/${i.length})`:"",f=[`${t}${u}`];s&&f.push(s);const g=gt(c,r);await pt(e,f.join(`
4
+ `),g)}}const wt=3900,ht=1200;function F(e,t=wt){return e.length<=t?{text:e,truncated:!1}:{text:`${e.slice(0,Math.max(0,t-15))}...
6
5
 
7
- [truncated]`,truncated:!0}}async function rt(e){const t="Working...",o=(await Q(e,t)).message_id;let s=t,a=0,r=Promise.resolve();const c=(i,d=!1)=>{const f=Date.now();!d&&f-a<ot||i!==s&&(s=i,a=f,r=r.then(async()=>{await I(e,o,i)}).catch(h=>{console.warn("[tg-agent] status edit failed",h)}))},u=i=>{s=i,a=Date.now(),r=r.then(async()=>{await tt(e,o,i)}).catch(d=>{console.warn("[tg-agent] status edit failed",d)})};return{update:(i,d=!1)=>{const f=N(i).text;c(f,d)},finalize:async i=>{const d=N(i).text;u(d),await r},fail:async i=>{const d=N(i).text;u(d),await r}}}function st(e){switch(e.type){case"agent_start":return"Working...";case"tool_start":return`Running tool: ${e.name}
8
- args: ${it(e.args)}`;case"tool_end":return e.ok?`Tool finished: ${e.name} (${e.durationMs}ms)`:`Tool failed: ${e.name} (${e.durationMs}ms)`;case"message_start":return e.role==="assistant"?"Generating reply...":null;case"message_end":return e.role==="assistant"?"Finalizing reply...":null;case"heartbeat":return`Working... ${Math.max(1,Math.round(e.elapsedMs/1e3))}s`;default:return null}}function it(e){try{const t=new WeakSet,n=200,o=12,s=12,a=3,r=(i,d)=>{if(i==null)return i;if(typeof i=="string")return i.length>n?`${i.slice(0,n)}...`:i;if(typeof i=="number"||typeof i=="boolean")return i;if(typeof i=="bigint")return i.toString();if(typeof i=="function")return"[function]";if(typeof i!="object")return String(i);if(t.has(i))return"[circular]";if(d>=a)return"[truncated]";if(t.add(i),Array.isArray(i)){const M=i.slice(0,s).map(g=>r(g,d+1));return i.length>s&&M.push("[truncated]"),M}const f=Object.entries(i),h={};for(const[M,g]of f.slice(0,o))h[M]=r(g,d+1);return f.length>o&&(h._truncated=!0),h},c=r(e,0),u=JSON.stringify(c);return u?u.length>700?`${u.slice(0,700)}...`:u:"null"}catch{return"[unavailable]"}}function j(e){const t=e instanceof Error?e.message:String(e),n=e?.cause;return n instanceof Error?`${t} (${n.message})`:n?`${t} (${String(n)})`:t}function at(e,t=140){return e.length<=t?e:`${e.slice(0,t-3)}...`}async function ct(){const e=await me(m.agentDir);if(e.length===0)return"No MCP servers configured. Add [mcp_servers.*] to ~/.tg-agent/config.toml.";const t=await Promise.all(e.map(o=>ge(o))),n=["MCP servers:"];for(let o=0;o<e.length;o+=1){const s=e[o],a=t[o],r=a.ok?"ok":`error: ${at(a.error??"unknown")}`;n.push(`- ${s.name} (${s.type}) ${de(s)} status=${r} (${a.durationMs}ms)`)}return n.join(`
9
- `)}async function lt(e,t,n,o){const s=await H(t),a=X(s);switch(a.length>0&&(await w(s),await Promise.all(a.map(r=>k(t,r).catch(c=>{console.warn(`[tg-agent] cleanup session file failed id=${r}`,c)})))),n){case"start":case"help":{const r=["Commands:","/new [title] - create a new session","/list - list sessions","/use <id> - switch active session","/close [id] - close a session (default: active)","/reset - clear active session history","/providers - list available providers","/models [provider] - list models for provider","/provider <name> - set provider for current session","/model <provider>/<model> - set model for current session","/mcp - list configured MCP servers","/mcp refresh - reload MCP catalog","/status - show session model settings","/login <provider> - login to OAuth provider","/logout <provider> - logout from provider","/stop - stop the current running request","","Tips:","Send images or files to attach them to the prompt."].join(`
10
- `);await l(e,r);return}case"new":{try{const c=L(s,o||"");await w(s),await l(e,`Created session ${c.id} (${c.title}).`)}catch(r){await l(e,r.message)}return}case"list":{await w(s),await l(e,Ie(he(s)));return}case"use":{if(!o){await l(e,"Usage: /use <id>");return}if(!$e(s,o)){await l(e,`Session not found: ${o}`);return}await w(s),await l(e,`Active session set to ${o}.`);return}case"close":{const r=o||s.activeSessionId;if(!r){await l(e,"No active session to close.");return}if(!we(s,r)){await l(e,`Session not found: ${r}`);return}await w(s),await k(t,r).catch(u=>{console.warn(`[tg-agent] delete session file failed id=${r}`,u)}),await l(e,`Closed session ${r}.`);return}case"reset":{const r=x(s);if(!r){await l(e,"No active session.");return}ye(r),await w(s),await k(t,r.id).catch(c=>{console.warn(`[tg-agent] reset session file failed id=${r.id}`,c)}),await l(e,`Reset session ${r.id}.`);return}case"providers":{const{authStorage:r,modelRegistry:c}=await P(),u=c.getError(),i=Ke(c,r),d=u?`Warning: ${u}
6
+ [truncated]`,truncated:!0}}async function yt(e){const t="Working...",o=(await se(e,t)).message_id;let r=t,a=0,s=Promise.resolve();const i=(c,u=!1)=>{const f=Date.now();!u&&f-a<ht||c!==r&&(r=c,a=f,s=s.then(async()=>{await ie(e,o,c)}).catch(g=>{console.warn("[tg-agent] status edit failed",g)}))},l=c=>{r=c,a=Date.now(),s=s.then(async()=>{await ct(e,o,c)}).catch(u=>{console.warn("[tg-agent] status edit failed",u)})};return{update:(c,u=!1)=>{const f=F(c).text;i(f,u)},finalize:async c=>{const u=F(c).text;l(u),await s},fail:async c=>{const u=F(c).text;l(u),await s}}}function $t(e){switch(e.type){case"agent_start":return"Working...";case"tool_start":return`Running tool: ${e.name}
7
+ args: ${vt(e.args)}`;case"tool_end":return e.ok?`Tool finished: ${e.name} (${e.durationMs}ms)`:`Tool failed: ${e.name} (${e.durationMs}ms)`;case"message_start":return e.role==="assistant"?"Generating reply...":null;case"message_end":return e.role==="assistant"?"Finalizing reply...":null;case"heartbeat":return`Working... ${Math.max(1,Math.round(e.elapsedMs/1e3))}s`;default:return null}}function vt(e){try{const t=new WeakSet,n=200,o=12,r=12,a=3,s=(c,u)=>{if(c==null)return c;if(typeof c=="string")return c.length>n?`${c.slice(0,n)}...`:c;if(typeof c=="number"||typeof c=="boolean")return c;if(typeof c=="bigint")return c.toString();if(typeof c=="function")return"[function]";if(typeof c!="object")return String(c);if(t.has(c))return"[circular]";if(u>=a)return"[truncated]";if(t.add(c),Array.isArray(c)){const A=c.slice(0,r).map(w=>s(w,u+1));return c.length>r&&A.push("[truncated]"),A}const f=Object.entries(c),g={};for(const[A,w]of f.slice(0,o))g[A]=s(w,u+1);return f.length>o&&(g._truncated=!0),g},i=s(e,0),l=JSON.stringify(i);return l?l.length>700?`${l.slice(0,700)}...`:l:"null"}catch{return"[unavailable]"}}function L(e){const t=e instanceof Error?e.message:String(e),n=e?.cause;return n instanceof Error?`${t} (${n.message})`:n?`${t} (${String(n)})`:t}function Mt(e,t=140){return e.length<=t?e:`${e.slice(0,t-3)}...`}async function St(){const e=await _e(m.agentDir);if(e.length===0)return"No MCP servers configured. Add [mcp_servers.*] to ~/.tg-agent/config.toml.";const t=await Promise.all(e.map(o=>Pe(o))),n=["MCP servers:"];for(let o=0;o<e.length;o+=1){const r=e[o],a=t[o],s=a.ok?"ok":`error: ${Mt(a.error??"unknown")}`;n.push(`- ${r.name} (${r.type}) ${Se(r)} status=${s} (${a.durationMs}ms)`)}return n.join(`
8
+ `)}async function ue(e,t,n,o){const r=await q(t),a=G(r);switch(a.length>0&&(await y(r),await Promise.all(a.map(s=>b(t,s).catch(i=>{console.warn(`[tg-agent] cleanup session file failed id=${s}`,i)})))),n){case"start":case"help":{const s=["Commands:","/new [title] - create a new session","/list - list sessions","/use <id> - switch active session","/close [id] - close a session (default: active)","/reset - clear active session history","/providers - list available providers","/models [provider] - list models for provider","/provider <name> - set provider for current session","/model <provider>/<model> - set model for current session","/mcp - list configured MCP servers","/mcp refresh - reload MCP catalog","/status - show session model settings","/login <provider> - login to OAuth provider","/logout <provider> - logout from provider","/stop - stop the current running request","","Tips:","Send images or files to attach them to the prompt."].join(`
9
+ `);await d(e,s);return}case"new":{try{const i=O(r,o||"");await y(r),await d(e,`Created session ${i.id} (${i.title}).`)}catch(s){await d(e,s.message)}return}case"list":{await y(r),await d(e,it(V(r)));return}case"use":{if(!o){await d(e,"Usage: /use <id>");return}if(!Ce(r,o)){await d(e,`Session not found: ${o}`);return}await y(r),await d(e,`Active session set to ${o}.`);return}case"close":{const s=o||r.activeSessionId;if(!s){await d(e,"No active session to close.");return}if(!xe(r,s)){await d(e,`Session not found: ${s}`);return}await y(r),await b(t,s).catch(l=>{console.warn(`[tg-agent] delete session file failed id=${s}`,l)}),await d(e,`Closed session ${s}.`);return}case"reset":{const s=C(r);if(!s){await d(e,"No active session.");return}Ee(s),await y(r),await b(t,s.id).catch(i=>{console.warn(`[tg-agent] reset session file failed id=${s.id}`,i)}),await d(e,`Reset session ${s.id}.`);return}case"providers":{const{authStorage:s,modelRegistry:i}=await x(),l=i.getError(),c=tt(i,s);if(c.length===0){const f=l?`Warning: ${l}
11
10
 
12
- ${i}`:i;await l(e,d);return}case"models":{const{authStorage:r,modelRegistry:c}=await P();let u=o?A(o):"";if(!u){const d=x(s);if(!d?.modelProvider){await l(e,"Usage: /models <provider>");return}u=d.modelProvider}const i=r.hasAuth(u);await l(e,Ge(c,u,i));return}case"provider":{if(!o){await l(e,"Usage: /provider <name>");return}const r=A(o),{modelRegistry:c}=await P();if(!c.getAll().some(d=>d.provider===r)){await l(e,`Unknown provider: ${r}`);return}const i=await Y(s,e);i.modelProvider=r,i.modelId=void 0,i.updatedAt=C(),await w(s),await l(e,`Session ${i.id} provider set to ${r}.`);return}case"model":{const r=Je(o);if(!r){await l(e,"Usage: /model <provider>/<model>");return}const c=await Y(s,e),u=A(r.provider??c.modelProvider??"");if(!u){await l(e,"Usage: /model <provider>/<model>");return}const{modelRegistry:i}=await P(),d=We(u,r.modelId);if(!i.find(u,d)){await l(e,`Model not found: ${u}/${d}`);return}c.modelProvider=u,c.modelId=d,c.updatedAt=C(),await w(s),await l(e,`Session ${c.id} model set to ${u}/${d}.`);return}case"status":{const r=x(s);if(!r){await l(e,"No active session.");return}const c=m.modelRef.includes("/")?m.modelRef:`${m.modelProvider}/${m.modelRef}`,u=r.modelProvider||r.modelId?`Session model: ${r.modelProvider??"?"}/${r.modelId??"?"}`:`Default model: ${c}`,i=[`Session: ${r.id} (${r.title})`,u].join(`
13
- `);await l(e,i);return}case"mcp":{if(o.trim().toLowerCase()==="refresh"){pe(),await q(m.agentDir,{timeoutMs:5e3,maxBytes:m.fetchMaxBytes,maxChars:3e3}),F(),await l(e,"MCP catalog refreshed.");return}const r=await ct();await l(e,r);return}case"login":{const r=re();if(!o){const i=r.map(d=>`- ${d.id} (${d.name})`);await l(e,["OAuth providers:",...i].join(`
14
- `));return}const c=A(o);if(z.has(t)){await l(e,"Login already in progress.");return}const u=r.find(i=>i.id===c);if(!u){await l(e,`Unknown OAuth provider: ${c}`);return}z.add(t);try{const{authStorage:i}=await P();await l(e,`Starting login for ${u.id}...`),await i.login(u.id,{onAuth:({url:d,instructions:f})=>{const h=["Open this URL in your browser:",d];f&&h.push("",f),l(e,h.join(`
15
- `))},onPrompt:d=>G(t,e,d),onProgress:d=>{l(e,d)},onManualCodeInput:()=>G(t,e,{message:"Paste the authorization code:"})}),await l(e,`Login completed for ${u.id}.`)}catch(i){const d=j(i);await l(e,`Login failed: ${d}`)}finally{z.delete(t),K(t)}return}case"logout":{if(!o){await l(e,"Usage: /logout <provider>");return}const r=A(o),{authStorage:c}=await P();c.logout(r),await l(e,`Logged out from ${r}.`);return}default:await l(e,`Unknown command: ${n}`)}}async function ut(e,t,n,o=[]){const s=J(n);if(s){await lt(e,t,s.command,s.args);return}const a=await H(t),r=X(a);r.length>0&&(await w(a),await Promise.all(r.map(p=>k(t,p).catch(_=>{console.warn(`[tg-agent] cleanup session file failed id=${p}`,_)}))));let c=x(a);if(!c)try{c=L(a,""),await w(a),await l(e,`Created session ${c.id}.`)}catch(p){await l(e,p.message);return}const{resolved:u,images:i}=await Oe(o);if(o.length>0&&u.length===0&&!n.trim()){await l(e,"Failed to download attachments.");return}const d=Le(u),f=[];n.trim()&&f.push(n.trim()),d&&f.push(d);const h=f.join(`
11
+ No providers found.`:"No providers found.";await d(e,f);return}const u=[];l&&u.push(`Warning: ${l}`),u.push("Providers:"),await de(e,u.join(`
12
+ `),c,{perRow:1,footer:"Tap a provider to set it. Use /models <provider> to list models."});return}case"models":{const{authStorage:s,modelRegistry:i}=await x();let l=o?T(o):"";if(!l){const g=C(r);if(!g?.modelProvider){await d(e,"Usage: /models <provider>");return}l=g.modelProvider}const c=s.hasAuth(l),u=ot(r,l),f=nt(i,l,u);if(f.length===0){await d(e,`No models found for provider ${l}.`);return}await de(e,`Models for ${l} (auth: ${c?"ok":"missing"}):`,f,{perRow:1,footer:"Tap a model to set it."});return}case"provider":{if(!o){await d(e,"Usage: /provider <name>");return}const s=T(o),{modelRegistry:i}=await x();if(!i.getAll().some(u=>u.provider===s)){await d(e,`Unknown provider: ${s}`);return}const c=await te(r,e);c.modelProvider=s,c.modelId=void 0,c.updatedAt=_(),await y(r),await d(e,`Session ${c.id} provider set to ${s}.`);return}case"model":{const s=rt(o);if(!s){await d(e,"Usage: /model <provider>/<model>");return}const i=await te(r,e),l=T(s.provider??i.modelProvider??"");if(!l){await d(e,"Usage: /model <provider>/<model>");return}const{modelRegistry:c}=await x(),u=Ze(l,s.modelId);if(!c.find(l,u)){await d(e,`Model not found: ${l}/${u}`);return}i.modelProvider=l,i.modelId=u,i.updatedAt=_(),await y(r),await d(e,`Session ${i.id} model set to ${l}/${u}.`);return}case"status":{const s=C(r);if(!s){await d(e,"No active session.");return}const i=m.modelRef.includes("/")?m.modelRef:`${m.modelProvider}/${m.modelRef}`,l=s.modelProvider||s.modelId?`Session model: ${s.modelProvider??"?"}/${s.modelId??"?"}`:`Default model: ${i}`,c=[`Session: ${s.id} (${s.title})`,l].join(`
13
+ `);await d(e,c);return}case"mcp":{if(o.trim().toLowerCase()==="refresh"){Te(),await H(m.agentDir,{timeoutMs:5e3,maxBytes:m.fetchMaxBytes,maxChars:3e3}),X(),await d(e,"MCP catalog refreshed.");return}const s=await St();await d(e,s);return}case"login":{const s=pe();if(!o){const c=s.map(u=>`- ${u.id} (${u.name})`);await d(e,["OAuth providers:",...c].join(`
14
+ `));return}const i=T(o);if(j.has(t)){await d(e,"Login already in progress.");return}const l=s.find(c=>c.id===i);if(!l){await d(e,`Unknown OAuth provider: ${i}`);return}j.add(t);try{const{authStorage:c}=await x();await d(e,`Starting login for ${l.id}...`),await c.login(l.id,{onAuth:({url:u,instructions:f})=>{const g=["Open this URL in your browser:",u];f&&g.push("",f),d(e,g.join(`
15
+ `))},onPrompt:u=>I(t,e,u),onProgress:u=>{d(e,u)},onManualCodeInput:()=>I(t,e,{message:"Paste the authorization code:"})}),await d(e,`Login completed for ${l.id}.`)}catch(c){const u=L(c);await d(e,`Login failed: ${u}`)}finally{j.delete(t),Z(t)}return}case"logout":{if(!o){await d(e,"Usage: /logout <provider>");return}const s=T(o),{authStorage:i}=await x();i.logout(s),await d(e,`Logged out from ${s}.`);return}default:await d(e,`Unknown command: ${n}`)}}async function _t(e,t,n,o=[]){const r=B(n);if(r){await ue(e,t,r.command,r.args);return}const a=await q(t),s=G(a);s.length>0&&(await y(a),await Promise.all(s.map(h=>b(t,h).catch(P=>{console.warn(`[tg-agent] cleanup session file failed id=${h}`,P)}))));let i=C(a);if(!i)try{i=O(a,""),await y(a),await d(e,`Created session ${i.id}.`)}catch(h){await d(e,h.message);return}const{resolved:l,images:c}=await Ke(o);if(o.length>0&&l.length===0&&!n.trim()){await d(e,"Failed to download attachments.");return}const u=Xe(l),f=[];n.trim()&&f.push(n.trim()),u&&f.push(u);const g=f.join(`
16
16
 
17
- `)||"Attachment received.",M={role:"user",content:h,ts:C()};W(c,M,m.maxHistoryMessages),await w(a),console.log(`[tg-agent] request user=${t} session=${c.id} messages=${c.messages.length} textLen=${h.length} attachments=${u.length} provider=${c.modelProvider??"-"} model=${c.modelId??"-"}`);let g=null;try{g=await rt(e)}catch(p){console.warn("[tg-agent] status message failed",p)}const T={sessionId:c.id,chatId:e,status:g,abortRequested:!1,cancelRequested:!1};Pe(t,T);try{const p=await Ae(async()=>{const R=await le({userId:t,sessionId:c.id,prompt:h,images:i,systemPrompt:m.systemPrompt,modelProvider:c.modelProvider,modelId:c.modelId,telegram:{chatId:e,sendPhoto:async($,v)=>{await y.sendPhoto(e,$,v?{caption:v}:void 0)},sendDocument:async($,v)=>{await y.sendDocument(e,$,v?{caption:v}:void 0)}},onAbortReady:$=>{T.abort=$,T.abortRequested&&$()},onStatus:g?$=>{const v=st($);v&&g?.update(v)}:void 0});return console.log(`[tg-agent] response session=${c.id} model=${R.modelProvider}/${R.modelId} file=${R.sessionFile}`),R.text});if(T.cancelRequested){g?await g.finalize("Cancelled by user."):await l(e,"Cancelled by user.");return}const _={role:"assistant",content:p,ts:C()};W(c,_,m.maxHistoryMessages),await w(a),g?await g.finalize(p):await l(e,p)}catch(p){if(console.error("[tg-agent] runModel error",p),T.cancelRequested){g?await g.fail("Cancelled by user."):await l(e,"Cancelled by user.");return}const _=j(p);g?await g.fail(`Error: ${_}`):await l(e,`Error: ${_}`)}finally{Te(t)}}y.on("message",e=>{if(e.chat.type!=="private"){y.sendMessage(e.chat.id,"This bot only supports direct messages.");return}if(!e.from?.id)return;const t=String(e.from.id),n=e.chat.id;if(!Qe(t)){Ze(t,n);return}const o=(e.text??e.caption??"").trim(),s=Ue(e);if(!o&&s.length===0)return;const a=S.get(t);if(a){if(o==="/stop"||o==="/cancel"){He(t,"Login cancelled by user."),l(n,"Login cancelled.");return}if(!o){l(n,"Login expects a text response.");return}K(t),a.resolve(o);return}if(J(o)?.command==="stop"){Xe(n,t);return}_e(t,()=>ut(n,t,o,s)).catch(async c=>{console.error("[tg-agent] runModel error",c);const u=j(c);await l(n,`Error: ${u}`)})}),y.on("polling_error",e=>{console.error("Polling error",e)}),console.log("tg-agent started");
17
+ `)||"Attachment received.",A={role:"user",content:g,ts:_()};K(i,A,m.maxHistoryMessages),await y(a),console.log(`[tg-agent] request user=${t} session=${i.id} messages=${i.messages.length} textLen=${g.length} attachments=${l.length} provider=${i.modelProvider??"-"} model=${i.modelId??"-"}`);let w=null;try{w=await yt(e)}catch(h){console.warn("[tg-agent] status message failed",h)}const E={sessionId:i.id,chatId:e,status:w,abortRequested:!1,cancelRequested:!1};Le(t,E);try{const h=await De(async()=>{const R=await ve({userId:t,sessionId:i.id,prompt:g,images:c,systemPrompt:m.systemPrompt,modelProvider:i.modelProvider,modelId:i.modelId,telegram:{chatId:e,sendPhoto:async(v,M)=>{await p.sendPhoto(e,v,M?{caption:M}:void 0)},sendDocument:async(v,M)=>{await p.sendDocument(e,v,M?{caption:M}:void 0)}},onAbortReady:v=>{E.abort=v,E.abortRequested&&v()},onStatus:w?v=>{const M=$t(v);M&&w?.update(M)}:void 0});return console.log(`[tg-agent] response session=${i.id} model=${R.modelProvider}/${R.modelId} file=${R.sessionFile}`),R.text});if(E.cancelRequested){w?await w.finalize("Cancelled by user."):await d(e,"Cancelled by user.");return}const P={role:"assistant",content:h,ts:_()};K(i,P,m.maxHistoryMessages),await y(a),w?await w.finalize(h):await d(e,h)}catch(h){if(console.error("[tg-agent] runModel error",h),E.cancelRequested){w?await w.fail("Cancelled by user."):await d(e,"Cancelled by user.");return}const P=L(h);w?await w.fail(`Error: ${P}`):await d(e,`Error: ${P}`)}finally{Ne(t)}}p.on("callback_query",e=>{const t=e.data??"",n=e.message?.chat.id;if(!e.from?.id||!n){p.answerCallbackQuery(e.id);return}const o=String(e.from.id);if(!re(o)){oe(o,n),p.answerCallbackQuery(e.id);return}if(!t.startsWith("cmd:")){p.answerCallbackQuery(e.id);return}const r=mt(t);if(!r){p.answerCallbackQuery(e.id,{text:"Command expired."});return}p.answerCallbackQuery(e.id),J(o,async()=>{const a=B(r);if(!a){await d(n,"Invalid command.");return}if(a.command==="stop"){await ee(n,o);return}await ue(n,o,a.command,a.args)}).catch(async a=>{console.error("[tg-agent] runModel error",a);const s=L(a);await d(n,`Error: ${s}`)})}),p.on("message",e=>{if(e.chat.type!=="private"){p.sendMessage(e.chat.id,"This bot only supports direct messages.");return}if(!e.from?.id)return;const t=String(e.from.id),n=e.chat.id;if(!re(t)){oe(t,n);return}const o=(e.text??e.caption??"").trim(),r=He(e);if(!o&&r.length===0)return;const a=S.get(t);if(a){if(o==="/stop"||o==="/cancel"){Ie(t,"Login cancelled by user."),d(n,"Login cancelled.");return}if(!o){d(n,"Login expects a text response.");return}Z(t),a.resolve(o);return}if(B(o)?.command==="stop"){ee(n,t);return}J(t,()=>_t(n,t,o,r)).catch(async i=>{console.error("[tg-agent] runModel error",i);const l=L(i);await d(n,`Error: ${l}`)})}),p.on("polling_error",e=>{console.error("Polling error",e)}),console.log("tg-agent started");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tg-agent",
3
- "version": "1.1.2",
3
+ "version": "1.1.3",
4
4
  "description": "Telegram Codex agent",
5
5
  "type": "module",
6
6
  "bin": {