Skip to content

Commit 8a0204f

Browse files
Dan JonesDan Jones
authored andcommitted
Add mapping of search results
1 parent f78c508 commit 8a0204f

File tree

6 files changed

+173
-32
lines changed

6 files changed

+173
-32
lines changed

src/query/agent.test.ts

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,9 @@ it("search-only mode success: caches searches and sends on subsequent request",
105105
}),
106106
} as unknown as WeaviateClient;
107107

108-
const capturedBodies: ApiSearchModeResponse<undefined>[] = [];
108+
const capturedBodies: ApiSearchModeResponse[] = [];
109109

110-
const apiSuccess: ApiSearchModeResponse<undefined> = {
110+
const apiSuccess: ApiSearchModeResponse = {
111111
original_query: "Test this search only mode!",
112112
searches: [
113113
{
@@ -138,23 +138,43 @@ it("search-only mode success: caches searches and sends on subsequent request",
138138
objects: [
139139
{
140140
uuid: "e6dc0a31-76f8-4bd3-b563-677ced6eb557",
141-
metadata: {},
142-
references: {},
143-
vectors: {},
141+
metadata: {
142+
creation_time: null,
143+
update_time: null,
144+
distance: null,
145+
certainty: null,
146+
score: 0.8,
147+
explain_score: null,
148+
rerank_score: null,
149+
is_consistent: null,
150+
},
151+
references: null,
152+
vector: {},
144153
properties: {
145154
test_property: 1.0,
146155
text: "hello",
147156
},
157+
collection: "test_collection",
148158
},
149159
{
150160
uuid: "cf5401cc-f4f1-4eb9-a6a1-173d34f94339",
151-
metadata: {},
152-
references: {},
153-
vectors: {},
161+
metadata: {
162+
creation_time: null,
163+
update_time: null,
164+
distance: null,
165+
certainty: null,
166+
score: 0.5,
167+
explain_score: null,
168+
rerank_score: null,
169+
is_consistent: null,
170+
},
171+
references: null,
172+
vector: {},
154173
properties: {
155174
test_property: 2.0,
156175
text: "world!",
157176
},
177+
collection: "test_collection",
158178
},
159179
],
160180
},
@@ -164,7 +184,7 @@ it("search-only mode success: caches searches and sends on subsequent request",
164184
global.fetch = jest.fn((url, init?: RequestInit) => {
165185
if (init && init.body) {
166186
capturedBodies.push(
167-
JSON.parse(init.body as string) as ApiSearchModeResponse<undefined>,
187+
JSON.parse(init.body as string) as ApiSearchModeResponse,
168188
);
169189
}
170190
return Promise.resolve({
@@ -206,7 +226,34 @@ it("search-only mode success: caches searches and sends on subsequent request",
206226
details: undefined,
207227
},
208228
totalTime: 1.5,
209-
searchResults: apiSuccess.search_results,
229+
searchResults: {
230+
objects: [
231+
{
232+
uuid: "e6dc0a31-76f8-4bd3-b563-677ced6eb557",
233+
metadata: {
234+
score: 0.8,
235+
},
236+
vectors: {},
237+
properties: {
238+
test_property: 1.0,
239+
text: "hello",
240+
},
241+
collection: "test_collection",
242+
},
243+
{
244+
uuid: "cf5401cc-f4f1-4eb9-a6a1-173d34f94339",
245+
metadata: {
246+
score: 0.5,
247+
},
248+
vectors: {},
249+
properties: {
250+
test_property: 2.0,
251+
text: "world!",
252+
},
253+
collection: "test_collection",
254+
},
255+
],
256+
},
210257
});
211258
expect(typeof first.next).toBe("function");
212259

src/query/agent.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -195,11 +195,11 @@ export class QueryAgent {
195195
* The returned response includes a `next` method for pagination which
196196
* reuses the same underlying searches to ensure consistency across pages.
197197
*/
198-
async search<T = undefined>(
198+
async search(
199199
query: string,
200200
{ limit = 20, collections }: QueryAgentSearchOnlyOptions = {},
201-
): Promise<SearchModeResponse<T>> {
202-
const searcher = new QueryAgentSearcher<T>(this.client, query, {
201+
): Promise<SearchModeResponse> {
202+
const searcher = new QueryAgentSearcher(this.client, query, {
203203
collections: collections ?? this.collections,
204204
systemPrompt: this.systemPrompt,
205205
agentsHost: this.agentsHost,

src/query/response/api-response.ts

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { WeaviateReturn } from "weaviate-client";
1+
import { Vectors, WeaviateField } from "weaviate-client";
22

33
import {
44
NumericMetrics,
@@ -180,10 +180,40 @@ export type ApiSource = {
180180
collection: string;
181181
};
182182

183-
export type ApiSearchModeResponse<T> = {
183+
export type ApiReturnMetadata = {
184+
creation_time: Date | null;
185+
update_time: Date | null;
186+
distance: number | null;
187+
certainty: number | null;
188+
score: number | null;
189+
explain_score: string | null;
190+
rerank_score: number | null;
191+
is_consistent: boolean | null;
192+
};
193+
194+
export type ApiWeaviateObject = {
195+
/** The returned properties of the object as untyped key-value pairs from the API. */
196+
properties: Record<string, WeaviateField>;
197+
/** The returned metadata of the object. */
198+
metadata: ApiReturnMetadata;
199+
/** The returned references of the object. */
200+
references: null; // TODO: QA never requests references, so they're never returned?? Check this
201+
/** The UUID of the object. */
202+
uuid: string;
203+
/** The returned vectors of the object. */
204+
vector: Vectors; // TODO: note no s!
205+
collection: string; // NOTE: NEW
206+
};
207+
208+
export type ApiWeaviateReturn = {
209+
/** The objects that were found by the query. */
210+
objects: ApiWeaviateObject[];
211+
};
212+
213+
export type ApiSearchModeResponse = {
184214
original_query: string;
185215
searches?: ApiSearchResult[];
186216
usage: ApiUsage;
187217
total_time: number;
188-
search_results: WeaviateReturn<T>;
218+
search_results: ApiWeaviateReturn;
189219
};

src/query/response/response-mapping.ts

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { ReturnMetadata } from "weaviate-client";
2+
13
import {
24
QueryAgentResponse,
35
SearchResult,
@@ -10,6 +12,8 @@ import {
1012
ProgressMessage,
1113
DateFilterValue,
1214
MappedSearchModeResponse,
15+
WeaviateObjectWithCollection,
16+
WeaviateReturnWithCollection,
1317
} from "./response.js";
1418

1519
import {
@@ -22,6 +26,8 @@ import {
2226
ApiSource,
2327
ApiDateFilterValue,
2428
ApiSearchModeResponse,
29+
ApiWeaviateObject,
30+
ApiWeaviateReturn,
2531
} from "./api-response.js";
2632

2733
import { ServerSentEvent } from "./server-sent-events.js";
@@ -302,19 +308,68 @@ export const mapResponseFromSSE = (
302308
};
303309
};
304310

305-
export const mapSearchOnlyResponse = <T>(
306-
response: ApiSearchModeResponse<T>,
311+
const mapWeaviateObject = (
312+
object: ApiWeaviateObject,
313+
): WeaviateObjectWithCollection => {
314+
const metadata: ReturnMetadata = {
315+
creationTime:
316+
object.metadata.creation_time !== null
317+
? object.metadata.creation_time
318+
: undefined,
319+
updateTime:
320+
object.metadata.update_time !== null
321+
? object.metadata.update_time
322+
: undefined,
323+
distance:
324+
object.metadata.distance !== null ? object.metadata.distance : undefined,
325+
certainty:
326+
object.metadata.certainty !== null
327+
? object.metadata.certainty
328+
: undefined,
329+
score: object.metadata.score !== null ? object.metadata.score : undefined,
330+
explainScore:
331+
object.metadata.explain_score !== null
332+
? object.metadata.explain_score
333+
: undefined,
334+
rerankScore:
335+
object.metadata.rerank_score !== null
336+
? object.metadata.rerank_score
337+
: undefined,
338+
isConsistent:
339+
object.metadata.is_consistent !== null
340+
? object.metadata.is_consistent
341+
: undefined,
342+
};
343+
344+
return {
345+
properties: object.properties,
346+
metadata: metadata,
347+
references: undefined,
348+
uuid: object.uuid,
349+
vectors: object.vector,
350+
collection: object.collection,
351+
};
352+
};
353+
354+
export const mapWeviateSearchResults = (
355+
response: ApiWeaviateReturn,
356+
): WeaviateReturnWithCollection => ({
357+
objects: response.objects.map(mapWeaviateObject),
358+
});
359+
360+
export const mapSearchOnlyResponse = (
361+
response: ApiSearchModeResponse,
307362
): {
308-
mappedResponse: MappedSearchModeResponse<T>;
363+
mappedResponse: MappedSearchModeResponse;
309364
apiSearches: ApiSearchResult[] | undefined;
310365
} => {
311366
const apiSearches = response.searches;
312-
const mappedResponse: MappedSearchModeResponse<T> = {
367+
const mappedResponse: MappedSearchModeResponse = {
313368
originalQuery: response.original_query,
314369
searches: apiSearches ? mapInnerSearches(apiSearches) : undefined,
315370
usage: mapUsage(response.usage),
316371
totalTime: response.total_time,
317-
searchResults: response.search_results,
372+
searchResults: mapWeviateSearchResults(response.search_results),
318373
};
319374
return { mappedResponse, apiSearches };
320375
};

src/query/response/response.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { WeaviateReturn } from "weaviate-client";
1+
import { WeaviateReturn, WeaviateObject } from "weaviate-client";
22

33
export type QueryAgentResponse = {
44
outputType: "finalState";
@@ -263,12 +263,20 @@ export type StreamedTokens = {
263263
delta: string;
264264
};
265265

266-
export type MappedSearchModeResponse<T> = {
266+
export type WeaviateObjectWithCollection = WeaviateObject<undefined> & {
267+
collection: string;
268+
};
269+
270+
export type WeaviateReturnWithCollection = WeaviateReturn<undefined> & {
271+
objects: WeaviateObjectWithCollection[];
272+
};
273+
274+
export type MappedSearchModeResponse = {
267275
originalQuery: string;
268276
searches?: SearchResult[];
269277
usage: Usage;
270278
totalTime: number;
271-
searchResults: WeaviateReturn<T>;
279+
searchResults: WeaviateReturnWithCollection;
272280
};
273281

274282
/** Options for the executing a prepared QueryAgent search. */
@@ -279,6 +287,6 @@ export type SearchExecutionOptions = {
279287
offset?: number;
280288
};
281289

282-
export type SearchModeResponse<T> = MappedSearchModeResponse<T> & {
283-
next: (options: SearchExecutionOptions) => Promise<SearchModeResponse<T>>;
290+
export type SearchModeResponse = MappedSearchModeResponse & {
291+
next: (options: SearchExecutionOptions) => Promise<SearchModeResponse>;
284292
};

src/query/search.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import {
2626
*
2727
* For more information, see the [Weaviate Query Agent Docs](https://weaviate.io/developers/agents/query)
2828
*/
29-
export class QueryAgentSearcher<T> {
29+
export class QueryAgentSearcher {
3030
private agentsHost: string;
3131
private query: string;
3232
private collections: (string | QueryAgentCollectionConfig)[];
@@ -103,9 +103,10 @@ export class QueryAgentSearcher<T> {
103103
* @param [options.offset] - The offset to start from. If not specified, retrieval begins from the first object.
104104
* @returns A SearchModeResponse object containing the results, usage, and underlying searches performed.
105105
*/
106-
async run({ limit = 20, offset = 0 }: SearchExecutionOptions = {}): Promise<
107-
SearchModeResponse<T>
108-
> {
106+
async run({
107+
limit = 20,
108+
offset = 0,
109+
}: SearchExecutionOptions = {}): Promise<SearchModeResponse> {
109110
if (!this.collections || this.collections.length === 0) {
110111
throw Error("No collections provided to the query agent.");
111112
}
@@ -121,9 +122,9 @@ export class QueryAgentSearcher<T> {
121122
if (!response.ok) {
122123
await handleError(await response.text());
123124
}
124-
const parsedResponse = (await response.json()) as ApiSearchModeResponse<T>;
125+
const parsedResponse = (await response.json()) as ApiSearchModeResponse;
125126
const { mappedResponse, apiSearches } =
126-
mapSearchOnlyResponse<T>(parsedResponse);
127+
mapSearchOnlyResponse(parsedResponse);
127128
// If we successfully mapped the searches, cache them for the next request.
128129
// Since this cache is a private internal value, there's not point in mapping
129130
// back and forth between the exported and API types, so we cache apiSearches

0 commit comments

Comments
 (0)