@naisys/common 3.0.0-beta.4 → 3.0.0-beta.5

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.
@@ -1,92 +1,119 @@
1
1
  import { z } from "zod";
2
2
  import { TARGET_MEGAPIXELS } from "./constants.js";
3
3
  import { URL_SAFE_KEY_MESSAGE, URL_SAFE_KEY_REGEX } from "./urlSafeKey.js";
4
- export const commandProtectionValues = [
5
- "none",
6
- "manual",
7
- "semi-auto",
8
- "auto",
9
- ];
4
+ export const commandProtectionValues = ["none", "manual", "semi-auto", "auto"];
10
5
  // Zod schema for validation
11
6
  export const AgentConfigFileSchema = z.object({
12
- username: z
13
- .string()
14
- .min(1, "Username is required")
15
- .regex(URL_SAFE_KEY_REGEX, URL_SAFE_KEY_MESSAGE)
16
- .describe("The name the agent identifies itself with when communicating with other agents"),
17
- title: z
18
- .string()
19
- .describe("Displayed to other agents to give context about this agent's role in the system"),
20
- agentPrompt: z
21
- .string()
22
- .min(1, "Agent prompt is required")
23
- .describe("Gives the agent instructions and/or purpose when starting up. Supports ${agent.*} and ${env.*} template variables"),
24
- spendLimitDollars: z
25
- .number()
26
- .min(0, "Must be non-negative")
27
- .optional()
28
- .describe("Spend limit in dollars for this agent. When set, this agent is exempt from the global spend limit. Defaults to the SPEND_LIMIT_DOLLARS variable"),
29
- spendLimitHours: z
30
- .number()
31
- .min(0, "Must be non-negative")
32
- .optional()
33
- .describe("Rolling time window in hours for spend limit, defaults to the SPEND_LIMIT_HOURS variable. If neither are set then the spend limit is fixed and not rolling"),
34
- tokenMax: z
35
- .number()
36
- .int("Must be a whole number")
37
- .min(1, "Must be at least 1")
38
- .describe("How many tokens this agent is allocated per session before it must end or compact the context"),
39
- shellModel: z
40
- .string()
41
- .min(1, "Shell model is required")
42
- .describe("Primary LLM used for shell interactions"),
43
- imageModel: z.string().optional().describe("Model used for image generation"),
44
- mailEnabled: z
45
- .boolean()
46
- .optional()
47
- .describe("Show mail commands to the agent. Mail encourages verbose communication which can be distracting"),
48
- chatEnabled: z
49
- .boolean()
50
- .optional()
51
- .describe("Show chat commands to the agent. Chat encourages more concise communication"),
52
- webEnabled: z
53
- .boolean()
54
- .optional()
55
- .describe("Allow agent to browse the web with Lynx, a text based browser"),
56
- completeSessionEnabled: z
57
- .boolean()
58
- .optional()
59
- .describe("Allow the agent to end its session. Once ended, it can only be restarted explicitly or via mail if wakeOnMessage is enabled. Disable on root agents to prevent the system from going unresponsive"),
60
- debugPauseSeconds: z
61
- .number()
62
- .int("Must be a whole number")
63
- .min(0, "Must be non-negative")
64
- .optional()
65
- .describe("Seconds to wait at the debug prompt before auto-continuing, only applies when the agent's console is in focus. Unset waits indefinitely for manual input"),
66
- wakeOnMessage: z
67
- .boolean()
68
- .optional()
69
- .describe("When mail or chat is received, start the agent automatically, or wake it from its wait state"),
70
- commandProtection: z
71
- .enum(commandProtectionValues)
72
- .optional()
73
- .describe("None allows the LLM to run any command, Manual requires user confirmation for each command, and Auto uses a secondary LLM to try to validate a command is safe"),
74
- initialCommands: z
75
- .array(z.string())
76
- .optional()
77
- .describe("Shell commands to run at session start before the first LLM prompt, providing additional context to the agent"),
78
- multipleCommandsEnabled: z
79
- .boolean()
80
- .optional()
81
- .describe("Allow the LLM to run multiple commands per turn. Faster but the LLM may get ahead of itself and produce errors"),
82
- workspacesEnabled: z
83
- .boolean()
84
- .optional()
85
- .describe("Experimental: Allows the LLM to pin files to the end of the context. Each turn the agent sees the latest version without old versions taking up context space"),
86
- controlDesktop: z
87
- .boolean()
88
- .optional()
89
- .describe(`Allow the agent to operate the desktop GUI. Requires a model with supportsComputerUse. Ideal screen resolution <= ${TARGET_MEGAPIXELS}MP to avoid downscaling`),
7
+ username: z
8
+ .string()
9
+ .min(1, "Username is required")
10
+ .regex(URL_SAFE_KEY_REGEX, URL_SAFE_KEY_MESSAGE)
11
+ .describe(
12
+ "The name the agent identifies itself with when communicating with other agents",
13
+ ),
14
+ title: z
15
+ .string()
16
+ .describe(
17
+ "Displayed to other agents to give context about this agent's role in the system",
18
+ ),
19
+ agentPrompt: z
20
+ .string()
21
+ .min(1, "Agent prompt is required")
22
+ .describe(
23
+ "Gives the agent instructions and/or purpose when starting up. Supports ${agent.*} and ${env.*} template variables",
24
+ ),
25
+ spendLimitDollars: z
26
+ .number()
27
+ .min(0, "Must be non-negative")
28
+ .optional()
29
+ .describe(
30
+ "Spend limit in dollars for this agent. When set, this agent is exempt from the global spend limit. Defaults to the SPEND_LIMIT_DOLLARS variable",
31
+ ),
32
+ spendLimitHours: z
33
+ .number()
34
+ .min(0, "Must be non-negative")
35
+ .optional()
36
+ .describe(
37
+ "Rolling time window in hours for spend limit, defaults to the SPEND_LIMIT_HOURS variable. If neither are set then the spend limit is fixed and not rolling",
38
+ ),
39
+ tokenMax: z
40
+ .number()
41
+ .int("Must be a whole number")
42
+ .min(1, "Must be at least 1")
43
+ .describe(
44
+ "How many tokens this agent is allocated per session before it must end or compact the context",
45
+ ),
46
+ shellModel: z
47
+ .string()
48
+ .min(1, "Shell model is required")
49
+ .describe("Primary LLM used for shell interactions"),
50
+ imageModel: z.string().optional().describe("Model used for image generation"),
51
+ mailEnabled: z
52
+ .boolean()
53
+ .optional()
54
+ .describe(
55
+ "Show mail commands to the agent. Mail encourages verbose communication which can be distracting",
56
+ ),
57
+ chatEnabled: z
58
+ .boolean()
59
+ .optional()
60
+ .describe(
61
+ "Show chat commands to the agent. Chat encourages more concise communication",
62
+ ),
63
+ webEnabled: z
64
+ .boolean()
65
+ .optional()
66
+ .describe("Allow agent to browse the web with Lynx, a text based browser"),
67
+ completeSessionEnabled: z
68
+ .boolean()
69
+ .optional()
70
+ .describe(
71
+ "Allow the agent to end its session. Once ended, it can only be restarted explicitly or via mail if wakeOnMessage is enabled. Disable on root agents to prevent the system from going unresponsive",
72
+ ),
73
+ debugPauseSeconds: z
74
+ .number()
75
+ .int("Must be a whole number")
76
+ .min(0, "Must be non-negative")
77
+ .optional()
78
+ .describe(
79
+ "Seconds to wait at the debug prompt before auto-continuing, only applies when the agent's console is in focus. Unset waits indefinitely for manual input",
80
+ ),
81
+ wakeOnMessage: z
82
+ .boolean()
83
+ .optional()
84
+ .describe(
85
+ "When mail or chat is received, start the agent automatically, or wake it from its wait state",
86
+ ),
87
+ commandProtection: z
88
+ .enum(commandProtectionValues)
89
+ .optional()
90
+ .describe(
91
+ "None allows the LLM to run any command, Manual requires user confirmation for each command, and Auto uses a secondary LLM to try to validate a command is safe",
92
+ ),
93
+ initialCommands: z
94
+ .array(z.string())
95
+ .optional()
96
+ .describe(
97
+ "Shell commands to run at session start before the first LLM prompt, providing additional context to the agent",
98
+ ),
99
+ multipleCommandsEnabled: z
100
+ .boolean()
101
+ .optional()
102
+ .describe(
103
+ "Allow the LLM to run multiple commands per turn. Faster but the LLM may get ahead of itself and produce errors",
104
+ ),
105
+ workspacesEnabled: z
106
+ .boolean()
107
+ .optional()
108
+ .describe(
109
+ "Experimental: Allows the LLM to pin files to the end of the context. Each turn the agent sees the latest version without old versions taking up context space",
110
+ ),
111
+ controlDesktop: z
112
+ .boolean()
113
+ .optional()
114
+ .describe(
115
+ `Allow the agent to operate the desktop GUI. Requires a model with supportsComputerUse. Ideal screen resolution <= ${TARGET_MEGAPIXELS}MP to avoid downscaling`,
116
+ ),
90
117
  });
