Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions src/client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1721,6 +1721,69 @@ describe('DakeraClient', () => {
expect(body.routing).toBe('hybrid');
expect(body.rerank).toBe(true);
});

it('should use smart_score as .score when server returns nested recall with smart_score', async () => {
mockFetch.mockResolvedValueOnce({
ok: true,
headers: new Headers({ 'content-type': 'application/json' }),
json: async () => ({
memories: [
{
memory: { id: 'mem_1', content: 'ranked memory', memory_type: 'episodic', importance: 0.8 },
score: 0.5,
weighted_score: 0.7,
smart_score: 0.9,
},
],
}),
});

const result = await client.recall('agent-1', 'test');
const m = result.memories[0];
expect(m.score).toBeCloseTo(0.9);
expect(m.smart_score).toBeCloseTo(0.9);
expect(m.weighted_score).toBeCloseTo(0.7);
});

it('should fall back to weighted_score when smart_score absent', async () => {
mockFetch.mockResolvedValueOnce({
ok: true,
headers: new Headers({ 'content-type': 'application/json' }),
json: async () => ({
memories: [
{
memory: { id: 'mem_2', content: 'mem', memory_type: 'episodic', importance: 0.5 },
score: 0.4,
weighted_score: 0.65,
},
],
}),
});

const result = await client.recall('agent-1', 'test');
expect(result.memories[0].score).toBeCloseTo(0.65);
expect(result.memories[0].smart_score).toBeUndefined();
expect(result.memories[0].weighted_score).toBeCloseTo(0.65);
});

it('should fall back to raw score when neither smart_score nor weighted_score present', async () => {
mockFetch.mockResolvedValueOnce({
ok: true,
headers: new Headers({ 'content-type': 'application/json' }),
json: async () => ({
memories: [
{
memory: { id: 'mem_3', content: 'mem', memory_type: 'episodic', importance: 0.5 },
score: 0.55,
},
],
}),
});

const result = await client.recall('agent-1', 'test');
expect(result.memories[0].score).toBeCloseTo(0.55);
expect(result.memories[0].smart_score).toBeUndefined();
});
});

// ---------------------------------------------------------------------------
Expand Down
12 changes: 10 additions & 2 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,19 @@ function parseErrorCode(raw: unknown): ErrorCode {
return ErrorCode.UNKNOWN;
}

/** Flatten server's nested recall item `{memory: {...}, score}` to flat `RecalledMemory`. */
/** Flatten server's nested recall item `{memory: {...}, score, weighted_score, smart_score}` to flat `RecalledMemory`. */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function flattenRecalledMemory(item: any): any {
if (item && typeof item === 'object' && item.memory && typeof item.memory === 'object') {
return { ...item.memory, score: item.score, depth: item.depth };
// smart_score is the server's ranking key; prefer it so .score reflects actual rank order.
const score = item.smart_score ?? item.weighted_score ?? item.score;
return {
...item.memory,
score,
smart_score: item.smart_score,
weighted_score: item.weighted_score,
depth: item.depth,
};
}
return item;
}
Expand Down
6 changes: 5 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -563,8 +563,12 @@ export interface RecalledMemory {
memory_type: string;
/** Importance score */
importance: number;
/** Similarity score */
/** Ranking score — equals smart_score when present, then weighted_score, then raw score. */
score: number;
/** Raw smart_score from the server (the primary ranking key). */
smart_score?: number;
/** Raw weighted_score from the server. */
weighted_score?: number;
/** Optional metadata */
metadata?: Record<string, unknown>;
/** Creation timestamp */
Expand Down
Loading