@red-hat-developer-hub/backstage-plugin-catalog-backend-module-ai-resource-agent 0.2.1 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,35 @@
1
1
  # @red-hat-developer-hub/backstage-plugin-catalog-backend-module-ai-resource-agent
2
2
 
3
+ ## 0.4.1
4
+
5
+ ### Patch Changes
6
+
7
+ - dbce029: Bump ai-integrations workspace to Backstage v1.54.0
8
+ - Updated dependencies [dbce029]
9
+ - @red-hat-developer-hub/backstage-plugin-catalog-model-ai-resource-agent@0.3.1
10
+
11
+ ## 0.4.0
12
+
13
+ ### Minor Changes
14
+
15
+ - 0c396f8: switch ai-model-server and ai-resource-agent from catalog model layer's addModelSource to addProcessor
16
+
17
+ ## 0.3.0
18
+
19
+ ### Minor Changes
20
+
21
+ - 6ddfd98: Add `AiResourceAgentProcessor` to validate agent-specific fields on
22
+ `kind: AiResource` entities with `spec.type: agent` at catalog ingestion.
23
+ Register the processor alongside the existing agent catalog model source.
24
+ - 6ddfd98: Make `spec.instructions` optional on agent AiResource entities so agents
25
+ with a baked-in default prompt can be registered without a catalog-side
26
+ system prompt.
27
+
28
+ ### Patch Changes
29
+
30
+ - Updated dependencies [6ddfd98]
31
+ - @red-hat-developer-hub/backstage-plugin-catalog-model-ai-resource-agent@0.3.0
32
+
3
33
  ## 0.2.1
4
34
 
5
35
  ### Patch Changes
