add files
Browse files- R/asa_api_helpers.R +47 -30
- Tests/api_contract_smoke.R +65 -25
- www/index.html +3 -0
R/asa_api_helpers.R
CHANGED
|
@@ -1115,49 +1115,65 @@ asa_api_normalize_result <- function(result, include_raw_output = FALSE, include
|
|
| 1115 |
output
|
| 1116 |
}
|
| 1117 |
|
| 1118 |
-
|
| 1119 |
-
|
| 1120 |
-
if (
|
| 1121 |
-
return(
|
| 1122 |
}
|
| 1123 |
-
|
| 1124 |
-
field <- tolower(trimws(field))
|
| 1125 |
-
field %in% c("base_url", "openai_api_base") ||
|
| 1126 |
-
grepl("(^|_)(backend|provider|model|model_id|model_name)$", field)
|
| 1127 |
}
|
| 1128 |
|
| 1129 |
-
|
| 1130 |
-
|
| 1131 |
-
|
|
|
|
| 1132 |
}
|
|
|
|
|
|
|
| 1133 |
|
| 1134 |
-
|
| 1135 |
-
|
| 1136 |
-
|
| 1137 |
-
|
| 1138 |
}
|
| 1139 |
|
| 1140 |
-
|
| 1141 |
-
|
|
|
|
|
|
|
| 1142 |
}
|
| 1143 |
|
| 1144 |
-
|
| 1145 |
-
|
| 1146 |
-
}
|
| 1147 |
|
| 1148 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1149 |
}
|
| 1150 |
|
| 1151 |
-
|
| 1152 |
if (!is.list(result)) {
|
| 1153 |
return(result)
|
| 1154 |
}
|
| 1155 |
|
| 1156 |
-
|
| 1157 |
-
|
| 1158 |
-
|
| 1159 |
-
|
| 1160 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1161 |
}
|
| 1162 |
|
| 1163 |
asa_api_is_result_like <- function(value) {
|
|
@@ -1378,6 +1394,7 @@ asa_api_run_gui_query <- function(payload, request_context = NULL) {
|
|
| 1378 |
log_con <- asa_api_request_context_log_con(request_context)
|
| 1379 |
stage_ref <- new.env(parent = emptyenv())
|
| 1380 |
stage_ref$value <- "run_single"
|
|
|
|
| 1381 |
capture <- asa_api_new_runtime_capture()
|
| 1382 |
capture$prompt <- asa_api_scalar_chr(payload$prompt, default = "")
|
| 1383 |
run_payload <- payload
|
|
@@ -1399,10 +1416,10 @@ asa_api_run_gui_query <- function(payload, request_context = NULL) {
|
|
| 1399 |
request_context = list(route = route, log_con = log_con)
|
| 1400 |
)
|
| 1401 |
|
| 1402 |
-
stage_ref$value <- "
|
| 1403 |
-
|
| 1404 |
},
|
| 1405 |
-
mode =
|
| 1406 |
route = route,
|
| 1407 |
payload = run_payload,
|
| 1408 |
prompt = capture$prompt,
|
|
|
|
| 1115 |
output
|
| 1116 |
}
|
| 1117 |
|
| 1118 |
+
asa_api_optional_scalar_chr <- function(value) {
|
| 1119 |
+
text <- asa_api_scalar_chr(value, default = "")
|
| 1120 |
+
if (nzchar(text)) {
|
| 1121 |
+
return(text)
|
| 1122 |
}
|
| 1123 |
+
NULL
|
|
|
|
|
|
|
|
|
|
| 1124 |
}
|
| 1125 |
|
| 1126 |
+
asa_api_optional_scalar_int <- function(value) {
|
| 1127 |
+
number <- asa_api_scalar_int(value, default = NA_integer_)
|
| 1128 |
+
if (!is.na(number)) {
|
| 1129 |
+
return(number)
|
| 1130 |
}
|
| 1131 |
+
NULL
|
| 1132 |
+
}
|
| 1133 |
|
| 1134 |
+
asa_api_gui_execution_mode <- function(execution, response_mode = NULL) {
|
| 1135 |
+
response_mode <- asa_api_scalar_chr(response_mode, default = "")
|
| 1136 |
+
if (identical(response_mode, "provider_direct_single")) {
|
| 1137 |
+
return("provider_direct")
|
| 1138 |
}
|
| 1139 |
|
| 1140 |
+
execution <- asa_api_named_list(execution)
|
| 1141 |
+
execution_mode <- asa_api_scalar_chr(execution$mode, default = "")
|
| 1142 |
+
if (identical(execution_mode, "provider_direct")) {
|
| 1143 |
+
return("provider_direct")
|
| 1144 |
}
|
| 1145 |
|
| 1146 |
+
"asa_agent"
|
| 1147 |
+
}
|
|
|
|
| 1148 |
|
| 1149 |
+
asa_api_gui_execution_summary <- function(execution, response_mode = NULL) {
|
| 1150 |
+
execution <- asa_api_named_list(asa_api_to_plain(execution))
|
| 1151 |
+
|
| 1152 |
+
asa_api_drop_nulls(list(
|
| 1153 |
+
mode = asa_api_gui_execution_mode(execution, response_mode = response_mode),
|
| 1154 |
+
thread_id = asa_api_optional_scalar_chr(execution$thread_id),
|
| 1155 |
+
backend_status = asa_api_optional_scalar_chr(execution$backend_status),
|
| 1156 |
+
status_code = asa_api_optional_scalar_int(execution$status_code),
|
| 1157 |
+
tool_calls_used = asa_api_optional_scalar_int(execution$tool_calls_used),
|
| 1158 |
+
search_calls_used = asa_api_optional_scalar_int(execution$search_calls_used),
|
| 1159 |
+
action_step_count = asa_api_optional_scalar_int(execution$action_step_count)
|
| 1160 |
+
))
|
| 1161 |
}
|
| 1162 |
|
| 1163 |
+
asa_api_project_gui_result <- function(result, response_mode = NULL) {
|
| 1164 |
if (!is.list(result)) {
|
| 1165 |
return(result)
|
| 1166 |
}
|
| 1167 |
|
| 1168 |
+
asa_api_drop_nulls(list(
|
| 1169 |
+
status = result$status %||% NULL,
|
| 1170 |
+
message = result$message %||% NULL,
|
| 1171 |
+
parsed = result$parsed %||% NULL,
|
| 1172 |
+
elapsed_time_min = result$elapsed_time_min %||% NULL,
|
| 1173 |
+
search_tier = result$search_tier %||% NULL,
|
| 1174 |
+
parsing_status = result$parsing_status %||% NULL,
|
| 1175 |
+
execution = asa_api_gui_execution_summary(result$execution, response_mode = response_mode)
|
| 1176 |
+
))
|
| 1177 |
}
|
| 1178 |
|
| 1179 |
asa_api_is_result_like <- function(value) {
|
|
|
|
| 1394 |
log_con <- asa_api_request_context_log_con(request_context)
|
| 1395 |
stage_ref <- new.env(parent = emptyenv())
|
| 1396 |
stage_ref$value <- "run_single"
|
| 1397 |
+
response_mode <- asa_api_single_mode(payload, allow_direct_provider = TRUE)
|
| 1398 |
capture <- asa_api_new_runtime_capture()
|
| 1399 |
capture$prompt <- asa_api_scalar_chr(payload$prompt, default = "")
|
| 1400 |
run_payload <- payload
|
|
|
|
| 1416 |
request_context = list(route = route, log_con = log_con)
|
| 1417 |
)
|
| 1418 |
|
| 1419 |
+
stage_ref$value <- "project_gui_result"
|
| 1420 |
+
asa_api_project_gui_result(result, response_mode = response_mode)
|
| 1421 |
},
|
| 1422 |
+
mode = response_mode,
|
| 1423 |
route = route,
|
| 1424 |
payload = run_payload,
|
| 1425 |
prompt = capture$prompt,
|
Tests/api_contract_smoke.R
CHANGED
|
@@ -452,7 +452,7 @@ assert_true(
|
|
| 452 |
|
| 453 |
{
|
| 454 |
original_run_single <- asa_api_run_single
|
| 455 |
-
|
| 456 |
gui_log_lines <- character(0)
|
| 457 |
gui_log_con <- textConnection("gui_log_lines", "w", local = TRUE)
|
| 458 |
gui_error <- NULL
|
|
@@ -464,7 +464,7 @@ assert_true(
|
|
| 464 |
execution = list(mode = "asa_agent")
|
| 465 |
)
|
| 466 |
}
|
| 467 |
-
|
| 468 |
stop("subscript out of bounds", call. = FALSE)
|
| 469 |
}
|
| 470 |
|
|
@@ -480,7 +480,7 @@ assert_true(
|
|
| 480 |
)
|
| 481 |
close(gui_log_con)
|
| 482 |
asa_api_run_single <- original_run_single
|
| 483 |
-
|
| 484 |
|
| 485 |
gui_failure <- asa_api_error_failure(gui_error)
|
| 486 |
gui_res_env <- new.env(parent = emptyenv())
|
|
@@ -489,10 +489,10 @@ assert_true(
|
|
| 489 |
assert_true(
|
| 490 |
inherits(gui_error, "asa_api_runtime_error") &&
|
| 491 |
identical(gui_failure$details$route, "/gui/query") &&
|
| 492 |
-
identical(gui_failure$details$stage, "
|
| 493 |
-
identical(gui_payload$details$stage, "
|
| 494 |
-
grepl("stage=
|
| 495 |
-
"GUI
|
| 496 |
)
|
| 497 |
}
|
| 498 |
|
|
@@ -574,31 +574,71 @@ asa_api_refresh_auth_cache(force = TRUE)
|
|
| 574 |
asa_api_run_single_via_direct <- original_direct
|
| 575 |
}
|
| 576 |
|
| 577 |
-
gui_result <-
|
| 578 |
status = "success",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 579 |
execution = list(
|
| 580 |
-
|
| 581 |
-
|
| 582 |
-
|
| 583 |
-
|
| 584 |
-
|
| 585 |
-
|
| 586 |
-
|
| 587 |
-
|
| 588 |
-
|
| 589 |
-
|
| 590 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 591 |
)
|
| 592 |
))
|
| 593 |
assert_true(
|
| 594 |
-
|
| 595 |
-
|
| 596 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 597 |
)
|
| 598 |
assert_true(
|
| 599 |
-
|
| 600 |
-
|
| 601 |
-
"GUI
|
| 602 |
)
|
| 603 |
|
| 604 |
cat("asa-api contract smoke checks passed\n")
|
|
|
|
| 452 |
|
| 453 |
{
|
| 454 |
original_run_single <- asa_api_run_single
|
| 455 |
+
original_project_gui_result <- asa_api_project_gui_result
|
| 456 |
gui_log_lines <- character(0)
|
| 457 |
gui_log_con <- textConnection("gui_log_lines", "w", local = TRUE)
|
| 458 |
gui_error <- NULL
|
|
|
|
| 464 |
execution = list(mode = "asa_agent")
|
| 465 |
)
|
| 466 |
}
|
| 467 |
+
asa_api_project_gui_result <- function(result, response_mode = NULL) {
|
| 468 |
stop("subscript out of bounds", call. = FALSE)
|
| 469 |
}
|
| 470 |
|
|
|
|
| 480 |
)
|
| 481 |
close(gui_log_con)
|
| 482 |
asa_api_run_single <- original_run_single
|
| 483 |
+
asa_api_project_gui_result <- original_project_gui_result
|
| 484 |
|
| 485 |
gui_failure <- asa_api_error_failure(gui_error)
|
| 486 |
gui_res_env <- new.env(parent = emptyenv())
|
|
|
|
| 489 |
assert_true(
|
| 490 |
inherits(gui_error, "asa_api_runtime_error") &&
|
| 491 |
identical(gui_failure$details$route, "/gui/query") &&
|
| 492 |
+
identical(gui_failure$details$stage, "project_gui_result") &&
|
| 493 |
+
identical(gui_payload$details$stage, "project_gui_result") &&
|
| 494 |
+
grepl("stage=project_gui_result", gui_log_text, fixed = TRUE),
|
| 495 |
+
"GUI projection failures should return the safe diagnostic summary and emit matching logs."
|
| 496 |
)
|
| 497 |
}
|
| 498 |
|
|
|
|
| 574 |
asa_api_run_single_via_direct <- original_direct
|
| 575 |
}
|
| 576 |
|
| 577 |
+
gui_result <- asa_api_project_gui_result(list(
|
| 578 |
status = "success",
|
| 579 |
+
message = "ok",
|
| 580 |
+
parsed = list(capital = "Paris"),
|
| 581 |
+
elapsed_time_min = 0.25,
|
| 582 |
+
search_tier = "unknown",
|
| 583 |
+
parsing_status = list(valid = TRUE),
|
| 584 |
execution = list(
|
| 585 |
+
thread_id = list("asa_123"),
|
| 586 |
+
backend_status = list("success"),
|
| 587 |
+
status_code = list(200L),
|
| 588 |
+
tool_calls_used = list(2L),
|
| 589 |
+
search_calls_used = list(1L),
|
| 590 |
+
action_step_count = list(6L),
|
| 591 |
+
tool_quality_events = list(list(
|
| 592 |
+
message_index_in_round = list(1L),
|
| 593 |
+
tool_name = list("update_plan"),
|
| 594 |
+
is_empty = list(FALSE),
|
| 595 |
+
is_off_target = list(FALSE),
|
| 596 |
+
is_error = list(FALSE),
|
| 597 |
+
error_type = NULL,
|
| 598 |
+
elapsed_ms_estimate = list(0L),
|
| 599 |
+
quality_version = list("v1")
|
| 600 |
+
)),
|
| 601 |
+
config_snapshot = list(backend = "gemini", model = "gemini-3-flash-preview")
|
| 602 |
)
|
| 603 |
))
|
| 604 |
assert_true(
|
| 605 |
+
identical(
|
| 606 |
+
names(gui_result$execution),
|
| 607 |
+
c(
|
| 608 |
+
"mode",
|
| 609 |
+
"thread_id",
|
| 610 |
+
"backend_status",
|
| 611 |
+
"status_code",
|
| 612 |
+
"tool_calls_used",
|
| 613 |
+
"search_calls_used",
|
| 614 |
+
"action_step_count"
|
| 615 |
+
)
|
| 616 |
+
) &&
|
| 617 |
+
identical(gui_result$execution$mode, "asa_agent") &&
|
| 618 |
+
identical(gui_result$execution$thread_id, "asa_123") &&
|
| 619 |
+
identical(gui_result$execution$tool_calls_used, 2L),
|
| 620 |
+
"GUI success responses should expose only a compact execution summary."
|
| 621 |
+
)
|
| 622 |
+
assert_true(
|
| 623 |
+
!("tool_quality_events" %in% names(gui_result$execution)) &&
|
| 624 |
+
!("config_snapshot" %in% names(gui_result$execution)),
|
| 625 |
+
"GUI projection should avoid recursing through nested execution diagnostics."
|
| 626 |
+
)
|
| 627 |
+
|
| 628 |
+
gui_direct_result <- asa_api_project_gui_result(
|
| 629 |
+
list(
|
| 630 |
+
status = "success",
|
| 631 |
+
execution = list(
|
| 632 |
+
mode = list("provider_direct"),
|
| 633 |
+
status_code = list(200L)
|
| 634 |
+
)
|
| 635 |
+
),
|
| 636 |
+
response_mode = "provider_direct_single"
|
| 637 |
)
|
| 638 |
assert_true(
|
| 639 |
+
identical(gui_direct_result$execution$mode, "provider_direct") &&
|
| 640 |
+
identical(gui_direct_result$execution$status_code, 200L),
|
| 641 |
+
"GUI projection should preserve direct-provider mode in the compact execution summary."
|
| 642 |
)
|
| 643 |
|
| 644 |
cat("asa-api contract smoke checks passed\n")
|
www/index.html
CHANGED
|
@@ -404,6 +404,9 @@
|
|
| 404 |
if (data && data.execution && data.execution.mode === "provider_direct") {
|
| 405 |
return "Mode: direct provider";
|
| 406 |
}
|
|
|
|
|
|
|
|
|
|
| 407 |
|
| 408 |
return "Mode: ASA agent";
|
| 409 |
}
|
|
|
|
| 404 |
if (data && data.execution && data.execution.mode === "provider_direct") {
|
| 405 |
return "Mode: direct provider";
|
| 406 |
}
|
| 407 |
+
if (data && data.execution && data.execution.mode === "asa_agent") {
|
| 408 |
+
return "Mode: ASA agent";
|
| 409 |
+
}
|
| 410 |
|
| 411 |
return "Mode: ASA agent";
|
| 412 |
}
|