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.

Files changed (104) hide show
  1. package/README.md +41 -161
  2. package/bin/.gitattributes +0 -0
  3. package/bin/naisys +10 -55
  4. package/bin/ns-comment.ps1 +2 -0
  5. package/bin/ns-genimg +3 -0
  6. package/bin/ns-genimg.ps1 +1 -0
  7. package/bin/ns-lynx +3 -0
  8. package/bin/ns-lynx.ps1 +1 -0
  9. package/bin/ns-mail +3 -0
  10. package/bin/ns-mail.ps1 +1 -0
  11. package/bin/ns-session +3 -0
  12. package/bin/ns-session.ps1 +1 -0
  13. package/bin/pg-query +79 -0
  14. package/dist/agent/agentConfig.js +137 -0
  15. package/dist/agent/agentManager.js +180 -0
  16. package/dist/agent/agentManagerInterface.js +2 -0
  17. package/dist/agent/agentRuntime.js +127 -0
  18. package/dist/agent/userDisplayService.js +193 -0
  19. package/dist/agent/userService.js +193 -0
  20. package/dist/command/commandDefs.js +225 -0
  21. package/dist/command/commandHandler.js +192 -220
  22. package/dist/command/commandLoop.js +384 -223
  23. package/dist/command/commandProtection.js +67 -41
  24. package/dist/command/commandRegistry.js +60 -0
  25. package/dist/command/debugCommand.js +100 -0
  26. package/dist/command/promptBuilder.js +120 -137
  27. package/dist/command/shellCommand.js +59 -51
  28. package/dist/command/shellWrapper.js +480 -303
  29. package/dist/computer-use/anthropic-computer-use.js +58 -0
  30. package/dist/computer-use/computerService.js +331 -0
  31. package/dist/computer-use/desktop.js +145 -0
  32. package/dist/computer-use/google-computer-use.js +343 -0
  33. package/dist/computer-use/macosDesktop.js +230 -0
  34. package/dist/computer-use/openai-computer-use.js +256 -0
  35. package/dist/computer-use/waylandDesktop.js +163 -0
  36. package/dist/computer-use/windowsDesktop.js +238 -0
  37. package/dist/computer-use/x11Desktop.js +80 -0
  38. package/dist/features/genImg.js +83 -0
  39. package/dist/features/listen.js +89 -0
  40. package/dist/features/look.js +131 -0
  41. package/dist/features/lynx.js +368 -0
  42. package/dist/features/session.js +165 -0
  43. package/dist/features/subagent.js +347 -217
  44. package/dist/features/workspaces.js +100 -40
  45. package/dist/globalConfig.js +92 -0
  46. package/dist/hub/hubClient.js +140 -0
  47. package/dist/hub/hubClientConfig.js +13 -0
  48. package/dist/hub/hubClientLog.js +34 -0
  49. package/dist/hub/hubConnection.js +109 -0
  50. package/dist/hub/hubCostBuffer.js +75 -0
  51. package/dist/hub/hubLogBuffer.js +49 -0
  52. package/dist/llm/commandTool.js +252 -0
  53. package/dist/llm/contextManager.js +316 -134
  54. package/dist/llm/costDisplayService.js +168 -0
  55. package/dist/llm/costTracker.js +198 -62
  56. package/dist/llm/llmDtos.js +11 -7
  57. package/dist/llm/llmService.js +70 -177
  58. package/dist/llm/systemMessage.js +94 -61
  59. package/dist/llm/vendors/anthropic.js +197 -0
  60. package/dist/llm/vendors/google.js +161 -0
  61. package/dist/llm/vendors/mock.js +28 -0
  62. package/dist/llm/vendors/openai-compatible.js +100 -0
  63. package/dist/llm/vendors/openai-standard.js +131 -0
  64. package/dist/llm/vendors/vendorTypes.js +2 -0
  65. package/dist/mail/chat.js +298 -0
  66. package/dist/mail/mail.js +273 -0
  67. package/dist/mail/mailDisplayService.js +92 -0
  68. package/dist/naisys.js +80 -5
  69. package/dist/services/attachmentService.js +80 -0
  70. package/dist/services/heartbeatService.js +27 -0
  71. package/dist/services/hostService.js +68 -0
  72. package/dist/services/logService.js +36 -0
  73. package/dist/services/modelService.js +65 -0
  74. package/dist/services/pathService.js +21 -0
  75. package/dist/services/runService.js +43 -0
  76. package/dist/services/shellPlatform.js +93 -0
  77. package/dist/utils/agentNames.js +0 -0
  78. package/dist/utils/confirmation.js +46 -0
  79. package/dist/utils/escKeyListener.js +39 -0
  80. package/dist/utils/inputMode.js +18 -9
  81. package/dist/utils/output.js +68 -27
  82. package/dist/utils/promptNotificationService.js +74 -0
  83. package/dist/utils/sharedReadline.js +24 -0
  84. package/dist/utils/utilities.js +0 -0
  85. package/dist/utils/writeEventManager.js +43 -0
  86. package/package.json +56 -43
  87. package/LICENSE.md +0 -7
  88. package/bin/endsession +0 -3
  89. package/bin/genimg +0 -3
  90. package/bin/llmail +0 -3
  91. package/bin/llmynx +0 -3
  92. package/bin/pause +0 -3
  93. package/bin/trimsession +0 -3
  94. package/dist/config.js +0 -133
  95. package/dist/features/genimg.js +0 -102
  96. package/dist/features/llmail.js +0 -427
  97. package/dist/features/llmynx.js +0 -309
  98. package/dist/llm/dreamMaker.js +0 -79
  99. package/dist/llm/llModels.js +0 -119
  100. package/dist/utils/dbUtils.js +0 -39
  101. package/dist/utils/enums.js +0 -9
  102. package/dist/utils/logService.js +0 -98
  103. package/dist/utils/pathService.js +0 -66
  104. /package/bin/{comment → ns-comment} +0 -0
