@soulcraft/sdk 1.6.2 → 2.0.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/client/create-client-sdk.d.ts +16 -2
- package/dist/client/create-client-sdk.d.ts.map +1 -1
- package/dist/client/create-client-sdk.js +2 -7
- package/dist/client/create-client-sdk.js.map +1 -1
- package/dist/client/index.d.ts +48 -37
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +61 -42
- package/dist/client/index.js.map +1 -1
- package/dist/client/namespace-proxy.d.ts +108 -0
- package/dist/client/namespace-proxy.d.ts.map +1 -0
- package/dist/client/namespace-proxy.js +151 -0
- package/dist/client/namespace-proxy.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/modules/app-context/index.d.ts +214 -0
- package/dist/modules/app-context/index.d.ts.map +1 -0
- package/dist/modules/app-context/index.js +569 -0
- package/dist/modules/app-context/index.js.map +1 -0
- package/dist/modules/auth/products.d.ts +208 -0
- package/dist/modules/auth/products.d.ts.map +1 -0
- package/dist/modules/auth/products.js +165 -0
- package/dist/modules/auth/products.js.map +1 -0
- package/dist/namespaces.d.ts +2942 -0
- package/dist/namespaces.d.ts.map +1 -0
- package/dist/namespaces.js +37 -0
- package/dist/namespaces.js.map +1 -0
- package/dist/rpc.d.ts +156 -0
- package/dist/rpc.d.ts.map +1 -0
- package/dist/rpc.js +26 -0
- package/dist/rpc.js.map +1 -0
- package/dist/server/create-sdk.d.ts.map +1 -1
- package/dist/server/create-sdk.js +3 -13
- package/dist/server/create-sdk.js.map +1 -1
- package/dist/server/handlers/annotations.d.ts +52 -0
- package/dist/server/handlers/annotations.d.ts.map +1 -0
- package/dist/server/handlers/annotations.js +204 -0
- package/dist/server/handlers/annotations.js.map +1 -0
- package/dist/server/handlers/auth.d.ts +53 -0
- package/dist/server/handlers/auth.d.ts.map +1 -0
- package/dist/server/handlers/auth.js +66 -0
- package/dist/server/handlers/auth.js.map +1 -0
- package/dist/server/handlers/certification.d.ts +32 -0
- package/dist/server/handlers/certification.d.ts.map +1 -0
- package/dist/server/handlers/certification.js +253 -0
- package/dist/server/handlers/certification.js.map +1 -0
- package/dist/server/handlers/chat/conversations.d.ts +91 -0
- package/dist/server/handlers/chat/conversations.d.ts.map +1 -0
- package/dist/server/handlers/chat/conversations.js +314 -0
- package/dist/server/handlers/chat/conversations.js.map +1 -0
- package/dist/server/handlers/chat/delegator.d.ts +144 -0
- package/dist/server/handlers/chat/delegator.d.ts.map +1 -0
- package/dist/server/handlers/chat/delegator.js +431 -0
- package/dist/server/handlers/chat/delegator.js.map +1 -0
- package/dist/server/handlers/chat/engine.d.ts +81 -0
- package/dist/server/handlers/chat/engine.d.ts.map +1 -0
- package/dist/server/handlers/chat/engine.js +442 -0
- package/dist/server/handlers/chat/engine.js.map +1 -0
- package/dist/server/handlers/chat/executor.d.ts +65 -0
- package/dist/server/handlers/chat/executor.d.ts.map +1 -0
- package/dist/server/handlers/chat/executor.js +375 -0
- package/dist/server/handlers/chat/executor.js.map +1 -0
- package/dist/server/handlers/chat/index.d.ts +62 -0
- package/dist/server/handlers/chat/index.d.ts.map +1 -0
- package/dist/server/handlers/chat/index.js +182 -0
- package/dist/server/handlers/chat/index.js.map +1 -0
- package/dist/server/handlers/chat/memory.d.ts +91 -0
- package/dist/server/handlers/chat/memory.d.ts.map +1 -0
- package/dist/server/handlers/chat/memory.js +293 -0
- package/dist/server/handlers/chat/memory.js.map +1 -0
- package/dist/server/handlers/chat/models.d.ts +180 -0
- package/dist/server/handlers/chat/models.d.ts.map +1 -0
- package/dist/server/handlers/chat/models.js +304 -0
- package/dist/server/handlers/chat/models.js.map +1 -0
- package/dist/server/handlers/chat/planner.d.ts +116 -0
- package/dist/server/handlers/chat/planner.d.ts.map +1 -0
- package/dist/server/handlers/chat/planner.js +344 -0
- package/dist/server/handlers/chat/planner.js.map +1 -0
- package/dist/server/handlers/chat/types.d.ts +500 -0
- package/dist/server/handlers/chat/types.d.ts.map +1 -0
- package/dist/server/handlers/chat/types.js +11 -0
- package/dist/server/handlers/chat/types.js.map +1 -0
- package/dist/server/handlers/collections.d.ts +67 -0
- package/dist/server/handlers/collections.d.ts.map +1 -0
- package/dist/server/handlers/collections.js +484 -0
- package/dist/server/handlers/collections.js.map +1 -0
- package/dist/server/handlers/commerce.d.ts +106 -0
- package/dist/server/handlers/commerce.d.ts.map +1 -0
- package/dist/server/handlers/commerce.js +62 -0
- package/dist/server/handlers/commerce.js.map +1 -0
- package/dist/server/handlers/config.d.ts +112 -0
- package/dist/server/handlers/config.d.ts.map +1 -0
- package/dist/server/handlers/config.js +122 -0
- package/dist/server/handlers/config.js.map +1 -0
- package/dist/server/handlers/export.d.ts +72 -0
- package/dist/server/handlers/export.d.ts.map +1 -0
- package/dist/server/handlers/export.js +175 -0
- package/dist/server/handlers/export.js.map +1 -0
- package/dist/server/handlers/formats.d.ts +77 -0
- package/dist/server/handlers/formats.d.ts.map +1 -0
- package/dist/server/handlers/formats.js +65 -0
- package/dist/server/handlers/formats.js.map +1 -0
- package/dist/server/handlers/graph.d.ts +31 -0
- package/dist/server/handlers/graph.d.ts.map +1 -0
- package/dist/server/handlers/graph.js +490 -0
- package/dist/server/handlers/graph.js.map +1 -0
- package/dist/server/handlers/import.d.ts +96 -0
- package/dist/server/handlers/import.d.ts.map +1 -0
- package/dist/server/handlers/import.js +108 -0
- package/dist/server/handlers/import.js.map +1 -0
- package/dist/server/handlers/index.d.ts +68 -0
- package/dist/server/handlers/index.d.ts.map +1 -0
- package/dist/server/handlers/index.js +71 -0
- package/dist/server/handlers/index.js.map +1 -0
- package/dist/server/handlers/media.d.ts +76 -0
- package/dist/server/handlers/media.d.ts.map +1 -0
- package/dist/server/handlers/media.js +53 -0
- package/dist/server/handlers/media.js.map +1 -0
- package/dist/server/handlers/project.d.ts +45 -0
- package/dist/server/handlers/project.d.ts.map +1 -0
- package/dist/server/handlers/project.js +181 -0
- package/dist/server/handlers/project.js.map +1 -0
- package/dist/server/handlers/publish.d.ts +102 -0
- package/dist/server/handlers/publish.d.ts.map +1 -0
- package/dist/server/handlers/publish.js +130 -0
- package/dist/server/handlers/publish.js.map +1 -0
- package/dist/server/handlers/pulse.d.ts +39 -0
- package/dist/server/handlers/pulse.d.ts.map +1 -0
- package/dist/server/handlers/pulse.js +78 -0
- package/dist/server/handlers/pulse.js.map +1 -0
- package/dist/server/handlers/realtime.d.ts +55 -0
- package/dist/server/handlers/realtime.d.ts.map +1 -0
- package/dist/server/handlers/realtime.js +49 -0
- package/dist/server/handlers/realtime.js.map +1 -0
- package/dist/server/handlers/search.d.ts +21 -0
- package/dist/server/handlers/search.d.ts.map +1 -0
- package/dist/server/handlers/search.js +237 -0
- package/dist/server/handlers/search.js.map +1 -0
- package/dist/server/handlers/session.d.ts +47 -0
- package/dist/server/handlers/session.d.ts.map +1 -0
- package/dist/server/handlers/session.js +286 -0
- package/dist/server/handlers/session.js.map +1 -0
- package/dist/server/handlers/settings.d.ts +97 -0
- package/dist/server/handlers/settings.d.ts.map +1 -0
- package/dist/server/handlers/settings.js +131 -0
- package/dist/server/handlers/settings.js.map +1 -0
- package/dist/server/handlers/workspace.d.ts +78 -0
- package/dist/server/handlers/workspace.d.ts.map +1 -0
- package/dist/server/handlers/workspace.js +270 -0
- package/dist/server/handlers/workspace.js.map +1 -0
- package/dist/server/hono-router.d.ts +66 -0
- package/dist/server/hono-router.d.ts.map +1 -0
- package/dist/server/hono-router.js +203 -0
- package/dist/server/hono-router.js.map +1 -0
- package/dist/server/index.d.ts +29 -19
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +33 -19
- package/dist/server/index.js.map +1 -1
- package/dist/server/namespace-router.d.ts +204 -0
- package/dist/server/namespace-router.d.ts.map +1 -0
- package/dist/server/namespace-router.js +262 -0
- package/dist/server/namespace-router.js.map +1 -0
- package/dist/transports/http-namespace.d.ts +210 -0
- package/dist/transports/http-namespace.d.ts.map +1 -0
- package/dist/transports/http-namespace.js +514 -0
- package/dist/transports/http-namespace.js.map +1 -0
- package/dist/transports/workshop.d.ts +173 -0
- package/dist/transports/workshop.d.ts.map +1 -0
- package/dist/transports/workshop.js +307 -0
- package/dist/transports/workshop.js.map +1 -0
- package/dist/types.d.ts +65 -67
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +7 -3
- package/dist/types.js.map +1 -1
- package/docs/ADR-004-product-registry.md +108 -0
- package/package.json +1 -1
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module server/handlers/chat/memory
|
|
3
|
+
* @description Proactive memory retrieval, conversation learning, and user
|
|
4
|
+
* expertise profiling.
|
|
5
|
+
*
|
|
6
|
+
* The memory system gives the AI long-term recall by:
|
|
7
|
+
* 1. **Retrieving** relevant past conversations, preferences, entities, and
|
|
8
|
+
* insights before each new message (proactive context enrichment).
|
|
9
|
+
* 2. **Learning** from completed conversations — extracting insights and
|
|
10
|
+
* updating the user's expertise profile.
|
|
11
|
+
*
|
|
12
|
+
* All operations use Brainy's semantic search and entity graph — no external
|
|
13
|
+
* vector DB needed.
|
|
14
|
+
*/
|
|
15
|
+
import type { Brainy } from '@soulcraft/brainy';
|
|
16
|
+
import type { RetrievedMemory, UserExpertiseProfile } from './types.js';
|
|
17
|
+
/**
|
|
18
|
+
* Retrieve memory items relevant to the current user message.
|
|
19
|
+
*
|
|
20
|
+
* Performs four parallel semantic searches:
|
|
21
|
+
* 1. Past conversation fragments matching the message
|
|
22
|
+
* 2. User preferences stored as entities
|
|
23
|
+
* 3. Knowledge graph entities related to the message
|
|
24
|
+
* 4. Insights derived from past conversations
|
|
25
|
+
*
|
|
26
|
+
* @param brain - Brainy instance with the user's knowledge graph.
|
|
27
|
+
* @param userMessage - The current message to find relevant context for.
|
|
28
|
+
* @returns Retrieved memory items grouped by type, or null on failure.
|
|
29
|
+
*/
|
|
30
|
+
export declare function retrieveRelevantMemory(brain: Brainy, userMessage: string): Promise<RetrievedMemory | null>;
|
|
31
|
+
/**
|
|
32
|
+
* Learn from a completed conversation — extract insights and patterns.
|
|
33
|
+
*
|
|
34
|
+
* Analyzes the conversation messages to identify:
|
|
35
|
+
* - Topics discussed
|
|
36
|
+
* - User preferences expressed
|
|
37
|
+
* - Decisions made
|
|
38
|
+
* - Knowledge gaps identified
|
|
39
|
+
*
|
|
40
|
+
* Stores insights as entities for future memory retrieval.
|
|
41
|
+
*
|
|
42
|
+
* @param brain - Brainy instance.
|
|
43
|
+
* @param conversationId - Conversation to learn from.
|
|
44
|
+
* @param messages - The conversation messages.
|
|
45
|
+
* @returns Number of insights stored.
|
|
46
|
+
*/
|
|
47
|
+
export declare function learnFromConversation(brain: Brainy, conversationId: string, messages: Array<{
|
|
48
|
+
role: string;
|
|
49
|
+
content: string;
|
|
50
|
+
}>): Promise<{
|
|
51
|
+
insightsStored: number;
|
|
52
|
+
}>;
|
|
53
|
+
/**
|
|
54
|
+
* Load the user's expertise profile from Brainy.
|
|
55
|
+
*
|
|
56
|
+
* The profile is stored as a single entity with `_aiDataType: 'expertise_profile'`.
|
|
57
|
+
* If no profile exists, returns the default profile.
|
|
58
|
+
*
|
|
59
|
+
* @param brain - Brainy instance.
|
|
60
|
+
* @returns The user's expertise profile.
|
|
61
|
+
*/
|
|
62
|
+
export declare function loadUserExpertiseProfile(brain: Brainy): Promise<UserExpertiseProfile>;
|
|
63
|
+
/**
|
|
64
|
+
* Update the user's expertise profile based on recent conversation.
|
|
65
|
+
*
|
|
66
|
+
* Analyzes message patterns to detect:
|
|
67
|
+
* - Technical vocabulary usage → adjust technicalLevel
|
|
68
|
+
* - Question patterns → identify growth areas
|
|
69
|
+
* - Confident statements → identify strong areas
|
|
70
|
+
*
|
|
71
|
+
* @param brain - Brainy instance.
|
|
72
|
+
* @param messages - Recent conversation messages.
|
|
73
|
+
* @returns Whether the profile was updated.
|
|
74
|
+
*/
|
|
75
|
+
export declare function updateUserExpertiseProfile(brain: Brainy, messages: Array<{
|
|
76
|
+
role: string;
|
|
77
|
+
content: string;
|
|
78
|
+
}>): Promise<{
|
|
79
|
+
profileUpdated: boolean;
|
|
80
|
+
}>;
|
|
81
|
+
/**
|
|
82
|
+
* Generate system prompt additions based on the user's expertise profile.
|
|
83
|
+
*
|
|
84
|
+
* Adapts the AI's communication style to match the user's demonstrated
|
|
85
|
+
* knowledge level.
|
|
86
|
+
*
|
|
87
|
+
* @param profile - The user's expertise profile.
|
|
88
|
+
* @returns A prompt fragment to append to the system prompt, or empty string.
|
|
89
|
+
*/
|
|
90
|
+
export declare function generateExpertisePromptAdditions(profile: UserExpertiseProfile): string;
|
|
91
|
+
//# sourceMappingURL=memory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../../../src/server/handlers/chat/memory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,KAAK,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAMvE;;;;;;;;;;;;GAYG;AACH,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CA8DjC;AAMD;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,MAAM,EACb,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,GACjD,OAAO,CAAC;IAAE,cAAc,EAAE,MAAM,CAAA;CAAE,CAAC,CAsDrC;AAgBD;;;;;;;;GAQG;AACH,wBAAsB,wBAAwB,CAC5C,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,oBAAoB,CAAC,CAuB/B;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,0BAA0B,CAC9C,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,GACjD,OAAO,CAAC;IAAE,cAAc,EAAE,OAAO,CAAA;CAAE,CAAC,CA0DtC;AAED;;;;;;;;GAQG;AACH,wBAAgB,gCAAgC,CAC9C,OAAO,EAAE,oBAAoB,GAC5B,MAAM,CAoBR"}
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module server/handlers/chat/memory
|
|
3
|
+
* @description Proactive memory retrieval, conversation learning, and user
|
|
4
|
+
* expertise profiling.
|
|
5
|
+
*
|
|
6
|
+
* The memory system gives the AI long-term recall by:
|
|
7
|
+
* 1. **Retrieving** relevant past conversations, preferences, entities, and
|
|
8
|
+
* insights before each new message (proactive context enrichment).
|
|
9
|
+
* 2. **Learning** from completed conversations — extracting insights and
|
|
10
|
+
* updating the user's expertise profile.
|
|
11
|
+
*
|
|
12
|
+
* All operations use Brainy's semantic search and entity graph — no external
|
|
13
|
+
* vector DB needed.
|
|
14
|
+
*/
|
|
15
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
16
|
+
// Memory Retrieval
|
|
17
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
18
|
+
/**
|
|
19
|
+
* Retrieve memory items relevant to the current user message.
|
|
20
|
+
*
|
|
21
|
+
* Performs four parallel semantic searches:
|
|
22
|
+
* 1. Past conversation fragments matching the message
|
|
23
|
+
* 2. User preferences stored as entities
|
|
24
|
+
* 3. Knowledge graph entities related to the message
|
|
25
|
+
* 4. Insights derived from past conversations
|
|
26
|
+
*
|
|
27
|
+
* @param brain - Brainy instance with the user's knowledge graph.
|
|
28
|
+
* @param userMessage - The current message to find relevant context for.
|
|
29
|
+
* @returns Retrieved memory items grouped by type, or null on failure.
|
|
30
|
+
*/
|
|
31
|
+
export async function retrieveRelevantMemory(brain, userMessage) {
|
|
32
|
+
try {
|
|
33
|
+
const [conversations, preferences, relatedEntities, insights] = await Promise.all([
|
|
34
|
+
// Past conversation fragments
|
|
35
|
+
brain.find({
|
|
36
|
+
query: userMessage,
|
|
37
|
+
where: { _aiDataType: { equals: 'message' } },
|
|
38
|
+
limit: 5,
|
|
39
|
+
}).then((results) => results.map((r) => ({
|
|
40
|
+
content: r.data?.content || r.data || '',
|
|
41
|
+
timestamp: r.data?.timestamp || r.metadata?.createdAt || '',
|
|
42
|
+
}))).catch(() => []),
|
|
43
|
+
// User preferences
|
|
44
|
+
brain.find({
|
|
45
|
+
where: { _aiDataType: { equals: 'preference' } },
|
|
46
|
+
limit: 10,
|
|
47
|
+
}).then((results) => results.map((r) => ({
|
|
48
|
+
key: r.data?.key || r.metadata?.name || '',
|
|
49
|
+
value: r.data?.value || r.data?.content || '',
|
|
50
|
+
}))).catch(() => []),
|
|
51
|
+
// Related knowledge graph entities
|
|
52
|
+
brain.find({
|
|
53
|
+
query: userMessage,
|
|
54
|
+
limit: 10,
|
|
55
|
+
excludeVFS: true,
|
|
56
|
+
}).then((results) => results
|
|
57
|
+
.filter((r) => {
|
|
58
|
+
const dt = r.metadata?._aiDataType;
|
|
59
|
+
return dt !== 'conversation' && dt !== 'message';
|
|
60
|
+
})
|
|
61
|
+
.slice(0, 5)
|
|
62
|
+
.map((r) => ({
|
|
63
|
+
id: r.id,
|
|
64
|
+
name: r.metadata?.name || r.data?.name || String(r.data || '').slice(0, 50),
|
|
65
|
+
type: r.type || r.metadata?.noun || 'concept',
|
|
66
|
+
}))).catch(() => []),
|
|
67
|
+
// Insights from past conversations
|
|
68
|
+
brain.find({
|
|
69
|
+
where: { _aiDataType: { equals: 'insight' } },
|
|
70
|
+
query: userMessage,
|
|
71
|
+
limit: 5,
|
|
72
|
+
}).then((results) => results.map((r) => ({
|
|
73
|
+
content: r.data?.content || r.data || '',
|
|
74
|
+
confidence: r.data?.confidence ?? r.metadata?.confidence ?? 0.5,
|
|
75
|
+
}))).catch(() => []),
|
|
76
|
+
]);
|
|
77
|
+
return { conversations, preferences, relatedEntities, insights };
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
84
|
+
// Learning
|
|
85
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
86
|
+
/**
|
|
87
|
+
* Learn from a completed conversation — extract insights and patterns.
|
|
88
|
+
*
|
|
89
|
+
* Analyzes the conversation messages to identify:
|
|
90
|
+
* - Topics discussed
|
|
91
|
+
* - User preferences expressed
|
|
92
|
+
* - Decisions made
|
|
93
|
+
* - Knowledge gaps identified
|
|
94
|
+
*
|
|
95
|
+
* Stores insights as entities for future memory retrieval.
|
|
96
|
+
*
|
|
97
|
+
* @param brain - Brainy instance.
|
|
98
|
+
* @param conversationId - Conversation to learn from.
|
|
99
|
+
* @param messages - The conversation messages.
|
|
100
|
+
* @returns Number of insights stored.
|
|
101
|
+
*/
|
|
102
|
+
export async function learnFromConversation(brain, conversationId, messages) {
|
|
103
|
+
if (messages.length < 2)
|
|
104
|
+
return { insightsStored: 0 };
|
|
105
|
+
// Extract user messages for topic analysis
|
|
106
|
+
const userMessages = messages
|
|
107
|
+
.filter(m => m.role === 'user')
|
|
108
|
+
.map(m => m.content);
|
|
109
|
+
if (userMessages.length === 0)
|
|
110
|
+
return { insightsStored: 0 };
|
|
111
|
+
// Simple keyword extraction for topics (no AI call needed)
|
|
112
|
+
const allText = userMessages.join(' ').toLowerCase();
|
|
113
|
+
const words = allText.split(/\s+/);
|
|
114
|
+
const wordFreq = new Map();
|
|
115
|
+
for (const word of words) {
|
|
116
|
+
if (word.length < 4)
|
|
117
|
+
continue;
|
|
118
|
+
wordFreq.set(word, (wordFreq.get(word) || 0) + 1);
|
|
119
|
+
}
|
|
120
|
+
// Find repeated topics (mentioned 2+ times)
|
|
121
|
+
const topics = [...wordFreq.entries()]
|
|
122
|
+
.filter(([, count]) => count >= 2)
|
|
123
|
+
.sort((a, b) => b[1] - a[1])
|
|
124
|
+
.slice(0, 5)
|
|
125
|
+
.map(([word]) => word);
|
|
126
|
+
if (topics.length === 0)
|
|
127
|
+
return { insightsStored: 0 };
|
|
128
|
+
// Store a conversation summary insight
|
|
129
|
+
let insightsStored = 0;
|
|
130
|
+
try {
|
|
131
|
+
await brain.add({
|
|
132
|
+
type: 'event',
|
|
133
|
+
data: {
|
|
134
|
+
content: `User discussed: ${topics.join(', ')}`,
|
|
135
|
+
topics,
|
|
136
|
+
messageCount: messages.length,
|
|
137
|
+
conversationId,
|
|
138
|
+
timestamp: new Date().toISOString(),
|
|
139
|
+
},
|
|
140
|
+
metadata: {
|
|
141
|
+
name: `Conversation insight: ${topics.slice(0, 3).join(', ')}`,
|
|
142
|
+
isAIManaged: true,
|
|
143
|
+
_aiDataType: 'insight',
|
|
144
|
+
confidence: 0.6,
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
insightsStored++;
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
// Non-fatal
|
|
151
|
+
}
|
|
152
|
+
return { insightsStored };
|
|
153
|
+
}
|
|
154
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
155
|
+
// Expertise Profile
|
|
156
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
157
|
+
/** Default expertise profile for new users. */
|
|
158
|
+
const DEFAULT_PROFILE = {
|
|
159
|
+
strongAreas: [],
|
|
160
|
+
growthAreas: [],
|
|
161
|
+
technicalLevel: 3,
|
|
162
|
+
preferredDetailLevel: 3,
|
|
163
|
+
communicationStyle: 'balanced',
|
|
164
|
+
domainExpertise: [],
|
|
165
|
+
};
|
|
166
|
+
/**
|
|
167
|
+
* Load the user's expertise profile from Brainy.
|
|
168
|
+
*
|
|
169
|
+
* The profile is stored as a single entity with `_aiDataType: 'expertise_profile'`.
|
|
170
|
+
* If no profile exists, returns the default profile.
|
|
171
|
+
*
|
|
172
|
+
* @param brain - Brainy instance.
|
|
173
|
+
* @returns The user's expertise profile.
|
|
174
|
+
*/
|
|
175
|
+
export async function loadUserExpertiseProfile(brain) {
|
|
176
|
+
try {
|
|
177
|
+
const results = await brain.find({
|
|
178
|
+
where: { _aiDataType: { equals: 'expertise_profile' } },
|
|
179
|
+
limit: 1,
|
|
180
|
+
});
|
|
181
|
+
if (results.length > 0) {
|
|
182
|
+
const data = results[0].data || {};
|
|
183
|
+
return {
|
|
184
|
+
strongAreas: data.strongAreas || [],
|
|
185
|
+
growthAreas: data.growthAreas || [],
|
|
186
|
+
technicalLevel: data.technicalLevel ?? 3,
|
|
187
|
+
preferredDetailLevel: data.preferredDetailLevel ?? 3,
|
|
188
|
+
communicationStyle: data.communicationStyle || 'balanced',
|
|
189
|
+
domainExpertise: data.domainExpertise || [],
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
catch {
|
|
194
|
+
// Fall through to default
|
|
195
|
+
}
|
|
196
|
+
return { ...DEFAULT_PROFILE };
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Update the user's expertise profile based on recent conversation.
|
|
200
|
+
*
|
|
201
|
+
* Analyzes message patterns to detect:
|
|
202
|
+
* - Technical vocabulary usage → adjust technicalLevel
|
|
203
|
+
* - Question patterns → identify growth areas
|
|
204
|
+
* - Confident statements → identify strong areas
|
|
205
|
+
*
|
|
206
|
+
* @param brain - Brainy instance.
|
|
207
|
+
* @param messages - Recent conversation messages.
|
|
208
|
+
* @returns Whether the profile was updated.
|
|
209
|
+
*/
|
|
210
|
+
export async function updateUserExpertiseProfile(brain, messages) {
|
|
211
|
+
const userMessages = messages.filter(m => m.role === 'user').map(m => m.content);
|
|
212
|
+
if (userMessages.length < 2)
|
|
213
|
+
return { profileUpdated: false };
|
|
214
|
+
const profile = await loadUserExpertiseProfile(brain);
|
|
215
|
+
let changed = false;
|
|
216
|
+
// Simple heuristic: detect technical vocabulary density
|
|
217
|
+
const technicalTerms = [
|
|
218
|
+
'api', 'function', 'async', 'promise', 'interface', 'type', 'class',
|
|
219
|
+
'database', 'query', 'schema', 'deploy', 'runtime', 'algorithm',
|
|
220
|
+
'architecture', 'component', 'module', 'endpoint', 'middleware',
|
|
221
|
+
];
|
|
222
|
+
const allText = userMessages.join(' ').toLowerCase();
|
|
223
|
+
const words = allText.split(/\s+/);
|
|
224
|
+
const techCount = words.filter(w => technicalTerms.includes(w)).length;
|
|
225
|
+
const techDensity = words.length > 0 ? techCount / words.length : 0;
|
|
226
|
+
// Adjust technical level based on vocabulary
|
|
227
|
+
if (techDensity > 0.05 && profile.technicalLevel < 5) {
|
|
228
|
+
profile.technicalLevel = Math.min(5, profile.technicalLevel + 0.5);
|
|
229
|
+
changed = true;
|
|
230
|
+
}
|
|
231
|
+
else if (techDensity < 0.01 && profile.technicalLevel > 1) {
|
|
232
|
+
profile.technicalLevel = Math.max(1, profile.technicalLevel - 0.3);
|
|
233
|
+
changed = true;
|
|
234
|
+
}
|
|
235
|
+
if (!changed)
|
|
236
|
+
return { profileUpdated: false };
|
|
237
|
+
// Persist updated profile
|
|
238
|
+
try {
|
|
239
|
+
const existing = await brain.find({
|
|
240
|
+
where: { _aiDataType: { equals: 'expertise_profile' } },
|
|
241
|
+
limit: 1,
|
|
242
|
+
});
|
|
243
|
+
if (existing.length > 0) {
|
|
244
|
+
await brain.update({
|
|
245
|
+
id: existing[0].id,
|
|
246
|
+
data: profile,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
await brain.add({
|
|
251
|
+
type: 'event',
|
|
252
|
+
data: profile,
|
|
253
|
+
metadata: {
|
|
254
|
+
name: 'User Expertise Profile',
|
|
255
|
+
isAIManaged: true,
|
|
256
|
+
_aiDataType: 'expertise_profile',
|
|
257
|
+
},
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
return { profileUpdated: true };
|
|
261
|
+
}
|
|
262
|
+
catch {
|
|
263
|
+
return { profileUpdated: false };
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Generate system prompt additions based on the user's expertise profile.
|
|
268
|
+
*
|
|
269
|
+
* Adapts the AI's communication style to match the user's demonstrated
|
|
270
|
+
* knowledge level.
|
|
271
|
+
*
|
|
272
|
+
* @param profile - The user's expertise profile.
|
|
273
|
+
* @returns A prompt fragment to append to the system prompt, or empty string.
|
|
274
|
+
*/
|
|
275
|
+
export function generateExpertisePromptAdditions(profile) {
|
|
276
|
+
if (!profile.strongAreas.length && !profile.growthAreas.length)
|
|
277
|
+
return '';
|
|
278
|
+
const parts = [];
|
|
279
|
+
if (profile.technicalLevel >= 4) {
|
|
280
|
+
parts.push('The user is technically advanced — use precise terminology, skip basic explanations.');
|
|
281
|
+
}
|
|
282
|
+
else if (profile.technicalLevel <= 2) {
|
|
283
|
+
parts.push('The user prefers clear, accessible explanations — avoid jargon, use analogies.');
|
|
284
|
+
}
|
|
285
|
+
if (profile.strongAreas.length > 0) {
|
|
286
|
+
parts.push(`Strong areas: ${profile.strongAreas.join(', ')}. Reference these confidently.`);
|
|
287
|
+
}
|
|
288
|
+
if (profile.growthAreas.length > 0) {
|
|
289
|
+
parts.push(`Growth areas: ${profile.growthAreas.join(', ')}. Be more explanatory here.`);
|
|
290
|
+
}
|
|
291
|
+
return parts.join('\n');
|
|
292
|
+
}
|
|
293
|
+
//# sourceMappingURL=memory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../../../../src/server/handlers/chat/memory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module server/handlers/chat/models
|
|
3
|
+
* @description Model routing, complexity analysis, and cost estimation for
|
|
4
|
+
* the tiered AI strategy.
|
|
5
|
+
*
|
|
6
|
+
* The chat engine uses a multi-model approach:
|
|
7
|
+
* - **Plan Mode ON**: Opus (deep analysis, planning) → Haiku (fast execution)
|
|
8
|
+
* - **Plan Mode OFF**: Sonnet (triage, synthesis) → Haiku (task execution)
|
|
9
|
+
*
|
|
10
|
+
* Complexity analysis scores each user message on 6 signals (multi-file ops,
|
|
11
|
+
* architecture keywords, question patterns, single-tool hints, entity count,
|
|
12
|
+
* conditional logic) to decide whether to recommend Plan Mode.
|
|
13
|
+
*
|
|
14
|
+
* All model IDs and pricing are configurable — products can override defaults
|
|
15
|
+
* via the {@link ModelSelector} interface in `types.ts`.
|
|
16
|
+
*/
|
|
17
|
+
import type { TieredRouting, ModelSelector } from './types.js';
|
|
18
|
+
/**
|
|
19
|
+
* Known Claude model configuration with pricing and capabilities.
|
|
20
|
+
*
|
|
21
|
+
* Pricing is per million tokens. Products can extend this with custom model
|
|
22
|
+
* entries via the {@link ModelConfig} type.
|
|
23
|
+
*/
|
|
24
|
+
export interface ModelConfig {
|
|
25
|
+
/** Model identifier sent to the API. */
|
|
26
|
+
id: string;
|
|
27
|
+
/** Display name for logs and UI. */
|
|
28
|
+
name: string;
|
|
29
|
+
/** Short display name for compact UI. */
|
|
30
|
+
shortName: string;
|
|
31
|
+
/** Pricing per million tokens. */
|
|
32
|
+
pricing: {
|
|
33
|
+
input: number;
|
|
34
|
+
output: number;
|
|
35
|
+
cacheHit: number;
|
|
36
|
+
};
|
|
37
|
+
/** Whether this model supports extended thinking. */
|
|
38
|
+
supportsThinking: boolean;
|
|
39
|
+
/** Maximum output tokens. */
|
|
40
|
+
maxTokens: number;
|
|
41
|
+
/** Best use cases for documentation. */
|
|
42
|
+
bestFor: string[];
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Default model catalog — Anthropic Claude models with current pricing.
|
|
46
|
+
*
|
|
47
|
+
* Products can supplement this with additional models. The engine only needs
|
|
48
|
+
* model IDs; it doesn't validate against this catalog at runtime.
|
|
49
|
+
*/
|
|
50
|
+
export declare const DEFAULT_MODELS: Record<string, ModelConfig>;
|
|
51
|
+
/** Default model assignments for each tier role. */
|
|
52
|
+
export declare const DEFAULT_MODEL_TIERS: {
|
|
53
|
+
readonly planner: "claude-opus-4-5-20251101";
|
|
54
|
+
readonly triage: "claude-sonnet-4-20250514";
|
|
55
|
+
readonly executor: "claude-3-5-haiku-latest";
|
|
56
|
+
readonly fallback: "claude-sonnet-4-20250514";
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Signal scores from complexity analysis.
|
|
60
|
+
*
|
|
61
|
+
* Each signal contributes a positive or negative score. The sum determines
|
|
62
|
+
* whether the message warrants plan mode or simple direct handling.
|
|
63
|
+
*/
|
|
64
|
+
export interface ComplexitySignals {
|
|
65
|
+
/** +3 if message mentions multi-file/multi-entity operations. */
|
|
66
|
+
multiFileOperations: number;
|
|
67
|
+
/** +2 if message contains architecture/design keywords. */
|
|
68
|
+
architectureKeywords: number;
|
|
69
|
+
/** -2 if message is a question (read-only, no mutation needed). */
|
|
70
|
+
questionWords: number;
|
|
71
|
+
/** -1 if message implies a single tool call. */
|
|
72
|
+
singleToolImplied: number;
|
|
73
|
+
/** +2 if message references 2+ entities by name. */
|
|
74
|
+
multipleEntities: number;
|
|
75
|
+
/** +2 if message contains conditional/branching logic. */
|
|
76
|
+
conditionalLogic: number;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Analyze a user message's complexity across 6 signal dimensions.
|
|
80
|
+
*
|
|
81
|
+
* @param message - The user's raw message text.
|
|
82
|
+
* @returns Signal scores (sum them for the total complexity score).
|
|
83
|
+
*/
|
|
84
|
+
export declare function analyzeComplexity(message: string): ComplexitySignals;
|
|
85
|
+
/**
|
|
86
|
+
* Sum all signal scores into a single complexity number.
|
|
87
|
+
*
|
|
88
|
+
* @param signals - Complexity signals from {@link analyzeComplexity}.
|
|
89
|
+
* @returns Total score (negative = simple, positive = complex).
|
|
90
|
+
*/
|
|
91
|
+
export declare function calculateComplexityScore(signals: ComplexitySignals): number;
|
|
92
|
+
/**
|
|
93
|
+
* Select the tiered routing strategy for a message.
|
|
94
|
+
*
|
|
95
|
+
* When Plan Mode is ON, uses Opus for planning and Haiku for execution.
|
|
96
|
+
* When OFF, uses Sonnet for triage and Haiku for tasks — and recommends
|
|
97
|
+
* Plan Mode if complexity exceeds the recommendation threshold.
|
|
98
|
+
*
|
|
99
|
+
* @param message - The user's message.
|
|
100
|
+
* @param planModeEnabled - Whether Plan Mode is explicitly enabled by the user.
|
|
101
|
+
* @param modelOverrides - Optional per-tier model overrides.
|
|
102
|
+
* @returns Complete routing decision.
|
|
103
|
+
*/
|
|
104
|
+
export declare function selectTieredRouting(message: string, planModeEnabled: boolean, modelOverrides?: Partial<typeof DEFAULT_MODEL_TIERS>): TieredRouting;
|
|
105
|
+
/**
|
|
106
|
+
* Create the default {@link ModelSelector} implementation.
|
|
107
|
+
*
|
|
108
|
+
* Uses complexity analysis and the default tier assignments. Products can
|
|
109
|
+
* pass custom tier overrides or replace this entirely.
|
|
110
|
+
*
|
|
111
|
+
* @param modelOverrides - Optional per-tier model overrides.
|
|
112
|
+
* @returns A ModelSelector using complexity-based routing.
|
|
113
|
+
*/
|
|
114
|
+
export declare function createDefaultModelSelector(modelOverrides?: Partial<typeof DEFAULT_MODEL_TIERS>): ModelSelector;
|
|
115
|
+
/**
|
|
116
|
+
* Cost estimate for a plan-execute flow.
|
|
117
|
+
*/
|
|
118
|
+
export interface CostEstimate {
|
|
119
|
+
/** Plan phase token usage. */
|
|
120
|
+
planTokens: {
|
|
121
|
+
input: number;
|
|
122
|
+
output: number;
|
|
123
|
+
};
|
|
124
|
+
/** Execute phase token usage. */
|
|
125
|
+
executeTokens: {
|
|
126
|
+
input: number;
|
|
127
|
+
output: number;
|
|
128
|
+
};
|
|
129
|
+
/** Total estimated cost in USD. */
|
|
130
|
+
totalUSD: number;
|
|
131
|
+
/** Breakdown by phase. */
|
|
132
|
+
breakdown: {
|
|
133
|
+
planCost: number;
|
|
134
|
+
executeCost: number;
|
|
135
|
+
};
|
|
136
|
+
/** What it would cost using a single model for everything. */
|
|
137
|
+
comparisonSingleModel: number;
|
|
138
|
+
/** Savings from tiered routing. */
|
|
139
|
+
savings: number;
|
|
140
|
+
/** Savings as a percentage. */
|
|
141
|
+
savingsPercent: number;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Estimate cost for a plan-execute flow based on token counts.
|
|
145
|
+
*
|
|
146
|
+
* @param planInputTokens - Input tokens for the planning phase.
|
|
147
|
+
* @param planOutputTokens - Output tokens for the planning phase.
|
|
148
|
+
* @param executeInputTokens - Input tokens for the execution phase.
|
|
149
|
+
* @param executeOutputTokens - Output tokens for the execution phase.
|
|
150
|
+
* @param planModel - Model used for planning.
|
|
151
|
+
* @param executeModel - Model used for execution.
|
|
152
|
+
* @returns Detailed cost estimate with savings comparison.
|
|
153
|
+
*/
|
|
154
|
+
export declare function estimateCost(planInputTokens: number, planOutputTokens: number, executeInputTokens: number, executeOutputTokens: number, planModel?: string, executeModel?: string): CostEstimate;
|
|
155
|
+
/**
|
|
156
|
+
* Get pricing for a model, falling back to Sonnet pricing for unknown models.
|
|
157
|
+
*
|
|
158
|
+
* @param modelId - Model identifier.
|
|
159
|
+
* @returns Pricing per million tokens.
|
|
160
|
+
*/
|
|
161
|
+
export declare function getModelPricing(modelId: string): {
|
|
162
|
+
input: number;
|
|
163
|
+
output: number;
|
|
164
|
+
cacheHit: number;
|
|
165
|
+
};
|
|
166
|
+
/**
|
|
167
|
+
* Get display name for a model, falling back to the raw ID.
|
|
168
|
+
*
|
|
169
|
+
* @param modelId - Model identifier.
|
|
170
|
+
* @returns Short display name.
|
|
171
|
+
*/
|
|
172
|
+
export declare function getModelShortName(modelId: string): string;
|
|
173
|
+
/**
|
|
174
|
+
* Format a USD cost for display.
|
|
175
|
+
*
|
|
176
|
+
* @param cost - Cost in USD.
|
|
177
|
+
* @returns Formatted string (e.g. "$0.0032", "<$0.001").
|
|
178
|
+
*/
|
|
179
|
+
export declare function formatCost(cost: number): string;
|
|
180
|
+
//# sourceMappingURL=models.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../../../src/server/handlers/chat/models.ts"],"names":[],"mappings":"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"}
|