feat(sandbox): update sandbox status messages and improve loading feedback

- Modified Docker run commands in CI workflows to include the `-direct` flag for enhanced server operation.
- Removed outdated loading status message during sandbox preparation and added new messages for improved user feedback.
- Introduced a loading message for waiting on AI responses, enhancing the user experience during sandbox execution.
- Refactored identity handling in stream processing to streamline message management.

Made-with: Cursor
This commit is contained in:
Max 2026-03-15 13:52:38 +08:00
parent a5c8109db8
commit 89e5840490
7 changed files with 50 additions and 34 deletions

View file

@ -1142,7 +1142,7 @@ jobs:
-v /tmp/kubeconfig-tai-k8s.yml:/etc/tai/kubeconfig.yml:ro \
-e TAI_K8S_UPSTREAM="tcp://${K3D_IP}:6443" \
-e TAI_KUBECONFIG=/etc/tai/kubeconfig.yml \
yaoapp/tai:latest server \
yaoapp/tai:latest server -direct \
-grpc 0.0.0.0:19100 -http 0.0.0.0:8099 -vnc 0.0.0.0:16080 -k8s 0.0.0.0:16443
for i in $(seq 1 30); do

View file

@ -853,7 +853,7 @@ jobs:
-v /tmp/kubeconfig-tai-k8s.yml:/etc/tai/kubeconfig.yml:ro \
-e TAI_K8S_UPSTREAM="tcp://${K3D_IP}:6443" \
-e TAI_KUBECONFIG=/etc/tai/kubeconfig.yml \
yaoapp/tai:latest server \
yaoapp/tai:latest server -direct \
-grpc 0.0.0.0:19100 -http 0.0.0.0:8099 -vnc 0.0.0.0:16080 -k8s 0.0.0.0:16443
for i in $(seq 1 30); do

View file