package/README.md CHANGED
@@ -1,25 +1,21 @@
1
- ## NAISYS (Node.js Autonomous Intelligence System)
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 colllaborate with the
6
- LLM, give it hints, and/or diagnose the session. Once the LLM reaches the token max you specified for the sesssion it
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 communiation. You can manually startup mulitple instances of NAISYS with different roles, or
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 'llmynx' that uses a separate LLM to reduce web page size as well as make links unique across the context
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
- - See notes for Windows users at the bottom of this file
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
- ```bash
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 creating a Neon Genesis Evangelion fan website.
91
- The website should be very simple html, able to be used from a text based browser like lynx. Pages should be relatively short.
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
- - If a yaml file is passed, naisys will start a single agent
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
- - `exit` - Exits NAISYS. If the LLM tries to use `exit`, it is directed to use `endsession` instead
173
- - `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 `comment` or `llmail` for communication)
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
- - `endsession "<note>"` - Clear the context and start a new session.
177
- - The LLM is directed to track it's context size and to end the session with a note before running over the context limit
178
- - `pause <seconds>` - Can be used by the debug agent or the LLM to pause execution for a set number of seconds
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
- - `llmail` - A context friendly 'mail system' used for agent to agent communication
181
- - `llmynx` - 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
182
- - `genimg "<description>" <filepath>` - Generates an image with the given description, save at the specified fully qualified path
183
- - `subagent` - A way for LLMs to start/stop their own sub-agents. Communicating with each other with `llmail`. Set the `subagentMax` in the agent config to enable.
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 'dreaming' as well as a mail 'blackout' period
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
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: Node.js Autonomous Intelligence System"
13
+ echo "NAISYS: Networked Agents Interface System"
14
14
  echo " Version: $VERSION"
15
- echo " Usage: naisys <path to agent config yaml, or directory>"
16
- echo " Note: If a folder is passed then all agents will be started in a tmux session"
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
- # if path is a yaml file then start a single agent
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 "$@"
@@ -0,0 +1,2 @@
1
+ # ./src/command/commandHandler.ts has the same message
2
+ Write-Host "Comment noted. Try running commands now to achieve your goal. ."
package/bin/ns-genimg ADDED
@@ -0,0 +1,3 @@
1
+ #!/bin/bash
2
+
3
+ echo "'ns-genimg' cannot be used with other commands on the same prompt."
@@ -0,0 +1 @@
1
+ Write-Host "'ns-genimg' cannot be used with other commands on the same prompt."
package/bin/ns-lynx ADDED
@@ -0,0 +1,3 @@
1
+ #!/bin/bash
2
+
3
+ echo "'ns-lynx' cannot be used with other commands on the same prompt."
@@ -0,0 +1 @@
1
+ Write-Host "'ns-lynx' cannot be used with other commands on the same prompt."
package/bin/ns-mail ADDED
@@ -0,0 +1,3 @@
1
+ #!/bin/bash
2
+
3
+ echo "'ns-mail' cannot be used with other commands on the same prompt."
@@ -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,3 @@
1
+ #!/bin/bash
2
+
3
+ echo "'ns-session' cannot be used with other commands on the same prompt."
@@ -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