pi-codemcp 1.3.2 → 1.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-codemcp",
3
- "version": "1.3.2",
3
+ "version": "1.3.3",
4
4
  "description": "Typed, sandboxed Code Mode access to configured MCP servers for Pi",
5
5
  "type": "module",
6
6
  "packageManager": "bun@1.3.10",
@@ -50,9 +50,10 @@ INSPECT_BYTE_LIMIT = 8 * 1024
50
50
  CHAIN_INPUT_EXTERNAL = "__codemcp_saved_chain_input"
51
51
 
52
52
 
53
- type FailureStage = Literal["preflight", "runtime", "timeout", "cancelled", "result"]
53
+ type FailureStage = Literal["preflight", "arguments", "runtime", "timeout", "cancelled", "result"]
54
54
  type FailureKind = Literal[
55
55
  "preflight",
56
+ "argument_validation",
56
57
  "result",
57
58
  "result_reference",
58
59
  "sandbox_runtime",
@@ -487,7 +488,18 @@ class MontyExecutor:
487
488
  raise RuntimeError(
488
489
  f"Call limit exceeded: maximum {context.settings.max_calls} total calls"
489
490
  )
490
- validated = catalog.validate_arguments(name, arguments)
491
+ try:
492
+ validated = catalog.validate_arguments(name, arguments)
493
+ except (TypeError, ValidationError, ValueError) as error:
494
+ message = f"{spec.call}: invalid arguments: {error}"
495
+ context.failure = ExecutionFailureInfo(
496
+ kind="argument_validation",
497
+ server=spec.server,
498
+ tool=spec.backend_name,
499
+ retryable=False,
500
+ message=message,
501
+ )
502
+ raise ValueError(message) from error
491
503
  if spec.kind == "saved_chain":
492
504
  context.chain_calls += 1
493
505
  return await context.call_tool(name, validated, context)
@@ -624,8 +636,10 @@ class MontyExecutor:
624
636
  context.metrics.runtime_ms += _elapsed_ms(runtime_started)
625
637
  message = error.display("type-msg").strip()
626
638
  lowered = message.lower()
627
- stage: Literal["runtime", "timeout"] = (
628
- "timeout"
639
+ stage: Literal["arguments", "runtime", "timeout"] = (
640
+ "arguments"
641
+ if context.failure is not None and context.failure.kind == "argument_validation"
642
+ else "timeout"
629
643
  if (context.failure is not None and context.failure.kind == "upstream_timeout")
630
644
  or "duration" in lowered
631
645
  or "timed out" in lowered
@@ -728,7 +742,7 @@ class MontyExecutor:
728
742
  @staticmethod
729
743
  def _failure(
730
744
  context: ExecutionContext,
731
- stage: Literal["preflight", "runtime", "timeout", "cancelled", "result"],
745
+ stage: FailureStage,
732
746
  error: str,
733
747
  ) -> ExecutionResponse:
734
748
  failure = context.failure or _execution_failure_info(stage, error)
@@ -749,6 +763,8 @@ def _execution_failure_info(
749
763
  ) -> ExecutionFailureInfo:
750
764
  if stage == "preflight":
751
765
  kind: FailureKind = "preflight"
766
+ elif stage == "arguments":
767
+ kind = "argument_validation"
752
768
  elif stage == "result":
753
769
  kind = "result"
754
770
  elif stage == "timeout":
@@ -1511,6 +1511,7 @@ def _execution_failure_subtype(response: ExecutionResponse) -> str:
1511
1511
  failure = response.failure
1512
1512
  if failure is not None and failure.kind in {
1513
1513
  "result_reference",
1514
+ "argument_validation",
1514
1515
  "sandbox_timeout",
1515
1516
  "upstream",
1516
1517
  "upstream_transport",
@@ -14,7 +14,7 @@ SANDBOX_FUNCTION_EXTERNALS = {
14
14
  EXPECT_INTEGER_NAME: "__codemcp_expect_integer",
15
15
  }
16
16
 
17
- STUB_IMPORTS = "from typing import Literal, Never, NotRequired, TypeAlias, TypedDict"
17
+ STUB_IMPORTS = "from typing import Literal, Mapping, Never, NotRequired, TypeAlias, TypedDict"
18
18
  JSON_TYPE_STUBS = (
19
19
  "JsonScalar: TypeAlias = bool | int | float | str | None",
20
20
  'JsonValue: TypeAlias = JsonScalar | list["JsonValue"] | dict[str, "JsonValue"]',
package/sidecar/stats.py CHANGED
@@ -98,6 +98,7 @@ DISTINCT_NAME_QUERIES = {
98
98
  FailureOutcome = Literal[
99
99
  "success",
100
100
  "preflight_rejection",
101
+ "argument_rejection",
101
102
  "result_refinement",
102
103
  "upstream_failure",
103
104
  "transport_failure",
@@ -996,6 +997,8 @@ def _operation_outcome(
996
997
  return "internal_error"
997
998
  if failure.stage == "preflight":
998
999
  return "preflight_rejection"
1000
+ if failure.stage == "arguments":
1001
+ return "argument_rejection"
999
1002
  if failure.stage == "result":
1000
1003
  return "result_refinement"
1001
1004
  if failure.stage == "cancelled":
@@ -426,7 +426,8 @@ class ToolCatalog(BaseModel):
426
426
  for spec in specs:
427
427
  definitions.extend(spec.stub.split("\n\n") if spec.stub else [])
428
428
  facade_methods.setdefault(spec.namespace, []).append(
429
- f" async def {spec.method}(self, arguments: {spec.input_type_name}) "
429
+ f" async def {spec.method}(self, arguments: "
430
+ f"{spec.input_type_name} | Mapping[str, JsonValue]) "
430
431
  f"-> {spec.output_type_name}: ..."
431
432
  )
432
433
  facades: list[str] = []
@@ -114,6 +114,9 @@ function renderCompactFailure(
114
114
  if (stage === "preflight") {
115
115
  return theme.fg("warning", `✗ Preflight · code not run · ${summary}`);
116
116
  }
117
+ if (stage === "arguments") {
118
+ return theme.fg("warning", `✗ Argument validation · code run · ${summary}`);
119
+ }
117
120
  if (stage === "timeout") {
118
121
  return theme.fg("error", `✗ Timeout · stopped after ${summary}`);
119
122
  }
@@ -131,6 +134,9 @@ function failureHeading(stage: string, calls: number, chainCalls: number, theme:
131
134
  if (stage === "preflight") {
132
135
  return `${theme.fg("warning", theme.bold("Preflight failed"))}\n${theme.fg("muted", "Code was not executed; no upstream side effects")}`;
133
136
  }
137
+ if (stage === "arguments") {
138
+ return `${theme.fg("warning", theme.bold("Argument validation failed"))}\n${theme.fg("muted", "Code ran; no invalid MCP call was sent")}`;
139
+ }
134
140
  if (stage === "timeout") {
135
141
  return `${theme.fg("error", theme.bold("Execution timed out"))}\n${theme.fg("muted", `Stopped after ${summary}`)}`;
136
142
  }