tg-agent 1.5.0 → 1.6.1
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.
- package/dist/cli.js +57 -45
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var
|
|
3
|
-
`);s>t*.6&&(r=r.slice(0,s)),n.push(r),o=o.slice(r.length)}return o.length>0&&n.push(o),n}function
|
|
2
|
+
var F=(e,t)=>()=>(e&&(t=e(e=0)),t);import Ve from"node:fs/promises";import oo from"node:os";import Re from"node:path";import{randomUUID as Rt}from"node:crypto";function z(){return Date.now()}function B(e){return e.startsWith("~")?Re.join(oo.homedir(),e.slice(1)):e}async function T(e){await Ve.mkdir(e,{recursive:!0})}async function Ce(e,t){let n=Re.dirname(e),o=`${Re.basename(e)}.${Rt()}.tmp`,r=Re.join(n,o),s=JSON.stringify(t,null,2);await Ve.writeFile(r,s,"utf8"),await Ve.rename(r,e)}function ae(){return Rt().split("-")[0]}function Xe(e,t){if(e.length<=t)return[e];let n=[],o=e;for(;o.length>t;){let r=o.slice(0,t),s=r.lastIndexOf(`
|
|
3
|
+
`);s>t*.6&&(r=r.slice(0,s)),n.push(r),o=o.slice(r.length)}return o.length>0&&n.push(o),n}function Ct(){let e=new Map;return async function(n,o){let s=(e.get(n)??Promise.resolve()).then(o,o);e.set(n,s);try{return await s}finally{e.get(n)===s&&e.delete(n)}}}function Tt(e){let t=0,n=[],o=()=>{if(t>=e)return;let r=n.shift();r&&(t+=1,r())};return async function(s){await new Promise(l=>{n.push(l),o()});try{return await s()}finally{t=Math.max(0,t-1),o()}}}var G=F(()=>{"use strict"});import Dt from"node:fs";import be from"node:path";import*as De from"@iarna/toml";function jt(){let e=B(Et);return be.join(e,ro)}function O(e,t){let n=e[t];return n&&typeof n=="object"&&!Array.isArray(n)?n:{}}function C(e,t){return typeof e=="string"?e:typeof e=="number"||typeof e=="boolean"?String(e):t}function q(e,t){if(typeof e=="number"&&Number.isFinite(e))return e;if(typeof e=="string"){let n=Number.parseInt(e,10);return Number.isNaN(n)?t:n}return t}function de(e,t){if(typeof e=="boolean")return e;if(typeof e=="string"){let n=e.trim().toLowerCase();if(n==="true"||n==="1"||n==="yes")return!0;if(n==="false"||n==="0"||n==="no")return!1}return t}function It(e){return Array.isArray(e)?e.map(t=>typeof t=="string"?t:String(t)).map(t=>t.trim()).filter(Boolean):typeof e=="string"?e.split(",").map(t=>t.trim()).filter(Boolean):[]}function so(e){return new Set(It(e))}function io(e){let t=new Map;for(let[n,o]of Object.entries(e))typeof o=="string"&&o.trim()&&t.set(n,be.resolve(B(o.trim())));return t}function ve(){let e=jt();try{let t=Dt.readFileSync(e,"utf8"),n=De.parse(t);return{configPath:e,data:n,exists:!0}}catch{return{configPath:e,data:{},exists:!1}}}async function Qe(e,t){await T(be.dirname(e));let n=De.stringify(t);await Dt.promises.writeFile(e,n,"utf8")}function Nt(){return{telegram:{bot_token:"",allowed_user_ids:[],parse_mode:""},model:{provider:"openai-codex",model:"gpt-5.2",openai_api_key:""},paths:{workspace_dir:"",session_dir:"~/.tg-agent/tg-sessions",restart_script_path:""},workspace_mappings:{},limits:{max_sessions:5,max_concurrent:5,max_history_messages:40,max_output_tokens:0},timeouts:{model_timeout_ms:6e4,model_timeout_stream_ms:3e5,fetch_timeout_ms:6e4},fetch:{max_bytes:2e5,proxy_url:""},proxy:{url:""},auth:{codex_home:"~/.codex"},logging:{agent_events:!0,agent_stream:!0},system:{prompt:Ot},tls:{extra_ca_certs:"",reject_unauthorized:""},security_audit:{enabled:!1,model_provider:"",model_id:"",whitelist_patterns:[],confirm_timeout_ms:12e4},memory:{enabled:!0,model_provider:"",model_id:"",system_prompt:"",rag:{enabled:!0,embedding_model:"openai/text-embedding-3-small",embedding_base_url:"",embedding_api_key:"",similarity_threshold:.5,max_results:5}}}}function Te(e){return!!(e&&typeof e=="object"&&!Array.isArray(e))}function Lt(e,t){let n=!1,o=(r,s)=>{for(let[l,a]of Object.entries(s)){if(!(l in r)){r[l]=a,n=!0;continue}let u=r[l];Te(u)&&Te(a)&&o(u,a)}};return Te(e)&&Te(t)&&o(e,t),n}function Ft(e){let t=O(e,"telegram");return C(t.bot_token,"").trim()}function zt(e,t){let n=O(e,"telegram");n.bot_token=t.trim(),e.telegram=n}function Ut(e){let t=O(e,"telegram"),n=O(e,"model"),o=O(e,"paths"),r=O(e,"limits"),s=O(e,"timeouts"),l=O(e,"fetch"),a=O(e,"proxy"),u=O(e,"auth"),m=O(e,"logging"),i=O(e,"system"),c=O(e,"tls"),d=O(e,"workspace_mappings"),p=O(e,"security_audit"),y=O(e,"memory"),h=O(y,"rag"),b=C(o.workspace_dir,process.cwd()),$=C(o.session_dir,"~/.tg-agent/tg-sessions"),A=io(d),M=C(c.reject_unauthorized,""),R=M===""?null:de(M,!0);return{telegramToken:C(t.bot_token,"").trim(),telegramAllowedUsers:so(t.allowed_user_ids),telegramParseMode:C(t.parse_mode,"").trim(),modelProvider:C(n.provider,"openai-codex").trim(),modelRef:C(n.model,"gpt-5.2").trim(),openaiApiKey:C(n.openai_api_key,"").trim(),sessionDir:B($),agentDir:B(Et),restartScriptPath:(()=>{let _=C(o.restart_script_path,"").trim();return _?be.resolve(B(_)):""})(),workspaceDir:be.resolve(B(b)),workspaceMappings:A,maxSessions:q(r.max_sessions,5),maxConcurrent:q(r.max_concurrent,5),maxHistoryMessages:q(r.max_history_messages,40),maxOutputTokens:q(r.max_output_tokens,0),fetchMaxBytes:q(l.max_bytes,2e5),fetchTimeoutMs:q(s.fetch_timeout_ms,6e4),modelTimeoutMs:q(s.model_timeout_ms,6e4),modelTimeoutStreamingMs:q(s.model_timeout_stream_ms,3e5),systemPrompt:C(i.prompt,Ot),proxyUrl:C(a.url,"").trim(),fetchProxyUrl:C(l.proxy_url,"").trim(),codexHome:B(C(u.codex_home,"~/.codex")),logAgentEvents:de(m.agent_events,!0),logAgentStream:de(m.agent_stream,!0),tlsExtraCaCerts:C(c.extra_ca_certs,"").trim(),tlsRejectUnauthorized:R,audit:{enabled:de(p.enabled,!1),modelProvider:C(p.model_provider,"").trim(),modelId:C(p.model_id,"").trim(),whitelistPatterns:It(p.whitelist_patterns),confirmTimeoutMs:q(p.confirm_timeout_ms,6e4)},memory:{enabled:de(y.enabled,!0),modelProvider:C(y.model_provider,"").trim(),modelId:C(y.model_id,"").trim(),systemPrompt:C(y.system_prompt,"").trim(),rag:{enabled:de(h.enabled,!0),embeddingModel:C(h.embedding_model,"openai/text-embedding-3-small").trim(),embeddingBaseUrl:C(h.embedding_base_url,"").trim(),embeddingApiKey:C(h.embedding_api_key,"").trim(),similarityThreshold:q(h.similarity_threshold,.5),maxResults:q(h.max_results,5)}}}}function Bt(){let{data:e}=ve();return g=Ut(e),g}function Kt(){let e=[];if(g.telegramToken||e.push("telegram.bot_token"),e.length>0)throw new Error(`Missing config values: ${e.join(", ")} (edit ${jt()})`)}var Et,ro,Ot,ao,g,K=F(()=>{"use strict";G();Et="~/.tg-agent",ro="config.toml",Ot=`You are running in user's personal computer or VPS, using telegram bot to interact with user.
|
|
4
4
|
|
|
5
5
|
Important behavioral rules:
|
|
6
6
|
- Do NOT mention the name of your underlying framework, technical implementation, or any package names
|
|
@@ -9,23 +9,23 @@ Important behavioral rules:
|
|
|
9
9
|
- Focus on helping with tasks rather than discussing your technical stack or architecture
|
|
10
10
|
- Do not mention documentation paths or framework-specific resources unless directly relevant to the task
|
|
11
11
|
|
|
12
|
-
Be concise and practical in all responses.`;({data:
|
|
13
|
-
`);return
|
|
14
|
-
(truncated)`),
|
|
15
|
-
`)})};fetch("http://127.0.0.1:7243/ingest/9e452bb4-cc67-4519-89fa-8fb51d810231",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({location:"mcp.ts:callStdioMcp:beforeInit",message:"sending initialize request",data:{elapsed:Date.now()-s},timestamp:Date.now(),sessionId:"debug-session",hypothesisId:"B,C"})}).catch(()=>{});let
|
|
16
|
-
`),fetch("http://127.0.0.1:7243/ingest/9e452bb4-cc67-4519-89fa-8fb51d810231",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({location:"mcp.ts:callStdioMcp:beforeMethod",message:"sending method request",data:{method:t,elapsed:Date.now()-s},timestamp:Date.now(),sessionId:"debug-session",hypothesisId:"C"})}).catch(()=>{});let
|
|
12
|
+
Be concise and practical in all responses.`;({data:ao}=ve()),g=Ut(ao)});import{createHash as co}from"node:crypto";import Jt from"node:fs";import lo from"node:path";import{execSync as uo}from"node:child_process";function po(){return lo.join(g.codexHome,mo)}function fo(e){return`cli|${co("sha256").update(e).digest("hex").slice(0,16)}`}function yo(){if(process.platform!=="darwin")return null;let e=g.codexHome,t=fo(e);try{let n=uo(`security find-generic-password -s "${go}" -a "${t}" -w`,{encoding:"utf8",timeout:5e3,stdio:["pipe","pipe","pipe"]}).trim(),o=JSON.parse(n),r=o.tokens,s=r?.access_token,l=r?.refresh_token;if(typeof s!="string"||!s||typeof l!="string"||!l)return null;let a=o.last_refresh,u=typeof a=="string"||typeof a=="number"?new Date(a).getTime():Date.now(),m=Number.isFinite(u)?u+3600*1e3:Date.now()+3600*1e3;return{accessToken:s,refreshToken:l,expiresAt:m,source:"keychain"}}catch{return null}}function ho(){let e=po();try{let t=Jt.readFileSync(e,"utf8"),o=JSON.parse(t).tokens,r=o?.access_token,s=o?.refresh_token;if(typeof r!="string"||!r||typeof s!="string"||!s)return null;let l=Date.now()+3600*1e3;try{l=Jt.statSync(e).mtimeMs+3600*1e3}catch{}return{accessToken:r,refreshToken:s,expiresAt:l,source:"file"}}catch{return null}}function Y(){return yo()??ho()}var mo,go,me=F(()=>{"use strict";K();mo="auth.json",go="Codex Auth"});function Wt(e){let t=e.trim().toLowerCase();if(t==="openai-codex"||t==="codex"){let n=Y();if(n)return{apiKey:n.accessToken,source:`codex:${n.source}`};throw new Error("No Codex OAuth credentials found. Run `codex login`.")}if(g.openaiApiKey)return{apiKey:g.openaiApiKey,source:"config.model.openai_api_key"};throw new Error(`No API key for provider: ${e}`)}function wo(){return g.proxyUrl?{url:g.proxyUrl,source:"config.proxy.url"}:g.fetchProxyUrl?{url:g.fetchProxyUrl,source:"config.fetch.proxy_url"}:null}function Ht(e){let t=e.toLowerCase();return t.startsWith("socks5://")||t.startsWith("socks4://")||t.startsWith("socks://")?"socks":t.startsWith("https://")?"https":"http"}function qt(){let e=wo();return e?{url:e.url,kind:Ht(e.url),source:e.source}:null}function Gt(){let e=[{key:"config.fetch.proxy_url",value:g.fetchProxyUrl},{key:"config.proxy.url",value:g.proxyUrl}];for(let t of e){let n=t.value?.trim();if(!n)continue;let o=Ht(n);if(o!=="socks")return{url:n,kind:o,source:t.key}}return null}var Ze=F(()=>{"use strict";K();me()});import{ProxyAgent as bo,setGlobalDispatcher as vo}from"undici";function Vt(){if(Yt)return et;Yt=!0;let e=Gt();if(!e)return et=null,null;let t=new bo(e.url);return vo(t),et=e,e}var Yt,et,Xt=F(()=>{"use strict";Ze();Yt=!1,et=null});import xo from"node:fs";import So from"node:fs/promises";import Mo from"node:path";import $o from"node:readline";import{spawn as Ao}from"node:child_process";import*as Zt from"@iarna/toml";function nn(e){return Mo.join(e,"config.toml")}function Ee(e){let t=nn(e);try{let n=xo.readFileSync(t,"utf8");return an(n)}catch{return[]}}async function xe(e){let t=nn(e);try{let n=await So.readFile(t,"utf8");return an(n)}catch{return[]}}async function Se(e,t={}){if(ge)return ge;let n=await xe(e);if(n.length===0)return ge="","";let o=t.maxTools??Po,r=t.maxChars??_o,s=t.timeoutMs??4e3,l=t.maxBytes??en,a=["MCP catalog (auto-discovered):","Use tool 'mcp' with server=<name> method=<tool> params=<object>."];for(let m of n){let i=await Co(m,{timeoutMs:s,maxBytes:l});if(a.push(`${m.name} (${m.type})`),i.length===0){a.push(" - tools unavailable");continue}let c=i.slice(0,o);for(let d of c){let p=d.description?`: ${d.description}`:"";a.push(` - ${d.name}${p}`)}i.length>c.length&&a.push(` - ...and ${i.length-c.length} more`)}let u=a.join(`
|
|
13
|
+
`);return u.length>r&&(u=`${u.slice(0,r-20)}...
|
|
14
|
+
(truncated)`),ge=u,u}function nt(){ge&&(tn=!0)}function on(){ge=null,tn=!1,J.clear()}function ce(e){if(e.type==="http")return e.url?`url=${e.url}`:"url=(missing)";let t=e.args&&e.args.length>0?` ${e.args.join(" ")}`:"";return e.command?`command=${e.command}${t}`:"command=(missing)"}async function rn(e,t=5e3){let n=Date.now();try{return await Oe(e,"tools/list",{},{timeoutMs:t}),{ok:!0,durationMs:Date.now()-n}}catch(o){let r=o instanceof Error?o.message:String(o);return{ok:!1,durationMs:Date.now()-n,error:r}}}async function Oe(e,t,n,o={}){let r=Qt(o.timeoutMs??ko,1e3,12e4),s=Qt(o.maxBytes??en,1024,5e6),l=new AbortController,a=()=>l.abort();o.signal?.addEventListener("abort",a,{once:!0});let u=setTimeout(()=>l.abort(),r);try{return e.type==="http"?(t!=="initialize"&&t!=="notifications/initialized"&&await Eo(e,s,l.signal),await Do(e,t,n,s,l.signal)):await Io(e,t,n,s,l.signal)}finally{clearTimeout(u),o.signal?.removeEventListener("abort",a)}}function Qt(e,t,n){return Number.isNaN(e)?t:Math.min(n,Math.max(t,e))}async function Co(e,t){try{let n=await Oe(e,"tools/list",{},t);return To(n.output)}catch(n){let o=n instanceof Error?n.message:String(n);return console.warn(`[tg-agent] mcp tools/list failed server=${e.name} error=${o}`),[]}}function To(e){let t;try{t=JSON.parse(e)}catch{return[]}if(!t||typeof t!="object")return[];let n=t,r=(n.result??n).tools??n.tools;if(!Array.isArray(r))return[];let s=[];for(let l of r){if(!l||typeof l!="object")continue;let a=l,u=typeof a.name=="string"?a.name:"";if(!u)continue;let m=typeof a.description=="string"?a.description:void 0,i=a.inputSchema;s.push({name:u,description:m,inputSchema:i})}return s}async function Do(e,t,n,o,r){if(!e.url)throw new Error("MCP server url is missing.");let s=Date.now(),l=await tt(e,t,n,o,r),a=sn(l.parsed);if(a)throw new Error(a);let u=l.bodyText;return l.parsed&&(u=JSON.stringify(l.parsed,null,2)),{ok:l.statusCode>=200&&l.statusCode<300,output:u,durationMs:Date.now()-s,bytes:l.bytes,truncated:l.truncated,statusCode:l.statusCode,statusText:l.statusText,contentType:l.contentType}}async function tt(e,t,n,o,r){if(!e.url)throw new Error("MCP server url is missing.");let s=J.get(e.name),l={jsonrpc:"2.0",id:`tg-agent-${Date.now()}`,method:t,params:n??{}},a={"content-type":"application/json"};e.auth&&(a.authorization=e.auth.startsWith("Bearer ")?e.auth:`Bearer ${e.auth}`),s?.cookie&&(a.cookie=s.cookie),s?.sessionId&&(a["mcp-session-id"]=s.sessionId);let u=await fetch(e.url,{method:"POST",headers:a,body:JSON.stringify(l),signal:r});Oo(e.name,u);let m=await No(u,o,r),i;try{i=JSON.parse(m.text)}catch{i=void 0}return jo(e.name,i),{statusCode:u.status,statusText:u.statusText,contentType:u.headers.get("content-type"),bodyText:m.text,parsed:i,bytes:m.bytes,truncated:m.truncated}}function sn(e){if(!e||typeof e!="object")return null;let t=e;if(t.error&&typeof t.error=="object"){let n=t.error;if(typeof n.message=="string")return n.message}return typeof t.error_description=="string"?t.error_description:typeof t.error=="string"?t.error:null}async function Eo(e,t,n){let o=J.get(e.name);if(o?.initializedAt)return;if(o?.inFlight){await o.inFlight;return}let r=(async()=>{let s=await tt(e,"initialize",{protocolVersion:"2024-11-05",clientInfo:{name:"tg-agent",version:process.env.npm_package_version??"dev"},capabilities:{}},t,n),l=sn(s.parsed);if(l){let m=l.toLowerCase();if(m.includes("method")&&m.includes("not"))return;throw new Error(l)}let a=new AbortController,u=setTimeout(()=>a.abort(),Ro);try{await tt(e,"notifications/initialized",{},t,a.signal)}catch{}finally{clearTimeout(u)}})();J.set(e.name,{initializedAt:Date.now(),inFlight:r});try{await r;let s=J.get(e.name);J.set(e.name,{initializedAt:Date.now(),cookie:s?.cookie,sessionId:s?.sessionId})}catch(s){throw J.delete(e.name),s}}function Oo(e,t){let o=J.get(e)??{initializedAt:0},r=t.headers.get("set-cookie"),s=t.headers.getSetCookie?.(),l=s&&s.length>0?s.join("; "):r;l&&J.set(e,{...o,cookie:l});let a=t.headers.get("mcp-session-id")??t.headers.get("x-mcp-session-id");a&&J.set(e,{...o,sessionId:a})}function jo(e,t){if(!t||typeof t!="object")return;let o=t.result;if(!o)return;let r=typeof o.sessionId=="string"&&o.sessionId||typeof o.session_id=="string"&&o.session_id;if(!r)return;let s=J.get(e)??{initializedAt:0};J.set(e,{...s,sessionId:r})}async function Io(e,t,n,o,r){if(!e.command)throw new Error("MCP server command is missing.");let s=Date.now(),l=Ao(e.command,e.args??[],{stdio:["pipe","pipe","pipe"]}),a=()=>{l.killed||l.kill("SIGTERM")};if(r.aborted)throw a(),new Error("MCP request aborted.");let u=new Map,m=!1,i="",c=new Error("MCP request aborted."),d=$o.createInterface({input:l.stdout,terminal:!1});d.on("line",v=>{if(v.length>o){m=!0;return}let x=null;try{x=JSON.parse(v)}catch{return}let k=typeof x.id=="string"?x.id:typeof x.id=="number"?String(x.id):"";if(!k)return;let D=u.get(k);D&&(u.delete(k),D.resolve(x))}),l.stderr?.on("data",v=>{let x=v.toString();if(i.length+x.length>o){m=!0;return}i+=x});let p=()=>{for(let v of u.values())v.reject(c);u.clear(),a()};r.addEventListener("abort",p,{once:!0});let y=v=>{let x=v===0?"MCP stdio exited.":i.trim()||"MCP stdio exited with error.";for(let k of u.values())k.reject(new Error(x));u.clear()};l.once("exit",v=>y(v));let h=async(v,x)=>{let k=`tg-agent-${Date.now()}-${Math.random().toString(16).slice(2,8)}`,D={jsonrpc:"2.0",id:k,method:v,params:x??{}};return await new Promise((he,Ge)=>{u.set(k,{resolve:he,reject:Ge}),l.stdin?.write(`${JSON.stringify(D)}
|
|
15
|
+
`)})};fetch("http://127.0.0.1:7243/ingest/9e452bb4-cc67-4519-89fa-8fb51d810231",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({location:"mcp.ts:callStdioMcp:beforeInit",message:"sending initialize request",data:{elapsed:Date.now()-s},timestamp:Date.now(),sessionId:"debug-session",hypothesisId:"B,C"})}).catch(()=>{});let b=await h("initialize",{protocolVersion:"2024-11-05",clientInfo:{name:"tg-agent",version:process.env.npm_package_version??"dev"},capabilities:{}});if(fetch("http://127.0.0.1:7243/ingest/9e452bb4-cc67-4519-89fa-8fb51d810231",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({location:"mcp.ts:callStdioMcp:afterInit",message:"initialize response received",data:{elapsed:Date.now()-s,hasError:!!b.error},timestamp:Date.now(),sessionId:"debug-session",hypothesisId:"B,C"})}).catch(()=>{}),b.error&&typeof b.error=="object"){let v=b.error.message??"MCP initialize failed.";throw a(),new Error(String(v))}let $={jsonrpc:"2.0",method:"notifications/initialized"};l.stdin?.write(`${JSON.stringify($)}
|
|
16
|
+
`),fetch("http://127.0.0.1:7243/ingest/9e452bb4-cc67-4519-89fa-8fb51d810231",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({location:"mcp.ts:callStdioMcp:beforeMethod",message:"sending method request",data:{method:t,elapsed:Date.now()-s},timestamp:Date.now(),sessionId:"debug-session",hypothesisId:"C"})}).catch(()=>{});let A=await h(t,n);r.removeEventListener("abort",p),d.close(),l.stdin?.end(),a();let M=new Promise(v=>{l.once("exit",()=>v())});if(await Promise.race([M,new Promise(v=>setTimeout(v,500))]),A.error&&typeof A.error=="object"){let v=A.error.message??"MCP request failed.";throw new Error(String(v))}let R=JSON.stringify(A,null,2),_=R.length>o?R.slice(0,o):R;return R.length>o&&(m=!0),{ok:!0,output:_,durationMs:Date.now()-s,bytes:Math.min(R.length,o),truncated:m}}async function No(e,t,n){let o=e.body?.getReader?.();if(!o){let c=await e.text(),d=Math.min(c.length,t);return{text:c.slice(0,t),bytes:d,truncated:c.length>t}}let r=new TextDecoder("utf-8"),s=[],l=0,a=!1;for(;;){if(n.aborted){try{await o.cancel()}catch{}throw new Error("MCP request aborted.")}let{done:c,value:d}=await o.read();if(c)break;if(!d)continue;let p=l+d.byteLength;if(p>t){let y=Math.max(0,t-l);y>0&&(s.push(d.slice(0,y)),l+=y),a=!0;try{await o.cancel()}catch{}break}s.push(d),l=p}let u=new Uint8Array(l),m=0;for(let c of s)u.set(c,m),m+=c.byteLength;return{text:r.decode(u),bytes:l,truncated:a}}function an(e){let t=[],n;try{n=Zt.parse(e)}catch{return t}let o=n.mcp_servers;if(!o||typeof o!="object")return t;for(let[r,s]of Object.entries(o)){if(!s||typeof s!="object")continue;let l=s,a=typeof l.type=="string"?l.type.toLowerCase():void 0,u=typeof l.url=="string"?l.url:void 0,m=typeof l.command=="string"?l.command:void 0,i=a==="http"||a==="stdio"?a:u?"http":m?"stdio":void 0;if(!i||i==="http"&&!u||i==="stdio"&&!m)continue;let c;Array.isArray(l.args)&&(c=l.args.filter(p=>typeof p=="string").map(p=>p.trim()));let d=typeof l.auth=="string"?l.auth:typeof l.authorization=="string"?l.authorization:typeof l.token=="string"?l.token:void 0;t.push({name:r,type:i,url:u,command:m,args:c,auth:d})}return t}var ko,en,Po,_o,ge,tn,J,Ro,je=F(()=>{"use strict";ko=6e4,en=2e5,Po=40,_o=3500,ge=null,tn=!1,J=new Map,Ro=1500});import ee from"node:path";import Lo from"node:fs/promises";import{Type as P}from"@sinclair/typebox";function Ie(e,t,n){return Number.isNaN(e)?t:Math.min(n,Math.max(t,e))}function Uo(e){if(!e)return{};let t={};if(Array.isArray(e)){for(let n of e)n?.name&&(t[n.name]=n.value??"");return t}for(let[n,o]of Object.entries(e))n&&(t[n]=o);return t}function cn(e){let t=g.fetchTimeoutMs>0?g.fetchTimeoutMs:zo;return Ie(e||t,1e3,12e4)}function ln(e){let t=g.fetchMaxBytes>0?g.fetchMaxBytes:Fo;return Ie(e||t,1024,5e6)}function un(e,t,n){let o=e.trim();if(!o)return null;let r=B(o),s=ee.isAbsolute(r)?r:ee.join(n,r),l=ee.resolve(s);for(let a of t){let u=ee.resolve(a);if(l===u||l.startsWith(`${u}${ee.sep}`))return l}return null}async function dn(e){try{let t=await Lo.stat(e);return t.isFile()?{bytes:t.size}:null}catch{return null}}function Bo(e){try{let t=new URL(e);return t.protocol==="http:"||t.protocol==="https:"}catch{return!1}}function Ko(e,t){let n=new Uint8Array(t),o=0;for(let r of e)n.set(r,o),o+=r.byteLength;return n}async function Jo(e,t,n){let o=e.body?.getReader?.();if(!o){let i=await e.text?.()??"",c=Math.min(i.length,t),d=i.length>t;return{text:i.slice(0,t),bytes:c,truncated:d}}let r=new TextDecoder("utf-8"),s=[],l=0,a=!1;for(;;){if(n?.aborted){try{await o.cancel?.()}catch{}throw new Error("Fetch aborted")}let{done:i,value:c}=await o.read();if(i)break;if(!c)continue;let d=l+c.byteLength;if(d>t){let p=Math.max(0,t-l);p>0&&(s.push(c.slice(0,p)),l+=p),a=!0;try{await o.cancel?.()}catch{}break}s.push(c),l=d}let u=Ko(s,l);return{text:r.decode(u),bytes:l,truncated:a}}function Wo(e,t){let n=`HTTP ${e.status} ${e.statusText}`.trim(),o=[`url: ${e.url}`,`bytes: ${e.bytes}${e.truncated?" (truncated)":""}`,`content-type: ${e.contentType??"unknown"}`];return`${n}
|
|
17
17
|
${o.join(`
|
|
18
18
|
`)}
|
|
19
19
|
|
|
20
|
-
${t}`}function
|
|
20
|
+
${t}`}function qo(){return{name:"fetch",label:"fetch",description:"Fetch a URL via HTTP(S) and return the response body.",parameters:Ho,execute:async(e,t,n,o,r)=>{if(!Bo(t.url))return{content:[{type:"text",text:"Invalid URL. Only http(s) is allowed."}],details:{url:t.url,status:0,statusText:"invalid_url",bytes:0,truncated:!1,contentType:null}};let s=cn(t.timeoutMs),l=ln(t.maxBytes),a=new AbortController,u=()=>a.abort();r?.addEventListener("abort",u,{once:!0});let m=setTimeout(()=>a.abort(),s);try{n?.({content:[{type:"text",text:`Fetching ${t.url}...`}],details:{url:t.url,status:0,statusText:"pending",bytes:0,truncated:!1,contentType:null}});let i=await fetch(t.url,{method:t.method?.toUpperCase()??"GET",headers:Uo(t.headers),body:t.body,signal:a.signal}),c=await Jo(i,l,r),d=i.headers.get("content-type");return{content:[{type:"text",text:Wo({url:i.url,status:i.status,statusText:i.statusText,bytes:c.bytes,truncated:c.truncated,contentType:d},c.text)}],details:{url:i.url,status:i.status,statusText:i.statusText,bytes:c.bytes,truncated:c.truncated,contentType:d}}}catch(i){return{content:[{type:"text",text:`Fetch failed: ${i instanceof Error?i.message:String(i)}`}],details:{url:t.url,status:0,statusText:"error",bytes:0,truncated:!1,contentType:null}}}finally{clearTimeout(m),r?.removeEventListener("abort",u)}}}}function Yo(e,t,n){let o=t.status>0?`HTTP ${t.status} ${t.statusText}`.trim():t.statusText,r=[`server: ${e.name}`,`type: ${e.type}`,`target: ${t.target}`,`bytes: ${t.bytes}${t.truncated?" (truncated)":""}`,`content-type: ${t.contentType??"unknown"}`];return`${o}
|
|
21
21
|
${r.join(`
|
|
22
22
|
`)}
|
|
23
23
|
|
|
24
|
-
${n}`}function
|
|
24
|
+
${n}`}function Vo(e){return{name:"mcp",label:"mcp",description:"Call an MCP endpoint via JSON-RPC.",parameters:Go,execute:async(t,n,o,r,s)=>{let l=await e();if(l.length===0)return{content:[{type:"text",text:"MCP is not configured. Add [mcp_servers.*] to ~/.tg-agent/config.toml."}],details:{server:"",type:"http",target:"",status:0,statusText:"not_configured",bytes:0,truncated:!1,contentType:null}};let a=n.server?.trim()??"";if(!a)if(l.length===1)a=l[0]?.name??"";else return{content:[{type:"text",text:`Multiple MCP servers configured. Provide server name. Available: ${l.map(m=>m.name).join(", ")}`}],details:{server:"",type:"http",target:"",status:0,statusText:"server_required",bytes:0,truncated:!1,contentType:null}};let u=l.find(m=>m.name===a);if(!u)return{content:[{type:"text",text:`MCP server not found: ${a}. Available: ${l.map(m=>m.name).join(", ")}`}],details:{server:a,type:"http",target:"",status:0,statusText:"server_not_found",bytes:0,truncated:!1,contentType:null}};try{o?.({content:[{type:"text",text:`Calling MCP ${u.name} ${n.method}...`}],details:{server:u.name,type:u.type,target:ce(u),status:0,statusText:"pending",bytes:0,truncated:!1,contentType:null}});let m=await Oe(u,n.method,n.params??{},{timeoutMs:cn(void 0),maxBytes:ln(void 0),signal:s});return{content:[{type:"text",text:Yo(u,{server:u.name,type:u.type,target:ce(u),status:m.statusCode??0,statusText:m.statusText??(m.ok?"ok":"error"),bytes:m.bytes,truncated:m.truncated,contentType:m.contentType??null},m.output)}],details:{server:u.name,type:u.type,target:ce(u),status:m.statusCode??0,statusText:m.statusText??(m.ok?"ok":"error"),bytes:m.bytes,truncated:m.truncated,contentType:m.contentType??null}}}catch(m){return{content:[{type:"text",text:`MCP failed: ${m instanceof Error?m.message:String(m)}`}],details:{server:u.name,type:u.type,target:ce(u),status:0,statusText:"error",bytes:0,truncated:!1,contentType:null}}}}}}function Zo(e){let t=[g.workspaceDir,ee.join(g.agentDir,"uploads")];return{name:"send_photo",label:"send_photo",description:"Send an image file to the current Telegram chat.",parameters:Xo,execute:async(n,o)=>{let r=un(o.path,t,g.workspaceDir);if(!r)return{content:[{type:"text",text:"Invalid path. Only workspace or uploads are allowed."}],details:{path:o.path,bytes:0}};let s=await dn(r);return s?(await e.sendPhoto(r,o.caption?.trim()||void 0),{content:[{type:"text",text:`Photo sent: ${ee.basename(r)}`}],details:{path:r,bytes:s.bytes}}):{content:[{type:"text",text:`File not found: ${r}`}],details:{path:r,bytes:0}}}}}function er(e){let t=[g.workspaceDir,ee.join(g.agentDir,"uploads")];return{name:"send_file",label:"send_file",description:"Send a file to the current Telegram chat.",parameters:Qo,execute:async(n,o)=>{let r=un(o.path,t,g.workspaceDir);if(!r)return{content:[{type:"text",text:"Invalid path. Only workspace or uploads are allowed."}],details:{path:o.path,bytes:0}};let s=await dn(r);return s?(await e.sendDocument(r,o.caption?.trim()||void 0),{content:[{type:"text",text:`File sent: ${ee.basename(r)}`}],details:{path:r,bytes:s.bytes}}):{content:[{type:"text",text:`File not found: ${r}`}],details:{path:r,bytes:0}}}}}function mn(e){let t=[qo()];return e?.telegram&&(t.push(Zo(e.telegram)),t.push(er(e.telegram))),Ee(g.agentDir).length>0&&t.push(Vo(()=>xe(g.agentDir))),t}var Fo,zo,Ho,Go,Xo,Qo,gn=F(()=>{"use strict";K();je();G();Fo=2e5,zo=6e4;Ho=P.Object({url:P.String({description:"HTTP or HTTPS URL"}),method:P.Optional(P.String({description:"HTTP method (default: GET)"})),headers:P.Optional(P.Array(P.Object({name:P.String({description:"Header name"}),value:P.String({description:"Header value"})}),{description:"Request headers as name/value pairs"})),body:P.Optional(P.String({description:"Request body (string)"})),timeoutMs:P.Optional(P.Integer({description:"Timeout in milliseconds",minimum:1e3,maximum:12e4})),maxBytes:P.Optional(P.Integer({description:"Max response bytes",minimum:1024,maximum:5e6}))});Go=P.Object({server:P.Optional(P.String({description:"MCP server name"})),method:P.String({description:"MCP method name"}),params:P.Optional(P.Any({description:"MCP params payload"}))});Xo=P.Object({path:P.String({description:"Image file path (relative to workspace or uploads)."}),caption:P.Optional(P.String({description:"Caption text (plain text)."}))}),Qo=P.Object({path:P.String({description:"File path (relative to workspace or uploads)."}),caption:P.Optional(P.String({description:"Caption text (plain text)."}))})});import yn from"node:fs/promises";import hn from"node:path";function wn(e){return hn.join(g.sessionDir,`${e}.json`)}function pn(e){return e.replace(/[^a-zA-Z0-9_-]/g,"_")}function ot(e,t){let n=pn(e),o=pn(t);return hn.join(g.sessionDir,`${n}-${o}.jsonl`)}async function pe(e,t){let n=ot(e,t);try{await yn.unlink(n)}catch(o){if(o.code==="ENOENT")return;throw o}}function fn(e,t){let n=t?.sessions??{},o=t?.activeSessionId??null,r=t?.workspaceDir,s={chatId:e,workspaceDir:r,activeSessionId:o,sessions:n};return(!o||!n[o])&&(s.activeSessionId=null),s}async function Le(e){await T(g.sessionDir);let t=Ne.get(e);if(t)return t;let n=wn(e);try{let o=await yn.readFile(n,"utf8"),r=JSON.parse(o),s=fn(e,r);return Ne.set(e,s),s}catch(o){if(o.code==="ENOENT"){let r=fn(e,{});return Ne.set(e,r),r}throw o}}async function j(e){await T(g.sessionDir);let t=wn(e.chatId);await Ce(t,e),Ne.set(e.chatId,e)}function rt(e){return Object.values(e.sessions).sort((t,n)=>n.updatedAt-t.updatedAt)}function st(e){return[]}function Fe(e,t){if(Object.keys(e.sessions).length>=g.maxSessions)throw new Error("Max sessions reached");let o=ae(),r=z(),s={id:o,title:t&&t.length>0?t:`session-${o}`,messages:[],createdAt:r,updatedAt:r};return e.sessions[o]=s,e.activeSessionId=o,s}function bn(e,t){return e.sessions[t]?(e.activeSessionId=t,!0):!1}function le(e){return e.activeSessionId?e.sessions[e.activeSessionId]??null:null}function it(e,t){return e.sessions[t]?(delete e.sessions[t],e.activeSessionId===t&&(e.activeSessionId=null),!0):!1}function vn(e){e.messages=[],e.updatedAt=z()}function at(e,t,n){e.messages.push(t),e.messages.length>n&&(e.messages=e.messages.slice(-n)),e.updatedAt=z()}function xn(e,t){e.workspaceDir=t}var Ne,ct=F(()=>{"use strict";K();G();Ne=new Map});import tr from"node:fs/promises";import Mn from"node:path";import{completeSimple as nr}from"@mariozechner/pi-ai";function ir(e,t){let n=e==="bash"&&typeof t.command=="string"?t.command:`${e}: ${JSON.stringify(t)}`;return sr.replace("{{command}}",n)}function ar(e){let t=e.trim();console.log(`[audit] AI response: ${t.slice(0,200)}`);try{let n=JSON.parse(t),o=n.riskLevel?.toLowerCase();if(o==="none"||o==="low"||o==="critical")return{riskLevel:o,reason:n.reason??"No reason"}}catch{}try{let n=t.match(/\{[^{}]*"riskLevel"\s*:\s*"[^"]*"[^{}]*\}/);if(n){let r=JSON.parse(n[0]),s=r.riskLevel?.toLowerCase();if(s==="none"||s==="low"||s==="critical")return{riskLevel:s,reason:r.reason??"No reason"}}let o=t.toLowerCase();return o.includes('"critical"')||o.includes("critical risk")?{riskLevel:"critical",reason:"AI indicated critical risk"}:o.includes('"none"')||o.includes("no risk")?{riskLevel:"none",reason:"AI indicated no risk"}:(console.warn("[audit] could not parse response, defaulting to low"),{riskLevel:"low",reason:"Could not parse AI response"})}catch(n){return console.warn("[audit] parse error:",n),{riskLevel:"low",reason:"Failed to parse AI response"}}}async function cr(e,t,n,o,r){let s=ir(n,o);try{let a={systemPrompt:'You are a security analyst. Reply with ONLY valid JSON: {"riskLevel":"none|low|critical","reason":"brief explanation"}.',messages:[{role:"user",content:s,timestamp:Date.now()}]},u=await nr(e,a,{apiKey:t,maxTokens:500,temperature:0,...r&&{sessionId:r}}),m=u.content.find(c=>c.type==="text"),i=m?.type==="text"?m.text:"";return i.trim()||(i=u.content.filter(d=>d.type==="thinking").map(d=>d.type==="thinking"?d.thinking:"").filter(Boolean).join(`
|
|
25
25
|
|
|
26
|
-
`)),
|
|
27
|
-
`;await
|
|
28
|
-
`)}function
|
|
26
|
+
`)),ar(i)}catch(l){let a=l instanceof Error?l.message:String(l);return console.error("[audit] AI analysis failed:",a),{riskLevel:"low",reason:`AI analysis failed: ${a}`}}}function lr(e,t){let n=e.trim();return t.some(o=>o.test(n))}function ur(e){let t=[];for(let n of e)try{t.push(new RegExp(n,"i"))}catch{console.warn(`[audit] invalid whitelist pattern: ${n}`)}return t}async function ne(e,t,n){try{await T(Sn);let o=Mn.join(Sn,`${e}-${t}.log`),r=JSON.stringify(n)+`
|
|
27
|
+
`;await tr.appendFile(o,r,"utf8")}catch(o){let r=o instanceof Error?o.message:String(o);console.error(`[audit] failed to write audit log: ${r}`)}}function dr(e){let t=e.toolName==="bash"?e.input.command??JSON.stringify(e.input):JSON.stringify(e.input,null,2);return["[Security Alert]",`Tool: ${e.toolName}`,`Command: ${t.slice(0,300)}`,`Risk: ${e.riskLevel.toUpperCase()} - ${e.analysis}`,"",'Press "Approve" to continue or "Stop" to block.'].join(`
|
|
28
|
+
`)}function $n(e,t){let n=g.audit,o=ur(n.whitelistPatterns);return r=>{r.on("tool_call",async(s,l)=>{let{toolName:a,toolCallId:u,input:m}=s,i={timestamp:new Date().toISOString(),sessionId:e.sessionId,toolName:a,toolCallId:u,input:m,riskLevel:"none",analysis:"",action:"passed"};if(or.has(a)){i.analysis="Read-only tool",await ne(e.chatId,e.sessionId,i),console.log(`[audit] tool=${a} id=${u} action=passed (read-only)`);return}if(!rr.has(a)){i.analysis="Tool not in analysis scope",await ne(e.chatId,e.sessionId,i),console.log(`[audit] tool=${a} id=${u} action=passed (not analyzed)`);return}if(a==="bash"){let d=m.command??"";if(lr(d,o)){i.analysis="Whitelisted bash command",await ne(e.chatId,e.sessionId,i),console.log(`[audit] tool=${a} id=${u} action=passed (whitelisted)`);return}}if(!t){i.analysis="No audit model configured",await ne(e.chatId,e.sessionId,i),console.log(`[audit] tool=${a} id=${u} action=passed (no audit model)`);return}console.log(`[audit] analyzing tool=${a} id=${u}`);let c=await cr(t.model,t.apiKey,a,m,e.sessionId);if(i.riskLevel=c.riskLevel,i.analysis=c.reason,c.riskLevel==="none"||c.riskLevel==="low"){i.action="passed",await ne(e.chatId,e.sessionId,i),console.log(`[audit] tool=${a} id=${u} risk=${c.riskLevel} action=passed`);return}console.log(`[audit] CRITICAL tool=${a} id=${u} reason=${c.reason}`);try{let d=dr(i);if(await e.requestConfirmation(d,n.confirmTimeoutMs)){i.action="approved",await ne(e.chatId,e.sessionId,i),console.log(`[audit] tool=${a} id=${u} action=approved`);return}return i.action="blocked",await ne(e.chatId,e.sessionId,i),console.log(`[audit] tool=${a} id=${u} action=blocked (user rejected)`),l.abort(),{block:!0,reason:"Operation blocked by user due to security risk."}}catch(d){let p=d instanceof Error?d.message:String(d);return i.action="blocked",i.analysis=`${c.reason} (confirmation failed: ${p})`,await ne(e.chatId,e.sessionId,i),console.log(`[audit] tool=${a} id=${u} action=blocked (${p})`),l.abort(),{block:!0,reason:`Security confirmation failed: ${p}`}}})}}var or,rr,sr,Sn,An=F(()=>{"use strict";K();G();or=new Set(["read","ls","find","grep"]),rr=new Set(["bash"]),sr=`Analyze this command for security risks. Reply with ONLY a JSON object, no other text.
|
|
29
29
|
|
|
30
30
|
Command: {{command}}
|
|
31
31
|
|
|
@@ -35,21 +35,21 @@ Risk levels:
|
|
|
35
35
|
- "critical": High risk (secrets exposure, destructive ops, network attacks, privilege escalation)
|
|
36
36
|
|
|
37
37
|
Reply format (ONLY this JSON, nothing else):
|
|
38
|
-
{"riskLevel":"none|low|critical","reason":"brief explanation"}`;
|
|
38
|
+
{"riskLevel":"none|low|critical","reason":"brief explanation"}`;Sn=Mn.join(g.sessionDir,"audit-logs")});import{readFileSync as mr,existsSync as gr,chmodSync as pr}from"node:fs";import kn from"node:path";import{getOAuthProvider as fr}from"@mariozechner/pi-ai";function te(){return lt||(lt=new ut),lt}var ut,lt,dt=F(()=>{"use strict";K();G();ut=class{filePath;data={};constructor(t){this.filePath=t??kn.join(g.agentDir,"multi-auth.json"),this.reload()}reload(){if(!gr(this.filePath)){this.data={};return}try{let t=mr(this.filePath,"utf8");this.data=JSON.parse(t)}catch{this.data={}}}async save(){let t=kn.dirname(this.filePath);await T(t),await Ce(this.filePath,this.data);try{pr(this.filePath,384)}catch{}}listAccounts(t){let n=this.data[t];return n?Object.entries(n.accounts).map(([o,r])=>({id:o,email:r.email,isDefault:n.defaultAccountId===o,lastUsedAt:r.lastUsedAt})):[]}async addAccount(t,n,o){this.data[t]||(this.data[t]={accounts:{}});let r=`acc_${ae()}`,s=n;return this.data[t].accounts[r]={type:"oauth",refresh:n.refresh,access:n.access,expires:n.expires,email:o?.email??s.email,projectId:s.projectId,createdAt:Date.now(),lastUsedAt:Date.now()},this.data[t].defaultAccountId||(this.data[t].defaultAccountId=r),await this.save(),r}getAccount(t,n){return this.data[t]?.accounts[n]??null}getDefaultAccount(t){let n=this.data[t];if(!n?.defaultAccountId)return null;let o=n.accounts[n.defaultAccountId];return o?{id:n.defaultAccountId,credential:o}:null}async setDefaultAccount(t,n){let o=this.data[t];return o?.accounts[n]?(o.defaultAccountId=n,await this.save(),!0):!1}async removeAccount(t,n){let o=this.data[t];if(!o?.accounts[n])return!1;if(delete o.accounts[n],o.defaultAccountId===n){let r=Object.keys(o.accounts);o.defaultAccountId=r[0]}return Object.keys(o.accounts).length===0&&delete this.data[t],await this.save(),!0}async removeAllAccounts(t){let n=this.data[t];if(!n)return 0;let o=Object.keys(n.accounts).length;return delete this.data[t],await this.save(),o}async updateCredential(t,n,o){let r=this.data[t]?.accounts[n];if(!r)return;r.refresh=o.refresh,r.access=o.access,r.expires=o.expires,r.lastUsedAt=Date.now();let s=o;s.projectId!==void 0&&(r.projectId=s.projectId),await this.save()}async getApiKey(t,n){let o=this.data[t]?.accounts[n];if(!o)return null;let r=fr(t);if(!r)return null;let s=Date.now(),l=300*1e3;if(o.expires-s<l)try{let a={refresh:o.refresh,access:o.access,expires:o.expires,...o.projectId!==void 0&&{projectId:o.projectId}},u=await r.refreshToken(a);return await this.updateCredential(t,n,u),r.getApiKey(u)}catch(a){return console.warn(`[multi-auth] token refresh failed for ${t}/${n}:`,a),o.expires>s?r.getApiKey(o):null}return r.getApiKey(o)}hasMultipleAccounts(t){let n=this.data[t]?.accounts;return n?Object.keys(n).length>1:!1}hasAccounts(t){let n=this.data[t]?.accounts;return n?Object.keys(n).length>0:!1}},lt=null});import{createAgentSession as yr,AuthStorage as hr,ModelRegistry as wr,SessionManager as br,SettingsManager as vr,DefaultResourceLoader as xr}from"@mariozechner/pi-coding-agent";import ze from"node:fs/promises";import Ue from"node:path";function Pn(e){let t=e.trim().toLowerCase();return t==="codex"?"openai-codex":t}function Mr(e,t){let n=e.trim();if(!n)return{provider:t,modelId:""};if(n.includes("/")){let[o,r]=n.split("/",2);return{provider:o.trim()||t,modelId:r.trim()}}return{provider:t,modelId:n}}function $r(e,t){return e!=="openai-codex"?t:Sr[t]??t}function Ar(e,t){let n=e.getAvailable().filter(r=>r.provider===t);return n.length>0?n[0]:e.getAll().filter(r=>r.provider===t)[0]}function kr(e,t){let n=!!t?.provider?.trim(),o=!!t?.modelId?.trim(),r=Pn(t?.provider||g.modelProvider||"openai-codex"),s=n||o?"":g.modelRef||"",{provider:l,modelId:a}=Mr(s,r),u=t?.provider?r:Pn(l),m=o?t?.modelId?.trim()||"":a;if(!m){let d=Ar(e,u);return d?{model:d,provider:u,modelId:d.id}:{model:void 0,provider:u,modelId:""}}let i=$r(u,m);return{model:e.find(u,i),provider:u,modelId:i}}function Pr(e){let t=Y();return t?(e.setRuntimeApiKey("openai-codex",t.accessToken),{source:t.source,expiresAt:t.expiresAt}):null}function _r(e){if(e?.role!=="assistant")return"";let n=e.content;if(typeof n=="string")return n.trim();if(!Array.isArray(n))return"";let o=n.filter(s=>typeof s=="object"&&s&&s.type==="text").map(s=>s.text??"").map(s=>s.trim()).filter(Boolean);if(o.length>0)return o.join(`
|
|
39
39
|
|
|
40
40
|
`);let r=n.filter(s=>typeof s=="object"&&s&&s.type==="thinking").map(s=>s.thinking??"").map(s=>s.trim()).filter(Boolean);return r.length>0?r.join(`
|
|
41
41
|
|
|
42
|
-
`):""}function
|
|
42
|
+
`):""}function Rr(e){if(e.length===0)return"messages=0";let t=e.slice(-6).map(n=>{let o=n?.role??"unknown",r=n.content,s=n?.stopReason,l=n?.errorMessage;if(typeof r=="string")return`${o}(text:${r.length}${s?`,stop=${s}`:""})`;if(Array.isArray(r)){let u=[`blocks:${r.map(m=>typeof m=="object"&&m&&"type"in m?String(m.type||"unknown"):typeof m).join(",")||"none"}`,s?`stop=${s}`:null,l?"error=1":null].filter(Boolean).join(",");return`${o}(${u})`}if(r==null){let a=["empty",s?`stop=${s}`:null,l?"error=1":null].filter(Boolean).join(",");return`${o}(${a})`}return`${o}(${typeof r}${s?`,stop=${s}`:""})`});return`messages=${e.length} last=[${t.join(" ")}]`}function Cr(e){let t=e.trim();return t.toLowerCase().includes("usage limit")?`${t}
|
|
43
43
|
|
|
44
|
-
Suggestion: wait for the limit to reset or switch to another provider/model.`:t}function
|
|
44
|
+
Suggestion: wait for the limit to reset or switch to another provider/model.`:t}function Tr(e,t){let n=t?.getLastAssistantText?.();if(n?.trim())return n.trim();for(let o=e.length-1;o>=0;o-=1){let r=_r(e[o]);if(r)return r}return""}function Dr(e){for(let t=e.length-1;t>=0;t-=1)if(e[t]?.role==="assistant")return e[t]}async function _n(e){let t=e.workspaceDir||g.workspaceDir;await T(g.sessionDir),await T(g.agentDir),await T(t);let n=ot(e.chatId,e.sessionId),o=Ue.join(g.agentDir,"auth.json"),r=new hr(o),s=Pr(r);s&&console.log(`[tg-agent] codex oauth source=${s.source} expiresAt=${new Date(s.expiresAt).toISOString()}`);let l=e.modelProvider||g.modelProvider,a=te();if(e.accountId){let w=await a.getApiKey(l,e.accountId);w?(r.setRuntimeApiKey(l,w),console.log(`[tg-agent] multi-auth: using account=${e.accountId} for ${l}`)):console.warn(`[tg-agent] multi-auth: account not found ${l}/${e.accountId}`)}else if(a.hasAccounts(l)){let w=a.getDefaultAccount(l);if(w){let S=await a.getApiKey(l,w.id);S&&(r.setRuntimeApiKey(l,S),console.log(`[tg-agent] multi-auth: using default account=${w.id} for ${l}`))}}let u=Ue.join(g.agentDir,"models.json"),m=new wr(r,u),{model:i,provider:c,modelId:d}=kr(m,{provider:e.modelProvider,modelId:e.modelId});d&&!i&&console.warn(`[tg-agent] model not found: ${c}/${d}`);let p=br.open(n),y=vr.create(t,g.agentDir);try{let w=Ue.join(g.agentDir,"skills"),S=Ue.join(t,".pi","skills"),L=await ze.access(w).then(()=>!0).catch(()=>!1),E=await ze.access(S).then(()=>!0).catch(()=>!1);if(L){let Z=(await ze.readdir(w,{withFileTypes:!0})).filter(H=>H.isDirectory()).map(H=>H.name);console.log(`[tg-agent] skills directory found at ${w} with ${Z.length} skill(s): ${Z.join(", ")}`)}else console.log(`[tg-agent] skills directory not found at ${w}`);if(E){let Z=(await ze.readdir(S,{withFileTypes:!0})).filter(H=>H.isDirectory()).map(H=>H.name);console.log(`[tg-agent] workspace skills directory found at ${S} with ${Z.length} skill(s): ${Z.join(", ")}`)}let W=y.getSettings?.();if(W){let Z=W.skills?.enabled!==!1;console.log(`[tg-agent] skills enabled in settings: ${Z}`)}}catch(w){let S=w instanceof Error?w.message:String(w);console.warn(`[tg-agent] skills check failed: ${S}`)}let h="";try{h=await Se(g.agentDir,{timeoutMs:4e3,maxBytes:g.fetchMaxBytes,maxChars:3e3})}catch(w){let S=w instanceof Error?w.message:String(w);console.warn(`[tg-agent] mcp catalog error: ${S}`)}let b=[];if(g.audit.enabled&&e.auditContext){let w={...e.auditContext,sessionId:e.sessionId},S;if(g.audit.modelProvider&&g.audit.modelId){let L=m.find(g.audit.modelProvider,g.audit.modelId);if(L){let E=await r.getApiKey(g.audit.modelProvider);S={provider:g.audit.modelProvider,model:L,apiKey:E??void 0},console.log(`[tg-agent] audit model: ${g.audit.modelProvider}/${g.audit.modelId} apiKey=${E?"present":"missing"}`)}else console.warn(`[tg-agent] audit model not found: ${g.audit.modelProvider}/${g.audit.modelId}`)}b.push($n(w,S)),console.log(`[tg-agent] security audit enabled for session ${e.sessionId}`)}let $=e.systemPrompt?.trim(),A=[];$&&A.push($),h&&A.push(h);let M=A.length>0?A.join(`
|
|
45
45
|
|
|
46
|
-
`):void 0;console.log(`[tg-agent] systemPrompt append=${A?A.slice(0,80)+"...":"(none)"}`);let I=new cr({cwd:t,agentDir:m.agentDir,settingsManager:g,extensionFactories:y.length>0?y:void 0,appendSystemPrompt:A});await I.reload();let{session:x,modelFallbackMessage:P}=await or({cwd:t,agentDir:m.agentDir,authStorage:r,modelRegistry:a,model:c??void 0,sessionManager:d,settingsManager:g,resourceLoader:I,customTools:en({telegram:e.telegram})});try{let h=x.messages,v=h.some(N=>{let Y=N.role,K=N.content;return Y==="system"&&typeof K=="string"?K.toLowerCase().includes("compaction")||K.toLowerCase().includes("compact"):N.type==="compaction"||N.compaction!==void 0});console.log(`[tg-agent] session manager type: ${typeof d}`),console.log(`[tg-agent] session messages count: ${h.length}`),console.log(`[tg-agent] compacting support detected: ${v||"unknown (will be detected during runtime)"}`);let C=typeof d.compact=="function",U=typeof d.appendCompaction=="function";console.log(`[tg-agent] SessionManager.compact method: ${C}`),console.log(`[tg-agent] SessionManager.appendCompaction method: ${U}`)}catch(h){let v=h instanceof Error?h.message:String(h);console.warn(`[tg-agent] compacting check failed: ${v}`)}P&&console.warn(`[tg-agent] modelFallback=${P}`);let ae=!1,S=()=>{ae=!0,x.abort()};e.onAbortReady?.(S);let b=m.logAgentEvents,k=m.logAgentStream,D=new Map,gt=x.subscribe(h=>{switch(h.type){case"agent_start":b&&console.log(`[tg-agent] agent start session=${e.sessionId}`),F=Date.now(),e.onStatus?.({type:"agent_start"});break;case"agent_end":b&&console.log(`[tg-agent] agent end session=${e.sessionId}`),e.onStatus?.({type:"agent_end"});break;case"turn_start":b&&console.log(`[tg-agent] turn start session=${e.sessionId}`),F=Date.now(),e.onStatus?.({type:"turn_start"});break;case"turn_end":b&&console.log(`[tg-agent] turn end session=${e.sessionId} toolResults=${h.toolResults.length}`),F=Date.now(),e.onStatus?.({type:"turn_end",toolResults:h.toolResults.length});break;case"message_start":{if(b){let v=h.message.role??"unknown";console.log(`[tg-agent] message start session=${e.sessionId} role=${v}`)}F=Date.now();{let v=h.message.role??"unknown";e.onStatus?.({type:"message_start",role:v})}break}case"message_end":{if(b){let v=h.message.role??"unknown";console.log(`[tg-agent] message end session=${e.sessionId} role=${v}`)}F=Date.now();{let v=h.message.role??"unknown";e.onStatus?.({type:"message_end",role:v})}break}case"message_update":{if(!k)break;if(h.assistantMessageEvent.type==="text_delta"){let L=(h.assistantMessageEvent.delta??"").length;L>0&&console.log(`[tg-agent] stream delta session=${e.sessionId} chars=${L}`),F=Date.now()}h.assistantMessageEvent.type==="thinking_delta"&&(F=Date.now());break}case"tool_execution_start":{D.set(h.toolCallId,Date.now()),console.log(`[tg-agent] tool start name=${h.toolName} id=${h.toolCallId}`),Ae+=1,F=Date.now(),e.onStatus?.({type:"tool_start",name:h.toolName,id:h.toolCallId,args:h.args});break}case"tool_execution_end":{let v=D.get(h.toolCallId),L=v?Date.now()-v:0;console.log(`[tg-agent] tool end name=${h.toolName} id=${h.toolCallId} ok=${!h.isError} durationMs=${L}`),D.delete(h.toolCallId),Ae=Math.max(0,Ae-1),F=Date.now(),e.onStatus?.({type:"tool_end",name:h.toolName,id:h.toolCallId,ok:!h.isError,durationMs:L});break}case"auto_compaction_start":{let v=h.reason??"unknown";console.log(`[tg-agent] auto compaction started session=${e.sessionId} reason=${v}`),F=Date.now();break}case"auto_compaction_end":{let v=h.willRetry??!1;console.log(`[tg-agent] auto compaction ended session=${e.sessionId} willRetry=${v}`),F=Date.now();break}default:break}}),oe=null,ye=null,$e=!1,pt=0,ft=!1,F=Date.now(),Ae=0;try{let h=Date.now();oe=setInterval(()=>{let C=Date.now()-h;console.log(`[tg-agent] prompt running session=${e.sessionId} elapsedMs=${C} streaming=${x.isStreaming}`),e.onStatus?.({type:"heartbeat",elapsedMs:C,streaming:x.isStreaming})},15e3),ye=setInterval(()=>{if($e||Ae>0)return;let C=Date.now()-F,U=x.isStreaming?m.modelTimeoutStreamingMs:m.modelTimeoutMs,N=Math.max(1e3,U);C>=N&&($e=!0,pt=N,ft=x.isStreaming,console.warn(`[tg-agent] model timeout session=${e.sessionId} elapsedMs=${C}`),x.abort())},2e3);try{if(await x.prompt(e.prompt,e.images&&e.images.length>0?{images:e.images}:void 0),$e)throw new Error(`Model request timed out after ${m.modelTimeoutMs}ms`)}catch(C){if(ae)throw new Error("Cancelled by user.");if($e){let U=ft?" (streaming)":"",N=pt||m.modelTimeoutMs;throw new Error(`Model request timed out after ${N}ms${U}`)}throw C}oe&&clearInterval(oe);let v=br(x.messages);if(v){let C=v?.stopReason,U=v?.errorMessage;if(C==="error"){let N=U?hr(U):"Model error without details.";throw console.warn(`[tg-agent] model error session=${e.sessionId} error=${N}`),new Error(N)}}let L=wr(x.messages,x);if(!L){let C=yr(x.messages);throw console.warn(`[tg-agent] empty response session=${e.sessionId} ${C}`),new Error("No assistant response.")}return{text:L,sessionFile:n,sessionId:x.sessionId,modelProvider:x.model?.provider??u,modelId:x.model?.id??i,modelFallbackMessage:P}}finally{oe&&clearInterval(oe),ye&&clearInterval(ye),gt(),d.flushPendingToolResults?.(),x.dispose()}}var lr,hn=j(()=>{"use strict";H();le();tn();De();X();nt();pn();lr={"codex-mini-latest":"gpt-5.1-codex-mini","codex-max-latest":"gpt-5.1-codex-max","codex-latest":"gpt-5.2-codex"}});import xr from"node:path";import*as wn from"@lancedb/lancedb";import ot from"openai";function Sr(){if(ee)return ee;let e=m.memory.rag;if(e.embeddingApiKey){let n={apiKey:e.embeddingApiKey};return e.embeddingBaseUrl&&(n.baseURL=e.embeddingBaseUrl),ee=new ot(n),console.log(`[memory-rag] using embedding API key${e.embeddingBaseUrl?` (baseURL: ${e.embeddingBaseUrl})`:""}`),ee}if(m.openaiApiKey)return ee=new ot({apiKey:m.openaiApiKey}),console.log("[memory-rag] using OpenAI API key from config"),ee;let t=q();if(t)return ee=new ot({apiKey:t.accessToken}),console.log("[memory-rag] using Codex OAuth token"),ee;throw new Error("No API key for embeddings. Set memory.rag.embedding_api_key or run `codex login`.")}async function st(e){let t=Sr(),n=m.memory.rag.embeddingModel;console.log(`[memory-rag] embedding ${e.length} chars using ${n}`);let o=3e4,r=new Promise((s,l)=>{setTimeout(()=>l(new Error(`Embedding timeout after ${o}ms`)),o)});try{let s=await Promise.race([t.embeddings.create({model:n,input:e,encoding_format:"float"}),r]);if(!s?.data?.[0]?.embedding)throw new Error(`Invalid embedding response: ${JSON.stringify(s).slice(0,200)}`);let l=s.data[0].embedding;return console.log(`[memory-rag] got ${l.length}D embedding`),l}catch(s){throw s instanceof Error&&console.error(`[memory-rag] embedding error: ${s.message}`),s}}async function me(){return ze||(await R(rt),ze=await wn.connect(rt),console.log(`[memory-rag] connected to DB at ${rt}`),ze)}async function Be(e,t,n,o,r){let s={sessionSaved:!1,memoriesIndexed:0,errors:[]};if(!m.memory.rag.enabled)return console.log("[memory-rag] RAG disabled, skipping save"),s;console.log(`[memory-rag] saving session ${e}`);try{let l=await me(),a=await l.tableNames(),c={sessionId:e,date:t,title:n,transcript:o,reflection:JSON.stringify(r),memoryCount:r.memories?.length??0,timestamp:Date.now()};if(a.includes(te)?await(await l.openTable(te)).add([c]):await l.createTable(te,[c]),s.sessionSaved=!0,console.log("[memory-rag] session saved to DB"),r.memories&&r.memories.length>0){let u=await kr(e,t,r.memories);s.memoriesIndexed=u.indexed,s.errors=u.errors}return s}catch(l){let a=l instanceof Error?l.message:String(l);return console.error(`[memory-rag] saveSession failed: ${a}`),s.errors.push(a),s}}async function Mr(){try{let e=await me();return(await e.tableNames()).includes(te)?(await(await e.openTable(te)).query().toArray()).map(r=>({sessionId:r.sessionId,date:r.date,title:r.title,transcript:r.transcript,reflection:r.reflection,memoryCount:r.memoryCount,timestamp:r.timestamp})):[]}catch(e){return console.error(`[memory-rag] getAllSessions failed: ${e}`),[]}}async function kr(e,t,n){let o={indexed:0,errors:[]};if(!m.memory.rag.enabled||n.length===0)return o;console.log(`[memory-rag] indexing ${n.length} memories for session ${e}`);try{let r=await me(),s=await r.tableNames(),l,a=!1;s.includes(G)?l=await r.openTable(G):a=!0;for(let c=0;c<n.length;c++){let u=n[c];try{let i=await st(u.content),d={id:`${e}-${c}`,sessionId:e,date:t,type:u.type,content:u.content,vector:i,timestamp:Date.now()};a?(l=await r.createTable(G,[d]),a=!1,console.log("[memory-rag] created memories table")):await l.add([d]),o.indexed++,console.log(`[memory-rag] indexed [${c+1}/${n.length}]: ${u.type}`)}catch(i){let d=i instanceof Error?i.message:String(i);o.errors.push(`${u.type}: ${d}`),console.error(`[memory-rag] failed to index item ${c}: ${d}`)}c<n.length-1&&await new Promise(i=>setTimeout(i,200))}return console.log(`[memory-rag] indexed ${o.indexed}/${n.length} memories`),o}catch(r){let s=r instanceof Error?r.message:String(r);return console.error(`[memory-rag] indexMemoryItems failed: ${s}`),o.errors.push(s),o}}async function bn(e,t=m.memory.rag.maxResults,n=m.memory.rag.similarityThreshold){if(!m.memory.rag.enabled)return[];console.log(`[memory-rag] searching: "${e.slice(0,50)}..."`);try{let o=await me();if(!(await o.tableNames()).includes(G))return console.log("[memory-rag] memories table not found"),[];let s=await o.openTable(G),l=await s.countRows();console.log(`[memory-rag] memories table has ${l} rows`);let a=await st(e),c=await s.vectorSearch(a).column(vr).limit(t*2).toArray();if(console.log(`[memory-rag] search returned ${c.length} results`),c.length>0){let d=c.map(g=>g._distance?.toFixed(4)??"N/A");console.log(`[memory-rag] distances: [${d.join(", ")}]`)}let u=(1-n)*2;console.log(`[memory-rag] threshold=${n}, maxDistance=${u.toFixed(4)}`);let i=c.filter(d=>{let g=d._distance;return g===void 0||g<=u}).slice(0,t).map(d=>({id:d.id,sessionId:d.sessionId,date:d.date,type:d.type,content:d.content,timestamp:d.timestamp,_distance:d._distance}));return console.log(`[memory-rag] filtered: ${i.length} memories`),i.length>0&&i.forEach((d,g)=>{console.log(`[memory-rag] ${g+1}. [${d.type}] "${d.content.slice(0,50)}..." (dist=${d._distance?.toFixed(4)??"N/A"})`)}),i}catch(o){let r=o instanceof Error?o.message:String(o);return console.warn(`[memory-rag] search failed: ${r}`),[]}}async function xn(){try{let e=await me(),t=await e.tableNames(),n=0,o=0;return t.includes(te)&&(n=await(await e.openTable(te)).countRows()),t.includes(G)&&(o=await(await e.openTable(G)).countRows()),{sessionsCount:n,memoriesCount:o,embeddingModel:m.memory.rag.embeddingModel}}catch{return{sessionsCount:0,memoriesCount:0,embeddingModel:m.memory.rag.embeddingModel}}}async function vn(e){let t={success:!1,totalSessions:0,totalMemories:0,indexedMemories:0,errors:[],embeddingModel:m.memory.rag.embeddingModel,vectorDimension:null};console.log("[reindex] ========================================"),console.log("[reindex] Rebuilding memories from sessions table"),console.log(`[reindex] Embedding model: ${m.memory.rag.embeddingModel}`),console.log("[reindex] ========================================");try{let n=await me(),o=await n.tableNames();if(!o.includes(te))return console.log("[reindex] No sessions table found, nothing to reindex"),t.success=!0,t;let r=await Mr();if(t.totalSessions=r.length,r.length===0)return console.log("[reindex] No sessions found"),t.success=!0,t;console.log(`[reindex] Found ${r.length} sessions`);let s=[];for(let a of r)try{let c=JSON.parse(a.reflection);if(c.memories&&c.memories.length>0)for(let u of c.memories)s.push({sessionId:a.sessionId,date:a.date,item:u})}catch(c){console.warn(`[reindex] Failed to parse reflection for session ${a.sessionId}: ${c}`)}if(t.totalMemories=s.length,console.log(`[reindex] Found ${s.length} memories to reindex`),s.length===0)return console.log("[reindex] No memories to reindex"),t.success=!0,t;o.includes(G)&&(await n.dropTable(G),console.log("[reindex] Dropped old memories table"));let l=null;for(let a=0;a<s.length;a++){let{sessionId:c,date:u,item:i}=s[a],d=`[${a+1}/${s.length}]`;try{e?.(a+1,s.length,`Indexing: ${i.content.slice(0,30)}...`);let g=await st(i.content);t.vectorDimension===null&&(t.vectorDimension=g.length);let f={id:`${c}-${a}`,sessionId:c,date:u,type:i.type,content:i.content,vector:g,timestamp:Date.now()};l===null?(l=await n.createTable(G,[f]),console.log(`[reindex] ${d} Created new memories table`)):await l.add([f]),t.indexedMemories++,console.log(`[reindex] ${d} Indexed: [${i.type}] ${i.content.slice(0,40)}...`)}catch(g){let f=g instanceof Error?g.message:String(g);t.errors.push(`${i.content.slice(0,30)}: ${f}`),console.error(`[reindex] ${d} Failed: ${f}`)}a<s.length-1&&await new Promise(g=>setTimeout(g,200))}return console.log("[reindex] ========================================"),console.log("[reindex] Reindex complete!"),console.log(`[reindex] Sessions: ${t.totalSessions}`),console.log(`[reindex] Total memories: ${t.totalMemories}`),console.log(`[reindex] Indexed: ${t.indexedMemories}`),console.log(`[reindex] Errors: ${t.errors.length}`),console.log("[reindex] ========================================"),t.success=!0,t}catch(n){let o=n instanceof Error?n.message:String(n);return console.error(`[reindex] Failed: ${o}`),t.errors.push(o),t}}var rt,te,G,vr,ze,ee,it=j(()=>{"use strict";H();X();le();rt=xr.join(m.agentDir,"tg-memory-db"),te="sessions",G="memories",vr="vector",ze=null,ee=null});import Sn from"node:path";import{AuthStorage as $r,ModelRegistry as Ar}from"@mariozechner/pi-coding-agent";import{completeSimple as _r,getModel as Pr}from"@mariozechner/pi-ai";function Cr(){return m.memory.systemPrompt||Rr}function Er(e){let t=e.trim().toLowerCase();return t==="codex"?"openai-codex":t}function Dr(e,t){return e!=="openai-codex"?t:Tr[t]??t}async function Or(e,t){await R(m.agentDir);let n=Sn.join(m.agentDir,"auth.json"),o=new $r(n),r=q();r&&o.setRuntimeApiKey("openai-codex",r.accessToken);let s=Sn.join(m.agentDir,"models.json"),l=new Ar(o,s),a=async(d,g,f)=>{let y=Er(d),w=Dr(y,g),$=l.find(y,w);if(!$)try{$=Pr(y,w)}catch{}if($){let A=await o.getApiKey(y);return{model:$,provider:y,modelId:w,apiKey:A??void 0,source:f}}return null};if(e&&t){let d=await a(e,t,"session");if(d)return console.log(`[memory] using session model: ${d.provider}/${d.modelId}`),d}if(m.memory.modelProvider&&m.memory.modelId){let d=await a(m.memory.modelProvider,m.memory.modelId,"memory-config");if(d)return console.log(`[memory] using configured memory model: ${d.provider}/${d.modelId}`),d}let c=m.modelProvider,u=m.modelRef.includes("/")?m.modelRef.split("/")[1]:m.modelRef;if(c&&u){let d=await a(c,u,"system-default");if(d)return console.log(`[memory] using system default model: ${d.provider}/${d.modelId}`),d}let i=l.getAll();if(i.length>0){let d=i[0],g=await o.getApiKey(d.provider);return console.log(`[memory] using first available model: ${d.provider}/${d.id}`),{model:d,provider:d.provider,modelId:d.id,apiKey:g??void 0,source:"first-available"}}return console.warn("[memory] no model available for reflection"),null}function Ir(e){let t={emotional:"",insights:"",advice:"",memories:[]};if(!e.trim())return t;try{let n=e.trim(),o=n.match(/```(?:json)?\s*([\s\S]*?)```/);o&&(n=o[1].trim());let r=JSON.parse(n),s={emotional:typeof r.emotional=="string"?r.emotional:"",insights:typeof r.insights=="string"?r.insights:"",advice:typeof r.advice=="string"?r.advice:"",memories:[]};if(Array.isArray(r.memories))for(let l of r.memories)l&&typeof l=="object"&&typeof l.type=="string"&&typeof l.content=="string"&&s.memories.push({type:l.type,content:l.content});return s}catch(n){return console.warn(`[memory] failed to parse reflection JSON: ${n}`),{emotional:"",insights:e.slice(0,500),advice:"",memories:[{type:"insight",content:`Session summary: ${e.slice(0,200)}`}]}}}async function Ue(e,t,n){if(!m.memory.enabled)return{success:!0,reflected:!1,memoriesIndexed:0};if(e.messages.length===0)return{success:!0,reflected:!1,memoriesIndexed:0};let r=new Date().toISOString().split("T")[0],s=e.messages.map(a=>`[${a.role.toUpperCase()}]: ${a.content}`).join(`
|
|
46
|
+
`):void 0;console.log(`[tg-agent] systemPrompt append=${M?M.slice(0,80)+"...":"(none)"}`);let R=new xr({cwd:t,agentDir:g.agentDir,settingsManager:y,extensionFactories:b.length>0?b:void 0,appendSystemPrompt:M});await R.reload();let{session:_,modelFallbackMessage:v}=await yr({cwd:t,agentDir:g.agentDir,authStorage:r,modelRegistry:m,model:i??void 0,sessionManager:p,settingsManager:y,resourceLoader:R,customTools:mn({telegram:e.telegram})});try{let w=_.messages,S=w.some(N=>{let Z=N.role,H=N.content;return Z==="system"&&typeof H=="string"?H.toLowerCase().includes("compaction")||H.toLowerCase().includes("compact"):N.type==="compaction"||N.compaction!==void 0});console.log(`[tg-agent] session manager type: ${typeof p}`),console.log(`[tg-agent] session messages count: ${w.length}`),console.log(`[tg-agent] compacting support detected: ${S||"unknown (will be detected during runtime)"}`);let E=typeof p.compact=="function",W=typeof p.appendCompaction=="function";console.log(`[tg-agent] SessionManager.compact method: ${E}`),console.log(`[tg-agent] SessionManager.appendCompaction method: ${W}`)}catch(w){let S=w instanceof Error?w.message:String(w);console.warn(`[tg-agent] compacting check failed: ${S}`)}v&&console.warn(`[tg-agent] modelFallback=${v}`);let x=!1,k=()=>{x=!0,_.abort()};e.onAbortReady?.(k);let D=g.logAgentEvents,kt=g.logAgentStream,he=new Map,Ge=_.subscribe(w=>{switch(w.type){case"agent_start":D&&console.log(`[tg-agent] agent start session=${e.sessionId}`),U=Date.now(),e.onStatus?.({type:"agent_start"});break;case"agent_end":D&&console.log(`[tg-agent] agent end session=${e.sessionId}`),e.onStatus?.({type:"agent_end"});break;case"turn_start":D&&console.log(`[tg-agent] turn start session=${e.sessionId}`),U=Date.now(),e.onStatus?.({type:"turn_start"});break;case"turn_end":D&&console.log(`[tg-agent] turn end session=${e.sessionId} toolResults=${w.toolResults.length}`),U=Date.now(),e.onStatus?.({type:"turn_end",toolResults:w.toolResults.length});break;case"message_start":{if(D){let S=w.message.role??"unknown";console.log(`[tg-agent] message start session=${e.sessionId} role=${S}`)}U=Date.now();{let S=w.message.role??"unknown";e.onStatus?.({type:"message_start",role:S})}break}case"message_end":{if(D){let S=w.message.role??"unknown";console.log(`[tg-agent] message end session=${e.sessionId} role=${S}`)}U=Date.now();{let S=w.message.role??"unknown";e.onStatus?.({type:"message_end",role:S})}break}case"message_update":{if(!kt)break;if(w.assistantMessageEvent.type==="text_delta"){let L=(w.assistantMessageEvent.delta??"").length;L>0&&console.log(`[tg-agent] stream delta session=${e.sessionId} chars=${L}`),U=Date.now()}w.assistantMessageEvent.type==="thinking_delta"&&(U=Date.now());break}case"tool_execution_start":{he.set(w.toolCallId,Date.now()),console.log(`[tg-agent] tool start name=${w.toolName} id=${w.toolCallId}`),_e+=1,U=Date.now(),e.onStatus?.({type:"tool_start",name:w.toolName,id:w.toolCallId,args:w.args});break}case"tool_execution_end":{let S=he.get(w.toolCallId),L=S?Date.now()-S:0;console.log(`[tg-agent] tool end name=${w.toolName} id=${w.toolCallId} ok=${!w.isError} durationMs=${L}`),he.delete(w.toolCallId),_e=Math.max(0,_e-1),U=Date.now(),e.onStatus?.({type:"tool_end",name:w.toolName,id:w.toolCallId,ok:!w.isError,durationMs:L});break}case"auto_compaction_start":{let S=w.reason??"unknown";console.log(`[tg-agent] auto compaction started session=${e.sessionId} reason=${S}`),U=Date.now();break}case"auto_compaction_end":{let S=w.willRetry??!1;console.log(`[tg-agent] auto compaction ended session=${e.sessionId} willRetry=${S}`),U=Date.now();break}default:break}}),we=null,Ye=null,Pe=!1,Pt=0,_t=!1,U=Date.now(),_e=0;try{let w=Date.now();we=setInterval(()=>{let E=Date.now()-w;console.log(`[tg-agent] prompt running session=${e.sessionId} elapsedMs=${E} streaming=${_.isStreaming}`),e.onStatus?.({type:"heartbeat",elapsedMs:E,streaming:_.isStreaming})},15e3),Ye=setInterval(()=>{if(Pe||_e>0)return;let E=Date.now()-U,W=_.isStreaming?g.modelTimeoutStreamingMs:g.modelTimeoutMs,N=Math.max(1e3,W);E>=N&&(Pe=!0,Pt=N,_t=_.isStreaming,console.warn(`[tg-agent] model timeout session=${e.sessionId} elapsedMs=${E}`),_.abort())},2e3);try{if(await _.prompt(e.prompt,e.images&&e.images.length>0?{images:e.images}:void 0),Pe)throw new Error(`Model request timed out after ${g.modelTimeoutMs}ms`)}catch(E){if(x)throw new Error("Cancelled by user.");if(Pe){let W=_t?" (streaming)":"",N=Pt||g.modelTimeoutMs;throw new Error(`Model request timed out after ${N}ms${W}`)}throw E}we&&clearInterval(we);let S=Dr(_.messages);if(S){let E=S?.stopReason,W=S?.errorMessage;if(E==="error"){let N=W?Cr(W):"Model error without details.";throw console.warn(`[tg-agent] model error session=${e.sessionId} error=${N}`),new Error(N)}}let L=Tr(_.messages,_);if(!L){let E=Rr(_.messages);throw console.warn(`[tg-agent] empty response session=${e.sessionId} ${E}`),new Error("No assistant response.")}return{text:L,sessionFile:n,sessionId:_.sessionId,modelProvider:_.model?.provider??c,modelId:_.model?.id??d,modelFallbackMessage:v}}finally{we&&clearInterval(we),Ye&&clearInterval(Ye),Ge(),p.flushPendingToolResults?.(),_.dispose()}}var Sr,Rn=F(()=>{"use strict";K();me();gn();je();G();ct();An();dt();Sr={"codex-mini-latest":"gpt-5.1-codex-mini","codex-max-latest":"gpt-5.1-codex-max","codex-latest":"gpt-5.2-codex"}});import Er from"node:path";import*as Cn from"@lancedb/lancedb";import mt from"openai";function jr(){if(oe)return oe;let e=g.memory.rag;if(e.embeddingApiKey){let n={apiKey:e.embeddingApiKey};return e.embeddingBaseUrl&&(n.baseURL=e.embeddingBaseUrl),oe=new mt(n),console.log(`[memory-rag] using embedding API key${e.embeddingBaseUrl?` (baseURL: ${e.embeddingBaseUrl})`:""}`),oe}if(g.openaiApiKey)return oe=new mt({apiKey:g.openaiApiKey}),console.log("[memory-rag] using OpenAI API key from config"),oe;let t=Y();if(t)return oe=new mt({apiKey:t.accessToken}),console.log("[memory-rag] using Codex OAuth token"),oe;throw new Error("No API key for embeddings. Set memory.rag.embedding_api_key or run `codex login`.")}async function pt(e){let t=jr(),n=g.memory.rag.embeddingModel;console.log(`[memory-rag] embedding ${e.length} chars using ${n}`);let o=3e4,r=new Promise((s,l)=>{setTimeout(()=>l(new Error(`Embedding timeout after ${o}ms`)),o)});try{let s=await Promise.race([t.embeddings.create({model:n,input:e,encoding_format:"float"}),r]);if(!s?.data?.[0]?.embedding)throw new Error(`Invalid embedding response: ${JSON.stringify(s).slice(0,200)}`);let l=s.data[0].embedding;return console.log(`[memory-rag] got ${l.length}D embedding`),l}catch(s){throw s instanceof Error&&console.error(`[memory-rag] embedding error: ${s.message}`),s}}async function fe(){return Be||(await T(gt),Be=await Cn.connect(gt),console.log(`[memory-rag] connected to DB at ${gt}`),Be)}async function Ke(e,t,n,o,r){let s={sessionSaved:!1,memoriesIndexed:0,errors:[]};if(!g.memory.rag.enabled)return console.log("[memory-rag] RAG disabled, skipping save"),s;console.log(`[memory-rag] saving session ${e}`);try{let l=await fe(),a=await l.tableNames(),u={sessionId:e,date:t,title:n,transcript:o,reflection:JSON.stringify(r),memoryCount:r.memories?.length??0,timestamp:Date.now()};if(a.includes(re)?await(await l.openTable(re)).add([u]):await l.createTable(re,[u]),s.sessionSaved=!0,console.log("[memory-rag] session saved to DB"),r.memories&&r.memories.length>0){let m=await Nr(e,t,r.memories);s.memoriesIndexed=m.indexed,s.errors=m.errors}return s}catch(l){let a=l instanceof Error?l.message:String(l);return console.error(`[memory-rag] saveSession failed: ${a}`),s.errors.push(a),s}}async function Ir(){try{let e=await fe();return(await e.tableNames()).includes(re)?(await(await e.openTable(re)).query().toArray()).map(r=>({sessionId:r.sessionId,date:r.date,title:r.title,transcript:r.transcript,reflection:r.reflection,memoryCount:r.memoryCount,timestamp:r.timestamp})):[]}catch(e){return console.error(`[memory-rag] getAllSessions failed: ${e}`),[]}}async function Nr(e,t,n){let o={indexed:0,errors:[]};if(!g.memory.rag.enabled||n.length===0)return o;console.log(`[memory-rag] indexing ${n.length} memories for session ${e}`);try{let r=await fe(),s=await r.tableNames(),l,a=!1;s.includes(V)?l=await r.openTable(V):a=!0;for(let u=0;u<n.length;u++){let m=n[u];try{let i=await pt(m.content),c={id:`${e}-${u}`,sessionId:e,date:t,type:m.type,content:m.content,vector:i,timestamp:Date.now()};a?(l=await r.createTable(V,[c]),a=!1,console.log("[memory-rag] created memories table")):await l.add([c]),o.indexed++,console.log(`[memory-rag] indexed [${u+1}/${n.length}]: ${m.type}`)}catch(i){let c=i instanceof Error?i.message:String(i);o.errors.push(`${m.type}: ${c}`),console.error(`[memory-rag] failed to index item ${u}: ${c}`)}u<n.length-1&&await new Promise(i=>setTimeout(i,200))}return console.log(`[memory-rag] indexed ${o.indexed}/${n.length} memories`),o}catch(r){let s=r instanceof Error?r.message:String(r);return console.error(`[memory-rag] indexMemoryItems failed: ${s}`),o.errors.push(s),o}}async function Tn(e,t=g.memory.rag.maxResults,n=g.memory.rag.similarityThreshold){if(!g.memory.rag.enabled)return[];console.log(`[memory-rag] searching: "${e.slice(0,50)}..."`);try{let o=await fe();if(!(await o.tableNames()).includes(V))return console.log("[memory-rag] memories table not found"),[];let s=await o.openTable(V),l=await s.countRows();console.log(`[memory-rag] memories table has ${l} rows`);let a=await pt(e),u=await s.vectorSearch(a).column(Or).limit(t*2).toArray();if(console.log(`[memory-rag] search returned ${u.length} results`),u.length>0){let c=u.map(d=>d._distance?.toFixed(4)??"N/A");console.log(`[memory-rag] distances: [${c.join(", ")}]`)}let m=(1-n)*2;console.log(`[memory-rag] threshold=${n}, maxDistance=${m.toFixed(4)}`);let i=u.filter(c=>{let d=c._distance;return d===void 0||d<=m}).slice(0,t).map(c=>({id:c.id,sessionId:c.sessionId,date:c.date,type:c.type,content:c.content,timestamp:c.timestamp,_distance:c._distance}));return console.log(`[memory-rag] filtered: ${i.length} memories`),i.length>0&&i.forEach((c,d)=>{console.log(`[memory-rag] ${d+1}. [${c.type}] "${c.content.slice(0,50)}..." (dist=${c._distance?.toFixed(4)??"N/A"})`)}),i}catch(o){let r=o instanceof Error?o.message:String(o);return console.warn(`[memory-rag] search failed: ${r}`),[]}}async function Dn(){try{let e=await fe(),t=await e.tableNames(),n=0,o=0;return t.includes(re)&&(n=await(await e.openTable(re)).countRows()),t.includes(V)&&(o=await(await e.openTable(V)).countRows()),{sessionsCount:n,memoriesCount:o,embeddingModel:g.memory.rag.embeddingModel}}catch{return{sessionsCount:0,memoriesCount:0,embeddingModel:g.memory.rag.embeddingModel}}}async function En(e){let t={success:!1,totalSessions:0,totalMemories:0,indexedMemories:0,errors:[],embeddingModel:g.memory.rag.embeddingModel,vectorDimension:null};console.log("[reindex] ========================================"),console.log("[reindex] Rebuilding memories from sessions table"),console.log(`[reindex] Embedding model: ${g.memory.rag.embeddingModel}`),console.log("[reindex] ========================================");try{let n=await fe(),o=await n.tableNames();if(!o.includes(re))return console.log("[reindex] No sessions table found, nothing to reindex"),t.success=!0,t;let r=await Ir();if(t.totalSessions=r.length,r.length===0)return console.log("[reindex] No sessions found"),t.success=!0,t;console.log(`[reindex] Found ${r.length} sessions`);let s=[];for(let a of r)try{let u=JSON.parse(a.reflection);if(u.memories&&u.memories.length>0)for(let m of u.memories)s.push({sessionId:a.sessionId,date:a.date,item:m})}catch(u){console.warn(`[reindex] Failed to parse reflection for session ${a.sessionId}: ${u}`)}if(t.totalMemories=s.length,console.log(`[reindex] Found ${s.length} memories to reindex`),s.length===0)return console.log("[reindex] No memories to reindex"),t.success=!0,t;o.includes(V)&&(await n.dropTable(V),console.log("[reindex] Dropped old memories table"));let l=null;for(let a=0;a<s.length;a++){let{sessionId:u,date:m,item:i}=s[a],c=`[${a+1}/${s.length}]`;try{e?.(a+1,s.length,`Indexing: ${i.content.slice(0,30)}...`);let d=await pt(i.content);t.vectorDimension===null&&(t.vectorDimension=d.length);let p={id:`${u}-${a}`,sessionId:u,date:m,type:i.type,content:i.content,vector:d,timestamp:Date.now()};l===null?(l=await n.createTable(V,[p]),console.log(`[reindex] ${c} Created new memories table`)):await l.add([p]),t.indexedMemories++,console.log(`[reindex] ${c} Indexed: [${i.type}] ${i.content.slice(0,40)}...`)}catch(d){let p=d instanceof Error?d.message:String(d);t.errors.push(`${i.content.slice(0,30)}: ${p}`),console.error(`[reindex] ${c} Failed: ${p}`)}a<s.length-1&&await new Promise(d=>setTimeout(d,200))}return console.log("[reindex] ========================================"),console.log("[reindex] Reindex complete!"),console.log(`[reindex] Sessions: ${t.totalSessions}`),console.log(`[reindex] Total memories: ${t.totalMemories}`),console.log(`[reindex] Indexed: ${t.indexedMemories}`),console.log(`[reindex] Errors: ${t.errors.length}`),console.log("[reindex] ========================================"),t.success=!0,t}catch(n){let o=n instanceof Error?n.message:String(n);return console.error(`[reindex] Failed: ${o}`),t.errors.push(o),t}}var gt,re,V,Or,Be,oe,ft=F(()=>{"use strict";K();G();me();gt=Er.join(g.agentDir,"tg-memory-db"),re="sessions",V="memories",Or="vector",Be=null,oe=null});import On from"node:path";import{AuthStorage as Lr,ModelRegistry as Fr}from"@mariozechner/pi-coding-agent";import{completeSimple as zr,getModel as Ur}from"@mariozechner/pi-ai";function Kr(){return g.memory.systemPrompt||Br}function Wr(e){let t=e.trim().toLowerCase();return t==="codex"?"openai-codex":t}function Hr(e,t){return e!=="openai-codex"?t:Jr[t]??t}async function qr(e,t){await T(g.agentDir);let n=On.join(g.agentDir,"auth.json"),o=new Lr(n),r=Y();r&&o.setRuntimeApiKey("openai-codex",r.accessToken);let s=On.join(g.agentDir,"models.json"),l=new Fr(o,s),a=async(c,d,p)=>{let y=Wr(c),h=Hr(y,d),b=l.find(y,h);if(!b)try{b=Ur(y,h)}catch{}if(b){let $=await o.getApiKey(y);return{model:b,provider:y,modelId:h,apiKey:$??void 0,source:p}}return null};if(e&&t){let c=await a(e,t,"session");if(c)return console.log(`[memory] using session model: ${c.provider}/${c.modelId}`),c}if(g.memory.modelProvider&&g.memory.modelId){let c=await a(g.memory.modelProvider,g.memory.modelId,"memory-config");if(c)return console.log(`[memory] using configured memory model: ${c.provider}/${c.modelId}`),c}let u=g.modelProvider,m=g.modelRef.includes("/")?g.modelRef.split("/")[1]:g.modelRef;if(u&&m){let c=await a(u,m,"system-default");if(c)return console.log(`[memory] using system default model: ${c.provider}/${c.modelId}`),c}let i=l.getAll();if(i.length>0){let c=i[0],d=await o.getApiKey(c.provider);return console.log(`[memory] using first available model: ${c.provider}/${c.id}`),{model:c,provider:c.provider,modelId:c.id,apiKey:d??void 0,source:"first-available"}}return console.warn("[memory] no model available for reflection"),null}function Gr(e){let t={emotional:"",insights:"",advice:"",memories:[]};if(!e.trim())return t;try{let n=e.trim(),o=n.match(/```(?:json)?\s*([\s\S]*?)```/);o&&(n=o[1].trim());let r=JSON.parse(n),s={emotional:typeof r.emotional=="string"?r.emotional:"",insights:typeof r.insights=="string"?r.insights:"",advice:typeof r.advice=="string"?r.advice:"",memories:[]};if(Array.isArray(r.memories))for(let l of r.memories)l&&typeof l=="object"&&typeof l.type=="string"&&typeof l.content=="string"&&s.memories.push({type:l.type,content:l.content});return s}catch(n){return console.warn(`[memory] failed to parse reflection JSON: ${n}`),{emotional:"",insights:e.slice(0,500),advice:"",memories:[{type:"insight",content:`Session summary: ${e.slice(0,200)}`}]}}}async function Je(e,t,n){if(!g.memory.enabled)return{success:!0,reflected:!1,memoriesIndexed:0};if(e.messages.length===0)return{success:!0,reflected:!1,memoriesIndexed:0};let r=new Date().toISOString().split("T")[0],s=e.messages.map(a=>`[${a.role.toUpperCase()}]: ${a.content}`).join(`
|
|
47
47
|
|
|
48
|
-
`),l=await
|
|
48
|
+
`),l=await qr(t,n);if(!l){console.log("[memory] no model available, saving raw session");let a={emotional:"",insights:"No model available for reflection",advice:"",memories:[]};return{success:(await Ke(e.id,r,e.title,s,a)).sessionSaved,reflected:!1,memoriesIndexed:0}}console.log(`[memory] reflecting on session ${e.id} using ${l.provider}/${l.modelId}`);try{let u={systemPrompt:Kr(),messages:[{role:"user",content:`Conversation transcript:
|
|
49
49
|
|
|
50
|
-
${s}`,timestamp:Date.now()}]},
|
|
50
|
+
${s}`,timestamp:Date.now()}]},m=await zr(l.model,u,{apiKey:l.apiKey,maxTokens:2e3,sessionId:e.id});if(m.stopReason==="error")throw new Error(m.errorMessage||"Unknown API error");let i=m.content.find(y=>y.type==="text"),c=i?.type==="text"?i.text:"";c.trim()||(c=m.content.filter(h=>h.type==="thinking").map(h=>h.type==="thinking"?h.thinking:"").filter(Boolean).join(`
|
|
51
51
|
|
|
52
|
-
`));let
|
|
52
|
+
`));let d=Gr(c);console.log(`[memory] reflection generated: ${d.memories.length} memories`);let p=await Ke(e.id,r,e.title,s,d);return p.errors.length>0&&console.warn(`[memory] some errors during save: ${p.errors.join(", ")}`),console.log(`[memory] session archived, ${p.memoriesIndexed} memories indexed`),{success:p.sessionSaved,reflected:!0,memoriesIndexed:p.memoriesIndexed}}catch(a){let u=a instanceof Error?a.message:String(a);console.error(`[memory] reflection failed: ${u}`);let m={emotional:"",insights:`Reflection failed: ${u}`,advice:"",memories:[]};return{success:(await Ke(e.id,r,e.title,s,m)).sessionSaved,reflected:!1,memoriesIndexed:0,error:u}}}var Br,Jr,jn=F(()=>{"use strict";K();G();me();ft();Br=`You are a caring AI companion summarizing a conversation with Shawn.
|
|
53
53
|
|
|
54
54
|
Your task is to:
|
|
55
55
|
1. Understand Shawn's emotional state and what's important to them
|
|
@@ -82,33 +82,45 @@ Guidelines:
|
|
|
82
82
|
- Each memory should be self-contained and specific
|
|
83
83
|
- Focus on information that would help Shawn in the future
|
|
84
84
|
- Keep each memory concise (one sentence)
|
|
85
|
-
- Prioritize what matters for Shawn's growth and wellbeing`;
|
|
86
|
-
`)}function
|
|
87
|
-
|
|
88
|
-
[Timed out - Operation blocked]`,{chat_id:t,message_id:l.message_id}).catch(()=>{}),
|
|
89
|
-
`)}function
|
|
90
|
-
`),
|
|
91
|
-
|
|
92
|
-
[truncated]`,truncated:!0}}async function
|
|
93
|
-
args: ${
|
|
94
|
-
`)}async function
|
|
95
|
-
`);await
|
|
96
|
-
|
|
97
|
-
No providers found.`:"No providers found.";await
|
|
98
|
-
`),
|
|
99
|
-
|
|
100
|
-
`
|
|
101
|
-
`)
|
|
102
|
-
`),r);return}
|
|
103
|
-
`),r)
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
85
|
+
- Prioritize what matters for Shawn's growth and wellbeing`;Jr={"codex-mini-latest":"gpt-5.1-codex-mini","codex-max-latest":"gpt-5.1-codex-max","codex-latest":"gpt-5.2-codex"}});var Ws={};import ye from"node:path";import{spawn as Yr}from"node:child_process";import In from"node:fs/promises";import Vr from"node-telegram-bot-api";import{AuthStorage as Xr,ModelRegistry as Qr}from"@mariozechner/pi-coding-agent";import{getOAuthProviders as Nn,getOAuthProvider as Zr}from"@mariozechner/pi-ai";function ts(e,t){ke.set(e,t)}function vt(e){ke.delete(e)}function ns(e){let t=e.trim();if(t){if(t==="Markdown"||t==="MarkdownV2"||t==="HTML")return t;console.warn(`[tg-agent] invalid TELEGRAM_PARSE_MODE=${t}, ignoring`)}}function rs(){return ye.join(g.agentDir,"uploads")}function ss(e){return e.length===0?null:e.reduce((t,n)=>{let o=t.file_size??t.width*t.height;return(n.file_size??n.width*n.height)>o?n:t})}function is(e){return!!e?.startsWith("image/")}function as(e){switch(ye.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 cs(e){if(!Number.isFinite(e)||e<=0)return"0 B";let t=["B","KB","MB","GB"],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 ls(e){return e.length===0?"":e.map(t=>{let n=[];t.mimeType&&n.push(t.mimeType),t.bytes>0&&n.push(cs(t.bytes));let o=n.length>0?` (${n.join(", ")})`:"";return`Attachment saved: ${t.path}${o}`}).join(`
|
|
86
|
+
`)}function us(e){let t=[];if(e.photo&&e.photo.length>0){let n=ss(e.photo);n&&t.push({kind:"photo",fileId:n.file_id,fileSize:n.file_size})}if(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}),e.audio){let n=e.audio.mime_type?.split("/")[1]??"mp3",o=e.audio.title??e.audio.performer??"audio";t.push({kind:"document",fileId:e.audio.file_id,fileName:`${o}.${n}`,mimeType:e.audio.mime_type,fileSize:e.audio.file_size})}if(e.voice&&t.push({kind:"document",fileId:e.voice.file_id,fileName:`voice.${e.voice.mime_type?.split("/")[1]??"ogg"}`,mimeType:e.voice.mime_type,fileSize:e.voice.file_size}),e.video){let n=e.video.mime_type?.split("/")[1]??"mp4";t.push({kind:"document",fileId:e.video.file_id,fileName:`video.${n}`,mimeType:e.video.mime_type,fileSize:e.video.file_size})}return e.video_note&&t.push({kind:"document",fileId:e.video_note.file_id,fileName:"video_note.mp4",mimeType:"video/mp4",fileSize:e.video_note.file_size}),t}async function ds(e){if(e.length===0)return{resolved:[],images:[]};let t=rs();await T(t);let n=[],o=[];for(let r of e)try{let s=await I.downloadFile(r.fileId,t),l=await In.stat(s),a=r.fileName??ye.basename(s),u=r.mimeType??as(s),m=r.kind==="photo"||is(u),i={path:s,name:a,mimeType:u,bytes:l.size,isImage:m};if(n.push(i),m){let c=await In.readFile(s);o.push({type:"image",data:c.toString("base64"),mimeType:u??os})}}catch(s){console.warn("[tg-agent] attachment download failed",s)}return{resolved:n,images:o}}function Me(e,t){let n=0;for(let o=0;o<e.length;o+=1){let r=e[o];if(r==="\\"){o+=1;continue}r===t&&(n+=1)}return n}function gs(e){if(Me(e,"*")%2!==0||Me(e,"_")%2!==0||Me(e,"`")%2!==0)return!1;let r=Me(e,"["),s=Me(e,"]");return r===s}function ps(e){for(let t=0;t<e.length;t+=1){let n=e[t];if(n==="\\"){t+=1;continue}if(ms.has(n))return!1}return!0}function Jn(e){let t=ns(g.telegramParseMode);return t?[t]:ps(e)?["MarkdownV2","Markdown"]:gs(e)?["Markdown"]:[]}function Ae(e,t){let n=$e.get(e);return n?(clearTimeout(n.timeoutId),$e.delete(e),n.messageId&&I.editMessageReplyMarkup({inline_keyboard:[]},{chat_id:n.chatId,message_id:n.messageId}).catch(()=>{}),n.resolve(t),!0):!1}async function Ln(e,t,n,o,r){if($e.has(e))throw new Error("Audit confirmation already pending.");let s=Mt([{label:"Approve",command:"/approve"},{label:"Stop",command:"/stop"}],2),l=await $t(t,n,s,r);return await new Promise((a,u)=>{let m=setTimeout(()=>{$e.delete(e),I.editMessageText(`${n}
|
|
87
|
+
|
|
88
|
+
[Timed out - Operation blocked]`,{chat_id:t,message_id:l.message_id}).catch(()=>{}),u(new Error("Audit confirmation timed out."))},o);$e.set(e,{resolve:a,reject:u,timeoutId:m,chatId:t,messageThreadId:r,messageId:l.message_id})})}function X(e){let t=e.trim().toLowerCase();return ys.get(t)??t}function ws(e,t){return e!=="openai-codex"?t:hs[t]??t}async function se(){await T(g.agentDir);let e=ye.join(g.agentDir,"auth.json"),t=new Xr(e),n=Y();n&&t.setRuntimeApiKey("openai-codex",n.accessToken);let o=ye.join(g.agentDir,"models.json"),r=new Qr(t,o);return{authStorage:t,modelRegistry:r}}function Wn(e){let t=ie.get(e);t&&(clearTimeout(t.timeoutId),ie.delete(e))}function bs(e,t){let n=ie.get(e);n&&(clearTimeout(n.timeoutId),ie.delete(e),n.reject(new Error(t)))}async function Fn(e,t,n,o){if(ie.has(e))throw new Error("Login is already awaiting input.");let r=n.placeholder?`${n.message} (${n.placeholder})`:n.message;return await f(t,r,o),await new Promise((s,l)=>{let a=setTimeout(()=>{ie.delete(e),l(new Error("Login prompt timed out."))},fs);ie.set(e,{resolve:s,reject:l,timeoutId:a,chatId:t})})}async function Hn(e,t,n){let o=ke.get(t);if(!o){await f(e,"No active request to stop.",n);return}o.cancelRequested=!0,o.abortRequested=!0,o.status&&o.status.update("Cancelled by user.",!0),o.abort&&o.abort(),(!o.status||o.chatId!==e)&&await f(e,"Stopping current request...",n)}async function qn(e,t,n,o){let r=await Le(t),s=n||r.activeSessionId;if(!s){await f(e,"No active session to close.",o);return}let l=r.sessions[s];if(l&&l.messages.length>0)try{await f(e,"Reflecting on session memory...",o);let i=await Je(l,l.modelProvider,l.modelId);i.reflected?await f(e,"Memory archived successfully.",o):i.error?await f(e,`Memory saved (reflection failed: ${i.error})`,o):await f(e,"Memory saved (no reflection).",o)}catch(i){console.warn("[tg-agent] memory archival failed",i),await f(e,`Memory archival failed: ${ue(i)}`,o)}let a=ke.get(t);if(a){if(a.cancelRequested=!0,a.abortRequested=!0,a.status&&a.status.update("Cancelled by user.",!0),a.abort)try{a.abort()}catch(i){console.warn("[tg-agent] abort callback failed during force close",i)}vt(t)}if(!it(r,s)){await f(e,`Session not found: ${s}`,o);return}await j(r),await pe(t,s).catch(i=>{console.warn(`[tg-agent] delete session file failed id=${s}`,i)});let m=a?`Force-closed session ${s} (interrupted running task).`:`Closed session ${s}.`;await f(e,m,o)}function vs(){console.log(`[tg-agent] modelProvider=${g.modelProvider} modelRef=${g.modelRef} sessionDir=${g.sessionDir} maxConcurrent=${g.maxConcurrent}`),console.log(`[tg-agent] agentDir=${g.agentDir} workspaceDir=${g.workspaceDir}`);let e=Ee(g.agentDir),t=e.length>0?`on (${e.length})`:"off";console.log(`[tg-agent] tools fetchMaxBytes=${g.fetchMaxBytes} fetchTimeoutMs=${g.fetchTimeoutMs} mcp=${t}`),console.log(`[tg-agent] proxy url=${g.proxyUrl||"(none)"} fetchProxy=${g.fetchProxyUrl||"(none)"}`),console.log(`[tg-agent] tls extra_ca=${g.tlsExtraCaCerts||"(empty)"} reject_unauthorized=${g.tlsRejectUnauthorized===null?"(unset)":String(g.tlsRejectUnauthorized)}`);try{let{source:o}=Wt(g.modelProvider);console.log(`[tg-agent] authSource=${o}`)}catch(o){let r=o instanceof Error?o.message:String(o);console.warn(`[tg-agent] authSource=missing (${r})`)}let n=qt();console.log(n?`[tg-agent] proxyUrl=${n.url} kind=${n.kind} source=${n.source}`:"[tg-agent] proxyUrl=(none)")}function xt(e){if(!e.startsWith("/"))return null;let t=e.trim(),[n,...o]=t.split(" ");return{command:n.split("@")[0].slice(1).toLowerCase(),args:o.join(" ").trim()}}async function ht(e,t,n){let o=le(e);return o||(o=Fe(e,""),await j(e),await f(t,`Created session ${o.id}.`,n)),o}function Ss(e,t){let n=e.getAll(),o=new Map;for(let r of n){let s=o.get(r.provider)??{count:0,auth:t.hasAuth(r.provider)};s.count+=1,o.set(r.provider,s)}return Array.from(o.entries()).filter(([r])=>xs.has(r)).sort((r,s)=>r[0].localeCompare(s[0])).map(([r,s])=>({label:`${r} (${s.count}, ${s.auth?"ok":"no auth"})`,command:`/provider ${r}`}))}function Ms(e,t,n=[]){let o=e.getAll().filter(a=>a.provider===t).sort((a,u)=>a.id.localeCompare(u.id));if(n.length===0)return o.map(a=>({label:a.id,command:`/model ${t}/${a.id}`}));let r=new Map(o.map(a=>[a.id,a])),s=new Set,l=[];for(let a of n){let u=r.get(a);!u||s.has(u.id)||(s.add(u.id),l.push(u))}for(let a of o)s.has(a.id)||l.push(a);return l.map(a=>({label:a.id,command:`/model ${t}/${a.id}`}))}function $s(e,t,n=3){let o=new Set,r=[],s=rt(e);for(let l of s){if(l.modelProvider!==t)continue;let a=l.modelId;if(!(!a||o.has(a))&&(o.add(a),r.push(a),r.length>=n))break}return r}function As(e){let t=e.trim();if(!t)return null;if(t.includes("/")){let[n,o]=t.split("/",2);return!n||!o?null:{provider:X(n),modelId:o.trim()}}return{modelId:t}}function Gn(e,t){let n=Date.now(),o=zn.get(e)??0;n-o<ks||(zn.set(e,n),console.warn(`[tg-agent] unauthorized user=${e} chat=${t}`))}function Yn(e){let t=g.telegramAllowedUsers;return!t||t.size===0?!0:t.has(e)}function Ps(e){return e.length===0?"No sessions found.":["Sessions:",...e.map(n=>{let o=new Date(n.updatedAt).toISOString();return`- ${n.id} | ${n.title} | updated ${o}`})].join(`
|
|
89
|
+
`)}function qe(e,t,n){let o=String(e);return t!==void 0&&!n?null:t!==void 0&&n?`${o}_${t}`:o}function bt(e,t){if(t.workspaceDir)return t.workspaceDir;let n=g.workspaceMappings.get(e);return n||g.workspaceDir}async function St(e,t,n,o){let r={};return n&&(r.parse_mode=n),o!==void 0&&(r.message_thread_id=o),await I.sendMessage(e,t,r)}async function Vn(e,t,n,o,r){let s={chat_id:e,message_id:t};o&&(s.parse_mode=o),r!==void 0&&(s.message_thread_id=r),await I.editMessageText(n,s)}async function Xn(e,t){let n;for(let o of t)try{return await e(o)}catch(r){n=r;let s=r instanceof Error?r.message:String(r);console.warn(`[tg-agent] parse_mode ${o} failed, trying fallback: ${s}`)}try{return await e(void 0)}catch(o){if(n){let r=o instanceof Error?o.message:String(o);console.warn(`[tg-agent] parse_mode fallback to plain failed: ${r}`)}throw o}}async function _s(e,t,n){return await Xn(o=>St(e,t,o,n),Jn(t))}async function Rs(e,t,n,o){await Xn(r=>Vn(e,t,n,r,o),Jn(n))}async function f(e,t,n){let o=Xe(t,3900);for(let r of o)await _s(e,r,n)}async function Cs(e,t,n){let o=Xe(t,3900);for(let r of o)await St(e,r,void 0,n)}function Ds(){let e=z()-Qn;for(let[o,r]of Q)r.createdAt<e&&Q.delete(o);if(Q.size<=Un)return;let t=Array.from(Q.entries()).sort((o,r)=>o[1].createdAt-r[1].createdAt),n=Q.size-Un;for(let o=0;o<n;o+=1)Q.delete(t[o][0])}function Es(e){Ds();let t=ae();for(;Q.has(t);)t=ae();return Q.set(t,{command:e,createdAt:z()}),t}function Os(e){if(!e.startsWith("cmd:"))return null;let t=e.slice(4),n=Q.get(t);return n?z()-n.createdAt>Qn?(Q.delete(t),null):n.command:null}function js(e,t){if(e.length<=t)return[e];let n=[];for(let o=0;o<e.length;o+=t)n.push(e.slice(o,o+t));return n}function Mt(e,t){let n=[],o=[];for(let r of e){let s=Es(r.command);o.push({text:r.label,callback_data:`cmd:${s}`}),o.length>=t&&(n.push(o),o=[])}return o.length>0&&n.push(o),n}async function $t(e,t,n,o){let r={reply_markup:{inline_keyboard:n}};return o!==void 0&&(r.message_thread_id=o),await I.sendMessage(e,t,r)}async function He(e,t,n,o){let r=o?.perRow??1,s=o?.pageSize??Ts,l=o?.footer,a=o?.messageThreadId,u=js(n,s);for(let m=0;m<u.length;m+=1){let i=u[m],c=u.length>1?` (page ${m+1}/${u.length})`:"",d=[`${t}${c}`];l&&d.push(l);let p=Mt(i,r);await $t(e,d.join(`
|
|
90
|
+
`),p,a)}}function wt(e,t=Is){return e.length<=t?{text:e,truncated:!1}:{text:`${e.slice(0,Math.max(0,t-15))}...
|
|
91
|
+
|
|
92
|
+
[truncated]`,truncated:!0}}async function Ls(e,t){let n="Working...",r=(await St(e,n,void 0,t)).message_id,s=n,l=0,a=Promise.resolve(),u=(i,c=!1)=>{let d=Date.now();!c&&d-l<Ns||i!==s&&(s=i,l=d,a=a.then(async()=>{await Vn(e,r,i,void 0,t)}).catch(p=>{console.warn("[tg-agent] status edit failed",p)}))},m=i=>{s=i,l=Date.now(),a=a.then(async()=>{await Rs(e,r,i,t)}).catch(c=>{console.warn("[tg-agent] status edit failed",c)})};return{update:(i,c=!1)=>{let d=wt(i).text;u(d,c)},finalize:async i=>{let c=wt(i).text;m(c),await a},fail:async i=>{let c=wt(i).text;m(c),await a}}}function Fs(e){switch(e.type){case"agent_start":return"Working...";case"tool_start":return`Running tool: ${e.name}
|
|
93
|
+
args: ${zs(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 zs(e){try{let t=new WeakSet,n=200,o=12,r=12,s=3,l=(m,i)=>{if(m==null)return m;if(typeof m=="string")return m.length>n?`${m.slice(0,n)}...`:m;if(typeof m=="number"||typeof m=="boolean")return m;if(typeof m=="bigint")return m.toString();if(typeof m=="function")return"[function]";if(typeof m!="object")return String(m);if(t.has(m))return"[circular]";if(i>=s)return"[truncated]";if(t.add(m),Array.isArray(m)){let p=m.slice(0,r).map(y=>l(y,i+1));return m.length>r&&p.push("[truncated]"),p}let c=Object.entries(m),d={};for(let[p,y]of c.slice(0,o))d[p]=l(y,i+1);return c.length>o&&(d._truncated=!0),d},a=l(e,0),u=JSON.stringify(a);return u?u.length>700?`${u.slice(0,700)}...`:u:"null"}catch{return"[unavailable]"}}function ue(e){let t=e instanceof Error?e.message:String(e),n=e?.cause;return n instanceof Error?`${t} (${n.message})`:n?`${t} (${String(n)})`:t}function Us(e,t=140){return e.length<=t?e:`${e.slice(0,t-3)}...`}async function Bs(){let e=await xe(g.agentDir);if(e.length===0)return"No MCP servers configured. Add [mcp_servers.*] to ~/.tg-agent/config.toml.";let t=await Promise.all(e.map(o=>rn(o))),n=["MCP servers:"];for(let o=0;o<e.length;o+=1){let r=e[o],s=t[o],l=s.ok?"ok":`error: ${Us(s.error??"unknown")}`;n.push(`- ${r.name} (${r.type}) ${ce(r)} status=${l} (${s.durationMs}ms)`)}return n.join(`
|
|
94
|
+
`)}async function At(e,t,n,o,r){let s=r,a=qe(e,s,s!==void 0);if(!a)return;let u=await Le(a),m=st(u);switch(m.length>0&&(await j(u),await Promise.all(m.map(i=>pe(a,i).catch(c=>{console.warn(`[tg-agent] cleanup session file failed id=${i}`,c)})))),n){case"start":case"help":{let i=["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","/workspace [path] - view or set workspace directory","/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 and workspace settings","/login <provider> - login to OAuth provider","/logout <provider> - logout from provider (lists accountIds if multiple)","/accounts [provider] - list OAuth accounts, tap to switch","/setdefault <provider>/<accountId> - set default OAuth account","/restart - run restart script (paths.restart_script_path in config)","/stop - stop the current running request","/approve - approve a pending security audit confirmation","/memory - show memory RAG status","/reindex - rebuild vector index for all memories","","Tips:","Send images or files to attach them to the prompt."].join(`
|
|
95
|
+
`);await f(e,i,r);return}case"new":{try{let i=o||"",c=le(u),d=c?.modelProvider,p=c?.modelId,y=Fe(u,i);d&&(y.modelProvider=d,p&&(y.modelId=p)),await j(u),await f(e,`Created session ${y.id} (${y.title}).`,r)}catch(i){await f(e,i.message,r)}return}case"list":{await j(u),await f(e,Ps(rt(u)),r);return}case"use":{if(!o){await f(e,"Usage: /use <id>",r);return}if(!bn(u,o)){await f(e,`Session not found: ${o}`,r);return}await j(u),await f(e,`Active session set to ${o}.`,r);return}case"close":{let i=o||u.activeSessionId;if(!i){await f(e,"No active session to close.",r);return}let c=u.sessions[i];if(c&&c.messages.length>0)try{await f(e,"Reflecting on session memory...",r);let h=await Je(c,c.modelProvider,c.modelId);h.reflected?await f(e,"Memory archived successfully.",r):h.error?await f(e,`Memory saved (reflection failed: ${h.error})`,r):await f(e,"Memory saved (no reflection).",r)}catch(h){console.warn("[tg-agent] memory archival failed",h),await f(e,`Memory archival failed: ${ue(h)}`,r)}let d=ke.get(a);if(d){if(d.cancelRequested=!0,d.abortRequested=!0,d.status&&d.status.update("Cancelled by user.",!0),d.abort)try{d.abort()}catch(h){console.warn("[tg-agent] abort callback failed during force close",h)}vt(a)}if(!it(u,i)){await f(e,`Session not found: ${i}`,r);return}await j(u),await pe(a,i).catch(h=>{console.warn(`[tg-agent] delete session file failed id=${i}`,h)});let y=d?`Force-closed session ${i} (interrupted running task).`:`Closed session ${i}.`;await f(e,y,r);return}case"reset":{let i=le(u);if(!i){await f(e,"No active session.",r);return}if(i.messages.length>0)try{await f(e,"Reflecting on session memory...",r);let c=await Je(i,i.modelProvider,i.modelId);c.reflected?await f(e,"Memory archived successfully.",r):c.error?await f(e,`Memory saved (reflection failed: ${c.error})`,r):await f(e,"Memory saved (no reflection).",r)}catch(c){console.warn("[tg-agent] memory archival failed",c),await f(e,`Memory archival failed: ${ue(c)}`,r)}vn(i),await j(u),await pe(a,i.id).catch(c=>{console.warn(`[tg-agent] reset session file failed id=${i.id}`,c)}),await f(e,`Reset session ${i.id}.`,r);return}case"workspace":{if(!o){let c=bt(a,u),d=u.workspaceDir?"chat":g.workspaceMappings.has(a)?"config":"default";await f(e,`Workspace: ${c} (source: ${d})`,r);return}let i=ye.resolve(B(o.trim()));xn(u,i),await j(u),await f(e,`Workspace set to: ${i}`,r);return}case"providers":{let{authStorage:i,modelRegistry:c}=await se(),d=c.getError(),p=Ss(c,i);if(p.length===0){let h=d?`Warning: ${d}
|
|
96
|
+
|
|
97
|
+
No providers found.`:"No providers found.";await f(e,h,r);return}let y=[];d&&y.push(`Warning: ${d}`),y.push("Providers:"),await He(e,y.join(`
|
|
98
|
+
`),p,{perRow:1,footer:"Tap a provider to set it. Use /models <provider> to list models.",messageThreadId:r});return}case"models":{let{authStorage:i,modelRegistry:c}=await se(),d=o?X(o):"";if(!d){let b=le(u);if(!b?.modelProvider){await f(e,"Usage: /models <provider>",r);return}d=b.modelProvider}let p=i.hasAuth(d),y=$s(u,d),h=Ms(c,d,y);if(h.length===0){await f(e,`No models found for provider ${d}.`,r);return}await He(e,`Models for ${d} (auth: ${p?"ok":"missing"}):`,h,{perRow:1,footer:"Tap a model to set it.",messageThreadId:r});return}case"provider":{if(!o){await f(e,"Usage: /provider <name>",r);return}let i=X(o),{modelRegistry:c}=await se();if(!c.getAll().some(y=>y.provider===i)){await f(e,`Unknown provider: ${i}`,r);return}let p=await ht(u,e,r);p.modelProvider=i,p.modelId=void 0,p.updatedAt=z(),await j(u),await f(e,`Session ${p.id} provider set to ${i}.`,r),await At(e,t,"models",i,r);return}case"model":{let i=As(o);if(!i){await f(e,"Usage: /model <provider>/<model>",r);return}let c=await ht(u,e,r),d=X(i.provider??c.modelProvider??"");if(!d){await f(e,"Usage: /model <provider>/<model>",r);return}let{modelRegistry:p}=await se(),y=ws(d,i.modelId);if(!p.find(d,y)){await f(e,`Model not found: ${d}/${y}`,r);return}c.modelProvider=d,c.modelId=y,c.updatedAt=z(),await j(u),await f(e,`Session ${c.id} model set to ${d}/${y}.`,r);return}case"status":{let i=le(u);if(!i){await f(e,"No active session.",r);return}let c=g.modelRef.includes("/")?g.modelRef:`${g.modelProvider}/${g.modelRef}`,d=i.modelProvider||i.modelId?`Model: ${i.modelProvider??"?"}/${i.modelId??"?"}`:`Model: ${c} (default)`,p="";if(i.accountId){let A=te().getAccount(i.modelProvider||"",i.accountId);A?p=`
|
|
99
|
+
Account: ${A.email||i.accountId}`:p=`
|
|
100
|
+
Account: ${i.accountId} (not found)`}let y=bt(a,u),h=u.workspaceDir?"chat":g.workspaceMappings.has(a)?"config":"default",b=[`Session: ${i.id} (${i.title})`,d+p,`Workspace: ${y} (${h})`].join(`
|
|
101
|
+
`);await f(e,b,r);return}case"mcp":{if(o.trim().toLowerCase()==="refresh"){on(),await Se(g.agentDir,{timeoutMs:5e3,maxBytes:g.fetchMaxBytes,maxChars:3e3}),nt(),await f(e,"MCP catalog refreshed.",r);return}let i=await Bs();await f(e,i,r);return}case"login":{let i=Nn();if(!o){let p=i.map(y=>`- ${y.id} (${y.name})`);await f(e,["OAuth providers:",...p].join(`
|
|
102
|
+
`),r);return}let c=X(o);if(yt.has(t)){await f(e,"Login already in progress.",r);return}let d=i.find(p=>p.id===c);if(!d){await f(e,`Unknown OAuth provider: ${c}`,r);return}yt.add(t);try{let{authStorage:p}=await se(),y=te(),h=y.listAccounts(c);h.length>0&&await f(e,`You have ${h.length} account(s) for ${c}. Adding a new one...`,r),await f(e,`Starting login for ${d.id}...`,r);let b=Zr(c);if(!b)throw new Error(`OAuth provider not found: ${c}`);let $=await b.login({onAuth:({url:v,instructions:x})=>{let k=["Open this URL in your browser:",v];x&&k.push("",x),Cs(e,k.join(`
|
|
103
|
+
`),r)},onPrompt:v=>Fn(t,e,v,r),onProgress:v=>{f(e,v,r)},onManualCodeInput:()=>Fn(t,e,{message:"Paste the authorization code:"},r)}),A=$.email,M=await y.addAccount(c,$,{email:A});p.set(c,{type:"oauth",...$});let R=y.listAccounts(c),_=A||M;await f(e,`Login completed for ${d.id}.
|
|
104
|
+
Account: ${_}
|
|
105
|
+
Account ID: ${M}
|
|
106
|
+
Total accounts: ${R.length}
|
|
107
|
+
Use /accounts ${c} to see all accounts.`,r)}catch(p){let y=ue(p);await f(e,`Login failed: ${y}`,r)}finally{yt.delete(t),Wn(t)}return}case"logout":{if(!o){await f(e,`Usage: /logout <provider> \u2014 lists accountIds if multiple.
|
|
108
|
+
/logout <provider>/<accountId> \u2014 logout one account.
|
|
109
|
+
/logout <provider>/all \u2014 logout all accounts for that provider.`,r);return}let i=te();if(o.includes("/")){let[c,d]=o.split("/",2),p=X(c);if(d==="all"){let b=await i.removeAllAccounts(p),{authStorage:$}=await se();$.logout(p),await f(e,`Logged out from ${p} (${b} account(s)).`,r);return}let y=i.getAccount(p,d);if(!y){await f(e,`Account not found: ${p}/${d}`,r);return}let h=y.email||d;if(await i.removeAccount(p,d),!i.hasAccounts(p)){let{authStorage:b}=await se();b.logout(p)}await f(e,`Logged out: ${h} (${p})`,r)}else{let c=X(o),d=i.listAccounts(c);if(d.length===0){await f(e,`No accounts for ${c}.`,r);return}if(d.length>1){let h=d.map(M=>` ${M.id}${M.email?` (${M.email})`:""}${M.isDefault?" [default]":""}`),b=[...d.map(M=>({label:M.email?`Logout ${M.email}`:`Logout ${M.id}`,command:`/logout ${c}/${M.id}`})),{label:"Logout all",command:`/logout ${c}/all`}],$=Mt(b,1),A=`You have ${d.length} account(s) for ${c}:
|
|
110
|
+
${h.join(`
|
|
111
|
+
`)}
|
|
112
|
+
|
|
113
|
+
Tap to logout:`;await $t(e,A,$,r);return}let p=await i.removeAllAccounts(c),{authStorage:y}=await se();y.logout(c),p>0?await f(e,`Logged out from ${c} (${p} account(s)).`,r):await f(e,`Logged out from ${c}.`,r)}return}case"accounts":{let i=te();if(!o){let y=Nn(),h=[];for(let b of y){let $=i.listAccounts(b.id);for(let A of $){let M=A.email||A.id,R=A.isDefault?" *":"";h.push({label:`${b.id}: ${M}${R}`,command:`/useaccount ${b.id}/${A.id}`})}}if(h.length===0){await f(e,"No accounts found. Use /login <provider> to add one.",r);return}await He(e,"All accounts (tap to switch session to this account):",h,{perRow:1,footer:"Tap to switch provider and account. * = default for that provider.",messageThreadId:r});return}let c=X(o),d=i.listAccounts(c);if(d.length===0){await f(e,`No accounts for ${c}. Use /login ${c} to add one.`,r);return}let p=d.map(y=>{let h=y.email||y.id,b=y.isDefault?" *":"";return{label:`${h}${b}`,command:`/useaccount ${c}/${y.id}`}});await He(e,`Accounts for ${c}:`,p,{perRow:1,footer:"Tap to use this account for current session. * = default",messageThreadId:r});return}case"useaccount":{if(!o||!o.includes("/")){await f(e,"Usage: /useaccount <provider>/<accountId>",r);return}let[i,c]=o.split("/",2),d=X(i),y=te().getAccount(d,c);if(!y){await f(e,`Account not found: ${d}/${c}`,r);return}let h=await ht(u,e,r);h.modelProvider=d,h.accountId=c,h.updatedAt=z(),await j(u);let b=y.email||c;await f(e,`Session "${h.title||h.id}" now using: ${b} (${d})`,r);return}case"setdefault":{if(!o||!o.includes("/")){await f(e,"Usage: /setdefault <provider>/<accountId>",r);return}let[i,c]=o.split("/",2),d=X(i),p=te(),y=p.getAccount(d,c);if(!y){await f(e,`Account not found: ${d}/${c}`,r);return}if(!await p.setDefaultAccount(d,c)){await f(e,"Failed to set default account.",r);return}let b=y.email||c;await f(e,`Default account for ${d} set to: ${b}`,r);return}case"restart":{let i=g.restartScriptPath;if(!i){await f(e,'restart_script_path not configured. Set [paths] restart_script_path = "path/to/script.sh" in config.toml.',r);return}try{Yr("bash",[i],{stdio:"ignore",detached:!0}).unref(),await f(e,`Restart script started: ${i}`,r)}catch(c){let d=c instanceof Error?c.message:String(c);await f(e,`Restart failed: ${d}`,r)}return}case"memory":{let i=g.memory.rag,c=await Dn(),d=["Memory System Status:","",`RAG Enabled: ${i.enabled?"Yes":"No"}`,`Embedding Model: ${i.embeddingModel}`,`Embedding Base URL: ${i.embeddingBaseUrl||"(default)"}`,`Similarity Threshold: ${i.similarityThreshold}`,`Max Results: ${i.maxResults}`,"","Database:",` Sessions: ${c.sessionsCount}`,` Memories: ${c.memoriesCount}`,"","Tip: Use /reindex to rebuild memory vectors after changing embedding model."];await f(e,d.join(`
|
|
114
|
+
`),r);return}case"reindex":{if(!g.memory.rag.enabled){await f(e,"Memory RAG is disabled. Enable it in config.toml first.",r);return}await f(e,["Starting memory reindex...","",`Embedding Model: ${g.memory.rag.embeddingModel}`,"","Reading sessions and rebuilding memories table..."].join(`
|
|
115
|
+
`),r);try{let i=await En((c,d,p)=>{(c%5===0||c===d)&&console.log(`[reindex] Progress: ${c}/${d} - ${p}`)});if(i.success){let c=["Reindex completed!","",`Sessions: ${i.totalSessions}`,`Total memories: ${i.totalMemories}`,`Indexed: ${i.indexedMemories}`,`Errors: ${i.errors.length}`,"",`Embedding Model: ${i.embeddingModel}`,`Vector Dimension: ${i.vectorDimension??"N/A"}`];i.errors.length>0&&(c.push("","Errors:"),i.errors.slice(0,5).forEach(d=>c.push(` - ${d}`)),i.errors.length>5&&c.push(` ... and ${i.errors.length-5} more`)),await f(e,c.join(`
|
|
116
|
+
`),r)}else await f(e,`Reindex failed: ${i.errors.join(", ")}`,r)}catch(i){let c=i instanceof Error?i.message:String(i);await f(e,`Reindex failed: ${c}`,r)}return}default:await f(e,`Unknown command: ${n}`,r)}}async function Ks(e,t,n,o=[],r){let s=xt(n);if(s){await At(e,t,s.command,s.args,r);return}let a=qe(e,r,r!==void 0);if(!a)return;let u=await Le(a),m=st(u);m.length>0&&(await j(u),await Promise.all(m.map(M=>pe(a,M).catch(R=>{console.warn(`[tg-agent] cleanup session file failed id=${M}`,R)}))));let i=le(u);if(!i)try{i=Fe(u,""),await j(u),await f(e,`Created session ${i.id}.`,r)}catch(M){await f(e,M.message,r);return}let{resolved:c,images:d}=await ds(o);if(o.length>0&&c.length===0&&!n.trim()){await f(e,"Failed to download attachments.",r);return}let p=ls(c),y=[];n.trim()&&y.push(n.trim()),p&&y.push(p);let h=y.join(`
|
|
117
|
+
|
|
118
|
+
`)||"Attachment received.",b={role:"user",content:h,ts:z()};at(i,b,g.maxHistoryMessages),await j(u),console.log(`[tg-agent] request user=${t} chat=${a} session=${i.id} messages=${i.messages.length} textLen=${h.length} attachments=${c.length} provider=${i.modelProvider??"-"} model=${i.modelId??"-"}`);let $=null;try{$=await Ls(e,r)}catch(M){console.warn("[tg-agent] status message failed",M)}let A={sessionId:i.id,chatId:e,messageThreadId:r,status:$,abortRequested:!1,cancelRequested:!1};ts(a,A);try{let M=g.systemPrompt;if(g.memory.rag.enabled&&h.trim())try{let v=await Tn(h);if(v.length>0){let x=v.map(k=>`- [${k.type}] ${k.content} (${k.date})`).join(`
|
|
119
|
+
`);M+=`
|
|
108
120
|
|
|
109
121
|
<relevant_memories>
|
|
110
122
|
Relevant facts about Shawn from past conversations:
|
|
111
123
|
|
|
112
|
-
${
|
|
113
|
-
</relevant_memories>`,console.log(`[memory-rag] injected ${
|
|
114
|
-
`),
|
|
124
|
+
${x}
|
|
125
|
+
</relevant_memories>`,console.log(`[memory-rag] injected ${v.length} memories into context`)}}catch(v){console.warn(`[memory-rag] retrieval failed: ${v}`)}let R=await es(async()=>{let v=await _n({chatId:a,sessionId:i.id,prompt:h,images:d,systemPrompt:M,modelProvider:i.modelProvider,modelId:i.modelId,accountId:i.accountId,workspaceDir:bt(a,u),telegram:{chatId:e,sendPhoto:async(x,k)=>{let D={};k&&(D.caption=k),r!==void 0&&(D.message_thread_id=r),await I.sendPhoto(e,x,D)},sendDocument:async(x,k)=>{let D={};k&&(D.caption=k),r!==void 0&&(D.message_thread_id=r),await I.sendDocument(e,x,D)},sendMessage:async x=>{await f(e,x,r)},requestConfirmation:async(x,k)=>await Ln(a,e,x,k,r)},auditContext:g.audit.enabled?{chatId:a,requestConfirmation:async(x,k)=>await Ln(a,e,x,k,r),sendNotification:async x=>{await f(e,x,r)}}:void 0,onAbortReady:x=>{A.abort=x,A.abortRequested&&x()},onStatus:$?x=>{let k=Fs(x);k&&$?.update(k)}:void 0});return console.log(`[tg-agent] response session=${i.id} model=${v.modelProvider}/${v.modelId} file=${v.sessionFile}`),v.text});if(A.cancelRequested){$?await $.finalize("Cancelled by user."):await f(e,"Cancelled by user.",r);return}let _={role:"assistant",content:R,ts:z()};at(i,_,g.maxHistoryMessages),await j(u),$?await $.finalize(R):await f(e,R,r)}catch(M){if(console.error("[tg-agent] runModel error",M),A.cancelRequested){$?await $.fail("Cancelled by user."):await f(e,"Cancelled by user.",r);return}let R=ue(M);$?await $.fail(`Error: ${R}`):await f(e,`Error: ${R}`,r)}finally{vt(a)}}async function Js(){let e=[{type:"default"},{type:"all_private_chats"},{type:"all_group_chats"}];for(let t of e)try{await I.setMyCommands(Bn,{scope:t}),console.log(`[tg-agent] bot commands registered scope=${t.type} count=${Bn.length}`)}catch(n){let o=n instanceof Error?n.message:String(n);console.warn(`[tg-agent] setMyCommands failed scope=${t.type}:`,o)}}var I,Kn,es,ke,os,ms,fs,ie,yt,$e,ys,hs,We,xs,ks,zn,Qn,Un,Ts,Q,Is,Ns,Bn,Zn=F(()=>{"use strict";K();Ze();Xt();Rn();me();dt();je();ct();jn();ft();G();Kt();I=new Vr(g.telegramToken,{polling:!0}),Kn=Ct(),es=Tt(g.maxConcurrent),ke=new Map;os="image/jpeg";ms=new Set(["_","*","[","]","(",")","~","`",">","#","+","-","=","|","{","}",".","!"]);fs=600*1e3,ie=new Map,yt=new Set,$e=new Map;ys=new Map([["codex","openai-codex"],["antigravity","google-antigravity"],["gemini","google-gemini-cli"],["gemini-cli","google-gemini-cli"]]),hs={"codex-mini-latest":"gpt-5.1-codex-mini","codex-max-latest":"gpt-5.1-codex-max","codex-latest":"gpt-5.2-codex"};vs();T(g.agentDir).catch(e=>{console.warn(`[tg-agent] ensure agentDir failed: ${e instanceof Error?e.message:String(e)}`)});(async()=>{try{await Se(g.agentDir,{timeoutMs:3e3,maxBytes:g.fetchMaxBytes,maxChars:2e3}),nt()}catch(e){let t=e instanceof Error?e.message:String(e);console.warn(`[tg-agent] mcp catalog warmup failed: ${t}`)}})();We=Vt();console.log(We?`[tg-agent] fetchProxy=${We.url} kind=${We.kind} source=${We.source}`:"[tg-agent] fetchProxy=(none)");xs=new Set(["openai-codex","google-antigravity","anthropic"]);ks=6e4,zn=new Map;Qn=1800*1e3,Un=2e3,Ts=60,Q=new Map;Is=3900,Ns=1200;I.on("callback_query",e=>{let t=e.data??"",n=e.message?.chat.id;if(!e.from?.id||!n){I.answerCallbackQuery(e.id);return}let o=String(e.from.id);if(!Yn(o)){Gn(o,n),I.answerCallbackQuery(e.id);return}if(!t.startsWith("cmd:")){I.answerCallbackQuery(e.id);return}let r=Os(t);if(!r){I.answerCallbackQuery(e.id,{text:"Command expired."});return}I.answerCallbackQuery(e.id);let s=e.message?.message_thread_id,l=e.message?.is_topic_message??!1,a=qe(n,s,l);if(!a)return;let u=xt(r);if(u?.command==="stop"){Ae(a,!1)?f(n,"Operation blocked.",s):Hn(n,a,s);return}if(u?.command==="close"){qn(n,a,u.args,s);return}if(u?.command==="approve"){Ae(a,!0)?f(n,"Operation approved.",s):f(n,"No pending audit confirmation.",s);return}Kn(a,async()=>{if(!u){await f(n,"Invalid command.",s);return}await At(n,o,u.command,u.args,s)}).catch(async m=>{console.error("[tg-agent] runModel error",m);let i=ue(m);await f(n,`Error: ${i}`,s)})});I.on("message",e=>{if(!e.from?.id)return;let t=String(e.from.id),n=e.chat.id;if(!Yn(t)){Gn(t,n);return}let o=e.message_thread_id,r=e.is_topic_message??!1,s=qe(n,o,r);if(!s)return;let l=(e.text??e.caption??"").trim(),a=us(e);if(!l&&a.length===0)return;let u=ie.get(t);if(u){if(l==="/stop"||l==="/cancel"){bs(t,"Login cancelled by user."),f(n,"Login cancelled.",o);return}if(!l){f(n,"Login expects a text response.",o);return}Wn(t),u.resolve(l);return}let m=xt(l);if(m?.command==="stop"){Ae(s,!1),Hn(n,s,o);return}if(m?.command==="close"){Ae(s,!1),qn(n,s,m.args,o);return}if(m?.command==="approve"){Ae(s,!0)?f(n,"Operation approved.",o):f(n,"No pending audit confirmation.",o);return}Kn(s,()=>Ks(n,t,l,a,o)).catch(async i=>{console.error("[tg-agent] runModel error",i);let c=ue(i);await f(n,`Error: ${c}`,o)})});I.on("polling_error",e=>{console.error("Polling error",e)});Bn=[{command:"new",description:"Create a new session"},{command:"list",description:"List all sessions"},{command:"use",description:"Switch to a session"},{command:"close",description:"Close current session"},{command:"reset",description:"Clear session history"},{command:"stop",description:"Stop current request"},{command:"workspace",description:"View/set workspace directory"},{command:"status",description:"Show session status"},{command:"providers",description:"List available providers"},{command:"models",description:"List models for provider"},{command:"provider",description:"Set provider for session"},{command:"model",description:"Set model for session"},{command:"mcp",description:"List MCP servers"},{command:"memory",description:"Show memory RAG status"},{command:"reindex",description:"Rebuild memory vector index"},{command:"login",description:"Login to OAuth provider"},{command:"logout",description:"Logout from provider"},{command:"accounts",description:"List OAuth accounts (tap to switch)"},{command:"setdefault",description:"Set default OAuth account"},{command:"restart",description:"Run restart script (config)"},{command:"approve",description:"Approve security audit"},{command:"help",description:"Show all commands"}];Js();console.log("tg-agent started")});K();import Hs from"node:fs";import eo from"node:path";import qs from"node:readline/promises";import{fileURLToPath as Gs}from"node:url";var to=process.argv.slice(2),no=(e,t)=>to.includes(e)||(t?to.includes(t):!1),Ys=no("--help","-h"),Vs=no("--version","-v"),Xs=["Usage: tg-agent [options]","","Options:"," -h, --help Show help"," -v, --version Show version"].join(`
|
|
126
|
+
`),Qs=()=>{if(process.env.npm_package_version)return process.env.npm_package_version;try{let e=Gs(import.meta.url),t=eo.dirname(e),n=eo.join(t,"..","package.json"),o=Hs.readFileSync(n,"utf8"),r=JSON.parse(o);if(r.version)return r.version}catch{}return"dev"};Ys&&(console.log(Xs),process.exit(0));Vs&&(console.log(Qs()),process.exit(0));async function Zs(){let e=qs.createInterface({input:process.stdin,output:process.stdout});try{return(await e.question("Enter TELEGRAM_BOT_TOKEN: ")).trim()}finally{e.close()}}async function ei(){let{configPath:e,data:t,exists:n}=ve(),o=Nt(),r=n?t:o,s=Lt(r,o);if(Ft(r)){s&&await Qe(e,r);return}process.stdin.isTTY||(console.error(`Missing telegram.bot_token in ${e}.`),process.exit(1));let a=await Zs();a||(console.error("Empty TELEGRAM_BOT_TOKEN."),process.exit(1)),zt(r,a),await Qe(e,r),console.log(`Saved config to ${e}.`)}async function ti(){let{data:e}=ve(),t=typeof e.tls=="object"&&e.tls?e.tls:{},n=typeof t.extra_ca_certs=="string"?t.extra_ca_certs.trim():"";if(n&&(process.env.NODE_EXTRA_CA_CERTS=n),typeof t.reject_unauthorized=="boolean"){process.env.NODE_TLS_REJECT_UNAUTHORIZED=t.reject_unauthorized?"1":"0";return}let o=typeof t.reject_unauthorized=="string"?t.reject_unauthorized.trim():"";o&&(process.env.NODE_TLS_REJECT_UNAUTHORIZED=o)}await ei();await ti();Bt();Promise.resolve().then(()=>Zn());
|