@graphext/cuery 0.6.2 → 0.7.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.
@@ -14,7 +14,6 @@ export type * from './persona.schema.js';
14
14
  export type * from './brand.schema.js';
15
15
  export type * from './funnel.schema.js';
16
16
  export type * from './keyword.schema.js';
17
- export type * from './pipeline.schema.js';
18
17
  export type * from './models.schema.js';
19
18
  export type * from './seedKeyword.schema.js';
20
19
  export type * from './topics.schema.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/src/schemas/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,mBAAmB,qBAAqB,CAAC;AACzC,mBAAmB,mBAAmB,CAAC;AACvC,mBAAmB,oBAAoB,CAAC;AACxC,mBAAmB,qBAAqB,CAAC;AACzC,mBAAmB,sBAAsB,CAAC;AAC1C,mBAAmB,oBAAoB,CAAC;AACxC,mBAAmB,yBAAyB,CAAC;AAC7C,mBAAmB,oBAAoB,CAAC;AACxC,mBAAmB,qBAAqB,CAAC;AACzC,mBAAmB,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/src/schemas/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,mBAAmB,qBAAqB,CAAC;AACzC,mBAAmB,mBAAmB,CAAC;AACvC,mBAAmB,oBAAoB,CAAC;AACxC,mBAAmB,qBAAqB,CAAC;AACzC,mBAAmB,oBAAoB,CAAC;AACxC,mBAAmB,yBAAyB,CAAC;AAC7C,mBAAmB,oBAAoB,CAAC;AACxC,mBAAmB,qBAAqB,CAAC;AACzC,mBAAmB,oBAAoB,CAAC"}
@@ -6,6 +6,8 @@ export declare const ABSentimentSchema: z.ZodObject<{
6
6
  negative: "negative";
7
7
  }>;
8
8
  reason: z.ZodString;
9
+ quote: z.ZodString;
10
+ context: z.ZodNullable<z.ZodString>;
9
11
  }, z.core.$strip>;
10
12
  export declare const ABSentimentsSchema: z.ZodObject<{
11
13
  aspects: z.ZodArray<z.ZodObject<{
@@ -15,6 +17,8 @@ export declare const ABSentimentsSchema: z.ZodObject<{
15
17
  negative: "negative";
16
18
  }>;
17
19
  reason: z.ZodString;
20
+ quote: z.ZodString;
21
+ context: z.ZodNullable<z.ZodString>;
18
22
  }, z.core.$strip>>;
19
23
  }, z.core.$strip>;
20
24
  export type ABSentiment = z.infer<typeof ABSentimentSchema>;
@@ -1 +1 @@
1
- {"version":3,"file":"sentiment.schema.d.ts","sourceRoot":"","sources":["../../../src/src/schemas/sentiment.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,+CAA+C,CAAC;AAElE,eAAO,MAAM,iBAAiB;;;;;;;iBAI5B,CAAC;AAEH,eAAO,MAAM,kBAAkB;;;;;;;;;iBAE7B,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC5D,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC"}
1
+ {"version":3,"file":"sentiment.schema.d.ts","sourceRoot":"","sources":["../../../src/src/schemas/sentiment.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,+CAA+C,CAAC;AAElE,eAAO,MAAM,iBAAiB;;;;;;;;;iBAc5B,CAAC;AAEH,eAAO,MAAM,kBAAkB;;;;;;;;;;;iBAE7B,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC5D,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC"}
@@ -2,8 +2,12 @@ import { z } from '../../deps/jsr.io/@zod/zod/4.3.6/src/index.js';
2
2
  export const ABSentimentSchema = z.object({
3
3
  aspect: z.string().describe('The specific entity or aspect mentioned in the text.'),
4
4
  sentiment: z.enum(['positive', 'negative']).describe('The sentiment expressed toward the aspect, either positive or negative.'),
5
- reason: z.string().describe('A brief explanation of why this sentiment was assigned to the aspect.')
5
+ reason: z.string().describe('A brief explanation of why this sentiment was assigned to the aspect.'),
6
+ quote: z.string().min(1).refine((val) => val.trim().length > 0, {
7
+ message: 'Quote must not be empty or whitespace-only',
8
+ }).describe('The exact text fragment from the input containing both the aspect and the sentiment expressed about it.'),
9
+ context: z.string().nullable().describe('Optional contextual information about the aspect, such as the brand or entity it relates to.'),
6
10
  });
7
11
  export const ABSentimentsSchema = z.object({
8
- aspects: z.array(ABSentimentSchema).describe('A list of aspects with their associated sentiments and reasons.')
12
+ aspects: z.array(ABSentimentSchema).describe('A list of aspects with their associated sentiments, reasons, quotes, and optional context.')
9
13
  });
@@ -1,7 +1,7 @@
1
- import type { Message } from '../llm.js';
1
+ import type { LLMResponse, Message } from '../llm.js';
2
2
  import type { BrandContext } from '../schemas/brand.schema.js';
3
3
  import { type ABSentiment, type ABSentiments } from '../schemas/sentiment.schema.js';
4
- import { Tool, type ModelConfig } from '../tool.js';
4
+ import { type ModelConfig, Tool } from '../tool.js';
5
5
  import { Classifier } from './classifier.js';
6
6
  export interface SentimentExtractorConfig {
7
7
  /** Additional instructions for sentiment extraction */
@@ -23,11 +23,17 @@ export declare class SentimentExtractor extends Tool<string | null, ABSentiments
23
23
  negative: "negative";
24
24
  }>;
25
25
  reason: import("../../deps/jsr.io/@zod/zod/4.3.6/src/index.js").ZodString;
26
+ quote: import("../../deps/jsr.io/@zod/zod/4.3.6/src/index.js").ZodString;
27
+ context: import("../../deps/jsr.io/@zod/zod/4.3.6/src/index.js").ZodNullable<import("../../deps/jsr.io/@zod/zod/4.3.6/src/index.js").ZodString>;
26
28
  }, import("../../deps/jsr.io/@zod/zod/4.3.6/src/v4/core/schemas.js").$strip>>;
27
29
  }, import("../../deps/jsr.io/@zod/zod/4.3.6/src/v4/core/schemas.js").$strip>;
28
30
  protected prompt(text: string | null): Message[];
29
31
  protected isEmpty(text: string | null): boolean;
30
32
  protected extractResult(parsed: ABSentiments): Array<ABSentiment>;
