UNPKG

@genkit-ai/ai

Version:

Genkit AI framework generative AI APIs.

1 lines 9.69 kB
{"version":3,"sources":["../src/resource.ts"],"sourcesContent":["/**\n * Copyright 2025 Google LLC\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 Action,\n ActionContext,\n detachedAction,\n DetachedAction,\n GenkitError,\n isAction,\n isDetachedAction,\n z,\n} from '@genkit-ai/core';\nimport { Registry } from '@genkit-ai/core/registry';\nimport uriTemplate from 'uri-templates';\nimport { PartSchema } from './model-types.js';\n\n/**\n * Options for defining a resource.\n */\nexport interface ResourceOptions {\n /**\n * Resource name. If not specified, uri or template will be used as name.\n */\n name?: string;\n\n /**\n * The URI of the resource. Can contain template variables.\n */\n uri?: string;\n\n /**\n * The URI template (ex. `my://resource/{id}`). See RFC6570 for specification.\n */\n template?: string;\n\n /**\n * A description of the resource.\n */\n description?: string;\n\n /**\n * Resource metadata.\n */\n metadata?: Record<string, any>;\n}\n\nexport const ResourceInputSchema = z.object({\n uri: z.string(),\n});\n\nexport type ResourceInput = z.infer<typeof ResourceInputSchema>;\n\nexport const ResourceOutputSchema = z.object({\n content: z.array(PartSchema),\n});\n\nexport type ResourceOutput = z.infer<typeof ResourceOutputSchema>;\n\n/**\n * A function that returns parts for a given resource.\n */\nexport type ResourceFn = (\n input: ResourceInput,\n ctx: ActionContext\n) => ResourceOutput | Promise<ResourceOutput>;\n\n/**\n * A resource action.\n */\nexport interface ResourceAction\n extends Action<typeof ResourceInputSchema, typeof ResourceOutputSchema> {\n matches(input: ResourceInput): boolean;\n}\n\n/**\n * Defines a resource.\n *\n * @param registry The registry to register the resource with.\n * @param opts The resource options.\n * @param fn The resource function.\n * @returns The resource action.\n */\nexport function defineResource(\n registry: Registry,\n opts: ResourceOptions,\n fn: ResourceFn\n): ResourceAction {\n const action = dynamicResource(opts, fn).attach(registry) as ResourceAction;\n // when defined via defineResource it's not dynamic.\n delete action.__action.metadata?.dynamic;\n action.matches = createMatcher(opts.uri, opts.template);\n registry.registerAction('resource', action);\n return action;\n}\n\n/**\n * A dynamic action with a `resource` type. Dynamic resources are detached actions -- not associated with any registry.\n */\nexport type DynamicResourceAction = DetachedAction<\n typeof ResourceInputSchema,\n typeof ResourceOutputSchema\n> & {\n __action: {\n metadata: {\n type: 'resource';\n };\n };\n matches(input: ResourceInput): boolean;\n};\n\n/**\n * Finds a matching resource in the registry. If not found returns undefined.\n */\nexport async function findMatchingResource(\n registry: Registry,\n input: ResourceInput\n): Promise<ResourceAction | undefined> {\n for (const actKeys of Object.keys(await registry.listResolvableActions())) {\n if (actKeys.startsWith('/resource/')) {\n const resource = (await registry.lookupAction(actKeys)) as ResourceAction;\n if (resource.matches(input)) {\n return resource;\n }\n }\n }\n return undefined;\n}\n\n/** Checks whether provided object is a dynamic resource. */\nexport function isDynamicResourceAction(\n t: unknown\n): t is DynamicResourceAction {\n return (\n (isDetachedAction(t) || isAction(t)) &&\n t.__action.metadata?.type === 'resource' &&\n !!t.__action.metadata?.dynamic\n );\n}\n\n/**\n * Defines a dynamic resource. Dynamic resources are just like regular resources but will not be\n * registered in the Genkit registry and can be defined dynamically at runtime.\n */\nexport function dynamicResource(\n opts: ResourceOptions,\n fn: ResourceFn\n): DynamicResourceAction {\n const uri = opts.uri ?? opts.template;\n if (!uri) {\n throw new GenkitError({\n status: 'INVALID_ARGUMENT',\n message: `must specify either url or template options`,\n });\n }\n const matcher = createMatcher(opts.uri, opts.template);\n\n const action = detachedAction(\n {\n actionType: 'resource',\n name: opts.name ?? uri,\n description: opts.description,\n inputSchema: ResourceInputSchema,\n outputSchema: ResourceOutputSchema,\n metadata: {\n resource: {\n uri: opts.uri,\n template: opts.template,\n },\n ...opts.metadata,\n type: 'resource',\n dynamic: true,\n },\n },\n async (input, ctx) => {\n const templateMatch = matcher(input);\n if (!templateMatch) {\n throw new GenkitError({\n status: 'INVALID_ARGUMENT',\n message: `input ${input} did not match template ${uri}`,\n });\n }\n const parts = await fn(input, ctx);\n parts.content.map((p) => {\n if (!p.metadata) {\n p.metadata = {};\n }\n if (p.metadata?.resource) {\n if (!(p.metadata as any).resource.parent) {\n (p.metadata as any).resource.parent = {\n uri: input.uri,\n };\n if (opts.template) {\n (p.metadata as any).resource.parent.template = opts.template;\n }\n }\n } else {\n (p.metadata as any).resource = {\n uri: input.uri,\n };\n if (opts.template) {\n (p.metadata as any).resource.template = opts.template;\n }\n }\n return p;\n });\n return parts;\n }\n ) as DynamicResourceAction;\n\n action.matches = matcher;\n\n return {\n __action: {\n ...action.__action,\n metadata: {\n ...action.__action.metadata,\n type: 'resource',\n },\n },\n attach(registry) {\n const bound = action.attach(registry) as ResourceAction;\n bound.matches = matcher;\n return bound;\n },\n matches: matcher,\n } as DynamicResourceAction;\n}\n\nfunction createMatcher(\n uriOpt: string | undefined,\n templateOpt: string | undefined\n): (input: ResourceInput) => boolean {\n // TODO: normalize resource URI during comparisons\n // foo://bar?baz=1&qux=2 and foo://bar?qux=2&baz=1 are equivalent URIs but would not match.\n if (uriOpt) {\n return (input: ResourceInput) => input.uri === uriOpt;\n }\n\n if (templateOpt) {\n const template = uriTemplate(templateOpt);\n return (input: ResourceInput) => template!.fromUri(input.uri) !== undefined;\n }\n\n throw new GenkitError({\n status: 'INVALID_ARGUMENT',\n message: 'must specify either url or template options',\n });\n}\n"],"mappings":"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","names":[]}