naisys 1.6.1 → 3.0.0-beta.4
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.
Potentially problematic release.
This version of naisys might be problematic. Click here for more details.
- package/README.md +41 -161
- package/bin/.gitattributes +0 -0
- package/bin/naisys +10 -55
- package/bin/ns-comment.ps1 +2 -0
- package/bin/ns-genimg +3 -0
- package/bin/ns-genimg.ps1 +1 -0
- package/bin/ns-lynx +3 -0
- package/bin/ns-lynx.ps1 +1 -0
- package/bin/ns-mail +3 -0
- package/bin/ns-mail.ps1 +1 -0
- package/bin/ns-session +3 -0
- package/bin/ns-session.ps1 +1 -0
- package/bin/pg-query +79 -0
- package/dist/agent/agentConfig.js +137 -0
- package/dist/agent/agentManager.js +180 -0
- package/dist/agent/agentManagerInterface.js +2 -0
- package/dist/agent/agentRuntime.js +127 -0
- package/dist/agent/userDisplayService.js +193 -0
- package/dist/agent/userService.js +193 -0
- package/dist/command/commandDefs.js +225 -0
- package/dist/command/commandHandler.js +192 -220
- package/dist/command/commandLoop.js +384 -223
- package/dist/command/commandProtection.js +67 -41
- package/dist/command/commandRegistry.js +60 -0
- package/dist/command/debugCommand.js +100 -0
- package/dist/command/promptBuilder.js +120 -137
- package/dist/command/shellCommand.js +59 -51
- package/dist/command/shellWrapper.js +480 -303
- package/dist/computer-use/anthropic-computer-use.js +58 -0
- package/dist/computer-use/computerService.js +331 -0
- package/dist/computer-use/desktop.js +145 -0
- package/dist/computer-use/google-computer-use.js +343 -0
- package/dist/computer-use/macosDesktop.js +230 -0
- package/dist/computer-use/openai-computer-use.js +256 -0
- package/dist/computer-use/waylandDesktop.js +163 -0
- package/dist/computer-use/windowsDesktop.js +238 -0
- package/dist/computer-use/x11Desktop.js +80 -0
- package/dist/features/genImg.js +83 -0
- package/dist/features/listen.js +89 -0
- package/dist/features/look.js +131 -0
- package/dist/features/lynx.js +368 -0
- package/dist/features/session.js +165 -0
- package/dist/features/subagent.js +347 -217
- package/dist/features/workspaces.js +100 -40
- package/dist/globalConfig.js +92 -0
- package/dist/hub/hubClient.js +140 -0
- package/dist/hub/hubClientConfig.js +13 -0
- package/dist/hub/hubClientLog.js +34 -0
- package/dist/hub/hubConnection.js +109 -0
- package/dist/hub/hubCostBuffer.js +75 -0
- package/dist/hub/hubLogBuffer.js +49 -0
- package/dist/llm/commandTool.js +252 -0
- package/dist/llm/contextManager.js +316 -134
- package/dist/llm/costDisplayService.js +168 -0
- package/dist/llm/costTracker.js +198 -62
- package/dist/llm/llmDtos.js +11 -7
- package/dist/llm/llmService.js +70 -177
- package/dist/llm/systemMessage.js +94 -61
- package/dist/llm/vendors/anthropic.js +197 -0
- package/dist/llm/vendors/google.js +161 -0
- package/dist/llm/vendors/mock.js +28 -0
- package/dist/llm/vendors/openai-compatible.js +100 -0
- package/dist/llm/vendors/openai-standard.js +131 -0
- package/dist/llm/vendors/vendorTypes.js +2 -0
- package/dist/mail/chat.js +298 -0
- package/dist/mail/mail.js +273 -0
- package/dist/mail/mailDisplayService.js +92 -0
- package/dist/naisys.js +80 -5
- package/dist/services/attachmentService.js +80 -0
- package/dist/services/heartbeatService.js +27 -0
- package/dist/services/hostService.js +68 -0
- package/dist/services/logService.js +36 -0
- package/dist/services/modelService.js +65 -0
- package/dist/services/pathService.js +21 -0
- package/dist/services/runService.js +43 -0
- package/dist/services/shellPlatform.js +93 -0
- package/dist/utils/agentNames.js +0 -0
- package/dist/utils/confirmation.js +46 -0
- package/dist/utils/escKeyListener.js +39 -0
- package/dist/utils/inputMode.js +18 -9
- package/dist/utils/output.js +68 -27
- package/dist/utils/promptNotificationService.js +74 -0
- package/dist/utils/sharedReadline.js +24 -0
- package/dist/utils/utilities.js +0 -0
- package/dist/utils/writeEventManager.js +43 -0
- package/package.json +56 -43
- package/LICENSE.md +0 -7
- package/bin/endsession +0 -3
- package/bin/genimg +0 -3
- package/bin/llmail +0 -3
- package/bin/llmynx +0 -3
- package/bin/pause +0 -3
- package/bin/trimsession +0 -3
- package/dist/config.js +0 -133
- package/dist/features/genimg.js +0 -102
- package/dist/features/llmail.js +0 -427
- package/dist/features/llmynx.js +0 -309
- package/dist/llm/dreamMaker.js +0 -79
- package/dist/llm/llModels.js +0 -119
- package/dist/utils/dbUtils.js +0 -39
- package/dist/utils/enums.js +0 -9
- package/dist/utils/logService.js +0 -98
- package/dist/utils/pathService.js +0 -66
- /package/bin/{comment → ns-comment} +0 -0
package/README.md
CHANGED
|
@@ -1,25 +1,21 @@
|
|
|
1
|
-
## NAISYS (
|
|
1
|
+
## NAISYS (Networked Agents Interface System)
|
|
2
|
+
|
|
3
|
+
[← Back to main README](../../README.md)
|
|
2
4
|
|
|
3
5
|
NAISYS allows any LLM you want to operate a standard Linux shell given your instructions. You can control how much
|
|
4
6
|
to spend, the maximum number of tokens to use per session, how long to wait between commands, etc.. Between each command
|
|
5
|
-
NAISYS will wait a few seconds to accept any input you want to put in yourself in case you want to
|
|
6
|
-
LLM, give it hints, and/or diagnose the session. Once the LLM reaches the token max you specified for the
|
|
7
|
+
NAISYS will wait a few seconds to accept any input you want to put in yourself in case you want to collaborate with the
|
|
8
|
+
LLM, give it hints, and/or diagnose the session. Once the LLM reaches the token max you specified for the session it
|
|
7
9
|
will wrap things up, and start a fresh shell for the LLM to continue on its work.
|
|
8
10
|
|
|
9
11
|
NAISYS tries to be a minimal wrapper, just helping the LLM operate in the shell 'better'. Making commands 'context friendly'. For instace if a command is long running, NAISYS will interrupt it, show the LLM the current output, and ask the LLM what it wants to
|
|
10
|
-
do next - wait, kill, or send input. The custom command prompt helps the LLM keep track of its token usage during the session. The 'comment' command helps the LLM think out loud without putting invalid commands into the shell.
|
|
12
|
+
do next - wait, kill, or send input. The custom command prompt helps the LLM keep track of its token usage during the session. The 'ns-comment' command helps the LLM think out loud without putting invalid commands into the shell.
|
|
11
13
|
|
|
12
14
|
Some use cases are building websites, diagnosing a system for security concerns, mapping out the topology of the local
|
|
13
15
|
network, learning and performing arbitrary tasks, or just plain exploring the limits of autonomy. NAISYS has a built-in
|
|
14
|
-
system for inter-agent
|
|
16
|
+
system for inter-agent communication. You can manually startup multiple instances of NAISYS with different roles, or
|
|
15
17
|
you can allow agents to start their own sub-agents on demand with instructions defined by the LLM itself!
|
|
16
18
|
|
|
17
|
-
[NPM](https://www.npmjs.com/package/naisys) | [Website](https://naisys.org) | [Discord](https://discord.gg/JBUPWSbaEt) | [Demo Video](https://www.youtube.com/watch?v=Ttya3ixjumo)
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
npm install -g naisys
|
|
21
|
-
```
|
|
22
|
-
|
|
23
19
|
#### Node.js is used to create a simple proxy shell environment for the LLM that
|
|
24
20
|
|
|
25
21
|
- Helps the LLM keep track of its current context size
|
|
@@ -28,120 +24,29 @@ npm install -g naisys
|
|
|
28
24
|
- Prevent the context from being polluted by catching common errors like output that includes the command prompt itself
|
|
29
25
|
- Allows debugging by way of a 'debug' prompt after each run of the LLM
|
|
30
26
|
- A custom 'mail' system for context friendly inter-agent communication
|
|
31
|
-
- A browser called '
|
|
27
|
+
- A browser called 'ns-lynx' that paginates web pages and makes links unique across the context
|
|
32
28
|
- Cost tracking and cost limits that must be set in the config
|
|
33
29
|
- Support for multiple LLM backends, configurable per agent - OpenAI, Google, Anthropic, and self-hosted LLMs
|
|
34
30
|
|
|
35
31
|
## Getting Started
|
|
36
32
|
|
|
37
|
-
-
|
|
38
|
-
- Install Node.js, NAISYS has been tested with version 20
|
|
39
|
-
- Install lynx using `apt install lynx`
|
|
40
|
-
- Run `npm install -g naisys`
|
|
41
|
-
- Create a `.env` file:
|
|
33
|
+
- Create a `.env` file based off the `.env.example` file
|
|
42
34
|
|
|
43
|
-
|
|
44
|
-
# Agent home files and NAISYS specific databases will be stored here
|
|
45
|
-
NAISYS_FOLDER="/var/naisys"
|
|
46
|
-
|
|
47
|
-
# The folder where the website and logs are served from (if not defined then logs put in the naisys folder)
|
|
48
|
-
WEBSITE_FOLDER="/var/www"
|
|
49
|
-
|
|
50
|
-
# Leave api keys/url blank if not using the service
|
|
51
|
-
OPENAI_API_KEY="xxx"
|
|
52
|
-
GOOGLE_API_KEY="yyy"
|
|
53
|
-
ANTHROPIC_API_KEY="zzz"
|
|
54
|
-
|
|
55
|
-
LOCAL_LLM_URL="http://localhost:1234/v1"
|
|
56
|
-
LOCAL_LLM_NAME="minstral instruct v0.2"
|
|
57
|
-
|
|
58
|
-
# Custom global vars for use in agent configurations here
|
|
59
|
-
WEBSITE_URL="http://localhost:8080/"
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
- Create an agent configuration file `smith.yaml`:
|
|
35
|
+
- Create an agent configuration file — see [`agents/template.yaml`](../../agents/template.yaml) for all available options and supported models. A minimal example:
|
|
63
36
|
|
|
64
37
|
```yaml
|
|
65
|
-
# Used to identify the agent on the prompt, logs, home dir, mail, etc..
|
|
66
38
|
username: smith
|
|
67
|
-
|
|
68
|
-
# How other agents will understand the role of this agent
|
|
69
39
|
title: Software Engineer
|
|
70
|
-
|
|
71
|
-
# The model to use for console interactions
|
|
72
|
-
# (gpt4turbo, gpt4turbo, gemini-pro, claude3sonnet, claude3opus, local)
|
|
73
|
-
shellModel: gpt4turbo
|
|
74
|
-
|
|
75
|
-
# Only used between sessions to provide guidance for the next session (use a more powerful model for this)
|
|
76
|
-
# defaults to the shellModel if omitted
|
|
77
|
-
dreamModel: claude3opus
|
|
78
|
-
|
|
79
|
-
# The model to use for llmynx, pre-processing websites to fit into a smaller context (use a cheaper model)
|
|
80
|
-
# defaults to the shellModel if omitted
|
|
81
|
-
webModel: claude3haiku
|
|
82
|
-
|
|
83
|
-
# The model used by the 'genimg' command. If not defined then the genimg command is not available to the LLM
|
|
84
|
-
# Valid values: dalle2-256, dalle2-512, dalle2-1024, dalle3-1024, dalle3-1024-HD
|
|
85
|
-
imageModel: dalle3-1024
|
|
86
|
-
|
|
87
|
-
# A system like prompt explaining the agent's role and responsibilities
|
|
88
|
-
# You can use config variables in this string
|
|
40
|
+
shellModel: claude4sonnet
|
|
89
41
|
agentPrompt: |
|
|
90
|
-
You are ${agent.username} a ${agent.title} with the job of
|
|
91
|
-
|
|
92
|
-
The location of the website files should be in ${env.WEBSITE_FOLDER}
|
|
93
|
-
The website can be tested with 'llmynx open ${env.WEBSITE_URL}' to see how it looks in a text based browser.
|
|
94
|
-
You can use PHP as a way to share layout across pages and reduce duplication.
|
|
95
|
-
Careful when creating new files that what you are creating is not already there.
|
|
96
|
-
|
|
97
|
-
# The number of tokens you want to limit a session to, independent of the LLM token max itself
|
|
98
|
-
# A lower max relies more on the LLM ending the session with good enough notes to not get lost when the session restarts
|
|
99
|
-
# A higher max allows the LLM to do more without losing track, but is more expensive
|
|
100
|
-
tokenMax: 5000
|
|
101
|
-
|
|
102
|
-
# The number of seconds to pause after each console interaction for debugging and rate limiting
|
|
103
|
-
# No value or zero means wait indefinitely (debug driven)
|
|
42
|
+
You are ${agent.username} a ${agent.title} with the job of building a website.
|
|
43
|
+
tokenMax: 50000
|
|
104
44
|
debugPauseSeconds: 5
|
|
105
|
-
|
|
106
|
-
# If true, regardless of the debugPauseSeconds, the agent will wake up on messages
|
|
107
|
-
# Useful for agents with long debugPauseSeconds, so that they can wake up and reply quickly
|
|
108
|
-
wakeOnMessage: false
|
|
109
|
-
|
|
110
|
-
# The maximum amount to spend on LLM interactions
|
|
111
|
-
# Once reached the agent will stop and this value will need to be increased to continue
|
|
112
|
-
spendLimitDollars: 2.00
|
|
113
|
-
|
|
114
|
-
# Command Protection: Useful for agents you want to restrict from modifying the system
|
|
115
|
-
# None: Commands from the LLM run automatically, this is the default setting as well if the value is not set
|
|
116
|
-
# Manual: Every command the LLM wants to run has to be approved [y/n]. Not very autonomous.
|
|
117
|
-
# Auto: All commands are run through the separate LLM instace that will check to see if the command is safe
|
|
118
|
-
commandProtection: "none"
|
|
119
|
-
|
|
120
|
-
# The max number of subagents allowed to be started and managed. Leave out to disable.
|
|
121
|
-
# Costs by the subagent are applied to the host agent's spend limit
|
|
122
|
-
# Careful: Sub-agents can be chatty, slowing down progress.
|
|
123
|
-
subagentMax: 0
|
|
124
|
-
|
|
125
|
-
# Run these commands on session start, in the example below the agent will see how to use mail and a list of other agents
|
|
126
|
-
initialCommands:
|
|
127
|
-
- llmail users
|
|
128
|
-
- llmail help
|
|
129
|
-
- cat ${env.NAISYS_FOLDER}/home/${agent.username}/PLAN.md
|
|
130
|
-
# Additional custom variables can be defined here and/or in the agent config to be loaded into the agent prompt
|
|
45
|
+
spendLimitDollars: 5.00
|
|
131
46
|
```
|
|
132
47
|
|
|
133
|
-
- Run `naisys <path to yaml or directory
|
|
134
|
-
-
|
|
135
|
-
- If a directory is passed, naisys will start a tmux session with the screen split for each agent
|
|
136
|
-
|
|
137
|
-
#### Creating a persistent agent run website (on Digital Ocean for example)
|
|
138
|
-
|
|
139
|
-
- Create new VM using the [LAMP stack droplet template](https://marketplace.digitalocean.com/apps/lamp)
|
|
140
|
-
- Login to the droplet using the web console
|
|
141
|
-
- Run `apt install npm`
|
|
142
|
-
- Install `nvm` using the `curl` url from these [instructions](https://github.com/nvm-sh/nvm?tab=readme-ov-file#installing-and-updating)
|
|
143
|
-
- Run `nvm install/use 20` to set node version to 20
|
|
144
|
-
- Follow the general install instructions above
|
|
48
|
+
- Run `naisys <path to agent yaml or directory> [options]`
|
|
49
|
+
- Pass a directory to run all agent yamls in that folder
|
|
145
50
|
|
|
146
51
|
## Using NAISYS
|
|
147
52
|
|
|
@@ -154,7 +59,6 @@ initialCommands:
|
|
|
154
59
|
- Pause on the debug prompt for that many seconds
|
|
155
60
|
- Pause indefinitely
|
|
156
61
|
- Pause until a new message is received from another agent
|
|
157
|
-
- Agents logs are written as html to `{WEBSITE_FOLDER or NAISYS_FOLDER}/logs`
|
|
158
62
|
|
|
159
63
|
#### Console Colors Legend
|
|
160
64
|
|
|
@@ -167,62 +71,38 @@ initialCommands:
|
|
|
167
71
|
|
|
168
72
|
- NAISYS tries to be light, acting as a helpful proxy between the LLM and a real shell, most commands should pass right though to the shell
|
|
169
73
|
- Debug Commands
|
|
170
|
-
- `cost` - Prints the current total LLM cost
|
|
171
|
-
- `context` - Prints the current context
|
|
172
|
-
- `
|
|
173
|
-
- `
|
|
74
|
+
- `ns-cost` - Prints the current total LLM cost
|
|
75
|
+
- `ns-context` - Prints the current context
|
|
76
|
+
- `ns-talk` - Communicate with the local agent to give hints or ask questions (the agent itself does not know about talk and is directed to use `ns-comment` or `ns-mail` for communication)
|
|
77
|
+
- `exit` - Exits NAISYS in debug mode. If the LLM tries to use `exit`, it is directed to use `ns-session compact/complete` instead
|
|
174
78
|
- Special Commands usable by the LLM as well as by the debug prompt
|
|
175
|
-
- `comment "<note>"` - The LLM is directed to use this for 'thinking out loud' which avoids 'invalid command' errors
|
|
176
|
-
- `
|
|
177
|
-
-
|
|
178
|
-
|
|
79
|
+
- `ns-comment "<note>"` - The LLM is directed to use this for 'thinking out loud' which avoids 'invalid command' errors
|
|
80
|
+
- `ns-session` - Session management commands:
|
|
81
|
+
- `ns-session wait <seconds>` - Pause execution for a set number of seconds
|
|
82
|
+
- `ns-session trim <indexes>` - Remove prompts by index to save tokens (e.g., "1-5, 8")
|
|
83
|
+
- `ns-session compact` - Compact the context and restart the session with that
|
|
84
|
+
- `ns-session complete "<result>"` - Mark task as complete and exit (for sub-agents: notifies lead agent)
|
|
179
85
|
- NAISYS apps
|
|
180
|
-
- `
|
|
181
|
-
- `
|
|
182
|
-
- `genimg "<description>" <filepath>` - Generates an image with the given description, save at the specified fully qualified path
|
|
183
|
-
- `
|
|
184
|
-
|
|
185
|
-
## Running NAISYS from Source
|
|
186
|
-
|
|
187
|
-
#### Getting started locally
|
|
188
|
-
|
|
189
|
-
- Install Node.js, NAISYS has been tested with version 20
|
|
190
|
-
- Clone the NAISYS repository from Github
|
|
191
|
-
- Run `npm install` to install dependencies
|
|
192
|
-
- Create a `.env` from the example above
|
|
193
|
-
- Run `npm run compile`
|
|
194
|
-
- Configure your agent using the examples in the `./agents` folder
|
|
195
|
-
- Run `node dist/naisys.js <path to agent yaml file>`
|
|
196
|
-
|
|
197
|
-
#### Notes for Windows users
|
|
198
|
-
|
|
199
|
-
- To use NAISYS on Windows you need to run it locally from source (or from within WSL)
|
|
200
|
-
- Use the above instructions to install locally, and then continue with the instructions below
|
|
201
|
-
- Install WSL (Windows Subsystem for Linux)
|
|
202
|
-
- Install a Linux distribution, Ubuntu can easily be installed from the Microsoft Store
|
|
203
|
-
- Make sure to the checked out code perserves the original line endings
|
|
204
|
-
- Files in the /bin folder should have LF endings only, not CRLF
|
|
205
|
-
- The `NAISYS_FOLDER` and `WEBSITE_FOLDER` should be set to the WSL path
|
|
206
|
-
- So `C:\var\naisys` should be `/mnt/c/var/naisys` in the `.env` file
|
|
207
|
-
|
|
208
|
-
#### Notes for MacOS users
|
|
209
|
-
|
|
210
|
-
- The browser llmynx requires `timeout` and `lynx`. Run these commands to install them:
|
|
211
|
-
- `brew install coreutils`
|
|
212
|
-
- `brew install lynx`
|
|
213
|
-
|
|
214
|
-
#### Using NAISYS for a website
|
|
215
|
-
|
|
216
|
-
- Many frameworks come with their own dev server
|
|
217
|
-
- PHP for example can start a server with `php -S localhost:8000 -d display_errors=On -d error_reporting=E_ALL`
|
|
218
|
-
- Start the server and put the URL in the `.env` file
|
|
86
|
+
- `ns-mail` - A context friendly 'mail system' used for agent to agent communication
|
|
87
|
+
- `ns-lynx` - A context friendly wrapping on the lynx browser that can use a separate LLM to reduce the size of a large webpage into something that can fit into the LLM's context
|
|
88
|
+
- `ns-genimg "<description>" <filepath>` - Generates an image with the given description, save at the specified fully qualified path
|
|
89
|
+
- `ns-agent` - A way for LLMs to start/stop their own sub-agents. Communicating with each other with `ns-mail`.
|
|
219
90
|
|
|
220
91
|
## Changelog
|
|
221
92
|
|
|
93
|
+
- 3.0: ERP and Desktop Control
|
|
94
|
+
- 2.2: NAISYS cross machine support enabled by a new hub process
|
|
95
|
+
- 2.1: Monorepo architecture, allowing Supervisor to run in-process
|
|
96
|
+
- 2.0: Agent multiplexing in the same process
|
|
97
|
+
- 1.7: Prompt caching, ns-lynx pagination, complete task command
|
|
222
98
|
- 1.6: Support for long running shell commands and full screen terminal output
|
|
223
99
|
- 1.5: Allow agents to start their own parallel `subagents`
|
|
224
|
-
- 1.4: `genimg` command for generating images
|
|
225
|
-
- 1.3: Post-session
|
|
100
|
+
- 1.4: `ns-genimg` command for generating images
|
|
101
|
+
- 1.3: Post-session session compaction as well as a mail 'blackout' period
|
|
226
102
|
- 1.2: Created stand-in shell commands for custom Naisys commands
|
|
227
103
|
- 1.1: Added command protection settings to prevent unwanted writes
|
|
228
104
|
- 1.0: Initial release
|
|
105
|
+
|
|
106
|
+
## License
|
|
107
|
+
|
|
108
|
+
MIT
|
package/bin/.gitattributes
CHANGED
|
File without changes
|
package/bin/naisys
CHANGED
|
@@ -10,62 +10,17 @@ SCRIPT_DIR=$(dirname "$SCRIPT")/..
|
|
|
10
10
|
if [ $# -eq 0 ]; then
|
|
11
11
|
# get version from package.json
|
|
12
12
|
VERSION=$(node -e "console.log(require('${SCRIPT_DIR}/package.json').version)")
|
|
13
|
-
echo "NAISYS:
|
|
13
|
+
echo "NAISYS: Networked Agents Interface System"
|
|
14
14
|
echo " Version: $VERSION"
|
|
15
|
-
echo " Usage: naisys <path to agent
|
|
16
|
-
echo "
|
|
15
|
+
echo " Usage: naisys <path to agent yaml or directory> [options]"
|
|
16
|
+
echo " Options:"
|
|
17
|
+
echo " --integrated-hub Start Hub in the same process"
|
|
18
|
+
echo " --supervisor Start Supervisor web UI (requires --integrated-hub)"
|
|
19
|
+
echo " --erp Start ERP web app (requires --supervisor)"
|
|
20
|
+
echo " --hub <url> Connect to a remote Hub server"
|
|
21
|
+
echo ""
|
|
22
|
+
echo " Pass a directory to run all agent yamls in that folder."
|
|
17
23
|
exit 1
|
|
18
24
|
fi
|
|
19
25
|
|
|
20
|
-
|
|
21
|
-
if [ -f "$1" ]; then
|
|
22
|
-
if [[ "$1" == *".yaml" ]]; then
|
|
23
|
-
echo "Starting single agent..."
|
|
24
|
-
node $SCRIPT_DIR/dist/naisys.js "$1"
|
|
25
|
-
exit 0
|
|
26
|
-
else
|
|
27
|
-
echo "Invalid file type. Please provide a .yaml file."
|
|
28
|
-
exit 1
|
|
29
|
-
fi
|
|
30
|
-
fi
|
|
31
|
-
|
|
32
|
-
# TODO: In the future should implement a max agents per window in the session
|
|
33
|
-
# Will require an outer loop to create new windows
|
|
34
|
-
# How many agents per window
|
|
35
|
-
# AGENTS_PER_WINDOW=4
|
|
36
|
-
|
|
37
|
-
# Directory containing agent files
|
|
38
|
-
AGENT_DIR="$1"
|
|
39
|
-
TEAM_NAME=$(basename "$AGENT_DIR")
|
|
40
|
-
|
|
41
|
-
# Start a new tmux session detached
|
|
42
|
-
tmux new-session -d -s $TEAM_NAME
|
|
43
|
-
|
|
44
|
-
# Get a list of agent paths
|
|
45
|
-
AGENT_FILES=($(find $AGENT_DIR -type f)) # This will list all files in the directory
|
|
46
|
-
|
|
47
|
-
# Split the window into panes and start agents
|
|
48
|
-
for ((i = 0; i < ${#AGENT_FILES[@]}; i++)); do
|
|
49
|
-
echo "Starting agent $((i + 1)) of ${#AGENT_FILES[@]}..."
|
|
50
|
-
sleep $((i == 0 ? 3 : 1)) # Sleep longer for the first agent
|
|
51
|
-
|
|
52
|
-
# For the first agent, no split is needed
|
|
53
|
-
if [ $i -eq 0 ]; then
|
|
54
|
-
tmux send-keys -t $TEAM_NAME:0.0 "node $SCRIPT_DIR/dist/naisys.js '${AGENT_FILES[i]}'" C-m # Quote the path
|
|
55
|
-
else
|
|
56
|
-
# Determine pane split direction based on odd/even pane index
|
|
57
|
-
if [ $((i % 2)) -eq 0 ]; then
|
|
58
|
-
tmux split-window -v -t $TEAM_NAME:0
|
|
59
|
-
else
|
|
60
|
-
tmux split-window -h -t $TEAM_NAME:0
|
|
61
|
-
fi
|
|
62
|
-
tmux send-keys "node $SCRIPT_DIR/dist/naisys.js '${AGENT_FILES[i]}'" C-m # Quote the path
|
|
63
|
-
tmux last-pane # Move focus back to the last pane to ensure correct targeting in the next iteration
|
|
64
|
-
fi
|
|
65
|
-
done
|
|
66
|
-
|
|
67
|
-
# Optionally, you can balance the panes if you want
|
|
68
|
-
tmux select-layout -t $TEAM_NAME tiled
|
|
69
|
-
|
|
70
|
-
# Attach to the session
|
|
71
|
-
tmux attach-session -t $TEAM_NAME
|
|
26
|
+
node $SCRIPT_DIR/dist/naisys.js "$@"
|
package/bin/ns-genimg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Write-Host "'ns-genimg' cannot be used with other commands on the same prompt."
|
package/bin/ns-lynx
ADDED
package/bin/ns-lynx.ps1
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Write-Host "'ns-lynx' cannot be used with other commands on the same prompt."
|
package/bin/ns-mail
ADDED
package/bin/ns-mail.ps1
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Write-Host "'ns-mail' cannot be used with other commands on the same prompt."
|
package/bin/ns-session
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Write-Host "'ns-session' cannot be used with other commands on the same prompt."
|
package/bin/pg-query
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# pg-query: A script to run SQL queries against a remote PostgreSQL database
|
|
4
|
+
# with smart display limits to prevent blowing out the context
|
|
5
|
+
|
|
6
|
+
# Unlike the other files in this directory, this must be moved to your ~/.local/bin directory
|
|
7
|
+
# and made executable with `chmod +x' to use. Also the agent needs to be made aware it exists.
|
|
8
|
+
|
|
9
|
+
# Config
|
|
10
|
+
HOST=""
|
|
11
|
+
PORT=""
|
|
12
|
+
USER=""
|
|
13
|
+
PASSWORD=""
|
|
14
|
+
DATABASE=""
|
|
15
|
+
|
|
16
|
+
# Default display limit
|
|
17
|
+
DEFAULT_LIMIT=20
|
|
18
|
+
|
|
19
|
+
smart-query() {
|
|
20
|
+
local query="$1"
|
|
21
|
+
local display_limit=${2:-$DEFAULT_LIMIT}
|
|
22
|
+
local check_limit=$((display_limit + 1)) # Get one extra row to detect truncation
|
|
23
|
+
|
|
24
|
+
if [[ $query =~ ^[[:space:]]*SELECT|^[[:space:]]*select ]]; then
|
|
25
|
+
# Always enforce our display limit, even if query has existing LIMIT
|
|
26
|
+
local temp_file=$(mktemp)
|
|
27
|
+
|
|
28
|
+
# Check if query already has LIMIT clause
|
|
29
|
+
if [[ $query =~ LIMIT|limit ]]; then
|
|
30
|
+
echo "Query has existing LIMIT - enforcing display limit of $display_limit rows"
|
|
31
|
+
else
|
|
32
|
+
echo "Checking for truncation (display limit: $display_limit rows)..."
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
# Add our LIMIT to get one more than we want to display (overrides any existing LIMIT)
|
|
36
|
+
local check_query="SELECT * FROM ($query) AS subquery LIMIT $check_limit"
|
|
37
|
+
|
|
38
|
+
PAGER="" PGPASSWORD="$PASSWORD" psql -h "$HOST" -p "$PORT" -U "$USER" -d "$DATABASE" --pset=pager=off -A -c "$check_query" > "$temp_file"
|
|
39
|
+
|
|
40
|
+
local total_lines=$(wc -l < "$temp_file")
|
|
41
|
+
local data_lines=$((total_lines - 2)) # Subtract psql headers (usually 2 lines)
|
|
42
|
+
|
|
43
|
+
if [ "$data_lines" -eq "$check_limit" ]; then
|
|
44
|
+
echo "⚠️ Results truncated: showing first $display_limit rows (more data available)"
|
|
45
|
+
echo "---"
|
|
46
|
+
head -$((display_limit + 2)) "$temp_file" # +2 for headers
|
|
47
|
+
echo "---"
|
|
48
|
+
echo "Note: Additional rows exist beyond what is displayed above, page the query to see more, or query more strategically."
|
|
49
|
+
else
|
|
50
|
+
echo "✓ Complete result: all $data_lines rows shown"
|
|
51
|
+
echo "---"
|
|
52
|
+
cat "$temp_file"
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
rm "$temp_file"
|
|
56
|
+
else
|
|
57
|
+
# Non-SELECT query (INSERT, UPDATE, DELETE, etc.)
|
|
58
|
+
echo "✓ Executing non-SELECT query"
|
|
59
|
+
PAGER="" PGPASSWORD="$PASSWORD" psql -h "$HOST" -p "$PORT" -U "$USER" -d "$DATABASE" --pset=pager=off -A -c "$query"
|
|
60
|
+
fi
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
# Main function - can be called as remote-pg
|
|
64
|
+
remote-pg() {
|
|
65
|
+
local query="$1"
|
|
66
|
+
local limit="$2"
|
|
67
|
+
|
|
68
|
+
if [ -z "$query" ]; then
|
|
69
|
+
echo "Usage: $(basename "$0") \"SQL_QUERY\" [DISPLAY_LIMIT]"
|
|
70
|
+
echo "Example: $(basename "$0") \"SELECT * FROM users\" 50"
|
|
71
|
+
echo "Default limit: $DEFAULT_LIMIT rows"
|
|
72
|
+
exit 1
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
smart-query "$query" "$limit"
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
# Execute the function with command line arguments
|
|
79
|
+
remote-pg "$@"
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { sanitizeSpendLimit } from "@naisys/common";
|
|
2
|
+
import table from "text-table";
|
|
3
|
+
import { agentConfigCmd } from "../command/commandDefs.js";
|
|
4
|
+
import { valueFromString } from "../utils/utilities.js";
|
|
5
|
+
export function createAgentConfig(localUserId, { globalConfig }, userService) {
|
|
6
|
+
let fullAgentConfig = loadConfig();
|
|
7
|
+
function loadConfig() {
|
|
8
|
+
const user = userService.getUserById(localUserId);
|
|
9
|
+
if (!user) {
|
|
10
|
+
throw new Error(`User with ID ${localUserId} not found`);
|
|
11
|
+
}
|
|
12
|
+
return buildFullAgentConfig(user.config);
|
|
13
|
+
}
|
|
14
|
+
function buildFullAgentConfig(config) {
|
|
15
|
+
// Sanitize spend limits
|
|
16
|
+
const spendLimitDollars = sanitizeSpendLimit(config.spendLimitDollars);
|
|
17
|
+
const spendLimitHours = sanitizeSpendLimit(config.spendLimitHours);
|
|
18
|
+
// Validate if spend limit is defined on the agent or .env
|
|
19
|
+
if (spendLimitDollars === undefined &&
|
|
20
|
+
globalConfig().spendLimitDollars === undefined) {
|
|
21
|
+
throw `Agent config: Error, 'spendLimitDollars' needs to be defined in the .env file or agent config`;
|
|
22
|
+
}
|
|
23
|
+
// Resolve model configs
|
|
24
|
+
const shellModel = resolveConfigVars(config.shellModel);
|
|
25
|
+
const imageModel = config.imageModel
|
|
26
|
+
? resolveConfigVars(config.imageModel)
|
|
27
|
+
: undefined;
|
|
28
|
+
function resolveConfigVars(templateString) {
|
|
29
|
+
let resolvedString = templateString;
|
|
30
|
+
resolvedString = resolveTemplateVars(resolvedString, "agent", config);
|
|
31
|
+
resolvedString = resolveTemplateVars(resolvedString, "env", globalConfig().variableMap);
|
|
32
|
+
return resolvedString;
|
|
33
|
+
}
|
|
34
|
+
function resolveTemplateVars(templateString, allowedVarString, mappedVar) {
|
|
35
|
+
const pattern = new RegExp(`\\$\\{${allowedVarString}\\.([^}]+)\\}`, "g");
|
|
36
|
+
return templateString.replace(pattern, (_match, key) => {
|
|
37
|
+
const value = valueFromString(mappedVar, key);
|
|
38
|
+
if (value === undefined) {
|
|
39
|
+
throw `Agent config: Error, ${key} is not defined`;
|
|
40
|
+
}
|
|
41
|
+
return value;
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
...config,
|
|
46
|
+
spendLimitDollars,
|
|
47
|
+
spendLimitHours,
|
|
48
|
+
shellModel,
|
|
49
|
+
imageModel,
|
|
50
|
+
resolveConfigVars,
|
|
51
|
+
mailEnabled: !!config.mailEnabled,
|
|
52
|
+
chatEnabled: !!config.chatEnabled,
|
|
53
|
+
webEnabled: !!config.webEnabled,
|
|
54
|
+
completeSessionEnabled: !!config.completeSessionEnabled,
|
|
55
|
+
wakeOnMessage: !!config.wakeOnMessage,
|
|
56
|
+
initialCommands: config.initialCommands ?? [],
|
|
57
|
+
commandProtection: config.commandProtection ?? "none",
|
|
58
|
+
debugPauseSeconds: config.debugPauseSeconds === undefined ? 0 : config.debugPauseSeconds,
|
|
59
|
+
multipleCommandsEnabled: !!config.multipleCommandsEnabled,
|
|
60
|
+
workspacesEnabled: !!config.workspacesEnabled,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function updateConfigField(field, value) {
|
|
64
|
+
const user = userService.getUserById(localUserId);
|
|
65
|
+
if (!user) {
|
|
66
|
+
throw new Error(`User with ID ${localUserId} not found`);
|
|
67
|
+
}
|
|
68
|
+
// Convert value to appropriate type
|
|
69
|
+
let typedValue = value;
|
|
70
|
+
if (value === "true")
|
|
71
|
+
typedValue = true;
|
|
72
|
+
else if (value === "false")
|
|
73
|
+
typedValue = false;
|
|
74
|
+
else if (!isNaN(Number(value)) && value.trim() !== "")
|
|
75
|
+
typedValue = Number(value);
|
|
76
|
+
if (!(field in user.config)) {
|
|
77
|
+
throw new Error(`Config field '${field}' does not exist`);
|
|
78
|
+
}
|
|
79
|
+
// set field
|
|
80
|
+
user.config[field] = typedValue;
|
|
81
|
+
// Update in-memory only (not persisted)
|
|
82
|
+
fullAgentConfig = buildFullAgentConfig(user.config);
|
|
83
|
+
}
|
|
84
|
+
function handleCommand(cmdArgs) {
|
|
85
|
+
const args = cmdArgs.trim().split(/\s+/).filter(Boolean);
|
|
86
|
+
const config = fullAgentConfig;
|
|
87
|
+
if (args.length === 0) {
|
|
88
|
+
// Show all config values as a table
|
|
89
|
+
const rows = Object.entries(config)
|
|
90
|
+
.filter(([, value]) => typeof value !== "function")
|
|
91
|
+
.map(([key, value]) => {
|
|
92
|
+
const displayValue = typeof value === "object" ? JSON.stringify(value) : String(value);
|
|
93
|
+
return [key, displayValue];
|
|
94
|
+
});
|
|
95
|
+
return table([["Name", "Value"], ...rows], { hsep: " | " });
|
|
96
|
+
}
|
|
97
|
+
else if (args.length === 1) {
|
|
98
|
+
// Show specific config value
|
|
99
|
+
const name = args[0];
|
|
100
|
+
const value = config[name];
|
|
101
|
+
if (value === undefined) {
|
|
102
|
+
return `Config field '${name}' not found`;
|
|
103
|
+
}
|
|
104
|
+
if (typeof value === "function") {
|
|
105
|
+
return `Config field '${name}' is a function and cannot be displayed`;
|
|
106
|
+
}
|
|
107
|
+
return typeof value === "object"
|
|
108
|
+
? JSON.stringify(value, null, 2)
|
|
109
|
+
: String(value);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
// Update config value (session-only, not persisted)
|
|
113
|
+
const name = args[0];
|
|
114
|
+
const value = args.slice(1).join(" ");
|
|
115
|
+
try {
|
|
116
|
+
updateConfigField(name, value);
|
|
117
|
+
return `Config field '${name}' updated to '${value}' (session only, not persisted)`;
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
return `Failed to update config: ${error instanceof Error ? error.message : String(error)}`;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
const registrableCommand = {
|
|
125
|
+
command: agentConfigCmd,
|
|
126
|
+
handleCommand,
|
|
127
|
+
};
|
|
128
|
+
return {
|
|
129
|
+
...registrableCommand,
|
|
130
|
+
agentConfig: () => fullAgentConfig,
|
|
131
|
+
reloadAgentConfig: () => {
|
|
132
|
+
fullAgentConfig = loadConfig();
|
|
133
|
+
},
|
|
134
|
+
updateConfigField,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=agentConfig.js.map
|