fix: clarify application retry prompts
This commit is contained in:
1 parent
1a496dd4fb
commit
5a8b8d75e5
12 files changed
+150
-29
No files matched your search
@@ -47,7 +47,7 @@ export function CloudAccessPanel({ slug, revision, publication, onChanged, activ
|
||||
<h2 className="font-medium">{access?.published_version ? '助手已准备好' : '准备好使用自己的助手了吗?'}</h2>
|
||||
<p className="mt-2 text-sm text-muted-foreground">{access?.published_version ? '应用最新修改后,新的对话会使用这次保存的要求。已有对话保留原来的版本。' : '开始使用后,只有你自己能用。以后还可以回来修改要求。'}</p>
|
||||
<p className="mt-2 text-xs text-muted-foreground">微信渠道和应用接入需要单独配置。</p>
|
||||
</div><Button disabled={busy || !access || (!publication.pending && publication.appliedRevision === revision)} onClick={() => void publish()}>{publication.busy ? '正在应用…' : publication.pending ? '重试本次发布' : publication.appliedRevision === revision ? '已应用最新修改' : access?.published_version ? '应用最新修改' : '确认开始使用'}</Button></div>
|
||||
</div><Button disabled={busy || !access || (!publication.pending && publication.appliedRevision === revision)} onClick={() => void publish()}>{publication.busy ? '正在应用…' : publication.pending ? '应用' : publication.appliedRevision === revision ? '已应用最新修改' : access?.published_version ? '应用最新修改' : '确认开始使用'}</Button></div>
|
||||
<p className="mt-4 text-sm leading-6">自己使用、API 调用、自动任务和个人微信渠道产生的费用,均从你的个人词元点数扣除。你可以随时停用智能体或撤销应用凭据。</p>
|
||||
{access?.published_version && <div className="mt-4 flex items-center gap-3 text-sm"><span>{access.enabled ? '智能体已启用' : '智能体已停用'}</span>
|
||||
<Button variant="outline" size="sm" disabled={busy} onClick={() => void act(() => cloudAgentsApi.call('setEnabled', { slug, enabled: !access.enabled }))}>
|
||||
|
||||
@@ -6,9 +6,10 @@ import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, D
|
||||
import { cloudAgentsApi } from '@/lib/cloud-agents-api';
|
||||
import { AppError } from '@/lib/error-model';
|
||||
import type { CloudPendingOperation } from '../../../shared/cloud-agents';
|
||||
import { APPLICATION_RETRY_MESSAGE, applicationErrorMessage } from './application-message';
|
||||
|
||||
const labels: Record<string, string> = {
|
||||
createAgent: '创建智能体', submit: '发送消息', preview: '预览草稿', resume: '继续任务', publish: '发布版本',
|
||||
createAgent: '创建智能体', submit: '发送消息', preview: '预览草稿', resume: '继续任务', publish: '应用设置',
|
||||
createApplication: '创建应用', createKey: '创建密钥', createKnowledge: '创建知识库', processKnowledge: '处理文档',
|
||||
createSchedule: '创建自动任务', runSchedule: '立即运行任务',
|
||||
importKnowledgeAttachment: '导入附件到知识库', createChild: '创建子智能体',
|
||||
@@ -23,6 +24,7 @@ export function CloudRecovery({ pending, onResolved, triggerContainer }: { pendi
|
||||
const [open, setOpen] = useState(false);
|
||||
const [busy, setBusy] = useState('');
|
||||
const [error, setError] = useState('');
|
||||
const [errorRecord, setErrorRecord] = useState('');
|
||||
const [notice, setNotice] = useState('');
|
||||
const [result, setResult] = useState<{ operation: string; name?: string; value: unknown } | null>(null);
|
||||
const inFlight = useRef(false);
|
||||
@@ -36,7 +38,7 @@ export function CloudRecovery({ pending, onResolved, triggerContainer }: { pendi
|
||||
const resolve = async (item: CloudPendingOperation, discard = false) => {
|
||||
if (inFlight.current || awaitingKeyClose.current) return;
|
||||
inFlight.current = true;
|
||||
setBusy(item.id); setError(''); setNotice('');
|
||||
setBusy(item.id); setError(''); setErrorRecord(''); setNotice('');
|
||||
try {
|
||||
const response = await cloudAgentsApi.resolvePending(item.id, discard);
|
||||
if (!alive.current) return;
|
||||
@@ -54,7 +56,9 @@ export function CloudRecovery({ pending, onResolved, triggerContainer }: { pendi
|
||||
onResolved();
|
||||
} catch (e) {
|
||||
if (!alive.current) return;
|
||||
const message = e instanceof Error ? e.message : '这次没能完成,请稍后再试。';
|
||||
setErrorRecord(item.id);
|
||||
const message = item.operation === 'publish' && !discard ? applicationErrorMessage(e)
|
||||
: e instanceof Error ? e.message : '这次没能完成,请稍后再试。';
|
||||
if (e instanceof AppError && e.details?.commandOutcome === 'definitive_failure') {
|
||||
setError(`${labels[item.operation] ?? '操作'}失败:${message}`);
|
||||
onResolved();
|
||||
@@ -84,16 +88,19 @@ export function CloudRecovery({ pending, onResolved, triggerContainer }: { pendi
|
||||
: retiredChannelOperations.has(item.operation) ? '旧版联系人权限操作(已移除)' : labels[item.operation] ?? '待处理记录'}</h3>
|
||||
<p className="agent-recovery-time">{new Date(item.created_at).toLocaleString()}</p>
|
||||
{item.operation === 'createAgent' && <p className="agent-recovery-record-help">还不确定有没有创建成功,先看看列表里有没有它。</p>}
|
||||
{item.operation === 'publish' && errorRecord !== item.id && <p className="agent-recovery-record-help">{APPLICATION_RETRY_MESSAGE}</p>}
|
||||
{typeof item.input.query === 'string' && <p className="mt-1 line-clamp-2 text-muted-foreground">{item.input.query}</p>}</div>
|
||||
{retiredChannelOperations.has(item.operation)
|
||||
? <Button size="sm" variant="ghost" disabled={actionsDisabled} onClick={() => void resolve(item)}>{busy === item.id ? '正在丢弃…' : '丢弃旧记录'}</Button>
|
||||
: <div className="agent-recovery-record-actions"><Button size="sm" disabled={actionsDisabled} onClick={() => void resolve(item)}>{busy === item.id ? '正在处理…' : '再试一次'}</Button>
|
||||
: <div className="agent-recovery-record-actions"><Button size="sm" disabled={actionsDisabled} onClick={() => void resolve(item)}>{item.operation === 'publish'
|
||||
? busy === item.id ? '正在应用…' : '应用' : busy === item.id ? '正在处理…' : '再试一次'}</Button>
|
||||
<Button size="sm" variant="ghost" disabled={actionsDisabled} onClick={() => void resolve(item, true)}>不再提醒</Button></div>}
|
||||
</article>)}
|
||||
{result && <div className="agent-recovery-result space-y-2"><p>{result.operation === 'createAgent'
|
||||
? `「${result.name || '智能体'}」创建成功,可以回到列表继续设置。`
|
||||
: result.operation === 'publish' ? '设置已应用。'
|
||||
: `${labels[result.operation] ?? '操作'}的结果已确认。`}{result.operation === 'createKey' && '请保存下面的密钥。关闭结果后将无法再次查看。'}</p>
|
||||
{result.operation !== 'createAgent' && <>
|
||||
{result.operation !== 'createAgent' && result.operation !== 'publish' && <>
|
||||
<details open={result.operation === 'createKey'}><summary className="cursor-pointer">查看结果</summary>
|
||||
<pre className="max-h-48 overflow-auto whitespace-pre-wrap break-all p-2 text-xs">{JSON.stringify(result.value, null, 2)}</pre></details>
|
||||
</>}
|
||||
|
||||
@@ -154,11 +154,11 @@ export function DraftEditor({ initial, recent, onBack, onSaved, startingPrompt,
|
||||
title={dirty ? '请先保存草稿,再应用修改' : '将已保存的修改应用到正在使用的助手'}
|
||||
onClick={() => void publication.publish()}>
|
||||
{publication.busy && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
|
||||
{publication.busy ? '正在应用…' : publication.pending ? '重试本次应用' : !dirty && publication.appliedRevision === saved.draft_revision ? '已应用' : '应用最新修改'}
|
||||
{publication.busy ? '正在应用…' : publication.pending ? '应用' : !dirty && publication.appliedRevision === saved.draft_revision ? '已应用' : '应用最新修改'}
|
||||
</Button>}
|
||||
{!saved.published_version && <Button className="min-h-10" variant="outline" disabled={busy || remote !== null || !publication.access} onClick={startUsing}>
|
||||
{publication.busy && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
|
||||
{publication.busy ? '正在开始…' : publication.pending ? '重试开始使用' : '开始使用'}
|
||||
{publication.busy ? '正在开始…' : publication.pending ? '应用' : '开始使用'}
|
||||
</Button>}
|
||||
</>}
|
||||
</header>
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import { AppError } from '@/lib/error-model';
|
||||
|
||||
export const APPLICATION_RETRY_MESSAGE = '网络可能不稳定,请再点一次「应用」。';
|
||||
|
||||
export function applicationErrorMessage(error: unknown): string {
|
||||
if (error instanceof AppError) {
|
||||
const status = error.details?.status;
|
||||
const rejected = error.details?.commandOutcome === 'definitive_failure'
|
||||
|| (typeof status === 'number' && status >= 400 && status < 500);
|
||||
if (!rejected && (error.code === 'NETWORK' || error.code === 'TIMEOUT'
|
||||
|| error.details?.backendCode === 'cloud_service_unavailable')) {
|
||||
return APPLICATION_RETRY_MESSAGE;
|
||||
}
|
||||
}
|
||||
return error instanceof Error ? error.message : '操作失败,请重试';
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { cloudAgentsApi } from '@/lib/cloud-agents-api';
|
||||
import type { CloudAccess, CloudAgentOperations } from '../../../shared/cloud-agents';
|
||||
import { applicationErrorMessage } from './application-message';
|
||||
|
||||
type Publication = CloudAgentOperations['publish']['output'];
|
||||
type PublishInput = { operation_id: string; expected_revision: number };
|
||||
@@ -52,7 +53,7 @@ export function useCloudPublication(slug: string, revision: number, onPublished:
|
||||
onPublished(result);
|
||||
await refresh();
|
||||
} catch (failure) {
|
||||
if (alive.current) setError(errorText(failure));
|
||||
if (alive.current) setError(applicationErrorMessage(failure));
|
||||
} finally {
|
||||
publishing.current = false;
|
||||
if (alive.current) setBusy(false);
|
||||
|
||||
Reference in new issue
Block a user