Merge pull request #4 from x-evor/release/v1.1.4

Release/v1.1.4
This commit is contained in:
Haitao Pan 2026-06-05 18:42:32 +08:00 committed by GitHub
commit e65fd7c3ac
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 34 additions and 80 deletions

View File

@ -93,17 +93,18 @@ func TestReassociateOpenClawTaskDerivesRuntimeBudgetWithoutExplicitBudget(t *tes
sess := server.reassociateOpenClawTask(tc.params)
if sess == nil {
t.Fatal("expected reassociated session")
}
sess.mu.Lock()
gotTaskBudget := sess.task.RuntimeBudgetMinutes
gotRecordBudget := sess.openClaw.RuntimeBudgetMinutes
sess.mu.Unlock()
} else {
sess.mu.Lock()
gotTaskBudget := sess.task.RuntimeBudgetMinutes
gotRecordBudget := sess.openClaw.RuntimeBudgetMinutes
sess.mu.Unlock()
if gotTaskBudget != tc.want {
t.Fatalf("task RuntimeBudgetMinutes = %d, want %d", gotTaskBudget, tc.want)
}
if gotRecordBudget != tc.want {
t.Fatalf("record RuntimeBudgetMinutes = %d, want %d", gotRecordBudget, tc.want)
if gotTaskBudget != tc.want {
t.Fatalf("task RuntimeBudgetMinutes = %d, want %d", gotTaskBudget, tc.want)
}
if gotRecordBudget != tc.want {
t.Fatalf("record RuntimeBudgetMinutes = %d, want %d", gotRecordBudget, tc.want)
}
}
})
}

View File

