import { type StandardSchemaV1 } from './schema.js'; /** * 应用内 AI 能力(LLM 中继):走平台的 OpenAI 兼容端点 `POST {aiBaseUrl}/chat/completions`, * 用与 Data API 相同的应用密钥(sk-conv-…)鉴权,用量由平台按 api-key 计入应用所有者的 ChatU 点数。 * 只在服务端使用(Route Handler / Server Action);密钥不得暴露给浏览器。 * * 同一套密钥还能用:`/embeddings`(向量)、`document-intelligence/analyze`(OCR / 文档解析)、 * `/agents/{agent}/tasks`(平台智能体:图片生成 ai.generateImage 同步;视频生成 ai.generateVideo 异步提交 + GET tasks/{id} 轮询)。 */ /** 多模态消息片段:文本或图片(图片用 https URL 或 `data:image/...;base64,...`,见 toDataUrl) */ export type AiContentPart = { type: 'text'; text: string; } | { type: 'image_url'; image_url: { url: string; detail?: 'auto' | 'low' | 'high'; }; }; export interface AiMessage { role: 'system' | 'user' | 'assistant' | 'tool'; /** 字符串,或多模态片段数组(图片理解) */ content: string | AiContentPart[]; name?: string; /** role=tool 时必填:对应 assistant 消息里 toolCalls[].id */ toolCallId?: string; /** role=assistant 时可带:模型上一轮发起的工具调用(runTools 会自动回填) */ toolCalls?: AiToolCall[]; } /** 工具定义(OpenAI function calling);parameters 为 JSON Schema */ export interface AiTool { name: string; description?: string; parameters?: Record; /** 给了 execute,ai.runTools 会自动执行并把结果回填给模型;返回值会 JSON 序列化 */ execute?: (args: TArgs) => Promise | TResult; } /** 模型发起的一次工具调用;arguments 已解析(解析失败时为 null,rawArguments 保留原文) */ export interface AiToolCall { id: string; name: string; arguments: any; rawArguments: string; } export interface AiChatOptions { /** 模型 id;缺省用 CHATU_AI_MODEL / PRIMARY_MODEL,都没有则不传由服务端决定 */ model?: string; temperature?: number; maxTokens?: number; signal?: AbortSignal; /** 可供模型调用的工具;chat() 只返回 toolCalls 不执行,要自动执行用 runTools() */ tools?: AiTool[]; /** 'auto'(默认)| 'none' | 'required' | 指定某个工具名 */ toolChoice?: 'auto' | 'none' | 'required' | { name: string; }; /** 透传到请求体的其它 OpenAI 兼容字段(如 top_p、stop、response_format) */ extra?: Record; } /** ai.stream 的选项:流式不支持工具调用(SSE 增量里的 tool_calls 不解析),要用工具走 ai.runTools / ai.chat */ export type AiStreamOptions = Omit; export interface AiUsage { promptTokens?: number; completionTokens?: number; totalTokens?: number; } export interface AiChatResult { content: string; model?: string; usage?: AiUsage; /** 模型要求调用的工具(给了 tools 时才可能有);有它时 content 通常为空 */ toolCalls?: AiToolCall[]; /** 'stop' | 'tool_calls' | 'length' | … */ finishReason?: string; } /** ai.json 的选项:schema 用于约束模型输出,validate 用于把结果收成业务类型(可直接传 zod schema 或 parse 函数) */ export interface AiJsonOptions extends AiChatOptions { /** * JSON Schema:随提示词发给模型,并用 `response_format: json_schema` 硬约束(服务端/模型不支持时自动降级为 json_object)。 * 也可以直接传 Standard Schema(zod / valibot)——此时它同时充当 validate;zod 4 会自动转出 JSON Schema。 */ schema?: Record | StandardSchemaV1; /** 期望结构的示例,比 schema 更直观,两者可同时给 */ example?: unknown; /** 校验/转换;抛错即视为不合格,会带着错误信息重试(zod: v => Schema.parse(v),或直接传 zod schema) */ validate?: ((value: unknown) => T) | StandardSchemaV1; /** 结构不合格时的重试次数,默认 1 */ retries?: number; /** 是否要求严格模式(json_schema strict=true,要求 schema 每个对象都 additionalProperties:false);默认 false */ strict?: boolean; } export interface AiRunToolsOptions extends AiChatOptions { /** 带 execute 的工具列表(必填) */ tools: AiTool[]; /** 最多来回几轮工具调用,默认 5;超过则抛 AI_TOOL_ROUNDS_EXCEEDED */ maxRounds?: number; /** 每次工具执行后的回调(调试/进度展示) */ onToolCall?: (call: AiToolCall, result: unknown) => void; } export interface AiRunToolsResult extends AiChatResult { /** 完整的消息序列(含每轮 assistant/tool 消息),可原样存下来续聊 */ messages: AiMessage[]; /** 实际发生的工具调用及其结果 */ steps: Array<{ call: AiToolCall; result: unknown; }>; } /** 流式结果:可 `for await` 逐段取文本;迭代结束后 usage / content 可读 */ export interface AiStream extends AsyncIterable { /** 迭代完成后可用(服务端总是带 usage 块) */ readonly usage: AiUsage | undefined; /** 迭代完成后可用:拼好的完整文本 */ readonly content: string; /** 迭代完成后可用 */ readonly finishReason: string | undefined; } export interface AiEmbedOptions { /** embedding 模型;缺省 CHATU_AI_EMBED_MODEL → text-embedding-3-small */ model?: string; /** 输出维度(text-embedding-3-* 支持缩短,如 256/512);缺省用模型默认(3-small 为 1536) */ dimensions?: number; signal?: AbortSignal; } export interface AiEmbedManyResult { vectors: number[][]; model?: string; usage?: AiUsage; } /** OCR 附加能力,每项按页额外计费;默认全不开 */ export type AiOcrFeature = 'highResolution' | 'formulas' | 'fontStyling' | 'barcodes' | 'languages' | 'keyValuePairs' | 'queryFields' | 'figures' | 'searchablePdf'; export interface AiOcrOptions { /** 文件名(带扩展名,服务端据此判断类型):pdf / png / jpg / tiff / docx / xlsx / pptx / html */ filename: string; /** OCR 模型标识;留空用默认版面分析模型 */ model?: string; features?: AiOcrFeature[]; /** features 含 queryFields 时要提取的字段名,如 ['发票号码', '金额'] */ queryFields?: string[]; signal?: AbortSignal; } export interface AiOcrPage { pageNumber: number; width?: number; height?: number; unit?: string; angle?: number; lines: string[]; } export interface AiOcrResult { /** 整篇文档的 Markdown 文本(表格已转 Markdown 表格)——喂给 LLM 直接用这个 */ content: string; pages: AiOcrPage[]; /** 服务端原始 AnalyzeResult(表格/键值对/查询字段等细节都在这里) */ raw: any; } /** * 生图 agent。按张计费(点数因 agent 而异,Seedream4 最便宜、NanoBanana 系列约 2 倍), * 平台白名单外的 agent 会 404。 */ export type AiImageAgent = 'Seedream4' | 'Seedream5Lite' | 'Seedream45' | 'Seedream5Pro' | 'NanoBanana' | 'NanoBananaPro' | 'Image2' | (string & {}); export interface AiImageOptions { /** 生图提示词(中英文均可) */ prompt: string; /** 缺省 CHATU_AI_IMAGE_AGENT → Seedream4 */ agent?: AiImageAgent; /** 生成张数,默认 1;上限因 agent 而异(Seedream ≤15、NanoBanana ≤8、Image2 ≤4),每张都计费 */ count?: number; /** * 尺寸/比例:'1K' | '2K' | '4K'(分辨率档)、'16:9'(比例)或 '1024x1024'(像素)。 * 各 agent 支持的写法不同,SDK 按 agent 家族映射到对应参数:Seedream 三种都收;NanoBanana 收档位(Pro)与比例;Image2 只收 1024x1024 / 1536x1024 / 1024x1536。 */ size?: string; /** 参考图 https URL(图生图 / 风格参考);Image2 不支持 */ referenceImages?: string[]; /** 透传给 agent 的其它参数(如 Seedream 的 watermark / seed,Image2 的 quality),会覆盖 SDK 的映射 */ extra?: Record; signal?: AbortSignal; } export interface AiGeneratedImage { /** 图片 URL(平台存储,可直接展示或下载) */ url: string; thumbnailUrl?: string; index: number; /** 实际尺寸(如 '2048x2048'),部分 agent 才有 */ size?: string; /** 模型随图返回的文字(NanoBanana 系列可能有) */ text?: string; } export interface AiImageResult { images: AiGeneratedImage[]; agent: string; /** 平台任务 id */ taskId?: string; /** 实际使用的模型版本 */ model?: string; /** agent 原样返回的 metadata / usage(各 agent 字段不一致,计费点数等看这里) */ metadata?: any; usage?: any; } /** * 视频 agent。按秒 × 分辨率计费、非常贵(一条 5 秒 720p 视频约 10~40 万点,即 2~8 元), * 平台只开放异步:提交后拿 taskId 轮询,白名单外的 agent 会 404。 */ export type AiVideoAgent = 'Seedance2Fast' | 'Seedance2Mini' | 'Seedance2' | 'Seedance25' | 'Seedance15' | 'Sora2' | 'MiniMaxH3' | (string & {}); export interface AiVideoOptions { /** 视频描述提示词(中英文均可) */ prompt: string; /** 缺省 CHATU_AI_VIDEO_AGENT → Seedance2Fast */ agent?: AiVideoAgent; /** 时长(秒)。Seedance 2 系列 5|10、Seedance25 4~30、MiniMaxH3 4~15、Sora2 4|8|12;缺省 5(Sora2 4) */ duration?: number; /** 画幅比例 '16:9' | '9:16' | '1:1'(Seedance25 / MiniMaxH3 另支持 4:3 3:4 21:9 adaptive);Sora2 只分横竖屏 */ ratio?: string; /** 分辨率 '480p' | '720p'(Seedance25 到 1080p;MiniMaxH3 为 '768P' | '2K');Sora2 不收 */ resolution?: string; /** 首帧图 https URL(图生视频);Sora2 不支持 */ firstFrameUrl?: string; /** 尾帧图 https URL(需同时给首帧);Sora2 不支持 */ lastFrameUrl?: string; /** 参考图 https URL 列表(多模态参考);Sora2 不支持 */ referenceImages?: string[]; /** 是否生成音频(Seedance 系列,默认 true) */ generateAudio?: boolean; /** 透传给 agent 的其它参数(如 Seedance 的 seed / watermark / cameraFixed、MiniMaxH3 的 referenceVideoUrls),会覆盖 SDK 的映射 */ extra?: Record; /** * 默认 true:SDK 轮询到终态再返回 AiVideoResult(通常 1~5 分钟)。 * false:提交后立刻返回 AiVideoTask(taskId),由应用自己用 ai.getTask / ai.waitForTask 查——适合 serverless 路由有执行时限的场景。 */ wait?: boolean; /** 轮询间隔毫秒,默认 5000 */ pollIntervalMs?: number; /** 轮询总超时毫秒,默认 15 分钟;超时抛 AI_VIDEO_TIMEOUT(任务本身仍在服务端继续) */ timeoutMs?: number; /** 每次轮询回调(state + 服务端进度文案,如"排队中...") */ onProgress?: (task: AiAgentTask) => void; signal?: AbortSignal; } /** 平台 agent 任务(异步模式)的通用快照:/v1/agents/{agent}/tasks/{id} */ export interface AiAgentTask { id: string; agent: string; /** submitted | working | completed | failed | canceled | unknown */ state: string; /** 非终态时服务端给的进度文案 */ message?: string; /** 完成态:agent 原样输出(视频类为 { video: {url,...}, totalCredits, metadata }) */ output?: any; /** 失败态:错误原因 */ error?: string; } /** ai.generateVideo({ wait:false }) 返回的任务句柄 */ export interface AiVideoTask { taskId: string; agent: string; state: string; message?: string; } export interface AiVideoResult { video: { url: string; name?: string; size?: number; type?: string; }; /** 尾帧图(Seedance)或封面图(Sora2)URL,部分 agent 才有 */ thumbnailUrl?: string; agent: string; taskId: string; /** 本次实际扣费点数 */ totalCredits?: number; /** agent 原样返回的 metadata(模型、分辨率、时长、上游任务 id 等) */ metadata?: any; } /** 应用可调用的平台智能体(ai.agents);mode=async 的只能异步(提交后轮询) */ export interface AiAgentInfo { id: string; name?: string; description?: string; version?: string; iconUrl?: string; type?: string; mode?: 'sync' | 'async'; } export interface AiClient { /** 一次性对话,返回完整回复;content 可含图片片段(图片理解);带 tools 时可能返回 toolCalls */ chat(messages: AiMessage[] | string, opts?: AiChatOptions): Promise; /** * 结构化输出:让模型只回 JSON 并解析成对象;给了 validate / Standard Schema 则校验不过会带着错误重试。 * 用它替代"让模型回一段文本再自己正则抠字段"。 */ json(messages: AiMessage[] | string, opts?: AiJsonOptions): Promise; /** 流式对话,逐段产出文本增量;迭代结束后可读 usage / content。不支持 tools(传了会抛错) */ stream(messages: AiMessage[] | string, opts?: AiStreamOptions): AiStream; /** * 工具调用循环:模型要调工具 → 执行 tools[].execute → 结果回填 → 直到模型给出最终回复。 * 适合"查订单 / 查天气 / 算价格再回答"的智能体场景。 */ runTools(messages: AiMessage[] | string, opts: AiRunToolsOptions): Promise; /** 文本向量(单条),配合 vectorSearch 做语义检索 / 知识库 */ embed(text: string, opts?: AiEmbedOptions): Promise; /** 文本向量(批量,一次请求;建议每批 ≤ 100 条) */ embedMany(texts: string[], opts?: AiEmbedOptions): Promise; /** OCR / 文档解析:PDF、图片、Office 文档 → Markdown 文本 + 分页信息;按页计费 */ ocr(file: Uint8Array | ArrayBuffer | Blob, opts: AiOcrOptions): Promise; /** 可用模型 id 列表 */ models(): Promise; /** * 文生图 / 图生图:调用平台生图 agent,同步等待(通常 5~60 秒,多图高质量可到 2~3 分钟),返回图片 URL 列表。 * 按张计费到应用所有者;失败(含余额不足)抛 AppSdkError。 */ generateImage(opts: AiImageOptions): Promise; /** * 文生视频 / 图生视频:提交到平台视频 agent(异步),默认轮询到完成(通常 1~5 分钟)返回视频 URL; * wait:false 则立刻返回 taskId,再用 getTask / waitForTask 查。按秒计费到应用所有者、单价很高,务必先向用户确认。 */ generateVideo(opts: AiVideoOptions & { wait: false; }): Promise; generateVideo(opts: AiVideoOptions): Promise; /** 查询一个 agent 任务的当前状态(不阻塞) */ getTask(agent: string, taskId: string): Promise; /** 轮询一个 agent 任务直到终态;完成返回快照,失败 / 超时抛 AppSdkError */ waitForTask(agent: string, taskId: string, opts?: { pollIntervalMs?: number; timeoutMs?: number; onProgress?: (task: AiAgentTask) => void; signal?: AbortSignal; }): Promise; /** 应用可调用的平台智能体列表(图片类 mode=sync,视频类 mode=async) */ agents(): Promise; /** * 本应用这个月的 AI 用量与配额(技术方案 36)。点数就是实际扣的点数,与账单同源。 * 预览(dev)与线上(prod)分开统计;`quota` 是应用给自己设的月度上限。 */ usage(): Promise; /** 设置本应用的月度点数上限(null / 0 取消)。超限后 AI 调用抛 AI_QUOTA_EXCEEDED,不影响 db/kv/storage。 */ setQuota(monthlyPoints: number | null): Promise; } /** 一个环境(dev / prod)的 AI 用量 */ export interface AiUsageBucket { /** 调用次数(chat / json / stream / runTools / embed 各算一次) */ calls: number; inputTokens: number; outputTokens: number; /** 实际扣的点数 */ points: number; } export interface AiQuota { /** 月度点数上限;null = 没设上限 */ monthlyPoints: number | null; /** 本月已用点数(dev + prod 合计) */ used: number; /** 还剩多少点;没设上限时为 null */ remaining: number | null; } export interface AiUsageReport { /** 统计月份,如 '2026-09'(UTC) */ month: string; dev: AiUsageBucket; prod: AiUsageBucket; total: AiUsageBucket; quota: AiQuota; } /** 把二进制转成 `data:` URL,用于图片理解(ai.chat 的 image_url);bytes 可来自 File/Blob.arrayBuffer() */ export declare function toDataUrl(bytes: Uint8Array | ArrayBuffer, mime: string): string; /** 解析 OpenAI 风格 SSE,只产出 choices[0].delta.content(保留给外部/测试用) */ export declare function parseSseDeltas(body: ReadableStream): AsyncGenerator; /** 去掉 ```json 代码围栏、取出第一个完整的 JSON 值;模型经常"顺手"包一层 */ export declare function extractJson(text: string): unknown; /** 生图缺省 agent:白名单里最便宜的一档 */ export declare const DEFAULT_IMAGE_AGENT = "Seedream4"; /** * SDK 统一选项 → 各 agent 家族的入参。字段名以服务端 agent 的输入模型为准(camelCase,服务端大小写不敏感): * - Seedream*:prompt / size / maxImages / referenceImageUrls * - NanoBanana*:prompt / count / aspectRatio / imageSize(Pro) / referenceImageUrls * - Image2:prompt / count / size * 未知 agent 按 Seedream 口径组装;opts.extra 最后合并、可覆盖任何字段。 */ export declare function buildImageInput(agent: string, opts: AiImageOptions): Record; /** /v1/agents 任务响应 → AiImageResult;非完成态或无图抛错 */ export declare function parseImageTask(agent: string, task: any): AiImageResult; /** 视频缺省 agent:白名单里最便宜、最快的一档(480p/720p,5|10 秒) */ export declare const DEFAULT_VIDEO_AGENT = "Seedance2Fast"; /** 视频轮询默认:5 秒一次,最长 15 分钟 */ export declare const VIDEO_POLL_INTERVAL_MS = 5000; export declare const VIDEO_POLL_TIMEOUT_MS: number; /** * SDK 统一选项 → 各视频 agent 家族的入参。字段名以服务端 agent 的输入模型为准(camelCase): * - Seedance*:prompt / mode(t2v|i2v-first|i2v-both|multimodal) / imageUrl / lastFrameUrl / referenceImageUrls / ratio / resolution / duration / generateAudio * - MiniMaxH3:prompt / firstFrameUrl / lastFrameUrl / referenceImageUrls / ratio / resolution / duration * - Sora2:prompt / size(1280x720|720x1280,由 ratio 推) / seconds("4"|"8"|"12" 字符串) * 未知 agent 按 Seedance 口径组装;opts.extra 最后合并、可覆盖任何字段。 */ export declare function buildVideoInput(agent: string, opts: AiVideoOptions): Record; /** /v1/agents 任务响应(任意状态)→ AiAgentTask */ export declare function parseAgentTask(agent: string, task: any): AiAgentTask; /** 任务是否已到终态(不会再变) */ export declare function isTerminalTaskState(state: string): boolean; /** 完成态的 agent 任务 → AiVideoResult;非完成态或无视频抛错 */ export declare function parseVideoTask(agent: string, task: any): AiVideoResult; /** 按当前配置取 AI 客户端(惰性、缓存;configure() 后自动重建) */ export declare function getAi(): AiClient; /** 便捷单例:`import { ai } from '@chatu-ai/app-sdk'` */ export declare const ai: AiClient;