package/README.md ADDED
@@ -0,0 +1,67 @@
1
+ # @red-hat-developer-hub/backstage-plugin-catalog-backend-module-ai-resource-agent
2
+
3
+ A Backstage catalog backend module that validates agent-shaped
4
+ `AiResource` entities at ingestion time.
5
+
6
+ Uses `catalogProcessingExtensionPoint.addProcessor()` so the catalog's
7
+ built-in kind processor (`BuiltinKindsEntityProcessor`) remains active
8
+ for standard kinds (User, Group, Component, etc.).
9
+
10
+ This package is intentionally separate from
11
+ `catalog-backend-module-ai-resource-extensions`, which owns shared RHDH
12
+ extensions such as `spec.scope` and OCI `source-location` checks.
13
+
14
+ ## What it registers
15
+
16
+ On init the module registers `AiResourceAgentProcessor`, which:
17
+
18
+ 1. Validates `kind: AiResource`, `spec.type: agent` entities via
19
+ `validateEntityKind`
20
+ 2. Validates agent-specific fields via `preProcessEntity`
21
+
22
+ ## Validation
23
+
24
+ ### `AiResourceAgentProcessor`
25
+
26
+ Runs only for `kind: AiResource`. When `spec.type` is `'agent'`, validates
27
+ agent-specific fields and collects all violations into a single error.
28
+ Non-agent AiResource entities (`skill`, `rule`, `model`, …) are unaffected.
29
+
30
+ | Field | Rule |
31
+ | ------------------------- | ------------------------------------------- |
32
+ | `spec.instructions` | Optional; must be a string if present |
33
+ | `spec.handoffs` | Optional; must be an array if present |
34
+ | `spec.tools` | Optional; must be an array if present |
35
+ | `spec.resetToolChoice` | Optional; must be a boolean if present |
36
+ | `spec.modelSettings` | Optional; must be a plain object if present |
37
+ | `spec.toolUseBehavior` | Optional; string or string array if present |
38
+ | `spec.outputSchema` | Optional; string or plain object if present |
39
+ | `spec.handoffDescription` | Optional; must be a string if present |
40
+ | `spec.model` | Optional; must be a string if present |
41
+
42
+ `handoffs` / `tools` accept opaque string arrays without entity-ref format
43
+ enforcement. Core entity fields such as `spec.owner` and `spec.lifecycle`
44
+ are not re-validated here.
45
+
46
+ Deeper schema typing (including array element types) is handled by the
47
+ companion `catalog-model-ai-resource-agent` package.
48
+
49
+ ## Related packages
50
+
51
+ | Package | Responsibility |
52
+ | --------------------------------------------------------- | -------------------------------------------------- |
53
+ | `catalog-model-ai-resource-agent` | Types, JSON schema, KindValidator |
54
+ | `catalog-backend-module-ai-resource-agent` (this package) | Agent kind validation + field-level processor |
55
+ | `catalog-backend-module-ai-resource-extensions` | RHDH `spec.scope` + OCI source-location validation |
56
+
57
+ ## Examples
58
+
59
+ See [`examples/ai-resource-agents.yaml`](../../examples/ai-resource-agents.yaml)
60
+ for router + specialist agent catalog entities.
61
+
62
+ ## Public API
63
+
64
+ | Export | Description |
65
+ | ---------------------------------------- | ------------------------------------------------------ |
66
+ | `catalogModuleAiResourceAgent` (default) | Backend module that registers the agent processor |
67
+ | `AiResourceAgentProcessor` | `CatalogProcessor` for agent-specific field validation |
@@ -0,0 +1,31 @@
1
+ 'use strict';
2
+
3
+ var backstagePluginCatalogModelAiResourceAgent = require('@red-hat-developer-hub/backstage-plugin-catalog-model-ai-resource-agent');
4
+ var collectAgentErrors = require('./collectAgentErrors.cjs.js');
5
+
6
+ class AiResourceAgentProcessor {
7
+ getProcessorName() {
8
+ return "AiResourceAgentProcessor";
9
+ }
10
+ async validateEntityKind(entity) {
11
+ if (entity.kind !== "AiResource" || entity.spec?.type !== "agent") {
12
+ return false;
13
+ }
14
+ return backstagePluginCatalogModelAiResourceAgent.agentAiResourceEntityV1alpha1Validator.check(entity);
15
+ }
16
+ async preProcessEntity(entity, _location, _emit) {
17
+ if (entity.kind !== "AiResource") {
18
+ return entity;
19
+ }
20
+ const errors = collectAgentErrors.collectAgentErrors(entity);
21
+ if (errors.length > 0) {
22
+ throw new Error(
23
+ `Validation failed for AiResource agent entity: ${errors.join("; ")}`
24
+ );
25
+ }
26
+ return entity;
27
+ }
28
+ }
29
+
30
+ exports.AiResourceAgentProcessor = AiResourceAgentProcessor;
31
+ //# sourceMappingURL=AiResourceAgentProcessor.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AiResourceAgentProcessor.cjs.js","sources":["../src/AiResourceAgentProcessor.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n CatalogProcessor,\n CatalogProcessorEmit,\n} from '@backstage/plugin-catalog-node';\nimport { Entity } from '@backstage/catalog-model';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\nimport { agentAiResourceEntityV1alpha1Validator } from '@red-hat-developer-hub/backstage-plugin-catalog-model-ai-resource-agent';\nimport { collectAgentErrors } from './collectAgentErrors';\n\n/**\n * A CatalogProcessor that validates agent-specific fields on\n * AiResource entities with `spec.type: 'agent'`.\n *\n * Implements `validateEntityKind` so the catalog's built-in kind\n * processor remains active for standard kinds. The previous\n * `addModelSource` approach caused the built-in processor to be\n * replaced entirely, breaking validation of User, Group, Component,\n * and other standard entity kinds.\n *\n * Also validates via `preProcessEntity`:\n * - `spec.instructions`: optional; must be a string if present\n * - `spec.handoffs` / `spec.tools`: must be arrays if present\n * - `spec.resetToolChoice`: must be boolean if present\n * - `spec.modelSettings`: must be plain object if present\n * - `spec.toolUseBehavior`: must be string or string array if present\n * - `spec.outputSchema`: must be string or object if present\n * - `spec.handoffDescription` / `spec.model`: must be strings if present\n *\n * Non-agent AiResource entities (skill, rule, model) are unaffected.\n * All constraint violations are collected and reported in a single\n * error rather than stopping at the first failure.\n *\n * @public\n */\nexport class AiResourceAgentProcessor implements CatalogProcessor {\n getProcessorName(): string {\n return 'AiResourceAgentProcessor';\n }\n\n async validateEntityKind(entity: Entity): Promise<boolean> {\n if (entity.kind !== 'AiResource' || entity.spec?.type !== 'agent') {\n return false;\n }\n return agentAiResourceEntityV1alpha1Validator.check(entity);\n }\n\n async preProcessEntity(\n entity: Entity,\n _location: LocationSpec,\n _emit: CatalogProcessorEmit,\n ): Promise<Entity> {\n if (entity.kind !== 'AiResource') {\n return entity;\n }\n\n const errors = collectAgentErrors(entity);\n\n if (errors.length > 0) {\n throw new Error(\n `Validation failed for AiResource agent entity: ${errors.join('; ')}`,\n );\n }\n\n return entity;\n }\n}\n"],"names":["agentAiResourceEntityV1alpha1Validator","collectAgentErrors"],"mappings":";;;;;AAkDO,MAAM,wBAAA,CAAqD;AAAA,EAChE,gBAAA,GAA2B;AACzB,IAAA,OAAO,0BAAA;AAAA,EACT;AAAA,EAEA,MAAM,mBAAmB,MAAA,EAAkC;AACzD,IAAA,IAAI,OAAO,IAAA,KAAS,YAAA,IAAgB,MAAA,CAAO,IAAA,EAAM,SAAS,OAAA,EAAS;AACjE,MAAA,OAAO,KAAA;AAAA,IACT;AACA,IAAA,OAAOA,iFAAA,CAAuC,MAAM,MAAM,CAAA;AAAA,EAC5D;AAAA,EAEA,MAAM,gBAAA,CACJ,MAAA,EACA,SAAA,EACA,KAAA,EACiB;AACjB,IAAA,IAAI,MAAA,CAAO,SAAS,YAAA,EAAc;AAChC,MAAA,OAAO,MAAA;AAAA,IACT;AAEA,IAAA,MAAM,MAAA,GAASC,sCAAmB,MAAM,CAAA;AAExC,IAAA,IAAI,MAAA,CAAO,SAAS,CAAA,EAAG;AACrB,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,+CAAA,EAAkD,MAAA,CAAO,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,OACrE;AAAA,IACF;AAEA,IAAA,OAAO,MAAA;AAAA,EACT;AACF;;;;"}
@@ -0,0 +1,81 @@
1
+ 'use strict';
2
+
3
+ function collectAgentErrors(entity) {
4
+ const spec = entity.spec;
5
+ if (spec?.type !== "agent") {
6
+ return [];
7
+ }
8
+ const errors = [];
9
+ if (spec.instructions !== void 0 && typeof spec.instructions !== "string") {
10
+ errors.push(
11
+ `spec.instructions must be a string; got ${typeLabel(spec.instructions)}`
12
+ );
13
+ }
14
+ if (spec.handoffs !== void 0 && !Array.isArray(spec.handoffs)) {
15
+ errors.push(
16
+ `spec.handoffs must be an array; got ${typeLabel(spec.handoffs)}`
17
+ );
18
+ }
19
+ if (spec.tools !== void 0 && !Array.isArray(spec.tools)) {
20
+ errors.push(`spec.tools must be an array; got ${typeLabel(spec.tools)}`);
21
+ }
22
+ if (spec.resetToolChoice !== void 0 && typeof spec.resetToolChoice !== "boolean") {
23
+ errors.push(
24
+ `spec.resetToolChoice must be a boolean; got ${typeLabel(
25
+ spec.resetToolChoice
26
+ )}`
27
+ );
28
+ }
29
+ if (spec.modelSettings !== void 0) {
30
+ if (typeof spec.modelSettings !== "object" || spec.modelSettings === null || Array.isArray(spec.modelSettings)) {
31
+ errors.push(
32
+ `spec.modelSettings must be an object; got ${typeLabel(
33
+ spec.modelSettings
34
+ )}`
35
+ );
36
+ }
37
+ }
38
+ if (spec.toolUseBehavior !== void 0) {
39
+ if (typeof spec.toolUseBehavior !== "string" && !Array.isArray(spec.toolUseBehavior)) {
40
+ errors.push(
41
+ `spec.toolUseBehavior must be a string or an array; got ${typeLabel(
42
+ spec.toolUseBehavior
43
+ )}`
44
+ );
45
+ }
46
+ }
47
+ if (spec.outputSchema !== void 0) {
48
+ const isString = typeof spec.outputSchema === "string";
49
+ const isObject = typeof spec.outputSchema === "object" && spec.outputSchema !== null && !Array.isArray(spec.outputSchema);
50
+ if (!isString && !isObject) {
51
+ errors.push(
52
+ `spec.outputSchema must be a string or an object; got ${typeLabel(
53
+ spec.outputSchema
54
+ )}`
55
+ );
56
+ }
57
+ }
58
+ if (spec.handoffDescription !== void 0 && typeof spec.handoffDescription !== "string") {
59
+ errors.push(
60
+ `spec.handoffDescription must be a string; got ${typeLabel(
61
+ spec.handoffDescription
62
+ )}`
63
+ );
64
+ }
65
+ if (spec.model !== void 0 && typeof spec.model !== "string") {
66
+ errors.push(`spec.model must be a string; got ${typeLabel(spec.model)}`);
67
+ }
68
+ return errors;
69
+ }
70
+ function typeLabel(value) {
71
+ if (value === null) {
72
+ return "null";
73
+ }
74
+ if (Array.isArray(value)) {
75
+ return "array";
76
+ }
77
+ return typeof value;
78
+ }
79
+
80
+ exports.collectAgentErrors = collectAgentErrors;
81
+ //# sourceMappingURL=collectAgentErrors.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collectAgentErrors.cjs.js","sources":["../src/collectAgentErrors.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Entity } from '@backstage/catalog-model';\n\n/**\n * Collects agent-specific validation errors for an AiResource entity\n * with `spec.type: 'agent'` without throwing. Returns an array of\n * error messages (empty if valid or if `spec.type` is not `'agent'`).\n *\n * Validates agent-specific fields only; does NOT re-validate core\n * entity fields such as `spec.owner` or `spec.lifecycle`.\n *\n * @internal\n */\nexport function collectAgentErrors(entity: Entity): string[] {\n const spec = entity.spec;\n if (spec?.type !== 'agent') {\n return [];\n }\n\n const errors: string[] = [];\n\n // Optional: spec.instructions — must be a string if present.\n // Omitted when the agent image/runtime already bakes in a default prompt.\n if (\n spec.instructions !== undefined &&\n typeof spec.instructions !== 'string'\n ) {\n errors.push(\n `spec.instructions must be a string; got ${typeLabel(spec.instructions)}`,\n );\n }\n\n // Optional: spec.handoffs — must be an array if present\n if (spec.handoffs !== undefined && !Array.isArray(spec.handoffs)) {\n errors.push(\n `spec.handoffs must be an array; got ${typeLabel(spec.handoffs)}`,\n );\n }\n\n // Optional: spec.tools — must be an array if present\n if (spec.tools !== undefined && !Array.isArray(spec.tools)) {\n errors.push(`spec.tools must be an array; got ${typeLabel(spec.tools)}`);\n }\n\n // Optional: spec.resetToolChoice — must be a boolean if present\n if (\n spec.resetToolChoice !== undefined &&\n typeof spec.resetToolChoice !== 'boolean'\n ) {\n errors.push(\n `spec.resetToolChoice must be a boolean; got ${typeLabel(\n spec.resetToolChoice,\n )}`,\n );\n }\n\n // Optional: spec.modelSettings — must be a plain object if present\n if (spec.modelSettings !== undefined) {\n if (\n typeof spec.modelSettings !== 'object' ||\n spec.modelSettings === null ||\n Array.isArray(spec.modelSettings)\n ) {\n errors.push(\n `spec.modelSettings must be an object; got ${typeLabel(\n spec.modelSettings,\n )}`,\n );\n }\n }\n\n // Optional: spec.toolUseBehavior — must be a string or string array\n if (spec.toolUseBehavior !== undefined) {\n if (\n typeof spec.toolUseBehavior !== 'string' &&\n !Array.isArray(spec.toolUseBehavior)\n ) {\n errors.push(\n `spec.toolUseBehavior must be a string or an array; got ${typeLabel(\n spec.toolUseBehavior,\n )}`,\n );\n }\n }\n\n // Optional: spec.outputSchema — must be a string or plain object\n if (spec.outputSchema !== undefined) {\n const isString = typeof spec.outputSchema === 'string';\n const isObject =\n typeof spec.outputSchema === 'object' &&\n spec.outputSchema !== null &&\n !Array.isArray(spec.outputSchema);\n if (!isString && !isObject) {\n errors.push(\n `spec.outputSchema must be a string or an object; got ${typeLabel(\n spec.outputSchema,\n )}`,\n );\n }\n }\n\n // Optional: spec.handoffDescription — must be a string if present\n if (\n spec.handoffDescription !== undefined &&\n typeof spec.handoffDescription !== 'string'\n ) {\n errors.push(\n `spec.handoffDescription must be a string; got ${typeLabel(\n spec.handoffDescription,\n )}`,\n );\n }\n\n // Optional: spec.model — must be a string if present\n if (spec.model !== undefined && typeof spec.model !== 'string') {\n errors.push(`spec.model must be a string; got ${typeLabel(spec.model)}`);\n }\n\n return errors;\n}\n\n/**\n * Returns a human-friendly type label for error messages.\n * Distinguishes arrays and null from plain \"object\".\n */\nfunction typeLabel(value: unknown): string {\n if (value === null) {\n return 'null';\n }\n if (Array.isArray(value)) {\n return 'array';\n }\n return typeof value;\n}\n"],"names":[],"mappings":"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"}
package/dist/index.cjs.js CHANGED
@@ -3,8 +3,10 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var module$1 = require('./module.cjs.js');
6
+ var AiResourceAgentProcessor = require('./AiResourceAgentProcessor.cjs.js');
6
7
 
