@convex-dev/agent
Version:
A agent component for Convex.
315 lines • 10.9 kB
JavaScript
import { v, } from "convex/values";
import { vVectorDimension } from "./component/vector/tables.js";
// const deprecated = v.optional(v.any()) as unknown as VNull<unknown, "optional">;
export const vProviderOptions = v.record(v.string(), v.record(v.string(), v.any()));
const providerOptions = v.optional(vProviderOptions);
export const vProviderMetadata = vProviderOptions;
const providerMetadata = providerOptions;
export const vThreadStatus = v.union(v.literal("active"), v.literal("archived") // unused
);
export const vMessageStatus = v.union(v.literal("pending"), v.literal("success"), v.literal("failed"));
export const vRole = v.union(v.literal("system"), v.literal("user"), v.literal("assistant"), v.literal("tool"));
export const vTextPart = v.object({
type: v.literal("text"),
text: v.string(),
providerOptions,
});
export const vImagePart = v.object({
type: v.literal("image"),
image: v.union(v.string(), v.bytes()),
mimeType: v.optional(v.string()),
providerOptions,
});
export const vFilePart = v.object({
type: v.literal("file"),
data: v.union(v.string(), v.bytes()),
filename: v.optional(v.string()),
mimeType: v.string(),
providerOptions,
});
export const vUserContent = v.union(v.string(), v.array(v.union(vTextPart, vImagePart, vFilePart)));
export const vReasoningPart = v.object({
type: v.literal("reasoning"),
text: v.string(),
signature: v.optional(v.string()),
providerOptions,
});
export const vRedactedReasoningPart = v.object({
type: v.literal("redacted-reasoning"),
data: v.string(),
providerOptions,
});
export const vReasoningDetails = v.array(v.union(v.object({
type: v.literal("text"),
text: v.string(),
signature: v.optional(v.string()),
}), v.object({
type: v.literal("redacted"),
data: v.string(),
})));
export const vToolCallPart = v.object({
type: v.literal("tool-call"),
toolCallId: v.string(),
toolName: v.string(),
args: v.any(),
providerOptions,
});
export const vAssistantContent = v.union(v.string(), v.array(v.union(vTextPart, vFilePart, vReasoningPart, vRedactedReasoningPart, vToolCallPart)));
const vToolResultContent = v.array(v.union(v.object({
type: v.literal("text"),
text: v.string(),
}), v.object({
type: v.literal("image"),
data: v.string(),
mimeType: v.optional(v.string()),
})));
const vToolResultPart = v.object({
type: v.literal("tool-result"),
toolCallId: v.string(),
toolName: v.string(),
result: v.any(),
// This is only here b/c steps include it in toolResults
// Normal CoreMessage doesn't have this
args: v.optional(v.any()),
experimental_content: v.optional(vToolResultContent),
isError: v.optional(v.boolean()),
providerOptions,
});
export const vToolContent = v.array(vToolResultPart);
export const vContent = v.union(vUserContent, vAssistantContent, vToolContent);
export const vUserMessage = v.object({
role: v.literal("user"),
content: vUserContent,
providerOptions,
});
export const vAssistantMessage = v.object({
role: v.literal("assistant"),
content: vAssistantContent,
providerOptions,
});
export const vToolMessage = v.object({
role: v.literal("tool"),
content: vToolContent,
providerOptions,
});
export const vSystemMessage = v.object({
role: v.literal("system"),
content: v.string(),
providerOptions,
});
export const vMessage = v.union(vUserMessage, vAssistantMessage, vToolMessage, vSystemMessage);
export const vSource = v.object({
sourceType: v.literal("url"),
id: v.string(),
url: v.string(),
title: v.optional(v.string()),
providerOptions,
});
export const vRequest = v.object({
body: v.optional(v.any()),
// These are not usually present
headers: v.optional(v.record(v.string(), v.string())),
method: v.optional(v.string()),
url: v.optional(v.string()),
});
const vMessageWithFileAndId = v.object({
id: v.optional(v.string()),
message: vMessage,
fileId: v.optional(v.id("files")),
});
export const vResponse = v.object({
id: v.string(),
timestamp: v.number(),
modelId: v.string(),
headers: v.optional(v.record(v.string(), v.string())), // clear these?
messages: v.array(vMessageWithFileAndId),
body: v.optional(v.any()),
});
export const vResponseWithoutMessages = v.object({
id: v.string(),
timestamp: v.number(),
modelId: v.string(),
headers: v.optional(v.record(v.string(), v.string())), // clear these?
body: v.optional(v.any()),
});
export const vFinishReason = v.union(v.literal("stop"), v.literal("length"), v.literal("content-filter"), v.literal("tool-calls"), v.literal("error"), v.literal("other"), v.literal("unknown"));
export const vUsage = v.object({
promptTokens: v.number(),
completionTokens: v.number(),
totalTokens: v.number(),
});
export const vLanguageModelV1CallWarning = v.union(v.object({
type: v.literal("unsupported-setting"),
setting: v.string(),
details: v.optional(v.string()),
}), v.object({
type: v.literal("unsupported-tool"),
tool: v.any(),
details: v.optional(v.string()),
}), v.object({
type: v.literal("other"),
message: v.string(),
}));
export const vMessageWithMetadataInternal = v.object({
id: v.optional(v.string()), // external id, e.g. from Vercel AI SDK
message: vMessage,
text: v.optional(v.string()),
fileIds: v.optional(v.array(v.id("files"))),
// metadata
finishReason: v.optional(vFinishReason),
model: v.optional(v.string()),
provider: v.optional(v.string()),
providerMetadata,
sources: v.optional(v.array(vSource)),
reasoning: v.optional(v.string()),
reasoningDetails: v.optional(vReasoningDetails),
usage: v.optional(vUsage),
warnings: v.optional(v.array(vLanguageModelV1CallWarning)),
error: v.optional(v.string()),
});
export const vMessageWithMetadata = v.object({
...vMessageWithMetadataInternal.fields,
fileIds: v.optional(v.array(v.string())),
});
export const vMessageEmbeddings = v.object({
model: v.string(),
dimension: vVectorDimension,
vectors: v.array(v.union(v.array(v.number()), v.null())),
});
export const vObjectResult = v.object({
request: vRequest,
response: vResponseWithoutMessages,
finishReason: vFinishReason,
usage: v.optional(v.any()),
object: v.any(),
error: v.optional(v.string()),
warnings: v.optional(v.array(vLanguageModelV1CallWarning)),
providerMetadata,
});
export const vSearchOptions = v.object({
vector: v.optional(v.array(v.number())),
vectorModel: v.optional(v.string()),
text: v.optional(v.string()),
limit: v.number(),
vectorScoreThreshold: v.optional(v.number()),
messageRange: v.optional(v.object({ before: v.number(), after: v.number() })),
});
export const vContextOptionsSearchOptions = v.object({
limit: v.number(),
textSearch: v.optional(v.boolean()),
vectorSearch: v.optional(v.boolean()),
messageRange: v.optional(v.object({ before: v.number(), after: v.number() })),
});
export const vContextOptions = v.object({
excludeToolMessages: v.optional(v.boolean()),
recentMessages: v.optional(v.number()),
searchOptions: v.optional(vContextOptionsSearchOptions),
searchOtherThreads: v.optional(v.boolean()),
});
export const vStorageOptions = v.object({
saveMessages: v.optional(v.union(v.literal("all"), v.literal("none"), v.literal("promptAndOutput"))),
});
const vStorageOptionsIncludingDeprecated = v.object({
...vStorageOptions.fields,
saveAllInputMessages: v.optional(v.boolean()),
saveAnyInputMessages: v.optional(v.boolean()),
saveOutputMessages: v.optional(v.boolean()),
});
const vPromptFields = {
system: v.optional(v.string()),
prompt: v.optional(v.string()),
messages: v.optional(v.array(vMessage)),
promptMessageId: v.optional(v.string()),
};
export const vCallSettingsFields = {
maxTokens: v.optional(v.number()),
temperature: v.optional(v.number()),
topP: v.optional(v.number()),
topK: v.optional(v.number()),
presencePenalty: v.optional(v.number()),
frequencyPenalty: v.optional(v.number()),
seed: v.optional(v.number()),
maxRetries: v.optional(v.number()),
headers: v.optional(v.record(v.string(), v.string())),
};
const vCommonArgs = {
userId: v.optional(v.string()),
threadId: v.optional(v.string()),
contextOptions: v.optional(vContextOptions),
storageOptions: v.optional(vStorageOptionsIncludingDeprecated),
providerOptions,
...vCallSettingsFields,
...vPromptFields,
};
export const vTextArgs = v.object({
...vCommonArgs,
stream: v.optional(v.boolean()),
toolChoice: v.optional(v.union(v.literal("auto"), v.literal("none"), v.literal("required"), v.object({
type: v.literal("tool"),
toolName: v.string(),
}))),
maxSteps: v.optional(v.number()),
experimental_continueSteps: v.optional(v.boolean()),
});
export const vSafeObjectArgs = v.object(vCommonArgs);
export const vEmbeddingsWithMetadata = v.object({
vectors: v.array(v.union(v.array(v.number()), v.null())),
dimension: vVectorDimension,
model: v.string(),
});
export function vPaginationResult(itemValidator) {
return v.object({
page: v.array(itemValidator),
continueCursor: v.string(),
isDone: v.boolean(),
splitCursor: v.optional(v.union(v.string(), v.null())),
pageStatus: v.optional(v.union(v.literal("SplitRecommended"), v.literal("SplitRequired"), v.null())),
});
}
export const vTextStreamPart = v.union(v.object({
type: v.literal("text-delta"),
textDelta: v.string(),
}), v.object({
type: v.literal("reasoning"),
textDelta: v.string(),
}), v.object({
type: v.literal("source"),
source: vSource,
}), vToolCallPart, v.object({
type: v.literal("tool-call-streaming-start"),
toolCallId: v.string(),
toolName: v.string(),
}), v.object({
type: v.literal("tool-call-delta"),
toolCallId: v.string(),
toolName: v.string(),
argsTextDelta: v.string(),
}), vToolResultPart);
export const vStreamCursor = v.object({
streamId: v.string(),
cursor: v.number(),
});
export const vStreamArgs = v.optional(v.union(v.object({
kind: v.literal("list"),
}), v.object({
kind: v.literal("deltas"),
cursors: v.array(vStreamCursor),
})));
export const vStreamMessage = v.object({
streamId: v.string(),
order: v.number(),
stepOrder: v.number(),
// metadata
userId: v.optional(v.string()),
agentName: v.optional(v.string()),
model: v.optional(v.string()),
provider: v.optional(v.string()),
providerOptions: v.optional(vProviderOptions), // Sent to model
});
export const vStreamDelta = v.object({
streamId: v.string(),
start: v.number(), // inclusive
end: v.number(), // exclusive
parts: v.array(vTextStreamPart),
});
//# sourceMappingURL=validators.js.map