91
118
  /**
92
119
  * Thoughts on the admin user:
@@ -100,30 +127,31 @@ export const AgentConfigFileSchema = z.object({
100
127
  * 6. Having it as an official user means mail will be logged by the hub as well which is helpful for debugging and monitoring
101
128
  */
102
129
  export function buildDefaultAgentConfig(username) {
103
- return {
104
- username,
105
- title: "Assistant",
106
- shellModel: "none",
107
- agentPrompt: "You are ${agent.username} a ${agent.title} with the job of helping out the admin with what they want to do.",
108
- tokenMax: 20000,
109
- debugPauseSeconds: 5,
110
- mailEnabled: true,
111
- chatEnabled: true,
112
- webEnabled: true,
113
- wakeOnMessage: true,
114
- completeSessionEnabled: true,
115
- multipleCommandsEnabled: true,
116
- };
117
- }
118
- export const adminAgentConfig = {
119
- username: "admin", // Must be "admin" for special handling in hub and supervisor
120
- title: "Admin",
130
+ return {
131
+ username,
132
+ title: "Assistant",
121
133
  shellModel: "none",
122
- agentPrompt: "Human admin for monitoring and control.",
123
- tokenMax: 100_000,
134
+ agentPrompt:
135
+ "You are ${agent.username} a ${agent.title} with the job of helping out the admin with what they want to do.",
136
+ tokenMax: 20000,
137
+ debugPauseSeconds: 5,
124
138
  mailEnabled: true,
125
139
  chatEnabled: true,
126
- wakeOnMessage: true,
127
140
  webEnabled: true,
128
- spendLimitDollars: 1, // Required on all agents
141
+ wakeOnMessage: true,
142
+ completeSessionEnabled: true,
143
+ multipleCommandsEnabled: true,
144
+ };
145
+ }
146
+ export const adminAgentConfig = {
147
+ username: "admin", // Must be "admin" for special handling in hub and supervisor
148
+ title: "Admin",
149
+ shellModel: "none",
150
+ agentPrompt: "Human admin for monitoring and control.",
151
+ tokenMax: 100_000,
152
+ mailEnabled: true,
153
+ chatEnabled: true,
154
+ wakeOnMessage: true,
155
+ webEnabled: true,
156
+ spendLimitDollars: 1, // Required on all agents
129
157
  };
