@youdotcom-oss/api 0.1.1 → 0.2.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.
Files changed (31) hide show
  1. package/README.md +36 -36
  2. package/bin/cli.js +233 -400
  3. package/package.json +1 -1
  4. package/src/cli.ts +92 -21
  5. package/src/contents/contents.schemas.ts +8 -7
  6. package/src/contents/tests/contents.request.spec.ts +109 -0
  7. package/src/contents/tests/contents.schema-validation.spec.ts +75 -0
  8. package/src/deep-search/deep-search.schemas.ts +48 -0
  9. package/src/deep-search/deep-search.utils.ts +79 -0
  10. package/src/deep-search/tests/deep-search.request.spec.ts +109 -0
  11. package/src/deep-search/tests/deep-search.schema-validation.spec.ts +71 -0
  12. package/src/deep-search/tests/deep-search.utils.docker.ts +139 -0
  13. package/src/main.ts +4 -3
  14. package/src/search/search.schemas.ts +65 -6
  15. package/src/search/search.utils.ts +6 -28
  16. package/src/search/tests/search.request.spec.ts +122 -0
  17. package/src/search/tests/search.schema-validation.spec.ts +152 -0
  18. package/src/search/tests/{search.utils.spec.ts → search.utils.docker.ts} +0 -10
  19. package/src/shared/api.constants.ts +1 -1
  20. package/src/shared/check-response-for-errors.ts +1 -1
  21. package/src/shared/command-runner.ts +95 -0
  22. package/src/shared/dry-run-utils.ts +141 -0
  23. package/src/shared/tests/command-runner.spec.ts +210 -0
  24. package/src/shared/use-get-user-agents.ts +1 -1
  25. package/src/commands/contents.ts +0 -52
  26. package/src/commands/express.ts +0 -52
  27. package/src/commands/search.ts +0 -52
  28. package/src/express/express.schemas.ts +0 -85
  29. package/src/express/express.utils.ts +0 -113
  30. package/src/express/tests/express.utils.spec.ts +0 -83
  31. /package/src/contents/tests/{contents.utils.spec.ts → contents.utils.docker.ts} +0 -0
