agent-office 0.0.2 → 0.0.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.
package/dist/cli.js CHANGED
@@ -13,6 +13,7 @@ program
13
13
  .option("--opencode-url <url>", "OpenCode server URL", process.env.OPENCODE_URL ?? "http://localhost:4096")
14
14
  .option("--host <host>", "Host to bind to", "127.0.0.1")
15
15
  .option("--port <port>", "Port to serve on", "7654")
16
+ .option("--memory-path <path>", "Directory for memory storage (default: ./.memory)", "./.memory")
16
17
  .option("--password <password>", "REQUIRED. API password", process.env.AGENT_OFFICE_PASSWORD)
17
18
  .action(async (options) => {
18
19
  const { serve } = await import("./commands/serve.js");
@@ -46,6 +47,26 @@ workerCmd
46
47
  const { listCoworkers } = await import("./commands/worker.js");
47
48
  await listCoworkers(token);
48
49
  });
50
+ workerCmd
51
+ .command("set-status")
52
+ .description("Set your public status (visible to coworkers and manager)")
53
+ .argument("<token>", "Agent token in the format <agent_code>@<server-url>")
54
+ .option("--status <status>", "Your status message (max 140 characters)")
55
+ .option("--clear", "Clear your status")
56
+ .action(async (token, options) => {
57
+ if (options.clear) {
58
+ const { setStatus } = await import("./commands/worker.js");
59
+ await setStatus(token, null);
60
+ }
61
+ else if (options.status !== undefined) {
62
+ const { setStatus } = await import("./commands/worker.js");
63
+ await setStatus(token, options.status);
64
+ }
65
+ else {
66
+ console.error("Error: either --status or --clear must be provided");
67
+ process.exit(1);
68
+ }
69
+ });
49
70
  workerCmd
50
71
  .command("send-message")
51
72
  .description("Send a message to one or more coworkers")
@@ -137,4 +158,47 @@ cronCmd
137
158
  const { cronHistory } = await import("./commands/worker.js");
138
159
  await cronHistory(token, cronId);
139
160
  });
161
+ // ── Worker Memory Commands (nested) ──────────────────────────────────────────
162
+ const memoryCmd = workerCmd
163
+ .command("memory")
164
+ .description("Manage your persistent memories");
165
+ memoryCmd
166
+ .command("add")
167
+ .argument("<token>", "Agent token in the format <agent_code>@<server-url>")
168
+ .description("Add a new memory")
169
+ .requiredOption("--content <content>", "Memory content to store")
170
+ .action(async (token, options) => {
171
+ const { memoryAdd } = await import("./commands/worker.js");
172
+ await memoryAdd(token, options.content);
173
+ });
174
+ memoryCmd
175
+ .command("search")
176
+ .argument("<token>", "Agent token in the format <agent_code>@<server-url>")
177
+ .description("Search memories using hybrid search (keyword + semantic)")
178
+ .requiredOption("--query <query>", "Search query")
179
+ .option("--limit <limit>", "Maximum results (default 10)", "10")
180
+ .action(async (token, options) => {
181
+ const limit = parseInt(options.limit ?? "10", 10);
182
+ const { memorySearch } = await import("./commands/worker.js");
183
+ await memorySearch(token, options.query, limit);
184
+ });
185
+ memoryCmd
186
+ .command("list")
187
+ .argument("<token>", "Agent token in the format <agent_code>@<server-url>")
188
+ .description("List all stored memories")
189
+ .option("--limit <limit>", "Maximum memories to list (default 50)", "50")
190
+ .action(async (token, options) => {
191
+ const limit = parseInt(options.limit ?? "50", 10);
192
+ const { memoryList } = await import("./commands/worker.js");
193
+ await memoryList(token, limit);
194
+ });
195
+ memoryCmd
196
+ .command("forget")
197
+ .argument("<token>", "Agent token in the format <agent_code>@<server-url>")
198
+ .argument("<memoryId>", "ID of the memory to forget")
199
+ .description("Delete a memory by ID")
200
+ .action(async (token, memoryId) => {
201
+ const { memoryForget } = await import("./commands/worker.js");
202
+ await memoryForget(token, memoryId);
203
+ });
140
204
  program.parse();