@ -227,32 +227,30 @@ func (s *streamState) handleToolCall(data []byte) int {
tc := toolCallArray[0]
props = map[string]interface{}{}
hasStaticFields := false
hasIdentity := false
if id, ok := tc["id"].(string); ok {
props["id"] = id
hasStaticFields = true
hasIdentity = true
}
if typ, ok := tc["type"].(string); ok {
props["type"] = typ
hasStaticFields = true
hasIdentity = true
}
if index, ok := tc["index"].(float64); ok {
props["index"] = int(index)
hasStaticFields = true
}
if fn, ok := tc["function"].(map[string]interface{}); ok {
if name, ok := fn["name"].(string); ok {
props["name"] = name
hasStaticFields = true
hasIdentity = true
}
if args, ok := fn["arguments"].(string); ok {
props["arguments"] = args
}
}
if hasStaticFields {
if hasIdentity {
// First chunk with id/name/type: merge so all fields are applied.
// arguments="" is included but that's fine — subsequent appends build on it.
deltaAction = "merge"
} else if _, ok := props["arguments"]; ok {
// Subsequent chunk with only arguments fragment: append to arguments.

View file

@ -116,7 +116,6 @@ func (ast *Assistant) initSandboxV2(ctx *context.Context, opts *context.Options)
}
// 7. Runner.Prepare (standard context).
updateLoadingV2(ctx, loadingMsgID, "sandbox.configuring")
err = runner.Prepare(stdCtx, &sandboxTypes.PrepareRequest{
Computer: computer,
Config: cfg,

View file

@ -100,14 +100,14 @@ func init() {
"kb.chat.description": "Auto-created knowledge base collection for chat sessions",
// Sandbox: assistant/sandbox.go - Sandbox status messages
"sandbox.preparing": "Preparing sandbox environment",
"sandbox.preparing": "Getting things ready...",
"sandbox.ready": "Sandbox ready",
"sandbox.working": "Working on your request",
"sandbox.completed": "Completed",
"sandbox.failed": "Execution failed",
"sandbox.starting": "Starting sandbox environment",
"sandbox.configuring": "Configuring runtime environment",
"sandbox.pulling_image": "Pulling container image",
"sandbox.starting": "Setting up workspace...",
"sandbox.pulling_image": "Preparing environment (first time may take a moment)",
"sandbox.waiting_response": "Waiting for AI response...",
// Sandbox: claude/executor.go - Tool execution messages
"sandbox.tool.read": "Reading file",
@ -227,14 +227,14 @@ func init() {
"kb.chat.description": "自动为聊天会话创建的知识库集合",
// Sandbox: assistant/sandbox.go - Sandbox status messages
"sandbox.preparing": "正在准备沙箱环境",
"sandbox.ready": "沙箱环境就绪",
"sandbox.preparing": "正在准备...",
"sandbox.ready": "就绪",
"sandbox.working": "正在处理您的请求",
"sandbox.completed": "处理完成",
"sandbox.failed": "执行失败",
"sandbox.starting": "正在启动沙箱环境",
"sandbox.configuring": "正在配置运行环境",
"sandbox.pulling_image": "正在拉取容器镜像",
"sandbox.starting": "正在启动工作区...",
"sandbox.pulling_image": "正在准备运行环境(首次可能需要一点时间)",
"sandbox.waiting_response": "等待 AI 响应...",
// Sandbox: claude/executor.go - Tool execution messages
"sandbox.tool.read": "正在读取文件",
@ -382,14 +382,14 @@ func init() {
"kb.chat.description": "自动为聊天会话创建的知识库集合",
// Sandbox: assistant/sandbox.go - Sandbox status messages
"sandbox.preparing": "正在准备沙箱环境",
"sandbox.ready": "沙箱环境就绪",
"sandbox.preparing": "正在准备...",
"sandbox.ready": "就绪",
"sandbox.working": "正在处理您的请求",
"sandbox.completed": "处理完成",
"sandbox.failed": "执行失败",
"sandbox.starting": "正在启动沙箱环境",
"sandbox.configuring": "正在配置运行环境",
"sandbox.pulling_image": "正在拉取容器镜像",
"sandbox.starting": "正在启动工作区...",
"sandbox.pulling_image": "正在准备运行环境(首次可能需要一点时间)",
"sandbox.waiting_response": "等待 AI 响应...",
// Sandbox: claude/executor.go - Tool execution messages
"sandbox.tool.read": "正在读取文件",

View file

@ -78,6 +78,10 @@ func parseStreamJSON(_ context.Context, stdout io.ReadCloser, handler message.St
toolIndex++
if handler != nil {
if messageStarted {
handler(message.ChunkMessageEnd, nil)
messageStarted = false
}
if !toolBlockActive {
startData := message.EventMessageStartData{
MessageID: fmt.Sprintf("sandbox-tool-%d", time.Now().UnixNano()),
@ -119,6 +123,7 @@ func parseStreamJSON(_ context.Context, stdout io.ReadCloser, handler message.St
if toolBlockActive {
handler(message.ChunkMessageEnd, nil)
toolBlockActive = false
messageStarted = false
}
if !messageStarted {
startData := message.EventMessageStartData{

View file

@ -8,6 +8,7 @@ import (
"time"
agentContext "github.com/yaoapp/yao/agent/context"
"github.com/yaoapp/yao/agent/i18n"
"github.com/yaoapp/yao/agent/output/message"
"github.com/yaoapp/yao/agent/sandbox/v2/types"
infra "github.com/yaoapp/yao/sandbox/v2"
@ -106,6 +107,19 @@ func ExecuteSandboxStream(
}
}()
if req.LoadingMsgID != "" {
waitMsg := &message.Message{
MessageID: req.LoadingMsgID,
Delta: true,
DeltaAction: message.DeltaReplace,
Type: message.TypeLoading,
Props: map[string]any{
"message": i18n.T(ctx.Locale, "sandbox.waiting_response"),
},
}
ctx.Send(waitMsg)
}
var textContent []byte
loadingClosed := false
wrappedHandler := func(chunkType message.StreamChunkType, data []byte) int {