@usejarvis/brain 0.1.0

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.
Files changed (266) hide show
  1. package/LICENSE +153 -0
  2. package/README.md +278 -0
  3. package/bin/jarvis.ts +413 -0
  4. package/package.json +74 -0
  5. package/scripts/ensure-bun.cjs +8 -0
  6. package/src/actions/README.md +421 -0
  7. package/src/actions/app-control/desktop-controller.test.ts +26 -0
  8. package/src/actions/app-control/desktop-controller.ts +438 -0
  9. package/src/actions/app-control/interface.ts +64 -0
  10. package/src/actions/app-control/linux.ts +273 -0
  11. package/src/actions/app-control/macos.ts +54 -0
  12. package/src/actions/app-control/sidecar-launcher.test.ts +23 -0
  13. package/src/actions/app-control/sidecar-launcher.ts +286 -0
  14. package/src/actions/app-control/windows.ts +44 -0
  15. package/src/actions/browser/cdp.ts +138 -0
  16. package/src/actions/browser/chrome-launcher.ts +252 -0
  17. package/src/actions/browser/session.ts +437 -0
  18. package/src/actions/browser/stealth.ts +49 -0
  19. package/src/actions/index.ts +20 -0
  20. package/src/actions/terminal/executor.ts +157 -0
  21. package/src/actions/terminal/wsl-bridge.ts +126 -0
  22. package/src/actions/test.ts +93 -0
  23. package/src/actions/tools/agents.ts +321 -0
  24. package/src/actions/tools/builtin.ts +846 -0
  25. package/src/actions/tools/commitments.ts +192 -0
  26. package/src/actions/tools/content.ts +217 -0
  27. package/src/actions/tools/delegate.ts +147 -0
  28. package/src/actions/tools/desktop.test.ts +55 -0
  29. package/src/actions/tools/desktop.ts +305 -0
  30. package/src/actions/tools/goals.ts +376 -0
  31. package/src/actions/tools/local-tools-guard.ts +20 -0
  32. package/src/actions/tools/registry.ts +171 -0
  33. package/src/actions/tools/research.ts +111 -0
  34. package/src/actions/tools/sidecar-list.ts +57 -0
  35. package/src/actions/tools/sidecar-route.ts +105 -0
  36. package/src/actions/tools/workflows.ts +216 -0
  37. package/src/agents/agent.ts +132 -0
  38. package/src/agents/delegation.ts +107 -0
  39. package/src/agents/hierarchy.ts +113 -0
  40. package/src/agents/index.ts +19 -0
  41. package/src/agents/messaging.ts +125 -0
  42. package/src/agents/orchestrator.ts +576 -0
  43. package/src/agents/role-discovery.ts +61 -0
  44. package/src/agents/sub-agent-runner.ts +307 -0
  45. package/src/agents/task-manager.ts +151 -0
  46. package/src/authority/approval-delivery.ts +59 -0
  47. package/src/authority/approval.ts +196 -0
  48. package/src/authority/audit.ts +158 -0
  49. package/src/authority/authority.test.ts +519 -0
  50. package/src/authority/deferred-executor.ts +103 -0
  51. package/src/authority/emergency.ts +66 -0
  52. package/src/authority/engine.ts +297 -0
  53. package/src/authority/index.ts +12 -0
  54. package/src/authority/learning.ts +111 -0
  55. package/src/authority/tool-action-map.ts +74 -0
  56. package/src/awareness/analytics.ts +466 -0
  57. package/src/awareness/awareness.test.ts +332 -0
  58. package/src/awareness/capture-engine.ts +305 -0
  59. package/src/awareness/context-graph.ts +130 -0
  60. package/src/awareness/context-tracker.ts +349 -0
  61. package/src/awareness/index.ts +25 -0
  62. package/src/awareness/intelligence.ts +321 -0
  63. package/src/awareness/ocr-engine.ts +88 -0
  64. package/src/awareness/service.ts +528 -0
  65. package/src/awareness/struggle-detector.ts +342 -0
  66. package/src/awareness/suggestion-engine.ts +476 -0
  67. package/src/awareness/types.ts +201 -0
  68. package/src/cli/autostart.ts +241 -0
  69. package/src/cli/deps.ts +449 -0
  70. package/src/cli/doctor.ts +230 -0
  71. package/src/cli/helpers.ts +401 -0
  72. package/src/cli/onboard.ts +580 -0
  73. package/src/comms/README.md +329 -0
  74. package/src/comms/auth-error.html +48 -0
  75. package/src/comms/channels/discord.ts +228 -0
  76. package/src/comms/channels/signal.ts +56 -0
  77. package/src/comms/channels/telegram.ts +316 -0
  78. package/src/comms/channels/whatsapp.ts +60 -0
  79. package/src/comms/channels.test.ts +173 -0
  80. package/src/comms/desktop-notify.ts +114 -0
  81. package/src/comms/example.ts +129 -0
  82. package/src/comms/index.ts +129 -0
  83. package/src/comms/streaming.ts +142 -0
  84. package/src/comms/voice.test.ts +152 -0
  85. package/src/comms/voice.ts +291 -0
  86. package/src/comms/websocket.test.ts +409 -0
  87. package/src/comms/websocket.ts +473 -0
  88. package/src/config/README.md +387 -0
  89. package/src/config/index.ts +6 -0
  90. package/src/config/loader.test.ts +137 -0
  91. package/src/config/loader.ts +142 -0
  92. package/src/config/types.ts +260 -0
  93. package/src/daemon/README.md +232 -0
  94. package/src/daemon/agent-service-interface.ts +9 -0
  95. package/src/daemon/agent-service.ts +600 -0
  96. package/src/daemon/api-routes.ts +2119 -0
  97. package/src/daemon/background-agent-service.ts +396 -0
  98. package/src/daemon/background-agent.test.ts +78 -0
  99. package/src/daemon/channel-service.ts +201 -0
  100. package/src/daemon/commitment-executor.ts +297 -0
  101. package/src/daemon/event-classifier.ts +239 -0
  102. package/src/daemon/event-coalescer.ts +123 -0
  103. package/src/daemon/event-reactor.ts +214 -0
  104. package/src/daemon/health.ts +220 -0
  105. package/src/daemon/index.ts +1004 -0
  106. package/src/daemon/llm-settings.ts +316 -0
  107. package/src/daemon/observer-service.ts +150 -0
  108. package/src/daemon/pid.ts +98 -0
  109. package/src/daemon/research-queue.ts +155 -0
  110. package/src/daemon/services.ts +175 -0
  111. package/src/daemon/ws-service.ts +788 -0
  112. package/src/goals/accountability.ts +240 -0
  113. package/src/goals/awareness-bridge.ts +185 -0
  114. package/src/goals/estimator.ts +185 -0
  115. package/src/goals/events.ts +28 -0
  116. package/src/goals/goals.test.ts +400 -0
  117. package/src/goals/integration.test.ts +329 -0
  118. package/src/goals/nl-builder.test.ts +220 -0
  119. package/src/goals/nl-builder.ts +256 -0
  120. package/src/goals/rhythm.test.ts +177 -0
  121. package/src/goals/rhythm.ts +275 -0
  122. package/src/goals/service.test.ts +135 -0
  123. package/src/goals/service.ts +348 -0
  124. package/src/goals/types.ts +106 -0
  125. package/src/goals/workflow-bridge.ts +96 -0
  126. package/src/integrations/google-api.ts +134 -0
  127. package/src/integrations/google-auth.ts +175 -0
  128. package/src/llm/README.md +291 -0
  129. package/src/llm/anthropic.ts +386 -0
  130. package/src/llm/gemini.ts +371 -0
  131. package/src/llm/index.ts +19 -0
  132. package/src/llm/manager.ts +153 -0
  133. package/src/llm/ollama.ts +307 -0
  134. package/src/llm/openai.ts +350 -0
  135. package/src/llm/provider.test.ts +231 -0
  136. package/src/llm/provider.ts +60 -0
  137. package/src/llm/test.ts +87 -0
  138. package/src/observers/README.md +278 -0
  139. package/src/observers/calendar.ts +113 -0
  140. package/src/observers/clipboard.ts +136 -0
  141. package/src/observers/email.ts +109 -0
  142. package/src/observers/example.ts +58 -0
  143. package/src/observers/file-watcher.ts +124 -0
  144. package/src/observers/index.ts +159 -0
  145. package/src/observers/notifications.ts +197 -0
  146. package/src/observers/observers.test.ts +203 -0
  147. package/src/observers/processes.ts +225 -0
  148. package/src/personality/README.md +61 -0
  149. package/src/personality/adapter.ts +196 -0
  150. package/src/personality/index.ts +20 -0
  151. package/src/personality/learner.ts +209 -0
  152. package/src/personality/model.ts +132 -0
  153. package/src/personality/personality.test.ts +236 -0
  154. package/src/roles/README.md +252 -0
  155. package/src/roles/authority.ts +119 -0
  156. package/src/roles/example-usage.ts +198 -0
  157. package/src/roles/index.ts +42 -0
  158. package/src/roles/loader.ts +143 -0
  159. package/src/roles/prompt-builder.ts +194 -0
  160. package/src/roles/test-multi.ts +102 -0
  161. package/src/roles/test-role.yaml +77 -0
  162. package/src/roles/test-utils.ts +93 -0
  163. package/src/roles/test.ts +106 -0
  164. package/src/roles/tool-guide.ts +190 -0
  165. package/src/roles/types.ts +36 -0
  166. package/src/roles/utils.ts +200 -0
  167. package/src/scripts/google-setup.ts +168 -0
  168. package/src/sidecar/connection.ts +179 -0
  169. package/src/sidecar/index.ts +6 -0
  170. package/src/sidecar/manager.ts +542 -0
  171. package/src/sidecar/protocol.ts +85 -0
  172. package/src/sidecar/rpc.ts +161 -0
  173. package/src/sidecar/scheduler.ts +136 -0
  174. package/src/sidecar/types.ts +112 -0
  175. package/src/sidecar/validator.ts +144 -0
  176. package/src/vault/README.md +110 -0
  177. package/src/vault/awareness.ts +341 -0
  178. package/src/vault/commitments.ts +299 -0
  179. package/src/vault/content-pipeline.ts +260 -0
  180. package/src/vault/conversations.ts +173 -0
  181. package/src/vault/entities.ts +180 -0
  182. package/src/vault/extractor.test.ts +356 -0
  183. package/src/vault/extractor.ts +345 -0
  184. package/src/vault/facts.ts +190 -0
  185. package/src/vault/goals.ts +477 -0
  186. package/src/vault/index.ts +87 -0
  187. package/src/vault/keychain.ts +99 -0
  188. package/src/vault/observations.ts +115 -0
  189. package/src/vault/relationships.ts +178 -0
  190. package/src/vault/retrieval.test.ts +126 -0
  191. package/src/vault/retrieval.ts +227 -0
  192. package/src/vault/schema.ts +658 -0
  193. package/src/vault/settings.ts +38 -0
  194. package/src/vault/vectors.ts +92 -0
  195. package/src/vault/workflows.ts +403 -0
  196. package/src/workflows/auto-suggest.ts +290 -0
  197. package/src/workflows/engine.ts +366 -0
  198. package/src/workflows/events.ts +24 -0
  199. package/src/workflows/executor.ts +207 -0
  200. package/src/workflows/nl-builder.ts +198 -0
  201. package/src/workflows/nodes/actions/agent-task.ts +73 -0
  202. package/src/workflows/nodes/actions/calendar-action.ts +85 -0
  203. package/src/workflows/nodes/actions/code-execution.ts +73 -0
  204. package/src/workflows/nodes/actions/discord.ts +77 -0
  205. package/src/workflows/nodes/actions/file-write.ts +73 -0
  206. package/src/workflows/nodes/actions/gmail.ts +69 -0
  207. package/src/workflows/nodes/actions/http-request.ts +117 -0
  208. package/src/workflows/nodes/actions/notification.ts +85 -0
  209. package/src/workflows/nodes/actions/run-tool.ts +55 -0
  210. package/src/workflows/nodes/actions/send-message.ts +82 -0
  211. package/src/workflows/nodes/actions/shell-command.ts +76 -0
  212. package/src/workflows/nodes/actions/telegram.ts +60 -0
  213. package/src/workflows/nodes/builtin.ts +119 -0
  214. package/src/workflows/nodes/error/error-handler.ts +37 -0
  215. package/src/workflows/nodes/error/fallback.ts +47 -0
  216. package/src/workflows/nodes/error/retry.ts +82 -0
  217. package/src/workflows/nodes/logic/delay.ts +42 -0
  218. package/src/workflows/nodes/logic/if-else.ts +41 -0
  219. package/src/workflows/nodes/logic/loop.ts +90 -0
  220. package/src/workflows/nodes/logic/merge.ts +38 -0
  221. package/src/workflows/nodes/logic/race.ts +40 -0
  222. package/src/workflows/nodes/logic/switch.ts +59 -0
  223. package/src/workflows/nodes/logic/template-render.ts +53 -0
  224. package/src/workflows/nodes/logic/variable-get.ts +37 -0
  225. package/src/workflows/nodes/logic/variable-set.ts +59 -0
  226. package/src/workflows/nodes/registry.ts +99 -0
  227. package/src/workflows/nodes/transform/aggregate.ts +99 -0
  228. package/src/workflows/nodes/transform/csv-parse.ts +70 -0
  229. package/src/workflows/nodes/transform/json-parse.ts +63 -0
  230. package/src/workflows/nodes/transform/map-filter.ts +84 -0
  231. package/src/workflows/nodes/transform/regex-match.ts +89 -0
  232. package/src/workflows/nodes/triggers/calendar.ts +33 -0
  233. package/src/workflows/nodes/triggers/clipboard.ts +32 -0
  234. package/src/workflows/nodes/triggers/cron.ts +40 -0
  235. package/src/workflows/nodes/triggers/email.ts +40 -0
  236. package/src/workflows/nodes/triggers/file-change.ts +45 -0
  237. package/src/workflows/nodes/triggers/git.ts +46 -0
  238. package/src/workflows/nodes/triggers/manual.ts +23 -0
  239. package/src/workflows/nodes/triggers/poll.ts +81 -0
  240. package/src/workflows/nodes/triggers/process.ts +44 -0
  241. package/src/workflows/nodes/triggers/screen-event.ts +37 -0
  242. package/src/workflows/nodes/triggers/webhook.ts +39 -0
  243. package/src/workflows/safe-eval.ts +139 -0
  244. package/src/workflows/template.ts +118 -0
  245. package/src/workflows/triggers/cron.ts +311 -0
  246. package/src/workflows/triggers/manager.ts +285 -0
  247. package/src/workflows/triggers/observer-bridge.ts +172 -0
  248. package/src/workflows/triggers/poller.ts +201 -0
  249. package/src/workflows/triggers/screen-condition.ts +218 -0
  250. package/src/workflows/triggers/triggers.test.ts +740 -0
  251. package/src/workflows/triggers/webhook.ts +191 -0
  252. package/src/workflows/types.ts +133 -0
  253. package/src/workflows/variables.ts +72 -0
  254. package/src/workflows/workflows.test.ts +383 -0
  255. package/src/workflows/yaml.ts +104 -0
  256. package/ui/dist/index-j75njzc1.css +1199 -0
  257. package/ui/dist/index-p2zh407q.js +80603 -0
  258. package/ui/dist/index.html +13 -0
  259. package/ui/public/openwakeword/models/embedding_model.onnx +0 -0
  260. package/ui/public/openwakeword/models/hey_jarvis_v0.1.onnx +0 -0
  261. package/ui/public/openwakeword/models/melspectrogram.onnx +0 -0
  262. package/ui/public/openwakeword/models/silero_vad.onnx +0 -0
  263. package/ui/public/ort/ort-wasm-simd-threaded.jsep.mjs +106 -0
  264. package/ui/public/ort/ort-wasm-simd-threaded.jsep.wasm +0 -0
  265. package/ui/public/ort/ort-wasm-simd-threaded.mjs +59 -0
  266. package/ui/public/ort/ort-wasm-simd-threaded.wasm +0 -0
