|
6 | 6 | "encoding/json" |
7 | 7 | "fmt" |
8 | 8 | "os" |
| 9 | + "strings" |
9 | 10 | ) |
10 | 11 |
|
11 | 12 | const maxInteractionScriptLineBytes = 50 * 1024 * 1024 |
@@ -37,6 +38,13 @@ func ParseInteractionScript(data []byte) ([]ScriptStep, error) { |
37 | 38 | if ok || err != nil { |
38 | 39 | return steps, err |
39 | 40 | } |
| 41 | + if text, ok := interactionScriptProviderResponseText(data); ok { |
| 42 | + steps, err := ParseInteractionScript([]byte(text)) |
| 43 | + if err != nil { |
| 44 | + return nil, fmt.Errorf("parse interaction script provider response: %w", err) |
| 45 | + } |
| 46 | + return steps, nil |
| 47 | + } |
40 | 48 | } |
41 | 49 |
|
42 | 50 | scanner := bufio.NewScanner(bytes.NewReader(data)) |
@@ -319,6 +327,96 @@ func interactionScriptObjectHasContainer(data []byte) bool { |
319 | 327 | return false |
320 | 328 | } |
321 | 329 |
|
| 330 | +func interactionScriptProviderResponseText(data []byte) (string, bool) { |
| 331 | + var object map[string]json.RawMessage |
| 332 | + if err := json.Unmarshal(data, &object); err != nil { |
| 333 | + return "", false |
| 334 | + } |
| 335 | + if scriptStepJSONHasDirectFields(object) { |
| 336 | + return "", false |
| 337 | + } |
| 338 | + for _, name := range []string{ |
| 339 | + "choice", |
| 340 | + "choices", |
| 341 | + "output", |
| 342 | + "outputs", |
| 343 | + "candidate", |
| 344 | + "candidates", |
| 345 | + "generation", |
| 346 | + "generations", |
| 347 | + "completion", |
| 348 | + "completions", |
| 349 | + "response", |
| 350 | + "responses", |
| 351 | + "result", |
| 352 | + "results", |
| 353 | + } { |
| 354 | + value, ok := object[name] |
| 355 | + if !ok { |
| 356 | + continue |
| 357 | + } |
| 358 | + if text, ok := interactionScriptProviderTextFromRaw(value, 0, false); ok { |
| 359 | + return text, true |
| 360 | + } |
| 361 | + } |
| 362 | + return "", false |
| 363 | +} |
| 364 | + |
| 365 | +func interactionScriptProviderTextFromRaw(raw json.RawMessage, depth int, allowScalar bool) (string, bool) { |
| 366 | + raw = bytes.TrimSpace(raw) |
| 367 | + if len(raw) == 0 || bytes.Equal(raw, []byte("null")) || depth > 8 { |
| 368 | + return "", false |
| 369 | + } |
| 370 | + var text string |
| 371 | + if err := json.Unmarshal(raw, &text); err == nil { |
| 372 | + text = strings.TrimSpace(text) |
| 373 | + return text, allowScalar && text != "" |
| 374 | + } |
| 375 | + if raw[0] == '[' { |
| 376 | + var items []json.RawMessage |
| 377 | + if err := json.Unmarshal(raw, &items); err != nil { |
| 378 | + return "", false |
| 379 | + } |
| 380 | + parts := make([]string, 0, len(items)) |
| 381 | + for _, item := range items { |
| 382 | + part, ok := interactionScriptProviderTextFromRaw(item, depth+1, false) |
| 383 | + if ok { |
| 384 | + parts = append(parts, part) |
| 385 | + } |
| 386 | + } |
| 387 | + if len(parts) == 0 { |
| 388 | + return "", false |
| 389 | + } |
| 390 | + return strings.Join(parts, "\n"), true |
| 391 | + } |
| 392 | + if raw[0] != '{' { |
| 393 | + return "", false |
| 394 | + } |
| 395 | + fields := map[string]json.RawMessage{} |
| 396 | + if err := json.Unmarshal(raw, &fields); err != nil { |
| 397 | + return "", false |
| 398 | + } |
| 399 | + for _, name := range []string{"text", "content", "value", "output"} { |
| 400 | + value, ok := fields[name] |
| 401 | + if !ok { |
| 402 | + continue |
| 403 | + } |
| 404 | + if text, ok := interactionScriptProviderTextFromRaw(value, depth+1, true); ok { |
| 405 | + return text, true |
| 406 | + } |
| 407 | + } |
| 408 | + for _, name := range []string{"message", "delta", "part", "parts", "candidate", "choice", "generation", "result", "response"} { |
| 409 | + value, ok := fields[name] |
| 410 | + if !ok { |
| 411 | + continue |
| 412 | + } |
| 413 | + if text, ok := interactionScriptProviderTextFromRaw(value, depth+1, false); ok { |
| 414 | + return text, true |
| 415 | + } |
| 416 | + } |
| 417 | + return "", false |
| 418 | +} |
| 419 | + |
322 | 420 | func parseInteractionScriptOptionalStepsValue(value json.RawMessage) ([]ScriptStep, bool, error) { |
323 | 421 | value = bytes.TrimSpace(value) |
324 | 422 | if len(value) == 0 || bytes.Equal(value, []byte("null")) { |
|
0 commit comments