@@ -3,6 +3,7 @@ interface ServeOptions {
3
3
  opencodeUrl: string;
4
4
  host: string;
5
5
  port: string;
6
+ memoryPath: string;
6
7
  password?: string;
7
8
  }
8
9
  export declare function serve(options: ServeOptions): Promise<void>;
@@ -3,6 +3,7 @@ import { runMigrations } from "../db/migrate.js";
3
3
  import { createOpencodeClient } from "../lib/opencode.js";
4
4
  import { createApp } from "../server/index.js";
5
5
  import { CronScheduler } from "../server/cron.js";
6
+ import { MemoryManager } from "../server/memory.js";
6
7
  export async function serve(options) {
7
8
  const password = options.password;
8
9
  if (!password) {
@@ -36,10 +37,25 @@ export async function serve(options) {
36
37
  // Init OpenCode client
37
38
  const opencode = createOpencodeClient(options.opencodeUrl);
38
39
  const serverUrl = `http://${options.host}:${port}`;
40
+ // Create memory manager and verify embedding model
41
+ const memoryManager = new MemoryManager(options.memoryPath);
42
+ console.log("Warming up embedding model...");
43
+ try {
44
+ await memoryManager.warmup();
45
+ console.log("Embedding model ready.");
46
+ }
47
+ catch (err) {
48
+ console.error("Embedding model failed to load:", err);
49
+ console.error("Try deleting the model cache and restarting:");
50
+ console.error(` rm -rf ${options.memoryPath}/.model-cache`);
51
+ memoryManager.closeAll();
52
+ await sql.end();
53
+ process.exit(1);
54
+ }
39
55
  // Create cron scheduler
40
56
  const cronScheduler = new CronScheduler();
41
57
  // Create Express app
42
- const app = createApp(sql, opencode, password, serverUrl, cronScheduler);
58
+ const app = createApp(sql, opencode, password, serverUrl, cronScheduler, memoryManager);
43
59
  // Start cron scheduler
44
60
  await cronScheduler.start(sql, opencode);
45
61
  // Start server
@@ -51,6 +67,7 @@ export async function serve(options) {
51
67
  console.log("\nShutting down...");
52
68
  server.close(async () => {
53
69
  cronScheduler.stop();
70
+ memoryManager.closeAll();
54
71
  await sql.end();
55
72
  console.log("Goodbye.");
56
73
  process.exit(0);
@@ -1,5 +1,6 @@
1
1
  export declare function clockIn(token: string): Promise<void>;
2
2
  export declare function listCoworkers(token: string): Promise<void>;
3
+ export declare function setStatus(token: string, status: string | null): Promise<void>;
3
4
  export declare function sendMessage(token: string, recipients: string[], body: string): Promise<void>;
4
5
  export declare function listCrons(token: string): Promise<void>;
5
6
  export declare function createCron(token: string, options: {
@@ -12,3 +13,7 @@ export declare function deleteCron(token: string, cronId: number): Promise<void>
12
13
  export declare function enableCron(token: string, cronId: number): Promise<void>;
13
14
  export declare function disableCron(token: string, cronId: number): Promise<void>;
14
15
  export declare function cronHistory(token: string, cronId: number): Promise<void>;
16
+ export declare function memoryAdd(token: string, content: string): Promise<void>;
17
+ export declare function memorySearch(token: string, query: string, limit: number): Promise<void>;
18
+ export declare function memoryList(token: string, limit: number): Promise<void>;
19
+ export declare function memoryForget(token: string, memoryId: string): Promise<void>;
@@ -112,6 +112,10 @@ export async function listCoworkers(token) {
112
112
  const workers = await fetchWorker(token, "/worker/list-coworkers");
113
113
  console.log(JSON.stringify(workers, null, 2));
114
114
  }
115
+ export async function setStatus(token, status) {
116
+ const result = await postWorker(token, "/worker/set-status", { status });
117
+ console.log(JSON.stringify(result, null, 2));
118
+ }
115
119
  export async function sendMessage(token, recipients, body) {
116
120
  const result = await postWorker(token, "/worker/send-message", { to: recipients, body });
117
121
  console.log(JSON.stringify(result, null, 2));
@@ -163,3 +167,66 @@ export async function cronHistory(token, cronId) {
163
167
  const history = await fetchWorker(token, `/worker/crons/${cronId}/history`);
164
168
  console.log(JSON.stringify(history, null, 2));
165
169
  }
170
+ // ── Memory Commands ──────────────────────────────────────────────────────────
171
+ export async function memoryAdd(token, content) {
172
+ const result = await postWorker(token, "/worker/memory/add", { content });
173
+ console.log(JSON.stringify(result, null, 2));
174
+ }
175
+ export async function memorySearch(token, query, limit) {
176
+ const result = await postWorker(token, "/worker/memory/search", { query, limit });
177
+ console.log(JSON.stringify(result, null, 2));
178
+ }
179
+ export async function memoryList(token, limit) {
180
+ const { agentCode, serverUrl } = parseToken(token);
181
+ const url = `${serverUrl}/worker/memory/list?code=${encodeURIComponent(agentCode)}&limit=${limit}`;
182
+ let res;
183
+ try {
184
+ res = await fetch(url);
185
+ }
186
+ catch (err) {
187
+ console.error(`Error: could not reach ${serverUrl}`);
188
+ console.error(err instanceof Error ? err.message : String(err));
189
+ process.exit(1);
190
+ }
191
+ let body;
192
+ try {
193
+ body = await res.json();
194
+ }
195
+ catch {
196
+ console.error(`Error: invalid response from server`);
197
+ process.exit(1);
198
+ }
199
+ if (!res.ok) {
200
+ const msg = body.error ?? `HTTP ${res.status}`;
201
+ console.error(`Error: ${msg}`);
202
+ process.exit(1);
203
+ }
204
+ console.log(JSON.stringify(body, null, 2));
205
+ }
206
+ export async function memoryForget(token, memoryId) {
207
+ const { agentCode, serverUrl } = parseToken(token);
208
+ const url = `${serverUrl}/worker/memory/${encodeURIComponent(memoryId)}?code=${encodeURIComponent(agentCode)}`;
209
+ let res;
210
+ try {
211
+ res = await fetch(url, { method: "DELETE" });
212
+ }
213
+ catch (err) {
214
+ console.error(`Error: could not reach ${serverUrl}`);
215
+ console.error(err instanceof Error ? err.message : String(err));
216
+ process.exit(1);
217
+ }
218
+ let body;
219
+ try {
220
+ body = await res.json();
221
+ }
222
+ catch {
223
+ console.error(`Error: invalid response from server`);
224
+ process.exit(1);
225
+ }
226
+ if (!res.ok) {
227
+ const msg = body.error ?? `HTTP ${res.status}`;
228
+ console.error(`Error: ${msg}`);
229
+ process.exit(1);
230
+ }
231
+ console.log(JSON.stringify(body, null, 2));
232
+ }
@@ -7,6 +7,7 @@ export interface SessionRow {
7
7
  session_id: string;
8
8
  agent_code: string;
9
9
  mode: string | null;
10
+ status: string | null;
10
11
  created_at: Date;
11
12
  }
12
13
  export interface ConfigRow {
@@ -86,6 +86,13 @@ const MIGRATIONS = [
86
86
  CREATE INDEX IF NOT EXISTS idx_cron_history_job_id ON cron_history(cron_job_id);
87
87
  `,
88
88
  },
89
+ {
90
+ version: 7,
91
+ name: "add_status_to_sessions",
92
+ sql: `
93
+ ALTER TABLE sessions ADD COLUMN IF NOT EXISTS status TEXT NULL;
94
+ `,
95
+ },
89
96
  ];
90
97
  export async function runMigrations(sql) {
91
98
  await sql `
@@ -23,7 +23,7 @@ const FOOTER_HINTS = {
23
23
  connecting: "",
24
24
  "auth-error": "",
25
25
  menu: "↑↓ navigate · Enter select · q quit",
26
- list: "↑↓ navigate · c create · d delete · r reveal code · g regen · t tail · i inject · m mail · Esc back",
26
+ list: "↑↓ navigate · c create · d delete · r reveal code · g regen · x revert · t tail · i inject · m mail · M memories · Esc back",
27
27
  "send-message": "Enter submit · Esc back to menu",
28
28
  "my-mail": "↑↓ select message · r reply · m mark read · a mark all read · s sent tab · Esc back",
29
29
  "profile": "Enter submit · Esc back to menu",