7
8
 
8
9
 
9
10
  exports.default = module$1.catalogModuleAiResourceAgent;
11
+ exports.AiResourceAgentProcessor = AiResourceAgentProcessor.AiResourceAgentProcessor;
10
12
  //# sourceMappingURL=index.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;"}
1
+ {"version":3,"file":"index.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;"}
package/dist/index.d.ts CHANGED
@@ -1,14 +1,50 @@
1
1
  import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api';
2
+ import { CatalogProcessor, CatalogProcessorEmit } from '@backstage/plugin-catalog-node';
3
+ import { Entity } from '@backstage/catalog-model';
4
+ import { LocationSpec } from '@backstage/plugin-catalog-common';
2
5
 
3
6
  /**
4
7
  * Registers the agent specType for the AiResource kind in the catalog.
5
8
  *
6
- * Follows the upstream pattern established by
7
- * `@backstage/plugin-catalog-backend-module-ai-model` which registers
8
- * skill/rule via `catalogModelExtensionPoint.addModelSource`.
9
+ * Uses `addProcessor` so the catalog's built-in kind processor
10
+ * (`BuiltinKindsEntityProcessor`) remains active for standard kinds.
11
+ * The previous `addModelSource` approach caused the built-in processor
12
+ * to be replaced entirely, breaking validation of User, Group,
13
+ * Component, and other standard entity kinds.
9
14
  *
10
15
  * @public
11
16
  */