@ -445,6 +445,9 @@ func (o *SessionOrchestrator) completeOpenClawTask(
}
if output == "" {
output = firstNonEmptyString(waitPayload, "output", "message", "summary", "assistantText", "text")
if output == "" {
output = firstNonEmptyString(shared.AsMap(waitPayload["result"]), "output", "message", "summary", "assistantText", "text")
}
}
noDisplayableOutput := strings.TrimSpace(output) == ""
if output == "" {
@ -471,6 +474,9 @@ func (o *SessionOrchestrator) completeOpenClawTask(
"runtimeBudgetMinutes": record.RuntimeBudgetMinutes,
}
mergeOpenClawArtifactPayload(result, waitPayload)
if nestedResult := shared.AsMap(waitPayload["result"]); len(nestedResult) > 0 {
mergeOpenClawArtifactPayload(result, nestedResult)
}
if collector != nil {
mergeOpenClawArtifactPayload(result, collector.artifactPayload())
}

View File

@ -1336,18 +1336,6 @@ func applyOpenClawArtifactContractResult(result map[string]any, contract openCla
}
}
func openClawArtifactExtension(artifact map[string]any) string {
for _, key := range []string{"relativePath", "path", "label", "name"} {
value := strings.TrimSpace(shared.StringArg(artifact, key, ""))
if value == "" {
continue
}
if extension := strings.TrimPrefix(strings.ToLower(filepath.Ext(value)), "."); extension != "" {
return extension
}
}
return ""
}
func mergeOpenClawArtifactPayload(result map[string]any, source map[string]any) {
if result == nil || len(source) == 0 {

View File

@ -471,8 +471,7 @@ func TestExecuteSessionTaskExplicitGatewayUsesResolvedGatewayProvider(t *testing
})
if rpcErr == nil {
t.Fatalf("expected gateway connectivity rpc error, got response: %v", response)
}
if rpcErr.Message == "GATEWAY_PROVIDER_REQUIRED" {
} else if rpcErr.Message == "GATEWAY_PROVIDER_REQUIRED" {
t.Fatalf("expected resolved gateway provider to be reused, got %q", rpcErr.Message)
}
}
@ -1213,8 +1212,7 @@ func TestExecuteSessionTaskGatewaySurfacesOpenClawChatSendError(t *testing.T) {
})
if rpcErr == nil {
t.Fatalf("expected OpenClaw chat.send error, got response: %#v", response)
}
if rpcErr.Code != -32002 || !strings.Contains(rpcErr.Message, "openclaw chat failed") {
} else if rpcErr.Code != -32002 || !strings.Contains(rpcErr.Message, "openclaw chat failed") {
t.Fatalf("expected surfaced chat.send failure, got %#v", rpcErr)
}
if got := gateway.Methods(); !sameMethods(got, []string{"connect", "xworkmate.artifacts.prepare", "chat.send"}) {
@ -1288,8 +1286,7 @@ func TestExecuteSessionTaskGatewayReturnsStructuredOpenClawSocketCloseAfterRetry
})
if rpcErr == nil {
t.Fatalf("expected OpenClaw socket close error, got response: %#v", response)
}
if rpcErr.Code != -32002 || !strings.Contains(rpcErr.Message, "OPENCLAW_GATEWAY_SOCKET_CLOSED") {
} else if rpcErr.Code != -32002 || !strings.Contains(rpcErr.Message, "OPENCLAW_GATEWAY_SOCKET_CLOSED") {
t.Fatalf("expected structured socket close failure, got %#v", rpcErr)
}
data := shared.AsMap(rpcErr.Data)
@ -2369,8 +2366,7 @@ func TestExecuteSessionTaskGatewayRejectsOversizedInlineAttachmentBeforeChatSend
})
if rpcErr == nil {
t.Fatalf("expected oversized attachment rpc error, got response: %#v", response)
}
if !strings.Contains(rpcErr.Message, "OPENCLAW_ATTACHMENT_FILE_TOO_LARGE") {
} else if !strings.Contains(rpcErr.Message, "OPENCLAW_ATTACHMENT_FILE_TOO_LARGE") {
t.Fatalf("expected attachment size error, got %#v", rpcErr)
}
if gateway.ChatSendCount() != 0 {
@ -2500,8 +2496,7 @@ func TestExecuteSessionTaskDefaultsExplicitGatewayToOpenClaw(t *testing.T) {
})
if rpcErr == nil {
t.Fatal("expected gateway connectivity error")
}
if rpcErr.Message == "GATEWAY_PROVIDER_REQUIRED" {
} else if rpcErr.Message == "GATEWAY_PROVIDER_REQUIRED" {
t.Fatalf("expected openclaw default from routing result, got %#v", rpcErr)
}
}
@ -3317,38 +3312,6 @@ func sameMethods(got []string, want []string) bool {
return true
}
func responseArtifactMaps(t *testing.T, response map[string]any) []map[string]any {
t.Helper()
if artifacts, ok := response["artifacts"].([]map[string]any); ok {
return artifacts
}
raw, ok := response["artifacts"].([]any)
if !ok {
t.Fatalf("expected artifacts payload, got %#v", response["artifacts"])
}
artifacts := make([]map[string]any, 0, len(raw))
for _, item := range raw {
artifacts = append(artifacts, shared.AsMap(item))
}
return artifacts
}
func mustStepMaps(t *testing.T, value any) []map[string]any {
t.Helper()
switch typed := value.(type) {
case []map[string]any:
return typed
case []any:
steps := make([]map[string]any, 0, len(typed))
for _, item := range typed {
steps = append(steps, shared.AsMap(item))
}
return steps
default:
t.Fatalf("expected step map list, got %#v", value)
return nil
}
}
func waitForCondition(t *testing.T, condition func() bool) {
t.Helper()
@ -3500,8 +3463,7 @@ func TestExecuteSessionTaskKeepsRemoteWorkspaceHintOutOfLocalCWD(t *testing.T) {
sess := server.sessions["session-remote-hint"]
if sess == nil {
t.Fatal("expected session state to be retained")
}
if sess.control.RequestedWorkingDir != workspaceDir {
} else if sess.control.RequestedWorkingDir != workspaceDir {
t.Fatalf("expected local requested cwd %q, got %q", workspaceDir, sess.control.RequestedWorkingDir)
}
if sess.control.RemoteWorkingDirHint != "/owners/local/user/demo/threads/main" {
@ -3530,8 +3492,7 @@ func TestExecuteSessionTaskRequiresRouting(t *testing.T) {
})
if rpcErr == nil {
t.Fatalf("expected routing-required error")
}
if rpcErr.Message != "ROUTING_REQUIRED" {
} else if rpcErr.Message != "ROUTING_REQUIRED" {
t.Fatalf("expected ROUTING_REQUIRED, got %#v", rpcErr)
}
}
@ -3566,8 +3527,7 @@ func TestExecuteSessionMessageMissingProviderStateReturnsContinuationUnavailable
})
if rpcErr == nil {
t.Fatalf("expected continuation unavailable error, got response %#v", response)
}
if rpcErr.Code != -32002 || !strings.Contains(rpcErr.Message, "SESSION_CONTINUATION_UNAVAILABLE") {
} else if rpcErr.Code != -32002 || !strings.Contains(rpcErr.Message, "SESSION_CONTINUATION_UNAVAILABLE") {
t.Fatalf("expected structured continuation error, got %#v", rpcErr)
}
data := shared.AsMap(rpcErr.Data)
@ -3607,8 +3567,7 @@ func TestExecuteSessionTaskComplexRequestNoLongerPromotesToMultiAgent(t *testing
})
if rpcErr == nil {
t.Fatalf("expected gateway-not-connected error, got response %#v", response)
}
if strings.Contains(rpcErr.Message, "multi-agent") {
} else if strings.Contains(rpcErr.Message, "multi-agent") {
t.Fatalf("expected no multi-agent path, got rpc error: %v", rpcErr)
}
}