@@ -0,0 +1,139 @@
1
+ import { describe, expect, test } from 'bun:test'
2
+ import { callDeepSearch } from '../deep-search.utils.ts'
3
+
4
+ const getUserAgent = () => 'API/test (You.com;TEST)'
5
+
6
+ describe('callDeepSearch', () => {
7
+ test(
8
+ 'returns valid response structure for basic query',
9
+ async () => {
10
+ const result = await callDeepSearch({
11
+ deepSearchQuery: {
12
+ query: 'What is TypeScript?',
13
+ search_effort: 'low',
14
+ },
15
+ getUserAgent,
16
+ })
17
+
18
+ expect(result).toHaveProperty('answer')
19
+ expect(result).toHaveProperty('results')
20
+ expect(typeof result.answer).toBe('string')
21
+ expect(Array.isArray(result.results)).toBe(true)
22
+ expect(result.answer.length).toBeGreaterThan(0)
23
+ },
24
+ { retry: 2 },
25
+ )
26
+
27
+ test(
28
+ 'handles medium search effort',
29
+ async () => {
30
+ const result = await callDeepSearch({
31
+ deepSearchQuery: {
32
+ query: 'Explain REST API principles',
33
+ search_effort: 'medium',
34
+ },
35
+ getUserAgent,
36
+ })
37
+
38
+ expect(result).toHaveProperty('answer')
39
+ expect(result).toHaveProperty('results')
40
+ expect(typeof result.answer).toBe('string')
41
+ expect(Array.isArray(result.results)).toBe(true)
42
+ },
43
+ { retry: 2 },
44
+ )
45
+
46
+ test(
47
+ 'validates response schema with sources',
48
+ async () => {
49
+ const result = await callDeepSearch({
50
+ deepSearchQuery: {
51
+ query: 'What are the benefits of microservices?',
52
+ search_effort: 'low',
53
+ },
54
+ getUserAgent,
55
+ })
56
+
57
+ // Test that results have required properties
58
+ expect(result.results.length).toBeGreaterThan(0)
59
+
60
+ const source = result.results[0]
61
+ expect(source).toBeDefined()
62
+ expect(source).toHaveProperty('url')
63
+ expect(source).toHaveProperty('title')
64
+ expect(source).toHaveProperty('snippets')
65
+ expect(typeof source?.url).toBe('string')
66
+ expect(typeof source?.title).toBe('string')
67
+ expect(Array.isArray(source?.snippets)).toBe(true)
68
+ },
69
+ { retry: 2 },
70
+ )
71
+
72
+ test(
73
+ 'answer contains markdown with inline citations',
74
+ async () => {
75
+ const result = await callDeepSearch({
76
+ deepSearchQuery: {
77
+ query: 'What is JWT authentication?',
78
+ search_effort: 'low',
79
+ },
80
+ getUserAgent,
81
+ })
82
+
83
+ // Answer should be non-empty markdown string
84
+ expect(typeof result.answer).toBe('string')
85
+ expect(result.answer.length).toBeGreaterThan(0)
86
+
87
+ // Answer typically contains citations in the format [1], [2], etc.
88
+ // This is a soft check - citations may or may not be present
89
+ if (result.answer.includes('[')) {
90
+ expect(result.answer).toMatch(/\[\d+\]/)
91
+ }
92
+ },
93
+ { retry: 2 },
94
+ )
95
+
96
+ test(
97
+ 'handles complex multi-part questions',
98
+ async () => {
99
+ const result = await callDeepSearch({
100
+ deepSearchQuery: {
101
+ query: 'What is GraphQL and how does it differ from REST?',
102
+ search_effort: 'low',
103
+ },
104
+ getUserAgent,
105
+ })
106
+
107
+ expect(result).toHaveProperty('answer')
108
+ expect(result).toHaveProperty('results')
109
+ expect(result.results.length).toBeGreaterThan(0)
110
+
111
+ // Complex questions should have substantial answers
112
+ expect(result.answer.length).toBeGreaterThan(100)
113
+ },
114
+ { retry: 2 },
115
+ )
116
+
117
+ test(
118
+ 'sources include relevant snippets',
119
+ async () => {
120
+ const result = await callDeepSearch({
121
+ deepSearchQuery: {
122
+ query: 'What is Docker containerization?',
123
+ search_effort: 'low',
124
+ },
125
+ getUserAgent,
126
+ })
127
+
128
+ // Check that at least one source has snippets
129
+ const sourcesWithSnippets = result.results.filter((source) => source.snippets.length > 0)
130
+ expect(sourcesWithSnippets.length).toBeGreaterThan(0)
131
+
132
+ // Snippets should be non-empty strings
133
+ const firstSource = sourcesWithSnippets[0]
134
+ expect(firstSource).toBeDefined()
135
+ expect(firstSource?.snippets[0]?.length).toBeGreaterThan(0)
136
+ },
137
+ { retry: 2 },
138
+ )
139
+ })
package/src/main.ts CHANGED
@@ -10,13 +10,14 @@
10
10
  // Contents
11
11
  export * from './contents/contents.schemas.ts'
12
12
  export * from './contents/contents.utils.ts'
13
- // Express
14
- export * from './express/express.schemas.ts'
15
- export * from './express/express.utils.ts'
13
+ // Deep-Search
14
+ export * from './deep-search/deep-search.schemas.ts'
15
+ export * from './deep-search/deep-search.utils.ts'
16
16
  // Search
17
17
  export * from './search/search.schemas.ts'
18
18
  export * from './search/search.utils.ts'
19
19
  // Shared
20
20
  export * from './shared/api.constants.ts'
21
21
  export * from './shared/api.types.ts'
22
+ export * from './shared/dry-run-utils.ts'
22
23
  export * from './shared/generate-error-report-link.ts'
@@ -1,7 +1,70 @@
1
1
  import * as z from 'zod'
2
2
 
