@graphext/cuery 0.4.0 → 0.5.2

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 (203) hide show
  1. package/esm/browser.d.ts +1 -1
  2. package/esm/browser.d.ts.map +1 -1
  3. package/esm/browser.js +1 -1
  4. package/esm/mod.d.ts +5 -2
  5. package/esm/mod.d.ts.map +1 -1
  6. package/esm/mod.js +7 -2
  7. package/esm/src/api.d.ts +36 -5
  8. package/esm/src/api.d.ts.map +1 -1
  9. package/esm/src/api.js +84 -37
  10. package/esm/src/apis/chatgptScraper/brightdata.js +1 -1
  11. package/esm/src/apis/chatgptScraper/oxy.js +1 -1
  12. package/esm/src/apis/chatgptScraper/scraper.js +2 -2
  13. package/esm/src/apis/hasdata/aim.js +1 -1
  14. package/esm/src/apis/hasdata/aio.js +1 -1
  15. package/esm/src/apis/hasdata/helpers.d.ts +1 -1
  16. package/esm/src/apis/hasdata/helpers.d.ts.map +1 -1
  17. package/esm/src/apis/hasdata/helpers.js +2 -2
  18. package/esm/src/assets/models.d.ts +60725 -0
  19. package/esm/src/assets/models.d.ts.map +1 -0
  20. package/esm/src/assets/models.js +71915 -0
  21. package/esm/src/helpers/async.d.ts.map +1 -0
  22. package/esm/src/{async.js → helpers/async.js} +1 -1
  23. package/esm/src/helpers/seedKeywords.d.ts.map +1 -0
  24. package/esm/src/helpers/urls.d.ts.map +1 -0
  25. package/esm/src/helpers/utils.d.ts.map +1 -0
  26. package/esm/src/llm.d.ts +35 -0
  27. package/esm/src/llm.d.ts.map +1 -0
  28. package/esm/src/llm.js +59 -0
  29. package/esm/src/providers/google.d.ts +12 -0
  30. package/esm/src/providers/google.d.ts.map +1 -0
  31. package/esm/src/providers/google.js +111 -0
  32. package/esm/src/providers/index.d.ts +13 -0
  33. package/esm/src/providers/index.d.ts.map +1 -0
  34. package/esm/src/providers/index.js +14 -0
  35. package/esm/src/providers/openai.d.ts +12 -0
  36. package/esm/src/providers/openai.d.ts.map +1 -0
  37. package/esm/src/providers/openai.js +141 -0
  38. package/esm/src/providers/pricing.d.ts +72 -0
  39. package/esm/src/providers/pricing.d.ts.map +1 -0
  40. package/esm/src/providers/pricing.js +88 -0
  41. package/esm/src/providers/registry.d.ts +20 -0
  42. package/esm/src/providers/registry.d.ts.map +1 -0
  43. package/esm/src/providers/registry.js +35 -0
  44. package/esm/src/providers/types.d.ts +49 -0
  45. package/esm/src/providers/types.d.ts.map +1 -0
  46. package/esm/src/providers/types.js +7 -0
  47. package/esm/src/response.d.ts +74 -0
  48. package/esm/src/response.d.ts.map +1 -0
  49. package/esm/src/response.js +110 -0
  50. package/esm/src/tool.d.ts +58 -0
  51. package/esm/src/tool.d.ts.map +1 -0
  52. package/esm/src/tool.js +91 -0
  53. package/esm/src/tools/brands.js +6 -6
  54. package/esm/src/tools/classifier.d.ts +80 -17
  55. package/esm/src/tools/classifier.d.ts.map +1 -1
  56. package/esm/src/tools/classifier.js +68 -80
  57. package/esm/src/tools/entities.d.ts +23 -12
  58. package/esm/src/tools/entities.d.ts.map +1 -1
  59. package/esm/src/tools/entities.js +27 -47
  60. package/esm/src/tools/funnel.js +7 -7
  61. package/esm/src/tools/generic.d.ts +17 -4
  62. package/esm/src/tools/generic.d.ts.map +1 -1
  63. package/esm/src/tools/generic.js +39 -14
  64. package/esm/src/tools/keywords.js +5 -5
  65. package/esm/src/tools/personas.d.ts +49 -2
  66. package/esm/src/tools/personas.d.ts.map +1 -1
  67. package/esm/src/tools/personas.js +59 -35
  68. package/esm/src/tools/scorer.d.ts +24 -6
  69. package/esm/src/tools/scorer.d.ts.map +1 -1
  70. package/esm/src/tools/scorer.js +27 -22
  71. package/esm/src/tools/search.d.ts.map +1 -1
  72. package/esm/src/tools/search.js +33 -9
  73. package/esm/src/tools/sentiment.d.ts +30 -8
  74. package/esm/src/tools/sentiment.d.ts.map +1 -1
  75. package/esm/src/tools/sentiment.js +33 -28
  76. package/esm/src/tools/sources.d.ts +5 -5
  77. package/esm/src/tools/sources.d.ts.map +1 -1
  78. package/esm/src/tools/sources.js +5 -6
  79. package/esm/src/tools/topics.d.ts +44 -16
  80. package/esm/src/tools/topics.d.ts.map +1 -1
  81. package/esm/src/tools/topics.js +77 -68
  82. package/esm/src/tools/translate.d.ts +22 -31
  83. package/esm/src/tools/translate.d.ts.map +1 -1
  84. package/esm/src/tools/translate.js +40 -36
  85. package/package.json +2 -1
  86. package/script/browser.d.ts +1 -1
  87. package/script/browser.d.ts.map +1 -1
  88. package/script/browser.js +1 -1
  89. package/script/mod.d.ts +5 -2
  90. package/script/mod.d.ts.map +1 -1
  91. package/script/mod.js +14 -2
  92. package/script/src/api.d.ts +36 -5
  93. package/script/src/api.d.ts.map +1 -1
  94. package/script/src/api.js +84 -35
  95. package/script/src/apis/chatgptScraper/brightdata.js +1 -1
  96. package/script/src/apis/chatgptScraper/oxy.js +1 -1
  97. package/script/src/apis/chatgptScraper/scraper.js +2 -2
  98. package/script/src/apis/hasdata/aim.js +1 -1
  99. package/script/src/apis/hasdata/aio.js +1 -1
  100. package/script/src/apis/hasdata/helpers.d.ts +1 -1
  101. package/script/src/apis/hasdata/helpers.d.ts.map +1 -1
  102. package/script/src/apis/hasdata/helpers.js +2 -2
  103. package/script/src/assets/models.d.ts +60725 -0
  104. package/script/src/assets/models.d.ts.map +1 -0
  105. package/script/src/assets/models.js +71917 -0
  106. package/script/src/helpers/async.d.ts.map +1 -0
  107. package/script/src/{async.js → helpers/async.js} +1 -1
  108. package/script/src/helpers/seedKeywords.d.ts.map +1 -0
  109. package/script/src/helpers/urls.d.ts.map +1 -0
  110. package/script/src/helpers/utils.d.ts.map +1 -0
  111. package/script/src/llm.d.ts +35 -0
  112. package/script/src/llm.d.ts.map +1 -0
  113. package/script/src/llm.js +65 -0
  114. package/script/src/providers/google.d.ts +12 -0
  115. package/script/src/providers/google.d.ts.map +1 -0
  116. package/script/src/providers/google.js +148 -0
  117. package/script/src/providers/index.d.ts +13 -0
  118. package/script/src/providers/index.d.ts.map +1 -0
  119. package/script/src/providers/index.js +24 -0
  120. package/script/src/providers/openai.d.ts +12 -0
  121. package/script/src/providers/openai.d.ts.map +1 -0
  122. package/script/src/providers/openai.js +181 -0
  123. package/script/src/providers/pricing.d.ts +72 -0
  124. package/script/src/providers/pricing.d.ts.map +1 -0
  125. package/script/src/providers/pricing.js +97 -0
  126. package/script/src/providers/registry.d.ts +20 -0
  127. package/script/src/providers/registry.d.ts.map +1 -0
  128. package/script/src/providers/registry.js +39 -0
  129. package/script/src/providers/types.d.ts +49 -0
  130. package/script/src/providers/types.d.ts.map +1 -0
  131. package/script/src/providers/types.js +8 -0
  132. package/script/src/response.d.ts +74 -0
  133. package/script/src/response.d.ts.map +1 -0
  134. package/script/src/response.js +114 -0
  135. package/script/src/tool.d.ts +58 -0
  136. package/script/src/tool.d.ts.map +1 -0
  137. package/script/src/tool.js +95 -0
  138. package/script/src/tools/brands.js +6 -6
  139. package/script/src/tools/classifier.d.ts +80 -17
  140. package/script/src/tools/classifier.d.ts.map +1 -1
  141. package/script/src/tools/classifier.js +72 -85
  142. package/script/src/tools/entities.d.ts +23 -12
  143. package/script/src/tools/entities.d.ts.map +1 -1
  144. package/script/src/tools/entities.js +29 -51
  145. package/script/src/tools/funnel.js +7 -7
  146. package/script/src/tools/generic.d.ts +17 -4
  147. package/script/src/tools/generic.d.ts.map +1 -1
  148. package/script/src/tools/generic.js +39 -14
  149. package/script/src/tools/keywords.js +5 -5
  150. package/script/src/tools/personas.d.ts +49 -2
  151. package/script/src/tools/personas.d.ts.map +1 -1
  152. package/script/src/tools/personas.js +63 -36
  153. package/script/src/tools/scorer.d.ts +24 -6
  154. package/script/src/tools/scorer.d.ts.map +1 -1
  155. package/script/src/tools/scorer.js +28 -24
  156. package/script/src/tools/search.d.ts.map +1 -1
  157. package/script/src/tools/search.js +69 -9
  158. package/script/src/tools/sentiment.d.ts +30 -8
  159. package/script/src/tools/sentiment.d.ts.map +1 -1
  160. package/script/src/tools/sentiment.js +37 -30
  161. package/script/src/tools/sources.d.ts +5 -5
  162. package/script/src/tools/sources.d.ts.map +1 -1
  163. package/script/src/tools/sources.js +4 -5
  164. package/script/src/tools/topics.d.ts +44 -16
  165. package/script/src/tools/topics.d.ts.map +1 -1
  166. package/script/src/tools/topics.js +80 -72
  167. package/script/src/tools/translate.d.ts +22 -31
  168. package/script/src/tools/translate.d.ts.map +1 -1
  169. package/script/src/tools/translate.js +43 -40
  170. package/esm/src/async.d.ts.map +0 -1
  171. package/esm/src/models.d.ts +0 -18
  172. package/esm/src/models.d.ts.map +0 -1
  173. package/esm/src/models.js +0 -48
  174. package/esm/src/openai.d.ts +0 -17
  175. package/esm/src/openai.d.ts.map +0 -1
  176. package/esm/src/openai.js +0 -136
  177. package/esm/src/tools/seedKeywords.d.ts.map +0 -1
  178. package/esm/src/urls.d.ts.map +0 -1
  179. package/esm/src/utils.d.ts.map +0 -1
  180. package/script/src/async.d.ts.map +0 -1
  181. package/script/src/models.d.ts +0 -18
  182. package/script/src/models.d.ts.map +0 -1
  183. package/script/src/models.js +0 -52
  184. package/script/src/openai.d.ts +0 -17
  185. package/script/src/openai.d.ts.map +0 -1
  186. package/script/src/openai.js +0 -175
  187. package/script/src/tools/seedKeywords.d.ts.map +0 -1
  188. package/script/src/urls.d.ts.map +0 -1
  189. package/script/src/utils.d.ts.map +0 -1
  190. /package/esm/src/{async.d.ts → helpers/async.d.ts} +0 -0
  191. /package/esm/src/{tools → helpers}/seedKeywords.d.ts +0 -0
  192. /package/esm/src/{tools → helpers}/seedKeywords.js +0 -0
  193. /package/esm/src/{urls.d.ts → helpers/urls.d.ts} +0 -0
  194. /package/esm/src/{urls.js → helpers/urls.js} +0 -0
  195. /package/esm/src/{utils.d.ts → helpers/utils.d.ts} +0 -0
  196. /package/esm/src/{utils.js → helpers/utils.js} +0 -0
  197. /package/script/src/{async.d.ts → helpers/async.d.ts} +0 -0
  198. /package/script/src/{tools → helpers}/seedKeywords.d.ts +0 -0
  199. /package/script/src/{tools → helpers}/seedKeywords.js +0 -0
  200. /package/script/src/{urls.d.ts → helpers/urls.d.ts} +0 -0
  201. /package/script/src/{urls.js → helpers/urls.js} +0 -0
  202. /package/script/src/{utils.d.ts → helpers/utils.d.ts} +0 -0
  203. /package/script/src/{utils.js → helpers/utils.js} +0 -0
