import { cli_locale } from "std/cli/localization"
import { cli_message } from "std/cli/localization/providers/tool_probe"
import { safe_bool, safe_dict, safe_list, safe_string } from "std/cli/render"
/**
* `harn provider tool-probe` ported to .harn — see harn#2310 (W10).
*
* Host aggregation either fires an HTTP
* probe through `run_tool_conformance_probe` or replays a fixture
* through `classify_tool_conformance_fixture`. Both stay in Rust: the
* probe machinery is sandbox-blocked, and the fixture classifier is a
* 1k-line parser tree that would be a rewrite, not a port. The Rust
* shim runs the aggregation and hands the JSON `ToolConformanceReport`
* here for rendering only.
*
* Inputs (from the dispatch shim):
* HARN_PROVIDER_TOOL_PROBE_PAYLOAD_JSON — JSON envelope matching the
* `ToolConformanceReport` shape; see
* `crates/harn-vm/src/llm/tool_conformance.rs` for the canonical
* definition. Required keys:
* provider, model, tool_format, cases[], tool_calling{native, text,
* streaming_native, fallback_mode, failure_reason?}
* HARN_OUTPUT_JSON — "1" for the JSON envelope (default at the
* handler level), else the human conformance summary.
*/
/**
* Mirror Rust's `Debug` format for `ToolProbeClassification`: serde
* emits snake_case in the JSON wire shape, but human output uses the
* original `UpperCamelCase` debug variant name. Map back so dispatch
* output stays stable.
*
* Order matches the enum declaration. Unknown values pass through
* verbatim so a future variant addition doesn't silently print "?";
* dispatch tests catch the divergence and the new branch can be
* added here.
*/
fn __classification_debug(value: string) -> string {
if value == "structured_native_tool_call" {
return "StructuredNativeToolCall"
}
if value == "parseable_harn_text_tool_call" {
return "ParseableHarnTextToolCall"
}
if value == "raw_model_tool_tag" {
return "RawModelToolTag"
}
if value == "prose_only_non_tool" {
return "ProseOnlyNonTool"
}
if value == "malformed_json_arguments" {
return "MalformedJsonArguments"
}
if value == "empty_silent" {
return "EmptySilent"
}
if value == "http_error" {
return "HttpError"
}
if value == "transport_error" {
return "TransportError"
}
if value == "direct_answer_no_tool" {
return "DirectAnswerNoTool"
}
if value == "unavailable_tool_repair" {
return "UnavailableToolRepair"
}
if value == "done_sentinel" {
return "DoneSentinel"
}
return value
}
fn __any_case_ok(report: dict) -> bool {
const cases = safe_list(report["cases"])
for c in cases {
if type_of(c) == "dict" && safe_bool(c["ok"], false) {
return true
}
}
return false
}
fn __render_human(__cli_locale: string, report: dict) -> string {
const provider = safe_string(report["provider"], "")
const model = safe_string(report["model"], "")
const tool_format = safe_string(report["tool_format"], "native")
const tc = safe_dict(report["tool_calling"])
const fallback = safe_string(tc["fallback_mode"], "")
const native = safe_string(tc["native"], "")
const text = safe_string(tc["text"], "")
const streaming_native = safe_string(tc["streaming_native"], "")
let out = cli_message(
__cli_locale,
"{0} {1} format={2} fallback={3} native={4} text={5} streaming_native={6}\n",
[
to_string(provider),
to_string(model),
to_string(tool_format),
to_string(fallback),
to_string(native),
to_string(text),
to_string(streaming_native),
],
)
const cases = safe_list(report["cases"])
for c in cases {
if type_of(c) != "dict" {
continue
}
const mode = safe_string(c["mode"], "")
const classification = __classification_debug(safe_string(c["classification"], ""))
const ok = safe_bool(c["ok"], false)
const reason = safe_string(c["failure_reason"], "-")
out = cli_message(
__cli_locale,
"{0} {1}: {2} ok={3} reason={4}\n",
[
to_string(out),
to_string(mode),
to_string(classification),
to_string(to_string(ok)),
to_string(reason),
],
)
}
return out
}
fn main(harness: Harness) -> int {
const __cli_locale = cli_locale(harness.env)
const raw = harness.env.get_or("HARN_PROVIDER_TOOL_PROBE_PAYLOAD_JSON", "")
if raw == "" {
harness.stdio.eprintln(
"internal error: HARN_PROVIDER_TOOL_PROBE_PAYLOAD_JSON not set by dispatch shim",
)
return 70
}
const json_mode = harness.env.get_or("HARN_OUTPUT_JSON", "0") == "1"
if json_mode {
// Forward the pre-formatted bytes so we don't lose serde's float
// fidelity through Harn's `json_parse`/`json_stringify` round-trip
// (matters for `elapsed_ms`-style fields that serde keeps typed).
const pretty = harness.env.get_or("HARN_PROVIDER_TOOL_PROBE_PAYLOAD_PRETTY", raw)
harness.stdio.println(pretty)
} else {
const report = try {
json_parse(raw)
} catch (e) {
harness.stdio.eprintln(
"internal error: failed to parse provider-tool-probe payload: " + e.message,
)
return 70
}
const text = __render_human(__cli_locale, report)
const trimmed = if len(text) > 0 && text[len(text) - 1] == "\n" {
text[0:len(text) - 1]
} else {
text
}
harness.stdio.println(trimmed)
}
// Compute exit code from the raw bytes via a quick parse. Tool
// transport probes still pass by producing a usable tool channel, but
// behavioral probes such as no-tool answer/refusal and done-sentinel
// intentionally have fallback=disabled when they succeed.
const probe = try {
json_parse(raw)
} catch (_) {
nil
}
if type_of(probe) == "dict" {
return if __any_case_ok(probe) {
0
} else {
1
}
}
return 0
}