3
+ /**
4
+ * Language codes supported by You.com Search API (BCP 47 format)
5
+ * Based on OpenAPI spec: https://you.com/specs/openapi_search_v1.yaml
6
+ */
7
+ export const LanguageSchema = z.enum([
8
+ 'AR',
9
+ 'EU',
10
+ 'BN',
11
+ 'BG',
12
+ 'CA',
13
+ 'ZH-HANS',
14
+ 'ZH-HANT',
15
+ 'HR',
16
+ 'CS',
17
+ 'DA',
18
+ 'NL',
19
+ 'EN',
20
+ 'EN-GB',
21
+ 'ET',
22
+ 'FI',
23
+ 'FR',
24
+ 'GL',
25
+ 'DE',
26
+ 'EL',
27
+ 'GU',
28
+ 'HE',
29
+ 'HI',
30
+ 'HU',
31
+ 'IS',
32
+ 'IT',
33
+ 'JP',
34
+ 'KN',
35
+ 'KO',
36
+ 'LV',
37
+ 'LT',
38
+ 'MS',
39
+ 'ML',
40
+ 'MR',
41
+ 'NB',
42
+ 'PL',
43
+ 'PT-BR',
44
+ 'PT-PT',
45
+ 'PA',
46
+ 'RO',
47
+ 'RU',
48
+ 'SR',
49
+ 'SK',
50
+ 'SL',
51
+ 'ES',
52
+ 'SV',
53
+ 'TA',
54
+ 'TE',
55
+ 'TH',
56
+ 'TR',
57
+ 'UK',
58
+ 'VI',
59
+ ])
60
+
3
61
  export const SearchQuerySchema = z.object({
4
- query: z.string().min(1, 'Query is required').describe('Search query (supports +, -, site:, filetype:, lang:)'),
62
+ query: z
63
+ .string()
64
+ .min(1, 'Query is required')
65
+ .describe(
66
+ 'Search query. Supports operators: site:domain.com (domain filter), filetype:pdf (file type), +term (include), -term (exclude), AND/OR/NOT (boolean logic), lang:en (language). Example: "machine learning (Python OR PyTorch) -TensorFlow filetype:pdf"',
67
+ ),
5
68
  count: z.number().int().min(1).max(100).optional().describe('Max results per section'),
6
69
  freshness: z.string().optional().describe('day/week/month/year or YYYY-MM-DDtoYYYY-MM-DD'),
7
70
  offset: z.number().int().min(0).max(9).optional().describe('Pagination offset'),
@@ -32,6 +95,7 @@ export const SearchQuerySchema = z.object({
32
95
  'CN',
33
96
  'PL',
34
97
  'PT',
98
+ 'PT-BR',
35
99
  'PH',
36
100
  'RU',
37
101
  'SA',
@@ -47,11 +111,6 @@ export const SearchQuerySchema = z.object({
47
111
  .optional()
48
112
  .describe('Country code'),
49
113
  safesearch: z.enum(['off', 'moderate', 'strict']).optional().describe('Filter level'),
50
- site: z.string().optional().describe('Specific domain'),
51
- fileType: z.string().optional().describe('File type'),
52
- language: z.string().optional().describe('ISO 639-1 language code'),
53
- excludeTerms: z.string().optional().describe('Terms to exclude (pipe-separated)'),
54
- exactTerms: z.string().optional().describe('Exact terms (pipe-separated)'),
55
114
  livecrawl: z.enum(['web', 'news', 'all']).optional().describe('Live-crawl sections for full content'),
56
115
  livecrawl_formats: z.enum(['html', 'markdown']).optional().describe('Format for crawled content'),
57
116
  })
@@ -5,7 +5,7 @@ import { type SearchQuery, SearchResponseSchema } from './search.schemas.ts'
5
5
 
6
6
  export const fetchSearchResults = async ({
7
7
  YDC_API_KEY = process.env.YDC_API_KEY,
8
- searchQuery: { query, site, fileType, language, exactTerms, excludeTerms, ...rest },
8
+ searchQuery,
9
9
  getUserAgent,
10
10
  }: {
11
11
  searchQuery: SearchQuery
@@ -16,33 +16,11 @@ export const fetchSearchResults = async ({
16
16
 
17
17
  const searchParams = new URLSearchParams()
18
18
 
19
- // Build Query Param
20
- const searchQuery = [query]
21
- site && searchQuery.push(`site:${site}`)
22
- fileType && searchQuery.push(`filetype:${fileType}`)
23
- language && searchQuery.push(`lang:${language}`)
24
- if (exactTerms && excludeTerms) {
25
- throw new Error('Cannot specify both exactTerms and excludeTerms - please use only one')
26
- }
27
- exactTerms &&
28
- searchQuery.push(
29
- exactTerms
30
- .split('|')
31
- .map((term) => `+${term}`)
32
- .join(' AND '),
33
- )
34
- excludeTerms &&
35
- searchQuery.push(
36
- excludeTerms
37
- .split('|')
38
- .map((term) => `-${term}`)
39
- .join(' AND '),
40
- )
41
- searchParams.append('query', searchQuery.join(' '))
42
-
43
- // Append additional advanced Params
44
- for (const [name, value] of Object.entries(rest)) {
45
- if (value) searchParams.append(name, `${value}`)
19
+ // Append all query parameters
20
+ for (const [name, value] of Object.entries(searchQuery)) {
21
+ if (value !== undefined && value !== null) {
22
+ searchParams.append(name, `${value}`)
23
+ }
46
24
  }
47
25
 
48
26
  url.search = searchParams.toString()
@@ -0,0 +1,122 @@
1
+ import { describe, expect, test } from 'bun:test'
2
+ import { SEARCH_API_URL } from '../../shared/api.constants.ts'
3
+ import { buildSearchRequest } from '../../shared/dry-run-utils.ts'
4
+
5
+ describe('buildSearchRequest', () => {
6
+ const getUserAgent = () => 'test-agent'
7
+ const YDC_API_KEY = 'test-key'
8
+
9
+ test('builds basic search request', () => {
10
+ const request = buildSearchRequest({
11
+ searchQuery: { query: 'AI' },
12
+ YDC_API_KEY,
13
+ getUserAgent,
14
+ })
15
+
16
+ expect(request.url).toBe(SEARCH_API_URL)
17
+ expect(request.method).toBe('GET')
18
+ expect(request.headers['X-API-Key']).toBe('test-key')
19
+ expect(request.headers['User-Agent']).toBe('test-agent')
20
+ expect(request.queryParams?.query).toBe('AI')
21
+ })
22
+
23
+ test('passes query with site: operator directly', () => {
24
+ const request = buildSearchRequest({
25
+ searchQuery: { query: 'AI site:you.com' },
26
+ YDC_API_KEY,
27
+ getUserAgent,
28
+ })
29
+
30
+ expect(request.queryParams?.query).toBe('AI site:you.com')
31
+ })
32
+
33
+ test('passes query with filetype: operator directly', () => {
34
+ const request = buildSearchRequest({
35
+ searchQuery: { query: 'tutorial filetype:pdf' },
36
+ YDC_API_KEY,
37
+ getUserAgent,
38
+ })
39
+
40
+ expect(request.queryParams?.query).toBe('tutorial filetype:pdf')
41
+ })
42
+
43
+ test('passes query with lang: operator directly', () => {
44
+ const request = buildSearchRequest({
45
+ searchQuery: { query: 'search lang:en' },
46
+ YDC_API_KEY,
47
+ getUserAgent,
48
+ })
49
+
50
+ expect(request.queryParams?.query).toBe('search lang:en')
51
+ })
52
+
53
+ test('passes query with +term inclusion operator directly', () => {
54
+ const request = buildSearchRequest({
55
+ searchQuery: { query: 'search +machine +learning' },
56
+ YDC_API_KEY,
57
+ getUserAgent,
58
+ })
59
+
60
+ expect(request.queryParams?.query).toBe('search +machine +learning')
61
+ })
62
+
63
+ test('passes query with -term exclusion operator directly', () => {
64
+ const request = buildSearchRequest({
65
+ searchQuery: { query: 'python -django -flask' },
66
+ YDC_API_KEY,
67
+ getUserAgent,
68
+ })
69
+
70
+ expect(request.queryParams?.query).toBe('python -django -flask')
71
+ })
72
+
73
+ test('passes query with boolean operators directly', () => {
74
+ const request = buildSearchRequest({
75
+ searchQuery: { query: '(Python OR JavaScript) AND tutorial -deprecated' },
76
+ YDC_API_KEY,
77
+ getUserAgent,
78
+ })
79
+
80
+ expect(request.queryParams?.query).toBe('(Python OR JavaScript) AND tutorial -deprecated')
81
+ })
82
+
83
+ test('includes advanced search parameters', () => {
84
+ const request = buildSearchRequest({
85
+ searchQuery: {
86
+ query: 'AI',
87
+ count: 10,
88
+ freshness: 'week',
89
+ offset: 5,
90
+ country: 'US',
91
+ safesearch: 'moderate',
92
+ livecrawl: 'web',
93
+ livecrawl_formats: 'markdown',
94
+ },
95
+ YDC_API_KEY,
96
+ getUserAgent,
97
+ })
98
+
99
+ expect(request.queryParams?.query).toBe('AI')
100
+ expect(request.queryParams?.count).toBe('10')
101
+ expect(request.queryParams?.freshness).toBe('week')
102
+ expect(request.queryParams?.offset).toBe('5')
103
+ expect(request.queryParams?.country).toBe('US')
104
+ expect(request.queryParams?.safesearch).toBe('moderate')
105
+ expect(request.queryParams?.livecrawl).toBe('web')
106
+ expect(request.queryParams?.livecrawl_formats).toBe('markdown')
107
+ })
108
+
109
+ test('combines multiple operators in query string', () => {
110
+ const request = buildSearchRequest({
111
+ searchQuery: {
112
+ query: 'machine learning best practices (Python OR PyTorch) -TensorFlow filetype:pdf',
113
+ },
114
+ YDC_API_KEY,
115
+ getUserAgent,
116
+ })
117
+
118
+ expect(request.queryParams?.query).toBe(
119
+ 'machine learning best practices (Python OR PyTorch) -TensorFlow filetype:pdf',
120
+ )
121
+ })
122
+ })
@@ -0,0 +1,152 @@
1
+ import { describe, expect, test } from 'bun:test'
2
+ import { LanguageSchema, SearchQuerySchema } from '../search.schemas.ts'
3
+
4
+ describe('SearchQuerySchema OpenAPI validation', () => {
5
+ test('accepts valid query parameters', () => {
6
+ const validQueries = [
7
+ { query: 'AI' },
8
+ { query: 'test', count: 10, freshness: 'week' },
9
+ { query: 'search', country: 'US', safesearch: 'moderate' },
10
+ { query: 'livecrawl test', livecrawl: 'web', livecrawl_formats: 'markdown' },
11
+ ]
12
+
13
+ for (const validQuery of validQueries) {
14
+ expect(() => SearchQuerySchema.parse(validQuery)).not.toThrow()
15
+ }
16
+ })
17
+
18
+ test('rejects invalid query parameters', () => {
19
+ const invalidQueries = [
20
+ {}, // Missing query
21
+ { query: '' }, // Empty query
22
+ { query: 'test', count: 0 }, // Count too low
23
+ { query: 'test', count: 101 }, // Count too high
24
+ { query: 'test', offset: -1 }, // Negative offset
25
+ { query: 'test', offset: 10 }, // Offset too high
26
+ { query: 'test', safesearch: 'invalid' }, // Invalid safesearch
27
+ { query: 'test', livecrawl: 'invalid' }, // Invalid livecrawl
28
+ ]
29
+
30
+ for (const invalidQuery of invalidQueries) {
31
+ expect(() => SearchQuerySchema.parse(invalidQuery)).toThrow()
32
+ }
33
+ })
34
+
35
+ test('LanguageSchema includes all 51 BCP 47 codes', () => {
36
+ // Test a sample of language codes from the OpenAPI spec
37
+ const languageCodes = [
38
+ 'AR',
39
+ 'EU',
40
+ 'BN',
41
+ 'BG',
42
+ 'CA',
43
+ 'ZH-HANS',
44
+ 'ZH-HANT',
45
+ 'HR',
46
+ 'CS',
47
+ 'DA',
48
+ 'NL',
49
+ 'EN',
50
+ 'EN-GB',
51
+ 'ET',
52
+ 'FI',
53
+ 'FR',
54
+ 'GL',
55
+ 'DE',
56
+ 'EL',
57
+ 'GU',
58
+ 'HE',
59
+ 'HI',
60
+ 'HU',
61
+ 'IS',
62
+ 'IT',
63
+ 'JP',
64
+ 'KN',
65
+ 'KO',
66
+ 'LV',
67
+ 'LT',
68
+ 'MS',
69
+ 'ML',
70
+ 'MR',
71
+ 'NB',
72
+ 'PL',
73
+ 'PT-BR',
74
+ 'PT-PT',
75
+ 'PA',
76
+ 'RO',
77
+ 'RU',
78
+ 'SR',
79
+ 'SK',
80
+ 'SL',
81
+ 'ES',
82
+ 'SV',
83
+ 'TA',
84
+ 'TE',
85
+ 'TH',
86
+ 'TR',
87
+ 'UK',
88
+ 'VI',
89
+ ]
90
+
91
+ for (const code of languageCodes) {
92
+ expect(() => LanguageSchema.parse(code)).not.toThrow()
93
+ }
94
+
95
+ // Test that the schema has exactly 51 values
96
+ expect(LanguageSchema.options.length).toBe(51)
97
+ })
98
+
99
+ test('rejects invalid language codes', () => {
100
+ const invalidCodes = ['XX', 'INVALID', 'en', 'zh', '123']
101
+
102
+ for (const code of invalidCodes) {
103
+ expect(() => LanguageSchema.parse(code)).toThrow()
104
+ }
105
+ })
106
+
107
+ test('accepts all country codes from OpenAPI spec', () => {
108
+ const countryCodes = [
109
+ 'AR',
110
+ 'AU',
111
+ 'AT',
112
+ 'BE',
113
+ 'BR',
114
+ 'CA',
115
+ 'CL',
116
+ 'DK',
117
+ 'FI',
118
+ 'FR',
119
+ 'DE',
120
+ 'HK',
121
+ 'IN',
122
+ 'ID',
123
+ 'IT',
124
+ 'JP',
125
+ 'KR',
126
+ 'MY',
127
+ 'MX',
128
+ 'NL',
129
+ 'NZ',
130
+ 'NO',
131
+ 'CN',
132
+ 'PL',
133
+ 'PT',
134
+ 'PT-BR',
135
+ 'PH',
136
+ 'RU',
137
+ 'SA',
138
+ 'ZA',
139
+ 'ES',
140
+ 'SE',
141
+ 'CH',
142
+ 'TW',
143
+ 'TR',
144
+ 'GB',
145
+ 'US',
146
+ ]
147
+
148
+ for (const code of countryCodes) {
149
+ expect(() => SearchQuerySchema.parse({ query: 'test', country: code })).not.toThrow()
150
+ }
151
+ })
152
+ })
@@ -15,9 +15,7 @@ describe('fetchSearchResults', () => {
15
15
  expect(result).toHaveProperty('results')
16
16
  expect(result).toHaveProperty('metadata')
17
17
  expect(result.results).toHaveProperty('web')
18
- // expect(result.results).toHaveProperty('news');
19
18
  expect(Array.isArray(result.results.web)).toBe(true)
20
- // expect(Array.isArray(result.results.news)).toBe(true);
21
19
 
22
20
  // Assert required metadata fields
23
21
  expect(typeof result.metadata?.query).toBe('string')
@@ -57,7 +55,6 @@ describe('fetchSearchResults', () => {
57
55
  })
58
56
 
59
57
  // Test that web results have required properties
60
- // biome-ignore lint/style/noNonNullAssertion: Test
61
58
  const webResult = result.results.web![0]
62
59
 
63
60
  expect(webResult).toHaveProperty('url')
@@ -65,13 +62,6 @@ describe('fetchSearchResults', () => {
65
62
  expect(webResult).toHaveProperty('description')
66
63
  expect(webResult).toHaveProperty('snippets')
67
64
  expect(Array.isArray(webResult?.snippets)).toBe(true)
68
-
69
- // Test that news results have required properties
70
- // const newsResult = result.results.news![0];
71
- // expect(newsResult).toHaveProperty('url');
72
- // expect(newsResult).toHaveProperty('title');
73
- // expect(newsResult).toHaveProperty('description');
74
- // expect(newsResult).toHaveProperty('page_age');
75
65
  },
76
66
  { retry: 2 },
77
67
  )
@@ -6,5 +6,5 @@
6
6
  */
7
7
 
8
8
  export const SEARCH_API_URL = 'https://ydc-index.io/v1/search'
9
- export const EXPRESS_API_URL = 'https://api.you.com/v1/agents/runs'
9
+ export const DEEP_SEARCH_API_URL = 'https://api.you.com/v1/deep_search'
10
10
  export const CONTENTS_API_URL = 'https://ydc-index.io/v1/contents'
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Checks if a response object contains an error field and throws if found
3
3
  * Handles API responses that return 200 status but contain error messages
4
- * Used by both search and express agent utilities
4
+ * Used by search, deep-search, and contents utilities
5
5
  */
6
6
  export const checkResponseForErrors = (responseData: unknown) => {
7
7
  if (typeof responseData === 'object' && responseData !== null && 'error' in responseData) {