@agenticmail/enterprise 0.5.311 → 0.5.313
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/README.md +682 -544
- package/dist/agent-autonomy-PSXQ4MNP.js +766 -0
- package/dist/agent-heartbeat-6H3YAQ32.js +510 -0
- package/dist/agent-heartbeat-7WS3XILF.js +510 -0
- package/dist/agent-heartbeat-BFGKYUUK.js +510 -0
- package/dist/agent-heartbeat-SSV65YTX.js +510 -0
- package/dist/agent-heartbeat-T5IIHVF4.js +510 -0
- package/dist/agent-heartbeat-X3C6FIU2.js +510 -0
- package/dist/agent-tools-BW6CLQQ7.js +13897 -0
- package/dist/agent-tools-KEA7QEWF.js +13897 -0
- package/dist/agent-tools-NU7V3S5N.js +13899 -0
- package/dist/agent-tools-WINDYRQ2.js +13897 -0
- package/dist/chunk-3ELH5CU6.js +4910 -0
- package/dist/chunk-4QYRS3MS.js +1519 -0
- package/dist/chunk-52REEVDW.js +1519 -0
- package/dist/chunk-5RZJ76YI.js +4977 -0
- package/dist/chunk-6L7FQI5Q.js +4909 -0
- package/dist/chunk-763OMGFI.js +1519 -0
- package/dist/chunk-7ILSXGY6.js +1519 -0
- package/dist/chunk-7UCKD25B.js +551 -0
- package/dist/chunk-A6MSR7DL.js +4977 -0
- package/dist/chunk-ASD2YB6O.js +1519 -0
- package/dist/chunk-AZOIHLLX.js +4977 -0
- package/dist/chunk-BDCFOP7O.js +537 -0
- package/dist/chunk-BSVWPG6I.js +106 -0
- package/dist/chunk-C46DNDZB.js +1519 -0
- package/dist/chunk-CFVTK4FQ.js +4977 -0
- package/dist/chunk-CHJAOKCJ.js +4921 -0
- package/dist/chunk-CYEWTXYH.js +4977 -0
- package/dist/chunk-D3KFSWLK.js +48 -0
- package/dist/chunk-DUVGNAIY.js +4977 -0
- package/dist/chunk-DX4XEFVE.js +25229 -0
- package/dist/chunk-EX6FQSEV.js +167 -0
- package/dist/chunk-F5VZ5EUH.js +1519 -0
- package/dist/chunk-FVUDSPOD.js +4977 -0
- package/dist/chunk-G6FTZKJX.js +4977 -0
- package/dist/chunk-GFEAZN6Y.js +1519 -0
- package/dist/chunk-HKV4FQFW.js +1519 -0
- package/dist/chunk-ICCPULDT.js +25217 -0
- package/dist/chunk-IYEM627Q.js +25216 -0
- package/dist/chunk-JHRJ4QJ6.js +1519 -0
- package/dist/chunk-K2DAUYHV.js +4977 -0
- package/dist/chunk-KDQDSZZQ.js +4973 -0
- package/dist/chunk-LDUD6AZY.js +1519 -0
- package/dist/chunk-LES5TJ5L.js +4909 -0
- package/dist/chunk-MJGGW6MC.js +106 -0
- package/dist/chunk-MQKIWAHQ.js +106 -0
- package/dist/chunk-NGA7BBPF.js +48 -0
- package/dist/chunk-OE3TI4IQ.js +1519 -0
- package/dist/chunk-OHSBIYDR.js +4977 -0
- package/dist/chunk-OPOBUYJT.js +1519 -0
- package/dist/chunk-OZEYDEPB.js +1519 -0
- package/dist/chunk-P4PODSQH.js +1519 -0
- package/dist/chunk-P7UOSFIE.js +636 -0
- package/dist/chunk-PFN6DODU.js +4921 -0
- package/dist/chunk-PKDVM4IY.js +4917 -0
- package/dist/chunk-Q5KG3G7U.js +25115 -0
- package/dist/chunk-QMVNW4FJ.js +25229 -0
- package/dist/chunk-QZ5UPRBE.js +4977 -0
- package/dist/chunk-SPP23N42.js +4977 -0
- package/dist/chunk-SRGHNFOY.js +4921 -0
- package/dist/chunk-TPLVQFXM.js +2594 -0
- package/dist/chunk-U3XYF4QP.js +4977 -0
- package/dist/chunk-VRRJH2DY.js +4921 -0
- package/dist/chunk-WY42BS3F.js +1519 -0
- package/dist/chunk-XAA4VHHZ.js +1519 -0
- package/dist/chunk-Y2KIY4BA.js +4969 -0
- package/dist/chunk-Z5Y5KTPC.js +4977 -0
- package/dist/chunk-ZA4QRACH.js +4977 -0
- package/dist/chunk-ZHLGSTXF.js +4909 -0
- package/dist/cli-agent-26BUULHZ.js +2169 -0
- package/dist/cli-agent-2FLJWXOC.js +2169 -0
- package/dist/cli-agent-4NNQFLO6.js +2255 -0
- package/dist/cli-agent-5WV3EEPW.js +2252 -0
- package/dist/cli-agent-65JUT6DU.js +2193 -0
- package/dist/cli-agent-6HLL7A5K.js +2255 -0
- package/dist/cli-agent-CZ26QWUZ.js +2210 -0
- package/dist/cli-agent-HPVSWDNQ.js +2255 -0
- package/dist/cli-agent-K4SBVG5X.js +2210 -0
- package/dist/cli-agent-K5D424X2.js +2252 -0
- package/dist/cli-agent-U4OL5FGK.js +2210 -0
- package/dist/cli-agent-WUMPOIKQ.js +2169 -0
- package/dist/cli-agent-WWRGGJ2F.js +2255 -0
- package/dist/cli-agent-ZDBBTVGU.js +2193 -0
- package/dist/cli-agent-ZIZ5JP4O.js +2252 -0
- package/dist/cli-recover-I4KNR2OI.js +487 -0
- package/dist/cli-recover-IQTUKWR2.js +487 -0
- package/dist/cli-recover-OYJHELOR.js +487 -0
- package/dist/cli-recover-PVQC7UXB.js +487 -0
- package/dist/cli-recover-T32NABFA.js +487 -0
- package/dist/cli-serve-FE4CMMSN.js +143 -0
- package/dist/cli-serve-FTQJ3RUK.js +143 -0
- package/dist/cli-serve-G4PUCASH.js +143 -0
- package/dist/cli-serve-HBZYUUQ3.js +143 -0
- package/dist/cli-serve-L3NUROMO.js +143 -0
- package/dist/cli-serve-LAA5WIZK.js +143 -0
- package/dist/cli-serve-LV4TUSJD.js +143 -0
- package/dist/cli-serve-MFCTVA2L.js +140 -0
- package/dist/cli-serve-QCRUFI5B.js +143 -0
- package/dist/cli-serve-S7OGQN4P.js +143 -0
- package/dist/cli-serve-SI4BQRXT.js +140 -0
- package/dist/cli-serve-UNB7EHN4.js +143 -0
- package/dist/cli-serve-UV3GVDRD.js +143 -0
- package/dist/cli-serve-V5QICXR5.js +143 -0
- package/dist/cli-serve-VG6Z6GIB.js +143 -0
- package/dist/cli-serve-XSYHPGZI.js +143 -0
- package/dist/cli-serve-Y534FCRV.js +140 -0
- package/dist/cli-verify-CZIITRED.js +149 -0
- package/dist/cli-verify-N73GOKEF.js +149 -0
- package/dist/cli-verify-QEEBZOUZ.js +149 -0
- package/dist/cli-verify-RC5HI6DU.js +149 -0
- package/dist/cli-verify-VKBNIEAX.js +149 -0
- package/dist/cli.js +5 -5
- package/dist/dashboard/app.js +16 -3
- package/dist/dashboard/components/org-switcher.js +5 -1
- package/dist/dashboard/org-switcher.js +156 -0
- package/dist/dashboard/pages/login.js +160 -4
- package/dist/dashboard/pages/task-pipeline.js +1 -1
- package/dist/factory-3IWXVE37.js +9 -0
- package/dist/factory-5M6PTMLC.js +11 -0
- package/dist/factory-CSSHN7GE.js +11 -0
- package/dist/factory-JFWXTAWK.js +11 -0
- package/dist/factory-TBGUYM5X.js +9 -0
- package/dist/google-W5AYGNUJ.js +33 -0
- package/dist/index.js +6 -6
- package/dist/meetings-FJ453ENF.js +12 -0
- package/dist/postgres-BCHZWRU3.js +832 -0
- package/dist/postgres-BI4QVRM6.js +825 -0
- package/dist/postgres-BOTHOPDW.js +875 -0
- package/dist/postgres-JBUKR3TA.js +873 -0
- package/dist/postgres-Z7QYSU6K.js +861 -0
- package/dist/routes-7QYAQTWA.js +90 -0
- package/dist/routes-JCBVZU54.js +90 -0
- package/dist/routes-KEDEJFRE.js +90 -0
- package/dist/routes-WI64ADVH.js +90 -0
- package/dist/routes-X36OSCID.js +90 -0
- package/dist/runtime-75XR6KEW.js +45 -0
- package/dist/runtime-BNM7ZNNL.js +45 -0
- package/dist/runtime-ES6WCJ7D.js +45 -0
- package/dist/runtime-KYJTML2B.js +45 -0
- package/dist/runtime-LO67ZHQA.js +45 -0
- package/dist/runtime-VIXKKVSZ.js +45 -0
- package/dist/runtime-WHWJPCGK.js +45 -0
- package/dist/runtime-Z2Q6GUHH.js +45 -0
- package/dist/runtime-ZZ6CALSB.js +45 -0
- package/dist/server-27A4WEJC.js +28 -0
- package/dist/server-2CBXP4WS.js +28 -0
- package/dist/server-4JQAB5R4.js +28 -0
- package/dist/server-6BOM5U64.js +28 -0
- package/dist/server-CA2I3LJY.js +28 -0
- package/dist/server-FLJKNPRD.js +28 -0
- package/dist/server-HMIHIQ2N.js +28 -0
- package/dist/server-KIXXLR2D.js +28 -0
- package/dist/server-KSEIZTXF.js +28 -0
- package/dist/server-MPVW7DKZ.js +28 -0
- package/dist/server-PRTVRQ2D.js +28 -0
- package/dist/server-SYIG6HAX.js +28 -0
- package/dist/server-U32KDIXC.js +28 -0
- package/dist/server-WFN6CA4T.js +28 -0
- package/dist/server-XQUE3FGT.js +28 -0
- package/dist/server-XWT2UORK.js +28 -0
- package/dist/server-Y3BGNN5Q.js +28 -0
- package/dist/setup-352L2TPS.js +20 -0
- package/dist/setup-4MM645XK.js +20 -0
- package/dist/setup-5JPWW6IP.js +20 -0
- package/dist/setup-CUN6LVUV.js +20 -0
- package/dist/setup-D3YHPWPY.js +20 -0
- package/dist/setup-D4A5I6UM.js +20 -0
- package/dist/setup-DOPLXTB3.js +20 -0
- package/dist/setup-E3NSIM6B.js +20 -0
- package/dist/setup-E3V2D7NL.js +20 -0
- package/dist/setup-FSYPGI2C.js +20 -0
- package/dist/setup-G3RPKRG3.js +20 -0
- package/dist/setup-KJ77HNWK.js +20 -0
- package/dist/setup-LPSOY5V5.js +20 -0
- package/dist/setup-N3ODDSQE.js +20 -0
- package/dist/setup-NLDM3M2P.js +20 -0
- package/dist/setup-PT6WGOYB.js +20 -0
- package/dist/setup-SWJMNDWF.js +20 -0
- package/dist/system-prompts-6OUTAMH6.js +41 -0
- package/dist/task-queue-YP2I54IA.js +9 -0
- package/dist/telegram-QRNGRT5M.js +17 -0
- package/dist/whatsapp-VYVINCGV.js +31 -0
- package/god_is_great.html +35 -0
- package/package.json +1 -1
- package/src/admin/routes.ts +24 -4
- package/src/agent-tools/index.ts +4 -1
- package/src/agent-tools/tool-resolver.ts +15 -4
- package/src/agent-tools/tools/browser.ts +2 -2
- package/src/agent-tools/tools/local/dependency-manager.ts +286 -0
- package/src/agent-tools/tools/local/index.ts +3 -0
- package/src/agent-tools/tools/messaging/telegram.ts +29 -0
- package/src/agent-tools/tools/messaging/whatsapp.ts +59 -4
- package/src/auth/routes.ts +15 -12
- package/src/cli-agent.ts +47 -6
- package/src/cli-serve.ts +2 -5
- package/src/dashboard/app.js +16 -3
- package/src/dashboard/components/org-switcher.js +5 -1
- package/src/dashboard/pages/login.js +160 -4
- package/src/dashboard/pages/task-pipeline.js +1 -1
- package/src/db/adapter.ts +2 -0
- package/src/db/factory.ts +78 -0
- package/src/db/postgres.ts +57 -12
- package/src/engine/agent-autonomy.ts +1 -1
- package/src/engine/agent-heartbeat.ts +1 -1
- package/src/engine/messaging-poller.ts +146 -11
- package/src/engine/oauth-connect-routes.ts +23 -3
- package/src/engine/routes.ts +1 -1
- package/src/engine/task-poller.ts +54 -3
- package/src/engine/task-queue.ts +30 -0
- package/src/runtime/index.ts +2 -1
- package/src/runtime/types.ts +2 -0
- package/src/server.ts +43 -1
- package/src/system-prompts/triage.ts +1 -1
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dependency Manager — Detects missing tools/packages and handles installation.
|
|
3
|
+
*
|
|
4
|
+
* Agents use this to:
|
|
5
|
+
* 1. Check if a command/tool is available before using it
|
|
6
|
+
* 2. Request installation if missing (with manager approval flow)
|
|
7
|
+
* 3. Track what was installed for cleanup
|
|
8
|
+
*
|
|
9
|
+
* Installation approval modes:
|
|
10
|
+
* - 'auto': Install without asking (for trusted/common tools)
|
|
11
|
+
* - 'ask_manager': Message manager for approval before installing
|
|
12
|
+
* - 'deny': Never install (locked-down environments)
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { exec as cpExec } from 'node:child_process';
|
|
16
|
+
import { promisify } from 'node:util';
|
|
17
|
+
import { platform } from 'node:os';
|
|
18
|
+
import type { ToolDefinition } from '../../types.js';
|
|
19
|
+
|
|
20
|
+
var execAsync = promisify(cpExec);
|
|
21
|
+
|
|
22
|
+
// Track installations per session for cleanup
|
|
23
|
+
var sessionInstalls = new Map<string, string[]>();
|
|
24
|
+
|
|
25
|
+
// Common tools and their package names per platform
|
|
26
|
+
var KNOWN_PACKAGES: Record<string, { brew?: string; apt?: string; pip?: string; npm?: string; description: string }> = {
|
|
27
|
+
ffmpeg: { brew: 'ffmpeg', apt: 'ffmpeg', description: 'Audio/video processing toolkit' },
|
|
28
|
+
ffprobe: { brew: 'ffmpeg', apt: 'ffmpeg', description: 'Audio/video analysis (part of ffmpeg)' },
|
|
29
|
+
convert: { brew: 'imagemagick', apt: 'imagemagick', description: 'Image manipulation (ImageMagick)' },
|
|
30
|
+
magick: { brew: 'imagemagick', apt: 'imagemagick', description: 'Image manipulation (ImageMagick)' },
|
|
31
|
+
sox: { brew: 'sox', apt: 'sox', description: 'Sound processing toolkit' },
|
|
32
|
+
jq: { brew: 'jq', apt: 'jq', description: 'JSON processor' },
|
|
33
|
+
curl: { brew: 'curl', apt: 'curl', description: 'HTTP client' },
|
|
34
|
+
wget: { brew: 'wget', apt: 'wget', description: 'File downloader' },
|
|
35
|
+
yt_dlp: { brew: 'yt-dlp', pip: 'yt-dlp', description: 'Video downloader' },
|
|
36
|
+
'yt-dlp': { brew: 'yt-dlp', pip: 'yt-dlp', description: 'Video downloader' },
|
|
37
|
+
tesseract: { brew: 'tesseract', apt: 'tesseract-ocr', description: 'OCR text recognition' },
|
|
38
|
+
pdftk: { brew: 'pdftk-java', apt: 'pdftk', description: 'PDF toolkit' },
|
|
39
|
+
ghostscript: { brew: 'ghostscript', apt: 'ghostscript', description: 'PDF/PostScript processor' },
|
|
40
|
+
gs: { brew: 'ghostscript', apt: 'ghostscript', description: 'PDF/PostScript processor' },
|
|
41
|
+
chromium: { brew: 'chromium', apt: 'chromium-browser', description: 'Web browser' },
|
|
42
|
+
pandoc: { brew: 'pandoc', apt: 'pandoc', description: 'Document format converter' },
|
|
43
|
+
rsvg: { brew: 'librsvg', apt: 'librsvg2-bin', description: 'SVG renderer' },
|
|
44
|
+
graphviz: { brew: 'graphviz', apt: 'graphviz', description: 'Graph visualization' },
|
|
45
|
+
dot: { brew: 'graphviz', apt: 'graphviz', description: 'Graph visualization (part of graphviz)' },
|
|
46
|
+
gifsicle: { brew: 'gifsicle', apt: 'gifsicle', description: 'GIF optimizer' },
|
|
47
|
+
optipng: { brew: 'optipng', apt: 'optipng', description: 'PNG optimizer' },
|
|
48
|
+
qrencode: { brew: 'qrencode', apt: 'qrencode', description: 'QR code generator' },
|
|
49
|
+
htop: { brew: 'htop', apt: 'htop', description: 'Process monitor' },
|
|
50
|
+
tree: { brew: 'tree', apt: 'tree', description: 'Directory tree viewer' },
|
|
51
|
+
ripgrep: { brew: 'ripgrep', apt: 'ripgrep', description: 'Fast text search (rg)' },
|
|
52
|
+
rg: { brew: 'ripgrep', apt: 'ripgrep', description: 'Fast text search' },
|
|
53
|
+
fd: { brew: 'fd', apt: 'fd-find', description: 'Fast file finder' },
|
|
54
|
+
bat: { brew: 'bat', apt: 'bat', description: 'Better cat with syntax highlighting' },
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export function createDependencyManagerTools(): ToolDefinition[] {
|
|
58
|
+
return [
|
|
59
|
+
{
|
|
60
|
+
name: 'check_dependency',
|
|
61
|
+
description: `Check if a command-line tool is available on this system. Returns availability, version info, and install instructions if missing. Use this BEFORE running shell commands that depend on specific tools (ffmpeg, imagemagick, etc.). If the tool is missing, use install_dependency to install it.`,
|
|
62
|
+
input_schema: {
|
|
63
|
+
type: 'object' as const,
|
|
64
|
+
properties: {
|
|
65
|
+
command: { type: 'string', description: 'Command to check (e.g. "ffmpeg", "convert", "jq")' },
|
|
66
|
+
},
|
|
67
|
+
required: ['command'],
|
|
68
|
+
},
|
|
69
|
+
execute: async (input: any) => {
|
|
70
|
+
var cmd = input.command.trim();
|
|
71
|
+
try {
|
|
72
|
+
var { stdout } = await execAsync(`which ${cmd} 2>/dev/null && ${cmd} --version 2>&1 || ${cmd} -version 2>&1 || echo "version-unknown"`, {
|
|
73
|
+
timeout: 5000,
|
|
74
|
+
env: { ...process.env, TERM: 'dumb' },
|
|
75
|
+
});
|
|
76
|
+
return {
|
|
77
|
+
available: true,
|
|
78
|
+
command: cmd,
|
|
79
|
+
path: stdout.split('\n')[0] || '',
|
|
80
|
+
versionInfo: stdout.slice(0, 500),
|
|
81
|
+
};
|
|
82
|
+
} catch {
|
|
83
|
+
var known = KNOWN_PACKAGES[cmd];
|
|
84
|
+
var os = platform();
|
|
85
|
+
var installCmd = '';
|
|
86
|
+
if (known) {
|
|
87
|
+
if (os === 'darwin' && known.brew) installCmd = `brew install ${known.brew}`;
|
|
88
|
+
else if (known.apt) installCmd = `sudo apt-get install -y ${known.apt}`;
|
|
89
|
+
else if (known.pip) installCmd = `pip install ${known.pip}`;
|
|
90
|
+
else if (known.npm) installCmd = `npm install -g ${known.npm}`;
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
available: false,
|
|
94
|
+
command: cmd,
|
|
95
|
+
description: known?.description || 'Unknown tool',
|
|
96
|
+
installCommand: installCmd || `Use shell_install with package="${cmd}"`,
|
|
97
|
+
suggestion: `Tool "${cmd}" is not installed. ${installCmd ? `Install with: ${installCmd}` : 'Use install_dependency to install it.'}`,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
name: 'install_dependency',
|
|
104
|
+
description: `Install a missing command-line tool using the system package manager (brew on macOS, apt on Linux). Auto-detects the correct package name for common tools. Tracks installations for cleanup. Use check_dependency first to verify the tool is actually missing.`,
|
|
105
|
+
input_schema: {
|
|
106
|
+
type: 'object' as const,
|
|
107
|
+
properties: {
|
|
108
|
+
command: { type: 'string', description: 'Tool name to install (e.g. "ffmpeg", "imagemagick")' },
|
|
109
|
+
package: { type: 'string', description: 'Override package name if different from command' },
|
|
110
|
+
method: { type: 'string', description: 'Force install method: brew|apt|pip|npm (auto-detected by default)' },
|
|
111
|
+
},
|
|
112
|
+
required: ['command'],
|
|
113
|
+
},
|
|
114
|
+
execute: async (input: any) => {
|
|
115
|
+
var cmd = input.command.trim();
|
|
116
|
+
var os = platform();
|
|
117
|
+
var known = KNOWN_PACKAGES[cmd];
|
|
118
|
+
var pkg = input.package || '';
|
|
119
|
+
var method = input.method || '';
|
|
120
|
+
|
|
121
|
+
// Determine install command
|
|
122
|
+
var installCmd = '';
|
|
123
|
+
var packageName = '';
|
|
124
|
+
|
|
125
|
+
if (method === 'pip' || (!method && known?.pip && !known?.brew && !known?.apt)) {
|
|
126
|
+
packageName = pkg || known?.pip || cmd;
|
|
127
|
+
installCmd = `pip install ${packageName}`;
|
|
128
|
+
} else if (method === 'npm' || (!method && known?.npm)) {
|
|
129
|
+
packageName = pkg || known?.npm || cmd;
|
|
130
|
+
installCmd = `npm install -g ${packageName}`;
|
|
131
|
+
} else if (os === 'darwin') {
|
|
132
|
+
packageName = pkg || known?.brew || cmd;
|
|
133
|
+
installCmd = `brew install ${packageName}`;
|
|
134
|
+
} else {
|
|
135
|
+
// Linux
|
|
136
|
+
packageName = pkg || known?.apt || cmd;
|
|
137
|
+
installCmd = `sudo apt-get install -y ${packageName}`;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
console.log(`[dep-manager] Installing: ${installCmd}`);
|
|
141
|
+
|
|
142
|
+
try {
|
|
143
|
+
var r = await execAsync(installCmd, {
|
|
144
|
+
timeout: 300000, // 5 min for large packages
|
|
145
|
+
maxBuffer: 2 * 1024 * 1024,
|
|
146
|
+
env: { ...process.env, DEBIAN_FRONTEND: 'noninteractive', TERM: 'dumb', HOMEBREW_NO_AUTO_UPDATE: '1' },
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// Track installation for cleanup
|
|
150
|
+
var key = 'global'; // Could be per-session if we had session context
|
|
151
|
+
var installed = sessionInstalls.get(key) || [];
|
|
152
|
+
installed.push(packageName);
|
|
153
|
+
sessionInstalls.set(key, installed);
|
|
154
|
+
|
|
155
|
+
// Verify installation
|
|
156
|
+
try {
|
|
157
|
+
await execAsync(`which ${cmd}`, { timeout: 3000 });
|
|
158
|
+
return {
|
|
159
|
+
ok: true,
|
|
160
|
+
command: cmd,
|
|
161
|
+
package: packageName,
|
|
162
|
+
method: installCmd.split(' ')[0],
|
|
163
|
+
stdout: (r.stdout || '').slice(-2000),
|
|
164
|
+
note: `Installed "${packageName}" successfully. The "${cmd}" command is now available.`,
|
|
165
|
+
};
|
|
166
|
+
} catch {
|
|
167
|
+
return {
|
|
168
|
+
ok: true,
|
|
169
|
+
command: cmd,
|
|
170
|
+
package: packageName,
|
|
171
|
+
warning: `Package installed but "${cmd}" not found in PATH. The binary may have a different name.`,
|
|
172
|
+
stdout: (r.stdout || '').slice(-2000),
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
} catch (err: any) {
|
|
176
|
+
return {
|
|
177
|
+
ok: false,
|
|
178
|
+
command: cmd,
|
|
179
|
+
error: (err.stderr || err.message || '').slice(0, 5000),
|
|
180
|
+
suggestion: `Installation failed. Try: 1) Check package name is correct, 2) Run with sudo if needed, 3) Use shell_exec to install manually.`,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
name: 'check_environment',
|
|
187
|
+
description: 'Check the current system environment: OS, package manager, installed common tools, available disk space, etc. Use at the start of complex tasks to understand capabilities.',
|
|
188
|
+
input_schema: {
|
|
189
|
+
type: 'object' as const,
|
|
190
|
+
properties: {},
|
|
191
|
+
required: [],
|
|
192
|
+
},
|
|
193
|
+
execute: async () => {
|
|
194
|
+
var os = platform();
|
|
195
|
+
var checks: Record<string, boolean> = {};
|
|
196
|
+
var commonTools = ['ffmpeg', 'convert', 'jq', 'curl', 'wget', 'sox', 'pandoc', 'tesseract', 'yt-dlp', 'rg', 'node', 'python3', 'pip3', 'git'];
|
|
197
|
+
|
|
198
|
+
for (var tool of commonTools) {
|
|
199
|
+
try {
|
|
200
|
+
await execAsync(`which ${tool}`, { timeout: 2000 });
|
|
201
|
+
checks[tool] = true;
|
|
202
|
+
} catch {
|
|
203
|
+
checks[tool] = false;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
var pkgManager = 'unknown';
|
|
208
|
+
try {
|
|
209
|
+
if (os === 'darwin') { await execAsync('which brew', { timeout: 2000 }); pkgManager = 'brew'; }
|
|
210
|
+
else { await execAsync('which apt-get', { timeout: 2000 }); pkgManager = 'apt'; }
|
|
211
|
+
} catch {
|
|
212
|
+
try { await execAsync('which dnf', { timeout: 2000 }); pkgManager = 'dnf'; }
|
|
213
|
+
catch { try { await execAsync('which pacman', { timeout: 2000 }); pkgManager = 'pacman'; } catch {} }
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
var diskSpace = '';
|
|
217
|
+
try {
|
|
218
|
+
var r = await execAsync('df -h / | tail -1', { timeout: 3000 });
|
|
219
|
+
diskSpace = r.stdout.trim();
|
|
220
|
+
} catch {}
|
|
221
|
+
|
|
222
|
+
var nodeVersion = '';
|
|
223
|
+
try { nodeVersion = (await execAsync('node --version', { timeout: 2000 })).stdout.trim(); } catch {}
|
|
224
|
+
|
|
225
|
+
return {
|
|
226
|
+
os,
|
|
227
|
+
arch: process.arch,
|
|
228
|
+
packageManager: pkgManager,
|
|
229
|
+
nodeVersion,
|
|
230
|
+
diskSpace,
|
|
231
|
+
tools: checks,
|
|
232
|
+
missingTools: Object.entries(checks).filter(([, v]) => !v).map(([k]) => k),
|
|
233
|
+
availableTools: Object.entries(checks).filter(([, v]) => v).map(([k]) => k),
|
|
234
|
+
installedThisSession: sessionInstalls.get('global') || [],
|
|
235
|
+
};
|
|
236
|
+
},
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
name: 'cleanup_installed',
|
|
240
|
+
description: 'List or uninstall packages that were installed during this session. Use for cleanup after completing tasks.',
|
|
241
|
+
input_schema: {
|
|
242
|
+
type: 'object' as const,
|
|
243
|
+
properties: {
|
|
244
|
+
action: { type: 'string', description: '"list" to see installed packages, "uninstall" to remove them, "keep" to clear tracking without removing' },
|
|
245
|
+
packages: { type: 'array', items: { type: 'string' }, description: 'Specific packages to uninstall (default: all session-installed)' },
|
|
246
|
+
},
|
|
247
|
+
required: ['action'],
|
|
248
|
+
},
|
|
249
|
+
execute: async (input: any) => {
|
|
250
|
+
var installed = sessionInstalls.get('global') || [];
|
|
251
|
+
|
|
252
|
+
if (input.action === 'list') {
|
|
253
|
+
return { installedThisSession: installed };
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if (input.action === 'keep') {
|
|
257
|
+
sessionInstalls.delete('global');
|
|
258
|
+
return { ok: true, message: 'Tracking cleared. Packages remain installed.', packages: installed };
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (input.action === 'uninstall') {
|
|
262
|
+
var toRemove = input.packages || installed;
|
|
263
|
+
var os = platform();
|
|
264
|
+
var results: any[] = [];
|
|
265
|
+
|
|
266
|
+
for (var pkg of toRemove) {
|
|
267
|
+
try {
|
|
268
|
+
var cmd = os === 'darwin' ? `brew uninstall ${pkg}` : `sudo apt-get remove -y ${pkg}`;
|
|
269
|
+
await execAsync(cmd, { timeout: 60000, env: { ...process.env, DEBIAN_FRONTEND: 'noninteractive' } });
|
|
270
|
+
results.push({ package: pkg, removed: true });
|
|
271
|
+
// Remove from tracking
|
|
272
|
+
installed = installed.filter((p: string) => p !== pkg);
|
|
273
|
+
} catch (err: any) {
|
|
274
|
+
results.push({ package: pkg, removed: false, error: (err.message || '').slice(0, 200) });
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
sessionInstalls.set('global', installed);
|
|
279
|
+
return { results, remaining: installed };
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
return { error: 'Unknown action. Use "list", "uninstall", or "keep".' };
|
|
283
|
+
},
|
|
284
|
+
},
|
|
285
|
+
];
|
|
286
|
+
}
|
|
@@ -11,6 +11,7 @@ import { createFileListTool } from './file-list.js';
|
|
|
11
11
|
import { createFileSearchTool } from './file-search.js';
|
|
12
12
|
import { createFileMoveTool, createFileDeleteTool } from './file-ops.js';
|
|
13
13
|
import { createShellTools } from './shell.js';
|
|
14
|
+
import { createDependencyManagerTools } from './dependency-manager.js';
|
|
14
15
|
import { createSystemInfoTool } from './system-info.js';
|
|
15
16
|
import { createCodingTools } from './coding.js';
|
|
16
17
|
import type { ToolDefinition } from '../../types.js';
|
|
@@ -36,6 +37,7 @@ export function createLocalSystemTools(config?: LocalToolsConfig): ToolDefinitio
|
|
|
36
37
|
createFileMoveTool(sandbox),
|
|
37
38
|
createFileDeleteTool(sandbox),
|
|
38
39
|
...createShellTools({ cwd: config?.shellCwd, timeout: config?.shellTimeout }),
|
|
40
|
+
...createDependencyManagerTools(),
|
|
39
41
|
createSystemInfoTool(),
|
|
40
42
|
...createCodingTools({ cwd: config?.shellCwd, sandbox }),
|
|
41
43
|
];
|
|
@@ -50,3 +52,4 @@ export { createFileMoveTool, createFileDeleteTool } from './file-ops.js';
|
|
|
50
52
|
export { createShellTools, createShellExecTool } from './shell.js';
|
|
51
53
|
export { createSystemInfoTool } from './system-info.js';
|
|
52
54
|
export { createCodingTools } from './coding.js';
|
|
55
|
+
export { createDependencyManagerTools } from './dependency-manager.js';
|
|
@@ -90,6 +90,35 @@ export function createTelegramTools(config: TelegramConfig): ToolDefinition[] {
|
|
|
90
90
|
input_schema: { type: 'object' as const, properties: {}, required: [] },
|
|
91
91
|
execute: async (_id: string) => tgApi(botToken, 'getMe'),
|
|
92
92
|
},
|
|
93
|
+
{
|
|
94
|
+
name: 'telegram_download_file',
|
|
95
|
+
description: 'Download a file from Telegram by file_id (from media messages). Returns the local path.',
|
|
96
|
+
input_schema: {
|
|
97
|
+
type: 'object' as const,
|
|
98
|
+
properties: {
|
|
99
|
+
fileId: { type: 'string', description: 'Telegram file_id from the message' },
|
|
100
|
+
fileName: { type: 'string', description: 'Optional output filename' },
|
|
101
|
+
},
|
|
102
|
+
required: ['fileId'],
|
|
103
|
+
},
|
|
104
|
+
execute: async (_id: string, input: any) => {
|
|
105
|
+
var fileData = await tgApi(botToken, 'getFile', { file_id: input.fileId });
|
|
106
|
+
if (!fileData.file_path) return { error: 'No file_path returned' };
|
|
107
|
+
var downloadUrl = `https://api.telegram.org/file/bot${botToken}/${fileData.file_path}`;
|
|
108
|
+
var resp = await fetch(downloadUrl);
|
|
109
|
+
if (!resp.ok) throw new Error(`Download failed: ${resp.status}`);
|
|
110
|
+
var { join } = await import('path');
|
|
111
|
+
var { mkdirSync, writeFileSync } = await import('fs');
|
|
112
|
+
var mediaDir = join('/tmp/agents/media');
|
|
113
|
+
try { mkdirSync(mediaDir, { recursive: true }); } catch {}
|
|
114
|
+
var ext = fileData.file_path.split('.').pop() || 'bin';
|
|
115
|
+
var localName = input.fileName || `telegram-${Date.now()}.${ext}`;
|
|
116
|
+
var localPath = join(mediaDir, localName);
|
|
117
|
+
var buffer = Buffer.from(await resp.arrayBuffer());
|
|
118
|
+
writeFileSync(localPath, buffer);
|
|
119
|
+
return { ok: true, localPath, size: buffer.length, originalPath: fileData.file_path };
|
|
120
|
+
},
|
|
121
|
+
},
|
|
93
122
|
{
|
|
94
123
|
name: 'telegram_get_chat',
|
|
95
124
|
description: 'Get chat/group details.',
|
|
@@ -155,22 +155,77 @@ export async function getOrCreateConnection(config: WhatsAppConfig): Promise<Wha
|
|
|
155
155
|
if (!isSelfChat) continue;
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
-
|
|
158
|
+
// Detect media
|
|
159
|
+
var mediaMessage = msg.message?.imageMessage || msg.message?.videoMessage ||
|
|
160
|
+
msg.message?.documentMessage || msg.message?.audioMessage ||
|
|
161
|
+
msg.message?.stickerMessage || null;
|
|
162
|
+
var hasMedia = !!mediaMessage;
|
|
163
|
+
|
|
164
|
+
// For media messages, caption may be the text
|
|
165
|
+
if (!text && mediaMessage) {
|
|
166
|
+
text = mediaMessage.caption || '';
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Skip if no text AND no media
|
|
170
|
+
if (!text && !hasMedia) continue;
|
|
159
171
|
|
|
160
172
|
var senderJid = isGroup ? msg.key.participant : remoteJid;
|
|
161
|
-
console.log(`[wa:${config.agentId.slice(0,8)}] Incoming from=${senderJid} group=${isGroup} selfChat=${!!isSelfChat} text="${text.slice(0,50)}"`);
|
|
173
|
+
console.log(`[wa:${config.agentId.slice(0,8)}] Incoming from=${senderJid} group=${isGroup} selfChat=${!!isSelfChat} hasMedia=${hasMedia} text="${(text||'').slice(0,50)}"`);
|
|
162
174
|
|
|
163
175
|
// Show typing indicator while agent processes
|
|
164
176
|
try { await sock.sendPresenceUpdate('composing', remoteJid); } catch {}
|
|
165
177
|
|
|
178
|
+
// Download media if present
|
|
179
|
+
var mediaPath: string | undefined;
|
|
180
|
+
var mediaType: string | undefined;
|
|
181
|
+
if (hasMedia && mediaMessage) {
|
|
182
|
+
try {
|
|
183
|
+
var { downloadMediaMessage } = await import('@whiskeysockets/baileys');
|
|
184
|
+
var buffer = await downloadMediaMessage(msg, 'buffer', {});
|
|
185
|
+
if (buffer && buffer.length > 0) {
|
|
186
|
+
var { join } = await import('path');
|
|
187
|
+
var { mkdirSync, writeFileSync } = await import('fs');
|
|
188
|
+
var mediaDir = join(config.dataDir || `/tmp/agents/${config.agentId}`, 'media');
|
|
189
|
+
try { mkdirSync(mediaDir, { recursive: true }); } catch {}
|
|
190
|
+
|
|
191
|
+
mediaType = msg.message?.imageMessage ? 'photo'
|
|
192
|
+
: msg.message?.videoMessage ? 'video'
|
|
193
|
+
: msg.message?.audioMessage ? 'audio'
|
|
194
|
+
: msg.message?.documentMessage ? 'document'
|
|
195
|
+
: msg.message?.stickerMessage ? 'sticker' : 'file';
|
|
196
|
+
|
|
197
|
+
var ext = mediaType === 'photo' ? 'jpg' : mediaType === 'video' ? 'mp4'
|
|
198
|
+
: mediaType === 'audio' ? 'ogg' : mediaType === 'sticker' ? 'webp'
|
|
199
|
+
: (mediaMessage.fileName?.split('.').pop() || 'bin');
|
|
200
|
+
var localName = mediaMessage.fileName || `${mediaType}-${Date.now()}.${ext}`;
|
|
201
|
+
mediaPath = join(mediaDir, localName);
|
|
202
|
+
writeFileSync(mediaPath, buffer);
|
|
203
|
+
console.log(`[wa:${config.agentId.slice(0,8)}] Media downloaded: ${mediaPath} (${buffer.length} bytes)`);
|
|
204
|
+
}
|
|
205
|
+
} catch (dlErr: any) {
|
|
206
|
+
console.error(`[wa:${config.agentId.slice(0,8)}] Media download failed: ${dlErr.message}`);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Build text with media info
|
|
211
|
+
var finalText = text || '';
|
|
212
|
+
if (mediaPath) {
|
|
213
|
+
var desc = `[${mediaType}${mediaMessage?.fileName ? ': ' + mediaMessage.fileName : ''}] saved to: ${mediaPath}`;
|
|
214
|
+
finalText = text ? `${text}\n\n${desc}` : desc;
|
|
215
|
+
} else if (hasMedia && !text) {
|
|
216
|
+
finalText = `[${mediaType || 'media'} received but download failed]`;
|
|
217
|
+
}
|
|
218
|
+
|
|
166
219
|
conn.lastMessageAt = Date.now();
|
|
167
220
|
conn.events.emit('message', {
|
|
168
221
|
from: remoteJid,
|
|
169
222
|
senderJid,
|
|
170
223
|
pushName: msg.pushName,
|
|
171
|
-
text,
|
|
224
|
+
text: finalText,
|
|
172
225
|
timestamp: msg.messageTimestamp,
|
|
173
|
-
hasMedia
|
|
226
|
+
hasMedia,
|
|
227
|
+
mediaPath,
|
|
228
|
+
mediaType,
|
|
174
229
|
messageId: msg.key.id,
|
|
175
230
|
isGroup,
|
|
176
231
|
isSelfChat: !!isSelfChat,
|
package/src/auth/routes.ts
CHANGED
|
@@ -73,11 +73,14 @@ export function createAuthRoutes(
|
|
|
73
73
|
return process.env.NODE_ENV === 'production' || process.env.SECURE_COOKIES === '1';
|
|
74
74
|
};
|
|
75
75
|
|
|
76
|
-
async function issueTokens(userId: string, email: string, role: string) {
|
|
76
|
+
async function issueTokens(userId: string, email: string, role: string, clientOrgId?: string | null) {
|
|
77
77
|
const { SignJWT } = await import('jose');
|
|
78
78
|
const secret = new TextEncoder().encode(jwtSecret);
|
|
79
79
|
|
|
80
|
-
const
|
|
80
|
+
const payload: Record<string, any> = { sub: userId, email, role };
|
|
81
|
+
if (clientOrgId) payload.clientOrgId = clientOrgId;
|
|
82
|
+
|
|
83
|
+
const token = await new SignJWT(payload)
|
|
81
84
|
.setProtectedHeader({ alg: 'HS256' })
|
|
82
85
|
.setIssuedAt()
|
|
83
86
|
.setExpirationTime(TOKEN_TTL)
|
|
@@ -93,8 +96,8 @@ export function createAuthRoutes(
|
|
|
93
96
|
}
|
|
94
97
|
|
|
95
98
|
/** Set session cookies and return token info */
|
|
96
|
-
async function setSessionCookies(c: any, userId: string, email: string, role: string, method: string) {
|
|
97
|
-
const { token, refreshToken } = await issueTokens(userId, email, role);
|
|
99
|
+
async function setSessionCookies(c: any, userId: string, email: string, role: string, method: string, clientOrgId?: string | null) {
|
|
100
|
+
const { token, refreshToken } = await issueTokens(userId, email, role, clientOrgId);
|
|
98
101
|
const csrf = generateCsrf();
|
|
99
102
|
const secure = isSecure();
|
|
100
103
|
|
|
@@ -301,7 +304,7 @@ export function createAuthRoutes(
|
|
|
301
304
|
});
|
|
302
305
|
}
|
|
303
306
|
|
|
304
|
-
const { token, refreshToken, csrf } = await setSessionCookies(c, user.id, user.email, user.role, 'password');
|
|
307
|
+
const { token, refreshToken, csrf } = await setSessionCookies(c, user.id, user.email, user.role, 'password', user.clientOrgId);
|
|
305
308
|
|
|
306
309
|
return c.json({
|
|
307
310
|
token,
|
|
@@ -360,7 +363,7 @@ export function createAuthRoutes(
|
|
|
360
363
|
|
|
361
364
|
pending2fa.delete(challengeToken);
|
|
362
365
|
|
|
363
|
-
const { token, refreshToken, csrf } = await setSessionCookies(c, user.id, user.email, user.role, 'password+2fa');
|
|
366
|
+
const { token, refreshToken, csrf } = await setSessionCookies(c, user.id, user.email, user.role, 'password+2fa', user.clientOrgId);
|
|
364
367
|
|
|
365
368
|
return c.json({
|
|
366
369
|
token,
|
|
@@ -614,7 +617,7 @@ export function createAuthRoutes(
|
|
|
614
617
|
const user = await db.getUser(key.createdBy);
|
|
615
618
|
if (!user) return c.json({ error: 'API key owner not found' }, 401);
|
|
616
619
|
|
|
617
|
-
const { token, refreshToken, csrf } = await setSessionCookies(c, user.id, user.email, user.role, 'api-key');
|
|
620
|
+
const { token, refreshToken, csrf } = await setSessionCookies(c, user.id, user.email, user.role, 'api-key', user.clientOrgId);
|
|
618
621
|
|
|
619
622
|
return c.json({
|
|
620
623
|
token,
|
|
@@ -643,7 +646,7 @@ export function createAuthRoutes(
|
|
|
643
646
|
const user = await db.getUser(payload.sub as string);
|
|
644
647
|
if (!user) return c.json({ error: 'User not found' }, 401);
|
|
645
648
|
|
|
646
|
-
const { token, refreshToken } = await issueTokens(user.id, user.email, user.role);
|
|
649
|
+
const { token, refreshToken } = await issueTokens(user.id, user.email, user.role, user.clientOrgId);
|
|
647
650
|
const csrf = generateCsrf();
|
|
648
651
|
const secure = isSecure();
|
|
649
652
|
|
|
@@ -694,7 +697,7 @@ export function createAuthRoutes(
|
|
|
694
697
|
if (!target) return c.json({ error: 'User not found' }, 404);
|
|
695
698
|
|
|
696
699
|
// Generate a short-lived token (1 hour) for the target user with impersonation flag
|
|
697
|
-
const impersonateToken = await new SignJWT({ sub: target.id, role: target.role, impersonatedBy: caller.id })
|
|
700
|
+
const impersonateToken = await new SignJWT({ sub: target.id, role: target.role, impersonatedBy: caller.id, clientOrgId: target.clientOrgId || undefined, orgId: target.clientOrgId || (target as any).org_id || undefined })
|
|
698
701
|
.setProtectedHeader({ alg: 'HS256' })
|
|
699
702
|
.setIssuedAt()
|
|
700
703
|
.setExpirationTime('1h')
|
|
@@ -890,7 +893,7 @@ export function createAuthRoutes(
|
|
|
890
893
|
ip: c.req.header('x-forwarded-for') || c.req.header('x-real-ip'),
|
|
891
894
|
});
|
|
892
895
|
|
|
893
|
-
const { token, refreshToken, csrf } = await setSessionCookies(c, user.id, user.email, user.role, 'bootstrap');
|
|
896
|
+
const { token, refreshToken, csrf } = await setSessionCookies(c, user.id, user.email, user.role, 'bootstrap', user.clientOrgId);
|
|
894
897
|
|
|
895
898
|
// Notify server that setup is complete (flips the dashboard latch)
|
|
896
899
|
opts?.onBootstrap?.();
|
|
@@ -1214,7 +1217,7 @@ export function createAuthRoutes(
|
|
|
1214
1217
|
}
|
|
1215
1218
|
|
|
1216
1219
|
// Issue session
|
|
1217
|
-
await setSessionCookies(c, result.user.id, result.user.email, result.user.role, 'oidc');
|
|
1220
|
+
await setSessionCookies(c, result.user.id, result.user.email, result.user.role, 'oidc', result.user.clientOrgId);
|
|
1218
1221
|
|
|
1219
1222
|
// Redirect to dashboard
|
|
1220
1223
|
return c.redirect('/dashboard');
|
|
@@ -1363,7 +1366,7 @@ export function createAuthRoutes(
|
|
|
1363
1366
|
}
|
|
1364
1367
|
|
|
1365
1368
|
// Issue session
|
|
1366
|
-
await setSessionCookies(c, result.user.id, result.user.email, result.user.role, 'saml');
|
|
1369
|
+
await setSessionCookies(c, result.user.id, result.user.email, result.user.role, 'saml', result.user.clientOrgId);
|
|
1367
1370
|
|
|
1368
1371
|
// Redirect to dashboard (or RelayState)
|
|
1369
1372
|
return c.redirect('/dashboard');
|
package/src/cli-agent.ts
CHANGED
|
@@ -393,11 +393,8 @@ export async function runAgent(_args: string[]) {
|
|
|
393
393
|
console.log(' Connecting to database...');
|
|
394
394
|
|
|
395
395
|
// 1. Connect to shared enterprise DB
|
|
396
|
-
const { createAdapter } = await import('./db/factory.js');
|
|
397
|
-
const db = await createAdapter(
|
|
398
|
-
type: DATABASE_URL.startsWith('postgres') ? 'postgres' : 'sqlite',
|
|
399
|
-
connectionString: DATABASE_URL,
|
|
400
|
-
});
|
|
396
|
+
const { createAdapter, smartDbConfig } = await import('./db/factory.js');
|
|
397
|
+
const db = await createAdapter(smartDbConfig(DATABASE_URL));
|
|
401
398
|
await db.migrate();
|
|
402
399
|
|
|
403
400
|
// 2. Initialize engine DB
|
|
@@ -902,6 +899,7 @@ export async function runAgent(_args: string[]) {
|
|
|
902
899
|
isDM: boolean;
|
|
903
900
|
messageText: string;
|
|
904
901
|
isManager?: boolean;
|
|
902
|
+
mediaFiles?: Array<{ path: string; type: string; mimeType?: string }>;
|
|
905
903
|
}>();
|
|
906
904
|
|
|
907
905
|
const isMessagingSource = ['whatsapp', 'telegram'].includes(ctx.source);
|
|
@@ -1063,6 +1061,23 @@ export async function runAgent(_args: string[]) {
|
|
|
1063
1061
|
`- No markdown formatting — plain text only.`,
|
|
1064
1062
|
`- For simple greetings/questions, reply in ONE tool call. Do not overthink.`,
|
|
1065
1063
|
'',
|
|
1064
|
+
`DEPENDENCY & TOOL MANAGEMENT:`,
|
|
1065
|
+
`- Before running commands that need specific tools (ffmpeg, imagemagick, etc.), use check_dependency to verify they're installed.`,
|
|
1066
|
+
`- If a tool is missing: use install_dependency to install it automatically (brew on macOS, apt on Linux).`,
|
|
1067
|
+
`- Tell your manager what you're installing and why — don't just silently install things. Example: "I need to install ffmpeg to process your video. Installing now..."`,
|
|
1068
|
+
`- After completing a task that required installing new tools, use cleanup_installed to review what was installed.`,
|
|
1069
|
+
`- For common tools (ffmpeg, imagemagick, jq, etc.) you can install without explicit permission — just inform.`,
|
|
1070
|
+
`- For unusual packages or large installs, ask your manager first.`,
|
|
1071
|
+
`- If installation fails, explain what happened and suggest alternatives.`,
|
|
1072
|
+
`- Use check_environment at the start of complex tasks to understand what's available.`,
|
|
1073
|
+
'',
|
|
1074
|
+
`FILE & MEDIA HANDLING:`,
|
|
1075
|
+
`- When you receive media files (images, videos, documents), they are saved locally and you can access them.`,
|
|
1076
|
+
`- For images: you can see them directly in the message. Describe what you see.`,
|
|
1077
|
+
`- For videos/audio: use ffmpeg (check_dependency first) to analyze, convert, or edit.`,
|
|
1078
|
+
`- For documents: use the appropriate tool to read/process them.`,
|
|
1079
|
+
`- You can send media back using ${ctx.source === 'telegram' ? 'telegram_send_media' : 'whatsapp_send_media'} with a local file path.`,
|
|
1080
|
+
'',
|
|
1066
1081
|
buildScheduleInfo(agentSchedule, agentTimezone),
|
|
1067
1082
|
ambientContext ? `\nCONTEXT FROM MEMORY:\n${ambientContext}` : '',
|
|
1068
1083
|
].filter(Boolean).join('\n');
|
|
@@ -1118,11 +1133,37 @@ export async function runAgent(_args: string[]) {
|
|
|
1118
1133
|
});
|
|
1119
1134
|
} catch (e: any) { /* non-fatal */ }
|
|
1120
1135
|
|
|
1136
|
+
// Build multimodal message content if media files are present
|
|
1137
|
+
let chatMessageContent: string = ctx.messageText;
|
|
1138
|
+
let mediaContentBlocks: any[] | undefined;
|
|
1139
|
+
if ((ctx as any).mediaFiles && (ctx as any).mediaFiles.length > 0) {
|
|
1140
|
+
const { readFileSync } = await import('fs');
|
|
1141
|
+
const blocks: any[] = [];
|
|
1142
|
+
if (ctx.messageText) blocks.push({ type: 'text', text: ctx.messageText });
|
|
1143
|
+
for (const media of (ctx as any).mediaFiles) {
|
|
1144
|
+
try {
|
|
1145
|
+
const buf = readFileSync(media.path);
|
|
1146
|
+
const b64 = buf.toString('base64');
|
|
1147
|
+
const mime = media.mimeType || (media.type === 'photo' ? 'image/jpeg' : 'application/octet-stream');
|
|
1148
|
+
if (mime.startsWith('image/')) {
|
|
1149
|
+
blocks.push({ type: 'image', source: { type: 'base64', media_type: mime, data: b64 } });
|
|
1150
|
+
blocks.push({ type: 'text', text: `[Image saved at: ${media.path}]` });
|
|
1151
|
+
} else {
|
|
1152
|
+
blocks.push({ type: 'text', text: `[File received: ${media.path} (${mime}). Use tools to read/process this file.]` });
|
|
1153
|
+
}
|
|
1154
|
+
} catch (fileErr: any) {
|
|
1155
|
+
blocks.push({ type: 'text', text: `[Media file: ${media.path} — could not read: ${fileErr.message}]` });
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
if (blocks.length > 0) mediaContentBlocks = blocks;
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1121
1161
|
const session = await runtime.spawnSession({
|
|
1122
1162
|
agentId: agentId,
|
|
1123
|
-
message:
|
|
1163
|
+
message: chatMessageContent,
|
|
1124
1164
|
systemPrompt,
|
|
1125
1165
|
...(sessionContext ? { sessionContext } : {}),
|
|
1166
|
+
...(mediaContentBlocks ? { messageContent: mediaContentBlocks } : {}),
|
|
1126
1167
|
});
|
|
1127
1168
|
|
|
1128
1169
|
// Mark task as in progress
|
package/src/cli-serve.ts
CHANGED
|
@@ -121,13 +121,10 @@ export async function runServe(_args: string[]) {
|
|
|
121
121
|
process.exit(1);
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
const { createAdapter } = await import('./db/factory.js');
|
|
124
|
+
const { createAdapter, smartDbConfig } = await import('./db/factory.js');
|
|
125
125
|
const { createServer } = await import('./server.js');
|
|
126
126
|
|
|
127
|
-
const db = await createAdapter(
|
|
128
|
-
type: DATABASE_URL.startsWith('postgres') ? 'postgres' : 'sqlite',
|
|
129
|
-
connectionString: DATABASE_URL,
|
|
130
|
-
});
|
|
127
|
+
const db = await createAdapter(smartDbConfig(DATABASE_URL));
|
|
131
128
|
|
|
132
129
|
await db.migrate();
|
|
133
130
|
|