@@ -1,7 +1,6 @@
1
1
  import { z } from '../../deps/jsr.io/@zod/zod/4.3.6/src/index.js';
2
- import { mapParallel } from '../async.js';
3
- import { askOpenAISafe } from '../openai.js';
4
- import { dedent, formatRecordsAttrWise } from '../utils.js';
2
+ import { Tool } from '../tool.js';
3
+ import { dedent, formatRecordsAttrWise } from '../helpers/utils.js';
5
4
  const PROMPT_TEMPLATE = dedent(`
6
5
  # Instructions
7
6
 
@@ -36,7 +35,6 @@ if it matches multiple categories. Assign all relevant labels that apply to the
36
35
  `);
37
36
  /**
38
37
  * Formats a record object into a human-readable text representation.
39
- * Similar to the record_to_text.jinja template in Python.
40
38
  */
41
39
  function formatRecord(record) {
42
40
  return Object.entries(record)
@@ -53,7 +51,6 @@ function formatLabels(labels) {
53
51
  }
54
52
  /**
55
53
  * Creates a dynamic Category schema based on provided labels.
56
- * Each category literal includes its description, which helps the LLM understand the classification.
57
54
  */
58
55
  function createLabelSchema(labels) {
59
56
  const entries = Object.entries(labels);
@@ -66,7 +63,6 @@ function createLabelSchema(labels) {
66
63
  label: z.literal(label).describe(description)
67
64
  });
68
65
  }
