@coffer-org/server 7.2.0 → 7.4.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.
- package/dist/auth-api.d.ts +4 -0
- package/dist/auth-api.js +52 -0
- package/dist/auth-store.d.ts +2 -0
- package/dist/auth-store.js +1 -0
- package/dist/compute-unit.js +0 -3
- package/dist/conversation-store.d.ts +61 -0
- package/dist/conversation-store.js +223 -0
- package/dist/entity-schema.d.ts +5 -2
- package/dist/entity-schema.js +35 -18
- package/dist/identity-link.d.ts +15 -0
- package/dist/identity-link.js +76 -0
- package/dist/identity-providers.d.ts +17 -0
- package/dist/identity-providers.js +14 -0
- package/dist/index.js +8 -1
- package/dist/mcp-contract/schema.d.ts +0 -1
- package/dist/mcp-contract/schema.js +0 -2
- package/dist/mcp-http.js +7 -3
- package/dist/mcp-tools.d.ts +4 -3
- package/dist/mcp-tools.js +84 -84
- package/dist/media/image.d.ts +23 -0
- package/dist/media/image.js +103 -0
- package/dist/media/index.d.ts +1 -0
- package/dist/media/index.js +1 -0
- package/dist/migrations.js +1 -1
- package/dist/mutate.js +0 -15
- package/dist/orchestrator/agent-capabilities.d.ts +2 -2
- package/dist/orchestrator/agent-capabilities.js +3 -3
- package/dist/orchestrator/allow.d.ts +1 -16
- package/dist/orchestrator/allow.js +3 -53
- package/dist/orchestrator/config.js +0 -1
- package/dist/orchestrator/context-facts.d.ts +27 -0
- package/dist/orchestrator/context-facts.js +89 -0
- package/dist/orchestrator/conversation-access.d.ts +9 -0
- package/dist/orchestrator/conversation-access.js +12 -0
- package/dist/orchestrator/draft-message.d.ts +18 -0
- package/dist/orchestrator/draft-message.js +85 -0
- package/dist/orchestrator/environment.d.ts +1 -0
- package/dist/orchestrator/environment.js +10 -0
- package/dist/orchestrator/file-inspection.d.ts +2 -2
- package/dist/orchestrator/file-inspection.js +41 -19
- package/dist/orchestrator/index.d.ts +14 -9
- package/dist/orchestrator/index.js +6 -7
- package/dist/orchestrator/live-message.d.ts +7 -4
- package/dist/orchestrator/live-message.js +52 -32
- package/dist/orchestrator/pipeline.d.ts +22 -4
- package/dist/orchestrator/pipeline.js +316 -115
- package/dist/orchestrator/registry.d.ts +2 -2
- package/dist/orchestrator/registry.js +1 -1
- package/dist/orchestrator/system-areas.d.ts +12 -0
- package/dist/orchestrator/system-areas.js +63 -0
- package/dist/orchestrator/system-capabilities.js +1 -1
- package/dist/orchestrator/turn-context.d.ts +18 -0
- package/dist/orchestrator/turn-context.js +39 -0
- package/dist/orchestrator/types.d.ts +100 -49
- package/dist/plugin-hooks.d.ts +38 -1
- package/dist/plugin-hooks.js +4 -0
- package/dist/plugin-http-mounts.d.ts +18 -0
- package/dist/plugin-http-mounts.js +94 -0
- package/dist/plugin-runtime.d.ts +4 -0
- package/dist/plugin-runtime.js +9 -5
- package/dist/plugins-api.d.ts +8 -2
- package/dist/plugins-api.js +4 -2
- package/dist/records-api.js +15 -3
- package/dist/settings-write.d.ts +1 -2
- package/dist/settings-write.js +1 -2
- package/dist/system-settings.js +0 -1
- package/dist/temporal.js +8 -3
- package/dist/thread-state.d.ts +14 -0
- package/dist/thread-state.js +71 -11
- package/dist/thread-store.d.ts +5 -3
- package/dist/thread-store.js +12 -9
- package/dist/turn-gate.d.ts +8 -0
- package/dist/turn-gate.js +39 -0
- package/package.json +7 -2
package/dist/thread-state.d.ts
CHANGED
|
@@ -1,8 +1,22 @@
|
|
|
1
1
|
export interface ThreadSelection {
|
|
2
2
|
agentId: string | null;
|
|
3
3
|
presetId: string | null;
|
|
4
|
+
title: string | null;
|
|
5
|
+
owner: string | null;
|
|
6
|
+
visibility: 'private' | null;
|
|
4
7
|
}
|
|
8
|
+
export declare const TITLE_MAX = 60;
|
|
5
9
|
export declare function getThreadState(connector: string, chatId: string): Promise<ThreadSelection>;
|
|
10
|
+
export declare function getThreadStates(connector: string, chatIds: string[]): Promise<Map<string, ThreadSelection>>;
|
|
6
11
|
export declare function setThreadState(connector: string, chatId: string, patch: Partial<ThreadSelection>): Promise<void>;
|
|
7
12
|
export declare function readAndTouchThreadState(connector: string, chatId: string): Promise<ThreadSelection>;
|
|
13
|
+
export declare function findChatByConvId(connector: string, convId: string): Promise<ChatLookup>;
|
|
14
|
+
export type ChatLookup = {
|
|
15
|
+
found: 'one';
|
|
16
|
+
chatId: string;
|
|
17
|
+
} | {
|
|
18
|
+
found: 'none';
|
|
19
|
+
} | {
|
|
20
|
+
found: 'ambiguous';
|
|
21
|
+
};
|
|
8
22
|
export declare function pruneThreadState(connector: string, cutoffIso: string): Promise<void>;
|
package/dist/thread-state.js
CHANGED
|
@@ -1,26 +1,63 @@
|
|
|
1
1
|
import { getEm } from "./db.js";
|
|
2
|
-
|
|
2
|
+
import { getLogger } from '@coffer-org/sdk/logger';
|
|
3
|
+
const log = getLogger('thread-state');
|
|
4
|
+
export const TITLE_MAX = 60;
|
|
5
|
+
function capTitle(title) {
|
|
6
|
+
const t = title.trim();
|
|
7
|
+
return t.length <= TITLE_MAX ? t : `${t.slice(0, TITLE_MAX - 1)}…`;
|
|
8
|
+
}
|
|
9
|
+
const EMPTY = { agentId: null, presetId: null, title: null, owner: null, visibility: null };
|
|
10
|
+
function toSelection(row) {
|
|
11
|
+
return {
|
|
12
|
+
agentId: row.agent_id,
|
|
13
|
+
presetId: row.preset_id,
|
|
14
|
+
title: row.title,
|
|
15
|
+
owner: row.owner,
|
|
16
|
+
visibility: row.visibility === 'private' ? 'private' : null,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
3
19
|
export async function getThreadState(connector, chatId) {
|
|
4
20
|
const em = getEm().fork();
|
|
5
21
|
const row = (await em.findOne('_ThreadState', { connector, chat_id: chatId }));
|
|
6
22
|
if (!row)
|
|
7
23
|
return { ...EMPTY };
|
|
8
|
-
return
|
|
24
|
+
return toSelection(row);
|
|
25
|
+
}
|
|
26
|
+
export async function getThreadStates(connector, chatIds) {
|
|
27
|
+
if (chatIds.length === 0)
|
|
28
|
+
return new Map();
|
|
29
|
+
const em = getEm().fork();
|
|
30
|
+
const rows = (await em.find('_ThreadState', { connector, chat_id: { $in: chatIds } }));
|
|
31
|
+
return new Map(rows.map((row) => [row.chat_id, toSelection(row)]));
|
|
9
32
|
}
|
|
10
33
|
export async function setThreadState(connector, chatId, patch) {
|
|
11
34
|
const em = getEm().fork();
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
35
|
+
const data = { updated_at: new Date().toISOString() };
|
|
36
|
+
if ('agentId' in patch)
|
|
37
|
+
data['agent_id'] = patch.agentId ?? null;
|
|
38
|
+
if ('presetId' in patch)
|
|
39
|
+
data['preset_id'] = patch.presetId ?? null;
|
|
40
|
+
if ('title' in patch)
|
|
41
|
+
data['title'] = patch.title ? capTitle(patch.title) : null;
|
|
42
|
+
if ('owner' in patch)
|
|
43
|
+
data['owner'] = patch.owner ?? null;
|
|
44
|
+
if ('visibility' in patch)
|
|
45
|
+
data['visibility'] = patch.visibility ?? null;
|
|
17
46
|
const existing = await em.findOne('_ThreadState', { connector, chat_id: chatId });
|
|
18
|
-
const data = { agent_id: next.agentId, preset_id: next.presetId, updated_at: new Date().toISOString() };
|
|
19
47
|
if (existing) {
|
|
20
48
|
em.assign(existing, data);
|
|
21
49
|
}
|
|
22
50
|
else {
|
|
23
|
-
em.persist(em.create('_ThreadState', {
|
|
51
|
+
em.persist(em.create('_ThreadState', {
|
|
52
|
+
connector,
|
|
53
|
+
chat_id: chatId,
|
|
54
|
+
agent_id: data['agent_id'] ?? null,
|
|
55
|
+
preset_id: data['preset_id'] ?? null,
|
|
56
|
+
title: data['title'] ?? null,
|
|
57
|
+
owner: data['owner'] ?? null,
|
|
58
|
+
visibility: data['visibility'] ?? null,
|
|
59
|
+
updated_at: data['updated_at'],
|
|
60
|
+
}));
|
|
24
61
|
}
|
|
25
62
|
await em.flush();
|
|
26
63
|
}
|
|
@@ -31,9 +68,32 @@ export async function readAndTouchThreadState(connector, chatId) {
|
|
|
31
68
|
return { ...EMPTY };
|
|
32
69
|
em.assign(row, { updated_at: new Date().toISOString() });
|
|
33
70
|
await em.flush();
|
|
34
|
-
return
|
|
71
|
+
return toSelection(row);
|
|
72
|
+
}
|
|
73
|
+
export async function findChatByConvId(connector, convId) {
|
|
74
|
+
const suffix = `:${convId}`;
|
|
75
|
+
const em = getEm().fork();
|
|
76
|
+
const like = { $like: `%${suffix}` };
|
|
77
|
+
const stateRows = (await em.find('_ThreadState', { connector, chat_id: like }));
|
|
78
|
+
const stateMatches = matchingChatIds(stateRows, suffix);
|
|
79
|
+
if (stateMatches.length > 0)
|
|
80
|
+
return pickUnambiguous(stateMatches, connector, convId);
|
|
81
|
+
const messageRows = (await em.find('_ThreadMessage', { connector, chat_id: like }));
|
|
82
|
+
const messageMatches = matchingChatIds(messageRows, suffix);
|
|
83
|
+
return pickUnambiguous(messageMatches, connector, convId);
|
|
84
|
+
}
|
|
85
|
+
function matchingChatIds(rows, suffix) {
|
|
86
|
+
return [...new Set(rows.map((r) => r.chat_id).filter((id) => id.endsWith(suffix)))];
|
|
87
|
+
}
|
|
88
|
+
function pickUnambiguous(matches, connector, convId) {
|
|
89
|
+
if (matches.length === 0)
|
|
90
|
+
return { found: 'none' };
|
|
91
|
+
if (matches.length === 1)
|
|
92
|
+
return { found: 'one', chatId: matches[0] };
|
|
93
|
+
log.warn(`ambiguous convId "${convId}" for connector "${connector}": ${matches.length} chats match`);
|
|
94
|
+
return { found: 'ambiguous' };
|
|
35
95
|
}
|
|
36
96
|
export async function pruneThreadState(connector, cutoffIso) {
|
|
37
97
|
const em = getEm().fork();
|
|
38
|
-
await em.nativeDelete('_ThreadState', { connector, updated_at: { $lt: cutoffIso } });
|
|
98
|
+
await em.nativeDelete('_ThreadState', { connector, updated_at: { $lt: cutoffIso }, owner: null, visibility: null });
|
|
39
99
|
}
|
package/dist/thread-store.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
export declare const HIDDEN_ROLES: readonly ["reasoning", "suggestions", "context"];
|
|
1
2
|
export declare const SIDECAR_ROLES: readonly ["reasoning", "suggestions"];
|
|
2
3
|
export interface StoredMsg {
|
|
3
4
|
msgId: string;
|
|
4
|
-
role: 'user' | 'assistant' | 'reasoning' | 'suggestions';
|
|
5
|
+
role: 'user' | 'assistant' | 'reasoning' | 'suggestions' | 'context';
|
|
5
6
|
sender: string | null;
|
|
6
7
|
text: string;
|
|
7
8
|
attachments?: StoredAttachment[];
|
|
@@ -25,7 +26,7 @@ export declare function putThreadMessage(m: {
|
|
|
25
26
|
connector: string;
|
|
26
27
|
chatId: string;
|
|
27
28
|
msgId: string;
|
|
28
|
-
role: 'user' | 'assistant' | 'reasoning' | 'suggestions';
|
|
29
|
+
role: 'user' | 'assistant' | 'reasoning' | 'suggestions' | 'context';
|
|
29
30
|
sender?: string | null;
|
|
30
31
|
attachments?: StoredAttachment[];
|
|
31
32
|
text: string;
|
|
@@ -34,4 +35,5 @@ export declare function putThreadMessage(m: {
|
|
|
34
35
|
}): Promise<void>;
|
|
35
36
|
export declare function pruneThreadMessages(connector: string, cutoffTs: number): Promise<void>;
|
|
36
37
|
export declare function listThreadMessages(connector: string, chatId: string, limit?: number): Promise<StoredMsg[]>;
|
|
37
|
-
export declare function
|
|
38
|
+
export declare function countUserTurns(connector: string, chatId: string): Promise<number>;
|
|
39
|
+
export declare function listAllThreadChats(connector: string): Promise<ThreadChat[]>;
|
package/dist/thread-store.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getEm } from "./db.js";
|
|
2
|
+
export const HIDDEN_ROLES = ['reasoning', 'suggestions', 'context'];
|
|
2
3
|
export const SIDECAR_ROLES = ['reasoning', 'suggestions'];
|
|
3
4
|
function toStored(r) {
|
|
4
5
|
let attachments;
|
|
@@ -50,7 +51,7 @@ export async function pruneThreadMessages(connector, cutoffTs) {
|
|
|
50
51
|
}
|
|
51
52
|
export async function listThreadMessages(connector, chatId, limit = 200) {
|
|
52
53
|
const em = getEm().fork();
|
|
53
|
-
const visible = (await em.find('_ThreadMessage', { connector, chat_id: chatId, role: { $nin:
|
|
54
|
+
const visible = (await em.find('_ThreadMessage', { connector, chat_id: chatId, role: { $nin: HIDDEN_ROLES } }, { orderBy: { ts: 'desc', msg_id: 'desc' }, limit }));
|
|
54
55
|
const oldest = visible.at(-1)?.ts;
|
|
55
56
|
const sidecars = oldest === undefined
|
|
56
57
|
? []
|
|
@@ -60,17 +61,14 @@ export async function listThreadMessages(connector, chatId, limit = 200) {
|
|
|
60
61
|
.reverse()
|
|
61
62
|
.map(toStored);
|
|
62
63
|
}
|
|
63
|
-
export async function
|
|
64
|
+
export async function countUserTurns(connector, chatId) {
|
|
64
65
|
const em = getEm().fork();
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const last = chatIdPrefix.charCodeAt(chatIdPrefix.length - 1);
|
|
69
|
-
const upper = chatIdPrefix.slice(0, -1) + String.fromCharCode(last + 1);
|
|
70
|
-
const rows = (await em.find('_ThreadMessage', { connector, chat_id: { $gte: chatIdPrefix, $lt: upper } }, { orderBy: { ts: 'asc' } }));
|
|
66
|
+
return em.count('_ThreadMessage', { connector, chat_id: chatId, role: 'user' });
|
|
67
|
+
}
|
|
68
|
+
function groupIntoChats(rows) {
|
|
71
69
|
const byChat = new Map();
|
|
72
70
|
for (const r of rows) {
|
|
73
|
-
if (
|
|
71
|
+
if (HIDDEN_ROLES.includes(r.role))
|
|
74
72
|
continue;
|
|
75
73
|
const cur = byChat.get(r.chat_id);
|
|
76
74
|
if (!cur) {
|
|
@@ -90,3 +88,8 @@ export async function listThreadChats(connector, chatIdPrefix) {
|
|
|
90
88
|
}
|
|
91
89
|
return [...byChat.values()].sort((a, b) => b.lastTs - a.lastTs);
|
|
92
90
|
}
|
|
91
|
+
export async function listAllThreadChats(connector) {
|
|
92
|
+
const em = getEm().fork();
|
|
93
|
+
const rows = (await em.find('_ThreadMessage', { connector }, { orderBy: { ts: 'asc' } }));
|
|
94
|
+
return groupIntoChats(rows);
|
|
95
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface BeginTurnOpts {
|
|
2
|
+
supersede: boolean;
|
|
3
|
+
}
|
|
4
|
+
export declare function beginTurn(connector: string, chatId: string, opts: BeginTurnOpts): Promise<{
|
|
5
|
+
signal: AbortSignal;
|
|
6
|
+
end(): void;
|
|
7
|
+
}>;
|
|
8
|
+
export declare function abortTurn(connector: string, chatId: string): boolean;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const turns = new Map();
|
|
2
|
+
function turnKey(connector, chatId) {
|
|
3
|
+
return `${connector}\0${chatId}`;
|
|
4
|
+
}
|
|
5
|
+
export async function beginTurn(connector, chatId, opts) {
|
|
6
|
+
const key = turnKey(connector, chatId);
|
|
7
|
+
const previous = turns.get(key);
|
|
8
|
+
const controller = new AbortController();
|
|
9
|
+
let resolveDone;
|
|
10
|
+
const done = new Promise((resolve) => {
|
|
11
|
+
resolveDone = resolve;
|
|
12
|
+
});
|
|
13
|
+
const turn = { controller, done };
|
|
14
|
+
turns.set(key, turn);
|
|
15
|
+
if (previous) {
|
|
16
|
+
if (opts.supersede)
|
|
17
|
+
previous.controller.abort();
|
|
18
|
+
await previous.done;
|
|
19
|
+
}
|
|
20
|
+
let ended = false;
|
|
21
|
+
return {
|
|
22
|
+
signal: controller.signal,
|
|
23
|
+
end() {
|
|
24
|
+
if (ended)
|
|
25
|
+
return;
|
|
26
|
+
ended = true;
|
|
27
|
+
if (turns.get(key) === turn)
|
|
28
|
+
turns.delete(key);
|
|
29
|
+
resolveDone();
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export function abortTurn(connector, chatId) {
|
|
34
|
+
const turn = turns.get(turnKey(connector, chatId));
|
|
35
|
+
if (!turn)
|
|
36
|
+
return false;
|
|
37
|
+
turn.controller.abort();
|
|
38
|
+
return true;
|
|
39
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coffer-org/server",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.4.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=24"
|
|
@@ -17,6 +17,10 @@
|
|
|
17
17
|
"types": "./dist/orchestrator/index.d.ts",
|
|
18
18
|
"default": "./dist/orchestrator/index.js"
|
|
19
19
|
},
|
|
20
|
+
"./media": {
|
|
21
|
+
"types": "./dist/media/index.d.ts",
|
|
22
|
+
"default": "./dist/media/index.js"
|
|
23
|
+
},
|
|
20
24
|
"./mcp": {
|
|
21
25
|
"types": "./dist/mcp-contract/tools.d.ts",
|
|
22
26
|
"default": "./dist/mcp-contract/tools.js"
|
|
@@ -36,7 +40,7 @@
|
|
|
36
40
|
"postpack": "node ../../scripts/swap-exports.mjs src"
|
|
37
41
|
},
|
|
38
42
|
"dependencies": {
|
|
39
|
-
"@coffer-org/sdk": "^7.
|
|
43
|
+
"@coffer-org/sdk": "^7.4.0",
|
|
40
44
|
"@extractus/oembed-extractor": "^4.1.0",
|
|
41
45
|
"@fastify/cors": "^11.2.0",
|
|
42
46
|
"@fastify/multipart": "^10.0.0",
|
|
@@ -48,6 +52,7 @@
|
|
|
48
52
|
"open-graph-scraper": "^6.11.0",
|
|
49
53
|
"pino": "^9.14.0",
|
|
50
54
|
"pino-pretty": "^13.1.3",
|
|
55
|
+
"sharp": "^0.35.4",
|
|
51
56
|
"zod": "^4.4.3"
|
|
52
57
|
},
|
|
53
58
|
"optionalDependencies": {
|