@ai-zen/agents-host 0.0.0-stage → 0.1.0-alpha.0
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/CHANGELOG.md +39 -0
- package/LICENSE +21 -0
- package/README.md +759 -2
- package/dist/app.d.ts +384 -0
- package/dist/app.js +1148 -0
- package/dist/cli.d.ts +21 -0
- package/dist/cli.js +353 -0
- package/dist/config.d.ts +97 -0
- package/dist/config.js +171 -0
- package/dist/handlers/agentHandlers.d.ts +18 -0
- package/dist/handlers/agentHandlers.js +20 -0
- package/dist/handlers/assetHandlers.d.ts +29 -0
- package/dist/handlers/assetHandlers.js +35 -0
- package/dist/handlers/capabilities.d.ts +26 -0
- package/dist/handlers/capabilities.js +138 -0
- package/dist/handlers/completionHandlers.d.ts +18 -0
- package/dist/handlers/completionHandlers.js +13 -0
- package/dist/handlers/configHandlers.d.ts +31 -0
- package/dist/handlers/configHandlers.js +59 -0
- package/dist/handlers/conversationHandlers.d.ts +118 -0
- package/dist/handlers/conversationHandlers.js +314 -0
- package/dist/handlers/handoffHandlers.d.ts +17 -0
- package/dist/handlers/handoffHandlers.js +14 -0
- package/dist/handlers/hostHandlers.d.ts +39 -0
- package/dist/handlers/hostHandlers.js +56 -0
- package/dist/handlers/index.d.ts +128 -0
- package/dist/handlers/index.js +92 -0
- package/dist/handlers/messageHandlers.d.ts +11 -0
- package/dist/handlers/messageHandlers.js +10 -0
- package/dist/handlers/modelHandlers.d.ts +17 -0
- package/dist/handlers/modelHandlers.js +19 -0
- package/dist/handlers/noticeHandlers.d.ts +24 -0
- package/dist/handlers/noticeHandlers.js +24 -0
- package/dist/handlers/questionHandlers.d.ts +16 -0
- package/dist/handlers/questionHandlers.js +16 -0
- package/dist/handlers/searchHandlers.d.ts +12 -0
- package/dist/handlers/searchHandlers.js +12 -0
- package/dist/handlers/workspaceHandlers.d.ts +29 -0
- package/dist/handlers/workspaceHandlers.js +47 -0
- package/dist/i18n/en.d.ts +243 -0
- package/dist/i18n/en.js +270 -0
- package/dist/i18n/index.d.ts +43 -0
- package/dist/i18n/index.js +72 -0
- package/dist/i18n/zh.d.ts +240 -0
- package/dist/i18n/zh.js +257 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +15 -0
- package/dist/net/UploadReceiver.d.ts +186 -0
- package/dist/net/UploadReceiver.js +494 -0
- package/dist/net/WsHub.d.ts +231 -0
- package/dist/net/WsHub.js +689 -0
- package/dist/net/auth.d.ts +73 -0
- package/dist/net/auth.js +74 -0
- package/dist/net/discovery.d.ts +72 -0
- package/dist/net/discovery.js +171 -0
- package/dist/net/index.d.ts +14 -0
- package/dist/net/index.js +10 -0
- package/dist/runtime/ChatRunner.d.ts +374 -0
- package/dist/runtime/ChatRunner.js +1204 -0
- package/dist/runtime/ConversationDrafts.d.ts +43 -0
- package/dist/runtime/ConversationDrafts.js +47 -0
- package/dist/runtime/RunRegistry.d.ts +79 -0
- package/dist/runtime/RunRegistry.js +108 -0
- package/dist/runtime/ScopeRegistry.d.ts +153 -0
- package/dist/runtime/ScopeRegistry.js +259 -0
- package/dist/runtime/TransientRunner.d.ts +90 -0
- package/dist/runtime/TransientRunner.js +179 -0
- package/dist/runtime/index.d.ts +14 -0
- package/dist/runtime/index.js +10 -0
- package/dist/services/AgentService.d.ts +150 -0
- package/dist/services/AgentService.js +718 -0
- package/dist/services/AssetService.d.ts +338 -0
- package/dist/services/AssetService.js +739 -0
- package/dist/services/AutoNaming.d.ts +92 -0
- package/dist/services/AutoNaming.js +235 -0
- package/dist/services/CompletionService.d.ts +122 -0
- package/dist/services/CompletionService.js +442 -0
- package/dist/services/ConfigService.d.ts +171 -0
- package/dist/services/ConfigService.js +695 -0
- package/dist/services/ConversationService.d.ts +274 -0
- package/dist/services/ConversationService.js +902 -0
- package/dist/services/CredentialService.d.ts +33 -0
- package/dist/services/CredentialService.js +86 -0
- package/dist/services/DiscoveryService.d.ts +182 -0
- package/dist/services/DiscoveryService.js +998 -0
- package/dist/services/HandoffService.d.ts +189 -0
- package/dist/services/HandoffService.js +414 -0
- package/dist/services/Logger.d.ts +130 -0
- package/dist/services/Logger.js +256 -0
- package/dist/services/MessageService.d.ts +88 -0
- package/dist/services/MessageService.js +280 -0
- package/dist/services/ModelService.d.ts +89 -0
- package/dist/services/ModelService.js +489 -0
- package/dist/services/NoticeService.d.ts +93 -0
- package/dist/services/NoticeService.js +217 -0
- package/dist/services/QuestionService.d.ts +184 -0
- package/dist/services/QuestionService.js +457 -0
- package/dist/services/SearchService.d.ts +54 -0
- package/dist/services/SearchService.js +117 -0
- package/dist/services/WorkspaceService.d.ts +96 -0
- package/dist/services/WorkspaceService.js +213 -0
- package/dist/services/imageSize.d.ts +41 -0
- package/dist/services/imageSize.js +146 -0
- package/dist/services/index.d.ts +20 -0
- package/dist/services/index.js +15 -0
- package/dist/services/secretMask.d.ts +24 -0
- package/dist/services/secretMask.js +34 -0
- package/dist/storage/AssetRepository.d.ts +87 -0
- package/dist/storage/AssetRepository.js +180 -0
- package/dist/storage/ConversationRepository.d.ts +55 -0
- package/dist/storage/ConversationRepository.js +128 -0
- package/dist/storage/CredentialRepository.d.ts +28 -0
- package/dist/storage/CredentialRepository.js +47 -0
- package/dist/storage/Database.d.ts +95 -0
- package/dist/storage/Database.js +180 -0
- package/dist/storage/MessageRepository.d.ts +104 -0
- package/dist/storage/MessageRepository.js +323 -0
- package/dist/storage/MetaRepository.d.ts +21 -0
- package/dist/storage/MetaRepository.js +33 -0
- package/dist/storage/NoticeRepository.d.ts +31 -0
- package/dist/storage/NoticeRepository.js +89 -0
- package/dist/storage/QuestionRepository.d.ts +34 -0
- package/dist/storage/QuestionRepository.js +96 -0
- package/dist/storage/WorkspaceRepository.d.ts +25 -0
- package/dist/storage/WorkspaceRepository.js +44 -0
- package/dist/storage/dbWorker.d.ts +10 -0
- package/dist/storage/dbWorker.js +132 -0
- package/dist/storage/index.d.ts +20 -0
- package/dist/storage/index.js +16 -0
- package/dist/storage/migrations.d.ts +26 -0
- package/dist/storage/migrations.js +207 -0
- package/dist/storage/types.d.ts +298 -0
- package/dist/storage/types.js +14 -0
- package/dist/wire/errors.d.ts +105 -0
- package/dist/wire/errors.js +143 -0
- package/dist/wire/events.d.ts +102 -0
- package/dist/wire/events.js +13 -0
- package/dist/wire/frames.d.ts +106 -0
- package/dist/wire/frames.js +156 -0
- package/dist/wire/index.d.ts +31 -0
- package/dist/wire/index.js +31 -0
- package/dist/wire/methods.d.ts +1896 -0
- package/dist/wire/methods.js +99 -0
- package/dist/wire/states.d.ts +487 -0
- package/dist/wire/states.js +61 -0
- package/package.json +63 -3
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 素材服务:上传产物的落定与登记、取用时变成内容段(F-H7 / R44)、按引用清理(R33)、
|
|
3
|
+
* 以及「落库只有 `__asset_id`」这条口径的两端。
|
|
4
|
+
*
|
|
5
|
+
* 它围着 `assets` 这一份真相做五件事:
|
|
6
|
+
*
|
|
7
|
+
* 1. **落定**({@link AssetService.finalizeUpload}):上传接收器(`net/UploadReceiver`)把字节收进
|
|
8
|
+
* 临时文件之后,本服务把它改名为正式文件、在 `assets` 表登记一行、回一个 {@link AssetRef}。
|
|
9
|
+
* 库里已经有同摘要的那一行时不重复落文件(全局去重),回既有那一行。
|
|
10
|
+
* 2. **取用**({@link AssetService.prepareAttachments}):`MessageInput.assetIds` → core 的内容段。
|
|
11
|
+
* 走文件引用、内联 base64 还是退化成文字,由**实发模型与它所用端点**决定,判定逻辑用 SDK 的
|
|
12
|
+
* `fileToContentSection`(同一份口径,不在这里另写一遍)。没送出去的一律如实记账,不假装成功。
|
|
13
|
+
* 同时给出「落库用」的那一份内容:素材在那里写成段上的 `__asset_id`(本地扩展字段)。
|
|
14
|
+
* 3. **重放**({@link AssetService.resolveHistory}):历史里的 `__asset_id` 在每轮发送前还原成
|
|
15
|
+
* 当前模型能吃的内容段 —— 换了模型、重启之后再跑,同一条历史照样发得出去。发出去的那一份
|
|
16
|
+
* 经 core 的 `formatContent` 按字段白名单重建,`__` 开头的键不会出网。
|
|
17
|
+
* 4. **厂商 file_id 的缓存**:`assets` 是真相;厂商的 `file_id` 是端点维度资源,落在
|
|
18
|
+
* `asset_vendor_files`({@link AssetService.vendorFiles})。三条:
|
|
19
|
+
* - 这个端点上有缓存行 → 直接用那个 `vendorFileId`;
|
|
20
|
+
* - 这个端点上没有、别的端点上有(换厂商 / 换端点)→ 内联 base64,不往新端点重传;
|
|
21
|
+
* - 哪个端点上都没有 → 上传一次并写回。
|
|
22
|
+
* 发送失败就报失败:不自动重试、不判失效、不清缓存。
|
|
23
|
+
* 5. **清理**({@link AssetService.sweepUnreferenced}):引用归零的素材才删行、删文件。关系行
|
|
24
|
+
* (`conversation_assets`)由外键级联删,所以这里判的是「删完之后还剩几张引用」。
|
|
25
|
+
* 这一层是碰 `assets/` 下**正式文件**的地方(临时文件的生与死归上传接收器)。
|
|
26
|
+
*
|
|
27
|
+
* 它被 `ChatRunner` 当作 `prepareAttachments` / `prepareHistory` / `linkMessageAssets` 注入
|
|
28
|
+
* (PRD F-H7 / 裁定 R44)。
|
|
29
|
+
*/
|
|
30
|
+
import type { AgentNS } from "@ai-zen/agents-core";
|
|
31
|
+
import type { Endpoint, Model, ToolEnvDeps } from "@ai-zen/agents-sdk";
|
|
32
|
+
import type { HostPaths } from "../config.js";
|
|
33
|
+
import type { UploadFinalizeRequest } from "../net/UploadReceiver.js";
|
|
34
|
+
import type { AttachmentPreparer, MessageAssetLinker } from "../runtime/ChatRunner.js";
|
|
35
|
+
import { type AssetGetResult, type AssetRef, type AssetVariant, type LocalMessageContentSection, type ProblemFact } from "../wire/index.js";
|
|
36
|
+
/**
|
|
37
|
+
* 素材行:本服务用到的字段(结构上等于存储层的 `AssetRow`)。
|
|
38
|
+
*
|
|
39
|
+
* 这里单独声明一份窄形状,是为了让本服务只依赖「它真的读的那些字段」,
|
|
40
|
+
* `AssetRepository` 结构上满足它,接线处直接传进来即可。
|
|
41
|
+
*/
|
|
42
|
+
export interface AssetRecord {
|
|
43
|
+
id: string;
|
|
44
|
+
name: string | null;
|
|
45
|
+
/** 数据根下的相对路径(如 `assets/<id>.png`) */
|
|
46
|
+
path: string;
|
|
47
|
+
mime: string;
|
|
48
|
+
bytes: number;
|
|
49
|
+
/** 内容摘要;全库唯一,所以它也是去重的键 */
|
|
50
|
+
sha256: string;
|
|
51
|
+
/** 像素宽度:落定时按文件头解出(PNG / JPEG),解不出来为 `null` */
|
|
52
|
+
width: number | null;
|
|
53
|
+
/** 像素高度;口径同 `width` */
|
|
54
|
+
height: number | null;
|
|
55
|
+
createdAt: number;
|
|
56
|
+
}
|
|
57
|
+
/** 一条厂商 file_id 缓存行(结构上等于存储层的 `AssetVendorFileRow`) */
|
|
58
|
+
export interface VendorFileRecord {
|
|
59
|
+
assetId: string;
|
|
60
|
+
endpointId: string;
|
|
61
|
+
vendorFileId: string;
|
|
62
|
+
createdAt: number;
|
|
63
|
+
}
|
|
64
|
+
/** 一个素材的缓存行分布:这个端点上有没有、别的端点上有没有 */
|
|
65
|
+
export interface VendorFilePresence {
|
|
66
|
+
/** 这个端点上已经有缓存行(命中就复用那个 file_id) */
|
|
67
|
+
onEndpoint: boolean;
|
|
68
|
+
/** 别的端点上有(换过厂商 / 端点,这次走内联) */
|
|
69
|
+
elsewhere: boolean;
|
|
70
|
+
}
|
|
71
|
+
/** 素材仓储里本服务用到的部分(`AssetRepository` 结构上满足) */
|
|
72
|
+
export interface AssetRegistry {
|
|
73
|
+
/** 插入;库里已有同摘要的那一行时回既有行(`created: false`) */
|
|
74
|
+
upsert(input: {
|
|
75
|
+
id: string;
|
|
76
|
+
name?: string | null;
|
|
77
|
+
path: string;
|
|
78
|
+
mime: string;
|
|
79
|
+
bytes: number;
|
|
80
|
+
sha256: string;
|
|
81
|
+
width?: number | null;
|
|
82
|
+
height?: number | null;
|
|
83
|
+
createdAt: number;
|
|
84
|
+
}): Promise<{
|
|
85
|
+
row: AssetRecord;
|
|
86
|
+
created: boolean;
|
|
87
|
+
}>;
|
|
88
|
+
get(id: string): Promise<AssetRecord | undefined>;
|
|
89
|
+
/** 按内容摘要找(`asset.begin` 带 sha256 时的去重命中判定,全库范围) */
|
|
90
|
+
findByDigest(sha256: string): Promise<AssetRecord | undefined>;
|
|
91
|
+
/** 记一行「这条消息引用了这份素材」;已经有这一行时返回 0 */
|
|
92
|
+
linkAsset(input: {
|
|
93
|
+
conversationId: string;
|
|
94
|
+
messageId: string;
|
|
95
|
+
assetId: string;
|
|
96
|
+
createdAt: number;
|
|
97
|
+
}): Promise<number>;
|
|
98
|
+
/** 这份素材被几行引用 */
|
|
99
|
+
countReferences(assetId: string): Promise<number>;
|
|
100
|
+
/** 归零才删(还有引用时返回 0,删不掉) */
|
|
101
|
+
deleteIfUnreferenced(assetId: string): Promise<number>;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* 厂商 file_id 缓存表的窄接口(`AssetRepository` 结构上满足)。
|
|
105
|
+
*
|
|
106
|
+
* 单列一个口子是为了让「缓存只是一张表」这件事在类型上就是真的:本服务只用这三个动作,
|
|
107
|
+
* 没有第二个地方会去改它。
|
|
108
|
+
*/
|
|
109
|
+
export interface AssetVendorRegistry {
|
|
110
|
+
getVendorFile(assetId: string, endpointId: string): Promise<VendorFileRecord | undefined>;
|
|
111
|
+
upsertVendorFile(input: VendorFileRecord): Promise<void>;
|
|
112
|
+
/** 这个素材的缓存行分布(决定这次是复用、内联还是上传) */
|
|
113
|
+
describeVendorFiles(assetId: string, endpointId: string): Promise<VendorFilePresence>;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* 实发模型的上下文:模型与它绑定的端点。
|
|
117
|
+
*
|
|
118
|
+
* 两者都不能只看 id 就猜:`file_id` 是端点维度的资源(传错端点会 not found),
|
|
119
|
+
* 「这个模型能不能看图」在模型定义上。谁解析出来由配置层决定,这里只收结果。
|
|
120
|
+
*/
|
|
121
|
+
export interface AttachmentModelContext {
|
|
122
|
+
model: Model | null;
|
|
123
|
+
endpoint: Endpoint | null;
|
|
124
|
+
}
|
|
125
|
+
/** 按模型 id 找模型与端点;找不到就回 `null` 字段(调用方按「没有能力信息」处理) */
|
|
126
|
+
export type AttachmentModelResolver = (modelId: string | null) => Promise<AttachmentModelContext> | AttachmentModelContext;
|
|
127
|
+
/** `ChatRunner` 注入点的入参(结构即契约,直接从那里取,不另定义一份) */
|
|
128
|
+
export type AttachmentPrepareContext = Parameters<AttachmentPreparer>[0];
|
|
129
|
+
/** `prepareAttachments` 的出参(同上) */
|
|
130
|
+
export type AttachmentPreparation = Awaited<ReturnType<AttachmentPreparer>>;
|
|
131
|
+
/** `ChatRunner` 的素材关系登记口(结构即契约,同上) */
|
|
132
|
+
export type MessageAssetLinkContext = Parameters<MessageAssetLinker>[0];
|
|
133
|
+
/** 素材服务依赖;由单根组装后注入 */
|
|
134
|
+
export interface AssetServiceOptions {
|
|
135
|
+
assets: AssetRegistry;
|
|
136
|
+
/** 厂商 file_id 的缓存表;不注入时每次发送都真上传(缓存那一层不生效) */
|
|
137
|
+
vendorFiles?: AssetVendorRegistry;
|
|
138
|
+
paths: HostPaths;
|
|
139
|
+
/**
|
|
140
|
+
* 按实发模型取模型与端点(F-H7 的判定依据)。不给时按「既没有视觉能力信息、也没有端点能力」
|
|
141
|
+
* 处理:图片会走内联,超过内联上限的会如实报失败。
|
|
142
|
+
*/
|
|
143
|
+
resolveModelContext?: AttachmentModelResolver;
|
|
144
|
+
/** 传给 SDK 转换器的依赖(测试替身上传;生产缺省走 OpenAI 兼容的 Files API) */
|
|
145
|
+
toolEnv?: ToolEnvDeps;
|
|
146
|
+
/** 时钟,缺省 `Date.now` */
|
|
147
|
+
now?: () => number;
|
|
148
|
+
/** 素材 id 生成,缺省 `crypto.randomUUID` */
|
|
149
|
+
newId?: () => string;
|
|
150
|
+
/** 降级 / 失败的事实上报口(日志或通知);缺省忽略 */
|
|
151
|
+
onProblem?: (problem: ProblemFact, context: string) => void;
|
|
152
|
+
}
|
|
153
|
+
export declare class AssetService {
|
|
154
|
+
private readonly options;
|
|
155
|
+
private readonly assets;
|
|
156
|
+
private readonly vendorFiles?;
|
|
157
|
+
private readonly now;
|
|
158
|
+
private readonly newId;
|
|
159
|
+
constructor(options: AssetServiceOptions);
|
|
160
|
+
/**
|
|
161
|
+
* 把收完的临时文件变成正式素材(`UploadReceiver` 的落定回调)。
|
|
162
|
+
*
|
|
163
|
+
* 顺序是「先改名、再登记行、失败就把文件删回去」:库里出现一行指向不存在的文件,
|
|
164
|
+
* 比文件多留一份更难收拾(取用时会变成「有引用但读不到」)。
|
|
165
|
+
*
|
|
166
|
+
* 登记走 upsert,键是 `sha256`(全库唯一):库里已经有同一份字节时(另一段对话传过、或
|
|
167
|
+
* 两个上传撞在一起),唯一约束会挡住插入,这时把刚写出去的文件删掉、回库里既有那一行 ——
|
|
168
|
+
* 全局去重的目的(整台机器只占一份磁盘)因此对两条路都成立。
|
|
169
|
+
*
|
|
170
|
+
* 「这段素材归哪段对话」不在这张表上:归属在消息落库那一刻写进 `conversation_assets`
|
|
171
|
+
* ({@link AssetService.linkMessageAssets}),所以这个入参里的 `conversationId` 不参与登记。
|
|
172
|
+
*
|
|
173
|
+
* 文件落到正式位置之后读一次文件头,把像素尺寸一并登记({@link readImageSizeFromFile}):
|
|
174
|
+
* 客户端拿 `width` / `height` 先排占位框,图显示出来时界面不会跳。量不到就是 `null`。
|
|
175
|
+
*/
|
|
176
|
+
finalizeUpload(request: UploadFinalizeRequest): Promise<AssetRef>;
|
|
177
|
+
/**
|
|
178
|
+
* 「库里已经有这张图了」时回既有那一行(`UploadReceiver.begin` 的去重判定)。
|
|
179
|
+
*
|
|
180
|
+
* 两个条件同时成立才算命中:同一个 `sha256`、同一个字节数。第二个条件看着多余
|
|
181
|
+
* (摘要相同就是同一份内容),但它是「客户端报的总长与宿主那一行对得上」的交叉校验:对不上
|
|
182
|
+
* 就当作没命中,让客户端老老实实传一遍。
|
|
183
|
+
*
|
|
184
|
+
* 去重是**全局**的:另一段对话传过的同一张图也算命中,命中之后两个对话各自在
|
|
185
|
+
* `conversation_assets` 里留一行引用,磁盘上仍然只有一份。
|
|
186
|
+
*/
|
|
187
|
+
findExistingAsset(input: {
|
|
188
|
+
sha256: string;
|
|
189
|
+
bytes: number;
|
|
190
|
+
}): Promise<AssetRef | null>;
|
|
191
|
+
/**
|
|
192
|
+
* 登记素材行失败的翻译。
|
|
193
|
+
*
|
|
194
|
+
* `assets` 这一行不挂任何外键(归属在关系表上),所以这里没有「对话不存在」这类可判别失败:
|
|
195
|
+
* 盘坏了、库坏了都是 internal,原因写进 detail 并进日志。
|
|
196
|
+
*/
|
|
197
|
+
private registrationError;
|
|
198
|
+
/**
|
|
199
|
+
* 消息落库那一刻:扫 `content` 里的 `__asset_id` 记关系行(同一 message + asset 只一行)。
|
|
200
|
+
*
|
|
201
|
+
* 关系行是「谁引用了它」的唯一记录,所以它跟消息行同一步写:之后撤回、删对话、删消息都由
|
|
202
|
+
* 外键级联删关系行,不需要谁去减计数。写不进去(素材 id 认不得、库出错)不让这一轮失败 ——
|
|
203
|
+
* 后果只是这份素材的引用少记一次,{@link AssetService.sweepUnreferenced} 因此会晚一步删。
|
|
204
|
+
*/
|
|
205
|
+
linkMessageAssets(context: MessageAssetLinkContext): Promise<number>;
|
|
206
|
+
/** 一条素材行(取用方要按 id 查 ref 时用) */
|
|
207
|
+
get(assetId: string): Promise<AssetRecord | undefined>;
|
|
208
|
+
/**
|
|
209
|
+
* 用户输入 + 已上传的素材 → 真正发给模型的内容(`ChatRunner` 的 `prepareAttachments`)。
|
|
210
|
+
*
|
|
211
|
+
* 口径(F-H7 逐条):
|
|
212
|
+
* - **文本段在前**:用户打的字始终是第一段,素材段按用户摆放的顺序跟在后面;
|
|
213
|
+
* - **按实发模型选传输方式**:能不能走 Files API 看端点声明、图片能不能进上下文看模型,
|
|
214
|
+
* 判定与转换交给 SDK 的 `fileToContentSection`(与工具链里那段代码同一份口径);
|
|
215
|
+
* - **失败要告警**:每张图各自的结局都记账(`deliveredAs` + `problem`),不合并成一句「成功」;
|
|
216
|
+
* - **全失败退回纯文本**:一张都没送出去时内容就是用户原来那段文字,
|
|
217
|
+
* 既没有凭空多出来的段,也没有假装发出去的占位。
|
|
218
|
+
*
|
|
219
|
+
* 同时给出**落库用**的那一份(`storedContent`):素材在那里是段上的 `__asset_id`。
|
|
220
|
+
* 一份内容、两种形状是故意的 —— 发给模型的带着厂商产物(`file_id` / base64),存下的带的是引用,
|
|
221
|
+
* 否则这条消息绑在「这一次发送所用的端点」上,换模型 / 换端点 / 重启之后就发了。
|
|
222
|
+
*/
|
|
223
|
+
prepareAttachments(context: AttachmentPrepareContext): Promise<AttachmentPreparation>;
|
|
224
|
+
/**
|
|
225
|
+
* 历史里的 `__asset_id` → 当前模型能吃的内容段(`ChatRunner` 的 `prepareHistory`)。
|
|
226
|
+
*
|
|
227
|
+
* 每轮发送前跑一次,因为「能不能吃」跟着模型 / 端点变:换个支持 Files API 的端点就会走文件引用,
|
|
228
|
+
* 换个不支持视觉的模型就退化成一句文字提示。还原不出来的那一段换成一句文字说明而不是把
|
|
229
|
+
* 引用原样交给厂商(那会让整条请求 400)。
|
|
230
|
+
*
|
|
231
|
+
* 无论有没有素材引用,内容都按 core 的字段白名单重建一次(`formatContent`):`__` 开头的键
|
|
232
|
+
* 是本机扩展,出网的那一份里不该有它们。没有引用时不读盘、不上传。
|
|
233
|
+
*/
|
|
234
|
+
resolveHistory(context: {
|
|
235
|
+
conversationId: string;
|
|
236
|
+
modelId: string | null;
|
|
237
|
+
messages: AgentNS.Message[];
|
|
238
|
+
}): Promise<AgentNS.Message[]>;
|
|
239
|
+
/**
|
|
240
|
+
* 按 id 取回素材内容(`asset.get`)。
|
|
241
|
+
*
|
|
242
|
+
* `thumb` 目前**等同原图**:本波不引入原生图像库,两档返回同一份字节与同一个 mime;
|
|
243
|
+
* 客户端要小图时按回包里的 `width` / `height`(未知为 `null`)自己缩。
|
|
244
|
+
*/
|
|
245
|
+
getAsset(input: {
|
|
246
|
+
assetId: string;
|
|
247
|
+
variant?: AssetVariant;
|
|
248
|
+
}): Promise<AssetGetResult>;
|
|
249
|
+
/**
|
|
250
|
+
* 一张素材的送达过程:读出字节来源、交给 SDK 转换、把结论译成 wire 上的「怎么走的」。
|
|
251
|
+
*
|
|
252
|
+
* 抛错不往上扔:一张图没送出去不该让整轮消息发不出去(F-H7 的「全失败退回纯文本」前提是
|
|
253
|
+
* 其余内容照发),所以这里收敛成一个 `dropped` 的结局并上报。
|
|
254
|
+
*
|
|
255
|
+
* `quiet` 是历史重放用的:重放是每一轮的内部动作,一张旧图今天没送出去不等于用户刚做错了什么,
|
|
256
|
+
* 不再往 `onProblem` 里塞一条(发送链上的告警留给“用户这一轮挂的图”)。
|
|
257
|
+
*/
|
|
258
|
+
private deliver;
|
|
259
|
+
/**
|
|
260
|
+
* 这次交给 SDK 的端点。
|
|
261
|
+
*
|
|
262
|
+
* 这个端点上已经有这个素材的缓存行(或者哪个端点上都没有)时原样给它:前者命中复用,
|
|
263
|
+
* 后者上传一次。只有「这个端点上没有、别的端点上有」才给 `null` —— 那是换厂商 / 换端点,
|
|
264
|
+
* 不往新端点重传,SDK 于是走内联 base64。
|
|
265
|
+
*/
|
|
266
|
+
private vendorEndpoint;
|
|
267
|
+
/**
|
|
268
|
+
* 交给 SDK 转换器的依赖:只把 `upload` 换成一个「先查缓存、miss 才真上传」的版本。
|
|
269
|
+
*
|
|
270
|
+
* SDK 那边不记任何 file_id,所以「同一张图不重复上传」由持有持久存储的这一层承担。
|
|
271
|
+
* 缓存行以 `(assetId, endpointId)` 为键:命中就拿那个 `vendorFileId`,miss 才发 HTTP 并写回。
|
|
272
|
+
*
|
|
273
|
+
* 每张素材各自拿一个闭包(不共享可变状态),并发发送两张不同的图不会互相写错行。
|
|
274
|
+
*/
|
|
275
|
+
private conversionDeps;
|
|
276
|
+
/**
|
|
277
|
+
* 素材 → `fileToContentSection` 的来源。
|
|
278
|
+
*
|
|
279
|
+
* 扩展名能推出同一个 MIME 时给路径(SDK 自己 stat + 读,省一次我们的读盘);
|
|
280
|
+
* 推不出来时给字节 + 显式 mime,否则 SDK 会因为「不认识的扩展名」直接拒掉一个我们明明知道类型的文件。
|
|
281
|
+
*/
|
|
282
|
+
private sourceOf;
|
|
283
|
+
/**
|
|
284
|
+
* 按 id 找模型与端点。
|
|
285
|
+
*
|
|
286
|
+
* 解析失败不让整轮崩掉:拿不到能力信息就按「没有端点能力、也没有模型信息」继续 ——
|
|
287
|
+
* 后果是图片走内联、超过内联上限的那张如实报「发不出去」,而不是整条消息失败。
|
|
288
|
+
*/
|
|
289
|
+
private resolveTarget;
|
|
290
|
+
/**
|
|
291
|
+
* 一批素材 id → 引用归零的那些:删行、删文件。
|
|
292
|
+
*
|
|
293
|
+
* 调用时机是「消息清理完之后」:撤回、删对话、删项目都已经交给外键把关系行级联删掉了,
|
|
294
|
+
* 这里再问一次「这张素材还剩几行引用」(`COUNT(*)`)——还剩就不动,归零才删。
|
|
295
|
+
* `assets` 那行的删除走 {@link AssetRegistry.deleteIfUnreferenced}(`RESTRICT` 是护栏:
|
|
296
|
+
* 判完之后又有人引用上时,物理删不掉)。
|
|
297
|
+
*
|
|
298
|
+
* 返回真正删掉的文件(数据根相对路径);行在而文件已经不在时不报错(清理要能重复执行)。
|
|
299
|
+
*/
|
|
300
|
+
sweepUnreferenced(assetIds: string[]): Promise<string[]>;
|
|
301
|
+
/**
|
|
302
|
+
* 只删文件。
|
|
303
|
+
*
|
|
304
|
+
* 入参是数据根下的相对路径(`assets` 行的 `path` 就是这个形状)。路径必须落在 `assets/` 里:
|
|
305
|
+
* 这是唯一会让本服务删掉库外文件的地方,越界的路径一律不碰。
|
|
306
|
+
*/
|
|
307
|
+
removeFiles(relativePaths: string[]): Promise<string[]>;
|
|
308
|
+
/** 数据根相对路径 → 绝对路径(已经是绝对路径的原样返回) */
|
|
309
|
+
private resolveAssetPath;
|
|
310
|
+
/** 只认 `assets/` 目录里面的路径(含 `..` 绕出去的都不认) */
|
|
311
|
+
private isInsideAssetsDir;
|
|
312
|
+
/**
|
|
313
|
+
* 一条给人看的事实(`LocalizedText` 的血缘:码 + 文案键 + 参数 + 当前语言下的句子)。
|
|
314
|
+
*
|
|
315
|
+
* 这里的语言用默认语言:素材转换发生在 `ChatRunner` 那一轮里,那一层拿不到「这是哪条连接」。
|
|
316
|
+
* 客户端要按自己连接的语言显示时,用 `messageKey` + `params` 重新渲染即可(D8 的存码不存句子)。
|
|
317
|
+
*/
|
|
318
|
+
private problem;
|
|
319
|
+
private report;
|
|
320
|
+
}
|
|
321
|
+
/** 素材行 → wire 上的引用(尺寸未知时为 `null`,客户端按「未知」排占位) */
|
|
322
|
+
export declare function toAssetRef(row: AssetRecord): AssetRef;
|
|
323
|
+
/**
|
|
324
|
+
* 素材 → 落库用的内容段。
|
|
325
|
+
*
|
|
326
|
+
* 图片是 `image_url`(`url` 留空),其余是 `file`(`filename` 记原始名字,`file_id` / `file_data`
|
|
327
|
+
* 都不出现);两种都只带本地扩展字段 `__asset_id`。真字段留空是故意的:库里存的是「引用哪份
|
|
328
|
+
* 素材」,而不是任何一种厂商产物。发送前由 {@link AssetService.resolveHistory} 按当时的模型
|
|
329
|
+
* 换成它能吃的真段。
|
|
330
|
+
*/
|
|
331
|
+
export declare function assetSectionOf(row: AssetRecord): LocalMessageContentSection;
|
|
332
|
+
/**
|
|
333
|
+
* 一条内容里的全部素材 id(按出现顺序、去重)。
|
|
334
|
+
*
|
|
335
|
+
* 撤回时的“回填输入框”(R62)与消息落库时的关系行都靠它复原「这条消息挂了哪几张图」:
|
|
336
|
+
* `assets` 行上不再记消息,`conversation_assets` 才是那个事实,而它的来源是 content。
|
|
337
|
+
*/
|
|
338
|
+
export declare function assetIdsOf(content: AgentNS.MessageContent | undefined): string[];
|