12
17
  declare const catalogModuleAiResourceAgent: _backstage_backend_plugin_api.BackendFeature;
13
18
 
14
- export { catalogModuleAiResourceAgent as default };
19
+ /**
20
+ * A CatalogProcessor that validates agent-specific fields on
21
+ * AiResource entities with `spec.type: 'agent'`.
22
+ *
23
+ * Implements `validateEntityKind` so the catalog's built-in kind
24
+ * processor remains active for standard kinds. The previous
25
+ * `addModelSource` approach caused the built-in processor to be
26
+ * replaced entirely, breaking validation of User, Group, Component,
27
+ * and other standard entity kinds.
28
+ *
29
+ * Also validates via `preProcessEntity`:
30
+ * - `spec.instructions`: optional; must be a string if present
31
+ * - `spec.handoffs` / `spec.tools`: must be arrays if present
32
+ * - `spec.resetToolChoice`: must be boolean if present
33
+ * - `spec.modelSettings`: must be plain object if present
34
+ * - `spec.toolUseBehavior`: must be string or string array if present
35
+ * - `spec.outputSchema`: must be string or object if present
36
+ * - `spec.handoffDescription` / `spec.model`: must be strings if present
37
+ *
38
+ * Non-agent AiResource entities (skill, rule, model) are unaffected.
39
+ * All constraint violations are collected and reported in a single
40
+ * error rather than stopping at the first failure.
41
+ *
42
+ * @public
43
+ */
44
+ declare class AiResourceAgentProcessor implements CatalogProcessor {
45
+ getProcessorName(): string;
46
+ validateEntityKind(entity: Entity): Promise<boolean>;
47
+ preProcessEntity(entity: Entity, _location: LocationSpec, _emit: CatalogProcessorEmit): Promise<Entity>;
48
+ }
49
+
50
+ export { AiResourceAgentProcessor, catalogModuleAiResourceAgent as default };
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  var backendPluginApi = require('@backstage/backend-plugin-api');
4
- var alpha = require('@backstage/plugin-catalog-node/alpha');
5
- var backstagePluginCatalogModelAiResourceAgent = require('@red-hat-developer-hub/backstage-plugin-catalog-model-ai-resource-agent');
4
+ var pluginCatalogNode = require('@backstage/plugin-catalog-node');
5
+ var AiResourceAgentProcessor = require('./AiResourceAgentProcessor.cjs.js');
6
6
 
