feat: support long text and safe attachment batches
Build web service image / build (push) Successful in 1m15s
Build web service image / build (push) Successful in 1m15s
This commit is contained in:
@@ -138,7 +138,9 @@ public sealed class AgentService(IAgentBackend backend, ServiceSecurity security
|
||||
{
|
||||
var kind = RequireText(request.Kind, "kind", 80);
|
||||
var accountId = RequireText(request.AccountId, "accountId", 200);
|
||||
var text = PrepareText(request.Text);
|
||||
var text = string.Equals(kind, "send-text", StringComparison.Ordinal)
|
||||
? PrepareLongText(request.Text)
|
||||
: PrepareText(request.Text);
|
||||
var idempotencyKey = RequireText(request.IdempotencyKey, "idempotencyKey", 128);
|
||||
if (!request.Confirmed) throw new ServiceException("ConfirmationRequired", 409, "Explicit send confirmation is required.");
|
||||
|
||||
@@ -271,6 +273,12 @@ public sealed class AgentService(IAgentBackend backend, ServiceSecurity security
|
||||
return value;
|
||||
}
|
||||
|
||||
private static string PrepareLongText(string? value)
|
||||
{
|
||||
try { return WechatTextInput.PrepareLongText(value ?? string.Empty); }
|
||||
catch (WxAgentException exception) { throw new ServiceException("InvalidRequest", 400, exception.Message); }
|
||||
}
|
||||
|
||||
private static string PrepareText(string? value)
|
||||
{
|
||||
try { return WechatTextInput.Prepare(value ?? string.Empty); }
|
||||
|
||||
@@ -841,7 +841,7 @@ public sealed class RemoteAgentHostedService(
|
||||
JsonElement Content,
|
||||
IReadOnlyList<RemoteReportingScope> ChatScopes);
|
||||
|
||||
private static async Task ReplayUnreportedResultsAsync(
|
||||
private async Task ReplayUnreportedResultsAsync(
|
||||
RemoteControlClient client,
|
||||
RemoteTaskLedger ledger,
|
||||
ReportingConfig reporting,
|
||||
@@ -851,7 +851,7 @@ public sealed class RemoteAgentHostedService(
|
||||
await ReportResultAsync(client, ledger, pending.Result, reporting, cancellationToken, pending.ReportingScopes);
|
||||
}
|
||||
|
||||
private static async Task ReportResultAsync(
|
||||
private async Task ReportResultAsync(
|
||||
RemoteControlClient client,
|
||||
RemoteTaskLedger ledger,
|
||||
RemoteTaskResult result,
|
||||
@@ -859,8 +859,16 @@ public sealed class RemoteAgentHostedService(
|
||||
CancellationToken cancellationToken,
|
||||
IReadOnlyList<RemoteReportingScope>? chatScopes = null)
|
||||
{
|
||||
await client.SendTaskResultAsync(result, reporting, chatScopes: chatScopes, cancellationToken: cancellationToken);
|
||||
ledger.MarkReported(result.TaskId);
|
||||
try
|
||||
{
|
||||
await client.SendTaskResultAsync(result, reporting, chatScopes: chatScopes, cancellationToken: cancellationToken);
|
||||
ledger.MarkReported(result.TaskId);
|
||||
}
|
||||
catch (RemoteClientException exception) when (exception.StatusCode == 404 && exception.Code == "TaskNotFound")
|
||||
{
|
||||
ledger.MarkResultTaskNotFound(result.TaskId);
|
||||
logger.LogWarning("Remote task result no longer exists on the control plane; result retained locally and will not be retried.");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<BackendSnapshot> ReadSnapshotAsync(RemoteAgentOptions remote, CancellationToken cancellationToken)
|
||||
@@ -972,8 +980,16 @@ public sealed class RemoteAgentHostedService(
|
||||
|| confirmed.ValueKind != JsonValueKind.True)
|
||||
return false;
|
||||
targetId = target.GetString() ?? "";
|
||||
text = content.GetString() ?? "";
|
||||
return targetId.Length is > 0 and <= 512 && text.Length is > 0 and <= 4000;
|
||||
if (targetId.Length is 0 or > 512) return false;
|
||||
try
|
||||
{
|
||||
text = WechatTextInput.PrepareLongText(content.GetString() ?? "");
|
||||
return true;
|
||||
}
|
||||
catch (WxAgentException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool GetBoolean(JsonElement value, string propertyName) =>
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
<label class="toggle"><input id="content" type="checkbox"> 显示正文 <span class="muted">需要 content 权限</span></label>
|
||||
</section>
|
||||
<section class="panel"><div class="section-heading"><h2>会话</h2><span class="muted">当前账号</span></div><div id="sessions" class="list"></div></section>
|
||||
<section class="panel reply-panel"><div class="section-heading"><h2>回复</h2><span id="replyCapability" class="muted">发送能力检查中…</span></div><div class="reply-form"><label for="replyTarget">目标会话</label><select id="replyTarget"><option value="">先选择会话</option></select><label for="replyText">文本</label><textarea id="replyText" rows="4" maxlength="4000" placeholder="输入要发送的文本" disabled></textarea><div class="reply-actions"><button id="sendReply" disabled>发送</button><span id="replyState" class="muted">写能力尚未开放。</span></div></div></section>
|
||||
<section class="panel reply-panel"><div class="section-heading"><h2>回复</h2><span id="replyCapability" class="muted">发送能力检查中…</span></div><div class="reply-form"><label for="replyTarget">目标会话</label><select id="replyTarget"><option value="">先选择会话</option></select><label for="replyText">文本</label><textarea id="replyText" rows="4" maxlength="20000" placeholder="输入要发送的文本" disabled></textarea><div class="reply-actions"><button id="sendReply" disabled>发送</button><span id="replyState" class="muted">写能力尚未开放。</span></div></div></section>
|
||||
<section class="panel"><div class="section-heading"><h2>可见消息</h2><span class="muted">只显示当前可读取的数据</span></div><div id="messages" class="list"></div></section>
|
||||
</section>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user