MCPcopy Create free account
hub / github.com/ScriptedAlchemy/tracedecay / coerce_value

Function coerce_value

src/tool_command/args.rs:578–639  ·  view source on GitHub ↗

Coerce a CLI string value to the JSON type declared in the property schema. Falls back to a JSON string when the schema is absent or specifies an unknown type.

(key: &str, prop_schema: Option<&Value>, raw: &str)

Source from the content-addressed store, hash-verified

576/// Falls back to a JSON string when the schema is absent or specifies an
577/// unknown type.
578fn coerce_value(key: &str, prop_schema: Option<&Value>, raw: &str) -> Result<Value> {
579 let ty = prop_schema
580 .and_then(|p| p.get("type"))
581 .and_then(Value::as_str)
582 .unwrap_or("string");
583
584 match ty {
585 "string" => Ok(Value::String(raw.to_string())),
586 "boolean" => match raw {
587 "true" | "1" | "yes" | "on" => Ok(Value::Bool(true)),
588 "false" | "0" | "no" | "off" => Ok(Value::Bool(false)),
589 other => {
590 let flag = key.replace('_', "-");
591 Err(TraceDecayError::Config {
592 message: format!(
593 "--{flag}: expected a boolean (true/false), got `{other}` — \
594 pass `--{flag} true` or `--{flag} false`"
595 ),
596 })
597 }
598 },
599 "integer" => raw
600 .parse::<i64>()
601 .map(Value::from)
602 .map_err(|_| TraceDecayError::Config {
603 message: format!("--{}: expected integer, got `{raw}`", key.replace('_', "-")),
604 }),
605 // `serde_json::Number::from_f64(25.0).as_u64()` returns `None`, so MCP
606 // handlers that read counts via `.as_u64()` would silently fall back
607 // to defaults. Prefer integer storage when the input is whole.
608 "number" => {
609 if let Ok(i) = raw.parse::<i64>() {
610 Ok(Value::from(i))
611 } else {
612 raw.parse::<f64>()
613 .ok()
614 .and_then(serde_json::Number::from_f64)
615 .map(Value::Number)
616 .ok_or_else(|| TraceDecayError::Config {
617 message: format!(
618 "--{}: expected a finite number, got `{raw}`",
619 key.replace('_', "-")
620 ),
621 })
622 }
623 }
624 // Array/object params accept inline JSON per-key (`--replacements
625 // '[["old","new"]]'`, `--project-selector '{"project_id":"x"}'`).
626 // Non-JSON strings fall through unchanged: arrays keep the
627 // comma-split/repetition behavior via `finalize_arrays`, and objects
628 // are caught by `validate_tool_args` with a corrective error.
629 "array" | "object" => {
630 if let Ok(parsed) = serde_json::from_str::<Value>(raw) {
631 if value_matches_type(&parsed, ty) {
632 return Ok(parsed);
633 }
634 }
635 Ok(Value::String(raw.to_string()))

Callers 2

bind_positionalsFunction · 0.85

Calls 1

value_matches_typeFunction · 0.85

Tested by

no test coverage detected