Consolidate approved trial client updates and preserve composer runtime
This commit is contained in:
1 parent
154a21a295
commit
020b36673d
32 files changed
+3668
-947
No files matched your search
@@ -60,6 +60,7 @@ function projectMutation(value: unknown): unknown {
|
||||
...(source.worker && typeof source.worker === 'object' ? { worker: copy(source.worker, ['account_id', 'address']) } : {}),
|
||||
...(source.wechat && typeof source.wechat === 'object' ? { wechat: copy(source.wechat, ['status', 'message']) } : {}),
|
||||
...(source.disconnected === undefined ? {} : { disconnected: source.disconnected === true }),
|
||||
...(source.unbound === undefined ? {} : { unbound: source.unbound === true }),
|
||||
};
|
||||
}
|
||||
function projectWechat(value: unknown): unknown {
|
||||
@@ -187,7 +188,7 @@ function projectSchedules(value: unknown): unknown { return { jobs: list(object(
|
||||
function validateChannelInput(operation: string, args: ObjectRecord): void {
|
||||
const channelOperations = new Set([
|
||||
'createChannelAccount', 'routeChannelAccount', 'enableChannelAccount', 'pauseChannelAccount',
|
||||
'disconnectChannelAccount', 'channelAccountWechatBindStart', 'channelAccountWechatBindStatus',
|
||||
'disconnectChannelAccount', 'unbindChannelAccount', 'channelAccountWechatBindStart', 'channelAccountWechatBindStatus',
|
||||
'channelAccountWechatBindVerification', 'channelAccountWechatBindAccount', 'channelAccountWechatUnbind',
|
||||
'channelAccountOperation',
|
||||
'createChannelBinding', 'switchChannelBindingAgent', 'enableChannelBinding', 'pauseChannelBinding',
|
||||
@@ -211,6 +212,9 @@ function validateChannelInput(operation: string, args: ObjectRecord): void {
|
||||
if (operation === 'routeChannelAccount' && args.target_agent_slug !== null
|
||||
&& (typeof args.target_agent_slug !== 'string' || !/^ml-[a-f0-9]{32}$/.test(args.target_agent_slug))) throw new Error('invalid_id');
|
||||
if (operation === 'routeChannelAccount' && args.target_agent_slug === null && args.enabled !== false) throw new Error('invalid_input');
|
||||
if (operation === 'unbindChannelAccount' && (typeof args.channel_account_id !== 'string'
|
||||
|| typeof args.operation_id !== 'string' || !Number.isSafeInteger(args.expected_revision)
|
||||
|| Number(args.expected_revision) < 0)) throw new Error('invalid_input');
|
||||
if (operation === 'switchChannelBindingAgent' && (typeof args.target_agent_slug !== 'string' || !/^ml-[a-f0-9]{32}$/.test(args.target_agent_slug))) throw new Error('invalid_id');
|
||||
if (operation === 'wechatBindStart' && typeof args.force !== 'boolean') throw new Error('invalid_input');
|
||||
if (operation === 'channelAccountWechatBindStart' && typeof args.force !== 'boolean') throw new Error('invalid_input');
|
||||
@@ -294,6 +298,7 @@ const operations: Record<keyof CloudAgentOperations, OperationSpec> = {
|
||||
enableChannelAccount: { method: 'POST', path: '/channel-accounts/:channel_account_id/enable', body: ['operation_id', 'expected_revision'], output: ['channel'], project: projectMutation },
|
||||
pauseChannelAccount: { method: 'POST', path: '/channel-accounts/:channel_account_id/pause', body: ['operation_id', 'expected_revision'], output: ['channel'], project: projectMutation },
|
||||
disconnectChannelAccount: { method: 'POST', path: '/channel-accounts/:channel_account_id/disconnect', body: ['operation_id', 'expected_revision'], output: ['channel', 'wechat', 'disconnected'], project: projectMutation },
|
||||
unbindChannelAccount: { method: 'POST', path: '/channel-accounts/:channel_account_id/unbind', body: ['operation_id', 'expected_revision'], output: ['channel', 'wechat', 'disconnected', 'unbound'], project: projectMutation },
|
||||
channelAccountWechatBindStart: { method: 'POST', path: '/channel-accounts/:channel_account_id/wechat-bind/start', body: ['operation_id', 'force'], output: ['session_key', 'status', 'message', 'qrcode_url'], project: projectWechat },
|
||||
channelAccountWechatBindStatus: { method: 'GET', path: '/channel-accounts/:channel_account_id/wechat-bind/status', query: { session_key: 'session_key' }, output: ['session_key', 'status', 'message', 'qrcode_url'], project: projectWechat },
|
||||
channelAccountWechatBindVerification: { method: 'POST', path: '/channel-accounts/:channel_account_id/wechat-bind/verification', body: ['operation_id', 'session_key', 'verify_code'], output: ['session_key', 'status', 'message', 'qrcode_url'], project: projectWechat },
|
||||
|
||||
@@ -49,11 +49,13 @@ const MESSAGES: Record<string, string> = {
|
||||
knowledge_processing: '知识库有文档正在处理,请完成后再维护',
|
||||
agent_archived: '请先从归档恢复智能体,再启用',
|
||||
attachment_too_large: '附件最大支持 5 MB',
|
||||
attachment_invalid: '附件内容或文件名称无效,请重新选择文件',
|
||||
avatar_too_large: '头像图片不能超过 5 MB',
|
||||
avatar_invalid: '请选择有效的 PNG、JPEG、WebP 或 GIF 图片(最大 5 MB)',
|
||||
download_failed: '文件保存失败,请重试',
|
||||
channel_not_found: '微信渠道不存在或已解绑',
|
||||
channel_operation_conflict: '微信渠道正在处理其他操作,请稍后查看状态',
|
||||
channel_operation_unconfirmed: '微信绑定的变更尚未确认,请查看待确认操作后重试',
|
||||
channel_request_invalid: '微信渠道请求无效,请刷新后重试',
|
||||
channel_rate_limited: '微信渠道操作过于频繁,请稍后重试',
|
||||
channel_conversation_not_found: '微信会话不存在或已关闭',
|
||||
@@ -423,9 +425,20 @@ export class CloudAgentsModule {
|
||||
let plan;
|
||||
try { plan = operationPlan(value); }
|
||||
catch { throw new CloudAgentsError(422, 'invalid_input'); }
|
||||
const invoke = async () => plan.project(await this.request(plan.path, plan.method, plan.body, plan.cloud === 'ws'));
|
||||
const invoke = async () => {
|
||||
const result = plan.project(await this.request(plan.path, plan.method, plan.body, plan.cloud === 'ws'));
|
||||
if (plan.operation === 'unbindChannelAccount') {
|
||||
const value = record(result), channel = record(value.channel);
|
||||
if (value.unbound !== true || value.disconnected !== true || channel.id !== plan.input.channel_account_id
|
||||
|| channel.enabled !== false || channel.target_agent_slug !== null || channel.health !== 'login_required') {
|
||||
// Keep the original operation in recovery until both routing and login are confirmed removed.
|
||||
throw new CloudAgentsError(503, 'channel_operation_unconfirmed');
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
const recoverable = ['submit', 'preview', 'resume', 'publish', 'createApplication', 'createKey', 'createKnowledge', 'processKnowledge', 'createSchedule', 'runSchedule', 'importKnowledgeAttachment', 'createChild',
|
||||
'createChannelAccount', 'routeChannelAccount', 'enableChannelAccount', 'pauseChannelAccount', 'disconnectChannelAccount',
|
||||
'createChannelAccount', 'routeChannelAccount', 'enableChannelAccount', 'pauseChannelAccount', 'disconnectChannelAccount', 'unbindChannelAccount',
|
||||
'channelAccountWechatBindStart', 'channelAccountWechatBindVerification', 'channelAccountWechatUnbind',
|
||||
'createChannelBinding', 'switchChannelBindingAgent', 'enableChannelBinding', 'pauseChannelBinding', 'disconnectChannelBinding',
|
||||
'wechatBindStart', 'wechatBindVerification', 'wechatUnbind',
|
||||
@@ -489,8 +502,46 @@ export class CloudAgentsModule {
|
||||
}
|
||||
|
||||
async upload(): Promise<CloudUpload | null> {
|
||||
const binding = getWorksSquareAccountBinding();
|
||||
if (!binding) throw new CloudAgentsError(401, 'session_expired');
|
||||
const body = await this.pickUpload();
|
||||
this.requireCurrent(binding);
|
||||
if (!body) return null;
|
||||
const result = await this.uploadTemporaryAttachment(body);
|
||||
this.requireCurrent(binding);
|
||||
return result;
|
||||
}
|
||||
|
||||
async uploadBytes(value: unknown): Promise<CloudUpload> {
|
||||
const binding = getWorksSquareAccountBinding();
|
||||
if (!binding) throw new CloudAgentsError(401, 'session_expired');
|
||||
const input = record(value);
|
||||
const limit = 5 * 1024 * 1024;
|
||||
if (Object.keys(input).some(key => !['bytesBase64', 'fileName', 'mimeType'].includes(key))
|
||||
|| typeof input.fileName !== 'string' || !input.fileName.trim() || input.fileName.length > 255
|
||||
|| /[\\/]/.test(input.fileName) || Array.from(input.fileName).some(char => char.charCodeAt(0) < 32 || char.charCodeAt(0) === 127)
|
||||
|| ['.', '..'].includes(input.fileName)
|
||||
|| typeof input.mimeType !== 'string' || input.mimeType.length > 127
|
||||
|| !/^[a-zA-Z0-9][a-zA-Z0-9!#$&^_.+-]*\/[a-zA-Z0-9][a-zA-Z0-9!#$&^_.+-]*$/.test(input.mimeType)
|
||||
|| typeof input.bytesBase64 !== 'string' || !input.bytesBase64) {
|
||||
throw new CloudAgentsError(422, 'attachment_invalid', 'definitive_failure');
|
||||
}
|
||||
if (input.bytesBase64.length > Math.ceil(limit / 3) * 4) throw new CloudAgentsError(422, 'attachment_too_large', 'definitive_failure');
|
||||
if (input.bytesBase64.length % 4 !== 0 || !/^[A-Za-z0-9+/]+={0,2}$/.test(input.bytesBase64)) {
|
||||
throw new CloudAgentsError(422, 'attachment_invalid', 'definitive_failure');
|
||||
}
|
||||
const bytes = Buffer.from(input.bytesBase64, 'base64');
|
||||
if (!bytes.length || bytes.toString('base64') !== input.bytesBase64) throw new CloudAgentsError(422, 'attachment_invalid', 'definitive_failure');
|
||||
if (bytes.length > limit) throw new CloudAgentsError(422, 'attachment_too_large', 'definitive_failure');
|
||||
const body = new FormData();
|
||||
body.append('file', new Blob([new Uint8Array(bytes)], { type: input.mimeType }), input.fileName);
|
||||
this.requireCurrent(binding);
|
||||
const result = await this.uploadTemporaryAttachment(body);
|
||||
this.requireCurrent(binding);
|
||||
return result;
|
||||
}
|
||||
|
||||
private async uploadTemporaryAttachment(body: FormData): Promise<CloudUpload> {
|
||||
const result = record(await this.request('/api/makelore/attachments/tmp', 'POST', body));
|
||||
return {
|
||||
object_name: textField(result.object_name, 2048), file_name: textField(result.file_name, 255),
|
||||
|
||||
Reference in new issue
Block a user