@@ -1,15 +1,11 @@
1
1
  export function determineAgentStatus(opts) {
2
- // Priority: disabled > offline > suspended > active > available
3
- if (!opts.isEnabled)
4
- return "disabled";
5
- const isOffline = opts.assignedHostIds?.length
6
- ? !opts.assignedHostIds.some(opts.isHostOnline)
7
- : !opts.hasNonRestrictedOnlineHost;
8
- if (isOffline)
9
- return "offline";
10
- if (opts.isSuspended)
11
- return "suspended";
12
- if (opts.isActive)
13
- return "active";
14
- return "available";
2
+ // Priority: disabled > offline > suspended > active > available
3
+ if (!opts.isEnabled) return "disabled";
4
+ const isOffline = opts.assignedHostIds?.length
5
+ ? !opts.assignedHostIds.some(opts.isHostOnline)
6
+ : !opts.hasNonRestrictedOnlineHost;
7
+ if (isOffline) return "offline";
8
+ if (opts.isSuspended) return "suspended";
9
+ if (opts.isActive) return "active";
10
+ return "available";
15
11
  }
package/dist/authCache.js CHANGED
@@ -1,41 +1,40 @@
1
1
  export class AuthCache {
2
- cache = new Map();
3
- ttlMs;
4
- negativeTtlMs;
5
- maxSize;
6
- constructor(options = {}) {
7
- this.ttlMs = options.ttlMs ?? 60_000;
8
- this.negativeTtlMs = options.negativeTtlMs ?? 10_000;
9
- this.maxSize = options.maxSize ?? 1_000;
2
+ cache = new Map();
3
+ ttlMs;
4
+ negativeTtlMs;
5
+ maxSize;
6
+ constructor(options = {}) {
7
+ this.ttlMs = options.ttlMs ?? 60_000;
8
+ this.negativeTtlMs = options.negativeTtlMs ?? 10_000;
9
+ this.maxSize = options.maxSize ?? 1_000;
10
+ }
11
+ /** Returns the cached user, `null` for a negative hit, or `undefined` on cache miss. */
12
+ get(key) {
13
+ const entry = this.cache.get(key);
14
+ if (!entry) return undefined;
15
+ if (Date.now() > entry.expiresAt) {
16
+ this.cache.delete(key);
17
+ return undefined;
10
18
  }
11
- /** Returns the cached user, `null` for a negative hit, or `undefined` on cache miss. */
12
- get(key) {
13
- const entry = this.cache.get(key);
14
- if (!entry)
15
- return undefined;
16
- if (Date.now() > entry.expiresAt) {
17
- this.cache.delete(key);
18
- return undefined;
19
- }
20
- return entry.user;
21
- }
22
- /** Cache a lookup result. Pass `null` to cache a negative (invalid token) result. */
23
- set(key, user) {
24
- if (this.cache.size >= this.maxSize) {
25
- const firstKey = this.cache.keys().next().value;
26
- this.cache.delete(firstKey);
27
- }
28
- this.cache.set(key, {
29
- user,
30
- expiresAt: Date.now() + (user ? this.ttlMs : this.negativeTtlMs),
31
- });
32
- }
33
- /** Remove a specific key from the cache (e.g. on logout). */
34
- invalidate(key) {
35
- this.cache.delete(key);
36
- }
37
- /** Clear the entire cache. */
38
- clear() {
39
- this.cache.clear();
19
+ return entry.user;
20
+ }
21
+ /** Cache a lookup result. Pass `null` to cache a negative (invalid token) result. */
22
+ set(key, user) {
23
+ if (this.cache.size >= this.maxSize) {
24
+ const firstKey = this.cache.keys().next().value;
25
+ this.cache.delete(firstKey);
40
26
  }
27
+ this.cache.set(key, {
28
+ user,
29
+ expiresAt: Date.now() + (user ? this.ttlMs : this.negativeTtlMs),
30
+ });
31
+ }
32
+ /** Remove a specific key from the cache (e.g. on logout). */
33
+ invalidate(key) {
34
+ this.cache.delete(key);
35
+ }
36
+ /** Clear the entire cache. */
37
+ clear() {
38
+ this.cache.clear();
39
+ }
41
40
  }