Skip to content

Feat/mcp build #174

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: mcp
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .cspell/project-words.txt
Original file line number Diff line number Diff line change
@@ -45,6 +45,7 @@ Macbook
MCPHTTP
minilm
Mixtral
modelcontextprotocol
modelinfo
multiservice
nanos
10 changes: 10 additions & 0 deletions src/ai-sdk-provider/provider.ts
Original file line number Diff line number Diff line change
@@ -318,6 +318,16 @@ function convertToAxChatPrompt(
break
}

case 'reasoning': {
// Reasoning parts are ignored in the message conversion
break
}

case 'redacted-reasoning': {
// Redacted reasoning parts are ignored in the message conversion
break
}

default: {
const _exhaustiveCheck = part
throw new Error(`Unsupported part: ${_exhaustiveCheck}`)
15 changes: 13 additions & 2 deletions src/ax/funcs/code.ts
Original file line number Diff line number Diff line change
@@ -80,8 +80,19 @@ export class AxJSInterpreter {
required: ['code'],
},

func: ({ code }: Readonly<{ code: string }>) =>
this.codeInterpreterJavascript(code),
func: async (args?: unknown, options?) => {
// Validate args
if (!args || typeof args !== 'object') {
throw new Error('Invalid arguments: expected object with code property')
}

const { code } = args as { code: string }
if (typeof code !== 'string') {
throw new Error('Code must be a string')
}

return this.codeInterpreterJavascript(code)
},
}
}
}
15 changes: 13 additions & 2 deletions src/ax/funcs/docker.ts
Original file line number Diff line number Diff line change
@@ -387,8 +387,19 @@ export class AxDockerSession {
required: ['command'],
},

func: async ({ command }: Readonly<{ command: string }>) =>
await this.executeCommand(command),
func: async (args?: unknown, options?) => {
// Validate args
if (!args || typeof args !== 'object') {
throw new Error('Invalid arguments: expected object with command property')
}

const { command } = args as { command: string }
if (typeof command !== 'string') {
throw new Error('Command must be a string')
}

return await this.executeCommand(command)
},
}
}
}
15 changes: 13 additions & 2 deletions src/ax/funcs/embed.ts
Original file line number Diff line number Diff line change
@@ -68,8 +68,19 @@ export class AxEmbeddingAdapter {
},
required: ['text'],
},
func: ({ text }: Readonly<{ text: string }>, options) =>
this.embedAdapter(text, options),
func: async (args?: unknown, options?) => {
// Validate args
if (!args || typeof args !== 'object') {
throw new Error('Invalid arguments: expected object with text property')
}

const { text } = args as { text: string }
if (typeof text !== 'string') {
throw new Error('Text must be a string')
}

return this.embedAdapter(text, options)
},
}
}
}
44 changes: 40 additions & 4 deletions src/ax/prompts/agent.ts
Original file line number Diff line number Diff line change
@@ -88,7 +88,7 @@ function processChildAgentFunction<IN extends AxGenIn>(
// add debug logging if enabled
processedFunction.func = async (childArgs, funcOptions) => {
const updatedChildArgs = {
...childArgs,
...(childArgs || {}),
...pick(parentValues, injectionKeys as (keyof IN)[]),
}

@@ -112,7 +112,11 @@ function processChildAgentFunction<IN extends AxGenIn>(
options.canConfigureSmartModelRouting
) {
processedFunction.parameters = addModelParameter(
processedFunction.parameters,
processedFunction.parameters || {
type: 'object',
properties: {},
required: []
},
modelList
)
}
@@ -172,7 +176,7 @@ export class AxAgent<IN extends AxGenIn, OUT extends AxGenOut = AxGenOut>

this.ai = ai
this.agents = agents
this.functions = functions
this.functions = this.initFunctions(functions)
this.disableSmartModelRouting = disableSmartModelRouting
this.excludeFieldsFromPassthrough = excludeFieldsFromPassthrough ?? []
this.debug = debug
@@ -250,9 +254,15 @@ export class AxAgent<IN extends AxGenIn, OUT extends AxGenOut = AxGenOut>

// Create a wrapper function that excludes the 'ai' parameter
const wrappedFunc: AxFunctionHandler = async (
valuesAndModel: IN & { model: string },
args?: unknown,
options?
): Promise<string> => {
// Type guard to ensure args is the expected type
if (!args || typeof args !== 'object') {
throw new Error('Invalid arguments: expected object')
}

const valuesAndModel = args as IN & { model: string }
const { model, ...values } = valuesAndModel

const ai = this.ai ?? options?.ai
@@ -403,6 +413,32 @@ export class AxAgent<IN extends AxGenIn, OUT extends AxGenOut = AxGenOut>
): boolean {
return options?.debug ?? this.debug ?? ai?.getOptions()?.debug ?? false
}

private initFunctions(
functions: AxInputFunctionType | undefined
): AxFunction[] | undefined {
if (!functions) return undefined

// Handle the two possible types:
// 1. Array of AxFunction objects
// 2. Array of objects with toFunction method
if (Array.isArray(functions)) {
// Check if the first item has a toFunction method
if (functions.length > 0 && functions[0] && 'toFunction' in functions[0]) {
// This is an array of objects with toFunction method
return (functions as { toFunction: () => AxFunction | AxFunction[] }[])
.flatMap(fn => {
const result = fn.toFunction()
return Array.isArray(result) ? result : [result]
})
} else {
// This is already an array of AxFunction objects
return functions as AxFunction[]
}
}

return []
}
}

function toCamelCase(inputString: string): string {