7
7
  const catalogModuleAiResourceAgent = backendPluginApi.createBackendModule({
8
8
  pluginId: "catalog",
@@ -10,15 +10,10 @@ const catalogModuleAiResourceAgent = backendPluginApi.createBackendModule({
10
10
  register(reg) {
11
11
  reg.registerInit({
12
12
  deps: {
13
- model: alpha.catalogModelExtensionPoint
13
+ catalog: pluginCatalogNode.catalogProcessingExtensionPoint
14
14
  },
15
- async init({ model }) {
16
- const source = {
17
- async *read() {
18
- yield { data: [{ layer: backstagePluginCatalogModelAiResourceAgent.agentAiResourceEntityModel }] };
19
- }
20
- };
21
- model.addModelSource(source);
15
+ async init({ catalog }) {
16
+ catalog.addProcessor(new AiResourceAgentProcessor.AiResourceAgentProcessor());
22
17
  }
23
18
  });
24
19
  }
@@ -1 +1 @@
1
- {"version":3,"file":"module.cjs.js","sources":["../src/module.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createBackendModule } from '@backstage/backend-plugin-api';\nimport type { CatalogModelSource } from '@backstage/catalog-model/alpha';\nimport { catalogModelExtensionPoint } from '@backstage/plugin-catalog-node/alpha';\nimport { agentAiResourceEntityModel } from '@red-hat-developer-hub/backstage-plugin-catalog-model-ai-resource-agent';\n\n/**\n * Registers the agent specType for the AiResource kind in the catalog.\n *\n * Follows the upstream pattern established by\n * `@backstage/plugin-catalog-backend-module-ai-model` which registers\n * skill/rule via `catalogModelExtensionPoint.addModelSource`.\n *\n * @public\n */\nexport const catalogModuleAiResourceAgent = createBackendModule({\n pluginId: 'catalog',\n moduleId: 'ai-resource-agent',\n register(reg) {\n reg.registerInit({\n deps: {\n model: catalogModelExtensionPoint,\n },\n async init({ model }) {\n const source: CatalogModelSource = {\n async *read() {\n yield { data: [{ layer: agentAiResourceEntityModel }] };\n },\n };\n model.addModelSource(source);\n },\n });\n },\n});\n"],"names":["createBackendModule","catalogModelExtensionPoint","agentAiResourceEntityModel"],"mappings":";;;;;;AA8BO,MAAM,+BAA+BA,oCAAA,CAAoB;AAAA,EAC9D,QAAA,EAAU,SAAA;AAAA,EACV,QAAA,EAAU,mBAAA;AAAA,EACV,SAAS,GAAA,EAAK;AACZ,IAAA,GAAA,CAAI,YAAA,CAAa;AAAA,MACf,IAAA,EAAM;AAAA,QACJ,KAAA,EAAOC;AAAA,OACT;AAAA,MACA,MAAM,IAAA,CAAK,EAAE,KAAA,EAAM,EAAG;AACpB,QAAA,MAAM,MAAA,GAA6B;AAAA,UACjC,OAAO,IAAA,GAAO;AACZ,YAAA,MAAM,EAAE,IAAA,EAAM,CAAC,EAAE,KAAA,EAAOC,qEAAA,EAA4B,CAAA,EAAE;AAAA,UACxD;AAAA,SACF;AACA,QAAA,KAAA,CAAM,eAAe,MAAM,CAAA;AAAA,MAC7B;AAAA,KACD,CAAA;AAAA,EACH;AACF,CAAC;;;;"}
1
+ {"version":3,"file":"module.cjs.js","sources":["../src/module.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createBackendModule } from '@backstage/backend-plugin-api';\nimport { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node';\n\nimport { AiResourceAgentProcessor } from './AiResourceAgentProcessor';\n\n/**\n * Registers the agent specType for the AiResource kind in the catalog.\n *\n * Uses `addProcessor` so the catalog's built-in kind processor\n * (`BuiltinKindsEntityProcessor`) remains active for standard kinds.\n * The previous `addModelSource` approach caused the built-in processor\n * to be replaced entirely, breaking validation of User, Group,\n * Component, and other standard entity kinds.\n *\n * @public\n */\nexport const catalogModuleAiResourceAgent = createBackendModule({\n pluginId: 'catalog',\n moduleId: 'ai-resource-agent',\n register(reg) {\n reg.registerInit({\n deps: {\n catalog: catalogProcessingExtensionPoint,\n },\n async init({ catalog }) {\n catalog.addProcessor(new AiResourceAgentProcessor());\n },\n });\n },\n});\n"],"names":["createBackendModule","catalogProcessingExtensionPoint","AiResourceAgentProcessor"],"mappings":";;;;;;AAgCO,MAAM,+BAA+BA,oCAAA,CAAoB;AAAA,EAC9D,QAAA,EAAU,SAAA;AAAA,EACV,QAAA,EAAU,mBAAA;AAAA,EACV,SAAS,GAAA,EAAK;AACZ,IAAA,GAAA,CAAI,YAAA,CAAa;AAAA,MACf,IAAA,EAAM;AAAA,QACJ,OAAA,EAASC;AAAA,OACX;AAAA,MACA,MAAM,IAAA,CAAK,EAAE,OAAA,EAAQ,EAAG;AACtB,QAAA,OAAA,CAAQ,YAAA,CAAa,IAAIC,iDAAA,EAA0B,CAAA;AAAA,MACrD;AAAA,KACD,CAAA;AAAA,EACH;AACF,CAAC;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@red-hat-developer-hub/backstage-plugin-catalog-backend-module-ai-resource-agent",
3
- "version": "0.2.1",
3
+ "version": "0.4.1",
4
4
  "license": "Apache-2.0",
5
5
  "description": "The ai-resource-agent backend module for the catalog plugin. Registers the agent specType for AiResource entities.",
6
6
  "main": "dist/index.cjs.js",
@@ -33,13 +33,15 @@
33
33
  "postpack": "backstage-cli package postpack"
34
34
  },
35
35
  "dependencies": {
36
- "@backstage/backend-plugin-api": "^1.9.2",
37
- "@backstage/catalog-model": "^1.9.0",
38
- "@backstage/plugin-catalog-node": "^2.2.2",
39
- "@red-hat-developer-hub/backstage-plugin-catalog-model-ai-resource-agent": "^0.2.0"
36
+ "@backstage/backend-plugin-api": "^1.10.0",
37
+ "@backstage/catalog-model": "^1.10.0",
38
+ "@backstage/plugin-catalog-common": "^1.1.10",
39
+ "@backstage/plugin-catalog-node": "^2.2.4",
40
+ "@red-hat-developer-hub/backstage-plugin-catalog-model-ai-resource-agent": "^0.3.1"
40
41
  },
41
42
  "devDependencies": {
42
- "@backstage/cli": "^0.36.3"
43
+ "@backstage/backend-test-utils": "^1.11.6",
44
+ "@backstage/cli": "^0.36.5"
43
45
  },
44
46
  "files": [
45
47
  "dist"