@@ -29,7 +29,8 @@ import { lazy } from '@genkit-ai/core/async';
2929import { logger } from '@genkit-ai/core/logging' ;
3030import type { Registry } from '@genkit-ai/core/registry' ;
3131import { toJsonSchema } from '@genkit-ai/core/schema' ;
32- import type { Message as DpMessage , PromptFunction } from 'dotprompt' ;
32+ import { SPAN_TYPE_ATTR , runInNewSpan } from '@genkit-ai/core/tracing' ;
33+ import { Message as DpMessage , PromptFunction } from 'dotprompt' ;
3334import { existsSync , readFileSync , readdirSync } from 'fs' ;
3435import { basename , join , resolve } from 'path' ;
3536import type { DocumentData } from './document.js' ;
@@ -252,72 +253,87 @@ function definePromptAsync<
252253 input : z . infer < I > ,
253254 renderOptions : PromptGenerateOptions < O , CustomOptions > | undefined
254255 ) : Promise < GenerateOptions > => {
255- const messages : MessageData [ ] = [ ] ;
256- renderOptions = { ...renderOptions } ; // make a copy, we will be trimming
257- const session = getCurrentSession ( registry ) ;
258- const resolvedOptions = await optionsPromise ;
259-
260- // order of these matters:
261- await renderSystemPrompt (
262- registry ,
263- session ,
264- input ,
265- messages ,
266- resolvedOptions ,
267- promptCache ,
268- renderOptions
269- ) ;
270- await renderMessages (
271- registry ,
272- session ,
273- input ,
274- messages ,
275- resolvedOptions ,
276- renderOptions ,
277- promptCache
278- ) ;
279- await renderUserPrompt (
256+ return await runInNewSpan (
280257 registry ,
281- session ,
282- input ,
283- messages ,
284- resolvedOptions ,
285- promptCache ,
286- renderOptions
287- ) ;
288-
289- let docs : DocumentData [ ] | undefined ;
290- if ( typeof resolvedOptions . docs === 'function' ) {
291- docs = await resolvedOptions . docs ( input , {
292- state : session ?. state ,
293- context : renderOptions ?. context || getContext ( registry ) || { } ,
294- } ) ;
295- } else {
296- docs = resolvedOptions . docs ;
297- }
298-
299- const opts : GenerateOptions = stripUndefinedProps ( {
300- model : resolvedOptions . model ,
301- maxTurns : resolvedOptions . maxTurns ,
302- messages,
303- docs,
304- tools : resolvedOptions . tools ,
305- returnToolRequests : resolvedOptions . returnToolRequests ,
306- toolChoice : resolvedOptions . toolChoice ,
307- context : resolvedOptions . context ,
308- output : resolvedOptions . output ,
309- use : resolvedOptions . use ,
310- ...stripUndefinedProps ( renderOptions ) ,
311- config : {
312- ...resolvedOptions ?. config ,
313- ...renderOptions ?. config ,
258+ {
259+ metadata : {
260+ name : 'render' ,
261+ input,
262+ } ,
263+ labels : {
264+ [ SPAN_TYPE_ATTR ] : 'promptTemplate' ,
265+ } ,
314266 } ,
315- } ) ;
316- // if config is empty and it was not explicitly passed in, we delete it, don't want {}
317- if ( Object . keys ( opts . config ) . length === 0 && ! renderOptions ?. config ) {
318- delete opts . config ;
319- }
320- return opts ;
267+ async ( metadata ) => {
268+ const messages : MessageData [ ] = [ ] ;
269+ renderOptions = { ...renderOptions } ; // make a copy, we will be trimming
270+ const session = getCurrentSession ( registry ) ;
271+ const resolvedOptions = await optionsPromise ;
272+
273+ // order of these matters:
274+ await renderSystemPrompt (
275+ registry ,
276+ session ,
277+ input ,
278+ messages ,
279+ resolvedOptions ,
280+ promptCache ,
281+ renderOptions
282+ ) ;
283+ await renderMessages (
284+ registry ,
285+ session ,
286+ input ,
287+ messages ,
288+ resolvedOptions ,
289+ renderOptions ,
290+ promptCache
291+ ) ;
292+ await renderUserPrompt (
293+ registry ,
294+ session ,
295+ input ,
296+ messages ,
297+ resolvedOptions ,
298+ promptCache ,
299+ renderOptions
300+ ) ;
301+
302+ let docs : DocumentData [ ] | undefined ;
303+ if ( typeof resolvedOptions . docs === 'function' ) {
304+ docs = await resolvedOptions . docs ( input , {
305+ state : session ?. state ,
306+ context : renderOptions ?. context || getContext ( registry ) || { } ,
307+ } ) ;
308+ } else {
309+ docs = resolvedOptions . docs ;
310+ }
311+
312+ const opts : GenerateOptions = stripUndefinedProps ( {
313+ model : resolvedOptions . model ,
314+ maxTurns : resolvedOptions . maxTurns ,
315+ messages,
316+ docs,
317+ tools : resolvedOptions . tools ,
318+ returnToolRequests : resolvedOptions . returnToolRequests ,
319+ toolChoice : resolvedOptions . toolChoice ,
320+ context : resolvedOptions . context ,
321+ output : resolvedOptions . output ,
322+ use : resolvedOptions . use ,
323+ ...stripUndefinedProps ( renderOptions ) ,
324+ config : {
325+ ...resolvedOptions ?. config ,
326+ ...renderOptions ?. config ,
327+ } ,
328+ } ) ;
329+ // if config is empty and it was not explicitly passed in, we delete it, don't want {}
330+ if ( Object . keys ( opts . config ) . length === 0 && ! renderOptions ?. config ) {
331+ delete opts . config ;
332+ }
333+ metadata . output = opts ;
334+ return opts ;
335+ }
336+ ) ;
321337 } ;
322338 const rendererActionConfig = lazy ( ( ) =>
323339 optionsPromise . then ( ( options : PromptConfig < I , O , CustomOptions > ) => {
@@ -432,9 +448,25 @@ function wrapInExecutablePrompt<
432448 input ?: I ,
433449 opts ?: PromptGenerateOptions < O , CustomOptions >
434450 ) : Promise < GenerateResponse < z . infer < O > > > => {
435- return generate ( registry , {
436- ...( await renderOptionsFn ( input , opts ) ) ,
437- } ) ;
451+ return await runInNewSpan (
452+ registry ,
453+ {
454+ metadata : {
455+ name : ( await rendererAction ) . __action . name ,
456+ input,
457+ } ,
458+ labels : {
459+ [ SPAN_TYPE_ATTR ] : 'dotprompt' ,
460+ } ,
461+ } ,
462+ async ( metadata ) => {
463+ const output = await generate ( registry , {
464+ ...( await renderOptionsFn ( input , opts ) ) ,
465+ } ) ;
466+ metadata . output = output ;
467+ return output ;
468+ }
469+ ) ;
438470 } ) as ExecutablePrompt < z . infer < I > , O , CustomOptions > ;
439471
440472 executablePrompt . render = async (
0 commit comments