@@ -0,0 +1,236 @@
1
+ import { test, expect, beforeEach, afterEach, describe } from 'bun:test';
2
+ import { initDatabase, closeDb } from '../vault/schema.ts';
3
+ import {
4
+ getPersonality,
5
+ savePersonality,
6
+ updatePersonality,
7
+ type PersonalityModel,
8
+ } from './model.ts';
9
+ import {
10
+ extractSignals,
11
+ applySignals,
12
+ recordInteraction,
13
+ } from './learner.ts';
14
+ import {
15
+ getChannelPersonality,
16
+ personalityToPrompt,
17
+ } from './adapter.ts';
18
+
19
+ describe('Personality Engine', () => {
20
+ beforeEach(() => {
21
+ // Initialize in-memory database for each test
22
+ initDatabase(':memory:');
23
+ });
24
+
25
+ afterEach(() => {
26
+ // Close database connection after each test
27
+ closeDb();
28
+ });
29
+
30
+ describe('Model', () => {
31
+ test('should get default personality', () => {
32
+ const personality = getPersonality();
33
+
34
+ expect(personality.core_traits).toEqual(['direct', 'strategic', 'resourceful']);
35
+ expect(personality.learned_preferences.verbosity).toBe(5);
36
+ expect(personality.learned_preferences.formality).toBe(5);
37
+ expect(personality.relationship.message_count).toBe(0);
38
+ });
39
+
40
+ test('should save and load personality', () => {
41
+ const personality = getPersonality();
42
+ personality.learned_preferences.verbosity = 8;
43
+ personality.relationship.message_count = 42;
44
+
45
+ savePersonality(personality);
46
+
47
+ const loaded = getPersonality();
48
+ expect(loaded.learned_preferences.verbosity).toBe(8);
49
+ expect(loaded.relationship.message_count).toBe(42);
50
+ });
51
+
52
+ test('should update personality with deep merge', () => {
53
+ const updated = updatePersonality({
54
+ learned_preferences: {
55
+ verbosity: 7,
56
+ },
57
+ });
58
+
59
+ expect(updated.learned_preferences.verbosity).toBe(7);
60
+ expect(updated.learned_preferences.formality).toBe(5); // unchanged
61
+ expect(updated.core_traits).toEqual(['direct', 'strategic', 'resourceful']); // unchanged
62
+ });
63
+ });
64
+
65
+ describe('Learner', () => {
66
+ test('should extract verbosity signals', () => {
67
+ const signals = extractSignals('Please keep it brief and concise', 'Here is a long response...');
68
+
69
+ expect(signals.length).toBeGreaterThan(0);
70
+ const verbositySignal = signals.find((s) => s.data.preference === 'verbosity');
71
+ expect(verbositySignal).toBeDefined();
72
+ expect(verbositySignal?.data.direction).toBe(-1);
73
+ });
74
+
75
+ test('should extract formality signals', () => {
76
+ const signals = extractSignals('Be more casual please', 'Understood.');
77
+
78
+ const formalitySignal = signals.find((s) => s.data.preference === 'formality');
79
+ expect(formalitySignal).toBeDefined();
80
+ expect(formalitySignal?.data.direction).toBe(-1);
81
+ });
82
+
83
+ test('should extract emoji usage signals', () => {
84
+ const signals = extractSignals('Great work! 🎉✨', 'Thank you!');
85
+
86
+ const emojiSignal = signals.find((s) => s.data.preference === 'emoji_usage');
87
+ expect(emojiSignal).toBeDefined();
88
+ expect(emojiSignal?.data.value).toBe(true);
89
+ });
90
+
91
+ test('should extract format preference signals', () => {
92
+ const signals = extractSignals('Can you show this as a table?', 'Sure!');
93
+
94
+ const formatSignal = signals.find((s) => s.data.preference === 'preferred_format');
95
+ expect(formatSignal).toBeDefined();
96
+ expect(formatSignal?.data.value).toBe('tables');
97
+ });
98
+
99
+ test('should apply signals to personality', () => {
100
+ const personality = getPersonality();
101
+ const initialVerbosity = personality.learned_preferences.verbosity;
102
+ const initialFormality = personality.learned_preferences.formality;
103
+
104
+ const signals = [
105
+ { type: 'user_feedback' as const, data: { preference: 'verbosity', direction: 2 } },
106
+ { type: 'explicit_preference' as const, data: { preference: 'formality', direction: -1 } },
107
+ ];
108
+
109
+ const updated = applySignals(personality, signals);
110
+
111
+ expect(updated.learned_preferences.verbosity).toBe(initialVerbosity + 2);
112
+ expect(updated.learned_preferences.formality).toBe(initialFormality - 1);
113
+ });
114
+
115
+ test('should clamp values to 0-10 range', () => {
116
+ let personality = getPersonality();
117
+ personality.learned_preferences.verbosity = 9;
118
+
119
+ const signals = [
120
+ { type: 'user_feedback' as const, data: { preference: 'verbosity', direction: 5 } },
121
+ ];
122
+
123
+ personality = applySignals(personality, signals);
124
+
125
+ expect(personality.learned_preferences.verbosity).toBe(10); // clamped
126
+ });
127
+
128
+ test('should record interactions and increase trust', () => {
129
+ let personality = getPersonality();
130
+ const initialCount = personality.relationship.message_count;
131
+
132
+ // Simulate 50 interactions
133
+ for (let i = 0; i < 50; i++) {
134
+ personality = recordInteraction(personality);
135
+ }
136
+
137
+ expect(personality.relationship.message_count).toBe(initialCount + 50);
138
+ // Trust should increase based on message count
139
+ expect(personality.relationship.trust_level).toBeGreaterThan(3);
140
+ });
141
+ });
142
+
143
+ describe('Adapter', () => {
144
+ test('should adapt personality for WhatsApp', () => {
145
+ const base = getPersonality();
146
+ const adapted = getChannelPersonality(base, 'whatsapp');
147
+
148
+ expect(adapted.learned_preferences.emoji_usage).toBe(true);
149
+ expect(adapted.learned_preferences.verbosity).toBe(4);
150
+ expect(adapted.learned_preferences.formality).toBe(3);
151
+ });
152
+
153
+ test('should adapt personality for email', () => {
154
+ const base = getPersonality();
155
+ const adapted = getChannelPersonality(base, 'email');
156
+
157
+ expect(adapted.learned_preferences.emoji_usage).toBe(false);
158
+ expect(adapted.learned_preferences.verbosity).toBe(7);
159
+ expect(adapted.learned_preferences.formality).toBe(8);
160
+ });
161
+
162
+ test('should use stored channel overrides', () => {
163
+ const personality = getPersonality();
164
+ personality.channel_overrides.custom_channel = {
165
+ learned_preferences: {
166
+ verbosity: 10,
167
+ formality: 0,
168
+ humor_level: 10,
169
+ emoji_usage: true,
170
+ preferred_format: 'lists',
171
+ },
172
+ };
173
+
174
+ const adapted = getChannelPersonality(personality, 'custom_channel');
175
+
176
+ expect(adapted.learned_preferences.verbosity).toBe(10);
177
+ expect(adapted.learned_preferences.formality).toBe(0);
178
+ });
179
+
180
+ test('should generate personality prompt', () => {
181
+ const personality = getPersonality();
182
+ personality.relationship.message_count = 25;
183
+ personality.relationship.shared_references = ['Project X', 'Anna'];
184
+
185
+ const prompt = personalityToPrompt(personality);
186
+
187
+ expect(prompt).toContain('Personality');
188
+ expect(prompt).toContain('direct, strategic, resourceful');
189
+ expect(prompt).toContain('25 interactions');
190
+ expect(prompt).toContain('Project X, Anna');
191
+ });
192
+ });
193
+
194
+ describe('Integration', () => {
195
+ test('should handle full learning cycle', () => {
196
+ // Start with default personality
197
+ let personality = getPersonality();
198
+ const initialVerbosity = personality.learned_preferences.verbosity;
199
+
200
+ // User sends multiple messages asking for brevity
201
+ const userMessages = [
202
+ 'Keep it short please',
203
+ 'TLDR version?',
204
+ 'Too long, can you summarize?',
205
+ ];
206
+
207
+ userMessages.forEach((msg) => {
208
+ const signals = extractSignals(msg, 'Response');
209
+ personality = applySignals(personality, signals);
210
+ personality = recordInteraction(personality);
211
+ });
212
+
213
+ // Save the learned personality
214
+ savePersonality(personality);
215
+
216
+ // Reload and verify
217
+ const loaded = getPersonality();
218
+ // Verbosity should have decreased from initial value
219
+ expect(loaded.learned_preferences.verbosity).toBeLessThan(initialVerbosity);
220
+ // Message count should have increased by 3
221
+ expect(loaded.relationship.message_count).toBeGreaterThanOrEqual(3);
222
+ });
223
+
224
+ test('should adapt for channel and generate prompt', () => {
225
+ let personality = getPersonality();
226
+ personality.relationship.message_count = 100;
227
+
228
+ const whatsappPersonality = getChannelPersonality(personality, 'whatsapp');
229
+ const prompt = personalityToPrompt(whatsappPersonality);
230
+
231
+ expect(prompt).toContain('Personality');
232
+ expect(prompt).toContain('100 interactions');
233
+ expect(whatsappPersonality.learned_preferences.emoji_usage).toBe(true);
234
+ });
235
+ });
236
+ });
@@ -0,0 +1,252 @@
1
+ # Role Engine
2
+
3
+ The Role Engine is a core component of Project J.A.R.V.I.S. that defines, loads, and manages AI agent roles with their permissions, responsibilities, and behavior patterns.
4
+
5
+ ## Overview
6
+
7
+ The Role Engine provides:
8
+
9
+ - **Role Definitions**: YAML-based role configuration with clear responsibilities and boundaries
10
+ - **Authority System**: 10-level permission system controlling what actions agents can perform
11
+ - **System Prompt Generation**: Automatic generation of detailed system prompts from role definitions
12
+ - **Validation**: Type-safe role loading with comprehensive validation
13
+ - **Multi-Role Management**: Load and manage multiple roles from a directory
14
+
15
+ ## Architecture
16
+
17
+ ```
18
+ src/roles/
19
+ ├── types.ts # TypeScript type definitions
20
+ ├── loader.ts # YAML loading and validation
21
+ ├── prompt-builder.ts # System prompt generation
22
+ ├── authority.ts # Permission and authority system
23
+ └── index.ts # Public API exports
24
+ ```
25
+
26
+ ## Usage
27
+
28
+ ### Loading a Single Role
29
+
30
+ ```typescript
31
+ import { loadRole } from './roles/index.ts';
32
+
33
+ const role = loadRole('/path/to/role.yaml');
34
+ console.log(role.name, role.authority_level);
35
+ ```
36
+
37
+ ### Loading Multiple Roles
38
+
39
+ ```typescript
40
+ import { loadRolesFromDir } from './roles/index.ts';
41
+
42
+ const roles = loadRolesFromDir('/config/roles');
43
+ for (const [id, role] of roles) {
44
+ console.log(`${id}: ${role.name}`);
45
+ }
46
+ ```
47
+
48
+ ### Building System Prompts
49
+
50
+ ```typescript
51
+ import { buildSystemPrompt } from './roles/index.ts';
52
+
53
+ const prompt = buildSystemPrompt(role, {
54
+ userName: 'John Doe',
55
+ currentTime: new Date().toLocaleString(),
56
+ activeCommitments: ['Finish report by Friday'],
57
+ recentObservations: ['User prefers morning meetings'],
58
+ agentHierarchy: 'Manager > Assistant (you) > Specialist',
59
+ });
60
+ ```
61
+
62
+ ### Checking Permissions
63
+
64
+ ```typescript
65
+ import { canPerform, getRolePermissionsSummary } from './roles/index.ts';
66
+
67
+ // Check specific action
68
+ if (canPerform(role, 'execute_command')) {
69
+ console.log('Can execute commands');
70
+ }
71
+
72
+ // Get full permission summary
73
+ const summary = getRolePermissionsSummary(role);
74
+ console.log(summary.allowed); // List of allowed actions
75
+ console.log(summary.denied); // List of denied actions
76
+ ```
77
+
78
+ ## Role Definition Format
79
+
80
+ Roles are defined in YAML files with the following structure:
81
+
82
+ ```yaml
83
+ id: unique_role_id
84
+ name: Human-Readable Role Name
85
+ description: Brief description of the role's purpose
86
+
87
+ responsibilities:
88
+ - First responsibility
89
+ - Second responsibility
90
+
91
+ autonomous_actions:
92
+ - Actions the agent can take without asking
93
+
94
+ approval_required:
95
+ - Actions that require user approval
96
+
97
+ kpis:
98
+ - name: KPI Name
99
+ metric: What to measure
100
+ target: Target value
101
+ check_interval: How often to check
102
+
103
+ communication_style:
104
+ tone: Description of communication tone
105
+ verbosity: concise | detailed | adaptive
106
+ formality: formal | casual | adaptive
107
+
108
+ heartbeat_instructions: |
109
+ Instructions for periodic check-ins.
110
+ What to monitor and when to notify the user.
111
+
112
+ sub_roles:
113
+ - role_id: sub_role_id
114
+ name: Sub-Role Name
115
+ description: What this sub-role does
116
+ spawned_by: parent_role_id
117
+ reports_to: parent_role_id
118
+ max_budget_per_task: 100
119
+
120
+ tools:
121
+ - tool_name_1
122
+ - tool_name_2
123
+
124
+ authority_level: 6 # 1-10
125
+ ```
126
+
127
+ ## Authority Levels
128
+
129
+ The authority system uses a 1-10 scale:
130
+
131
+ | Level | Capabilities |
132
+ |-------|-------------|
133
+ | 1-2 | **Read Only**: Can read data but cannot modify anything |
134
+ | 3-4 | **Read & Write**: Can read/write data and send messages |
135
+ | 5-6 | **Command Execution**: Can execute commands, control apps, access browser |
136
+ | 7-8 | **Agent Management**: Can spawn agents, send emails, install software |
137
+ | 9-10 | **Full Access**: Can make payments, modify settings, delete data, terminate agents |
138
+
139
+ ### Action Categories
140
+
141
+ The following action categories are enforced:
142
+
143
+ **Level 1+**: `read_data`
144
+
145
+ **Level 3+**: `write_data`, `send_message`
146
+
147
+ **Level 5+**: `execute_command`, `access_browser`, `control_app`
148
+
149
+ **Level 7+**: `spawn_agent`, `send_email`, `install_software`
150
+
151
+ **Level 9+**: `make_payment`, `modify_settings`, `delete_data`, `terminate_agent`
152
+
153
+ ## Example Roles
154
+
155
+ See `/config/roles/` for example role definitions:
156
+
157
+ - **Executive Assistant** (Level 6): Manages schedule, communications, and tasks
158
+ - **Research Specialist** (Level 4): Deep research and report generation
159
+ - **System Administrator** (Level 9): System maintenance and infrastructure
160
+
161
+ ## Type Definitions
162
+
163
+ ### RoleDefinition
164
+
165
+ ```typescript
166
+ type RoleDefinition = {
167
+ id: string;
168
+ name: string;
169
+ description: string;
170
+ responsibilities: string[];
171
+ autonomous_actions: string[];
172
+ approval_required: string[];
173
+ kpis: KPI[];
174
+ communication_style: CommunicationStyle;
175
+ heartbeat_instructions: string;
176
+ sub_roles: SubRoleTemplate[];
177
+ tools: string[];
178
+ authority_level: number; // 1-10
179
+ };
180
+ ```
181
+
182
+ ### KPI
183
+
184
+ ```typescript
185
+ type KPI = {
186
+ name: string;
187
+ metric: string;
188
+ target: string;
189
+ check_interval: string;
190
+ };
191
+ ```
192
+
193
+ ### CommunicationStyle
194
+
195
+ ```typescript
196
+ type CommunicationStyle = {
197
+ tone: string;
198
+ verbosity: 'concise' | 'detailed' | 'adaptive';
199
+ formality: 'formal' | 'casual' | 'adaptive';
200
+ };
201
+ ```
202
+
203
+ ### SubRoleTemplate
204
+
205
+ ```typescript
206
+ type SubRoleTemplate = {
207
+ role_id: string;
208
+ name: string;
209
+ description: string;
210
+ spawned_by: string;
211
+ reports_to: string;
212
+ max_budget_per_task: number;
213
+ };
214
+ ```
215
+
216
+ ## Testing
217
+
218
+ Run the test suite:
219
+
220
+ ```bash
221
+ # Test single role loading
222
+ bun run src/roles/test.ts
223
+
224
+ # Test multi-role loading
225
+ bun run src/roles/test-multi.ts
226
+ ```
227
+
228
+ ## Integration with J.A.R.V.I.S.
229
+
230
+ The Role Engine integrates with:
231
+
232
+ 1. **Agent System**: Agents are instantiated with specific roles
233
+ 2. **LLM Integration**: System prompts are generated for LLM context
234
+ 3. **Permission System**: Authority levels enforce action restrictions
235
+ 4. **Daemon**: Roles are loaded at startup and managed by the daemon
236
+
237
+ ## Best Practices
238
+
239
+ 1. **Authority Principle**: Assign the minimum authority level needed for the role
240
+ 2. **Clear Boundaries**: Explicitly define autonomous vs approval-required actions
241
+ 3. **Measurable KPIs**: Define concrete, measurable success metrics
242
+ 4. **Heartbeat Clarity**: Provide clear, actionable heartbeat instructions
243
+ 5. **Tool Assignment**: Only assign tools the role actually needs
244
+ 6. **Communication Style**: Match style to the role's purpose and audience
245
+
246
+ ## Future Enhancements
247
+
248
+ - Role templates and inheritance
249
+ - Dynamic authority adjustment based on performance
250
+ - Role-based routing and delegation
251
+ - Automatic KPI tracking and reporting
252
+ - Role versioning and migration
@@ -0,0 +1,119 @@
1
+ import type { RoleDefinition } from './types.ts';
2
+
3
+ export type ActionCategory =
4
+ | 'read_data' | 'write_data' | 'delete_data'
5
+ | 'send_message' | 'send_email'
6
+ | 'execute_command' | 'install_software'
7
+ | 'make_payment' | 'modify_settings'
8
+ | 'spawn_agent' | 'terminate_agent'
9
+ | 'access_browser' | 'control_app';
10
+
11
+ /**
12
+ * Maps action categories to minimum required authority level
13
+ *
14
+ * Authority levels:
15
+ * - 1-2: Read only (read_data)
16
+ * - 3-4: Read + write + send messages (write_data, send_message)
17
+ * - 5-6: + execute commands, control apps (execute_command, access_browser, control_app)
18
+ * - 7-8: + spawn agents, send email, install software (spawn_agent, send_email, install_software)
19
+ * - 9-10: Full access including payments and settings (make_payment, modify_settings, delete_data, terminate_agent)
20
+ */
21
+ export const AUTHORITY_REQUIREMENTS: Record<ActionCategory, number> = {
22
+ // Level 1-2: Read only
23
+ 'read_data': 1,
24
+
25
+ // Level 3-4: Read + write + send messages
26
+ 'write_data': 3,
27
+ 'send_message': 3,
28
+
29
+ // Level 5-6: + execute commands, control apps
30
+ 'execute_command': 5,
31
+ 'access_browser': 5,
32
+ 'control_app': 5,
33
+
34
+ // Level 7-8: + spawn agents, send email, install software
35
+ 'spawn_agent': 7,
36
+ 'send_email': 7,
37
+ 'install_software': 7,
38
+
39
+ // Level 9-10: Full access including payments and settings
40
+ 'make_payment': 9,
41
+ 'modify_settings': 9,
42
+ 'delete_data': 9,
43
+ 'terminate_agent': 9,
44
+ };
45
+
46
+ /**
47
+ * Check if a role can perform a specific action
48
+ */
49
+ export function canPerform(role: RoleDefinition, action: ActionCategory): boolean {
50
+ const requiredLevel = AUTHORITY_REQUIREMENTS[action];
51
+ return role.authority_level >= requiredLevel;
52
+ }
53
+
54
+ /**
55
+ * Get the required authority level for an action
56
+ */
57
+ export function getRequiredLevel(action: ActionCategory): number {
58
+ return AUTHORITY_REQUIREMENTS[action];
59
+ }
60
+
61
+ /**
62
+ * List all actions a role is allowed to perform
63
+ */
64
+ export function listAllowedActions(role: RoleDefinition): ActionCategory[] {
65
+ const actions = Object.keys(AUTHORITY_REQUIREMENTS) as ActionCategory[];
66
+ return actions.filter(action => canPerform(role, action));
67
+ }
68
+
69
+ /**
70
+ * List all actions a role is NOT allowed to perform
71
+ */
72
+ export function listDeniedActions(role: RoleDefinition): ActionCategory[] {
73
+ const actions = Object.keys(AUTHORITY_REQUIREMENTS) as ActionCategory[];
74
+ return actions.filter(action => !canPerform(role, action));
75
+ }
76
+
77
+ /**
78
+ * Get a human-readable description of what an authority level allows
79
+ */
80
+ export function describeAuthorityLevel(level: number): string {
81
+ if (level < 1 || level > 10) {
82
+ return 'Invalid authority level';
83
+ }
84
+
85
+ if (level <= 2) {
86
+ return 'Read-only access. Can read data but cannot modify anything.';
87
+ }
88
+
89
+ if (level <= 4) {
90
+ return 'Read and write access. Can read/write data and send messages.';
91
+ }
92
+
93
+ if (level <= 6) {
94
+ return 'Command execution. Can execute commands, control apps, and access browser.';
95
+ }
96
+
97
+ if (level <= 8) {
98
+ return 'Agent management. Can spawn agents, send emails, and install software.';
99
+ }
100
+
101
+ return 'Full access. Can make payments, modify settings, delete data, and terminate agents.';
102
+ }
103
+
104
+ /**
105
+ * Get a summary of a role's permissions
106
+ */
107
+ export function getRolePermissionsSummary(role: RoleDefinition): {
108
+ level: number;
109
+ description: string;
110
+ allowed: ActionCategory[];
111
+ denied: ActionCategory[];
112
+ } {
113
+ return {
114
+ level: role.authority_level,
115
+ description: describeAuthorityLevel(role.authority_level),
116
+ allowed: listAllowedActions(role),
117
+ denied: listDeniedActions(role),
118
+ };
119
+ }