Skip to content

Commit aa11b42

Browse files
authored
Merge pull request #924 from constructive-io/devin/1774660034-pluggable-embeddings
feat(codegen): pluggable embedding system with --auto-embed flag [CI]
2 parents a236c7f + 6059956 commit aa11b42

11 files changed

Lines changed: 2204 additions & 61 deletions

File tree

graphql/codegen/src/__tests__/codegen/__snapshots__/cli-generator.test.ts.snap

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ myapp car find-first --where.id.equalTo <value>
321321
### List car records with field selection
322322

323323
\`\`\`bash
324-
myapp car list --fields id,id
324+
myapp car list --select id,id
325325
\`\`\`
326326

327327
### List car records with filtering and ordering
@@ -393,7 +393,7 @@ myapp driver find-first --where.id.equalTo <value>
393393
### List driver records with field selection
394394

395395
\`\`\`bash
396-
myapp driver list --fields id,id
396+
myapp driver list --select id,id
397397
\`\`\`
398398

399399
### List driver records with filtering and ordering
@@ -706,7 +706,7 @@ const fieldSchema: FieldSchema = {
706706
isElectric: "boolean",
707707
createdAt: "string"
708708
};
709-
const usage = "\\ncar <command>\\n\\nCommands:\\n list List car records\\n find-first Find first matching car record\\n get Get a car by ID\\n create Create a new car\\n update Update an existing car\\n delete Delete a car\\n\\nList Options:\\n --limit <n> Max number of records to return (forward pagination)\\n --last <n> Number of records from the end (backward pagination)\\n --after <cursor> Cursor for forward pagination\\n --before <cursor> Cursor for backward pagination\\n --offset <n> Number of records to skip\\n --fields <fields> Comma-separated list of fields to return\\n --where.<field>.<op> Filter (dot-notation, e.g. --where.name.equalTo foo)\\n --condition.<f>.<op> Condition filter (dot-notation)\\n --orderBy <values> Comma-separated ordering values (e.g. NAME_ASC,CREATED_AT_DESC)\\n\\nFind-First Options:\\n --fields <fields> Comma-separated list of fields to return\\n --where.<field>.<op> Filter (dot-notation, e.g. --where.status.equalTo active)\\n --condition.<f>.<op> Condition filter (dot-notation)\\n\\n --help, -h Show this help message\\n";
709+
const usage = "\\ncar <command>\\n\\nCommands:\\n list List car records\\n find-first Find first matching car record\\n get Get a car by ID\\n create Create a new car\\n update Update an existing car\\n delete Delete a car\\n\\nList Options:\\n --limit <n> Max number of records to return (forward pagination)\\n --last <n> Number of records from the end (backward pagination)\\n --after <cursor> Cursor for forward pagination\\n --before <cursor> Cursor for backward pagination\\n --offset <n> Number of records to skip\\n --select <fields> Comma-separated list of fields to return\\n --where.<field>.<op> Filter (dot-notation, e.g. --where.name.equalTo foo)\\n --condition.<f>.<op> Condition filter (dot-notation)\\n --orderBy <values> Comma-separated ordering values (e.g. NAME_ASC,CREATED_AT_DESC)\\n\\nFind-First Options:\\n --select <fields> Comma-separated list of fields to return\\n --where.<field>.<op> Filter (dot-notation, e.g. --where.status.equalTo active)\\n --condition.<f>.<op> Condition filter (dot-notation)\\n\\n --help, -h Show this help message\\n";
710710
export default async (argv: Partial<Record<string, unknown>>, prompter: Inquirerer, _options: CLIOptions) => {
711711
if (argv.help || argv.h) {
712712
console.log(usage);
@@ -1166,7 +1166,7 @@ const fieldSchema: FieldSchema = {
11661166
name: "string",
11671167
licenseNumber: "string"
11681168
};
1169-
const usage = "\\ndriver <command>\\n\\nCommands:\\n list List driver records\\n find-first Find first matching driver record\\n get Get a driver by ID\\n create Create a new driver\\n update Update an existing driver\\n delete Delete a driver\\n\\nList Options:\\n --limit <n> Max number of records to return (forward pagination)\\n --last <n> Number of records from the end (backward pagination)\\n --after <cursor> Cursor for forward pagination\\n --before <cursor> Cursor for backward pagination\\n --offset <n> Number of records to skip\\n --fields <fields> Comma-separated list of fields to return\\n --where.<field>.<op> Filter (dot-notation, e.g. --where.name.equalTo foo)\\n --condition.<f>.<op> Condition filter (dot-notation)\\n --orderBy <values> Comma-separated ordering values (e.g. NAME_ASC,CREATED_AT_DESC)\\n\\nFind-First Options:\\n --fields <fields> Comma-separated list of fields to return\\n --where.<field>.<op> Filter (dot-notation, e.g. --where.status.equalTo active)\\n --condition.<f>.<op> Condition filter (dot-notation)\\n\\n --help, -h Show this help message\\n";
1169+
const usage = "\\ndriver <command>\\n\\nCommands:\\n list List driver records\\n find-first Find first matching driver record\\n get Get a driver by ID\\n create Create a new driver\\n update Update an existing driver\\n delete Delete a driver\\n\\nList Options:\\n --limit <n> Max number of records to return (forward pagination)\\n --last <n> Number of records from the end (backward pagination)\\n --after <cursor> Cursor for forward pagination\\n --before <cursor> Cursor for backward pagination\\n --offset <n> Number of records to skip\\n --select <fields> Comma-separated list of fields to return\\n --where.<field>.<op> Filter (dot-notation, e.g. --where.name.equalTo foo)\\n --condition.<f>.<op> Condition filter (dot-notation)\\n --orderBy <values> Comma-separated ordering values (e.g. NAME_ASC,CREATED_AT_DESC)\\n\\nFind-First Options:\\n --select <fields> Comma-separated list of fields to return\\n --where.<field>.<op> Filter (dot-notation, e.g. --where.status.equalTo active)\\n --condition.<f>.<op> Condition filter (dot-notation)\\n\\n --help, -h Show this help message\\n";
11701170
export default async (argv: Partial<Record<string, unknown>>, prompter: Inquirerer, _options: CLIOptions) => {
11711171
if (argv.help || argv.h) {
11721172
console.log(usage);
@@ -3197,7 +3197,7 @@ const fieldSchema: FieldSchema = {
31973197
email: "string",
31983198
name: "string"
31993199
};
3200-
const usage = "\\nuser <command>\\n\\nCommands:\\n list List user records\\n find-first Find first matching user record\\n get Get a user by ID\\n create Create a new user\\n update Update an existing user\\n delete Delete a user\\n\\nList Options:\\n --limit <n> Max number of records to return (forward pagination)\\n --last <n> Number of records from the end (backward pagination)\\n --after <cursor> Cursor for forward pagination\\n --before <cursor> Cursor for backward pagination\\n --offset <n> Number of records to skip\\n --fields <fields> Comma-separated list of fields to return\\n --where.<field>.<op> Filter (dot-notation, e.g. --where.name.equalTo foo)\\n --condition.<f>.<op> Condition filter (dot-notation)\\n --orderBy <values> Comma-separated ordering values (e.g. NAME_ASC,CREATED_AT_DESC)\\n\\nFind-First Options:\\n --fields <fields> Comma-separated list of fields to return\\n --where.<field>.<op> Filter (dot-notation, e.g. --where.status.equalTo active)\\n --condition.<f>.<op> Condition filter (dot-notation)\\n\\n --help, -h Show this help message\\n";
3200+
const usage = "\\nuser <command>\\n\\nCommands:\\n list List user records\\n find-first Find first matching user record\\n get Get a user by ID\\n create Create a new user\\n update Update an existing user\\n delete Delete a user\\n\\nList Options:\\n --limit <n> Max number of records to return (forward pagination)\\n --last <n> Number of records from the end (backward pagination)\\n --after <cursor> Cursor for forward pagination\\n --before <cursor> Cursor for backward pagination\\n --offset <n> Number of records to skip\\n --select <fields> Comma-separated list of fields to return\\n --where.<field>.<op> Filter (dot-notation, e.g. --where.name.equalTo foo)\\n --condition.<f>.<op> Condition filter (dot-notation)\\n --orderBy <values> Comma-separated ordering values (e.g. NAME_ASC,CREATED_AT_DESC)\\n\\nFind-First Options:\\n --select <fields> Comma-separated list of fields to return\\n --where.<field>.<op> Filter (dot-notation, e.g. --where.status.equalTo active)\\n --condition.<f>.<op> Condition filter (dot-notation)\\n\\n --help, -h Show this help message\\n";
32013201
export default async (argv: Partial<Record<string, unknown>>, prompter: Inquirerer, _options: CLIOptions) => {
32023202
if (argv.help || argv.h) {
32033203
console.log(usage);
@@ -3425,7 +3425,7 @@ const fieldSchema: FieldSchema = {
34253425
id: "uuid",
34263426
role: "string"
34273427
};
3428-
const usage = "\\nmember <command>\\n\\nCommands:\\n list List member records\\n find-first Find first matching member record\\n get Get a member by ID\\n create Create a new member\\n update Update an existing member\\n delete Delete a member\\n\\nList Options:\\n --limit <n> Max number of records to return (forward pagination)\\n --last <n> Number of records from the end (backward pagination)\\n --after <cursor> Cursor for forward pagination\\n --before <cursor> Cursor for backward pagination\\n --offset <n> Number of records to skip\\n --fields <fields> Comma-separated list of fields to return\\n --where.<field>.<op> Filter (dot-notation, e.g. --where.name.equalTo foo)\\n --condition.<f>.<op> Condition filter (dot-notation)\\n --orderBy <values> Comma-separated ordering values (e.g. NAME_ASC,CREATED_AT_DESC)\\n\\nFind-First Options:\\n --fields <fields> Comma-separated list of fields to return\\n --where.<field>.<op> Filter (dot-notation, e.g. --where.status.equalTo active)\\n --condition.<f>.<op> Condition filter (dot-notation)\\n\\n --help, -h Show this help message\\n";
3428+
const usage = "\\nmember <command>\\n\\nCommands:\\n list List member records\\n find-first Find first matching member record\\n get Get a member by ID\\n create Create a new member\\n update Update an existing member\\n delete Delete a member\\n\\nList Options:\\n --limit <n> Max number of records to return (forward pagination)\\n --last <n> Number of records from the end (backward pagination)\\n --after <cursor> Cursor for forward pagination\\n --before <cursor> Cursor for backward pagination\\n --offset <n> Number of records to skip\\n --select <fields> Comma-separated list of fields to return\\n --where.<field>.<op> Filter (dot-notation, e.g. --where.name.equalTo foo)\\n --condition.<f>.<op> Condition filter (dot-notation)\\n --orderBy <values> Comma-separated ordering values (e.g. NAME_ASC,CREATED_AT_DESC)\\n\\nFind-First Options:\\n --select <fields> Comma-separated list of fields to return\\n --where.<field>.<op> Filter (dot-notation, e.g. --where.status.equalTo active)\\n --condition.<f>.<op> Condition filter (dot-notation)\\n\\n --help, -h Show this help message\\n";
34293429
export default async (argv: Partial<Record<string, unknown>>, prompter: Inquirerer, _options: CLIOptions) => {
34303430
if (argv.help || argv.h) {
34313431
console.log(usage);
@@ -3640,7 +3640,7 @@ const fieldSchema: FieldSchema = {
36403640
isElectric: "boolean",
36413641
createdAt: "string"
36423642
};
3643-
const usage = "\\ncar <command>\\n\\nCommands:\\n list List car records\\n find-first Find first matching car record\\n get Get a car by ID\\n create Create a new car\\n update Update an existing car\\n delete Delete a car\\n\\nList Options:\\n --limit <n> Max number of records to return (forward pagination)\\n --last <n> Number of records from the end (backward pagination)\\n --after <cursor> Cursor for forward pagination\\n --before <cursor> Cursor for backward pagination\\n --offset <n> Number of records to skip\\n --fields <fields> Comma-separated list of fields to return\\n --where.<field>.<op> Filter (dot-notation, e.g. --where.name.equalTo foo)\\n --condition.<f>.<op> Condition filter (dot-notation)\\n --orderBy <values> Comma-separated ordering values (e.g. NAME_ASC,CREATED_AT_DESC)\\n\\nFind-First Options:\\n --fields <fields> Comma-separated list of fields to return\\n --where.<field>.<op> Filter (dot-notation, e.g. --where.status.equalTo active)\\n --condition.<f>.<op> Condition filter (dot-notation)\\n\\n --help, -h Show this help message\\n";
3643+
const usage = "\\ncar <command>\\n\\nCommands:\\n list List car records\\n find-first Find first matching car record\\n get Get a car by ID\\n create Create a new car\\n update Update an existing car\\n delete Delete a car\\n\\nList Options:\\n --limit <n> Max number of records to return (forward pagination)\\n --last <n> Number of records from the end (backward pagination)\\n --after <cursor> Cursor for forward pagination\\n --before <cursor> Cursor for backward pagination\\n --offset <n> Number of records to skip\\n --select <fields> Comma-separated list of fields to return\\n --where.<field>.<op> Filter (dot-notation, e.g. --where.name.equalTo foo)\\n --condition.<f>.<op> Condition filter (dot-notation)\\n --orderBy <values> Comma-separated ordering values (e.g. NAME_ASC,CREATED_AT_DESC)\\n\\nFind-First Options:\\n --select <fields> Comma-separated list of fields to return\\n --where.<field>.<op> Filter (dot-notation, e.g. --where.status.equalTo active)\\n --condition.<f>.<op> Condition filter (dot-notation)\\n\\n --help, -h Show this help message\\n";
36443644
export default async (argv: Partial<Record<string, unknown>>, prompter: Inquirerer, _options: CLIOptions) => {
36453645
if (argv.help || argv.h) {
36463646
console.log(usage);

graphql/codegen/src/core/codegen/cli/docs-generator.ts

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import {
1010
getSearchFields,
1111
categorizeSpecialFields,
1212
buildSpecialFieldsMarkdown,
13+
buildSearchExamples,
14+
buildSearchExamplesMarkdown,
1315
getReadmeHeader,
1416
getReadmeFooter,
1517
gqlTypeToJsonSchemaType,
@@ -160,6 +162,7 @@ export function generateReadme(
160162
}
161163
const specialGroups = categorizeSpecialFields(table, registry);
162164
lines.push(...buildSpecialFieldsMarkdown(specialGroups));
165+
lines.push(...buildSearchExamplesMarkdown(specialGroups, toolName, kebab));
163166
lines.push('');
164167
}
165168
}
@@ -424,18 +427,13 @@ export function generateSkills(
424427
},
425428
{
426429
description: `List ${singularName} records with field selection`,
427-
code: [`${toolName} ${kebab} list --fields id,${pk.name}`],
430+
code: [`${toolName} ${kebab} list --select id,${pk.name}`],
428431
},
429432
{
430433
description: `List ${singularName} records with filtering and ordering`,
431434
code: [`${toolName} ${kebab} list --where.${pk.name}.equalTo <value> --orderBy ${pk.name.replace(/([A-Z])/g, '_$1').toUpperCase()}_ASC`],
432435
},
433-
...(skillSpecialGroups.some((g) => g.category === 'search' || g.category === 'embedding')
434-
? [{
435-
description: `Search ${singularName} records`,
436-
code: [`${toolName} ${kebab} search "query text" --limit 10 --fields id,searchScore`],
437-
}]
438-
: []),
436+
...buildSearchExamples(skillSpecialGroups, toolName, kebab),
439437
{
440438
description: `Create a ${singularName}`,
441439
code: [
@@ -763,6 +761,7 @@ export function generateMultiTargetReadme(
763761
}
764762
const mtSpecialGroups = categorizeSpecialFields(table, registry);
765763
lines.push(...buildSpecialFieldsMarkdown(mtSpecialGroups));
764+
lines.push(...buildSearchExamplesMarkdown(mtSpecialGroups, toolName, `${tgt.name}:${kebab}`));
766765
lines.push('');
767766
}
768767

@@ -1096,12 +1095,7 @@ export function generateMultiTargetSkills(
10961095
description: `List ${singularName} records with filtering and ordering`,
10971096
code: [`${toolName} ${cmd} list --where.${pk.name}.equalTo <value> --orderBy ${pk.name.replace(/([A-Z])/g, '_$1').toUpperCase()}_ASC`],
10981097
},
1099-
...(mtSkillSpecialGroups.some((g) => g.category === 'search' || g.category === 'embedding')
1100-
? [{
1101-
description: `Search ${singularName} records`,
1102-
code: [`${toolName} ${cmd} search "query text" --limit 10 --fields id,searchScore`],
1103-
}]
1104-
: []),
1098+
...buildSearchExamples(mtSkillSpecialGroups, toolName, cmd),
11051099
{
11061100
description: `Create a ${singularName}`,
11071101
code: [

graphql/codegen/src/core/codegen/cli/index.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
generateMultiTargetContextCommand,
1515
} from './infra-generator';
1616
import { generateTableCommand } from './table-command-generator';
17-
import { generateUtilsFile, generateNodeFetchFile, generateEntryPointFile } from './utils-generator';
17+
import { generateUtilsFile, generateNodeFetchFile, generateEntryPointFile, generateEmbedderFile } from './utils-generator';
1818

1919
export interface GenerateCliOptions {
2020
tables: Table[];
@@ -59,6 +59,14 @@ export function generateCli(options: GenerateCliOptions): GenerateCliResult {
5959
const utilsFile = generateUtilsFile();
6060
files.push(utilsFile);
6161

62+
// Generate embedder module if any table has vector embedding fields
63+
const hasAnyEmbeddings = tables.some((t) =>
64+
t.fields.some((f) => f.type.gqlType === 'Vector' || f.type.gqlType === '[Float]'),
65+
);
66+
if (hasAnyEmbeddings) {
67+
files.push(generateEmbedderFile());
68+
}
69+
6270
// Generate node HTTP adapter if configured (for *.localhost subdomain routing)
6371
if (useNodeHttpAdapter) {
6472
files.push(generateNodeFetchFile());
@@ -180,6 +188,16 @@ export function generateMultiTargetCli(
180188
const utilsFile = generateUtilsFile();
181189
files.push(utilsFile);
182190

191+
// Generate embedder module if any target has tables with vector embedding fields
192+
const hasAnyMtEmbeddings = targets.some((tgt) =>
193+
tgt.tables.some((t) =>
194+
t.fields.some((f) => f.type.gqlType === 'Vector' || f.type.gqlType === '[Float]'),
195+
),
196+
);
197+
if (hasAnyMtEmbeddings) {
198+
files.push(generateEmbedderFile());
199+
}
200+
183201
// Generate node HTTP adapter if configured (for *.localhost subdomain routing)
184202
if (options.nodeHttpAdapter) {
185203
files.push(generateNodeFetchFile());
@@ -299,5 +317,5 @@ export {
299317
export type { MultiTargetDocsInput } from './docs-generator';
300318
export { resolveDocsConfig } from '../docs-utils';
301319
export type { GeneratedDocFile } from '../docs-utils';
302-
export { generateUtilsFile, generateEntryPointFile } from './utils-generator';
320+
export { generateUtilsFile, generateEntryPointFile, generateEmbedderFile } from './utils-generator';
303321
export type { GeneratedFile, MultiTargetExecutorInput } from './executor-generator';

0 commit comments

Comments
 (0)