fix(arch): remove expectedArtifactExtensions from bridge payload
This commit is contained in:
parent
fc965b3ec4
commit
e6437d9be7
@ -599,7 +599,7 @@ func TestProbeOpenClawTaskFailsAfterMaxAllowedSilentDuration(t *testing.T) {
|
|||||||
}
|
}
|
||||||
sess.mu.Unlock()
|
sess.mu.Unlock()
|
||||||
|
|
||||||
result := orchestrator.probeOpenClawTask(context.Background(), sess, nil)
|
result := orchestrator.probeOpenClawTask(context.Background(), sess, nil, false)
|
||||||
|
|
||||||
if got := result["status"]; got != string(TaskStateFailed) {
|
if got := result["status"]; got != string(TaskStateFailed) {
|
||||||
t.Fatalf("expected failed status after silent duration, got %#v", result)
|
t.Fatalf("expected failed status after silent duration, got %#v", result)
|
||||||
|
|||||||
@ -82,15 +82,6 @@ func TestReassociateOpenClawTaskDerivesRuntimeBudgetWithoutExplicitBudget(t *tes
|
|||||||
},
|
},
|
||||||
want: openClawShortTaskMinutes,
|
want: openClawShortTaskMinutes,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "required final artifact",
|
|
||||||
params: map[string]any{
|
|
||||||
"runId": "run-pdf",
|
|
||||||
"artifactScope": "tasks/main/run-pdf",
|
|
||||||
"expectedArtifactExtensions": []any{"pdf"},
|
|
||||||
},
|
|
||||||
want: openClawLongTaskMinutes,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
|
|||||||
@ -75,7 +75,7 @@ func openClawTaskRuntimePolicy(params map[string]any, chatParams map[string]any,
|
|||||||
}) {
|
}) {
|
||||||
return "complex_chain_task", openClawComplexTaskMinutes
|
return "complex_chain_task", openClawComplexTaskMinutes
|
||||||
}
|
}
|
||||||
if len(contract.ExpectedArtifactExtensions) > 0 || openClawMessageContainsAny(lower, []string{
|
if openClawMessageContainsAny(lower, []string{
|
||||||
"生成文件", "同步生成文件", "产物", "附件", "pdf", "docx", "ppt", "pptx", "markdown", ".md", "png", "jpg", "jpeg", "mp4",
|
"生成文件", "同步生成文件", "产物", "附件", "pdf", "docx", "ppt", "pptx", "markdown", ".md", "png", "jpg", "jpeg", "mp4",
|
||||||
}) || len(shared.ListArg(params, "attachments"))+len(shared.ListArg(params, "inlineAttachments")) >= 2 {
|
}) || len(shared.ListArg(params, "attachments"))+len(shared.ListArg(params, "inlineAttachments")) >= 2 {
|
||||||
return "long_task", openClawLongTaskMinutes
|
return "long_task", openClawLongTaskMinutes
|
||||||
@ -106,10 +106,6 @@ func openClawRunningTaskResult(record *OpenClawTaskRecord) map[string]any {
|
|||||||
if record.PreparedArtifact != nil {
|
if record.PreparedArtifact != nil {
|
||||||
applyOpenClawPreparedArtifactToResult(result, record.PreparedArtifact)
|
applyOpenClawPreparedArtifactToResult(result, record.PreparedArtifact)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(record.ArtifactContract.ExpectedArtifactExtensions) > 0 {
|
|
||||||
result["expectedArtifactExtensions"] = append([]string(nil), record.ArtifactContract.ExpectedArtifactExtensions...)
|
|
||||||
}
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,7 +164,7 @@ func (o *SessionOrchestrator) startOpenClawTaskMonitor(sess *session) {
|
|||||||
o.failOpenClawTask(sess, "TASK_SLA_EXPIRED", "OpenClaw task exceeded its runtime SLA")
|
o.failOpenClawTask(sess, "TASK_SLA_EXPIRED", "OpenClaw task exceeded its runtime SLA")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
o.probeOpenClawTask(context.Background(), sess, nil)
|
o.probeOpenClawTask(context.Background(), sess, nil, false)
|
||||||
sess.mu.Lock()
|
sess.mu.Lock()
|
||||||
state = sess.task.State
|
state = sess.task.State
|
||||||
sess.mu.Unlock()
|
sess.mu.Unlock()
|
||||||
@ -243,7 +239,7 @@ func (o *SessionOrchestrator) failOpenClawTask(sess *session, code string, messa
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *SessionOrchestrator) probeOpenClawTask(ctx context.Context, sess *session, notify func(map[string]any)) map[string]any {
|
func (o *SessionOrchestrator) probeOpenClawTask(ctx context.Context, sess *session, notify func(map[string]any), waitForArtifacts bool) map[string]any {
|
||||||
if sess == nil {
|
if sess == nil {
|
||||||
return map[string]any{"status": "not_found"}
|
return map[string]any{"status": "not_found"}
|
||||||
}
|
}
|
||||||
@ -294,13 +290,17 @@ func (o *SessionOrchestrator) probeOpenClawTask(ctx context.Context, sess *sessi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
waitStarted := time.Now()
|
waitStarted := time.Now()
|
||||||
|
waitParams := map[string]any{
|
||||||
|
"runId": runID,
|
||||||
|
"timeoutMs": openClawTaskProbeTimeoutMs,
|
||||||
|
}
|
||||||
|
if waitForArtifacts {
|
||||||
|
waitParams["waitForArtifacts"] = true
|
||||||
|
}
|
||||||
waitResult := o.openClawGatewayRequestWithRetry(
|
waitResult := o.openClawGatewayRequestWithRetry(
|
||||||
gatewayProvider,
|
gatewayProvider,
|
||||||
"agent.wait",
|
"agent.wait",
|
||||||
map[string]any{
|
waitParams,
|
||||||
"runId": runID,
|
|
||||||
"timeoutMs": openClawTaskProbeTimeoutMs,
|
|
||||||
},
|
|
||||||
openClawTaskProbeTimeout,
|
openClawTaskProbeTimeout,
|
||||||
notifyWithCollection,
|
notifyWithCollection,
|
||||||
)
|
)
|
||||||
@ -475,15 +475,6 @@ func (o *SessionOrchestrator) completeOpenClawTask(
|
|||||||
mergeOpenClawArtifactPayload(result, collector.artifactPayload())
|
mergeOpenClawArtifactPayload(result, collector.artifactPayload())
|
||||||
}
|
}
|
||||||
applyOpenClawPreparedArtifactToResult(result, record.PreparedArtifact)
|
applyOpenClawPreparedArtifactToResult(result, record.PreparedArtifact)
|
||||||
snapshotPayload := o.openClawArtifactCollectAndSnapshot(
|
|
||||||
record.GatewayProviderID,
|
|
||||||
record.ChatParams,
|
|
||||||
record.RunID,
|
|
||||||
record.ArtifactSinceUnixMs,
|
|
||||||
record.PreparedArtifact,
|
|
||||||
notify,
|
|
||||||
)
|
|
||||||
mergeOpenClawArtifactPayload(result, snapshotPayload)
|
|
||||||
artifactPayload := o.openClawArtifactExport(
|
artifactPayload := o.openClawArtifactExport(
|
||||||
record.GatewayProviderID,
|
record.GatewayProviderID,
|
||||||
record.ChatParams,
|
record.ChatParams,
|
||||||
@ -493,6 +484,15 @@ func (o *SessionOrchestrator) completeOpenClawTask(
|
|||||||
notify,
|
notify,
|
||||||
)
|
)
|
||||||
mergeOpenClawArtifactPayload(result, artifactPayload)
|
mergeOpenClawArtifactPayload(result, artifactPayload)
|
||||||
|
snapshotPayload := o.openClawArtifactCollectAndSnapshot(
|
||||||
|
record.GatewayProviderID,
|
||||||
|
record.ChatParams,
|
||||||
|
record.RunID,
|
||||||
|
record.ArtifactSinceUnixMs,
|
||||||
|
record.PreparedArtifact,
|
||||||
|
notify,
|
||||||
|
)
|
||||||
|
mergeOpenClawArtifactPayload(result, snapshotPayload)
|
||||||
result[openClawArtifactExportAttemptedField] = true
|
result[openClawArtifactExportAttemptedField] = true
|
||||||
exportedCount := openClawArtifactPayloadCount(result)
|
exportedCount := openClawArtifactPayloadCount(result)
|
||||||
logOpenClawArtifactSync(record.GatewayProviderID, record.SessionKey, record.RunID, "export", record.PreparedArtifact != nil, exportedCount > 0, exportedCount == 0)
|
logOpenClawArtifactSync(record.GatewayProviderID, record.SessionKey, record.RunID, "export", record.PreparedArtifact != nil, exportedCount > 0, exportedCount == 0)
|
||||||
|
|||||||
@ -9,7 +9,6 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -686,9 +685,6 @@ func openClawArtifactSystemProvenanceReceipt(
|
|||||||
"- Do not report completion until requested final deliverables are present in artifactDirectory.",
|
"- Do not report completion until requested final deliverables are present in artifactDirectory.",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if len(contract.ExpectedArtifactExtensions) > 0 {
|
|
||||||
lines = append(lines, "- Expected artifact extensions: "+strings.Join(contract.ExpectedArtifactExtensions, ", "))
|
|
||||||
}
|
|
||||||
return strings.Join(lines, "\n")
|
return strings.Join(lines, "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -699,42 +695,10 @@ func shellSingleQuote(value string) string {
|
|||||||
type openClawArtifactContract struct {
|
type openClawArtifactContract struct {
|
||||||
TaskLoadClass string
|
TaskLoadClass string
|
||||||
ComplexLongChain bool
|
ComplexLongChain bool
|
||||||
ExpectedArtifactExtensions []string
|
ExpectedArtifactDirs []string
|
||||||
SourceMessage string
|
SourceMessage string
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
openClawDottedExtensionPattern = regexp.MustCompile(`(?i)\.([a-z0-9]{2,5})\b`)
|
|
||||||
openClawFormatTokenPattern = regexp.MustCompile(`(?i)\b([a-z0-9]{2,5})\s*(?:格式|文件|产物|artifact|file|output)`)
|
|
||||||
openClawOutputTokenPattern = regexp.MustCompile(`(?i)(?:输出|导出|生成|制作)\s*([a-z0-9]{2,5})`)
|
|
||||||
openClawKnownArtifactExtensions = map[string]bool{
|
|
||||||
"csv": true,
|
|
||||||
"doc": true,
|
|
||||||
"docx": true,
|
|
||||||
"epub": true,
|
|
||||||
"gif": true,
|
|
||||||
"html": true,
|
|
||||||
"jpeg": true,
|
|
||||||
"jpg": true,
|
|
||||||
"json": true,
|
|
||||||
"md": true,
|
|
||||||
"mov": true,
|
|
||||||
"mp3": true,
|
|
||||||
"mp4": true,
|
|
||||||
"pdf": true,
|
|
||||||
"png": true,
|
|
||||||
"ppt": true,
|
|
||||||
"pptx": true,
|
|
||||||
"svg": true,
|
|
||||||
"txt": true,
|
|
||||||
"wav": true,
|
|
||||||
"webm": true,
|
|
||||||
"webp": true,
|
|
||||||
"xls": true,
|
|
||||||
"xlsx": true,
|
|
||||||
"zip": true,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func openClawArtifactContractForParams(params map[string]any, chatParams map[string]any) openClawArtifactContract {
|
func openClawArtifactContractForParams(params map[string]any, chatParams map[string]any) openClawArtifactContract {
|
||||||
metadata := shared.AsMap(params["metadata"])
|
metadata := shared.AsMap(params["metadata"])
|
||||||
@ -744,122 +708,33 @@ func openClawArtifactContractForParams(params map[string]any, chatParams map[str
|
|||||||
message = openClawCurrentTurnMessage(params)
|
message = openClawCurrentTurnMessage(params)
|
||||||
}
|
}
|
||||||
lowerMessage := strings.ToLower(message)
|
lowerMessage := strings.ToLower(message)
|
||||||
expected := normalizeOpenClawExtensionList(shared.ListArg(metadata, "expectedArtifactExtensions"))
|
expectedDirs := normalizeOpenClawDirList(shared.ListArg(metadata, "expectedArtifactDirs"))
|
||||||
if len(expected) == 0 {
|
|
||||||
expected = extractOpenClawExtensionMentions(lowerMessage)
|
|
||||||
}
|
|
||||||
expected = appendOpenClawUniqueExtensions(expected, inferOpenClawArtifactExtensions(lowerMessage, expected)...)
|
|
||||||
complex := taskLoadClass == "complex_long_chain_task" || isOpenClawLongArtifactTask(lowerMessage)
|
complex := taskLoadClass == "complex_long_chain_task" || isOpenClawLongArtifactTask(lowerMessage)
|
||||||
return openClawArtifactContract{
|
return openClawArtifactContract{
|
||||||
TaskLoadClass: taskLoadClass,
|
TaskLoadClass: taskLoadClass,
|
||||||
ComplexLongChain: complex,
|
ComplexLongChain: complex,
|
||||||
ExpectedArtifactExtensions: expected,
|
ExpectedArtifactDirs: expectedDirs,
|
||||||
SourceMessage: message,
|
SourceMessage: message,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func appendOpenClawUniqueExtensions(base []string, values ...string) []string {
|
func normalizeOpenClawDirList(values []any) []string {
|
||||||
result := append([]string(nil), base...)
|
if len(values) == 0 {
|
||||||
seen := map[string]bool{}
|
return nil
|
||||||
for _, extension := range result {
|
|
||||||
seen[extension] = true
|
|
||||||
}
|
}
|
||||||
for _, value := range values {
|
|
||||||
extension := normalizeOpenClawArtifactExtension(value)
|
|
||||||
if extension == "" || seen[extension] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
seen[extension] = true
|
|
||||||
result = append(result, extension)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func inferOpenClawArtifactExtensions(lowerMessage string, existing []string) []string {
|
|
||||||
result := make([]string, 0, 2)
|
|
||||||
hasExisting := func(extension string) bool {
|
|
||||||
for _, value := range existing {
|
|
||||||
if value == extension {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
hasDocumentOutput := openClawMessageContainsAny(lowerMessage, []string{
|
|
||||||
"pdf", "ppt", "pptx", "powerpoint", "doc", "docx", "文档",
|
|
||||||
})
|
|
||||||
if openClawMessageContainsAny(lowerMessage, []string{
|
|
||||||
"video", "mp4", "remotion", "ffmpeg", "render", "视频", "渲染",
|
|
||||||
}) && !hasExisting("mp4") {
|
|
||||||
result = append(result, "mp4")
|
|
||||||
}
|
|
||||||
if len(existing) == 0 && !hasDocumentOutput && openClawMessageContainsAny(lowerMessage, []string{
|
|
||||||
"image", "images", "png", "jpg", "jpeg", "图片", "生成图", "配图", "插图", "多图片",
|
|
||||||
}) {
|
|
||||||
result = append(result, "png")
|
|
||||||
}
|
|
||||||
if len(existing) == 0 && openClawMessageContainsAny(lowerMessage, []string{
|
|
||||||
"文案", "小红书", "微信文章", "头条号", "copywriting", "资讯", "新闻", "报告", "news",
|
|
||||||
}) {
|
|
||||||
result = append(result, "md")
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func normalizeOpenClawExtensionList(values []any) []string {
|
|
||||||
result := make([]string, 0, len(values))
|
result := make([]string, 0, len(values))
|
||||||
seen := map[string]bool{}
|
seen := map[string]bool{}
|
||||||
for _, value := range values {
|
for _, value := range values {
|
||||||
extension := normalizeOpenClawArtifactExtension(fmt.Sprint(value))
|
dir := strings.TrimSpace(fmt.Sprint(value))
|
||||||
if extension == "" || seen[extension] {
|
if dir == "" || seen[dir] {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
seen[extension] = true
|
seen[dir] = true
|
||||||
result = append(result, extension)
|
result = append(result, dir)
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func extractOpenClawExtensionMentions(message string) []string {
|
|
||||||
result := make([]string, 0, 4)
|
|
||||||
add := func(value string) {
|
|
||||||
extension := normalizeOpenClawArtifactExtension(value)
|
|
||||||
if extension == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, existing := range result {
|
|
||||||
if existing == extension {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result = append(result, extension)
|
|
||||||
}
|
|
||||||
for _, match := range openClawDottedExtensionPattern.FindAllStringSubmatch(message, -1) {
|
|
||||||
if len(match) > 1 {
|
|
||||||
add(match[1])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, match := range openClawFormatTokenPattern.FindAllStringSubmatch(message, -1) {
|
|
||||||
if len(match) > 1 {
|
|
||||||
add(match[1])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, match := range openClawOutputTokenPattern.FindAllStringSubmatch(message, -1) {
|
|
||||||
if len(match) > 1 {
|
|
||||||
add(match[1])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func normalizeOpenClawArtifactExtension(value string) string {
|
|
||||||
extension := strings.TrimPrefix(strings.ToLower(strings.TrimSpace(value)), ".")
|
|
||||||
if extension == "" || !openClawKnownArtifactExtensions[extension] {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return extension
|
|
||||||
}
|
|
||||||
|
|
||||||
func openClawChatSendParams(
|
func openClawChatSendParams(
|
||||||
params map[string]any,
|
params map[string]any,
|
||||||
turnID string,
|
turnID string,
|
||||||
@ -1450,41 +1325,6 @@ func applyOpenClawArtifactContractResult(result map[string]any, contract openCla
|
|||||||
if strings.TrimSpace(contract.TaskLoadClass) != "" {
|
if strings.TrimSpace(contract.TaskLoadClass) != "" {
|
||||||
result["taskLoadClass"] = contract.TaskLoadClass
|
result["taskLoadClass"] = contract.TaskLoadClass
|
||||||
}
|
}
|
||||||
if len(contract.ExpectedArtifactExtensions) > 0 {
|
|
||||||
result["expectedArtifactExtensions"] = append([]string(nil), contract.ExpectedArtifactExtensions...)
|
|
||||||
}
|
|
||||||
if !parseBool(result["success"]) || len(contract.ExpectedArtifactExtensions) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
remoteWorkingDirectory := strings.TrimSpace(shared.StringArg(result, "remoteWorkingDirectory", ""))
|
|
||||||
artifacts := extractArtifactPayloads(result, remoteWorkingDirectory)
|
|
||||||
found := map[string]bool{}
|
|
||||||
for _, artifact := range artifacts {
|
|
||||||
if extension := openClawArtifactExtension(artifact); extension != "" {
|
|
||||||
found[extension] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
missing := make([]string, 0, len(contract.ExpectedArtifactExtensions))
|
|
||||||
for _, extension := range contract.ExpectedArtifactExtensions {
|
|
||||||
if !found[extension] {
|
|
||||||
missing = append(missing, extension)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(missing) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
message := openClawRequiredArtifactMissingText
|
|
||||||
if len(artifacts) > 0 {
|
|
||||||
message = "openclaw returned partial artifacts without required final deliverables"
|
|
||||||
}
|
|
||||||
result["success"] = false
|
|
||||||
result["status"] = string(TaskStateFailed)
|
|
||||||
result["code"] = "OPENCLAW_REQUIRED_ARTIFACT_MISSING"
|
|
||||||
result["error"] = message
|
|
||||||
result["message"] = message
|
|
||||||
result["output"] = message
|
|
||||||
result["summary"] = message
|
|
||||||
result["missingArtifactExtensions"] = missing
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func openClawArtifactExtension(artifact map[string]any) string {
|
func openClawArtifactExtension(artifact map[string]any) string {
|
||||||
|
|||||||
@ -37,12 +37,12 @@ func TestCapabilitiesExposeBuiltInProductionProviderCatalog(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
capabilities := response
|
capabilities := response
|
||||||
if capabilities["multiAgent"] != true {
|
if capabilities["multiAgent"] != false {
|
||||||
t.Fatalf("expected multiAgent capability to be enabled, got %#v", capabilities["multiAgent"])
|
t.Fatalf("expected multiAgent capability to be disabled, got %#v", capabilities["multiAgent"])
|
||||||
}
|
}
|
||||||
nestedCapabilities := shared.AsMap(capabilities["capabilities"])
|
nestedCapabilities := shared.AsMap(capabilities["capabilities"])
|
||||||
if nestedCapabilities["multi_agent"] != true {
|
if nestedCapabilities["multi_agent"] != false {
|
||||||
t.Fatalf("expected nested multi_agent capability to be enabled, got %#v", nestedCapabilities["multi_agent"])
|
t.Fatalf("expected nested multi_agent capability to be disabled, got %#v", nestedCapabilities["multi_agent"])
|
||||||
}
|
}
|
||||||
targets, ok := capabilities["availableExecutionTargets"].([]any)
|
targets, ok := capabilities["availableExecutionTargets"].([]any)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|||||||
@ -562,7 +562,7 @@ func TestExecuteSessionTaskGatewayAutoConnectsLocalOpenClaw(t *testing.T) {
|
|||||||
if gateway.ArtifactExportCount() != 1 {
|
if gateway.ArtifactExportCount() != 1 {
|
||||||
t.Fatalf("expected one OpenClaw artifact export sync after run, got %d", gateway.ArtifactExportCount())
|
t.Fatalf("expected one OpenClaw artifact export sync after run, got %d", gateway.ArtifactExportCount())
|
||||||
}
|
}
|
||||||
if got := gateway.Methods(); !sameMethods(got, []string{"connect", "xworkmate.artifacts.prepare", "chat.send", "agent.wait", "xworkmate.artifacts.collect-and-snapshot", "xworkmate.artifacts.export"}) {
|
if got := gateway.Methods(); !sameMethods(got, []string{"connect", "xworkmate.artifacts.prepare", "chat.send", "agent.wait", "xworkmate.artifacts.export", "xworkmate.artifacts.collect-and-snapshot"}) {
|
||||||
t.Fatalf("expected connect, artifact prepare, chat.send, agent.wait, then artifact export, got %#v", got)
|
t.Fatalf("expected connect, artifact prepare, chat.send, agent.wait, then artifact export, got %#v", got)
|
||||||
}
|
}
|
||||||
client := gateway.LastConnectClient()
|
client := gateway.LastConnectClient()
|
||||||
@ -617,45 +617,6 @@ func TestOpenClawAgentWaitTimeoutUsesOneHourForLongPDFImageWork(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOpenClawArtifactContractInfersRemoteScenarioDeliverables(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
text string
|
|
||||||
want []string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "video",
|
|
||||||
text: "围绕 AI Agent 身份演进 测试制作视频",
|
|
||||||
want: []string{"mp4"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "image",
|
|
||||||
text: "Preferred skills:\n- it-infra-continuous-png\n\n连续制作 7 张图片",
|
|
||||||
want: []string{"png"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "copywriting",
|
|
||||||
text: "输出小红书风格、微信文章风格、头条号风格文案",
|
|
||||||
want: []string{"md"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "news",
|
|
||||||
text: "采集今天最新 AI Agent 资讯并输出报告",
|
|
||||||
want: []string{"md"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
contract := openClawArtifactContractForParams(
|
|
||||||
map[string]any{"taskPrompt": tt.text},
|
|
||||||
map[string]any{"message": tt.text},
|
|
||||||
)
|
|
||||||
if !slices.Equal(contract.ExpectedArtifactExtensions, tt.want) {
|
|
||||||
t.Fatalf("expected expected extensions %#v, got %#v", tt.want, contract.ExpectedArtifactExtensions)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGatewayRequestForwardsOpenClawSkillsStatus(t *testing.T) {
|
func TestGatewayRequestForwardsOpenClawSkillsStatus(t *testing.T) {
|
||||||
gateway := newAcpFakeOpenClawGateway(t)
|
gateway := newAcpFakeOpenClawGateway(t)
|
||||||
@ -809,48 +770,6 @@ func TestExecuteSessionTaskGatewayNoDisplayableOutputFails(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExecuteSessionTaskGatewayComplexArtifactContractAcceptsRequiredFinalArtifact(t *testing.T) {
|
|
||||||
gateway := newAcpFakeOpenClawGateway(t)
|
|
||||||
defer gateway.Close()
|
|
||||||
|
|
||||||
t.Setenv("GATEWAY_RPC_URL", gateway.URL())
|
|
||||||
t.Setenv("BRIDGE_AUTH_TOKEN", "bridge-token")
|
|
||||||
|
|
||||||
server := NewServer()
|
|
||||||
response, rpcErr := server.executeSessionTask(task{
|
|
||||||
req: shared.RPCRequest{
|
|
||||||
Method: "session.start",
|
|
||||||
Params: map[string]any{
|
|
||||||
"sessionId": "session-openclaw-complex-pdf",
|
|
||||||
"threadId": "thread-openclaw-complex-pdf",
|
|
||||||
"taskPrompt": "make pdf artifact",
|
|
||||||
"workingDirectory": t.TempDir(),
|
|
||||||
"metadata": map[string]any{
|
|
||||||
"taskLoadClass": "complex_long_chain_task",
|
|
||||||
"expectedArtifactExtensions": []any{"pdf"},
|
|
||||||
},
|
|
||||||
"routing": map[string]any{
|
|
||||||
"routingMode": "explicit",
|
|
||||||
"explicitExecutionTarget": "gateway",
|
|
||||||
"preferredGatewayProviderId": "openclaw",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if rpcErr != nil {
|
|
||||||
t.Fatalf("expected gateway response, got rpc error: %#v", rpcErr)
|
|
||||||
}
|
|
||||||
if got := response["success"]; got != true {
|
|
||||||
t.Fatalf("expected required PDF artifact to satisfy contract, got %#v", response)
|
|
||||||
}
|
|
||||||
artifacts := responseArtifactMaps(t, response)
|
|
||||||
if len(artifacts) != 1 || artifacts[0]["relativePath"] != "exports/final.pdf" {
|
|
||||||
t.Fatalf("expected final PDF artifact, got %#v", artifacts)
|
|
||||||
}
|
|
||||||
if got := response["expectedArtifactExtensions"]; fmt.Sprint(got) != "[pdf]" {
|
|
||||||
t.Fatalf("expected artifact extension diagnostics, got %#v", response)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestExecuteSessionTaskGatewayFailsArtifactContractAfterWaitFailure(t *testing.T) {
|
func TestExecuteSessionTaskGatewayFailsArtifactContractAfterWaitFailure(t *testing.T) {
|
||||||
gateway := newAcpFakeOpenClawGateway(t)
|
gateway := newAcpFakeOpenClawGateway(t)
|
||||||
@ -1027,130 +946,12 @@ func TestExecuteSessionMessageGatewayUsesOpenClawChatSend(t *testing.T) {
|
|||||||
if gateway.ArtifactExportCount() != 1 {
|
if gateway.ArtifactExportCount() != 1 {
|
||||||
t.Fatalf("expected one OpenClaw artifact export sync after message run, got %d", gateway.ArtifactExportCount())
|
t.Fatalf("expected one OpenClaw artifact export sync after message run, got %d", gateway.ArtifactExportCount())
|
||||||
}
|
}
|
||||||
if got := gateway.Methods(); !sameMethods(got, []string{"connect", "xworkmate.artifacts.prepare", "chat.send", "agent.wait", "xworkmate.artifacts.collect-and-snapshot", "xworkmate.artifacts.export"}) {
|
if got := gateway.Methods(); !sameMethods(got, []string{"connect", "xworkmate.artifacts.prepare", "chat.send", "agent.wait", "xworkmate.artifacts.export", "xworkmate.artifacts.collect-and-snapshot"}) {
|
||||||
t.Fatalf("expected connect, artifact prepare, chat.send, agent.wait, then artifact export, got %#v", got)
|
t.Fatalf("expected connect, artifact prepare, chat.send, agent.wait, then artifact export, got %#v", got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExecuteSessionTaskMultiAgentModes(t *testing.T) {
|
|
||||||
cases := []struct {
|
|
||||||
name string
|
|
||||||
mode string
|
|
||||||
maxTurns int
|
|
||||||
wantSteps int
|
|
||||||
}{
|
|
||||||
{name: "sequence", mode: "sequence", wantSteps: 2},
|
|
||||||
{name: "parallel", mode: "parallel", wantSteps: 2},
|
|
||||||
{name: "race", mode: "race", wantSteps: 1},
|
|
||||||
{name: "conversation", mode: "conversation", maxTurns: 2, wantSteps: 2},
|
|
||||||
}
|
|
||||||
for _, tc := range cases {
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
|
||||||
server := NewServer()
|
|
||||||
opencodeProvider := newExternalSingleAgentProvider(t, "opencode", "opencode-output")
|
|
||||||
defer opencodeProvider.Close()
|
|
||||||
geminiProvider := newExternalSingleAgentProvider(t, "gemini", "gemini-output")
|
|
||||||
defer geminiProvider.Close()
|
|
||||||
setTestBridgeProvider(server, syncedProvider{
|
|
||||||
ProviderID: "opencode",
|
|
||||||
Label: "OpenCode",
|
|
||||||
Endpoint: opencodeProvider.URL,
|
|
||||||
Enabled: true,
|
|
||||||
})
|
|
||||||
setTestBridgeProvider(server, syncedProvider{
|
|
||||||
ProviderID: "gemini",
|
|
||||||
Label: "Gemini",
|
|
||||||
Endpoint: geminiProvider.URL,
|
|
||||||
Enabled: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
routing := map[string]any{
|
|
||||||
"orchestrationMode": tc.mode,
|
|
||||||
"steps": []any{
|
|
||||||
map[string]any{"providerId": "opencode", "prompt": "first"},
|
|
||||||
map[string]any{"providerId": "gemini", "prompt": "second sees {{previousOutput}}"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if tc.mode == "conversation" {
|
|
||||||
routing["maxTurns"] = tc.maxTurns
|
|
||||||
routing["participants"] = []any{"opencode", "gemini"}
|
|
||||||
}
|
|
||||||
response, rpcErr := server.executeSessionTask(task{
|
|
||||||
req: shared.RPCRequest{
|
|
||||||
Method: "session.start",
|
|
||||||
Params: map[string]any{
|
|
||||||
"sessionId": "session-multi-" + tc.name,
|
|
||||||
"threadId": "thread-multi-" + tc.name,
|
|
||||||
"taskPrompt": "coordinate two agents",
|
|
||||||
"workingDirectory": t.TempDir(),
|
|
||||||
"multiAgent": true,
|
|
||||||
"routing": routing,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if rpcErr != nil {
|
|
||||||
t.Fatalf("expected multi-agent response, got rpc error: %#v", rpcErr)
|
|
||||||
}
|
|
||||||
if !parseBool(response["success"]) {
|
|
||||||
t.Fatalf("expected successful multi-agent response, got %#v", response)
|
|
||||||
}
|
|
||||||
if got := response["resolvedExecutionTarget"]; got != "multi-agent" {
|
|
||||||
t.Fatalf("expected multi-agent execution target, got %#v", response)
|
|
||||||
}
|
|
||||||
if got := response["orchestrationMode"]; got != tc.mode {
|
|
||||||
t.Fatalf("expected orchestration mode %q, got %#v", tc.mode, response)
|
|
||||||
}
|
|
||||||
steps := mustStepMaps(t, response["steps"])
|
|
||||||
if len(steps) != tc.wantSteps {
|
|
||||||
t.Fatalf("expected %d step results, got %#v", tc.wantSteps, steps)
|
|
||||||
}
|
|
||||||
if output := strings.TrimSpace(shared.StringArg(response, "output", "")); output == "" {
|
|
||||||
t.Fatalf("expected displayable multi-agent output, got %#v", response)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestExecuteSessionTaskMultiAgentProviderUnavailableIsResultFailure(t *testing.T) {
|
|
||||||
server := NewServer()
|
|
||||||
providerServer := newExternalSingleAgentProvider(t, "opencode", "opencode-output")
|
|
||||||
defer providerServer.Close()
|
|
||||||
setTestBridgeProvider(server, syncedProvider{
|
|
||||||
ProviderID: "opencode",
|
|
||||||
Label: "OpenCode",
|
|
||||||
Endpoint: providerServer.URL,
|
|
||||||
Enabled: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
response, rpcErr := server.executeSessionTask(task{
|
|
||||||
req: shared.RPCRequest{
|
|
||||||
Method: "session.start",
|
|
||||||
Params: map[string]any{
|
|
||||||
"sessionId": "session-multi-missing",
|
|
||||||
"threadId": "thread-multi-missing",
|
|
||||||
"taskPrompt": "coordinate agents",
|
|
||||||
"workingDirectory": t.TempDir(),
|
|
||||||
"multiAgent": true,
|
|
||||||
"routing": map[string]any{
|
|
||||||
"orchestrationMode": "parallel",
|
|
||||||
"steps": []any{
|
|
||||||
map[string]any{"providerId": "opencode", "prompt": "first"},
|
|
||||||
map[string]any{"providerId": "missing", "prompt": "second"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if rpcErr != nil {
|
|
||||||
t.Fatalf("expected normalized failure result, got rpc error: %#v", rpcErr)
|
|
||||||
}
|
|
||||||
if parseBool(response["success"]) || response["status"] != "failed" {
|
|
||||||
t.Fatalf("expected failed multi-agent result, got %#v", response)
|
|
||||||
}
|
|
||||||
if !strings.Contains(strings.TrimSpace(shared.StringArg(response, "error", "")), "missing: provider unavailable") {
|
|
||||||
t.Fatalf("expected provider unavailable error, got %#v", response)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestInternalJobsSubmitCompletesAndReportsStats(t *testing.T) {
|
func TestInternalJobsSubmitCompletesAndReportsStats(t *testing.T) {
|
||||||
server := NewServer()
|
server := NewServer()
|
||||||
@ -1685,7 +1486,7 @@ func TestExecuteSessionTaskGatewayExportsOpenClawArtifacts(t *testing.T) {
|
|||||||
if got := shared.BoolArg(shared.StringArg(exportParams, "includeContent", ""), true); got {
|
if got := shared.BoolArg(shared.StringArg(exportParams, "includeContent", ""), true); got {
|
||||||
t.Fatalf("expected OpenClaw artifact export to omit content, got %#v", exportParams)
|
t.Fatalf("expected OpenClaw artifact export to omit content, got %#v", exportParams)
|
||||||
}
|
}
|
||||||
if got := gateway.Methods(); !sameMethods(got, []string{"connect", "xworkmate.artifacts.prepare", "chat.send", "agent.wait", "xworkmate.artifacts.collect-and-snapshot", "xworkmate.artifacts.export"}) {
|
if got := gateway.Methods(); !sameMethods(got, []string{"connect", "xworkmate.artifacts.prepare", "chat.send", "agent.wait", "xworkmate.artifacts.export", "xworkmate.artifacts.collect-and-snapshot"}) {
|
||||||
t.Fatalf("expected connect, artifact prepare, chat.send, agent.wait, then artifact export, got %#v", got)
|
t.Fatalf("expected connect, artifact prepare, chat.send, agent.wait, then artifact export, got %#v", got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1736,7 +1537,7 @@ func TestExecuteSessionTaskGatewayDoesNotTreatPromptTextAsArtifactContract(t *te
|
|||||||
if got := shared.BoolArg(shared.StringArg(exportParams, "includeContent", ""), true); got {
|
if got := shared.BoolArg(shared.StringArg(exportParams, "includeContent", ""), true); got {
|
||||||
t.Fatalf("expected latest workspace export to omit content, got %#v", exportParams)
|
t.Fatalf("expected latest workspace export to omit content, got %#v", exportParams)
|
||||||
}
|
}
|
||||||
if got := gateway.Methods(); !sameMethods(got, []string{"connect", "xworkmate.artifacts.prepare", "chat.send", "agent.wait", "xworkmate.artifacts.collect-and-snapshot", "xworkmate.artifacts.export"}) {
|
if got := gateway.Methods(); !sameMethods(got, []string{"connect", "xworkmate.artifacts.prepare", "chat.send", "agent.wait", "xworkmate.artifacts.export", "xworkmate.artifacts.collect-and-snapshot"}) {
|
||||||
t.Fatalf("expected connect, artifact prepare, chat.send, agent.wait, then artifact export, got %#v", got)
|
t.Fatalf("expected connect, artifact prepare, chat.send, agent.wait, then artifact export, got %#v", got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1797,7 +1598,7 @@ func TestExecuteSessionTaskGatewayExportsWithActualOpenClawRunID(t *testing.T) {
|
|||||||
if got := parsedDownloadURL.Query().Get("artifactScope"); got != "tasks/"+shared.StringArg(response, "sessionKey", "")+"/openclaw-run-actual" {
|
if got := parsedDownloadURL.Query().Get("artifactScope"); got != "tasks/"+shared.StringArg(response, "sessionKey", "")+"/openclaw-run-actual" {
|
||||||
t.Fatalf("expected download URL to use actual OpenClaw artifact scope, got %q", got)
|
t.Fatalf("expected download URL to use actual OpenClaw artifact scope, got %q", got)
|
||||||
}
|
}
|
||||||
if got := gateway.Methods(); !sameMethods(got, []string{"connect", "xworkmate.artifacts.prepare", "chat.send", "xworkmate.artifacts.prepare", "agent.wait", "xworkmate.artifacts.collect-and-snapshot", "xworkmate.artifacts.export"}) {
|
if got := gateway.Methods(); !sameMethods(got, []string{"connect", "xworkmate.artifacts.prepare", "chat.send", "xworkmate.artifacts.prepare", "agent.wait", "xworkmate.artifacts.export", "xworkmate.artifacts.collect-and-snapshot"}) {
|
||||||
t.Fatalf("expected bridge to reprepare actual OpenClaw run before wait/export, got %#v", got)
|
t.Fatalf("expected bridge to reprepare actual OpenClaw run before wait/export, got %#v", got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1948,7 +1749,7 @@ func TestExecuteSessionMessageGatewayDoesNotRewriteClaimedArtifactsWithoutGatewa
|
|||||||
if gateway.ArtifactExportCount() != 1 {
|
if gateway.ArtifactExportCount() != 1 {
|
||||||
t.Fatalf("expected one post-run artifact export sync, got %d", gateway.ArtifactExportCount())
|
t.Fatalf("expected one post-run artifact export sync, got %d", gateway.ArtifactExportCount())
|
||||||
}
|
}
|
||||||
if got := gateway.Methods(); !sameMethods(got, []string{"connect", "xworkmate.artifacts.prepare", "chat.send", "agent.wait", "xworkmate.artifacts.collect-and-snapshot", "xworkmate.artifacts.export"}) {
|
if got := gateway.Methods(); !sameMethods(got, []string{"connect", "xworkmate.artifacts.prepare", "chat.send", "agent.wait", "xworkmate.artifacts.export", "xworkmate.artifacts.collect-and-snapshot"}) {
|
||||||
t.Fatalf("expected connect, artifact prepare, chat.send, agent.wait, then artifact export, got %#v", got)
|
t.Fatalf("expected connect, artifact prepare, chat.send, agent.wait, then artifact export, got %#v", got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1998,7 +1799,7 @@ func TestExecuteSessionMessageGatewayExportsArtifactsWithoutPromptHeuristic(t *t
|
|||||||
if got := strings.TrimSpace(shared.StringArg(exportParams, "artifactScope", "")); got == "" {
|
if got := strings.TrimSpace(shared.StringArg(exportParams, "artifactScope", "")); got == "" {
|
||||||
t.Fatalf("expected bridge to export the prepared task artifact scope, got %#v", exportParams)
|
t.Fatalf("expected bridge to export the prepared task artifact scope, got %#v", exportParams)
|
||||||
}
|
}
|
||||||
if got := gateway.Methods(); !sameMethods(got, []string{"connect", "xworkmate.artifacts.prepare", "chat.send", "agent.wait", "xworkmate.artifacts.collect-and-snapshot", "xworkmate.artifacts.export"}) {
|
if got := gateway.Methods(); !sameMethods(got, []string{"connect", "xworkmate.artifacts.prepare", "chat.send", "agent.wait", "xworkmate.artifacts.export", "xworkmate.artifacts.collect-and-snapshot"}) {
|
||||||
t.Fatalf("expected connect, artifact prepare, chat.send, agent.wait, then artifact export, got %#v", got)
|
t.Fatalf("expected connect, artifact prepare, chat.send, agent.wait, then artifact export, got %#v", got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2665,46 +2466,6 @@ func TestExecuteSessionTaskGatewayAlwaysSyncsGatewayArtifactsAfterRun(t *testing
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExecuteSessionTaskGatewayFailsHallucinatedFileClaimsWithoutArtifacts(t *testing.T) {
|
|
||||||
gateway := newAcpFakeOpenClawGateway(t)
|
|
||||||
defer gateway.Close()
|
|
||||||
|
|
||||||
t.Setenv("GATEWAY_RPC_URL", gateway.URL())
|
|
||||||
t.Setenv("BRIDGE_AUTH_TOKEN", "bridge-token")
|
|
||||||
|
|
||||||
server := NewServer()
|
|
||||||
response, rpcErr := server.executeSessionTask(task{
|
|
||||||
req: shared.RPCRequest{
|
|
||||||
Method: "session.start",
|
|
||||||
Params: map[string]any{
|
|
||||||
"sessionId": "session-openclaw-missing-files",
|
|
||||||
"threadId": "thread-openclaw-missing-files",
|
|
||||||
"taskPrompt": "输出 PPT PDF docx 文件 hallucinate-files",
|
|
||||||
"workingDirectory": t.TempDir(),
|
|
||||||
"routing": map[string]any{
|
|
||||||
"routingMode": "explicit",
|
|
||||||
"explicitExecutionTarget": "gateway",
|
|
||||||
"preferredGatewayProviderId": "openclaw",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if rpcErr != nil {
|
|
||||||
t.Fatalf("expected bridge response, got rpc error: %#v", rpcErr)
|
|
||||||
}
|
|
||||||
if success, _ := response["success"].(bool); success {
|
|
||||||
t.Fatalf("expected bridge to reject hallucinated file success without artifacts, got %#v", response)
|
|
||||||
}
|
|
||||||
if got := response["code"]; got != "OPENCLAW_REQUIRED_ARTIFACT_MISSING" {
|
|
||||||
t.Fatalf("expected required artifact failure code, got %#v", response)
|
|
||||||
}
|
|
||||||
if _, ok := response["artifacts"]; ok {
|
|
||||||
t.Fatalf("expected no artifacts when export returned none, got %#v", response["artifacts"])
|
|
||||||
}
|
|
||||||
if missing := fmt.Sprint(response["missingArtifactExtensions"]); missing == "[]" || strings.TrimSpace(missing) == "" {
|
|
||||||
t.Fatalf("expected missing extension diagnostics, got %#v", response)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestExtractArtifactPayloadsDoesNotScanRemoteDirectoryFallback(t *testing.T) {
|
func TestExtractArtifactPayloadsDoesNotScanRemoteDirectoryFallback(t *testing.T) {
|
||||||
root := t.TempDir()
|
root := t.TempDir()
|
||||||
|
|||||||
@ -98,7 +98,11 @@ func (s *Server) handleTaskGet(ctx context.Context, params map[string]any, notif
|
|||||||
if sess == nil {
|
if sess == nil {
|
||||||
return map[string]any{"status": "not_found"}
|
return map[string]any{"status": "not_found"}
|
||||||
}
|
}
|
||||||
return s.orchestrator.probeOpenClawTask(ctx, sess, notify)
|
waitForArtifacts := shared.BoolArg(shared.StringArg(params, "waitForArtifacts", ""), false)
|
||||||
|
if val, ok := params["waitForArtifacts"].(bool); ok {
|
||||||
|
waitForArtifacts = val
|
||||||
|
}
|
||||||
|
return s.orchestrator.probeOpenClawTask(ctx, sess, notify, waitForArtifacts)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) handleTaskCancel(ctx context.Context, params map[string]any, notify func(map[string]any)) map[string]any {
|
func (s *Server) handleTaskCancel(ctx context.Context, params map[string]any, notify func(map[string]any)) map[string]any {
|
||||||
@ -200,7 +204,7 @@ func (s *Server) reassociateOpenClawTask(params map[string]any) *session {
|
|||||||
}
|
}
|
||||||
contract := openClawArtifactContract{
|
contract := openClawArtifactContract{
|
||||||
TaskLoadClass: strings.TrimSpace(shared.StringArg(params, "taskLoadClass", "")),
|
TaskLoadClass: strings.TrimSpace(shared.StringArg(params, "taskLoadClass", "")),
|
||||||
ExpectedArtifactExtensions: normalizeOpenClawExtensionList(shared.ListArg(params, "expectedArtifactExtensions")),
|
ComplexLongChain: shared.BoolArg(shared.StringArg(params, "complexLongChain", ""), false),
|
||||||
}
|
}
|
||||||
taskLoadClass, budget := openClawTaskRuntimePolicy(params, map[string]any{"sessionKey": sessionKey}, contract)
|
taskLoadClass, budget := openClawTaskRuntimePolicy(params, map[string]any{"sessionKey": sessionKey}, contract)
|
||||||
if explicitBudget := shared.IntArg(shared.StringArg(params, "runtimeBudgetMinutes", ""), 0); explicitBudget > 0 {
|
if explicitBudget := shared.IntArg(shared.StringArg(params, "runtimeBudgetMinutes", ""), 0); explicitBudget > 0 {
|
||||||
|
|||||||
@ -719,7 +719,7 @@ func TestHTTPHandlerGatewayOpenClawFiltersRawGatewayEventsAndKeepsFinalResult(t
|
|||||||
if !strings.Contains(fmt.Sprint(result), openClawArtifactDownloadPath) {
|
if !strings.Contains(fmt.Sprint(result), openClawArtifactDownloadPath) {
|
||||||
t.Fatalf("expected normalized artifact download URL in task result, got %#v", result)
|
t.Fatalf("expected normalized artifact download URL in task result, got %#v", result)
|
||||||
}
|
}
|
||||||
if got := gateway.Methods(); !sameMethods(got, []string{"connect", "xworkmate.artifacts.prepare", "chat.send", "agent.wait", "xworkmate.artifacts.collect-and-snapshot", "xworkmate.artifacts.export"}) {
|
if got := gateway.Methods(); !sameMethods(got, []string{"connect", "xworkmate.artifacts.prepare", "chat.send", "agent.wait", "xworkmate.artifacts.export", "xworkmate.artifacts.collect-and-snapshot"}) {
|
||||||
t.Fatalf("expected artifact workflow methods to prepare before chat.send, got %#v", got)
|
t.Fatalf("expected artifact workflow methods to prepare before chat.send, got %#v", got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user