33
+ /**
34
+ * Override invoke to add quote validation
35
+ */
36
+ invoke(input: string | null, options?: Partial<ModelConfig>): Promise<LLMResponse<Array<ABSentiment> | null>>;
31
37
  }
32
38
  /**
33
39
  * Sentiment polarity labels for classification.
@@ -1 +1 @@
1
- {"version":3,"file":"sentiment.d.ts","sourceRoot":"","sources":["../../../src/src/tools/sentiment.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAsB,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,MAAM,gCAAgC,CAAC;AACzG,OAAO,EAAE,IAAI,EAAE,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAwC7C,MAAM,WAAW,wBAAwB;IACxC,uDAAuD;IACvD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yCAAyC;IACzC,KAAK,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;CAC5B;AAED;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,IAAI,CAAC,MAAM,GAAG,IAAI,EAAE,YAAY,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC;IAC5F,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;gBAE1B,MAAM,EAAE,wBAAwB,YAAK,EAAE,WAAW,EAAE,WAAW;cAgBxD,MAAM;;;;;;;;;;IAIzB,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,EAAE;cAQ7B,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO;cAIrC,aAAa,CAAC,MAAM,EAAE,YAAY,GAAG,KAAK,CAAC,WAAW,CAAC;CAG1E;AAMD;;GAEG;AACH,eAAO,MAAM,yBAAyB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAI5D,CAAC;AAWF;;GAEG;AACH,MAAM,WAAW,iCAAiC;IACjD,iDAAiD;IACjD,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,qBAAa,2BAA4B,SAAQ,UAAU;gBAC9C,MAAM,EAAE,iCAAiC,YAAK,EAAE,WAAW,EAAE,WAAW;CAOpF;AAED,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACvF,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC"}
1
+ {"version":3,"file":"sentiment.d.ts","sourceRoot":"","sources":["../../../src/src/tools/sentiment.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAW,MAAM,4BAA4B,CAAC;AACxE,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,YAAY,EAAsB,MAAM,gCAAgC,CAAC;AACzG,OAAO,EAAE,KAAK,WAAW,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AA6D7C,MAAM,WAAW,wBAAwB;IACxC,uDAAuD;IACvD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yCAAyC;IACzC,KAAK,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;CAC5B;AAED;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,IAAI,CAAC,MAAM,GAAG,IAAI,EAAE,YAAY,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC;IAC5F,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;gBAE1B,MAAM,EAAE,wBAAwB,YAAK,EAAE,WAAW,EAAE,WAAW;cAuBxD,MAAM;;;;;;;;;;;;IAIzB,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,EAAE;cAQ7B,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO;cAIrC,aAAa,CAAC,MAAM,EAAE,YAAY,GAAG,KAAK,CAAC,WAAW,CAAC;IAI1E;;OAEG;IACY,MAAM,CACpB,KAAK,EAAE,MAAM,GAAG,IAAI,EACpB,OAAO,GAAE,OAAO,CAAC,WAAW,CAAM,GAChC,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,IAAI,CAAC,CAAC;CA+BlD;AAMD;;GAEG;AACH,eAAO,MAAM,yBAAyB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAI5D,CAAC;AAWF;;GAEG;AACH,MAAM,WAAW,iCAAiC;IACjD,iDAAiD;IACjD,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,qBAAa,2BAA4B,SAAQ,UAAU;gBAC9C,MAAM,EAAE,iCAAiC,YAAK,EAAE,WAAW,EAAE,WAAW;CAOpF;AAED,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACvF,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC"}
@@ -2,6 +2,15 @@ import { dedent } from '../helpers/utils.js';
2
2
  import { ABSentimentsSchema } from '../schemas/sentiment.schema.js';
3
3
  import { Tool } from '../tool.js';
4
4
  import { Classifier } from './classifier.js';
5
+ /**
6
+ * Formats a portfolio array as a comma-separated list of product/service names.
7
+ * Includes category in parentheses if available.
8
+ */
9
+ function formatPortfolio(portfolio) {
10
+ return portfolio
11
+ .map((p) => (p.category ? `${p.name} (${p.category})` : p.name))
12
+ .join(', ');
13
+ }
5
14
  const ABS_PROMPT_SYSTEM = dedent(`
6
15
  You're an expert in Aspect-Based Sentiment Analysis. Your task involves identifying specific
7
16
  entities mentioned in a text (e.g. a person, product, service, or experience) and determining the
@@ -15,10 +24,23 @@ Specifically:
15
24
  a. the aspect as it occurs in the text (key "aspect")
16
25
  b. the sentiment label as either "positive" or "negative" (key "sentiment")
17
26
  c. the reason for the sentiment assignment as a short text (key "reason")
27
+ d. the exact text fragment containing both the aspect and what is said about it (key "quote") - must be a verbatim substring
28
+ e. optional contextual information about the aspect, such as the brand or entity it relates to (key "context") - use null if not applicable
18
29
  4. If there are no sentiment-bearing aspects in the text, the output should be an empty list
19
30
 
20
- Example Output format:
21
- [{"aspect": "room service", "sentiment": "negative", "reason": "Room service was mentioned being rude."}, ...]
31
+ IMPORTANT: The "quote" field must be an EXACT verbatim substring from the input text. It should
32
+ include the complete phrase mentioning both the aspect and the sentiment expressed about it.
33
+
34
+ Example:
35
+
36
+ Input text: "The room service at the Grand Hotel was absolutely terrible and the staff were rude, but the view from our room was breathtaking."
37
+
38
+ Output:
39
+ [
40
+ {"aspect": "The room service at the Grand Hotel", "sentiment": "negative", "reason": "Described as terrible.", "quote": "The room service at the Grand Hotel was absolutely terrible", "context": "Grand Hotel"},
41
+ {"aspect": "the staff", "sentiment": "negative", "reason": "Described as rude.", "quote": "the staff were rude", "context": "Grand Hotel"},
42
+ {"aspect": "the view from our room", "sentiment": "positive", "reason": "Described as breathtaking.", "quote": "the view from our room was breathtaking", "context": "Grand Hotel"}
43
+ ]
22
44
 
23
45
  Only extract aspects that have an explicitly expressed sentiment associated with them, i.e.
24
46
  subjective opinions, feelings, or evaluations. Do not infer sentiment from factual statements,
@@ -45,11 +67,18 @@ export class SentimentExtractor extends Tool {
45
67
  super(modelConfig);
46
68
  const { instructions = '', brand = null } = config;
47
69
  const brandInstructions = brand
48
- ? dedent(`
49
- When analyzing the text, pay special attention to any mentions of the brand "${brand.shortName}"
50
- or its products/services (${brand.portfolio}). Ensure that any sentiments expressed toward this
51
- brand or its offerings are accurately captured in your output. Respond in language code ${brand.language}.
52
- `)
70
+ ? (() => {
71
+ const portfolio = formatPortfolio(brand.portfolio);
72
+ const portfolioText = portfolio
73
+ ? ` or its products/services (${portfolio})`
74
+ : '';
75
+ return dedent(`
76
+ Pay special attention to mentions of "${brand.shortName}"${portfolioText}.
77
+ When an aspect relates to a brand/entity, set the "context" field to "${brand.shortName}".
78
+ Keep aspect names and quoted text exactly as they appear in the original input.
79
+ Respond in language code ${brand.language}.
80
+ `);
81
+ })()
53
82
  : '';
54
83
  const combinedInstructions = [instructions, brandInstructions].filter(Boolean).join('\n\n');
55
84
  this.systemPrompt = ABS_PROMPT_SYSTEM.replace('{instructions}', combinedInstructions);
@@ -61,7 +90,7 @@ export class SentimentExtractor extends Tool {
61
90
  const userPrompt = ABS_PROMPT_USER.replace('{text}', text ?? '');
62
91
  return [
63
92
  { role: 'system', content: this.systemPrompt },
64
- { role: 'user', content: userPrompt }
93
+ { role: 'user', content: userPrompt },
65
94
  ];
66
95
  }
67
96
  isEmpty(text) {
@@ -70,6 +99,33 @@ export class SentimentExtractor extends Tool {
70
99
  extractResult(parsed) {
71
100
  return parsed.aspects;
72
101
  }
102
+ /**
103
+ * Override invoke to add quote validation
104
+ */
105
+ async invoke(input, options = {}) {
106
+ const response = await super.invoke(input, options);
107
+ // If we have a successful result and non-empty input, validate quotes
108
+ if (response.parsed && input && input.trim() !== '') {
109
+ const validatedResult = response.parsed.filter((sentiment) => {
110
+ // Check that quote is non-empty and not just whitespace
111
+ if (!sentiment.quote || sentiment.quote.trim().length === 0) {
112
+ console.warn(`Empty or whitespace-only quote for aspect "${sentiment.aspect}"`);
113
+ return false;
114
+ }
115
+ // Check that quote is a substring of the input
116
+ if (!input.includes(sentiment.quote)) {
117
+ console.warn(`Quote not found in text: "${sentiment.quote}" for aspect "${sentiment.aspect}"`);
118
+ return false;
119
+ }
120
+ return true;
121
+ });
122
+ return {
123
+ ...response,
124
+ parsed: validatedResult,
125
+ };
126
+ }
127
+ return response;
128
+ }
73
129
  }
74
130
  // =============================================================================
75
131
  // SentimentPolarityClassifier (overall sentiment polarity)
@@ -80,7 +136,7 @@ export class SentimentExtractor extends Tool {
80
136
  export const SENTIMENT_POLARITY_LABELS = {
81
137
  positive: 'Expresses favorable opinions, approval, satisfaction, or optimism.',
82
138
  neutral: 'No clear sentiment expressed; factual, balanced, or ambiguous.',
83
- negative: 'Expresses unfavorable opinions, criticism, dissatisfaction, or pessimism.'
139
+ negative: 'Expresses unfavorable opinions, criticism, dissatisfaction, or pessimism.',
84
140
  };
85
141
  /**
86
142
  * Predefined instructions for sentiment polarity classification.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graphext/cuery",
3
- "version": "0.6.2",
3
+ "version": "0.7.0",
4
4
  "description": "Cuery tools for AI-powered keyword research and brand analysis",
5
5
  "repository": {
6
6
  "type": "git",
@@ -14,7 +14,6 @@ export type * from './persona.schema.js';
14
14
  export type * from './brand.schema.js';
15
15
  export type * from './funnel.schema.js';
16
16
  export type * from './keyword.schema.js';
17
- export type * from './pipeline.schema.js';
18
17
  export type * from './models.schema.js';
19
18
  export type * from './seedKeyword.schema.js';
20
19
  export type * from './topics.schema.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/src/schemas/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,mBAAmB,qBAAqB,CAAC;AACzC,mBAAmB,mBAAmB,CAAC;AACvC,mBAAmB,oBAAoB,CAAC;AACxC,mBAAmB,qBAAqB,CAAC;AACzC,mBAAmB,sBAAsB,CAAC;AAC1C,mBAAmB,oBAAoB,CAAC;AACxC,mBAAmB,yBAAyB,CAAC;AAC7C,mBAAmB,oBAAoB,CAAC;AACxC,mBAAmB,qBAAqB,CAAC;AACzC,mBAAmB,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/src/schemas/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,mBAAmB,qBAAqB,CAAC;AACzC,mBAAmB,mBAAmB,CAAC;AACvC,mBAAmB,oBAAoB,CAAC;AACxC,mBAAmB,qBAAqB,CAAC;AACzC,mBAAmB,oBAAoB,CAAC;AACxC,mBAAmB,yBAAyB,CAAC;AAC7C,mBAAmB,oBAAoB,CAAC;AACxC,mBAAmB,qBAAqB,CAAC;AACzC,mBAAmB,oBAAoB,CAAC"}
@@ -6,6 +6,8 @@ export declare const ABSentimentSchema: z.ZodObject<{
6
6
  negative: "negative";
7
7
  }>;
8
8
  reason: z.ZodString;
9
+ quote: z.ZodString;
10
+ context: z.ZodNullable<z.ZodString>;
9
11
  }, z.core.$strip>;
10
12
  export declare const ABSentimentsSchema: z.ZodObject<{
11
13
  aspects: z.ZodArray<z.ZodObject<{
@@ -15,6 +17,8 @@ export declare const ABSentimentsSchema: z.ZodObject<{
15
17
  negative: "negative";
16
18
  }>;
17
19
  reason: z.ZodString;
20
+ quote: z.ZodString;
21
+ context: z.ZodNullable<z.ZodString>;
18
22
  }, z.core.$strip>>;
19
23
  }, z.core.$strip>;
20
24
  export type ABSentiment = z.infer<typeof ABSentimentSchema>;
@@ -1 +1 @@
1
- {"version":3,"file":"sentiment.schema.d.ts","sourceRoot":"","sources":["../../../src/src/schemas/sentiment.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,+CAA+C,CAAC;AAElE,eAAO,MAAM,iBAAiB;;;;;;;iBAI5B,CAAC;AAEH,eAAO,MAAM,kBAAkB;;;;;;;;;iBAE7B,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC5D,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC"}
1
+ {"version":3,"file":"sentiment.schema.d.ts","sourceRoot":"","sources":["../../../src/src/schemas/sentiment.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,+CAA+C,CAAC;AAElE,eAAO,MAAM,iBAAiB;;;;;;;;;iBAc5B,CAAC;AAEH,eAAO,MAAM,kBAAkB;;;;;;;;;;;iBAE7B,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC5D,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC"}
@@ -5,8 +5,12 @@ const index_js_1 = require("../../deps/jsr.io/@zod/zod/4.3.6/src/index.js");
5
5
  exports.ABSentimentSchema = index_js_1.z.object({
6
6
  aspect: index_js_1.z.string().describe('The specific entity or aspect mentioned in the text.'),
7
7
  sentiment: index_js_1.z.enum(['positive', 'negative']).describe('The sentiment expressed toward the aspect, either positive or negative.'),
8
- reason: index_js_1.z.string().describe('A brief explanation of why this sentiment was assigned to the aspect.')
8
+ reason: index_js_1.z.string().describe('A brief explanation of why this sentiment was assigned to the aspect.'),
9
+ quote: index_js_1.z.string().min(1).refine((val) => val.trim().length > 0, {
10
+ message: 'Quote must not be empty or whitespace-only',
11
+ }).describe('The exact text fragment from the input containing both the aspect and the sentiment expressed about it.'),
12
+ context: index_js_1.z.string().nullable().describe('Optional contextual information about the aspect, such as the brand or entity it relates to.'),
9
13
  });
10
14
  exports.ABSentimentsSchema = index_js_1.z.object({
11
- aspects: index_js_1.z.array(exports.ABSentimentSchema).describe('A list of aspects with their associated sentiments and reasons.')
15
+ aspects: index_js_1.z.array(exports.ABSentimentSchema).describe('A list of aspects with their associated sentiments, reasons, quotes, and optional context.')
12
16
  });
@@ -1,7 +1,7 @@
1
- import type { Message } from '../llm.js';
1
+ import type { LLMResponse, Message } from '../llm.js';
2
2
  import type { BrandContext } from '../schemas/brand.schema.js';
3
3
  import { type ABSentiment, type ABSentiments } from '../schemas/sentiment.schema.js';
4
- import { Tool, type ModelConfig } from '../tool.js';
4
+ import { type ModelConfig, Tool } from '../tool.js';
5
5
  import { Classifier } from './classifier.js';
6
6
  export interface SentimentExtractorConfig {
7
7
  /** Additional instructions for sentiment extraction */
@@ -23,11 +23,17 @@ export declare class SentimentExtractor extends Tool<string | null, ABSentiments
23
23
  negative: "negative";
24
24
  }>;
25
25
  reason: import("../../deps/jsr.io/@zod/zod/4.3.6/src/index.js").ZodString;
26
+ quote: import("../../deps/jsr.io/@zod/zod/4.3.6/src/index.js").ZodString;
27
+ context: import("../../deps/jsr.io/@zod/zod/4.3.6/src/index.js").ZodNullable<import("../../deps/jsr.io/@zod/zod/4.3.6/src/index.js").ZodString>;
26
28
  }, import("../../deps/jsr.io/@zod/zod/4.3.6/src/v4/core/schemas.js").$strip>>;
27
29
  }, import("../../deps/jsr.io/@zod/zod/4.3.6/src/v4/core/schemas.js").$strip>;
28
30
  protected prompt(text: string | null): Message[];
29
31
  protected isEmpty(text: string | null): boolean;
30
32
  protected extractResult(parsed: ABSentiments): Array<ABSentiment>;
33
+ /**
34
+ * Override invoke to add quote validation
35
+ */
36
+ invoke(input: string | null, options?: Partial<ModelConfig>): Promise<LLMResponse<Array<ABSentiment> | null>>;
31
37
  }
32
38
  /**
33
39
  * Sentiment polarity labels for classification.
@@ -1 +1 @@
1
- {"version":3,"file":"sentiment.d.ts","sourceRoot":"","sources":["../../../src/src/tools/sentiment.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAsB,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,MAAM,gCAAgC,CAAC;AACzG,OAAO,EAAE,IAAI,EAAE,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAwC7C,MAAM,WAAW,wBAAwB;IACxC,uDAAuD;IACvD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yCAAyC;IACzC,KAAK,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;CAC5B;AAED;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,IAAI,CAAC,MAAM,GAAG,IAAI,EAAE,YAAY,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC;IAC5F,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;gBAE1B,MAAM,EAAE,wBAAwB,YAAK,EAAE,WAAW,EAAE,WAAW;cAgBxD,MAAM;;;;;;;;;;IAIzB,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,EAAE;cAQ7B,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO;cAIrC,aAAa,CAAC,MAAM,EAAE,YAAY,GAAG,KAAK,CAAC,WAAW,CAAC;CAG1E;AAMD;;GAEG;AACH,eAAO,MAAM,yBAAyB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAI5D,CAAC;AAWF;;GAEG;AACH,MAAM,WAAW,iCAAiC;IACjD,iDAAiD;IACjD,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,qBAAa,2BAA4B,SAAQ,UAAU;gBAC9C,MAAM,EAAE,iCAAiC,YAAK,EAAE,WAAW,EAAE,WAAW;CAOpF;AAED,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACvF,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC"}
1
+ {"version":3,"file":"sentiment.d.ts","sourceRoot":"","sources":["../../../src/src/tools/sentiment.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAW,MAAM,4BAA4B,CAAC;AACxE,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,YAAY,EAAsB,MAAM,gCAAgC,CAAC;AACzG,OAAO,EAAE,KAAK,WAAW,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AA6D7C,MAAM,WAAW,wBAAwB;IACxC,uDAAuD;IACvD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yCAAyC;IACzC,KAAK,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;CAC5B;AAED;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,IAAI,CAAC,MAAM,GAAG,IAAI,EAAE,YAAY,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC;IAC5F,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;gBAE1B,MAAM,EAAE,wBAAwB,YAAK,EAAE,WAAW,EAAE,WAAW;cAuBxD,MAAM;;;;;;;;;;;;IAIzB,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,EAAE;cAQ7B,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO;cAIrC,aAAa,CAAC,MAAM,EAAE,YAAY,GAAG,KAAK,CAAC,WAAW,CAAC;IAI1E;;OAEG;IACY,MAAM,CACpB,KAAK,EAAE,MAAM,GAAG,IAAI,EACpB,OAAO,GAAE,OAAO,CAAC,WAAW,CAAM,GAChC,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,IAAI,CAAC,CAAC;CA+BlD;AAMD;;GAEG;AACH,eAAO,MAAM,yBAAyB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAI5D,CAAC;AAWF;;GAEG;AACH,MAAM,WAAW,iCAAiC;IACjD,iDAAiD;IACjD,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,qBAAa,2BAA4B,SAAQ,UAAU;gBAC9C,MAAM,EAAE,iCAAiC,YAAK,EAAE,WAAW,EAAE,WAAW;CAOpF;AAED,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACvF,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC"}
@@ -5,6 +5,15 @@ const utils_js_1 = require("../helpers/utils.js");
5
5
  const sentiment_schema_js_1 = require("../schemas/sentiment.schema.js");
6
6
  const tool_js_1 = require("../tool.js");
7
7
  const classifier_js_1 = require("./classifier.js");
8
+ /**
9
+ * Formats a portfolio array as a comma-separated list of product/service names.
10
+ * Includes category in parentheses if available.
11
+ */
12
+ function formatPortfolio(portfolio) {
13
+ return portfolio
14
+ .map((p) => (p.category ? `${p.name} (${p.category})` : p.name))
15
+ .join(', ');
16
+ }
8
17
  const ABS_PROMPT_SYSTEM = (0, utils_js_1.dedent)(`
9
18
  You're an expert in Aspect-Based Sentiment Analysis. Your task involves identifying specific
10
19
  entities mentioned in a text (e.g. a person, product, service, or experience) and determining the
@@ -18,10 +27,23 @@ Specifically:
18
27
  a. the aspect as it occurs in the text (key "aspect")
19
28
  b. the sentiment label as either "positive" or "negative" (key "sentiment")
20
29
  c. the reason for the sentiment assignment as a short text (key "reason")
30
+ d. the exact text fragment containing both the aspect and what is said about it (key "quote") - must be a verbatim substring
31
+ e. optional contextual information about the aspect, such as the brand or entity it relates to (key "context") - use null if not applicable
21
32
  4. If there are no sentiment-bearing aspects in the text, the output should be an empty list
22
33
 
23
- Example Output format:
24
- [{"aspect": "room service", "sentiment": "negative", "reason": "Room service was mentioned being rude."}, ...]
34
+ IMPORTANT: The "quote" field must be an EXACT verbatim substring from the input text. It should
35
+ include the complete phrase mentioning both the aspect and the sentiment expressed about it.
36
+
37
+ Example:
38
+
39
+ Input text: "The room service at the Grand Hotel was absolutely terrible and the staff were rude, but the view from our room was breathtaking."
40
+
41
+ Output:
42
+ [
43
+ {"aspect": "The room service at the Grand Hotel", "sentiment": "negative", "reason": "Described as terrible.", "quote": "The room service at the Grand Hotel was absolutely terrible", "context": "Grand Hotel"},
44
+ {"aspect": "the staff", "sentiment": "negative", "reason": "Described as rude.", "quote": "the staff were rude", "context": "Grand Hotel"},
45
+ {"aspect": "the view from our room", "sentiment": "positive", "reason": "Described as breathtaking.", "quote": "the view from our room was breathtaking", "context": "Grand Hotel"}
46
+ ]
25
47
 
26
48
  Only extract aspects that have an explicitly expressed sentiment associated with them, i.e.
27
49
  subjective opinions, feelings, or evaluations. Do not infer sentiment from factual statements,
@@ -48,11 +70,18 @@ class SentimentExtractor extends tool_js_1.Tool {
48
70
  super(modelConfig);
49
71
  const { instructions = '', brand = null } = config;
50
72
  const brandInstructions = brand
51
- ? (0, utils_js_1.dedent)(`
52
- When analyzing the text, pay special attention to any mentions of the brand "${brand.shortName}"
53
- or its products/services (${brand.portfolio}). Ensure that any sentiments expressed toward this
54
- brand or its offerings are accurately captured in your output. Respond in language code ${brand.language}.
55
- `)
73
+ ? (() => {
74
+ const portfolio = formatPortfolio(brand.portfolio);
75
+ const portfolioText = portfolio
76
+ ? ` or its products/services (${portfolio})`
77
+ : '';
78
+ return (0, utils_js_1.dedent)(`
79
+ Pay special attention to mentions of "${brand.shortName}"${portfolioText}.
80
+ When an aspect relates to a brand/entity, set the "context" field to "${brand.shortName}".
81
+ Keep aspect names and quoted text exactly as they appear in the original input.
82
+ Respond in language code ${brand.language}.
83
+ `);
84
+ })()
56
85
  : '';
57
86
  const combinedInstructions = [instructions, brandInstructions].filter(Boolean).join('\n\n');
58
87
  this.systemPrompt = ABS_PROMPT_SYSTEM.replace('{instructions}', combinedInstructions);
@@ -64,7 +93,7 @@ class SentimentExtractor extends tool_js_1.Tool {
64
93
  const userPrompt = ABS_PROMPT_USER.replace('{text}', text ?? '');
65
94
  return [
66
95
  { role: 'system', content: this.systemPrompt },
67
- { role: 'user', content: userPrompt }
96
+ { role: 'user', content: userPrompt },
68
97
  ];
69
98
  }
70
99
  isEmpty(text) {
@@ -73,6 +102,33 @@ class SentimentExtractor extends tool_js_1.Tool {
73
102
  extractResult(parsed) {
74
103
  return parsed.aspects;
75
104
  }
105
+ /**
106
+ * Override invoke to add quote validation
107
+ */
108
+ async invoke(input, options = {}) {
109
+ const response = await super.invoke(input, options);
110
+ // If we have a successful result and non-empty input, validate quotes
111
+ if (response.parsed && input && input.trim() !== '') {
112
+ const validatedResult = response.parsed.filter((sentiment) => {
113
+ // Check that quote is non-empty and not just whitespace
114
+ if (!sentiment.quote || sentiment.quote.trim().length === 0) {
115
+ console.warn(`Empty or whitespace-only quote for aspect "${sentiment.aspect}"`);
116
+ return false;
117
+ }
118
+ // Check that quote is a substring of the input
119
+ if (!input.includes(sentiment.quote)) {
120
+ console.warn(`Quote not found in text: "${sentiment.quote}" for aspect "${sentiment.aspect}"`);
121
+ return false;
122
+ }
123
+ return true;
124
+ });
125
+ return {
126
+ ...response,
127
+ parsed: validatedResult,
128
+ };
129
+ }
130
+ return response;
131
+ }
76
132
  }
77
133
  exports.SentimentExtractor = SentimentExtractor;
78
134
  // =============================================================================
@@ -84,7 +140,7 @@ exports.SentimentExtractor = SentimentExtractor;
84
140
  exports.SENTIMENT_POLARITY_LABELS = {
85
141
  positive: 'Expresses favorable opinions, approval, satisfaction, or optimism.',
86
142
  neutral: 'No clear sentiment expressed; factual, balanced, or ambiguous.',
87
- negative: 'Expresses unfavorable opinions, criticism, dissatisfaction, or pessimism.'
143
+ negative: 'Expresses unfavorable opinions, criticism, dissatisfaction, or pessimism.',
88
144
  };
89
145
  /**
90
146
  * Predefined instructions for sentiment polarity classification.
@@ -1,146 +0,0 @@
1
- /**
2
- * Pipeline Context Type Definitions
3
- *
4
- * These types define the structure for pipeline execution contexts.
5
- * They are shared between client and server code.
6
- *
7
- * IMPORTANT: This type must be kept in sync with the dynamically generated
8
- * type from: supabase/functions/pipelines/workflows/audit.ts
9
- *
10
- * The actual pipeline generates:
11
- * export type AiAuditPromptsPipelineContext = OrchestratorRunContext<typeof promptsPipeline>;
12
- *
13
- * This static definition serves as a contract for client-side usage.
14
- * It represents the union of all context types required by the pipeline nodes.
15
- */
16
- import type { Brand, BrandContext, FlaggedBrand } from './brand.schema.js';
17
- import type { Funnel } from './funnel.schema.js';
18
- import type { ModelIdentifier } from './models.schema.js';
19
- import type { Persona } from './persona.schema.js';
20
- import type { TopicType } from './topics.schema.js';
21
- export interface KeywordPlannerOptions {
22
- url?: string;
23
- urlAsExpandRelevanceContext?: string;
24
- generateIdeasFromSeeds?: boolean;
25
- }
26
- export interface AiAuditPromptsPipelineOptions {
27
- filterLowRelevanceKeywords?: boolean;
28
- /** When true, adds deduplicatedKeywords column with all keywords sharing the same metrics */
29
- includeDeduplicatedKeywords?: boolean;
30
- /** When true, includes seedKeywords column in output records. Defaults to false. */
31
- includeSeedKeywords?: boolean;
32
- /** When true, generates a separate dataset with all keywords (dedup by keyword only). Defaults to false. */
33
- includeAllKeywordsDataset?: boolean;
34
- }
35
- /**
36
- * AI Audit Pipeline Request Structure
37
- *
38
- * This represents the structure of the request sent to the /pipelines/run endpoint.
39
- * The `context` field should match the AiAuditPromptsPipelineContext from the orchestrator.
40
- */
41
- export interface AiAuditPromptsPipelineRequest {
42
- pipelineName: 'promptsPipeline';
43
- context: AiAuditPromptsPipelineContext;
44
- }
45
- /**
46
- * AI Audit Answers Pipeline Request Structure
47
- *
48
- * This represents the structure of the request sent to the /pipelines/run endpoint.
49
- * The `context` field should match the AiAuditAnswersPipelineContext from the orchestrator.
50
- */
51
- export interface AiAuditAnswersPipelineRequest {
52
- pipelineName: 'answersPipeline';
53
- context: AiAuditAnswersPipelineContext;
54
- }
55
- /**
56
- * AI Audit Prompts Pipeline Context Data - Static Definition
57
- *
58
- * This represents the union of all context parameters required by the
59
- * various nodes in the AI audit prompts pipeline:
60
- *
61
- * - { keywordPlanner }: Keyword Planner parameters & seed sources
62
- * - { options }: Pipeline-level flags
63
- * - { workspaceId, projectName }: Project creation parameters
64
- * - { funnel }: Funnel assignment parameters
65
- * - { brand }: Brand-specific processing parameters
66
- * - { brands }: Brand collection parameters
67
- */
68
- export interface AiAuditPromptsPipelineContext {
69
- clientUserEmail: string;
70
- workspaceId: number;
71
- projectName?: string;
72
- /** Optional existing project to append prompts into. */
73
- projectId?: number;
74
- keywordPlanner: KeywordPlannerOptions;
75
- /** ISO 639-1 language code for prompts/keywords (e.g., "en"). */
76
- languageCode?: string;
77
- /** ISO 3166-1 alpha-2 country code to localize sources (e.g., "US"). */
78
- countryISOCode?: string;
79
- /**
80
- * Custom prompts provided by the user.
81
- * These go directly to the prompt dataset without keyword expansion.
82
- */
83
- directPrompts?: Array<string>;
84
- /**
85
- * Custom seed keywords provided by the user.
86
- * These are processed through keyword expansion like other seed keywords.
87
- */
88
- customSeedKeywords?: Array<string>;
89
- funnel?: Funnel;
90
- brand: BrandContext;
91
- competitors: Array<FlaggedBrand | Brand>;
92
- personas: Array<Persona>;
93
- options?: AiAuditPromptsPipelineOptions;
94
- topics?: Array<TopicType>;
95
- }
96
- /**
97
- * AI Audit Answers Pipeline Context Data
98
- *
99
- * Context parameters required by the answers pipeline.
100
- */
101
- export interface AiAuditAnswersPipelineContext {
102
- clientUserEmail: string;
103
- projectId: number;
104
- promptIds: Array<number>;
105
- models: Array<ModelIdentifier>;
106
- countryISOCode?: string;
107
- brand: BrandContext;
108
- competitors?: Array<FlaggedBrand | Brand>;
109
- /**
110
- * Panel ID for grouping answers by execution source.
111
- * When present (scheduled cron execution), answers are grouped by panelId.
112
- */
113
- panelId?: number;
114
- }
115
- /**
116
- * Persisted project configuration (pipeline context without user metadata).
117
- */
118
- export type AiAuditProjectConfig = Omit<AiAuditPromptsPipelineContext, 'clientUserEmail' | 'projectId'>;
119
- /**
120
- * Topic Update Pipeline Request Structure
121
- *
122
- * This represents the structure of the request sent to the /pipelines/run endpoint
123
- * for updating topic hierarchy in existing prompts.
124
- */
125
- export interface TopicUpdatePipelineRequest {
126
- pipelineName: 'topicUpdatePipeline';
127
- context: TopicUpdatePipelineContext;
128
- }
129
- /**
130
- * Topic Update Pipeline Context Data
131
- *
132
- * Context parameters required by the topic update pipeline.
133
- * This pipeline downloads the prompts dataset, re-assigns topics using AI
134
- * based on the provided taxonomy, and uploads the updated dataset back to the project.
135
- */
136
- export interface TopicUpdatePipelineContext {
137
- clientUserEmail: string;
138
- projectId: number;
139
- /**
140
- * The topics taxonomy to use for assigning topics.
141
- * Each topic contains a name and a list of subtopics.
142
- * The AI will classify each prompt into the appropriate topic/subtopic.
143
- */
144
- topics: Array<TopicType>;
145
- }
146
- //# sourceMappingURL=pipeline.schema.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"pipeline.schema.d.ts","sourceRoot":"","sources":["../../../src/src/schemas/pipeline.schema.ts"],"names":[],"mappings":"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"}
@@ -1,16 +0,0 @@
1
- /**
2
- * Pipeline Context Type Definitions
3
- *
4
- * These types define the structure for pipeline execution contexts.
5
- * They are shared between client and server code.
6
- *
7
- * IMPORTANT: This type must be kept in sync with the dynamically generated
8
- * type from: supabase/functions/pipelines/workflows/audit.ts
9
- *
10
- * The actual pipeline generates:
11
- * export type AiAuditPromptsPipelineContext = OrchestratorRunContext<typeof promptsPipeline>;
12
- *
13
- * This static definition serves as a contract for client-side usage.
14
- * It represents the union of all context types required by the pipeline nodes.
15
- */
16
- export {};
@@ -1,146 +0,0 @@
1
- /**
2
- * Pipeline Context Type Definitions
3
- *
4
- * These types define the structure for pipeline execution contexts.
5
- * They are shared between client and server code.
6
- *
7
- * IMPORTANT: This type must be kept in sync with the dynamically generated
8
- * type from: supabase/functions/pipelines/workflows/audit.ts
9
- *
10
- * The actual pipeline generates:
11
- * export type AiAuditPromptsPipelineContext = OrchestratorRunContext<typeof promptsPipeline>;
12
- *
13
- * This static definition serves as a contract for client-side usage.
14
- * It represents the union of all context types required by the pipeline nodes.
15
- */
16
- import type { Brand, BrandContext, FlaggedBrand } from './brand.schema.js';
17
- import type { Funnel } from './funnel.schema.js';
18
- import type { ModelIdentifier } from './models.schema.js';
19
- import type { Persona } from './persona.schema.js';
20
- import type { TopicType } from './topics.schema.js';
21
- export interface KeywordPlannerOptions {
22
- url?: string;
23
- urlAsExpandRelevanceContext?: string;
24
- generateIdeasFromSeeds?: boolean;
25
- }
26
- export interface AiAuditPromptsPipelineOptions {
27
- filterLowRelevanceKeywords?: boolean;
28
- /** When true, adds deduplicatedKeywords column with all keywords sharing the same metrics */
29
- includeDeduplicatedKeywords?: boolean;
30
- /** When true, includes seedKeywords column in output records. Defaults to false. */
31
- includeSeedKeywords?: boolean;
32
- /** When true, generates a separate dataset with all keywords (dedup by keyword only). Defaults to false. */
33
- includeAllKeywordsDataset?: boolean;
34
- }
35
- /**
36
- * AI Audit Pipeline Request Structure
37
- *
38
- * This represents the structure of the request sent to the /pipelines/run endpoint.
39
- * The `context` field should match the AiAuditPromptsPipelineContext from the orchestrator.
40
- */
41
- export interface AiAuditPromptsPipelineRequest {
42
- pipelineName: 'promptsPipeline';
43
- context: AiAuditPromptsPipelineContext;
44
- }
45
- /**
46
- * AI Audit Answers Pipeline Request Structure
47
- *
48
- * This represents the structure of the request sent to the /pipelines/run endpoint.
49
- * The `context` field should match the AiAuditAnswersPipelineContext from the orchestrator.
50
- */
51
- export interface AiAuditAnswersPipelineRequest {
52
- pipelineName: 'answersPipeline';
53
- context: AiAuditAnswersPipelineContext;
54
- }
55
- /**
56
- * AI Audit Prompts Pipeline Context Data - Static Definition
57
- *
58
- * This represents the union of all context parameters required by the
59
- * various nodes in the AI audit prompts pipeline:
60
- *
61
- * - { keywordPlanner }: Keyword Planner parameters & seed sources
62
- * - { options }: Pipeline-level flags
63
- * - { workspaceId, projectName }: Project creation parameters
64
- * - { funnel }: Funnel assignment parameters
65
- * - { brand }: Brand-specific processing parameters
66
- * - { brands }: Brand collection parameters
67
- */
68
- export interface AiAuditPromptsPipelineContext {
69
- clientUserEmail: string;
70
- workspaceId: number;
71
- projectName?: string;
72
- /** Optional existing project to append prompts into. */
73
- projectId?: number;
74
- keywordPlanner: KeywordPlannerOptions;
75
- /** ISO 639-1 language code for prompts/keywords (e.g., "en"). */
76
- languageCode?: string;
77
- /** ISO 3166-1 alpha-2 country code to localize sources (e.g., "US"). */
78
- countryISOCode?: string;
79
- /**
80
- * Custom prompts provided by the user.
81
- * These go directly to the prompt dataset without keyword expansion.
82
- */
83
- directPrompts?: Array<string>;
84
- /**
85
- * Custom seed keywords provided by the user.
86
- * These are processed through keyword expansion like other seed keywords.
87
- */
88
- customSeedKeywords?: Array<string>;
89
- funnel?: Funnel;
90
- brand: BrandContext;
91
- competitors: Array<FlaggedBrand | Brand>;
92
- personas: Array<Persona>;
93
- options?: AiAuditPromptsPipelineOptions;
94
- topics?: Array<TopicType>;
95
- }
96
- /**
97
- * AI Audit Answers Pipeline Context Data
98
- *
99
- * Context parameters required by the answers pipeline.
100
- */
101
- export interface AiAuditAnswersPipelineContext {
102
- clientUserEmail: string;
103
- projectId: number;
104
- promptIds: Array<number>;
105
- models: Array<ModelIdentifier>;
106
- countryISOCode?: string;
107
- brand: BrandContext;
108
- competitors?: Array<FlaggedBrand | Brand>;
109
- /**
110
- * Panel ID for grouping answers by execution source.
111
- * When present (scheduled cron execution), answers are grouped by panelId.
112
- */
113
- panelId?: number;
114
- }
115
- /**
116
- * Persisted project configuration (pipeline context without user metadata).
117
- */
118
- export type AiAuditProjectConfig = Omit<AiAuditPromptsPipelineContext, 'clientUserEmail' | 'projectId'>;
119
- /**
120
- * Topic Update Pipeline Request Structure
121
- *
122
- * This represents the structure of the request sent to the /pipelines/run endpoint
123
- * for updating topic hierarchy in existing prompts.
124
- */
125
- export interface TopicUpdatePipelineRequest {
126
- pipelineName: 'topicUpdatePipeline';
127
- context: TopicUpdatePipelineContext;
128
- }
129
- /**
130
- * Topic Update Pipeline Context Data
131
- *
132
- * Context parameters required by the topic update pipeline.
133
- * This pipeline downloads the prompts dataset, re-assigns topics using AI
134
- * based on the provided taxonomy, and uploads the updated dataset back to the project.
135
- */
136
- export interface TopicUpdatePipelineContext {
137
- clientUserEmail: string;
138
- projectId: number;
139
- /**
140
- * The topics taxonomy to use for assigning topics.
141
- * Each topic contains a name and a list of subtopics.
142
- * The AI will classify each prompt into the appropriate topic/subtopic.
143
- */
144
- topics: Array<TopicType>;
145
- }
146
- //# sourceMappingURL=pipeline.schema.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"pipeline.schema.d.ts","sourceRoot":"","sources":["../../../src/src/schemas/pipeline.schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC3E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAEpD,MAAM,WAAW,qBAAqB;IACrC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,2BAA2B,CAAC,EAAE,MAAM,CAAC;IACrC,sBAAsB,CAAC,EAAE,OAAO,CAAC;CACjC;AAED,MAAM,WAAW,6BAA6B;IAC7C,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,6FAA6F;IAC7F,2BAA2B,CAAC,EAAE,OAAO,CAAC;IACtC,oFAAoF;IACpF,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,4GAA4G;IAC5G,yBAAyB,CAAC,EAAE,OAAO,CAAC;CACpC;AAED;;;;;GAKG;AACH,MAAM,WAAW,6BAA6B;IAC7C,YAAY,EAAE,iBAAiB,CAAC;IAChC,OAAO,EAAE,6BAA6B,CAAC;CACvC;AAED;;;;;GAKG;AACH,MAAM,WAAW,6BAA6B;IAC7C,YAAY,EAAE,iBAAiB,CAAC;IAChC,OAAO,EAAE,6BAA6B,CAAC;CACvC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,6BAA6B;IAE7C,eAAe,EAAE,MAAM,CAAC;IAExB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wDAAwD;IACxD,SAAS,CAAC,EAAE,MAAM,CAAC;IAGnB,cAAc,EAAE,qBAAqB,CAAC;IACtC,iEAAiE;IACjE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,wEAAwE;IACxE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,aAAa,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC9B;;;OAGG;IACH,kBAAkB,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAGnC,MAAM,CAAC,EAAE,MAAM,CAAC;IAGhB,KAAK,EAAE,YAAY,CAAC;IAGpB,WAAW,EAAE,KAAK,CAAC,YAAY,GAAG,KAAK,CAAC,CAAC;IAGzC,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IAEzB,OAAO,CAAC,EAAE,6BAA6B,CAAC;IAExC,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;CAE1B;AAED;;;;GAIG;AACH,MAAM,WAAW,6BAA6B;IAE7C,eAAe,EAAE,MAAM,CAAC;IAGxB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAGzB,MAAM,EAAE,KAAK,CAAC,eAAe,CAAC,CAAC;IAC/B,cAAc,CAAC,EAAE,MAAM,CAAC;IAGxB,KAAK,EAAE,YAAY,CAAC;IACpB,WAAW,CAAC,EAAE,KAAK,CAAC,YAAY,GAAG,KAAK,CAAC,CAAC;IAE1C;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG,IAAI,CAAC,6BAA6B,EAAE,iBAAiB,GAAG,WAAW,CAAC,CAAC;AAExG;;;;;GAKG;AACH,MAAM,WAAW,0BAA0B;IAC1C,YAAY,EAAE,qBAAqB,CAAC;IACpC,OAAO,EAAE,0BAA0B,CAAC;CACpC;AAED;;;;;;GAMG;AACH,MAAM,WAAW,0BAA0B;IAE1C,eAAe,EAAE,MAAM,CAAC;IAGxB,SAAS,EAAE,MAAM,CAAC;IAElB;;;;OAIG;IACH,MAAM,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;CACzB"}
@@ -1,17 +0,0 @@
1
- "use strict";
2
- /**
3
- * Pipeline Context Type Definitions
4
- *
5
- * These types define the structure for pipeline execution contexts.
6
- * They are shared between client and server code.
7
- *
8
- * IMPORTANT: This type must be kept in sync with the dynamically generated
9
- * type from: supabase/functions/pipelines/workflows/audit.ts
10
- *
11
- * The actual pipeline generates:
12
- * export type AiAuditPromptsPipelineContext = OrchestratorRunContext<typeof promptsPipeline>;
13
- *
14
- * This static definition serves as a contract for client-side usage.
15
- * It represents the union of all context types required by the pipeline nodes.
16
- */
17
- Object.defineProperty(exports, "__esModule", { value: true });