@webiny/api-headless-cms 6.6.0-alpha.1 → 6.6.0-alpha.3
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.
- package/features/ai/DescribeContentModelTool.d.ts +11 -6
- package/features/ai/DescribeContentModelTool.js +21 -12
- package/features/ai/DescribeContentModelTool.js.map +1 -1
- package/features/ai/ListContentModelsTool.d.ts +11 -6
- package/features/ai/ListContentModelsTool.js +21 -12
- package/features/ai/ListContentModelsTool.js.map +1 -1
- package/features/ai/QueryEntriesTool.d.ts +14 -9
- package/features/ai/QueryEntriesTool.js +20 -11
- package/features/ai/QueryEntriesTool.js.map +1 -1
- package/features/ai/feature.d.ts +2 -2
- package/features/ai/feature.js.map +1 -1
- package/package.json +16 -16
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import
|
|
2
|
+
import { AiSdkToolDefinition, AiSdkToolHandler } from "@webiny/api-core/features/ai/index.js";
|
|
3
3
|
import { GetModelUseCase } from "../../features/contentModel/GetModel/index.js";
|
|
4
4
|
declare const inputSchema: z.ZodObject<{
|
|
5
5
|
modelId: z.ZodString;
|
|
@@ -29,13 +29,17 @@ interface ModelDescription {
|
|
|
29
29
|
titleFieldId: string;
|
|
30
30
|
fields: FieldDescription[];
|
|
31
31
|
}
|
|
32
|
+
declare class DescribeContentModelToolHandlerImpl implements AiSdkToolHandler.Interface<Input> {
|
|
33
|
+
private getModel;
|
|
34
|
+
constructor(getModel: GetModelUseCase.Interface);
|
|
35
|
+
execute(input: Input): Promise<ModelDescription>;
|
|
36
|
+
}
|
|
32
37
|
/**
|
|
33
38
|
* Supplies the field detail needed to build a valid `queryEntries` filter. Deliberately a separate
|
|
34
39
|
* call from `listContentModels`: returning full field sets for every model would be large and mostly
|
|
35
40
|
* unread, so the model pays for detail only on the model it actually cares about.
|
|
36
41
|
*/
|
|
37
|
-
declare class DescribeContentModelToolImpl implements
|
|
38
|
-
private getModel;
|
|
42
|
+
declare class DescribeContentModelToolImpl implements AiSdkToolDefinition.Interface<Input> {
|
|
39
43
|
readonly name = "describeContentModel";
|
|
40
44
|
readonly title = "Describe content model";
|
|
41
45
|
readonly description = "Returns the fields of one content model \u2014 field IDs, types, whether each is a list, required flags, allowed values, and referenced models. Call this before queryEntries so filters use real field IDs.";
|
|
@@ -46,10 +50,11 @@ declare class DescribeContentModelToolImpl implements IAiSdkTool<Input> {
|
|
|
46
50
|
readOnlyHint: boolean;
|
|
47
51
|
idempotentHint: boolean;
|
|
48
52
|
};
|
|
49
|
-
|
|
50
|
-
|
|
53
|
+
readonly handler: typeof DescribeContentModelToolHandlerImpl & {
|
|
54
|
+
__abstraction: import("@webiny/di").Abstraction<import("@webiny/api-core/features/ai/abstractions").IAiSdkToolHandler<any>>;
|
|
55
|
+
};
|
|
51
56
|
}
|
|
52
57
|
export declare const DescribeContentModelTool: typeof DescribeContentModelToolImpl & {
|
|
53
|
-
__abstraction: import("@webiny/di").Abstraction<
|
|
58
|
+
__abstraction: import("@webiny/di").Abstraction<import("@webiny/api-core/features/ai/abstractions").IAiSdkToolDefinition<any>>;
|
|
54
59
|
};
|
|
55
60
|
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import {
|
|
2
|
+
import { AiSdkToolDefinition, AiSdkToolHandler } from "@webiny/api-core/features/ai/index.js";
|
|
3
3
|
import { GetModelUseCase } from "../contentModel/GetModel/index.js";
|
|
4
4
|
const inputSchema = z.object({
|
|
5
5
|
modelId: z.string().describe("Model ID as returned by listContentModels (e.g. 'product', not 'Products').")
|
|
@@ -22,17 +22,9 @@ const describeField = (field)=>{
|
|
|
22
22
|
if (nested?.length) described.fields = nested.map(describeField);
|
|
23
23
|
return described;
|
|
24
24
|
};
|
|
25
|
-
class
|
|
25
|
+
class DescribeContentModelToolHandlerImpl {
|
|
26
26
|
constructor(getModel){
|
|
27
27
|
this.getModel = getModel;
|
|
28
|
-
this.name = "describeContentModel";
|
|
29
|
-
this.title = "Describe content model";
|
|
30
|
-
this.description = "Returns the fields of one content model — field IDs, types, whether each is a list, required flags, allowed values, and referenced models. Call this before queryEntries so filters use real field IDs.";
|
|
31
|
-
this.inputSchema = inputSchema;
|
|
32
|
-
this.annotations = {
|
|
33
|
-
readOnlyHint: true,
|
|
34
|
-
idempotentHint: true
|
|
35
|
-
};
|
|
36
28
|
}
|
|
37
29
|
async execute(input) {
|
|
38
30
|
const result = await this.getModel.execute(input.modelId);
|
|
@@ -49,12 +41,29 @@ class DescribeContentModelToolImpl {
|
|
|
49
41
|
};
|
|
50
42
|
}
|
|
51
43
|
}
|
|
52
|
-
const
|
|
53
|
-
implementation:
|
|
44
|
+
const DescribeContentModelToolHandler = AiSdkToolHandler.createImplementation({
|
|
45
|
+
implementation: DescribeContentModelToolHandlerImpl,
|
|
54
46
|
dependencies: [
|
|
55
47
|
GetModelUseCase
|
|
56
48
|
]
|
|
57
49
|
});
|
|
50
|
+
class DescribeContentModelToolImpl {
|
|
51
|
+
constructor(){
|
|
52
|
+
this.name = "describeContentModel";
|
|
53
|
+
this.title = "Describe content model";
|
|
54
|
+
this.description = "Returns the fields of one content model — field IDs, types, whether each is a list, required flags, allowed values, and referenced models. Call this before queryEntries so filters use real field IDs.";
|
|
55
|
+
this.inputSchema = inputSchema;
|
|
56
|
+
this.annotations = {
|
|
57
|
+
readOnlyHint: true,
|
|
58
|
+
idempotentHint: true
|
|
59
|
+
};
|
|
60
|
+
this.handler = DescribeContentModelToolHandler;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
const DescribeContentModelTool = AiSdkToolDefinition.createImplementation({
|
|
64
|
+
implementation: DescribeContentModelToolImpl,
|
|
65
|
+
dependencies: []
|
|
66
|
+
});
|
|
58
67
|
export { DescribeContentModelTool };
|
|
59
68
|
|
|
60
69
|
//# sourceMappingURL=DescribeContentModelTool.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/ai/DescribeContentModelTool.js","sources":["../../../src/features/ai/DescribeContentModelTool.ts"],"sourcesContent":["import { z } from \"zod\";\nimport {
|
|
1
|
+
{"version":3,"file":"features/ai/DescribeContentModelTool.js","sources":["../../../src/features/ai/DescribeContentModelTool.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { AiSdkToolDefinition, AiSdkToolHandler } from \"@webiny/api-core/features/ai/index.js\";\nimport { GetModelUseCase } from \"~/features/contentModel/GetModel/index.js\";\nimport type { CmsModelField } from \"~/types/index.js\";\n\nconst inputSchema = z.object({\n modelId: z\n .string()\n .describe(\"Model ID as returned by listContentModels (e.g. 'product', not 'Products').\")\n});\n\ntype Input = z.infer<typeof inputSchema>;\n\ninterface FieldDescription {\n fieldId: string;\n type: string;\n label: string;\n /** True when the field holds an array of values — affects which `where` operators apply. */\n list: boolean;\n required: boolean;\n description?: string;\n /** Allowed values for enum-like fields, so a filter can be built without guessing. */\n predefinedValues?: string[];\n /** For `ref` fields: which models this field can point at. */\n refModels?: string[];\n /** For `object` fields: the nested field set. */\n fields?: FieldDescription[];\n}\n\ninterface ModelDescription {\n modelId: string;\n name: string;\n description: string | null;\n singularApiName: string;\n pluralApiName: string;\n titleFieldId: string;\n fields: FieldDescription[];\n}\n\nconst isRequired = (field: CmsModelField): boolean =>\n field.validation.some(validator => validator.name === \"required\");\n\nconst describeField = (field: CmsModelField): FieldDescription => {\n const described: FieldDescription = {\n fieldId: field.fieldId,\n type: field.type,\n label: field.label,\n list: Boolean(field.list),\n required: isRequired(field)\n };\n\n if (field.description) {\n described.description = field.description;\n }\n\n const values = field.predefinedValues;\n if (values?.enabled && values.values?.length) {\n described.predefinedValues = values.values.map(entry => entry.value);\n }\n\n const refModels = field.settings?.models;\n if (refModels?.length) {\n described.refModels = refModels.map(model => model.modelId);\n }\n\n const nested = field.settings?.fields;\n if (nested?.length) {\n described.fields = nested.map(describeField);\n }\n\n return described;\n};\n\nclass DescribeContentModelToolHandlerImpl implements AiSdkToolHandler.Interface<Input> {\n constructor(private getModel: GetModelUseCase.Interface) {}\n\n async execute(input: Input): Promise<ModelDescription> {\n const result = await this.getModel.execute(input.modelId);\n\n if (result.isFail()) {\n throw new Error(\n `Could not describe model \"${input.modelId}\": ${result.error.message}. Call listContentModels for valid model IDs.`\n );\n }\n\n const model = result.value;\n\n return {\n modelId: model.modelId,\n name: model.name,\n description: model.description,\n singularApiName: model.singularApiName,\n pluralApiName: model.pluralApiName,\n titleFieldId: model.titleFieldId,\n fields: model.fields.map(describeField)\n };\n }\n}\n\nconst DescribeContentModelToolHandler = AiSdkToolHandler.createImplementation({\n implementation: DescribeContentModelToolHandlerImpl,\n dependencies: [GetModelUseCase]\n});\n\n/**\n * Supplies the field detail needed to build a valid `queryEntries` filter. Deliberately a separate\n * call from `listContentModels`: returning full field sets for every model would be large and mostly\n * unread, so the model pays for detail only on the model it actually cares about.\n */\nclass DescribeContentModelToolImpl implements AiSdkToolDefinition.Interface<Input> {\n readonly name = \"describeContentModel\";\n readonly title = \"Describe content model\";\n readonly description =\n \"Returns the fields of one content model — field IDs, types, whether each is a list, required flags, allowed values, and referenced models. Call this before queryEntries so filters use real field IDs.\";\n readonly inputSchema = inputSchema;\n readonly annotations = { readOnlyHint: true, idempotentHint: true };\n readonly handler = DescribeContentModelToolHandler;\n}\n\nexport const DescribeContentModelTool = AiSdkToolDefinition.createImplementation({\n implementation: DescribeContentModelToolImpl,\n dependencies: []\n});\n"],"names":["inputSchema","z","isRequired","field","validator","describeField","described","Boolean","values","entry","refModels","model","nested","DescribeContentModelToolHandlerImpl","getModel","input","result","Error","DescribeContentModelToolHandler","AiSdkToolHandler","GetModelUseCase","DescribeContentModelToolImpl","DescribeContentModelTool","AiSdkToolDefinition"],"mappings":";;;AAKA,MAAMA,cAAcC,EAAE,MAAM,CAAC;IACzB,SAASA,EAAAA,MACE,GACN,QAAQ,CAAC;AAClB;AA8BA,MAAMC,aAAa,CAACC,QAChBA,MAAM,UAAU,CAAC,IAAI,CAACC,CAAAA,YAAaA,AAAmB,eAAnBA,UAAU,IAAI;AAErD,MAAMC,gBAAgB,CAACF;IACnB,MAAMG,YAA8B;QAChC,SAASH,MAAM,OAAO;QACtB,MAAMA,MAAM,IAAI;QAChB,OAAOA,MAAM,KAAK;QAClB,MAAMI,QAAQJ,MAAM,IAAI;QACxB,UAAUD,WAAWC;IACzB;IAEA,IAAIA,MAAM,WAAW,EACjBG,UAAU,WAAW,GAAGH,MAAM,WAAW;IAG7C,MAAMK,SAASL,MAAM,gBAAgB;IACrC,IAAIK,QAAQ,WAAWA,OAAO,MAAM,EAAE,QAClCF,UAAU,gBAAgB,GAAGE,OAAO,MAAM,CAAC,GAAG,CAACC,CAAAA,QAASA,MAAM,KAAK;IAGvE,MAAMC,YAAYP,MAAM,QAAQ,EAAE;IAClC,IAAIO,WAAW,QACXJ,UAAU,SAAS,GAAGI,UAAU,GAAG,CAACC,CAAAA,QAASA,MAAM,OAAO;IAG9D,MAAMC,SAAST,MAAM,QAAQ,EAAE;IAC/B,IAAIS,QAAQ,QACRN,UAAU,MAAM,GAAGM,OAAO,GAAG,CAACP;IAGlC,OAAOC;AACX;AAEA,MAAMO;IACF,YAAoBC,QAAmC,CAAE;aAArCA,QAAQ,GAARA;IAAsC;IAE1D,MAAM,QAAQC,KAAY,EAA6B;QACnD,MAAMC,SAAS,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,CAACD,MAAM,OAAO;QAExD,IAAIC,OAAO,MAAM,IACb,MAAM,IAAIC,MACN,CAAC,0BAA0B,EAAEF,MAAM,OAAO,CAAC,GAAG,EAAEC,OAAO,KAAK,CAAC,OAAO,CAAC,6CAA6C,CAAC;QAI3H,MAAML,QAAQK,OAAO,KAAK;QAE1B,OAAO;YACH,SAASL,MAAM,OAAO;YACtB,MAAMA,MAAM,IAAI;YAChB,aAAaA,MAAM,WAAW;YAC9B,iBAAiBA,MAAM,eAAe;YACtC,eAAeA,MAAM,aAAa;YAClC,cAAcA,MAAM,YAAY;YAChC,QAAQA,MAAM,MAAM,CAAC,GAAG,CAACN;QAC7B;IACJ;AACJ;AAEA,MAAMa,kCAAkCC,iBAAiB,oBAAoB,CAAC;IAC1E,gBAAgBN;IAChB,cAAc;QAACO;KAAgB;AACnC;AAOA,MAAMC;;aACO,IAAI,GAAG;aACP,KAAK,GAAG;aACR,WAAW,GAChB;aACK,WAAW,GAAGrB;aACd,WAAW,GAAG;YAAE,cAAc;YAAM,gBAAgB;QAAK;aACzD,OAAO,GAAGkB;;AACvB;AAEO,MAAMI,2BAA2BC,oBAAoB,oBAAoB,CAAC;IAC7E,gBAAgBF;IAChB,cAAc,EAAE;AACpB"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import
|
|
2
|
+
import { AiSdkToolDefinition, AiSdkToolHandler } from "@webiny/api-core/features/ai/index.js";
|
|
3
3
|
import { ListModelsUseCase } from "../../features/contentModel/ListModels/index.js";
|
|
4
4
|
declare const inputSchema: z.ZodObject<{
|
|
5
5
|
includeSystem: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -15,13 +15,17 @@ interface ModelSummary {
|
|
|
15
15
|
titleFieldId: string;
|
|
16
16
|
fieldCount: number;
|
|
17
17
|
}
|
|
18
|
+
declare class ListContentModelsToolHandlerImpl implements AiSdkToolHandler.Interface<Input> {
|
|
19
|
+
private listModels;
|
|
20
|
+
constructor(listModels: ListModelsUseCase.Interface);
|
|
21
|
+
execute(input: Input): Promise<ModelSummary[]>;
|
|
22
|
+
}
|
|
18
23
|
/**
|
|
19
24
|
* Entry point for any content question. The CMS schema is defined per project (and per tenant), so a
|
|
20
25
|
* model list cannot be baked into a system prompt — it has to be discovered at call time. Returns a
|
|
21
26
|
* summary only; `describeContentModel` supplies the field detail needed to actually build a query.
|
|
22
27
|
*/
|
|
23
|
-
declare class ListContentModelsToolImpl implements
|
|
24
|
-
private listModels;
|
|
28
|
+
declare class ListContentModelsToolImpl implements AiSdkToolDefinition.Interface<Input> {
|
|
25
29
|
readonly name = "listContentModels";
|
|
26
30
|
readonly title = "List content models";
|
|
27
31
|
readonly description = "Lists the content models available in this project. Call this first when you need to find content \u2014 model IDs are project-specific and cannot be guessed. Returns a summary per model; use describeContentModel for field details.";
|
|
@@ -32,10 +36,11 @@ declare class ListContentModelsToolImpl implements IAiSdkTool<Input> {
|
|
|
32
36
|
readOnlyHint: boolean;
|
|
33
37
|
idempotentHint: boolean;
|
|
34
38
|
};
|
|
35
|
-
|
|
36
|
-
|
|
39
|
+
readonly handler: typeof ListContentModelsToolHandlerImpl & {
|
|
40
|
+
__abstraction: import("@webiny/di").Abstraction<import("@webiny/api-core/features/ai/abstractions").IAiSdkToolHandler<any>>;
|
|
41
|
+
};
|
|
37
42
|
}
|
|
38
43
|
export declare const ListContentModelsTool: typeof ListContentModelsToolImpl & {
|
|
39
|
-
__abstraction: import("@webiny/di").Abstraction<
|
|
44
|
+
__abstraction: import("@webiny/di").Abstraction<import("@webiny/api-core/features/ai/abstractions").IAiSdkToolDefinition<any>>;
|
|
40
45
|
};
|
|
41
46
|
export {};
|
|
@@ -1,22 +1,14 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import {
|
|
2
|
+
import { AiSdkToolDefinition, AiSdkToolHandler } from "@webiny/api-core/features/ai/index.js";
|
|
3
3
|
import { ListModelsUseCase } from "../contentModel/ListModels/index.js";
|
|
4
4
|
const HIDDEN_MODEL_GROUP = "hidden";
|
|
5
5
|
const inputSchema = z.object({
|
|
6
6
|
includeSystem: z.boolean().optional().describe("Include system models that back Webiny itself (languages, tenants, task settings) and internal models belonging to other apps. Off by default — these are never what a user means by 'content'.")
|
|
7
7
|
});
|
|
8
8
|
const isSystemModel = (model)=>Boolean(model.isPrivate) || model.group === HIDDEN_MODEL_GROUP;
|
|
9
|
-
class
|
|
9
|
+
class ListContentModelsToolHandlerImpl {
|
|
10
10
|
constructor(listModels){
|
|
11
11
|
this.listModels = listModels;
|
|
12
|
-
this.name = "listContentModels";
|
|
13
|
-
this.title = "List content models";
|
|
14
|
-
this.description = "Lists the content models available in this project. Call this first when you need to find content — model IDs are project-specific and cannot be guessed. Returns a summary per model; use describeContentModel for field details.";
|
|
15
|
-
this.inputSchema = inputSchema;
|
|
16
|
-
this.annotations = {
|
|
17
|
-
readOnlyHint: true,
|
|
18
|
-
idempotentHint: true
|
|
19
|
-
};
|
|
20
12
|
}
|
|
21
13
|
async execute(input) {
|
|
22
14
|
const result = await this.listModels.execute();
|
|
@@ -33,12 +25,29 @@ class ListContentModelsToolImpl {
|
|
|
33
25
|
}));
|
|
34
26
|
}
|
|
35
27
|
}
|
|
36
|
-
const
|
|
37
|
-
implementation:
|
|
28
|
+
const ListContentModelsToolHandler = AiSdkToolHandler.createImplementation({
|
|
29
|
+
implementation: ListContentModelsToolHandlerImpl,
|
|
38
30
|
dependencies: [
|
|
39
31
|
ListModelsUseCase
|
|
40
32
|
]
|
|
41
33
|
});
|
|
34
|
+
class ListContentModelsToolImpl {
|
|
35
|
+
constructor(){
|
|
36
|
+
this.name = "listContentModels";
|
|
37
|
+
this.title = "List content models";
|
|
38
|
+
this.description = "Lists the content models available in this project. Call this first when you need to find content — model IDs are project-specific and cannot be guessed. Returns a summary per model; use describeContentModel for field details.";
|
|
39
|
+
this.inputSchema = inputSchema;
|
|
40
|
+
this.annotations = {
|
|
41
|
+
readOnlyHint: true,
|
|
42
|
+
idempotentHint: true
|
|
43
|
+
};
|
|
44
|
+
this.handler = ListContentModelsToolHandler;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const ListContentModelsTool = AiSdkToolDefinition.createImplementation({
|
|
48
|
+
implementation: ListContentModelsToolImpl,
|
|
49
|
+
dependencies: []
|
|
50
|
+
});
|
|
42
51
|
export { ListContentModelsTool };
|
|
43
52
|
|
|
44
53
|
//# sourceMappingURL=ListContentModelsTool.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/ai/ListContentModelsTool.js","sources":["../../../src/features/ai/ListContentModelsTool.ts"],"sourcesContent":["import { z } from \"zod\";\nimport {
|
|
1
|
+
{"version":3,"file":"features/ai/ListContentModelsTool.js","sources":["../../../src/features/ai/ListContentModelsTool.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { AiSdkToolDefinition, AiSdkToolHandler } from \"@webiny/api-core/features/ai/index.js\";\nimport { ListModelsUseCase } from \"~/features/contentModel/ListModels/index.js\";\nimport type { CmsModel } from \"~/types/index.js\";\n\nconst HIDDEN_MODEL_GROUP = \"hidden\";\n\nconst inputSchema = z.object({\n includeSystem: z\n .boolean()\n .optional()\n .describe(\n \"Include system models that back Webiny itself (languages, tenants, task settings) and internal models belonging to other apps. Off by default — these are never what a user means by 'content'.\"\n )\n});\n\ntype Input = z.infer<typeof inputSchema>;\n\ninterface ModelSummary {\n modelId: string;\n name: string;\n description: string | null;\n group: string;\n singularApiName: string;\n pluralApiName: string;\n titleFieldId: string;\n fieldCount: number;\n}\n\n/**\n * Models Webiny itself owns. Two separate markers, both needed:\n * - `group: \"hidden\"` — the convention system models use (languages, tenants, background-task\n * settings). The admin UI filters the same way, see app-headless-cms useCmsData.\n * - `isPrivate` — models another app owns and manages through its own UI (e.g. Website Builder).\n */\nconst isSystemModel = (model: CmsModel): boolean =>\n Boolean(model.isPrivate) || model.group === HIDDEN_MODEL_GROUP;\n\nclass ListContentModelsToolHandlerImpl implements AiSdkToolHandler.Interface<Input> {\n constructor(private listModels: ListModelsUseCase.Interface) {}\n\n async execute(input: Input): Promise<ModelSummary[]> {\n const result = await this.listModels.execute();\n\n if (result.isFail()) {\n throw new Error(`Could not list content models: ${result.error.message}`);\n }\n\n return result.value\n .filter(model => (input.includeSystem ? true : !isSystemModel(model)))\n .map(model => ({\n modelId: model.modelId,\n name: model.name,\n description: model.description,\n group: model.group,\n singularApiName: model.singularApiName,\n pluralApiName: model.pluralApiName,\n titleFieldId: model.titleFieldId,\n fieldCount: model.fields.length\n }));\n }\n}\n\nconst ListContentModelsToolHandler = AiSdkToolHandler.createImplementation({\n implementation: ListContentModelsToolHandlerImpl,\n dependencies: [ListModelsUseCase]\n});\n\n/**\n * Entry point for any content question. The CMS schema is defined per project (and per tenant), so a\n * model list cannot be baked into a system prompt — it has to be discovered at call time. Returns a\n * summary only; `describeContentModel` supplies the field detail needed to actually build a query.\n */\nclass ListContentModelsToolImpl implements AiSdkToolDefinition.Interface<Input> {\n readonly name = \"listContentModels\";\n readonly title = \"List content models\";\n readonly description =\n \"Lists the content models available in this project. Call this first when you need to find content — model IDs are project-specific and cannot be guessed. Returns a summary per model; use describeContentModel for field details.\";\n readonly inputSchema = inputSchema;\n readonly annotations = { readOnlyHint: true, idempotentHint: true };\n readonly handler = ListContentModelsToolHandler;\n}\n\nexport const ListContentModelsTool = AiSdkToolDefinition.createImplementation({\n implementation: ListContentModelsToolImpl,\n dependencies: []\n});\n"],"names":["HIDDEN_MODEL_GROUP","inputSchema","z","isSystemModel","model","Boolean","ListContentModelsToolHandlerImpl","listModels","input","result","Error","ListContentModelsToolHandler","AiSdkToolHandler","ListModelsUseCase","ListContentModelsToolImpl","ListContentModelsTool","AiSdkToolDefinition"],"mappings":";;;AAKA,MAAMA,qBAAqB;AAE3B,MAAMC,cAAcC,EAAE,MAAM,CAAC;IACzB,eAAeA,EAAAA,OACH,GACP,QAAQ,GACR,QAAQ,CACL;AAEZ;AAqBA,MAAMC,gBAAgB,CAACC,QACnBC,QAAQD,MAAM,SAAS,KAAKA,MAAM,KAAK,KAAKJ;AAEhD,MAAMM;IACF,YAAoBC,UAAuC,CAAE;aAAzCA,UAAU,GAAVA;IAA0C;IAE9D,MAAM,QAAQC,KAAY,EAA2B;QACjD,MAAMC,SAAS,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO;QAE5C,IAAIA,OAAO,MAAM,IACb,MAAM,IAAIC,MAAM,CAAC,+BAA+B,EAAED,OAAO,KAAK,CAAC,OAAO,EAAE;QAG5E,OAAOA,OAAO,KAAK,CACd,MAAM,CAACL,CAAAA,QAAUI,MAAM,aAAa,GAAG,OAAO,CAACL,cAAcC,QAC7D,GAAG,CAACA,CAAAA,QAAU;gBACX,SAASA,MAAM,OAAO;gBACtB,MAAMA,MAAM,IAAI;gBAChB,aAAaA,MAAM,WAAW;gBAC9B,OAAOA,MAAM,KAAK;gBAClB,iBAAiBA,MAAM,eAAe;gBACtC,eAAeA,MAAM,aAAa;gBAClC,cAAcA,MAAM,YAAY;gBAChC,YAAYA,MAAM,MAAM,CAAC,MAAM;YACnC;IACR;AACJ;AAEA,MAAMO,+BAA+BC,iBAAiB,oBAAoB,CAAC;IACvE,gBAAgBN;IAChB,cAAc;QAACO;KAAkB;AACrC;AAOA,MAAMC;;aACO,IAAI,GAAG;aACP,KAAK,GAAG;aACR,WAAW,GAChB;aACK,WAAW,GAAGb;aACd,WAAW,GAAG;YAAE,cAAc;YAAM,gBAAgB;QAAK;aACzD,OAAO,GAAGU;;AACvB;AAEO,MAAMI,wBAAwBC,oBAAoB,oBAAoB,CAAC;IAC1E,gBAAgBF;IAChB,cAAc,EAAE;AACpB"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import
|
|
2
|
+
import { AiSdkToolDefinition, AiSdkToolHandler } from "@webiny/api-core/features/ai/index.js";
|
|
3
3
|
import { GetModelUseCase } from "../../features/contentModel/GetModel/index.js";
|
|
4
4
|
import { ListLatestEntriesUseCase } from "../../features/contentEntry/ListEntries/index.js";
|
|
5
5
|
import { CmsWhereMapper } from "../../features/whereMapper/abstractions.js";
|
|
@@ -31,6 +31,14 @@ interface QueryEntriesResult {
|
|
|
31
31
|
cursor: string | null;
|
|
32
32
|
};
|
|
33
33
|
}
|
|
34
|
+
declare class QueryEntriesToolHandlerImpl implements AiSdkToolHandler.Interface<Input> {
|
|
35
|
+
private getModel;
|
|
36
|
+
private listLatestEntries;
|
|
37
|
+
private whereMapper;
|
|
38
|
+
private sortMapper;
|
|
39
|
+
constructor(getModel: GetModelUseCase.Interface, listLatestEntries: ListLatestEntriesUseCase.Interface, whereMapper: CmsWhereMapper.Interface, sortMapper: CmsSortMapper.Interface);
|
|
40
|
+
execute(input: Input): Promise<QueryEntriesResult>;
|
|
41
|
+
}
|
|
34
42
|
/**
|
|
35
43
|
* Reads entries for one model.
|
|
36
44
|
*
|
|
@@ -46,11 +54,7 @@ interface QueryEntriesResult {
|
|
|
46
54
|
* model's own fields under `values` and leave entry meta at the top. The flat form is what a model
|
|
47
55
|
* writes, because `describeContentModel` hands it a flat list of fieldIds.
|
|
48
56
|
*/
|
|
49
|
-
declare class QueryEntriesToolImpl implements
|
|
50
|
-
private getModel;
|
|
51
|
-
private listLatestEntries;
|
|
52
|
-
private whereMapper;
|
|
53
|
-
private sortMapper;
|
|
57
|
+
declare class QueryEntriesToolImpl implements AiSdkToolDefinition.Interface<Input> {
|
|
54
58
|
readonly name = "queryEntries";
|
|
55
59
|
readonly title = "Query content entries";
|
|
56
60
|
readonly description = "Queries content entries for a model, with filtering, sorting, search and pagination. Returns the latest revision of each entry (including unpublished changes). Call describeContentModel first to learn the field IDs used in `where` and `sort`.";
|
|
@@ -66,10 +70,11 @@ declare class QueryEntriesToolImpl implements IAiSdkTool<Input> {
|
|
|
66
70
|
readonly annotations: {
|
|
67
71
|
readOnlyHint: boolean;
|
|
68
72
|
};
|
|
69
|
-
|
|
70
|
-
|
|
73
|
+
readonly handler: typeof QueryEntriesToolHandlerImpl & {
|
|
74
|
+
__abstraction: import("@webiny/di").Abstraction<import("@webiny/api-core/features/ai/abstractions").IAiSdkToolHandler<any>>;
|
|
75
|
+
};
|
|
71
76
|
}
|
|
72
77
|
export declare const QueryEntriesTool: typeof QueryEntriesToolImpl & {
|
|
73
|
-
__abstraction: import("@webiny/di").Abstraction<
|
|
78
|
+
__abstraction: import("@webiny/di").Abstraction<import("@webiny/api-core/features/ai/abstractions").IAiSdkToolDefinition<any>>;
|
|
74
79
|
};
|
|
75
80
|
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import {
|
|
2
|
+
import { AiSdkToolDefinition, AiSdkToolHandler } from "@webiny/api-core/features/ai/index.js";
|
|
3
3
|
import { GetModelUseCase } from "../contentModel/GetModel/index.js";
|
|
4
4
|
import { ListLatestEntriesUseCase } from "../contentEntry/ListEntries/index.js";
|
|
5
5
|
import { CmsWhereMapper } from "../whereMapper/abstractions.js";
|
|
@@ -15,19 +15,12 @@ const inputSchema = z.object({
|
|
|
15
15
|
limit: z.number().int().positive().optional().describe(`Maximum entries to return. Defaults to ${DEFAULT_LIMIT}, capped at ${MAX_LIMIT}.`),
|
|
16
16
|
after: z.string().optional().describe("Pagination cursor from a previous call's meta.cursor.")
|
|
17
17
|
});
|
|
18
|
-
class
|
|
18
|
+
class QueryEntriesToolHandlerImpl {
|
|
19
19
|
constructor(getModel, listLatestEntries, whereMapper, sortMapper){
|
|
20
20
|
this.getModel = getModel;
|
|
21
21
|
this.listLatestEntries = listLatestEntries;
|
|
22
22
|
this.whereMapper = whereMapper;
|
|
23
23
|
this.sortMapper = sortMapper;
|
|
24
|
-
this.name = "queryEntries";
|
|
25
|
-
this.title = "Query content entries";
|
|
26
|
-
this.description = "Queries content entries for a model, with filtering, sorting, search and pagination. Returns the latest revision of each entry (including unpublished changes). Call describeContentModel first to learn the field IDs used in `where` and `sort`.";
|
|
27
|
-
this.inputSchema = inputSchema;
|
|
28
|
-
this.annotations = {
|
|
29
|
-
readOnlyHint: true
|
|
30
|
-
};
|
|
31
24
|
}
|
|
32
25
|
async execute(input) {
|
|
33
26
|
const modelResult = await this.getModel.execute(input.modelId);
|
|
@@ -76,8 +69,8 @@ class QueryEntriesToolImpl {
|
|
|
76
69
|
};
|
|
77
70
|
}
|
|
78
71
|
}
|
|
79
|
-
const
|
|
80
|
-
implementation:
|
|
72
|
+
const QueryEntriesToolHandler = AiSdkToolHandler.createImplementation({
|
|
73
|
+
implementation: QueryEntriesToolHandlerImpl,
|
|
81
74
|
dependencies: [
|
|
82
75
|
GetModelUseCase,
|
|
83
76
|
ListLatestEntriesUseCase,
|
|
@@ -85,6 +78,22 @@ const QueryEntriesTool = AiSdkTool.createImplementation({
|
|
|
85
78
|
CmsSortMapper
|
|
86
79
|
]
|
|
87
80
|
});
|
|
81
|
+
class QueryEntriesToolImpl {
|
|
82
|
+
constructor(){
|
|
83
|
+
this.name = "queryEntries";
|
|
84
|
+
this.title = "Query content entries";
|
|
85
|
+
this.description = "Queries content entries for a model, with filtering, sorting, search and pagination. Returns the latest revision of each entry (including unpublished changes). Call describeContentModel first to learn the field IDs used in `where` and `sort`.";
|
|
86
|
+
this.inputSchema = inputSchema;
|
|
87
|
+
this.annotations = {
|
|
88
|
+
readOnlyHint: true
|
|
89
|
+
};
|
|
90
|
+
this.handler = QueryEntriesToolHandler;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const QueryEntriesTool = AiSdkToolDefinition.createImplementation({
|
|
94
|
+
implementation: QueryEntriesToolImpl,
|
|
95
|
+
dependencies: []
|
|
96
|
+
});
|
|
88
97
|
export { QueryEntriesTool };
|
|
89
98
|
|
|
90
99
|
//# sourceMappingURL=QueryEntriesTool.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/ai/QueryEntriesTool.js","sources":["../../../src/features/ai/QueryEntriesTool.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { AiSdkTool } from \"@webiny/api-core/features/ai/index.js\";\nimport type { IAiSdkTool } from \"@webiny/api-core/features/ai/index.js\";\nimport { GetModelUseCase } from \"~/features/contentModel/GetModel/index.js\";\nimport { ListLatestEntriesUseCase } from \"~/features/contentEntry/ListEntries/index.js\";\nimport { CmsWhereMapper } from \"~/features/whereMapper/abstractions.js\";\nimport { CmsSortMapper } from \"~/features/sortMapper/abstractions.js\";\nimport type { CmsEntryListParams } from \"~/types/index.js\";\nimport type { CmsEntryListSort } from \"~/types/index.js\";\n\n/**\n * Hard ceiling on returned entries. A model asking for \"all products\" would otherwise pull an entire\n * collection into the context window; the cursor in the response is the correct way to go deeper.\n */\nconst MAX_LIMIT = 50;\nconst DEFAULT_LIMIT = 10;\n\nconst inputSchema = z.object({\n modelId: z.string().describe(\"Model ID as returned by listContentModels.\"),\n where: z\n .record(z.string(), z.unknown())\n .optional()\n .describe(\n \"Flat filter object. Keys are `<fieldId>` for an exact match or `<fieldId>_<operator>` otherwise — e.g. { onSale: true, price_gt: 100, name_contains: 'desk', status: 'draft' }. Operators: _not, _in, _not_in, _lt, _lte, _gt, _gte, _contains, _not_contains, _startsWith, _not_startsWith, _between, _not_between. Mix the model's own fields with entry meta fields (id, entryId, status, createdOn, savedOn) freely — they are separated automatically. Use describeContentModel first so field IDs are real.\"\n ),\n sort: z\n .array(z.string())\n .optional()\n .describe(\n \"Sort directives as `<fieldId>_ASC` or `<fieldId>_DESC` — e.g. ['price_DESC'] for a model field or ['savedOn_DESC'] for entry meta. Both forms are accepted; the distinction is handled automatically.\"\n ),\n search: z\n .string()\n .optional()\n .describe(\"Full-text search across the model's searchable fields.\"),\n fields: z\n .array(z.string())\n .optional()\n .describe(\n \"Restrict returned values to these field IDs. Use it whenever you only need a few fields — entries can be large.\"\n ),\n limit: z\n .number()\n .int()\n .positive()\n .optional()\n .describe(\n `Maximum entries to return. Defaults to ${DEFAULT_LIMIT}, capped at ${MAX_LIMIT}.`\n ),\n after: z.string().optional().describe(\"Pagination cursor from a previous call's meta.cursor.\")\n});\n\ntype Input = z.infer<typeof inputSchema>;\n\ninterface EntrySummary {\n id: string;\n entryId: string;\n status: string;\n createdOn: string;\n savedOn: string;\n values: Record<string, unknown>;\n}\n\ninterface QueryEntriesResult {\n modelId: string;\n entries: EntrySummary[];\n meta: {\n totalCount: number;\n hasMoreItems: boolean;\n cursor: string | null;\n };\n}\n\n/**\n * Reads entries for one model.\n *\n * Uses the LATEST revisions (the manage-API view), not published ones — an editor asking \"which\n * products are discounted\" means the content as it currently stands in the admin app, including\n * unpublished edits. Filter on `status` for a published-only view.\n *\n * `where` is passed through to the CMS rather than re-modelled as a Zod schema: the valid keys depend\n * entirely on the model's fields, which are only known at runtime. An invalid filter surfaces as a\n * tool error the model can correct, which is why `describeContentModel` is named in the description.\n *\n * `where` and `sort` arrive FLAT and go through `CmsWhereMapper`/`CmsSortMapper`, which nest the\n * model's own fields under `values` and leave entry meta at the top. The flat form is what a model\n * writes, because `describeContentModel` hands it a flat list of fieldIds.\n */\nclass QueryEntriesToolImpl implements IAiSdkTool<Input> {\n readonly name = \"queryEntries\";\n readonly title = \"Query content entries\";\n readonly description =\n \"Queries content entries for a model, with filtering, sorting, search and pagination. Returns the latest revision of each entry (including unpublished changes). Call describeContentModel first to learn the field IDs used in `where` and `sort`.\";\n readonly inputSchema = inputSchema;\n readonly annotations = { readOnlyHint: true };\n\n constructor(\n private getModel: GetModelUseCase.Interface,\n private listLatestEntries: ListLatestEntriesUseCase.Interface,\n private whereMapper: CmsWhereMapper.Interface,\n private sortMapper: CmsSortMapper.Interface\n ) {}\n\n async execute(input: Input): Promise<QueryEntriesResult> {\n const modelResult = await this.getModel.execute(input.modelId);\n\n if (modelResult.isFail()) {\n throw new Error(\n `Unknown model \"${input.modelId}\": ${modelResult.error.message}. Call listContentModels for valid model IDs.`\n );\n }\n\n const model = modelResult.value;\n\n const params: CmsEntryListParams = {\n limit: Math.min(input.limit ?? DEFAULT_LIMIT, MAX_LIMIT)\n };\n\n if (input.where) {\n const where = this.whereMapper.map({ fields: model.fields, input: input.where });\n\n if (where) {\n params.where = where;\n }\n }\n\n if (input.sort?.length) {\n /*\n * `CmsEntryListSort` is a template-literal type, while the schema yields plain strings\n * because a model writes whatever it likes. Casting here is safe only because of the\n * check below, which refuses the call if the mapper could not read every directive.\n */\n const requested = input.sort as CmsEntryListSort;\n const sort = this.sortMapper.map({ fields: model.fields, input: requested });\n\n /*\n * The mapper drops a directive it cannot parse. Silence is the wrong answer here: the\n * query would run unsorted and the model would present the result as sorted. Comparing\n * lengths rather than re-checking the format keeps this in step with whatever the mapper\n * accepts.\n */\n if (!sort || sort.length !== input.sort.length) {\n throw new Error(\n `Could not read every sort directive in [${input.sort.join(\", \")}]. Each one must be \\`<fieldId>_ASC\\` or \\`<fieldId>_DESC\\`, using a field ID from describeContentModel.`\n );\n }\n\n params.sort = sort;\n }\n\n if (input.search) {\n params.search = input.search;\n }\n\n if (input.fields?.length) {\n params.fields = input.fields;\n }\n\n if (input.after) {\n params.after = input.after;\n }\n\n const result = await this.listLatestEntries.execute(model, params);\n\n if (result.isFail()) {\n throw new Error(`Could not query \"${input.modelId}\" entries: ${result.error.message}`);\n }\n\n const { entries, meta } = result.value;\n\n return {\n modelId: input.modelId,\n entries: entries.map(entry => ({\n id: entry.id,\n entryId: entry.entryId,\n status: entry.status,\n createdOn: entry.createdOn,\n savedOn: entry.savedOn,\n values: entry.values\n })),\n meta: {\n totalCount: meta.totalCount,\n hasMoreItems: meta.hasMoreItems,\n cursor: meta.cursor\n }\n };\n }\n}\n\nexport const QueryEntriesTool = AiSdkTool.createImplementation({\n implementation: QueryEntriesToolImpl,\n dependencies: [GetModelUseCase, ListLatestEntriesUseCase, CmsWhereMapper, CmsSortMapper]\n});\n"],"names":["MAX_LIMIT","DEFAULT_LIMIT","inputSchema","z","QueryEntriesToolImpl","getModel","listLatestEntries","whereMapper","sortMapper","input","modelResult","Error","model","params","Math","where","requested","sort","result","entries","meta","entry","QueryEntriesTool","AiSdkTool","GetModelUseCase","ListLatestEntriesUseCase","CmsWhereMapper","CmsSortMapper"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"features/ai/QueryEntriesTool.js","sources":["../../../src/features/ai/QueryEntriesTool.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { AiSdkToolDefinition, AiSdkToolHandler } from \"@webiny/api-core/features/ai/index.js\";\nimport { GetModelUseCase } from \"~/features/contentModel/GetModel/index.js\";\nimport { ListLatestEntriesUseCase } from \"~/features/contentEntry/ListEntries/index.js\";\nimport { CmsWhereMapper } from \"~/features/whereMapper/abstractions.js\";\nimport { CmsSortMapper } from \"~/features/sortMapper/abstractions.js\";\nimport type { CmsEntryListParams } from \"~/types/index.js\";\nimport type { CmsEntryListSort } from \"~/types/index.js\";\n\n/**\n * Hard ceiling on returned entries. A model asking for \"all products\" would otherwise pull an entire\n * collection into the context window; the cursor in the response is the correct way to go deeper.\n */\nconst MAX_LIMIT = 50;\nconst DEFAULT_LIMIT = 10;\n\nconst inputSchema = z.object({\n modelId: z.string().describe(\"Model ID as returned by listContentModels.\"),\n where: z\n .record(z.string(), z.unknown())\n .optional()\n .describe(\n \"Flat filter object. Keys are `<fieldId>` for an exact match or `<fieldId>_<operator>` otherwise — e.g. { onSale: true, price_gt: 100, name_contains: 'desk', status: 'draft' }. Operators: _not, _in, _not_in, _lt, _lte, _gt, _gte, _contains, _not_contains, _startsWith, _not_startsWith, _between, _not_between. Mix the model's own fields with entry meta fields (id, entryId, status, createdOn, savedOn) freely — they are separated automatically. Use describeContentModel first so field IDs are real.\"\n ),\n sort: z\n .array(z.string())\n .optional()\n .describe(\n \"Sort directives as `<fieldId>_ASC` or `<fieldId>_DESC` — e.g. ['price_DESC'] for a model field or ['savedOn_DESC'] for entry meta. Both forms are accepted; the distinction is handled automatically.\"\n ),\n search: z\n .string()\n .optional()\n .describe(\"Full-text search across the model's searchable fields.\"),\n fields: z\n .array(z.string())\n .optional()\n .describe(\n \"Restrict returned values to these field IDs. Use it whenever you only need a few fields — entries can be large.\"\n ),\n limit: z\n .number()\n .int()\n .positive()\n .optional()\n .describe(\n `Maximum entries to return. Defaults to ${DEFAULT_LIMIT}, capped at ${MAX_LIMIT}.`\n ),\n after: z.string().optional().describe(\"Pagination cursor from a previous call's meta.cursor.\")\n});\n\ntype Input = z.infer<typeof inputSchema>;\n\ninterface EntrySummary {\n id: string;\n entryId: string;\n status: string;\n createdOn: string;\n savedOn: string;\n values: Record<string, unknown>;\n}\n\ninterface QueryEntriesResult {\n modelId: string;\n entries: EntrySummary[];\n meta: {\n totalCount: number;\n hasMoreItems: boolean;\n cursor: string | null;\n };\n}\n\nclass QueryEntriesToolHandlerImpl implements AiSdkToolHandler.Interface<Input> {\n constructor(\n private getModel: GetModelUseCase.Interface,\n private listLatestEntries: ListLatestEntriesUseCase.Interface,\n private whereMapper: CmsWhereMapper.Interface,\n private sortMapper: CmsSortMapper.Interface\n ) {}\n\n async execute(input: Input): Promise<QueryEntriesResult> {\n const modelResult = await this.getModel.execute(input.modelId);\n\n if (modelResult.isFail()) {\n throw new Error(\n `Unknown model \"${input.modelId}\": ${modelResult.error.message}. Call listContentModels for valid model IDs.`\n );\n }\n\n const model = modelResult.value;\n\n const params: CmsEntryListParams = {\n limit: Math.min(input.limit ?? DEFAULT_LIMIT, MAX_LIMIT)\n };\n\n if (input.where) {\n const where = this.whereMapper.map({ fields: model.fields, input: input.where });\n\n if (where) {\n params.where = where;\n }\n }\n\n if (input.sort?.length) {\n /*\n * `CmsEntryListSort` is a template-literal type, while the schema yields plain strings\n * because a model writes whatever it likes. Casting here is safe only because of the\n * check below, which refuses the call if the mapper could not read every directive.\n */\n const requested = input.sort as CmsEntryListSort;\n const sort = this.sortMapper.map({ fields: model.fields, input: requested });\n\n /*\n * The mapper drops a directive it cannot parse. Silence is the wrong answer here: the\n * query would run unsorted and the model would present the result as sorted. Comparing\n * lengths rather than re-checking the format keeps this in step with whatever the mapper\n * accepts.\n */\n if (!sort || sort.length !== input.sort.length) {\n throw new Error(\n `Could not read every sort directive in [${input.sort.join(\", \")}]. Each one must be \\`<fieldId>_ASC\\` or \\`<fieldId>_DESC\\`, using a field ID from describeContentModel.`\n );\n }\n\n params.sort = sort;\n }\n\n if (input.search) {\n params.search = input.search;\n }\n\n if (input.fields?.length) {\n params.fields = input.fields;\n }\n\n if (input.after) {\n params.after = input.after;\n }\n\n const result = await this.listLatestEntries.execute(model, params);\n\n if (result.isFail()) {\n throw new Error(`Could not query \"${input.modelId}\" entries: ${result.error.message}`);\n }\n\n const { entries, meta } = result.value;\n\n return {\n modelId: input.modelId,\n entries: entries.map(entry => ({\n id: entry.id,\n entryId: entry.entryId,\n status: entry.status,\n createdOn: entry.createdOn,\n savedOn: entry.savedOn,\n values: entry.values\n })),\n meta: {\n totalCount: meta.totalCount,\n hasMoreItems: meta.hasMoreItems,\n cursor: meta.cursor\n }\n };\n }\n}\n\nconst QueryEntriesToolHandler = AiSdkToolHandler.createImplementation({\n implementation: QueryEntriesToolHandlerImpl,\n dependencies: [GetModelUseCase, ListLatestEntriesUseCase, CmsWhereMapper, CmsSortMapper]\n});\n\n/**\n * Reads entries for one model.\n *\n * Uses the LATEST revisions (the manage-API view), not published ones — an editor asking \"which\n * products are discounted\" means the content as it currently stands in the admin app, including\n * unpublished edits. Filter on `status` for a published-only view.\n *\n * `where` is passed through to the CMS rather than re-modelled as a Zod schema: the valid keys depend\n * entirely on the model's fields, which are only known at runtime. An invalid filter surfaces as a\n * tool error the model can correct, which is why `describeContentModel` is named in the description.\n *\n * `where` and `sort` arrive FLAT and go through `CmsWhereMapper`/`CmsSortMapper`, which nest the\n * model's own fields under `values` and leave entry meta at the top. The flat form is what a model\n * writes, because `describeContentModel` hands it a flat list of fieldIds.\n */\nclass QueryEntriesToolImpl implements AiSdkToolDefinition.Interface<Input> {\n readonly name = \"queryEntries\";\n readonly title = \"Query content entries\";\n readonly description =\n \"Queries content entries for a model, with filtering, sorting, search and pagination. Returns the latest revision of each entry (including unpublished changes). Call describeContentModel first to learn the field IDs used in `where` and `sort`.\";\n readonly inputSchema = inputSchema;\n readonly annotations = { readOnlyHint: true };\n readonly handler = QueryEntriesToolHandler;\n}\n\nexport const QueryEntriesTool = AiSdkToolDefinition.createImplementation({\n implementation: QueryEntriesToolImpl,\n dependencies: []\n});\n"],"names":["MAX_LIMIT","DEFAULT_LIMIT","inputSchema","z","QueryEntriesToolHandlerImpl","getModel","listLatestEntries","whereMapper","sortMapper","input","modelResult","Error","model","params","Math","where","requested","sort","result","entries","meta","entry","QueryEntriesToolHandler","AiSdkToolHandler","GetModelUseCase","ListLatestEntriesUseCase","CmsWhereMapper","CmsSortMapper","QueryEntriesToolImpl","QueryEntriesTool","AiSdkToolDefinition"],"mappings":"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"}
|
package/features/ai/feature.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Read-only CMS tools for AI callers. Registered as `
|
|
3
|
-
* builds a tool set from that abstraction picks them up without naming them.
|
|
2
|
+
* Read-only CMS tools for AI callers. Registered as `AiSdkToolDefinition` implementations, so any
|
|
3
|
+
* caller that builds a tool set from that abstraction picks them up without naming them.
|
|
4
4
|
*/
|
|
5
5
|
export declare const CmsAiToolsFeature: {
|
|
6
6
|
name: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/ai/feature.js","sources":["../../../src/features/ai/feature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport { ListContentModelsTool } from \"./ListContentModelsTool.js\";\nimport { DescribeContentModelTool } from \"./DescribeContentModelTool.js\";\nimport { QueryEntriesTool } from \"./QueryEntriesTool.js\";\n\n/**\n * Read-only CMS tools for AI callers. Registered as `
|
|
1
|
+
{"version":3,"file":"features/ai/feature.js","sources":["../../../src/features/ai/feature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport { ListContentModelsTool } from \"./ListContentModelsTool.js\";\nimport { DescribeContentModelTool } from \"./DescribeContentModelTool.js\";\nimport { QueryEntriesTool } from \"./QueryEntriesTool.js\";\n\n/**\n * Read-only CMS tools for AI callers. Registered as `AiSdkToolDefinition` implementations, so any\n * caller that builds a tool set from that abstraction picks them up without naming them.\n */\nexport const CmsAiToolsFeature = createFeature({\n name: \"HeadlessCms/AiTools\",\n register(container) {\n container.register(ListContentModelsTool);\n container.register(DescribeContentModelTool);\n container.register(QueryEntriesTool);\n }\n});\n"],"names":["CmsAiToolsFeature","createFeature","container","ListContentModelsTool","DescribeContentModelTool","QueryEntriesTool"],"mappings":";;;;AASO,MAAMA,oBAAoBC,cAAc;IAC3C,MAAM;IACN,UAASC,SAAS;QACdA,UAAU,QAAQ,CAACC;QACnBD,UAAU,QAAQ,CAACE;QACnBF,UAAU,QAAQ,CAACG;IACvB;AACJ"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webiny/api-headless-cms",
|
|
3
|
-
"version": "6.6.0-alpha.
|
|
3
|
+
"version": "6.6.0-alpha.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./index.js",
|
|
@@ -25,18 +25,18 @@
|
|
|
25
25
|
"@babel/code-frame": "8.0.0",
|
|
26
26
|
"@graphql-tools/merge": "9.2.3",
|
|
27
27
|
"@graphql-tools/schema": "10.1.0",
|
|
28
|
-
"@webiny/api": "6.6.0-alpha.
|
|
29
|
-
"@webiny/api-core": "6.6.0-alpha.
|
|
30
|
-
"@webiny/api-core-testing": "6.6.0-alpha.
|
|
31
|
-
"@webiny/api-graphql": "6.6.0-alpha.
|
|
28
|
+
"@webiny/api": "6.6.0-alpha.3",
|
|
29
|
+
"@webiny/api-core": "6.6.0-alpha.3",
|
|
30
|
+
"@webiny/api-core-testing": "6.6.0-alpha.3",
|
|
31
|
+
"@webiny/api-graphql": "6.6.0-alpha.3",
|
|
32
32
|
"@webiny/di": "1.1.0",
|
|
33
|
-
"@webiny/error": "6.6.0-alpha.
|
|
34
|
-
"@webiny/event-handler-core": "6.6.0-alpha.
|
|
35
|
-
"@webiny/feature": "6.6.0-alpha.
|
|
36
|
-
"@webiny/handler": "6.6.0-alpha.
|
|
37
|
-
"@webiny/plugins": "6.6.0-alpha.
|
|
38
|
-
"@webiny/utils": "6.6.0-alpha.
|
|
39
|
-
"@webiny/validation": "6.6.0-alpha.
|
|
33
|
+
"@webiny/error": "6.6.0-alpha.3",
|
|
34
|
+
"@webiny/event-handler-core": "6.6.0-alpha.3",
|
|
35
|
+
"@webiny/feature": "6.6.0-alpha.3",
|
|
36
|
+
"@webiny/handler": "6.6.0-alpha.3",
|
|
37
|
+
"@webiny/plugins": "6.6.0-alpha.3",
|
|
38
|
+
"@webiny/utils": "6.6.0-alpha.3",
|
|
39
|
+
"@webiny/validation": "6.6.0-alpha.3",
|
|
40
40
|
"dot-prop-immutable": "2.1.1",
|
|
41
41
|
"graphql": "16.14.2",
|
|
42
42
|
"graphql-tag": "2.12.7",
|
|
@@ -49,10 +49,10 @@
|
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"@types/pluralize": "0.0.33",
|
|
52
|
-
"@webiny/build-tools": "6.6.0-alpha.
|
|
53
|
-
"@webiny/db-dynamodb": "6.6.0-alpha.
|
|
54
|
-
"@webiny/sdk": "6.6.0-alpha.
|
|
55
|
-
"@webiny/wcp": "6.6.0-alpha.
|
|
52
|
+
"@webiny/build-tools": "6.6.0-alpha.3",
|
|
53
|
+
"@webiny/db-dynamodb": "6.6.0-alpha.3",
|
|
54
|
+
"@webiny/sdk": "6.6.0-alpha.3",
|
|
55
|
+
"@webiny/wcp": "6.6.0-alpha.3",
|
|
56
56
|
"graphql": "16.14.2",
|
|
57
57
|
"oxfmt": "0.64.0",
|
|
58
58
|
"rimraf": "6.1.3",
|