69
- // TypeScript now knows entries.length >= 2
70
66
  const literals = entries.map(([label, description]) => z.literal(label).describe(description));
71
67
  return z.object({
72
68
  label: z.union(literals)
@@ -74,7 +70,6 @@ function createLabelSchema(labels) {
74
70
  }
75
71
  /**
76
72
  * Creates a dynamic multi-label schema based on provided labels.
77
- * Returns a schema that accepts an array of labels, reusing the single label schema.
78
73
  */
79
74
  function createMultiLabelSchema(labels) {
80
75
  const singleLabelSchema = createLabelSchema(labels);
@@ -86,55 +81,55 @@ function createMultiLabelSchema(labels) {
86
81
  });
87
82
  }
88
83
  /**
89
- * Classifies a single data record into one of the provided categories using an LLM call.
84
+ * A tool that classifies records into one of the provided categories.
90
85
  */
91
- export async function classify(record, labels, instructions = '', model = 'gpt-4.1-mini') {
92
- if (record == null || Object.keys(record).length === 0) {
93
- return null;
86
+ export class Classifier extends Tool {
87
+ labelSchema;
88
+ promptTemplate;
89
+ constructor(config, modelConfig) {
90
+ super(modelConfig);
91
+ const { labels, instructions = '' } = config;
92
+ this.labelSchema = createLabelSchema(labels);
93
+ this.promptTemplate = PROMPT_TEMPLATE
94
+ .replace('{labels}', formatLabels(labels))
95
+ .replace('{instructions}', instructions);
94
96
  }
95
- const categorySchema = createLabelSchema(labels);
96
- const prompt = PROMPT_TEMPLATE
97
- .replace('{labels}', formatLabels(labels))
98
- .replace('{instructions}', instructions)
99
- .replace('{record}', formatRecord(record));
100
- const { parsed } = await askOpenAISafe(prompt, model, categorySchema);
101
- if (!parsed) {
102
- throw new Error('Failed to parse response from OpenAI');
97
+ schema() {
98
+ return this.labelSchema;
103
99
  }
104
- return parsed.label;
105
- }
106
- /**
107
- * Classifies multiple data records concurrently while preserving order.
108
- */
109
- export function classifyBatch(records, labels, instructions = '', model = 'gpt-4.1-mini', maxConcurrency = 100) {
110
- return mapParallel(records, maxConcurrency, record => classify(record, labels, instructions, model));
111
- }
112
- /**
113
- * Assigns one or more labels to a single data record using an LLM call.
114
- */
115
- export async function label(record, labels, instructions = '', model = 'gpt-4.1-mini') {
116
- if (record == null || Object.keys(record).length === 0) {
117
- return null;
100
+ prompt(record) {
101
+ return this.promptTemplate.replace('{record}', formatRecord(record));
118
102
  }
119
- const multiLabelSchema = createMultiLabelSchema(labels);
120
- const prompt = MULTI_LABEL_PROMPT_TEMPLATE
121
- .replace('{labels}', formatLabels(labels))
122
- .replace('{instructions}', instructions)
123
- .replace('{record}', formatRecord(record));
124
- const { parsed } = await askOpenAISafe(prompt, model, multiLabelSchema);
125
- if (!parsed) {
126
- throw new Error('Failed to parse response from OpenAI');
103
+ extractResult(parsed) {
104
+ return parsed.label;
127
105
  }
128
- return parsed.labels;
129
106
  }
130
107
  /**
131
- * Assigns labels to multiple data records concurrently while preserving order.
108
+ * A tool that assigns one or more labels to records from provided options.
132
109
  */
133
- export function labelBatch(records, labels, instructions = '', model = 'gpt-4.1-mini', maxConcurrency = 100) {
134
- return mapParallel(records, maxConcurrency, record => label(record, labels, instructions, model));
110
+ export class Labeler extends Tool {
111
+ multiLabelSchema;
112
+ promptTemplate;
113
+ constructor(config, modelConfig) {
114
+ super(modelConfig);
115
+ const { labels, instructions = '' } = config;
116
+ this.multiLabelSchema = createMultiLabelSchema(labels);
117
+ this.promptTemplate = MULTI_LABEL_PROMPT_TEMPLATE
118
+ .replace('{labels}', formatLabels(labels))
119
+ .replace('{instructions}', instructions);
120
+ }
121
+ schema() {
122
+ return this.multiLabelSchema;
123
+ }
124
+ prompt(record) {
125
+ return this.promptTemplate.replace('{record}', formatRecord(record));
126
+ }
127
+ extractResult(parsed) {
128
+ return parsed.labels;
129
+ }
135
130
  }
136
131
  // =============================================================================
137
- // Label Extraction
132
+ // LabelExtractor (extract classification labels from records)
138
133
  // =============================================================================
139
134
  const EXTRACT_LABELS_PROMPT = dedent(`
140
135
  # Instructions
@@ -162,10 +157,6 @@ unless the user provides different instructions below.
162
157
 
163
158
  {records}
164
159
  `);
165
- /**
166
- * Schema for extracted labels - an array of label objects.
167
- * Uses array format instead of record because OpenAI doesn't support propertyNames in JSON schema.
168
- */
169
160
  const ExtractedLabelsSchema = z.object({
170
161
  labels: z.array(z.object({
171
162
  name: z.string(),
@@ -173,39 +164,36 @@ const ExtractedLabelsSchema = z.object({
173
164
  }))
174
165
  });
175
166
  /**
176
- * Extracts a set of classification labels from an array of records using an LLM.
167
+ * A tool that extracts classification labels from a set of records.
177
168
  * Returns a Record<string, string> mapping label names to descriptions,
178
- * which can be used directly with classify() and classifyBatch().
169
+ * which can be used directly with Classifier and Labeler.
179
170
  */
180
- export async function extractLabels({ records, nLabels = 10, instructions = '', maxSamples = 500, model = 'gpt-4.1', modelParams = {}, maxRetries = 8, language = 'The same language as the records' }) {
181
- if (!records || records.length === 0) {
182
- return {};
171
+ export class LabelExtractor extends Tool {
172
+ maxSamples;
173
+ promptTemplate;
174
+ constructor(config = {}, modelConfig) {
175
+ super(modelConfig);
176
+ const { nLabels = 10, instructions = '', maxSamples = 500, language = 'The same language as the records' } = config;
177
+ this.maxSamples = maxSamples;
178
+ this.promptTemplate = EXTRACT_LABELS_PROMPT
179
+ .replace('{n_labels}', String(nLabels))
180
+ .replace('{instructions}', instructions)
181
+ .replace('{language}', language);
182
+ }
183
+ schema() {
184
+ return ExtractedLabelsSchema;
185
+ }
186
+ prompt(records) {
187
+ const sampledRecords = records.length > this.maxSamples
188
+ ? records.slice(0, this.maxSamples)
189
+ : records;
190
+ const formattedRecords = formatRecordsAttrWise(sampledRecords);
191
+ return this.promptTemplate.replace('{records}', formattedRecords);
183
192
  }
184
- const sampledRecords = records.length > maxSamples
185
- ? records.slice(0, maxSamples)
186
- : records;
187
- const formattedRecords = formatRecordsAttrWise(sampledRecords);
188
- const prompt = EXTRACT_LABELS_PROMPT
189
- .replace('{n_labels}', String(nLabels))
190
- .replace('{instructions}', instructions)
191
- .replace('{records}', formattedRecords)
192
- .replace('{language}', language);
193
- const { parsed, output_text, error } = await askOpenAISafe(prompt, model, ExtractedLabelsSchema, modelParams, maxRetries, 'return');
194
- if (error != null) {
195
- if (output_text == null) {
196
- throw new Error('Failed to get response from OpenAI');
197
- }
198
- try {
199
- const extracted = JSON.parse(output_text);
200
- const { labels } = ExtractedLabelsSchema.parse(extracted);
201
- return Object.fromEntries(labels.map(l => [l.name, l.description]));
202
- }
203
- catch (parseError) {
204
- throw new Error(`Failed to parse response: ${parseError instanceof Error ? parseError.message : String(parseError)}`);
205
- }
193
+ isEmpty(records) {
194
+ return !records || records.length === 0;
206
195
  }
207
- if (parsed == null) {
208
- throw new Error('Failed to parse response from OpenAI');
196
+ extractResult(parsed) {
197
+ return Object.fromEntries(parsed.labels.map(l => [l.name, l.description]));
209
198
  }
210
- return Object.fromEntries(parsed.labels.map(l => [l.name, l.description]));
211
199
  }
@@ -1,19 +1,30 @@
1
- import { type AIParams } from '../openai.js';
2
- import { type Entity } from '../schemas/entity.schema.js';
3
- export declare const PROMPT: string;
1
+ import { Tool, type ModelConfig } from '../tool.js';
2
+ import { type Entity, type Entities } from '../schemas/entity.schema.js';
4
3
  /**
5
- *
6
- * Extracts free-form entities from the given text (without enforced entity types).
4
+ * Configuration for the EntityExtractor tool.
7
5
  */
8
- export declare function extractAnyEntities(body: string, instructions: string | undefined, model: string, modelParams?: AIParams): Promise<Array<Entity>>;
6
+ export interface EntityExtractorConfig {
7
+ /** Entity type definitions (string or map of type to description) */
8
+ entityDefinitions?: string | Record<string, string>;
9
+ /** Additional instructions */
10
+ instructions?: string;
11
+ }
9
12
  /**
10
- * Extracts entities in pre-specified categories from a single text.
13
+ * A tool that extracts entities from text.
11
14
  */
12
- export declare function extractEntitiesFromText(text: string | null, entityDefinitions: string | Record<string, string>, instructions?: string, model?: string, modelParams?: AIParams): Promise<Array<Entity>>;
13
- /**
14
- * Extracts entities from a batch of texts.
15
- */
16
- export declare function extractEntitiesBatch(texts: Array<string | null>, entityDefinitions: Record<string, string> | string, instructions?: string, model?: string, maxConcurrency?: number, modelParams?: AIParams): Promise<Array<Array<Entity>>>;
15
+ export declare class EntityExtractor extends Tool<string | null, Entities, Array<Entity>> {
16
+ private readonly promptTemplate;
17
+ constructor(config: EntityExtractorConfig | undefined, modelConfig: ModelConfig);
18
+ protected schema(): import("../../deps/jsr.io/@zod/zod/4.3.6/src/index.js").ZodObject<{
19
+ entities: import("../../deps/jsr.io/@zod/zod/4.3.6/src/index.js").ZodArray<import("../../deps/jsr.io/@zod/zod/4.3.6/src/index.js").ZodObject<{
20
+ name: import("../../deps/jsr.io/@zod/zod/4.3.6/src/index.js").ZodString;
21
+ type: import("../../deps/jsr.io/@zod/zod/4.3.6/src/index.js").ZodString;
22
+ }, import("../../deps/jsr.io/@zod/zod/4.3.6/src/v4/core/schemas.js").$strip>>;
23
+ }, import("../../deps/jsr.io/@zod/zod/4.3.6/src/v4/core/schemas.js").$strip>;
24
+ protected prompt(text: string | null): string;
25
+ protected isEmpty(text: string | null): boolean;
26
+ protected extractResult(parsed: Entities): Array<Entity>;
27
+ }
17
28
  export type { Entity, Entities } from '../schemas/entity.schema.js';
18
29
  export { EntitySchema, EntitiesSchema } from '../schemas/entity.schema.js';
19
30
  //# sourceMappingURL=entities.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"entities.d.ts","sourceRoot":"","sources":["../../../src/src/tools/entities.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAE5D,OAAO,EAAkB,KAAK,MAAM,EAAE,MAAM,6BAA6B,CAAC;AAG1E,eAAO,MAAM,MAAM,QAyBjB,CAAC;AAEH;;;GAGG;AACH,wBAAsB,kBAAkB,CACvC,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,YAAK,EACzB,KAAK,EAAE,MAAM,EACb,WAAW,GAAE,QAAa,GACxB,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAYxB;AAED;;GAEG;AACH,wBAAsB,uBAAuB,CAC5C,IAAI,EAAE,MAAM,GAAG,IAAI,EACnB,iBAAiB,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAClD,YAAY,GAAE,MAAW,EACzB,KAAK,GAAE,MAAuB,EAC9B,WAAW,GAAE,QAAa,GACxB,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAsBxB;AAGD;;GAEG;AACH,wBAAsB,oBAAoB,CACzC,KAAK,EAAE,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,EAC3B,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,EAClD,YAAY,GAAE,MAAW,EACzB,KAAK,GAAE,MAAuB,EAC9B,cAAc,GAAE,MAAY,EAC5B,WAAW,GAAE,QAAa,GACxB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAc/B;AAED,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC"}
1
+ {"version":3,"file":"entities.d.ts","sourceRoot":"","sources":["../../../src/src/tools/entities.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAkB,KAAK,MAAM,EAAE,KAAK,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAkCzF;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACrC,qEAAqE;IACrE,iBAAiB,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpD,8BAA8B;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,qBAAa,eAAgB,SAAQ,IAAI,CAAC,MAAM,GAAG,IAAI,EAAE,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAChF,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;gBAE5B,MAAM,EAAE,qBAAqB,YAAK,EAAE,WAAW,EAAE,WAAW;cAgBrD,MAAM;;;;;;IAIzB,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;cAIjB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO;cAIrC,aAAa,CAAC,MAAM,EAAE,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC;CAGjE;AAGD,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC"}
@@ -1,8 +1,7 @@
1
- import { mapParallel } from '../async.js';
2
- import { askOpenAISafe } from '../openai.js';
1
+ import { Tool } from '../tool.js';
3
2
  import { EntitiesSchema } from '../schemas/entity.schema.js';
4
- import { dedent } from '../utils.js';
5
- export const PROMPT = dedent(`
3
+ import { dedent } from '../helpers/utils.js';
4
+ const PROMPT = dedent(`
6
5
  # Instructions
7
6
 
8
7
  From the Data Record section below extract entities in the following categories:
@@ -29,52 +28,33 @@ definitions include a "brand" category and a "product" category, the expected ou
29
28
  {text}
30
29
  `);
31
30
  /**
32
- *
33
- * Extracts free-form entities from the given text (without enforced entity types).
31
+ * A tool that extracts entities from text.
34
32
  */
35
- export async function extractAnyEntities(body, instructions = '', model, modelParams = {}) {
36
- const prompt = PROMPT
37
- .replace('{definitions}', '')
38
- .replace('{text}', body)
39
- .replace('{instructions}', instructions);
40
- const { parsed } = await askOpenAISafe(prompt, model, EntitiesSchema, modelParams);
41
- if (!parsed) {
42
- throw new Error('Failed to parse response from OpenAI');
33
+ export class EntityExtractor extends Tool {
34
+ promptTemplate;
35
+ constructor(config = {}, modelConfig) {
36
+ super(modelConfig);
37
+ const { entityDefinitions = '', instructions = '' } = config;
38
+ const definitionsText = typeof entityDefinitions === 'string'
39
+ ? entityDefinitions
40
+ : Object.entries(entityDefinitions)
41
+ .map(([type, description]) => `- ${type}: ${description}`)
42
+ .join('\n');
43
+ this.promptTemplate = PROMPT
44
+ .replace('{definitions}', definitionsText)
45
+ .replace('{instructions}', instructions);
43
46
  }
44
- return parsed.entities;
45
- }
46
- /**
47
- * Extracts entities in pre-specified categories from a single text.
48
- */
49
- export async function extractEntitiesFromText(text, entityDefinitions, instructions = '', model = 'gpt-4.1-mini', modelParams = {}) {
50
- if (text === null) {
51
- return [];
47
+ schema() {
48
+ return EntitiesSchema;
52
49
  }
53
- const definitionsText = typeof entityDefinitions === 'string'
54
- ? entityDefinitions
55
- : Object.entries(entityDefinitions)
56
- .map(([type, description]) => `- ${type}: ${description}`)
57
- .join('\n');
58
- const prompt = PROMPT
59
- .replace('{definitions}', definitionsText)
60
- .replace('{text}', text)
61
- .replace('{instructions}', instructions);
62
- const { parsed } = await askOpenAISafe(prompt, model, EntitiesSchema, modelParams);
63
- if (!parsed) {
64
- throw new Error('Failed to parse response from OpenAI');
50
+ prompt(text) {
51
+ return this.promptTemplate.replace('{text}', text ?? '');
52
+ }
53
+ isEmpty(text) {
54
+ return text == null || text.trim() === '';
55
+ }
56
+ extractResult(parsed) {
57
+ return parsed.entities;
65
58
  }
66
- return parsed.entities;
67
- }
68
- /**
69
- * Extracts entities from a batch of texts.
70
- */
71
- export async function extractEntitiesBatch(texts, entityDefinitions, instructions = '', model = 'gpt-4.1-mini', maxConcurrency = 100, modelParams = {}) {
72
- // Do this once outside the loop
73
- const definitions = typeof entityDefinitions === 'string'
74
- ? entityDefinitions
75
- : Object.entries(entityDefinitions)
76
- .map(([type, description]) => `- ${type}: ${description}`)
77
- .join('\n');
78
- return mapParallel(texts, maxConcurrency, (text) => extractEntitiesFromText(text, definitions, instructions, model, modelParams));
79
59
  }
80
60
  export { EntitySchema, EntitiesSchema } from '../schemas/entity.schema.js';
@@ -1,7 +1,7 @@
1
- import { mapParallel } from '../async.js';
2
- import { askOpenAISafe } from '../openai.js';
1
+ import { mapParallel } from '../helpers/async.js';
2
+ import { askLLMSafe } from '../llm.js';
3
3
  import { FunnelWithExplanationSchema, SeedsSchema } from '../schemas/funnel.schema.js';
4
- import { dedent } from '../utils.js';
4
+ import { dedent } from '../helpers/utils.js';
5
5
  export { FunnelWithExplanationSchema };
6
6
  /**
7
7
  * Iterates over all categories in a funnel, yielding references to stage info and category objects.
@@ -294,9 +294,9 @@ export async function customizeFunnel(sector, language, userLanguage = null, cou
294
294
  .replace('{language}', language)
295
295
  .replace('{userLanguage}', userLanguage ?? language)
296
296
  .replace('{funnel}', JSON.stringify(funnelData, null, 2));
297
- const { parsed } = await askOpenAISafe(prompt, model, FunnelWithExplanationSchema);
297
+ const { parsed } = await askLLMSafe({ prompt, model, schema: FunnelWithExplanationSchema });
298
298
  if (!parsed) {
299
- throw new Error('Failed to parse response from OpenAI');
299
+ throw new Error('Failed to parse response from LLM');
300
300
  }
301
301
  return parsed;
302
302
  }
@@ -337,9 +337,9 @@ export async function generateSeedKeywords(stage, goal, category, sector, langua
337
337
  .replace('{sector}', sector)
338
338
  .replace('{market}', country)
339
339
  .replace('{language}', language);
340
- const { parsed } = await askOpenAISafe(prompt, model, SeedsSchema);
340
+ const { parsed } = await askLLMSafe({ prompt, model, schema: SeedsSchema });
341
341
  if (!parsed) {
342
- throw new Error('Failed to parse seed keywords from OpenAI');
342
+ throw new Error('Failed to parse seed keywords from LLM');
343
343
  }
344
344
  return parsed.seeds;
345
345
  }
@@ -5,7 +5,9 @@
5
5
  * is either provided directly or inferred from the user's instructions using an LLM.
6
6
  */
7
7
  import { z } from '../../deps/jsr.io/@zod/zod/4.3.6/src/index.js';
8
- import { type AIParams } from '../openai.js';
8
+ import { type LLMResponse, type ProviderParams } from '../llm.js';
9
+ import { BatchResponse } from '../response.js';
10
+ export type AIParams = ProviderParams;
9
11
  /**
10
12
  * Schema for the schema generation response.
11
13
  */
@@ -42,15 +44,18 @@ export interface GenericBatchOptions extends BaseLLMOptions {
42
44
  records: Array<Record<string, unknown> | null>;
43
45
  schema: Record<string, unknown>;
44
46
  maxConcurrency?: number;
47
+ trackCost?: boolean;
45
48
  }
46
49
  /**
47
50
  * Processes a single record using an LLM with a provided JSON schema.
51
+ * Returns both the result and usage information.
48
52
  */
49
- export declare function generic<T = Record<string, unknown>>({ record, instructions, schema, model, modelParams, maxRetries }: GenericOptions): Promise<T | null>;
53
+ export declare function generic<T = Record<string, unknown>>({ record, instructions, schema, model, modelParams, maxRetries }: GenericOptions): Promise<LLMResponse<T | null>>;
50
54
  /**
51
55
  * Processes multiple records using an LLM with a provided JSON schema.
56
+ * Returns a BatchResponse with usage tracking.
52
57
  */
53
- export declare function genericBatch<T = Record<string, unknown>>({ records, instructions, schema, model, modelParams, maxRetries, maxConcurrency }: GenericBatchOptions): Promise<Array<T | null>>;
58
+ export declare function genericBatch<T = Record<string, unknown>>({ records, instructions, schema, model, modelParams, maxRetries, maxConcurrency, trackCost, }: GenericBatchOptions): Promise<BatchResponse<T | null>>;
54
59
  /** Common options for auto functions */
55
60
  interface BaseAutoOptions extends BaseLLMOptions {
56
61
  schemaOrInstructions?: string | Record<string, unknown> | null;
@@ -78,11 +83,19 @@ export interface AutoResult<T> {
78
83
  * 3. Processes the record using the generated schema
79
84
  */
80
85
  export declare function auto<T = Record<string, unknown>>({ record, instructions, schemaOrInstructions, model, schemaModel, modelParams, maxRetries }: AutoOptions): Promise<AutoResult<T | null>>;
86
+ /**
87
+ * Result from autoBatch includes schema info and BatchResponse.
88
+ */
89
+ export interface AutoBatchResult<T> {
90
+ data: BatchResponse<T | null>;
91
+ schema: Record<string, unknown>;
92
+ schemaReasoning: string;
93
+ }
81
94
  /**
82
95
  * Automatically generates a response schema and processes multiple records.
83
96
  *
84
97
  * The schema is generated once from the instructions, then used to process all records.
85
98
  */
86
- export declare function autoBatch<T = Record<string, unknown>>({ records, instructions, schemaOrInstructions, model, schemaModel, modelParams, maxRetries, maxConcurrency }: AutoBatchOptions): Promise<AutoResult<Array<T | null>>>;
99
+ export declare function autoBatch<T = Record<string, unknown>>({ records, instructions, schemaOrInstructions, model, schemaModel, modelParams, maxRetries, maxConcurrency }: AutoBatchOptions): Promise<AutoBatchResult<T>>;
87
100
  export {};
88
101
  //# sourceMappingURL=generic.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"generic.d.ts","sourceRoot":"","sources":["../../../src/src/tools/generic.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"generic.d.ts","sourceRoot":"","sources":["../../../src/src/tools/generic.ts"],"names":[],"mappings":"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"}
@@ -5,9 +5,10 @@
5
5
  * is either provided directly or inferred from the user's instructions using an LLM.
6
6
  */
7
7
  import { z } from '../../deps/jsr.io/@zod/zod/4.3.6/src/index.js';
8
- import { mapParallel } from '../async.js';
9
- import { askOpenAISafe } from '../openai.js';
10
- import { dedent } from '../utils.js';
8
+ import { mapParallel } from '../helpers/async.js';
9
+ import { askLLMSafe } from '../llm.js';
10
+ import { BatchResponse } from '../response.js';
11
+ import { dedent } from '../helpers/utils.js';
11
12
  // ============================================================================
12
13
  // Prompts
13
14
  // ============================================================================
@@ -108,7 +109,14 @@ export async function generateSchema({ instructions, model = 'gpt-4.1', modelPar
108
109
  { role: 'system', content: SCHEMA_GENERATION_SYSTEM_PROMPT },
109
110
  { role: 'user', content: SCHEMA_GENERATION_PROMPT.replace('{instructions}', instructions) }
110
111
  ];
111
- const { parsed, error } = await askOpenAISafe(prompt, model, SchemaResponseSchema, modelParams, maxRetries, 'return');
112
+ const { parsed, error } = await askLLMSafe({
113
+ prompt,
114
+ model,
115
+ schema: SchemaResponseSchema,
116
+ params: modelParams,
117
+ maxRetries,
118
+ onError: 'return',
119
+ });
112
120
  if (error || !parsed) {
113
121
  throw new Error(`Failed to generate schema: ${error?.message ?? 'Unknown error'}`);
114
122
  }
@@ -120,7 +128,14 @@ export async function generateSchema({ instructions, model = 'gpt-4.1', modelPar
120
128
  */
121
129
  async function convertToSchemaInstructions(instructions, model, modelParams, maxRetries) {
122
130
  const prompt = SCHEMA_CONVERSION_PROMPT.replace('{instructions}', instructions);
123
- const { parsed, error } = await askOpenAISafe(prompt, model, SchemaInstructionsSchema, modelParams, maxRetries, 'return');
131
+ const { parsed, error } = await askLLMSafe({
132
+ prompt,
133
+ model,
134
+ schema: SchemaInstructionsSchema,
135
+ params: modelParams,
136
+ maxRetries,
137
+ onError: 'return',
138
+ });
124
139
  if (error || !parsed) {
125
140
  throw new Error(`Failed to convert instructions: ${error?.message ?? 'Unknown error'}`);
126
141
  }
@@ -128,26 +143,36 @@ async function convertToSchemaInstructions(instructions, model, modelParams, max
128
143
  }
129
144
  /**
130
145
  * Processes a single record using an LLM with a provided JSON schema.
146
+ * Returns both the result and usage information.
131
147
  */
132
148
  export async function generic({ record, instructions, schema, model = 'gpt-4.1-mini', modelParams = {}, maxRetries = 3 }) {
133
149
  if (record == null || Object.keys(record).length === 0) {
134
- return null;
150
+ return { parsed: null, text: null, usage: null, error: null };
135
151
  }
136
152
  const zodSchema = z.fromJSONSchema(schema);
137
153
  const prompt = GENERIC_PROMPT
138
154
  .replace('{instructions}', instructions)
139
155
  .replace('{record}', formatRecord(record));
140
- const { parsed, error } = await askOpenAISafe(prompt, model, zodSchema, modelParams, maxRetries, 'return');
141
- if (error || parsed == null) {
142
- throw new Error(`Failed to process record: ${error?.message ?? 'Unknown error'}`);
156
+ const response = await askLLMSafe({
157
+ prompt,
158
+ model,
159
+ schema: zodSchema,
160
+ params: modelParams,
161
+ maxRetries,
162
+ onError: 'return',
163
+ });
164
+ if (response.error || response.parsed == null) {
165
+ throw new Error(`Failed to process record: ${response.error?.message ?? 'Unknown error'}`);
143
166
  }
144
- return parsed;
167
+ return { parsed: response.parsed, text: response.text, usage: response.usage, error: null };
145
168
  }
146
169
  /**
147
170
  * Processes multiple records using an LLM with a provided JSON schema.
171
+ * Returns a BatchResponse with usage tracking.
148
172
  */
149
- export function genericBatch({ records, instructions, schema, model = 'gpt-4.1-mini', modelParams = {}, maxRetries = 3, maxConcurrency = 100 }) {
150
- return mapParallel(records, maxConcurrency, (record) => generic({ record, instructions, schema, model, modelParams, maxRetries }));
173
+ export async function genericBatch({ records, instructions, schema, model = 'gpt-4.1-mini', modelParams = {}, maxRetries = 3, maxConcurrency = 100, trackCost = false, }) {
174
+ const responses = await mapParallel(records, maxConcurrency, (record) => generic({ record, instructions, schema, model, modelParams, maxRetries }));
175
+ return new BatchResponse(responses.map(r => r.parsed), trackCost ? responses.map(r => r.usage) : undefined, trackCost ? model : undefined);
151
176
  }
152
177
  /**
153
178
  * Resolves a schema from various input types:
@@ -189,7 +214,7 @@ async function resolveSchema(schemaOrInstructions, taskInstructions, model, mode
189
214
  */
190
215
  export async function auto({ record, instructions, schemaOrInstructions = null, model = 'gpt-4.1-mini', schemaModel = 'gpt-4.1', modelParams = {}, maxRetries = 3 }) {
191
216
  const { schema, schemaReasoning } = await resolveSchema(schemaOrInstructions, instructions, schemaModel, modelParams, maxRetries);
192
- const data = await generic({
217
+ const response = await generic({
193
218
  record,
194
219
  instructions,
195
220
  schema,
@@ -197,7 +222,7 @@ export async function auto({ record, instructions, schemaOrInstructions = null,
197
222
  modelParams,
198
223
  maxRetries
199
224
  });
200
- return { data, schema, schemaReasoning };
225
+ return { data: response.parsed, schema, schemaReasoning };
201
226
  }
202
227
  /**
203
228
  * Automatically generates a response schema and processes multiple records.
@@ -1,8 +1,8 @@
1
- import { mapParallel } from '../async.js';
2
- import { askOpenAISafe } from '../openai.js';
1
+ import { mapParallel } from '../helpers/async.js';
2
+ import { askLLMSafe } from '../llm.js';
3
3
  import { buildBrandContext } from './brands.js';
4
4
  import { KeywordsResponseSchema } from '../schemas/keyword.schema.js';
5
- import { dedent } from '../utils.js';
5
+ import { dedent } from '../helpers/utils.js';
6
6
  import { keywords as getGoogleAdsKeywords } from '../apis/googleAds/keywordPlanner.js';
7
7
  export async function expandKeywords({ seedKeywords, url, urlAsExpandRelevanceContext, language = 'EN', countryISOCode, generateIdeasFromSeeds = false, includeSeedKeywords = false }) {
8
8
  url = url?.trim();
@@ -163,9 +163,9 @@ export async function generateKeywords({ sector, market, brand, brandDomain, lan
163
163
  .replaceAll('{brandsInfo}', brandsInfo || '')
164
164
  .replaceAll('{personasInfo}', personasInfo || '')
165
165
  .replaceAll('{funnelInfo}', funnelInfo || '');
166
- const { parsed } = await askOpenAISafe(content, model, KeywordsResponseSchema);
166
+ const { parsed } = await askLLMSafe({ prompt: content, model, schema: KeywordsResponseSchema });
167
167
  if (!parsed) {
168
- throw new Error('Failed to parse response from OpenAI');
168
+ throw new Error('Failed to parse response from LLM');
169
169
  }
170
170
  return parsed;
171
171
  }