From 04cde0549cc4f76b56e4bb817b499f76871f3811 Mon Sep 17 00:00:00 2001 From: Ingrid Fielker Date: Mon, 5 Jan 2026 19:08:04 -0500 Subject: [PATCH 1/4] feat(js/core): Dap Action updates --- js/core/src/dynamic-action-provider.ts | 48 +++++++++---------- js/core/tests/dynamic-action-provider_test.ts | 38 +++++++-------- js/testapps/mcp/src/index.ts | 8 ++-- 3 files changed, 44 insertions(+), 50 deletions(-) diff --git a/js/core/src/dynamic-action-provider.ts b/js/core/src/dynamic-action-provider.ts index fd251cfd01..9d3c611e07 100644 --- a/js/core/src/dynamic-action-provider.ts +++ b/js/core/src/dynamic-action-provider.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import type * as z from 'zod'; +import * as z from 'zod'; import { Action, ActionMetadata, defineAction } from './action.js'; import { GenkitError } from './error.js'; import { ActionMetadataRecord, ActionType, Registry } from './registry.js'; @@ -66,12 +66,17 @@ class SimpleCache { this.expiresAt = Date.now() + this.ttlMillis; if (!params?.skipTrace) { - // Also run the action - // This action actually does nothing, with the important side - // effect of logging its input and output (which are the same). - // It does not change what we return, it just makes - // the content of the DAP visible in the DevUI and logging trace. - await this.dap.run(transformDapValue(this.value)); + // The action goes and gets the same data again, but it + // doesn't cache it. (It doesn't have access to the Cache and + // we are not allowed pass it in). + // We are not allowed to pass in either the DapValue we just got or + // the cache because the action input MUST be void + // and the output MUST be an array of ActionMetadata. + // And we can't construct the DapValue (which contains full Actions) + // from just the ActionMetadata. + // So unfortunately we need to fetch from the DAP twice, and there's + // a small chance that what gets traced is not what gets cached/used. + await this.dap.run(null); } return this.value; } catch (error) { @@ -107,8 +112,8 @@ export interface DynamicRegistry { } export type DynamicActionProviderAction = Action< - z.ZodTypeAny, - z.ZodTypeAny, + z.ZodAny, + z.ZodAny, z.ZodTypeAny > & DynamicRegistry & { @@ -142,12 +147,10 @@ export type DapMetadata = { [K in ActionType]?: ActionMetadata[]; }; -function transformDapValue(value: DapValue): DapMetadata { - const metadata: DapMetadata = {}; - for (const key of Object.keys(value)) { - metadata[key] = value[key].map((a) => { - return a.__action; - }); +function transformDapValue(value: DapValue): ActionMetadata[] { + const metadata: ActionMetadata[] = []; + for (const typeKey of Object.keys(value)) { + metadata.push(...value[typeKey].map((a) => a.__action)); } return metadata; } @@ -167,20 +170,13 @@ export function defineDynamicActionProvider( registry, { ...cfg, + inputSchema: z.any(), + outputSchema: z.any(), actionType: 'dynamic-action-provider', metadata: { ...(cfg.metadata || {}), type: 'dynamic-action-provider' }, }, - async (i, _options) => { - // The actions are retrieved, saved in a cache, formatted nicely and - // then passed in here so they can be automatically logged by the action - // call. This action is for logging only. We cannot run the actual - // 'getting the data from the DAP' here because the DAP data is required - // to resolve tools/resources etc. And there can be a LOT of tools etc. - // for a single generate. Which would log one DAP action per resolve, - // and unnecessarily overwhelm the Dev UI with DAP actions that all have - // the same information. So we only run this action (for the logging) when - // we go get new data from the DAP (so we can see what it returned). - return i; + async (_options) => { + return transformDapValue(await fn()); } ); implementDap(a as DynamicActionProviderAction, cfg, fn); diff --git a/js/core/tests/dynamic-action-provider_test.ts b/js/core/tests/dynamic-action-provider_test.ts index 396c189acf..40d979d926 100644 --- a/js/core/tests/dynamic-action-provider_test.ts +++ b/js/core/tests/dynamic-action-provider_test.ts @@ -58,7 +58,7 @@ describe('dynamic action provider', () => { const action = await dap.getAction('tool', 'tool1'); assert.strictEqual(action, tool1); - assert.strictEqual(callCount, 1); + assert.strictEqual(callCount, 2); }); it('lists action metadata', async () => { @@ -72,7 +72,7 @@ describe('dynamic action provider', () => { const metadata = await dap.listActionMetadata('tool', '*'); assert.deepStrictEqual(metadata, [tool1.__action, tool2.__action]); - assert.strictEqual(callCount, 1); + assert.strictEqual(callCount, 2); }); it('caches the actions', async () => { @@ -86,16 +86,16 @@ describe('dynamic action provider', () => { let action = await dap.getAction('tool', 'tool1'); assert.strictEqual(action, tool1); - assert.strictEqual(callCount, 1); + assert.strictEqual(callCount, 2); // This should be cached action = await dap.getAction('tool', 'tool2'); assert.strictEqual(action, tool2); - assert.strictEqual(callCount, 1); + assert.strictEqual(callCount, 2); const metadata = await dap.listActionMetadata('tool', '*'); assert.deepStrictEqual(metadata, [tool1.__action, tool2.__action]); - assert.strictEqual(callCount, 1); + assert.strictEqual(callCount, 2); }); it('invalidates the cache', async () => { @@ -108,12 +108,12 @@ describe('dynamic action provider', () => { }); await dap.getAction('tool', 'tool1'); - assert.strictEqual(callCount, 1); + assert.strictEqual(callCount, 2); dap.invalidateCache(); await dap.getAction('tool', 'tool2'); - assert.strictEqual(callCount, 2); + assert.strictEqual(callCount, 4); }); it('respects cache ttl', async () => { @@ -130,12 +130,12 @@ describe('dynamic action provider', () => { ); await dap.getAction('tool', 'tool1'); - assert.strictEqual(callCount, 1); + assert.strictEqual(callCount, 2); await setTimeout(20); await dap.getAction('tool', 'tool2'); - assert.strictEqual(callCount, 2); + assert.strictEqual(callCount, 4); }); it('lists actions with prefix', async () => { @@ -154,7 +154,7 @@ describe('dynamic action provider', () => { const metadata = await dap.listActionMetadata('tool', 'tool*'); assert.deepStrictEqual(metadata, [tool1.__action, tool2.__action]); - assert.strictEqual(callCount, 1); + assert.strictEqual(callCount, 2); }); it('lists actions with exact match', async () => { @@ -168,7 +168,7 @@ describe('dynamic action provider', () => { const metadata = await dap.listActionMetadata('tool', 'tool1'); assert.deepStrictEqual(metadata, [tool1.__action]); - assert.strictEqual(callCount, 1); + assert.strictEqual(callCount, 2); }); it('gets action metadata record', async () => { @@ -207,7 +207,7 @@ describe('dynamic action provider', () => { assert.deepStrictEqual(metadata1, [tool1.__action, tool2.__action]); assert.deepStrictEqual(metadata2, [tool1.__action, tool2.__action]); - assert.strictEqual(callCount, 1); + assert.strictEqual(callCount, 2); }); it('handles fetch errors', async () => { @@ -227,7 +227,7 @@ describe('dynamic action provider', () => { const metadata = await dap.listActionMetadata('tool', '*'); assert.deepStrictEqual(metadata, [tool1.__action, tool2.__action]); - assert.strictEqual(callCount, 2); + assert.strictEqual(callCount, 3); }); it('runs the action with transformed metadata when fetching', async () => { @@ -237,18 +237,16 @@ describe('dynamic action provider', () => { }; }); - let runInput: any; + let runResult: any; const originalRun = dap.run.bind(dap); dap.run = async (input, options) => { - runInput = input; - return originalRun(input, options); + runResult = await originalRun(input, options); + return runResult; }; await dap.__cache.getOrFetch(); - assert.deepStrictEqual(runInput, { - tool: [tool1.__action, tool2.__action], - }); + assert.deepStrictEqual(runResult.result, [tool1.__action, tool2.__action]); }); it('skips trace when requested', async () => { @@ -275,7 +273,7 @@ describe('dynamic action provider', () => { await dap.__cache.getOrFetch(); assert.strictEqual(runCalled, true); - assert.strictEqual(callCount, 2); + assert.strictEqual(callCount, 3); }); it('identifies dynamic action providers', async () => { diff --git a/js/testapps/mcp/src/index.ts b/js/testapps/mcp/src/index.ts index e4d19223c8..18c5f8cbeb 100644 --- a/js/testapps/mcp/src/index.ts +++ b/js/testapps/mcp/src/index.ts @@ -102,7 +102,7 @@ ai.defineFlow('get-file', async (q) => { ai.defineFlow('dynamic-get-file', async (q) => { const { text } = await ai.generate({ prompt: `summarize contexts of hello-world.txt (in '${process.cwd()}/test-workspace')`, - tools: ['test-mcp-manager:tool/fs/read_file'], // Just this one tool + tools: ['test-mcp-manager:tool/fs/read_text_file'], // Just this one tool }); return text; @@ -126,7 +126,7 @@ ai.defineFlow('dynamic-disable-enable', async (q) => { // we change something with the mcpHost config. const { text: text1 } = await ai.generate({ prompt: `summarize contexts of hello-world.txt (in '${process.cwd()}/test-workspace')`, - tools: ['test-mcp-manager:tool/fs/read_file'], // Just this one tool + tools: ['test-mcp-manager:tool/fs/read_text_file'], // Just this one tool }); // Now disable fs to show that we invalidate the dap cache @@ -137,7 +137,7 @@ ai.defineFlow('dynamic-disable-enable', async (q) => { // after disabling the mcp client providing it. const { text } = await ai.generate({ prompt: `summarize contexts of hello-world.txt (in '${process.cwd()}/test-workspace')`, - tools: ['test-mcp-manager:tool/fs/read_file'], // Just this one tool + tools: ['test-mcp-manager:tool/fs/read_text_file'], // Just this one tool }); text2 = 'ERROR! This should have failed to find the tool but succeeded instead: ' + @@ -151,7 +151,7 @@ ai.defineFlow('dynamic-disable-enable', async (q) => { await mcpHost.reconnect('fs'); const { text: text3 } = await ai.generate({ prompt: `summarize contexts of hello-world.txt (in '${process.cwd()}/test-workspace')`, - tools: ['test-mcp-manager:tool/fs/read_file'], // Just this one tool + tools: ['test-mcp-manager:tool/fs/read_text_file'], // Just this one tool }); return ( 'Original:
' + From 6c4a5121bcc2314ef480d53bdc7c4e8485689e0f Mon Sep 17 00:00:00 2001 From: Ingrid Fielker Date: Tue, 6 Jan 2026 15:22:09 -0500 Subject: [PATCH 2/4] review changes --- js/core/src/dynamic-action-provider.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/js/core/src/dynamic-action-provider.ts b/js/core/src/dynamic-action-provider.ts index 9d3c611e07..a6f4c71010 100644 --- a/js/core/src/dynamic-action-provider.ts +++ b/js/core/src/dynamic-action-provider.ts @@ -76,7 +76,7 @@ class SimpleCache { // from just the ActionMetadata. // So unfortunately we need to fetch from the DAP twice, and there's // a small chance that what gets traced is not what gets cached/used. - await this.dap.run(null); + await this.dap.run(); } return this.value; } catch (error) { @@ -148,11 +148,9 @@ export type DapMetadata = { }; function transformDapValue(value: DapValue): ActionMetadata[] { - const metadata: ActionMetadata[] = []; - for (const typeKey of Object.keys(value)) { - metadata.push(...value[typeKey].map((a) => a.__action)); - } - return metadata; + return Object.values(value).flatMap( + (actions) => actions?.map((a) => a.__action) || [] + ); } export function defineDynamicActionProvider( From 7d66df2e26277b5760ab38cf067771a69c5c79fb Mon Sep 17 00:00:00 2001 From: Ingrid Fielker Date: Tue, 6 Jan 2026 18:57:32 -0500 Subject: [PATCH 3/4] review changes --- js/core/src/dynamic-action-provider.ts | 59 +++++++++---------- js/core/tests/dynamic-action-provider_test.ts | 28 ++++----- 2 files changed, 41 insertions(+), 46 deletions(-) diff --git a/js/core/src/dynamic-action-provider.ts b/js/core/src/dynamic-action-provider.ts index a6f4c71010..6eb1bb0195 100644 --- a/js/core/src/dynamic-action-provider.ts +++ b/js/core/src/dynamic-action-provider.ts @@ -27,22 +27,26 @@ class SimpleCache { private value: DapValue | undefined; private expiresAt: number | undefined; private ttlMillis: number; - private dap: DynamicActionProviderAction; + private dap: DynamicActionProviderAction | undefined; private dapFn: DapFn; private fetchPromise: Promise | null = null; - constructor( - dap: DynamicActionProviderAction, - config: DapConfig, - dapFn: DapFn - ) { - this.dap = dap; + constructor(config: DapConfig, dapFn: DapFn) { this.dapFn = dapFn; this.ttlMillis = !config.cacheConfig?.ttlMillis ? 3 * 1000 : config.cacheConfig?.ttlMillis; } + setDap(dap: DynamicActionProviderAction) { + this.dap = dap; + } + + setValue(value: DapValue) { + this.value = value; + this.expiresAt = Date.now() + this.ttlMillis; + } + /** * Gets or fetches the DAP data. * @param skipTrace Don't run the action. i.e. don't create a trace log. @@ -61,22 +65,13 @@ class SimpleCache { if (!this.fetchPromise) { this.fetchPromise = (async () => { try { - // Get a new value - this.value = await this.dapFn(); // this returns the actual actions - this.expiresAt = Date.now() + this.ttlMillis; - - if (!params?.skipTrace) { - // The action goes and gets the same data again, but it - // doesn't cache it. (It doesn't have access to the Cache and - // we are not allowed pass it in). - // We are not allowed to pass in either the DapValue we just got or - // the cache because the action input MUST be void - // and the output MUST be an array of ActionMetadata. - // And we can't construct the DapValue (which contains full Actions) - // from just the ActionMetadata. - // So unfortunately we need to fetch from the DAP twice, and there's - // a small chance that what gets traced is not what gets cached/used. - await this.dap.run(); + if (this.dap && !params?.skipTrace) { + await this.dap.run(); // calls setValue + } else { + this.setValue(await this.dapFn()); + } + if (!this.value) { + throw new Error('value is undefined'); } return this.value; } catch (error) { @@ -164,29 +159,29 @@ export function defineDynamicActionProvider( } else { cfg = { ...config }; } + const cache = new SimpleCache(cfg, fn); const a = defineAction( registry, { ...cfg, - inputSchema: z.any(), + inputSchema: z.void(), outputSchema: z.any(), actionType: 'dynamic-action-provider', metadata: { ...(cfg.metadata || {}), type: 'dynamic-action-provider' }, }, async (_options) => { - return transformDapValue(await fn()); + const dapValue = await fn(); + cache.setValue(dapValue); + return transformDapValue(dapValue); } ); - implementDap(a as DynamicActionProviderAction, cfg, fn); + implementDap(a as DynamicActionProviderAction, cache); return a as DynamicActionProviderAction; } -function implementDap( - dap: DynamicActionProviderAction, - config: DapConfig, - dapFn: DapFn -) { - dap.__cache = new SimpleCache(dap, config, dapFn); +function implementDap(dap: DynamicActionProviderAction, cache: SimpleCache) { + cache.setDap(dap); + dap.__cache = cache; dap.invalidateCache = () => { dap.__cache.invalidate(); }; diff --git a/js/core/tests/dynamic-action-provider_test.ts b/js/core/tests/dynamic-action-provider_test.ts index 40d979d926..80ed0ce181 100644 --- a/js/core/tests/dynamic-action-provider_test.ts +++ b/js/core/tests/dynamic-action-provider_test.ts @@ -58,7 +58,7 @@ describe('dynamic action provider', () => { const action = await dap.getAction('tool', 'tool1'); assert.strictEqual(action, tool1); - assert.strictEqual(callCount, 2); + assert.strictEqual(callCount, 1); }); it('lists action metadata', async () => { @@ -72,7 +72,7 @@ describe('dynamic action provider', () => { const metadata = await dap.listActionMetadata('tool', '*'); assert.deepStrictEqual(metadata, [tool1.__action, tool2.__action]); - assert.strictEqual(callCount, 2); + assert.strictEqual(callCount, 1); }); it('caches the actions', async () => { @@ -86,16 +86,16 @@ describe('dynamic action provider', () => { let action = await dap.getAction('tool', 'tool1'); assert.strictEqual(action, tool1); - assert.strictEqual(callCount, 2); + assert.strictEqual(callCount, 1); // This should be cached action = await dap.getAction('tool', 'tool2'); assert.strictEqual(action, tool2); - assert.strictEqual(callCount, 2); + assert.strictEqual(callCount, 1); const metadata = await dap.listActionMetadata('tool', '*'); assert.deepStrictEqual(metadata, [tool1.__action, tool2.__action]); - assert.strictEqual(callCount, 2); + assert.strictEqual(callCount, 1); }); it('invalidates the cache', async () => { @@ -108,12 +108,12 @@ describe('dynamic action provider', () => { }); await dap.getAction('tool', 'tool1'); - assert.strictEqual(callCount, 2); + assert.strictEqual(callCount, 1); dap.invalidateCache(); await dap.getAction('tool', 'tool2'); - assert.strictEqual(callCount, 4); + assert.strictEqual(callCount, 2); }); it('respects cache ttl', async () => { @@ -130,12 +130,12 @@ describe('dynamic action provider', () => { ); await dap.getAction('tool', 'tool1'); - assert.strictEqual(callCount, 2); + assert.strictEqual(callCount, 1); await setTimeout(20); await dap.getAction('tool', 'tool2'); - assert.strictEqual(callCount, 4); + assert.strictEqual(callCount, 2); }); it('lists actions with prefix', async () => { @@ -154,7 +154,7 @@ describe('dynamic action provider', () => { const metadata = await dap.listActionMetadata('tool', 'tool*'); assert.deepStrictEqual(metadata, [tool1.__action, tool2.__action]); - assert.strictEqual(callCount, 2); + assert.strictEqual(callCount, 1); }); it('lists actions with exact match', async () => { @@ -168,7 +168,7 @@ describe('dynamic action provider', () => { const metadata = await dap.listActionMetadata('tool', 'tool1'); assert.deepStrictEqual(metadata, [tool1.__action]); - assert.strictEqual(callCount, 2); + assert.strictEqual(callCount, 1); }); it('gets action metadata record', async () => { @@ -207,7 +207,7 @@ describe('dynamic action provider', () => { assert.deepStrictEqual(metadata1, [tool1.__action, tool2.__action]); assert.deepStrictEqual(metadata2, [tool1.__action, tool2.__action]); - assert.strictEqual(callCount, 2); + assert.strictEqual(callCount, 1); }); it('handles fetch errors', async () => { @@ -227,7 +227,7 @@ describe('dynamic action provider', () => { const metadata = await dap.listActionMetadata('tool', '*'); assert.deepStrictEqual(metadata, [tool1.__action, tool2.__action]); - assert.strictEqual(callCount, 3); + assert.strictEqual(callCount, 2); }); it('runs the action with transformed metadata when fetching', async () => { @@ -273,7 +273,7 @@ describe('dynamic action provider', () => { await dap.__cache.getOrFetch(); assert.strictEqual(runCalled, true); - assert.strictEqual(callCount, 3); + assert.strictEqual(callCount, 2); }); it('identifies dynamic action providers', async () => { From e78bd185d616bf85ec463aac95ca02f375666857 Mon Sep 17 00:00:00 2001 From: Ingrid Fielker Date: Fri, 9 Jan 2026 14:45:10 -0500 Subject: [PATCH 4/4] add ActionMetadataSchema --- genkit-tools/common/src/types/action.ts | 37 +++++++++++++++++++++++++ js/core/src/action.ts | 35 ++++++++++++++++++++++- js/core/src/dynamic-action-provider.ts | 13 ++++++--- js/testapps/mcp/src/index.ts | 8 +++--- 4 files changed, 84 insertions(+), 9 deletions(-) diff --git a/genkit-tools/common/src/types/action.ts b/genkit-tools/common/src/types/action.ts index f75d9b370f..9db733df33 100644 --- a/genkit-tools/common/src/types/action.ts +++ b/genkit-tools/common/src/types/action.ts @@ -58,6 +58,43 @@ export const ActionSchema = z export type Action = z.infer; +export const ActionMetadataSchema = z + .object({ + actionType: z + .enum([ + 'custom', + 'dynamic-action-provider', + 'embedder', + 'evaluator', + 'executable-prompt', + 'flow', + 'indexer', + 'model', + 'background-model', + 'check-operation', + 'cancel-operation', + 'prompt', + 'reranker', + 'retriever', + 'tool', + 'tool.v2', + 'util', + 'resource', + ]) + .optional(), + name: z.string(), + description: z.string().optional(), + inputSchema: z.unknown().optional(), + inputJsonSchema: JSONSchema7Schema.optional(), + outputSchema: z.unknown().optional(), + outputJsonSchema: JSONSchema7Schema.optional(), + streamSchema: z.unknown().optional(), + metadata: z.record(z.string(), CustomAnySchema).optional(), + }) + .openapi('ActionMetadata'); + +export type ActionMetadata = z.infer; + export const RunActionResponseSchema = z.object({ result: z.unknown().optional(), telemetry: z diff --git a/js/core/src/action.ts b/js/core/src/action.ts index 27d746f761..e4a6209995 100644 --- a/js/core/src/action.ts +++ b/js/core/src/action.ts @@ -15,7 +15,7 @@ */ import type { JSONSchema7 } from 'json-schema'; -import type * as z from 'zod'; +import * as z from 'zod'; import { getAsyncContext } from './async-context.js'; import { lazy } from './async.js'; import { getContext, runWithContext, type ActionContext } from './context.js'; @@ -62,6 +62,39 @@ export interface ActionMetadata< metadata?: Record; } +export const ActionMetadataSchema = z.object({ + actionType: z + .enum([ + 'custom', + 'dynamic-action-provider', + 'embedder', + 'evaluator', + 'executable-prompt', + 'flow', + 'indexer', + 'model', + 'background-model', + 'check-operation', + 'cancel-operation', + 'prompt', + 'reranker', + 'retriever', + 'tool', + 'tool.v2', + 'util', + 'resource', + ]) + .optional(), + name: z.string(), + description: z.string().optional(), + inputSchema: z.unknown().optional(), + inputJsonSchema: z.object({}).optional(), + outputSchema: z.unknown().optional(), + outputJsonSchema: z.object({}).optional(), + streamSchema: z.unknown().optional(), + metadata: z.record(z.string(), z.any()).optional(), +}); + /** * Results of an action run. Includes telemetry. */ diff --git a/js/core/src/dynamic-action-provider.ts b/js/core/src/dynamic-action-provider.ts index 6eb1bb0195..23b975bc7c 100644 --- a/js/core/src/dynamic-action-provider.ts +++ b/js/core/src/dynamic-action-provider.ts @@ -15,7 +15,12 @@ */ import * as z from 'zod'; -import { Action, ActionMetadata, defineAction } from './action.js'; +import { + Action, + ActionMetadata, + ActionMetadataSchema, + defineAction, +} from './action.js'; import { GenkitError } from './error.js'; import { ActionMetadataRecord, ActionType, Registry } from './registry.js'; @@ -107,8 +112,8 @@ export interface DynamicRegistry { } export type DynamicActionProviderAction = Action< - z.ZodAny, - z.ZodAny, + z.ZodVoid, + z.ZodArray, z.ZodTypeAny > & DynamicRegistry & { @@ -165,7 +170,7 @@ export function defineDynamicActionProvider( { ...cfg, inputSchema: z.void(), - outputSchema: z.any(), + outputSchema: z.array(ActionMetadataSchema), actionType: 'dynamic-action-provider', metadata: { ...(cfg.metadata || {}), type: 'dynamic-action-provider' }, }, diff --git a/js/testapps/mcp/src/index.ts b/js/testapps/mcp/src/index.ts index 18c5f8cbeb..e4d19223c8 100644 --- a/js/testapps/mcp/src/index.ts +++ b/js/testapps/mcp/src/index.ts @@ -102,7 +102,7 @@ ai.defineFlow('get-file', async (q) => { ai.defineFlow('dynamic-get-file', async (q) => { const { text } = await ai.generate({ prompt: `summarize contexts of hello-world.txt (in '${process.cwd()}/test-workspace')`, - tools: ['test-mcp-manager:tool/fs/read_text_file'], // Just this one tool + tools: ['test-mcp-manager:tool/fs/read_file'], // Just this one tool }); return text; @@ -126,7 +126,7 @@ ai.defineFlow('dynamic-disable-enable', async (q) => { // we change something with the mcpHost config. const { text: text1 } = await ai.generate({ prompt: `summarize contexts of hello-world.txt (in '${process.cwd()}/test-workspace')`, - tools: ['test-mcp-manager:tool/fs/read_text_file'], // Just this one tool + tools: ['test-mcp-manager:tool/fs/read_file'], // Just this one tool }); // Now disable fs to show that we invalidate the dap cache @@ -137,7 +137,7 @@ ai.defineFlow('dynamic-disable-enable', async (q) => { // after disabling the mcp client providing it. const { text } = await ai.generate({ prompt: `summarize contexts of hello-world.txt (in '${process.cwd()}/test-workspace')`, - tools: ['test-mcp-manager:tool/fs/read_text_file'], // Just this one tool + tools: ['test-mcp-manager:tool/fs/read_file'], // Just this one tool }); text2 = 'ERROR! This should have failed to find the tool but succeeded instead: ' + @@ -151,7 +151,7 @@ ai.defineFlow('dynamic-disable-enable', async (q) => { await mcpHost.reconnect('fs'); const { text: text3 } = await ai.generate({ prompt: `summarize contexts of hello-world.txt (in '${process.cwd()}/test-workspace')`, - tools: ['test-mcp-manager:tool/fs/read_text_file'], // Just this one tool + tools: ['test-mcp-manager:tool/fs/read_file'], // Just this one tool }); return ( 'Original:
' +