View File

@ -78,7 +78,7 @@ func (xi *XdotoolInjector) Start() error {
}
if err := cmd.Start(); err != nil {
stdin.Close()
_ = stdin.Close()
return fmt.Errorf("failed to start xdotool process: %w", err)
}
@ -144,7 +144,7 @@ func (xi *XdotoolInjector) Inject(event InputEvent) error {
// Try to restart if pipe is broken
log.Printf("xdotool write error: %v. Attempting to restart injector.", err)
xi.isStarted = false
xi.stdin.Close()
_ = xi.stdin.Close()
if restartErr := xi.Start(); restartErr == nil {
_, _ = xi.stdin.Write([]byte(cmdStr))
}

View File

@ -56,19 +56,19 @@ func (s *Service) StartSession(sessionID string, cfg PipelineConfig, iceServers
// 2. Initialize WebRTC server
webrtcSrv, err := NewWebRTCServer(injector)
if err != nil {
injector.Close()
_ = injector.Close()
return nil, fmt.Errorf("failed to create WebRTC server: %w", err)
}
if err := webrtcSrv.InitPeerConnection(iceServers); err != nil {
injector.Close()
_ = injector.Close()
return nil, fmt.Errorf("failed to init peer connection: %w", err)
}
// Start local UDP listener for GStreamer RTP packets
if err := webrtcSrv.StartRTPReceiver(cfg.Port); err != nil {
webrtcSrv.Close()
injector.Close()
_ = injector.Close()
return nil, fmt.Errorf("failed to start RTP receiver: %w", err)
}
@ -76,7 +76,7 @@ func (s *Service) StartSession(sessionID string, cfg PipelineConfig, iceServers
pipeline := NewPipelineManager()
if err := pipeline.Start(cfg); err != nil {
webrtcSrv.Close()
injector.Close()
_ = injector.Close()
return nil, fmt.Errorf("failed to start capture pipeline: %w", err)
}

View File

@ -59,13 +59,13 @@ func (w *WebRTCServer) InitPeerConnection(iceServers []string) error {
"xworkmate-desktop",
)
if err != nil {
pc.Close()
_ = pc.Close()
return fmt.Errorf("failed to create video track: %w", err)
}
_, err = pc.AddTrack(videoTrack)
if err != nil {
pc.Close()
_ = pc.Close()
return fmt.Errorf("failed to add video track: %w", err)
}