@plumeai/plugin-sdk 0.0.0-stage → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/bin/plume-plugin.mjs +70 -0
- package/dist/client/styles/src/index.d.ts +123 -0
- package/dist/client/ui/src/avatar/AgentAvatar.d.ts +42 -0
- package/dist/client/ui/src/avatar/AvatarPile.d.ts +36 -0
- package/dist/client/ui/src/avatar/AvatarStack.d.ts +26 -0
- package/dist/client/ui/src/avatar/art.d.ts +32 -0
- package/dist/client/ui/src/fileIcon.d.ts +33 -0
- package/dist/client/ui/src/hooks/useCopied.d.ts +16 -0
- package/dist/client/ui/src/hooks/useLiveRefresh.d.ts +22 -0
- package/dist/client/ui/src/hooks/useNarrow.d.ts +16 -0
- package/dist/client/ui/src/i18n/context.d.ts +17 -0
- package/dist/client/ui/src/i18n/index.d.ts +2 -0
- package/dist/client/ui/src/i18n/list.d.ts +20 -0
- package/dist/client/ui/src/i18n/locales.d.ts +10 -0
- package/dist/client/ui/src/i18n/messages/en.d.ts +1418 -0
- package/dist/client/ui/src/i18n/messages/index.d.ts +6 -0
- package/dist/client/ui/src/i18n/messages/zh-CN.d.ts +1263 -0
- package/dist/client/ui/src/i18n/plural.d.ts +16 -0
- package/dist/client/ui/src/i18n/translate.d.ts +43 -0
- package/dist/client/ui/src/icons/index.d.ts +5 -0
- package/dist/client/ui/src/image/AnnotateCanvas.d.ts +29 -0
- package/dist/client/ui/src/image/AnnotateToolbar.d.ts +73 -0
- package/dist/client/ui/src/image/Annotator.d.ts +154 -0
- package/dist/client/ui/src/image/annotate.d.ts +227 -0
- package/dist/client/ui/src/image/paint.d.ts +35 -0
- package/dist/client/ui/src/image/screenshot-geometry.d.ts +112 -0
- package/dist/client/ui/src/image/useBarDrag.d.ts +31 -0
- package/dist/client/ui/src/image/useMovableBar.d.ts +26 -0
- package/dist/client/ui/src/image/useToolbarPlacement.d.ts +42 -0
- package/dist/client/ui/src/index.d.ts +140 -0
- package/dist/client/ui/src/inputs/ColorField.d.ts +9 -0
- package/dist/client/ui/src/inputs/ComposerToggle.d.ts +23 -0
- package/dist/client/ui/src/inputs/DateRangeField.d.ts +25 -0
- package/dist/client/ui/src/inputs/NativeField.d.ts +5 -0
- package/dist/client/ui/src/inputs/SearchField.d.ts +21 -0
- package/dist/client/ui/src/inputs/Segmented.d.ts +23 -0
- package/dist/client/ui/src/inputs/Select.d.ts +32 -0
- package/dist/client/ui/src/inputs/ShortcutRecorder.d.ts +8 -0
- package/dist/client/ui/src/inputs/Slider.d.ts +13 -0
- package/dist/client/ui/src/inputs/TextArea.d.ts +30 -0
- package/dist/client/ui/src/inputs/Toggle.d.ts +10 -0
- package/dist/client/ui/src/inputs/WorktreeToggle.d.ts +19 -0
- package/dist/client/ui/src/inputs/day-range.d.ts +57 -0
- package/dist/client/ui/src/inputs/pickers.d.ts +40 -0
- package/dist/client/ui/src/inputs/useFieldFade.d.ts +1 -0
- package/dist/client/ui/src/keyboard.d.ts +21 -0
- package/dist/client/ui/src/layout/ApprovalFrame.d.ts +33 -0
- package/dist/client/ui/src/layout/Collapse.d.ts +9 -0
- package/dist/client/ui/src/layout/CopyMark.d.ts +19 -0
- package/dist/client/ui/src/layout/Disclosure.d.ts +66 -0
- package/dist/client/ui/src/layout/ErrorBoundary.d.ts +26 -0
- package/dist/client/ui/src/layout/PageTopRow.d.ts +19 -0
- package/dist/client/ui/src/layout/PanelEmpty.d.ts +17 -0
- package/dist/client/ui/src/layout/ResizeHandle.d.ts +24 -0
- package/dist/client/ui/src/layout/RetainedViews.d.ts +32 -0
- package/dist/client/ui/src/layout/Settings.d.ts +41 -0
- package/dist/client/ui/src/layout/Splitter.d.ts +25 -0
- package/dist/client/ui/src/lib/agent-avatar.d.ts +58 -0
- package/dist/client/ui/src/lib/code/font-stack.d.ts +12 -0
- package/dist/client/ui/src/lib/code/themes.d.ts +35 -0
- package/dist/client/ui/src/lib/date-format.d.ts +8 -0
- package/dist/client/ui/src/lib/dispatches.d.ts +8 -0
- package/dist/client/ui/src/lib/hour-style.d.ts +13 -0
- package/dist/client/ui/src/lib/number-draft.d.ts +24 -0
- package/dist/client/ui/src/lib/relative-time.d.ts +18 -0
- package/dist/client/ui/src/lib/tiling.d.ts +89 -0
- package/dist/client/ui/src/lib/typing.d.ts +19 -0
- package/dist/client/ui/src/motion/RollWords.d.ts +26 -0
- package/dist/client/ui/src/motion/RollingText.d.ts +43 -0
- package/dist/client/ui/src/motion/TypedText.d.ts +9 -0
- package/dist/client/ui/src/motion/freeze.d.ts +22 -0
- package/dist/client/ui/src/motion/held.d.ts +17 -0
- package/dist/client/ui/src/motion/loaders.d.ts +65 -0
- package/dist/client/ui/src/motion/reduced.d.ts +13 -0
- package/dist/client/ui/src/motion/ticked.d.ts +24 -0
- package/dist/client/ui/src/motion/ticker.d.ts +31 -0
- package/dist/client/ui/src/motion/tokens.d.ts +29 -0
- package/dist/client/ui/src/motion/useNow.d.ts +6 -0
- package/dist/client/ui/src/overlay/Confirm.d.ts +96 -0
- package/dist/client/ui/src/overlay/ContextMenu.d.ts +40 -0
- package/dist/client/ui/src/overlay/Dialog.d.ts +60 -0
- package/dist/client/ui/src/overlay/Menu.d.ts +90 -0
- package/dist/client/ui/src/overlay/Overlay.d.ts +17 -0
- package/dist/client/ui/src/overlay/Popover.d.ts +127 -0
- package/dist/client/ui/src/overlay/Tooltip.d.ts +14 -0
- package/dist/client/ui/src/overlay/afterimage.d.ts +20 -0
- package/dist/client/ui/src/overlay/chrome-top.d.ts +8 -0
- package/dist/client/ui/src/overlay/hover-layers.d.ts +41 -0
- package/dist/client/ui/src/overlay/portal.d.ts +21 -0
- package/dist/client/ui/src/overlay/scrims.d.ts +20 -0
- package/dist/client/ui/src/overlay/tooltip-attribute.d.ts +62 -0
- package/dist/client/ui/src/primitives/Button.d.ts +64 -0
- package/dist/client/ui/src/primitives/Caret.d.ts +25 -0
- package/dist/client/ui/src/primitives/ChoiceMark.d.ts +12 -0
- package/dist/client/ui/src/primitives/ClosableTab.d.ts +23 -0
- package/dist/client/ui/src/primitives/CountUp.d.ts +21 -0
- package/dist/client/ui/src/primitives/GitHubMark.d.ts +12 -0
- package/dist/client/ui/src/primitives/IconButton.d.ts +55 -0
- package/dist/client/ui/src/primitives/MarkNumber.d.ts +12 -0
- package/dist/client/ui/src/primitives/RowDeleteButton.d.ts +6 -0
- package/dist/client/ui/src/primitives/Skeleton.d.ts +36 -0
- package/dist/client/ui/src/primitives/TabStrip.d.ts +29 -0
- package/dist/client/ui/src/primitives/Text.d.ts +341 -0
- package/dist/client/ui/src/primitives/TimeAgo.d.ts +13 -0
- package/dist/client/ui/src/primitives/useCountUp.d.ts +23 -0
- package/dist/client/ui/src/row/FlowRow.d.ts +31 -0
- package/dist/client/ui/src/row/HoverRow.d.ts +28 -0
- package/dist/client/ui/src/scroll/BackToLatest.d.ts +19 -0
- package/dist/client/ui/src/scroll/OverlayScrollbar.d.ts +9 -0
- package/dist/client/ui/src/scroll/ScrollText.d.ts +24 -0
- package/dist/client/ui/src/scroll/Scroller.d.ts +66 -0
- package/dist/client/ui/src/scroll/Sideways.d.ts +30 -0
- package/dist/client/ui/src/scroll/fade.d.ts +2 -0
- package/dist/client/ui/src/scroll/follow.d.ts +157 -0
- package/dist/client/ui/src/scroll/measure-batch.d.ts +13 -0
- package/dist/client/ui/src/scroll/memory.d.ts +22 -0
- package/dist/client/ui/src/scroll/signature.d.ts +24 -0
- package/dist/client/ui/src/scroll/useFollowBottom.d.ts +80 -0
- package/dist/client/ui/src/scroll/useSideways.d.ts +29 -0
- package/dist/contract/src/app.d.ts +16 -0
- package/dist/contract/src/changes.d.ts +50 -0
- package/dist/contract/src/diagnostics.d.ts +86 -0
- package/dist/contract/src/index.d.ts +18 -0
- package/dist/contract/src/plugin.d.ts +1391 -0
- package/dist/contract/src/resources.d.ts +79 -0
- package/dist/contract/src/service.d.ts +806 -0
- package/dist/contract/src/ui.d.ts +1039 -0
- package/dist/contract/src/usage.d.ts +102 -0
- package/dist/core/llm/ai/anthropic-messages-request.d.ts +82 -0
- package/dist/core/llm/ai/anthropic-messages.d.ts +43 -0
- package/dist/core/llm/ai/cache-routing.d.ts +53 -0
- package/dist/core/llm/ai/chat-delta.d.ts +107 -0
- package/dist/core/llm/ai/compat-key.d.ts +19 -0
- package/dist/core/llm/ai/endpoint.d.ts +57 -0
- package/dist/core/llm/ai/failure.d.ts +181 -0
- package/dist/core/llm/ai/index.d.ts +16 -0
- package/dist/core/llm/ai/openai-chat-completions-request.d.ts +49 -0
- package/dist/core/llm/ai/openai-chat-completions.d.ts +37 -0
- package/dist/core/llm/ai/openai-responses-request.d.ts +63 -0
- package/dist/core/llm/ai/openai-responses.d.ts +11 -0
- package/dist/core/llm/ai/prefix-fingerprint.d.ts +20 -0
- package/dist/core/llm/ai/reasoning-compat.d.ts +69 -0
- package/dist/core/llm/ai/request-params-compat.d.ts +39 -0
- package/dist/core/llm/ai/retry.d.ts +130 -0
- package/dist/core/llm/ai/sanitize-history.d.ts +23 -0
- package/dist/core/llm/ai/think-tag.d.ts +37 -0
- package/dist/core/llm/ai/thinking-options.d.ts +35 -0
- package/dist/core/llm/ai/tool-names.d.ts +17 -0
- package/dist/core/llm/ai/tool-pairing-compat.d.ts +53 -0
- package/dist/core/llm/ai/tool-result-images-compat.d.ts +24 -0
- package/dist/core/llm/ai/tool-schema.d.ts +20 -0
- package/dist/core/llm/ai/usage-fields.d.ts +30 -0
- package/dist/core/llm/ai/vendors/index.d.ts +20 -0
- package/dist/core/llm/ai/vendors/thinking.d.ts +39 -0
- package/dist/core/llm/ai/vendors/types.d.ts +47 -0
- package/dist/core/llm/config/image-models.d.ts +34 -0
- package/dist/core/llm/config/retry-policy.d.ts +35 -0
- package/dist/core/llm/images/chat-images.d.ts +11 -0
- package/dist/core/llm/images/dimensions.d.ts +15 -0
- package/dist/core/llm/images/generate.d.ts +15 -0
- package/dist/core/llm/images/openai-images.d.ts +11 -0
- package/dist/core/llm/images/quota.d.ts +9 -0
- package/dist/core/llm/images/shape.d.ts +44 -0
- package/dist/core/llm/images/types.d.ts +118 -0
- package/dist/core/llm/model-catalog-format.d.ts +50 -0
- package/dist/core/llm/model-catalog.d.ts +51 -0
- package/dist/core/llm/types/message.d.ts +450 -0
- package/dist/core/llm/types/provider.d.ts +169 -0
- package/dist/core/llm/types/tool.d.ts +23 -0
- package/dist/core/llm/types.d.ts +10 -0
- package/dist/core/llm/utils/pricing.d.ts +18 -0
- package/dist/core/llm/utils/record.d.ts +2 -0
- package/dist/core/llm/utils/sse.d.ts +69 -0
- package/dist/infra/rpc/src/endpoint.d.ts +36 -0
- package/dist/infra/rpc/src/index.d.ts +2 -0
- package/dist/infra/rpc/src/rpc.d.ts +54 -0
- package/dist/theme.css +336 -0
- package/dist/ui.d.ts +2 -0
- package/lib/build.mjs +143 -0
- package/lib/check.mjs +23 -0
- package/lib/dev.mjs +52 -0
- package/lib/icons.mjs +2 -0
- package/lib/init.mjs +109 -0
- package/lib/install.mjs +80 -0
- package/lib/link.mjs +44 -0
- package/lib/lint/i18n.mjs +149 -0
- package/lib/lint/imports.mjs +83 -0
- package/lib/lint/index.mjs +54 -0
- package/lib/lint/styles.mjs +160 -0
- package/lib/manifest.d.mts +9 -0
- package/lib/manifest.mjs +99 -0
- package/lib/targets.mjs +60 -0
- package/package.json +34 -4
- package/skill/SKILL.md +150 -0
- package/skill/references/components.md +2830 -0
- package/skill/references/logic.md +526 -0
- package/skill/references/style-i18n.md +70 -0
- package/skill/references/ui.md +532 -0
- package/template/AGENTS.md +17 -0
- package/template/CLAUDE.md +1 -0
- package/template/README.md +12 -0
- package/template/gitignore +2 -0
- package/template/src/index.ts +28 -0
- package/template/src/messages.ts +16 -0
- package/template/src/types.ts +8 -0
- package/template/src/ui.tsx +30 -0
- package/template/tsconfig.json +7 -0
- package/tsconfig.json +25 -0
- package/README.md +0 -3
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a tool result's image goes on the Responses API — learned from the endpoint, then kept.
|
|
3
|
+
*
|
|
4
|
+
* The protocol puts it inside the result: `function_call_output.output` may be a list with
|
|
5
|
+
* `input_image` parts, and that is the default. Relays that translate Responses into Chat
|
|
6
|
+
* Completions do not all carry that across. Measured 2026-09-27 on a relay serving `glm-5.3-flash`
|
|
7
|
+
* (an MCP tool returning a screenshot), the request with the image was refused outright:
|
|
8
|
+
*
|
|
9
|
+
* Upstream request failed: [invalid_value] messages[5]: tool content: part type "image_url"
|
|
10
|
+
* is not supported; only text is
|
|
11
|
+
*
|
|
12
|
+
* and not once: the image stays in history, so every later request in that conversation would be
|
|
13
|
+
* refused the same way. Having been told, the image moves to a user message right after the
|
|
14
|
+
* results — the shape Chat Completions uses anyway — and the request is sent again.
|
|
15
|
+
*
|
|
16
|
+
* In memory only, like the other compat axes: relearning after a restart costs one refused request.
|
|
17
|
+
*/
|
|
18
|
+
/** `inline`: inside `function_call_output`. `lifted`: in a user message after the results. */
|
|
19
|
+
export type ToolResultImages = "inline" | "lifted";
|
|
20
|
+
export declare function toolResultImages(providerId: string, modelId: string): ToolResultImages;
|
|
21
|
+
/** Learn from one failure. Returns "the conclusion changed, worth resending in the new shape". */
|
|
22
|
+
export declare function learnToolResultImages(providerId: string, modelId: string, error: string): boolean;
|
|
23
|
+
/** For tests: forget everything learned. */
|
|
24
|
+
export declare function resetToolResultImagesCompat(): void;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 工具参数 schema 发出去之前、三种格式都要做的改写。各家专有的规整(Anthropic 的关键字白名单)留在各自的
|
|
3
|
+
* encoder 里;这里只放对所有端点都语义等价的那种。
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* 指向 `$defs` 以外的本地 `$ref`(`#/properties/a`、`#/definitions/X`),目标复制进 `$defs`、引用改指过去。
|
|
7
|
+
*
|
|
8
|
+
* MCP 服务器的 schema 常这样复用前面某个属性的定义。Kimi 的工具 schema 要守 MFJS 规范:「`$defs` must be
|
|
9
|
+
* defined at the schema root level; `$ref` only supports referencing internal subschemas … indexed through
|
|
10
|
+
* `$defs`」(github.com/MoonshotAI/walle docs/mfjs-spec.md),原样发出过不了校验——装了那个 MCP,之后每一轮
|
|
11
|
+
* 都 400。搬过去之后引用解析到的是同一个形状,对认任意 JSON Pointer 的端点也毫无差别,所以不挂在厂商上、
|
|
12
|
+
* 三种格式一律做。
|
|
13
|
+
*
|
|
14
|
+
* 搬走的目标原处不留第二份:`definitions` 里的删掉(删空了整个去掉),别处的换成指向 `$defs` 的引用。否则
|
|
15
|
+
* 同一份定义每轮在工具列表里发两遍。
|
|
16
|
+
*
|
|
17
|
+
* 没有这种引用时返回**原来那个对象**:这在每一轮的工具列表上跑一遍,绝大多数 schema 都不会走到改写。解析
|
|
18
|
+
* 不到的引用和外部引用不动、也不抛——改不了的交给端点判,至少不比原来更糟。
|
|
19
|
+
*/
|
|
20
|
+
export declare function hoistLocalRefs<T>(schema: T): T;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 三条协议的用量字段:每个桶从哪几个字段读、按什么顺序回退、`input` 里含不含缓存。
|
|
3
|
+
*
|
|
4
|
+
* 从前三个适配器各写一段 `if (typeof raw.xxx === "number")`,Chat 链只认 `prompt_tokens_details.cached_tokens`、
|
|
5
|
+
* 缓存写入写死 0——DeepSeek 的命中数在 `prompt_cache_hit_tokens`、Kimi 的在顶层 `cached_tokens`,于是这两家
|
|
6
|
+
* 的缓存命中在账上一直是 0、全按原价算。服务商每多一个,三处就各要改一遍,改漏一处就是一条账不对。
|
|
7
|
+
*
|
|
8
|
+
* 现在只有一张表(`USAGE_DIALECTS`)。**新增一个服务商变体 = 在对应协议、对应桶的列表里加一行**,
|
|
9
|
+
* 写明字段路径和出处;解析逻辑一个字都不用动。
|
|
10
|
+
*
|
|
11
|
+
* 四个桶(input / output / cacheRead / cacheWrite)必须不重叠——用量页和计价器都是四个桶直接相加,
|
|
12
|
+
* 重叠一份就算两遍钱。`reasoning` 不是第五个桶,它是 output 里的一部分,只用于展示。
|
|
13
|
+
*/
|
|
14
|
+
import type { ApiFormat, Usage } from "../types.ts";
|
|
15
|
+
/** 表里能声明的桶。 */
|
|
16
|
+
export type UsageBucket = "input" | "output" | "cacheRead" | "cacheWrite" | "reasoning";
|
|
17
|
+
/**
|
|
18
|
+
* 按协议读出这一帧里出现了的桶。没出现的桶不在结果里——调用方据此决定「不动」而不是「清零」。
|
|
19
|
+
*
|
|
20
|
+
* 「`input` 含缓存」的协议有一条额外约束:input 和它含着的那几个桶**一起给、一起更新**。给了 input
|
|
21
|
+
* 却没给缓存字段,缓存桶就是 0,不能沿用上一帧的值——否则扣的和存的不是同一个数,桶又重叠了。
|
|
22
|
+
*/
|
|
23
|
+
export declare function readUsage(api: ApiFormat, raw: Record<string, unknown>): Partial<Record<UsageBucket, number>>;
|
|
24
|
+
/**
|
|
25
|
+
* 把一帧用量合进 `usage`:出现了的桶覆盖,没出现的不动,`total` 跟着重算。
|
|
26
|
+
*
|
|
27
|
+
* 「没出现的不动」是 Anthropic 那条链要的:`message_start` 带输入和缓存,`message_delta` 通常只带
|
|
28
|
+
* `output_tokens`,清零会把前一帧的输入抹掉。费用不在这里算,见 `priceAttempt`。
|
|
29
|
+
*/
|
|
30
|
+
export declare function applyUsage(api: ApiFormat, usage: Usage, raw: unknown): void;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 厂商特例的唯一去处。
|
|
3
|
+
*
|
|
4
|
+
* 这里只放**事先就知道、又学不会**的事:端点不报错只是静默忽略(发 `budget_tokens` 给只认 effort 的模型),
|
|
5
|
+
* 或者报了错但报得认不出(Gemini 2.5 的 `invalid argument`),以及省掉一次必然的 400(新 Claude 的 adaptive)。
|
|
6
|
+
* 端点会报错并点名原因的,走「撞出来再学」的那几张表(`request-params-compat.ts`、`reasoning-compat.ts`、
|
|
7
|
+
* `tool-pairing-compat.ts`、Anthropic 链的 `learnAdaptiveThinking`),不写这里。
|
|
8
|
+
*
|
|
9
|
+
* 从前这些先验散在三个适配器里,同一件事在一条链上有、另一条链上没有,Gemini 关思考在 Chat 链上全挂就是
|
|
10
|
+
* 这么来的。现在适配器只问这里。
|
|
11
|
+
*
|
|
12
|
+
* 加一条的门槛:撞到过、或者官方文档写明了,而且学习表认领不了。只照着别家产品的内置表抄来的不加——
|
|
13
|
+
* 模型名正则随版本过期,每一条都是要人看着的维护负担,而判错的代价多半只是档位没送到。
|
|
14
|
+
*/
|
|
15
|
+
import type { ResolvedThinking } from "./types.ts";
|
|
16
|
+
/** 这个端点上的这个模型,思考开关该怎么写。 */
|
|
17
|
+
export declare function thinkingDialect(endpoint: string, modelId: string): ResolvedThinking;
|
|
18
|
+
/** 缓存在这一家能留多久;没有规则时是 undefined,由调用方用自己的默认值。 */
|
|
19
|
+
export declare function cacheHotMs(endpoint: string, modelId: string): number | undefined;
|
|
20
|
+
export type { ResolvedThinking } from "./types.ts";
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 把 `thinkingDialect` 查到的写法翻成三种格式各自的请求体字段。
|
|
3
|
+
*
|
|
4
|
+
* 适配器只做一件事:把这里返回的对象展开进请求体。写法的选择在 `index.ts`,学到的结论(adaptive、被撤掉的
|
|
5
|
+
* 参数)由适配器查好传进来——这里不碰任何一张学习表,所以是纯函数,能直接测。
|
|
6
|
+
*/
|
|
7
|
+
import type { AnthropicThinkingOn, ResolvedThinking } from "./types.ts";
|
|
8
|
+
type Fields = Record<string, unknown>;
|
|
9
|
+
export interface AnthropicThinkingInput {
|
|
10
|
+
/** 开着时的档位;`undefined` 表示关着。 */
|
|
11
|
+
effort: string | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* 没填(`undefined`)时开着照发——从前就是这样;关着时什么都不发:不知道这个模型有没有思考,就别给
|
|
14
|
+
* 它发一个它可能不认的 `thinking` 字段,被拒了也没有哪条学习轴能撤掉它。
|
|
15
|
+
*/
|
|
16
|
+
supportsThinking: boolean | undefined;
|
|
17
|
+
budget: number | undefined;
|
|
18
|
+
maxTokens: number;
|
|
19
|
+
/** 这个模型撞出过「不认 budget_tokens」。只在写法本来是 `budget` 时起作用。 */
|
|
20
|
+
learnedAdaptive: boolean;
|
|
21
|
+
}
|
|
22
|
+
/** 这一次实际用哪种写法开思考。budget 写法要校验 budget、要带交错思考的头,适配器靠它判断。 */
|
|
23
|
+
export declare function anthropicThinkingOn(dialect: ResolvedThinking, learnedAdaptive: boolean): AnthropicThinkingOn;
|
|
24
|
+
export declare function anthropicThinkingFields(dialect: ResolvedThinking, input: AnthropicThinkingInput): Fields;
|
|
25
|
+
export interface OpenAiThinkingInput {
|
|
26
|
+
/** 开着时的档位;`undefined` 表示关着。 */
|
|
27
|
+
effort: string | undefined;
|
|
28
|
+
supportsThinking: boolean | undefined;
|
|
29
|
+
/** 这个端点撞过之后要求别发的参数,见 `request-params-compat.ts`。 */
|
|
30
|
+
dropped: ReadonlySet<string>;
|
|
31
|
+
}
|
|
32
|
+
/** Chat Completions。关着时 `reasoning_effort: "none"` 撞过就撤(`reasoning-off`)。 */
|
|
33
|
+
export declare function chatThinkingFields(dialect: ResolvedThinking, input: OpenAiThinkingInput): Fields;
|
|
34
|
+
/**
|
|
35
|
+
* Responses。摘要要组织验证过才给,没验证的账号整个请求 400——撞过就只撤它(`reasoning-summary`),effort
|
|
36
|
+
* 照发;密文同理(`include-encrypted`)。关着时 `effort: "none"` 撞过就撤(`reasoning-off`)。
|
|
37
|
+
*/
|
|
38
|
+
export declare function responsesThinkingFields(dialect: ResolvedThinking, input: OpenAiThinkingInput): Fields;
|
|
39
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 厂商特例的描述方式。见 `index.ts` 顶上那段:为什么有这一层、和「撞出来再学」的那几张表怎么分工。
|
|
3
|
+
*
|
|
4
|
+
* 一条规则只是数据:在哪些模型 / 端点上、思考开关在每种格式下该怎么写。怎么把它翻成请求体是 `thinking.ts`
|
|
5
|
+
* 的事,适配器只问结果,不认识任何一家厂商。
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Anthropic 格式开思考的写法。
|
|
9
|
+
*
|
|
10
|
+
* - `budget`:`thinking: {type: "enabled", budget_tokens}`。默认;端点点名不认时会学成 `adaptive`。
|
|
11
|
+
* - `adaptive`:`thinking: {type: "adaptive"}` + `output_config.effort`。
|
|
12
|
+
* - `enabled-effort`:`thinking: {type: "enabled"}` + `output_config.effort`——认 effort、忽略 budget 的兼容端点。
|
|
13
|
+
* - `effort-only`:只发 `output_config.effort`,不发 `thinking`——请求结构里根本没有这个字段的端点。
|
|
14
|
+
*/
|
|
15
|
+
export type AnthropicThinkingOn = "budget" | "adaptive" | "enabled-effort" | "effort-only";
|
|
16
|
+
/** 一个模型族在思考开关上的脾气。只写和默认不同的那几项,其余由 `index.ts` 的默认值补齐。 */
|
|
17
|
+
interface ThinkingDialect {
|
|
18
|
+
anthropic?: AnthropicThinkingOn;
|
|
19
|
+
/** Chat Completions 关思考时不收 `reasoning_effort: "none"`,整个字段不发。 */
|
|
20
|
+
chatRefusesNone?: boolean;
|
|
21
|
+
/** Responses 关思考时不收 `reasoning: {effort: "none"}`,整个 `reasoning` 不发。 */
|
|
22
|
+
responsesRefusesNone?: boolean;
|
|
23
|
+
/** Responses 上每个助手轮都要以推理项开头(DeepSeek)。见 `openai-responses-request.ts` 的补位分支。 */
|
|
24
|
+
leadingReasoning?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* 关不掉:服务端强制思考,发关闭参数会报错。界面上不给「关闭」,请求里也不发关闭参数。
|
|
27
|
+
*/
|
|
28
|
+
alwaysOn?: boolean;
|
|
29
|
+
}
|
|
30
|
+
/** 补齐默认值之后的结果。适配器拿到的就是这个。 */
|
|
31
|
+
export type ResolvedThinking = Required<ThinkingDialect>;
|
|
32
|
+
/** 一条规则。`model` 和 `endpoint` 都写时两个都要命中;要「任一命中」就写成两条。 */
|
|
33
|
+
export interface VendorRule {
|
|
34
|
+
/** 线上模型名(`model.modelId`)。不写表示不看模型。 */
|
|
35
|
+
model?: RegExp;
|
|
36
|
+
/** 端点地址(`provider.baseUrl`)。不写表示不看端点。 */
|
|
37
|
+
endpoint?: RegExp;
|
|
38
|
+
thinking: ThinkingDialect;
|
|
39
|
+
/**
|
|
40
|
+
* 同一前缀隔多久以内多半还读得到缓存,毫秒。不写就用分叉的默认值(`compaction-fork.ts` 的 `FORK_HOT_MS`,
|
|
41
|
+
* 按最短的常见有效期定)。写错的代价是一次压缩:分叉时缓存已凉,完整历史按原价读一遍。
|
|
42
|
+
*/
|
|
43
|
+
cacheHotMs?: number;
|
|
44
|
+
/** 出处:官方原话、实测记录。说不出出处的不要加。 */
|
|
45
|
+
source: string;
|
|
46
|
+
}
|
|
47
|
+
export {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which configured models draw pictures, and which one a request means.
|
|
3
|
+
*
|
|
4
|
+
* Browser-safe on purpose: the chat picker has to leave these out and the
|
|
5
|
+
* settings page has to list them, and both are the renderer. Nothing here imports a value.
|
|
6
|
+
*/
|
|
7
|
+
import type { ModelConfig, ProviderConfig } from "../types/provider.ts";
|
|
8
|
+
export declare function isImageModelId(modelId: string): boolean;
|
|
9
|
+
/** A stored choice first; the name only when nobody has said. */
|
|
10
|
+
export declare function isImageModel(model: Pick<ModelConfig, "modelId" | "imageOutput">): boolean;
|
|
11
|
+
export interface ImageModelRow {
|
|
12
|
+
provider: ProviderConfig;
|
|
13
|
+
model: ModelConfig;
|
|
14
|
+
}
|
|
15
|
+
/** Every image model on an enabled provider, in the order they are configured. */
|
|
16
|
+
export declare function imageModelRows(providers: readonly ProviderConfig[] | undefined): ImageModelRow[];
|
|
17
|
+
/**
|
|
18
|
+
* The image model a call means.
|
|
19
|
+
*
|
|
20
|
+
* `asked` is whatever the conversation named — "gpt-image-2.5", "Nano Banana" — so it is matched the
|
|
21
|
+
* way a person would mean it: the local id, then the provider's id or the display name exactly, then
|
|
22
|
+
* a unique partial match. An ambiguous or unknown name is not quietly replaced by the default: the
|
|
23
|
+
* person asked for a particular model, and drawing with another one is the wrong answer billed to them.
|
|
24
|
+
*
|
|
25
|
+
* Without `asked`, the configured default (`Settings.imageModelId`) if it still resolves, else the
|
|
26
|
+
* first image model there is.
|
|
27
|
+
*/
|
|
28
|
+
export declare function resolveImageModel(providers: readonly ProviderConfig[] | undefined, preferred: string | null | undefined, asked?: string): {
|
|
29
|
+
row: ImageModelRow;
|
|
30
|
+
} | {
|
|
31
|
+
row?: undefined;
|
|
32
|
+
reason: "none" | "unknown" | "ambiguous";
|
|
33
|
+
candidates: ImageModelRow[];
|
|
34
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export interface RetryRule {
|
|
2
|
+
/** Retries after the initial request; null means until cancelled. */
|
|
3
|
+
retries: number | null;
|
|
4
|
+
strategy: "fixed" | "linear";
|
|
5
|
+
intervalMs: number;
|
|
6
|
+
maxIntervalMs: number;
|
|
7
|
+
}
|
|
8
|
+
export interface RetryPolicy {
|
|
9
|
+
network: RetryRule;
|
|
10
|
+
upstream: RetryRule;
|
|
11
|
+
}
|
|
12
|
+
export type RetryFailure = keyof RetryPolicy;
|
|
13
|
+
/**
|
|
14
|
+
* A policy, or a way to read the current one.
|
|
15
|
+
*
|
|
16
|
+
* A request that is retrying every five seconds until the network comes back can outlive several
|
|
17
|
+
* visits to the settings page, and taking a copy at the start meant those edits reached it only
|
|
18
|
+
* after it had finished — which for the unlimited rule is never. Handed a function instead, the
|
|
19
|
+
* budget reads the live setting before each wait, so raising a limit or shortening an interval
|
|
20
|
+
* applies from the next retry on. Callers with a fixed policy of their own still pass a value.
|
|
21
|
+
*/
|
|
22
|
+
export type RetryPolicySource = RetryPolicy | (() => RetryPolicy | undefined);
|
|
23
|
+
export declare const DEFAULT_RETRY_RULE: RetryRule;
|
|
24
|
+
export declare const DEFAULT_RETRY_POLICY: RetryPolicy;
|
|
25
|
+
/** Separate fault policies, each bounded the same way wherever it was written. */
|
|
26
|
+
export declare function normalizeRetryPolicy(value: unknown): RetryPolicy;
|
|
27
|
+
/**
|
|
28
|
+
* How long this wait is. A fixed interval carries ±20% jitter; on average it is still the setting.
|
|
29
|
+
*
|
|
30
|
+
* It was deliberately exact once, so that "every 5 seconds" meant exactly that. The cost: when a relay
|
|
31
|
+
* hiccups, every client on it drops at the same instant and comes back in lockstep every 5 seconds,
|
|
32
|
+
* knocking the recovering end over on the same beat each time. A second either way makes no
|
|
33
|
+
* difference to the person waiting. `random` is injected only by tests.
|
|
34
|
+
*/
|
|
35
|
+
export declare function policyDelay(policy: RetryRule, retry: number, random?: () => number): number;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Drawing through a chat completion that is asked for image output.
|
|
3
|
+
*
|
|
4
|
+
* The route for hosts that never grew an Images API — OpenRouter, and the Gemini models that write and
|
|
5
|
+
* draw on endpoints that only speak chat. The request is an ordinary user turn with
|
|
6
|
+
* `modalities: ["image", "text"]`; the picture comes back in one of three places depending on who
|
|
7
|
+
* translated the upstream answer, and all three are read.
|
|
8
|
+
*/
|
|
9
|
+
import type { ModelConfig, ProviderConfig } from "../types/provider.ts";
|
|
10
|
+
import type { ImageCallOptions, ImageRequest, ImageResult } from "./types.ts";
|
|
11
|
+
export declare function viaChatCompletions(provider: ProviderConfig, model: ModelConfig, request: ImageRequest, options: ImageCallOptions): Promise<ImageResult>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Width and height out of an image's own header.
|
|
3
|
+
*
|
|
4
|
+
* The card holds the picture's place at its real shape before the bytes have loaded, and the model is
|
|
5
|
+
* told what it got. Asking the provider is not enough: the Images API reports a requested size, not
|
|
6
|
+
* the delivered one, and a relay in front of Gemini reports nothing at all. PNG, JPEG and WebP — what
|
|
7
|
+
* image models return — and `null` for anything else rather than a guess.
|
|
8
|
+
*/
|
|
9
|
+
export interface Dimensions {
|
|
10
|
+
width: number;
|
|
11
|
+
height: number;
|
|
12
|
+
}
|
|
13
|
+
export declare function imageDimensions(bytes: Uint8Array): Dimensions | null;
|
|
14
|
+
/** The MIME type the bytes actually are, which is not always what the response claimed. */
|
|
15
|
+
export declare function sniffImageType(bytes: Uint8Array): string | null;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Draw with an image model, through whichever endpoint its provider actually has.
|
|
3
|
+
*
|
|
4
|
+
* There is no field that says. An OpenAI-compatible base URL may serve the Images API, chat
|
|
5
|
+
* completions with image output, or both, and which one is a property of the host and the model
|
|
6
|
+
* together: the same Gemini model is reachable through `/v1/images` on one relay and only through chat
|
|
7
|
+
* on OpenRouter. So the first call tries the likelier route, a "this endpoint is not here" answer
|
|
8
|
+
* switches to the other, and the route that worked is remembered for the rest of the run — one wasted
|
|
9
|
+
* request per model per launch, not per picture.
|
|
10
|
+
*/
|
|
11
|
+
import type { ModelConfig, ProviderConfig } from "../types/provider.ts";
|
|
12
|
+
import type { ImageCallOptions, ImageRequest, ImageResult } from "./types.ts";
|
|
13
|
+
/** Forget the routes learned so far. For tests. */
|
|
14
|
+
export declare function resetImageRoutes(): void;
|
|
15
|
+
export declare function generateImages(provider: ProviderConfig, model: ModelConfig, request: ImageRequest, options?: ImageCallOptions): Promise<ImageResult>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Drawing through the OpenAI Images API: `/v1/images/generations`, and `/v1/images/edits` when there
|
|
3
|
+
* are pictures to work from.
|
|
4
|
+
*
|
|
5
|
+
* The common denominator: OpenAI's own image models, and the relays that put Gemini, Flux or Seedream
|
|
6
|
+
* behind the same two endpoints. A chat-only host answers 404 here, and `generate.ts` takes that as
|
|
7
|
+
* the cue to try a chat completion instead.
|
|
8
|
+
*/
|
|
9
|
+
import type { ModelConfig, ProviderConfig } from "../types/provider.ts";
|
|
10
|
+
import type { ImageCallOptions, ImageRequest, ImageResult } from "./types.ts";
|
|
11
|
+
export declare function viaImagesApi(provider: ProviderConfig, model: ModelConfig, request: ImageRequest, options: ImageCallOptions): Promise<ImageResult>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A spent quota, told apart from a busy moment before anything waits on it.
|
|
3
|
+
*
|
|
4
|
+
* Both arrive as 429. A busy moment is worth a retry a second later; a spent quota answers the same
|
|
5
|
+
* for hours — Antigravity says "Your quota will reset after 1h52m45s" — and every retry against it is
|
|
6
|
+
* a turn held open with the card spinning, for an answer that was already final. So the response is
|
|
7
|
+
* read before the retry loop sees it, and a spent quota leaves as final, with the wait it named.
|
|
8
|
+
*/
|
|
9
|
+
export declare function quotaGuard(doFetch: typeof globalThis.fetch): typeof globalThis.fetch;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shape and detail a picture is asked for in, said the way each model family understands it.
|
|
3
|
+
*
|
|
4
|
+
* The tool speaks in aspect ratios because that is what a person asks for ("a 16:9 banner") and what
|
|
5
|
+
* the card needs to hold the picture's place. Providers each want their own spelling, and a wrong one
|
|
6
|
+
* is refused outright rather than approximated:
|
|
7
|
+
*
|
|
8
|
+
* - OpenAI's lines take a short list of pixel sizes each.
|
|
9
|
+
* - A relay in front of Gemini (CliRelay) takes `aspect_ratio` and `image_size` (`512`, `1K`, `2K`,
|
|
10
|
+
* `4K`), refuses `"16:9"` as a `size`, and ignores `quality` — so detail has to travel as
|
|
11
|
+
* `image_size` or it is lost.
|
|
12
|
+
* - Anything else gets a pixel size in the ratio's proportions, which hosts with fixed sizes snap to.
|
|
13
|
+
*/
|
|
14
|
+
import type { ImageRequest } from "./types.ts";
|
|
15
|
+
export declare const ASPECT_RATIOS: readonly ["1:1", "4:3", "3:4", "3:2", "2:3", "16:9", "9:16", "21:9", "5:4", "4:5"];
|
|
16
|
+
export declare const QUALITIES: readonly ["low", "medium", "high", "max"];
|
|
17
|
+
/** `"16:9"` as numbers, or `null` for `auto`, empty, or anything that is not a ratio. */
|
|
18
|
+
export declare function parseRatio(value: string | undefined): {
|
|
19
|
+
width: number;
|
|
20
|
+
height: number;
|
|
21
|
+
} | null;
|
|
22
|
+
/**
|
|
23
|
+
* The fields of an Images API request that depend on the model, beyond `model`, `prompt` and `n`.
|
|
24
|
+
*
|
|
25
|
+
* Unknown fields are not sent to a family that might refuse them: OpenAI answers an unrecognised
|
|
26
|
+
* parameter with a 400.
|
|
27
|
+
*/
|
|
28
|
+
export declare function imageFields(modelId: string, request: Pick<ImageRequest, "aspectRatio" | "quality" | "background">): Record<string, string>;
|
|
29
|
+
/**
|
|
30
|
+
* How many pictures one request may ask for.
|
|
31
|
+
*
|
|
32
|
+
* DALL·E 3 draws one per request. A relay in front of Gemini runs `n` one after another and fails the
|
|
33
|
+
* lot if any one fails, so pictures there are asked for one per request — side by side, which is also
|
|
34
|
+
* faster than its own queue.
|
|
35
|
+
*/
|
|
36
|
+
export declare function perRequestLimit(modelId: string): number;
|
|
37
|
+
/**
|
|
38
|
+
* Whether an edit goes as JSON with data URLs rather than multipart.
|
|
39
|
+
*
|
|
40
|
+
* The relay takes both for Gemini, and refuses a disallowed model on JSON with a clear 403 where the
|
|
41
|
+
* multipart form gets past its model check and fails later as a bare 502. OpenAI's own edits endpoint
|
|
42
|
+
* is multipart only.
|
|
43
|
+
*/
|
|
44
|
+
export declare function editsAsJson(modelId: string): boolean;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A request to draw, and what comes back — independent of which endpoint does the drawing.
|
|
3
|
+
*/
|
|
4
|
+
import type { RetryPolicySource } from "../config/retry-policy.ts";
|
|
5
|
+
import type { RequestOptions } from "../types/provider.ts";
|
|
6
|
+
/** The tool's name, in one place: the transcript is searched for its results by it. */
|
|
7
|
+
export declare const IMAGE_TOOL_NAME = "image_generate";
|
|
8
|
+
/** An image going in: something to edit, or to draw after. */
|
|
9
|
+
export interface ImageInput {
|
|
10
|
+
/** base64, no `data:` prefix. */
|
|
11
|
+
data: string;
|
|
12
|
+
mimeType: string;
|
|
13
|
+
/** A file name for the multipart upload; some endpoints reject a part without one. */
|
|
14
|
+
name?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface ImageRequest {
|
|
17
|
+
prompt: string;
|
|
18
|
+
/** Present means an edit: these are the pictures the prompt is about. */
|
|
19
|
+
images?: ImageInput[];
|
|
20
|
+
/** `"16:9"` and friends; absent or `auto` leaves the shape to the model. */
|
|
21
|
+
aspectRatio?: string;
|
|
22
|
+
/** `max` is the largest the model offers — 4K on Gemini — and is slow to arrive over a relay. */
|
|
23
|
+
quality?: "low" | "medium" | "high" | "max";
|
|
24
|
+
count?: number;
|
|
25
|
+
background?: "transparent" | "opaque";
|
|
26
|
+
}
|
|
27
|
+
export interface GeneratedImage {
|
|
28
|
+
data: string;
|
|
29
|
+
mimeType: string;
|
|
30
|
+
}
|
|
31
|
+
/** Which endpoint drew it: the Images API, or a chat completion asked for image output. */
|
|
32
|
+
export type ImageRoute = "images" | "chat";
|
|
33
|
+
export interface ImageResult {
|
|
34
|
+
images: GeneratedImage[];
|
|
35
|
+
/** What the provider says it actually drew from, when it rewrote the prompt. */
|
|
36
|
+
revisedPrompt?: string;
|
|
37
|
+
route: ImageRoute;
|
|
38
|
+
usage?: {
|
|
39
|
+
input?: number;
|
|
40
|
+
output?: number;
|
|
41
|
+
total?: number;
|
|
42
|
+
};
|
|
43
|
+
/** Why the pictures that did not arrive did not, when only some of several did. */
|
|
44
|
+
failures?: string[];
|
|
45
|
+
}
|
|
46
|
+
export interface ImageCallOptions {
|
|
47
|
+
signal?: AbortSignal;
|
|
48
|
+
fetch?: typeof globalThis.fetch;
|
|
49
|
+
retryAttempts?: number;
|
|
50
|
+
retryPolicy?: RetryPolicySource;
|
|
51
|
+
onRetry?: RequestOptions["onRetry"];
|
|
52
|
+
}
|
|
53
|
+
/** A picture already in the conversation, not yet read: inline pixels or a file under `session-media`. */
|
|
54
|
+
export interface ImagePointer {
|
|
55
|
+
data?: string;
|
|
56
|
+
media?: string;
|
|
57
|
+
mimeType: string;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* What `image_generate` hands the window: once as the call starts, so the place can be held at the
|
|
61
|
+
* right shape before anything arrives, and again in the result.
|
|
62
|
+
*/
|
|
63
|
+
export interface ImageGenerateDetails {
|
|
64
|
+
kind: typeof IMAGE_TOOL_NAME;
|
|
65
|
+
/** As asked, `"16:9"`; absent for `auto`. */
|
|
66
|
+
aspectRatio?: string;
|
|
67
|
+
count: number;
|
|
68
|
+
/**
|
|
69
|
+
* The pictures that went in, by `session-media` name, in the order they were given.
|
|
70
|
+
*
|
|
71
|
+
* What makes a picture's history drawable in the gallery: the dog, the dog in a hat, the girl
|
|
72
|
+
* holding it. Absent on results written before it existed; those are traced back from the call's
|
|
73
|
+
* own `#1`/path arguments instead (`lineage.ts`).
|
|
74
|
+
*/
|
|
75
|
+
sources?: string[];
|
|
76
|
+
/**
|
|
77
|
+
* The shape the picture will most likely come back in, when none was asked for: an edit keeps the
|
|
78
|
+
* shape of the picture it starts from. Width over height.
|
|
79
|
+
*
|
|
80
|
+
* Without it the place was a square, and an edit of a wide picture landed as a square snapping to
|
|
81
|
+
* its real shape — the card, and everything under it, jumping on the frame the picture arrived.
|
|
82
|
+
*/
|
|
83
|
+
shapeHint?: number;
|
|
84
|
+
/** Which model, by id and by the name the card shows; with the two below, what the estimate is timed against. */
|
|
85
|
+
model?: string;
|
|
86
|
+
modelName?: string;
|
|
87
|
+
quality?: string;
|
|
88
|
+
/** Pictures went in: an edit, which takes a little longer. */
|
|
89
|
+
edit?: boolean;
|
|
90
|
+
startedAt?: number;
|
|
91
|
+
/** The wait the call is in, while it is in one: the card says so instead of a stage that is not happening. */
|
|
92
|
+
retry?: {
|
|
93
|
+
attempt: number;
|
|
94
|
+
delayMs: number;
|
|
95
|
+
reason: string;
|
|
96
|
+
};
|
|
97
|
+
/** Why it failed, for the card: a spent quota or a key without the model is something the user acts on. */
|
|
98
|
+
error?: {
|
|
99
|
+
summary: string;
|
|
100
|
+
detail?: string;
|
|
101
|
+
hint?: string;
|
|
102
|
+
retryAfterMs?: number;
|
|
103
|
+
};
|
|
104
|
+
/** The rest is there once it has drawn. */
|
|
105
|
+
/** Where each picture was saved, in the order of the pictures. */
|
|
106
|
+
paths?: string[];
|
|
107
|
+
/** The same pictures by `session-media` name, with the size read from their headers: what `#N` and the card read. */
|
|
108
|
+
images?: {
|
|
109
|
+
media: string;
|
|
110
|
+
mimeType: string;
|
|
111
|
+
width?: number;
|
|
112
|
+
height?: number;
|
|
113
|
+
}[];
|
|
114
|
+
references?: number;
|
|
115
|
+
route?: ImageRoute;
|
|
116
|
+
revisedPrompt?: string;
|
|
117
|
+
failures?: string[];
|
|
118
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 模型目录的数据格式:类型、校验,以及把 pi 的原始目录压成这个格式。
|
|
3
|
+
*
|
|
4
|
+
* 单独成文件而不放在 `model-catalog.ts`:那边一加载就要校验打包的快照,生成快照的脚本和远程同步
|
|
5
|
+
* 不能依赖一份可能还是旧格式的快照。这里没有状态,也不碰文件系统和网络。
|
|
6
|
+
*/
|
|
7
|
+
import type { ModelPricingTier, ThinkingLevel } from "./types/provider.ts";
|
|
8
|
+
/** 唯一的目录来源:pi 的公开模型目录。 */
|
|
9
|
+
export declare const MODEL_CATALOG_URL = "https://pi.dev/api/models";
|
|
10
|
+
export interface CatalogModel {
|
|
11
|
+
id: string;
|
|
12
|
+
name: string;
|
|
13
|
+
/** 这个条目所在端点。个别条目为空或带占位符,那样的只能按型号参考,匹配不到端点。 */
|
|
14
|
+
baseUrl: string;
|
|
15
|
+
contextWindow: number;
|
|
16
|
+
maxOutputTokens: number;
|
|
17
|
+
supportsThinking: boolean;
|
|
18
|
+
/** 可选的思考档位,按 pi 的 `thinkingLevelMap` 折算(见 `thinkingLevels`)。只在支持思考时有。 */
|
|
19
|
+
thinkingLevels?: ThinkingLevel[];
|
|
20
|
+
supportsImages: boolean;
|
|
21
|
+
inputPrice?: number;
|
|
22
|
+
outputPrice?: number;
|
|
23
|
+
cacheReadPrice?: number;
|
|
24
|
+
cacheWritePrice?: number;
|
|
25
|
+
tiers?: ModelPricingTier[];
|
|
26
|
+
}
|
|
27
|
+
export interface CatalogProvider {
|
|
28
|
+
id: string;
|
|
29
|
+
models: CatalogModel[];
|
|
30
|
+
}
|
|
31
|
+
export interface ModelCatalogDocument {
|
|
32
|
+
/** 3:条目带上思考档位。旧格式的缓存整份不认,下次同步重新拉。 */
|
|
33
|
+
schema: 3;
|
|
34
|
+
source: {
|
|
35
|
+
name: string;
|
|
36
|
+
url: string;
|
|
37
|
+
/** 上游给的目录版本号(`x-pi-model-catalog-revision`),也进计价缓存的 key。 */
|
|
38
|
+
revision: string;
|
|
39
|
+
/** 上游的 `last-modified`:远程目录只在比当前的新时才换上。 */
|
|
40
|
+
updatedAt: string;
|
|
41
|
+
};
|
|
42
|
+
providers: CatalogProvider[];
|
|
43
|
+
}
|
|
44
|
+
/** 校验一份目录。远程拉来的内容走同一道校验,不合法就整份拒绝,不会半套生效。 */
|
|
45
|
+
export declare function parseModelCatalog(value: unknown): ModelCatalogDocument;
|
|
46
|
+
/**
|
|
47
|
+
* pi 目录(`{ 供应商 id: { 模型 id: 条目 } }`)压成自己的目录格式,只留上限、思考与档位、图片、端点和价格。
|
|
48
|
+
* 字段不全的条目跳过,不猜。
|
|
49
|
+
*/
|
|
50
|
+
export declare function compactPiCatalog(raw: unknown, source: ModelCatalogDocument["source"]): ModelCatalogDocument;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 模型目录:一个模型的上下文窗口、最大输出、思考能力与档位、图片能力,以及参考价格,都从这里查。
|
|
3
|
+
*
|
|
4
|
+
* 数据来自 pi 的公开模型目录(https://pi.dev/api/models)。仓库里打包一份压缩过的快照
|
|
5
|
+
* `catalog/model-catalog.json`,桌面主进程运行时定期拉最新的换上(`model-catalog-sync.ts`),
|
|
6
|
+
* 所以离线也能用,联网时自动更新。这个文件不碰文件系统和网络——渲染进程也要用它。
|
|
7
|
+
*
|
|
8
|
+
* 目录只是参考:导入模型、在编辑器里搜索选中时,把条目的上限、能力、思考档位和价格一次性填进模型配置,
|
|
9
|
+
* 之后配置归用户,目录更新不会改动它。用量页给没有配置价格的历史记录估算费用时也查这里。
|
|
10
|
+
*
|
|
11
|
+
* 自动匹配顺序:同一端点(Base URL)下的同名模型 → 按型号家族找厂商官方条目和 OpenRouter 的参考值。
|
|
12
|
+
* 发送给供应商的模型 ID 从不改写。
|
|
13
|
+
*/
|
|
14
|
+
import { type CatalogModel, type CatalogProvider, type ModelCatalogDocument } from "./model-catalog-format.ts";
|
|
15
|
+
import type { ModelConfig, ModelPricing, ProviderConfig } from "./types/provider.ts";
|
|
16
|
+
export type { CatalogModel, CatalogProvider, ModelCatalogDocument } from "./model-catalog-format.ts";
|
|
17
|
+
export interface CatalogMatch {
|
|
18
|
+
provider: CatalogProvider;
|
|
19
|
+
model: CatalogModel;
|
|
20
|
+
match: "exact" | "alias" | "reference";
|
|
21
|
+
}
|
|
22
|
+
/** 从目录填进模型配置的那几项。 */
|
|
23
|
+
export type CatalogFill = Pick<ModelConfig, "contextWindow" | "maxOutputTokens" | "supportsThinking" | "thinkingOptions" | "supportsImages" | "supportsTools" | "pricing">;
|
|
24
|
+
/**
|
|
25
|
+
* 目录里找不到时的初始值:新建模型和导入时没匹配上的模型用它。
|
|
26
|
+
*
|
|
27
|
+
* 能力全开:这一档接的是中转起的私有名字、刚发布的型号、自建端点,如今几乎都会思考、看图、调工具。
|
|
28
|
+
* 猜错的代价不对等——开着而不支持,供应商回一个说得清楚的错;关着而支持,是能力凭空少一块还不报错。
|
|
29
|
+
*/
|
|
30
|
+
export declare const DEFAULT_MODEL_LIMITS: Omit<CatalogFill, "pricing">;
|
|
31
|
+
/** 当前生效的目录:打包的那份,或更新过的远程版本。 */
|
|
32
|
+
export declare function activeModelCatalog(): ModelCatalogDocument;
|
|
33
|
+
/** 目录版本,进计价缓存的 key 和价格快照:目录一换,旧的估价重算。 */
|
|
34
|
+
export declare function modelCatalogVersion(): string;
|
|
35
|
+
/**
|
|
36
|
+
* 换上一份目录,只在它比当前的新时生效。返回是否真的换了。
|
|
37
|
+
*
|
|
38
|
+
* 按 `updatedAt` 比而不是无条件替换:应用升级后打包的快照可能比本地缓存的远程版本还新。
|
|
39
|
+
*/
|
|
40
|
+
export declare function installModelCatalog(document: ModelCatalogDocument): boolean;
|
|
41
|
+
/** 测试用:回到打包的快照。 */
|
|
42
|
+
export declare function resetModelCatalog(): void;
|
|
43
|
+
export declare function catalogModelFor(provider: Pick<ProviderConfig, "baseUrl">, modelId: string): CatalogMatch | null;
|
|
44
|
+
export declare function catalogPricing(model: CatalogModel): ModelPricing | undefined;
|
|
45
|
+
/**
|
|
46
|
+
* 一个目录条目要填进模型配置的值。输出上限不超过窗口;全零价格的订阅制条目不填价格。
|
|
47
|
+
*
|
|
48
|
+
* 关不掉思考的模型(`vendors/` 的 `alwaysOn`)不给「关闭」这一档:目录里的档位不一定知道这一点,而界面上
|
|
49
|
+
* 多一个点了没用的「关闭」,用户以为省了钱。给了端点就连端点一起看,规则可以按端点写。
|
|
50
|
+
*/
|
|
51
|
+
export declare function catalogFill(model: CatalogModel, provider?: Pick<ProviderConfig, "baseUrl">): CatalogFill;
|