agent-office 0.4.0 → 0.4.1
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/db/postgresql-storage.d.ts +1 -0
- package/dist/db/postgresql-storage.js +15 -0
- package/dist/db/sqlite-storage.d.ts +1 -0
- package/dist/db/sqlite-storage.js +16 -0
- package/dist/db/storage-base.d.ts +1 -0
- package/dist/db/storage.d.ts +1 -0
- package/dist/server/routes.js +21 -4
- package/package.json +1 -1
|
@@ -26,6 +26,7 @@ export declare class AgentOfficePostgresqlStorage extends AgentOfficeStorageBase
|
|
|
26
26
|
}): Promise<MessageRow[]>;
|
|
27
27
|
listMessagesFromSender(name: string): Promise<MessageRow[]>;
|
|
28
28
|
countUnreadBySender(recipientName: string): Promise<Map<string, number>>;
|
|
29
|
+
lastMessageAtByCoworker(humanName: string): Promise<Map<string, Date>>;
|
|
29
30
|
createMessageImpl(from: string, to: string, body: string): Promise<MessageRow>;
|
|
30
31
|
markMessageAsRead(id: number): Promise<MessageRow | null>;
|
|
31
32
|
markMessageAsInjected(id: number): Promise<void>;
|
|
@@ -142,6 +142,21 @@ export class AgentOfficePostgresqlStorage extends AgentOfficeStorageBase {
|
|
|
142
142
|
}
|
|
143
143
|
return result;
|
|
144
144
|
}
|
|
145
|
+
async lastMessageAtByCoworker(humanName) {
|
|
146
|
+
const rows = await this.sql `
|
|
147
|
+
SELECT
|
|
148
|
+
CASE WHEN from_name = ${humanName} THEN to_name ELSE from_name END AS coworker,
|
|
149
|
+
MAX(created_at) AS last_at
|
|
150
|
+
FROM messages
|
|
151
|
+
WHERE from_name = ${humanName} OR to_name = ${humanName}
|
|
152
|
+
GROUP BY coworker
|
|
153
|
+
`;
|
|
154
|
+
const result = new Map();
|
|
155
|
+
for (const row of rows) {
|
|
156
|
+
result.set(row.coworker, row.last_at);
|
|
157
|
+
}
|
|
158
|
+
return result;
|
|
159
|
+
}
|
|
145
160
|
async createMessageImpl(from, to, body) {
|
|
146
161
|
const [row] = await this.sql `
|
|
147
162
|
INSERT INTO messages (from_name, to_name, body)
|
|
@@ -27,6 +27,7 @@ export declare class AgentOfficeSqliteStorage extends AgentOfficeStorageBase {
|
|
|
27
27
|
}): Promise<MessageRow[]>;
|
|
28
28
|
listMessagesFromSender(name: string): Promise<MessageRow[]>;
|
|
29
29
|
countUnreadBySender(recipientName: string): Promise<Map<string, number>>;
|
|
30
|
+
lastMessageAtByCoworker(humanName: string): Promise<Map<string, Date>>;
|
|
30
31
|
createMessageImpl(from: string, to: string, body: string): Promise<MessageRow>;
|
|
31
32
|
markMessageAsRead(id: number): Promise<MessageRow | null>;
|
|
32
33
|
markMessageAsInjected(id: number): Promise<void>;
|
|
@@ -197,6 +197,22 @@ export class AgentOfficeSqliteStorage extends AgentOfficeStorageBase {
|
|
|
197
197
|
}
|
|
198
198
|
return result;
|
|
199
199
|
}
|
|
200
|
+
async lastMessageAtByCoworker(humanName) {
|
|
201
|
+
const stmt = this.db.prepare(`
|
|
202
|
+
SELECT
|
|
203
|
+
CASE WHEN from_name = ? THEN to_name ELSE from_name END AS coworker,
|
|
204
|
+
MAX(created_at) AS last_at
|
|
205
|
+
FROM messages
|
|
206
|
+
WHERE from_name = ? OR to_name = ?
|
|
207
|
+
GROUP BY coworker
|
|
208
|
+
`);
|
|
209
|
+
const rows = stmt.all(humanName, humanName, humanName);
|
|
210
|
+
const result = new Map();
|
|
211
|
+
for (const row of rows) {
|
|
212
|
+
result.set(row.coworker, new Date(row.last_at + 'Z'));
|
|
213
|
+
}
|
|
214
|
+
return result;
|
|
215
|
+
}
|
|
200
216
|
async createMessageImpl(from, to, body) {
|
|
201
217
|
const stmt = this.db.prepare(`
|
|
202
218
|
INSERT INTO messages (from_name, to_name, body)
|
|
@@ -28,6 +28,7 @@ export declare abstract class AgentOfficeStorageBase implements AgentOfficeStora
|
|
|
28
28
|
}): Promise<MessageRow[]>;
|
|
29
29
|
abstract listMessagesFromSender(name: string): Promise<MessageRow[]>;
|
|
30
30
|
abstract countUnreadBySender(recipientName: string): Promise<Map<string, number>>;
|
|
31
|
+
abstract lastMessageAtByCoworker(humanName: string): Promise<Map<string, Date>>;
|
|
31
32
|
abstract markMessageAsRead(id: number): Promise<MessageRow | null>;
|
|
32
33
|
abstract markMessageAsInjected(id: number): Promise<void>;
|
|
33
34
|
abstract markMessagesAsNotified(ids: number[]): Promise<void>;
|
package/dist/db/storage.d.ts
CHANGED
|
@@ -37,6 +37,7 @@ export interface AgentOfficeStorage {
|
|
|
37
37
|
}): Promise<MessageRow[]>;
|
|
38
38
|
listMessagesFromSender(name: string): Promise<MessageRow[]>;
|
|
39
39
|
countUnreadBySender(recipientName: string): Promise<Map<string, number>>;
|
|
40
|
+
lastMessageAtByCoworker(humanName: string): Promise<Map<string, Date>>;
|
|
40
41
|
createMessage(from: string, to: string, body: string): Promise<MessageRow>;
|
|
41
42
|
markMessageAsRead(id: number): Promise<MessageRow | null>;
|
|
42
43
|
markMessageAsInjected(id: number): Promise<void>;
|
package/dist/server/routes.js
CHANGED
|
@@ -190,17 +190,34 @@ export function createRouter(storage, agenticCodingServer, serverUrl, scheduler)
|
|
|
190
190
|
try {
|
|
191
191
|
const sessions = await storage.listSessions();
|
|
192
192
|
const humanName = await storage.getConfig('human_name') ?? "Human";
|
|
193
|
-
const unreadCounts = await
|
|
193
|
+
const [unreadCounts, lastMessageAt] = await Promise.all([
|
|
194
|
+
storage.countUnreadBySender(humanName),
|
|
195
|
+
storage.lastMessageAtByCoworker(humanName),
|
|
196
|
+
]);
|
|
194
197
|
const coworkers = [
|
|
195
|
-
{ name: humanName, status: null, isHuman: true, unreadMessages: 0 },
|
|
198
|
+
{ name: humanName, status: null, isHuman: true, unreadMessages: 0, lastMessageAt: null },
|
|
196
199
|
...sessions.map(s => ({
|
|
197
200
|
name: s.name,
|
|
198
201
|
status: s.status,
|
|
199
202
|
isHuman: false,
|
|
200
|
-
unreadMessages: unreadCounts.get(s.name) ?? 0
|
|
203
|
+
unreadMessages: unreadCounts.get(s.name) ?? 0,
|
|
204
|
+
lastMessageAt: lastMessageAt.get(s.name)?.toISOString() ?? null,
|
|
201
205
|
}))
|
|
202
206
|
];
|
|
203
|
-
|
|
207
|
+
// Sort non-human coworkers by most recent message (most recent first),
|
|
208
|
+
// coworkers with no messages appear last (sorted by name as tiebreaker)
|
|
209
|
+
const [human, ...agents] = coworkers;
|
|
210
|
+
agents.sort((a, b) => {
|
|
211
|
+
if (a.lastMessageAt && b.lastMessageAt) {
|
|
212
|
+
return new Date(b.lastMessageAt).getTime() - new Date(a.lastMessageAt).getTime();
|
|
213
|
+
}
|
|
214
|
+
if (a.lastMessageAt)
|
|
215
|
+
return -1;
|
|
216
|
+
if (b.lastMessageAt)
|
|
217
|
+
return 1;
|
|
218
|
+
return a.name.localeCompare(b.name);
|
|
219
|
+
});
|
|
220
|
+
res.json([human, ...agents]);
|
|
204
221
|
}
|
|
205
222
|
catch (err) {
|
|
206
223
|
console.error("GET /coworkers error:", err);
|