@agentic/core
Advanced tools
Comparing version 7.2.0 to 7.3.0
@@ -1,2 +0,2 @@ | ||
import { Jsonifiable, Simplify, SetOptional, SetRequired, JsonValue, JsonObject } from 'type-fest'; | ||
import { Jsonifiable, Simplify, SetOptional, JsonValue, JsonObject } from 'type-fest'; | ||
export { SetOptional, SetRequired, Simplify } from 'type-fest'; | ||
@@ -105,3 +105,3 @@ import { z, ZodType } from 'zod'; | ||
/** Possible roles for a message. */ | ||
type Role = 'system' | 'user' | 'assistant' | 'function' | 'tool'; | ||
type Role = 'system' | 'developer' | 'user' | 'assistant' | 'function' | 'tool'; | ||
namespace Call { | ||
@@ -137,2 +137,8 @@ /** | ||
}; | ||
/** Message with text content for the developer. */ | ||
type Developer = { | ||
role: 'developer'; | ||
content: string; | ||
name?: string; | ||
}; | ||
/** Message with text content from the user. */ | ||
@@ -192,2 +198,9 @@ type User = { | ||
}): Msg.System; | ||
/** Create a developer message. Cleans indentation and newlines by default. */ | ||
function developer(content: string, opts?: { | ||
/** Custom name for the message. */ | ||
name?: string; | ||
/** Whether to clean extra newlines and indentation. Defaults to true. */ | ||
cleanContent?: boolean; | ||
}): Msg.Developer; | ||
/** Create a user message. Cleans indentation and newlines by default. */ | ||
@@ -245,2 +258,4 @@ function user(content: string, opts?: { | ||
function isSystem(message: Msg): message is Msg.System; | ||
/** Check if a message is a developer message. */ | ||
function isDeveloper(message: Msg): message is Msg.Developer; | ||
/** Check if a message is a user message. */ | ||
@@ -262,2 +277,3 @@ function isUser(message: Msg): message is Msg.User; | ||
function narrow(message: Msg.System): Msg.System; | ||
function narrow(message: Msg.Developer): Msg.Developer; | ||
function narrow(message: Msg.User): Msg.User; | ||
@@ -495,47 +511,3 @@ function narrow(message: Msg.Assistant): Msg.Assistant; | ||
type AIChainParams<Result extends AIChainResult = string> = { | ||
/** Name of the chain */ | ||
name: string; | ||
/** Chat completions function */ | ||
chatFn: ChatFn; | ||
/** Description of the chain */ | ||
description?: string; | ||
/** Optional chat completion params */ | ||
params?: Simplify<Partial<Omit<ChatParams, 'tools' | 'functions'>>>; | ||
/** Optional tools */ | ||
tools?: AIFunctionLike[]; | ||
/** Optional response schema */ | ||
schema?: z.ZodType<Result> | Schema<Result>; | ||
/** | ||
* Whether or not the response schema should use OpenAI's structured output | ||
* generation. | ||
*/ | ||
strict?: boolean; | ||
/** Max number of LLM calls to allow */ | ||
maxCalls?: number; | ||
/** Max number of retries to allow */ | ||
maxRetries?: number; | ||
/** Max concurrency when invoking tool calls */ | ||
toolCallConcurrency?: number; | ||
/** Whether or not to inject the schema into the context */ | ||
injectSchemaIntoSystemMessage?: boolean; | ||
}; | ||
/** | ||
* Creates a chain of chat completion calls that can be invoked as a single | ||
* function. It is meant to simplify the process of resolving tool calls | ||
* and optionally adding validation to the final result. | ||
* | ||
* The returned function will invoke the `chatFn` up to `maxCalls` times, | ||
* resolving any tool calls to the included `functions` and retrying if | ||
* necessary up to `maxRetries`. | ||
* | ||
* The chain ends when a non-tool call is returned, and the final result can | ||
* optionally be validated against a Zod schema, which defaults to a `string`. | ||
* | ||
* To prevent possible infinite loops, the chain will throw an error if it | ||
* exceeds `maxCalls` (`maxCalls` is expected to be >= `maxRetries`). | ||
*/ | ||
declare function createAIChain<Result extends AIChainResult = string>({ name, description, chatFn, params, schema: rawSchema, tools, maxCalls, maxRetries, toolCallConcurrency, injectSchemaIntoSystemMessage, strict }: AIChainParams<Result>): AIChain<Result>; | ||
/** | ||
* Create a function meant to be used with OpenAI tool or function calling. | ||
@@ -593,7 +565,2 @@ * | ||
type ExtractObjectParams<Result extends AIChainResult = string> = Simplify<SetRequired<Omit<AIChainParams<Result>, 'tools' | 'toolCallConcurrency' | 'params'>, 'schema'> & { | ||
params: SetRequired<Partial<ChatParams>, 'messages'>; | ||
}>; | ||
declare function extractObject<Result extends AIChainResult = string>(args: ExtractObjectParams<Result>): Promise<Result>; | ||
/** | ||
@@ -722,2 +689,2 @@ * Parses a string which is expected to contain a structured JSON value. | ||
export { type AIChain, type AIChainParams, type AIChainResult, type AIFunction, type AIFunctionImpl, type AIFunctionLike, AIFunctionSet, type AIFunctionSpec, AIFunctionsProvider, type AIToolSpec, AbortError, type ChatFn, type ChatMessageContentPart, type ChatParams, type DeepNullable, EchoAITool, type ExtractObjectParams, type JSONSchema, type LegacyChatParams, type LegacyMsg, type MaybePromise, Msg, type Nullable, ParseError, type ParseFn, type PrivateAIFunctionMetadata, type RelaxedChatParams, type RelaxedJsonifiable, type ResponseFormatJSONSchema, RetryableError, type SafeParseFn, type SafeParseResult, type Schema, TimeoutError, aiFunction, asSchema, assert, augmentSystemMessageWithJsonSchema, cleanStringForModel, createAIChain, createAIFunction, createSchema, createSchemaFromZodSchema, echoAIFunction, extractJSONFromString, extractObject, getEnv, getErrorMessage, getShortDateString, isAIFunction, isSchema, isZodSchema, noop, omit, parseArrayOutput, parseBooleanOutput, parseNumberOutput, parseObjectOutput, parseStructuredOutput, pick, pruneEmpty, pruneEmptyDeep, pruneNullOrUndefined, pruneNullOrUndefinedDeep, pruneUndefined, safeParseStructuredOutput, sanitizeSearchParams, schemaSymbol, stringifyForModel, throttleKy, zodToJsonSchema }; | ||
export { type AIChain, type AIChainResult, type AIFunction, type AIFunctionImpl, type AIFunctionLike, AIFunctionSet, type AIFunctionSpec, AIFunctionsProvider, type AIToolSpec, AbortError, type ChatFn, type ChatMessageContentPart, type ChatParams, type DeepNullable, EchoAITool, type JSONSchema, type LegacyChatParams, type LegacyMsg, type MaybePromise, Msg, type Nullable, ParseError, type ParseFn, type PrivateAIFunctionMetadata, type RelaxedChatParams, type RelaxedJsonifiable, type ResponseFormatJSONSchema, RetryableError, type SafeParseFn, type SafeParseResult, type Schema, TimeoutError, aiFunction, asSchema, assert, augmentSystemMessageWithJsonSchema, cleanStringForModel, createAIFunction, createSchema, createSchemaFromZodSchema, echoAIFunction, extractJSONFromString, getEnv, getErrorMessage, getShortDateString, isAIFunction, isSchema, isZodSchema, noop, omit, parseArrayOutput, parseBooleanOutput, parseNumberOutput, parseObjectOutput, parseStructuredOutput, pick, pruneEmpty, pruneEmptyDeep, pruneNullOrUndefined, pruneNullOrUndefinedDeep, pruneUndefined, safeParseStructuredOutput, sanitizeSearchParams, schemaSymbol, stringifyForModel, throttleKy, zodToJsonSchema }; |
@@ -620,4 +620,35 @@ var __create = Object.create; | ||
// src/create-ai-chain.ts | ||
import pMap from "p-map"; | ||
// src/echo.ts | ||
import { z as z2 } from "zod"; | ||
var _echo_dec, _a, _init; | ||
var EchoAITool = class extends (_a = AIFunctionsProvider, _echo_dec = [aiFunction({ | ||
name: "echo", | ||
description: "Echoes the input.", | ||
inputSchema: z2.object({ | ||
query: z2.string().describe("input query to echo") | ||
}) | ||
})], _a) { | ||
constructor() { | ||
super(...arguments); | ||
__runInitializers(_init, 5, this); | ||
} | ||
async echo({ query }) { | ||
return query; | ||
} | ||
}; | ||
_init = __decoratorStart(_a); | ||
__decorateElement(_init, 1, "echo", _echo_dec, EchoAITool); | ||
__decoratorMetadata(_init, EchoAITool); | ||
var echoAIFunction = createAIFunction( | ||
{ | ||
name: "echo", | ||
description: "Echoes the input.", | ||
inputSchema: z2.object({ | ||
query: z2.string().describe("input query to echo") | ||
}) | ||
}, | ||
({ query }) => { | ||
return query; | ||
} | ||
); | ||
@@ -636,2 +667,11 @@ // src/message.ts | ||
Msg2.system = system; | ||
function developer(content, opts) { | ||
const { name, cleanContent = true } = opts ?? {}; | ||
return { | ||
role: "developer", | ||
content: cleanContent ? cleanStringForModel(content) : content, | ||
...name ? { name } : {} | ||
}; | ||
} | ||
Msg2.developer = developer; | ||
function user(content, opts) { | ||
@@ -721,2 +761,6 @@ const { name, cleanContent = true } = opts ?? {}; | ||
Msg2.isSystem = isSystem; | ||
function isDeveloper(message) { | ||
return message.role === "developer"; | ||
} | ||
Msg2.isDeveloper = isDeveloper; | ||
function isUser(message) { | ||
@@ -754,2 +798,5 @@ return message.role === "user"; | ||
} | ||
if (isDeveloper(message)) { | ||
return message; | ||
} | ||
if (isUser(message)) { | ||
@@ -834,177 +881,2 @@ return message; | ||
} | ||
// src/create-ai-chain.ts | ||
function createAIChain({ | ||
name, | ||
description, | ||
chatFn, | ||
params, | ||
schema: rawSchema, | ||
tools, | ||
maxCalls = 5, | ||
maxRetries = 2, | ||
toolCallConcurrency = 8, | ||
injectSchemaIntoSystemMessage = false, | ||
strict = false | ||
}) { | ||
const functionSet = new AIFunctionSet(tools); | ||
const schema = rawSchema ? asSchema(rawSchema, { strict }) : void 0; | ||
const defaultParams = schema && !functionSet.size ? { | ||
response_format: strict ? { | ||
type: "json_schema", | ||
json_schema: { | ||
name, | ||
description, | ||
strict, | ||
schema: schema.jsonSchema | ||
} | ||
} : { type: "json_object" } | ||
} : void 0; | ||
return async (chatParams) => { | ||
const { messages, ...modelParams } = typeof chatParams === "string" ? { | ||
...defaultParams, | ||
...params, | ||
messages: [...params?.messages ?? [], Msg.user(chatParams)] | ||
} : { | ||
...defaultParams, | ||
...params, | ||
...chatParams, | ||
messages: [ | ||
...params?.messages ?? [], | ||
...chatParams?.messages ?? [] | ||
] | ||
}; | ||
if (!messages.length) { | ||
throw new Error('AIChain error: "messages" is empty'); | ||
} | ||
if (schema && injectSchemaIntoSystemMessage) { | ||
const lastSystemMessageIndex = messages.findLastIndex(Msg.isSystem); | ||
const lastSystemMessageContent = messages[lastSystemMessageIndex]?.content; | ||
const systemMessage = augmentSystemMessageWithJsonSchema({ | ||
system: lastSystemMessageContent, | ||
schema: schema.jsonSchema | ||
}); | ||
if (lastSystemMessageIndex >= 0) { | ||
messages[lastSystemMessageIndex] = Msg.system(systemMessage); | ||
} else { | ||
messages.unshift(Msg.system(systemMessage)); | ||
} | ||
} | ||
let numCalls = 0; | ||
let numErrors = 0; | ||
do { | ||
++numCalls; | ||
const response = await chatFn({ | ||
...modelParams, | ||
messages, | ||
tools: functionSet.size ? functionSet.toolSpecs : void 0 | ||
}); | ||
const { message } = response; | ||
messages.push(message); | ||
try { | ||
if (Msg.isToolCall(message)) { | ||
if (!functionSet.size) { | ||
throw new AbortError("No functions provided to handle tool call"); | ||
} | ||
for (const toolCall of message.tool_calls) { | ||
const func = functionSet.get(toolCall.function.name); | ||
if (!func) { | ||
throw new Error( | ||
`No function found with name ${toolCall.function.name}` | ||
); | ||
} | ||
} | ||
await pMap( | ||
message.tool_calls, | ||
async (toolCall) => { | ||
const func = functionSet.get(toolCall.function.name); | ||
const result = await func(toolCall.function.arguments); | ||
const toolResult = Msg.toolResult(result, toolCall.id); | ||
messages.push(toolResult); | ||
}, | ||
{ | ||
concurrency: toolCallConcurrency | ||
} | ||
); | ||
} else if (Msg.isFuncCall(message)) { | ||
throw new AbortError( | ||
"Function calls are not supported; expected tool call" | ||
); | ||
} else if (Msg.isRefusal(message)) { | ||
throw new AbortError(`Model refusal: ${message.refusal}`); | ||
} else if (Msg.isAssistant(message)) { | ||
if (schema) { | ||
return schema.parse(message.content); | ||
} else { | ||
return message.content; | ||
} | ||
} | ||
} catch (err) { | ||
numErrors++; | ||
if (err instanceof AbortError) { | ||
throw err; | ||
} | ||
console.warn(`Chain "${name}" error:`, err.message); | ||
messages.push( | ||
Msg.user( | ||
`There was an error validating the response. Please check the error message and try again. | ||
Error: | ||
${getErrorMessage(err)}` | ||
) | ||
); | ||
if (numErrors > maxRetries) { | ||
throw new Error( | ||
`Chain ${name} failed after ${numErrors} errors: ${err.message}`, | ||
{ | ||
cause: err | ||
} | ||
); | ||
} | ||
} | ||
} while (numCalls < maxCalls); | ||
throw new Error( | ||
`Chain "${name}" aborted after reaching max ${maxCalls} calls` | ||
); | ||
}; | ||
} | ||
// src/echo.ts | ||
import { z as z2 } from "zod"; | ||
var _echo_dec, _a, _init; | ||
var EchoAITool = class extends (_a = AIFunctionsProvider, _echo_dec = [aiFunction({ | ||
name: "echo", | ||
description: "Echoes the input.", | ||
inputSchema: z2.object({ | ||
query: z2.string().describe("input query to echo") | ||
}) | ||
})], _a) { | ||
constructor() { | ||
super(...arguments); | ||
__runInitializers(_init, 5, this); | ||
} | ||
async echo({ query }) { | ||
return query; | ||
} | ||
}; | ||
_init = __decoratorStart(_a); | ||
__decorateElement(_init, 1, "echo", _echo_dec, EchoAITool); | ||
__decoratorMetadata(_init, EchoAITool); | ||
var echoAIFunction = createAIFunction( | ||
{ | ||
name: "echo", | ||
description: "Echoes the input.", | ||
inputSchema: z2.object({ | ||
query: z2.string().describe("input query to echo") | ||
}) | ||
}, | ||
({ query }) => { | ||
return query; | ||
} | ||
); | ||
// src/extract-object.ts | ||
function extractObject(args) { | ||
const chain = createAIChain(args); | ||
return chain(); | ||
} | ||
export { | ||
@@ -1024,3 +896,2 @@ AIFunctionSet, | ||
cleanStringForModel, | ||
createAIChain, | ||
createAIFunction, | ||
@@ -1032,3 +903,2 @@ createSchema, | ||
extractJSONFromString, | ||
extractObject, | ||
getEnv, | ||
@@ -1035,0 +905,0 @@ getErrorMessage, |
{ | ||
"name": "@agentic/core", | ||
"version": "7.2.0", | ||
"version": "7.3.0", | ||
"description": "Agentic AI utils which work with any LLM and TypeScript AI SDK.", | ||
@@ -29,7 +29,7 @@ "author": "Travis Fischer <travis@transitivebullsh.it>", | ||
"jsonrepair": "^3.9.0", | ||
"ky": "^1.7.2", | ||
"ky": "^1.7.5", | ||
"openai-zod-to-json-schema": "^1.0.3", | ||
"p-map": "^7.0.2", | ||
"p-throttle": "^6.2.0", | ||
"type-fest": "^4.26.1", | ||
"p-throttle": "^7.0.0", | ||
"type-fest": "^4.35.0", | ||
"zod-validation-error": "^3.4.0" | ||
@@ -36,0 +36,0 @@ }, |
Sorry, the diff of this file is not supported yet
116666
1580
+ Addedp-throttle@7.0.0(transitive)
- Removedp-throttle@6.2.0(transitive)
Updatedky@^1.7.5
Updatedp-throttle@^7.0.0
Updatedtype-fest@^4.35.0