mtrx-cli 0.1.21 → 0.1.22

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": "mtrx-cli",
3
- "version": "0.1.21",
3
+ "version": "0.1.22",
4
4
  "description": "MATRX CLI for routing Codex, Claude, and Cursor through Matrx",
5
5
  "homepage": "https://mtrx.so",
6
6
  "repository": {
@@ -1 +1 @@
1
- __version__ = "0.1.21"
1
+ __version__ = "0.1.22"
@@ -579,33 +579,21 @@ def _build_gemini_env(
579
579
  orchestration: dict | None = None,
580
580
  ) -> tuple[dict[str, str], str]:
581
581
  matrx = state["auth"]["matrx"]
582
- # Assuming we might store Gemini-specific keys in future, or use OpenAI key fallback
583
- # For now, we don't have a specific 'gemini' auth section in state.py, but we can assume
584
- # if direct route, we use env var.
582
+ proxy_root = ensure_root_url(matrx.get("base_url"))
585
583
  proxy_base = ensure_v1_url(matrx.get("base_url"))
586
584
  mx_key, matrx_auth_source = _resolve_matrx_route_key(state, env)
587
-
588
- # Check for direct key in env or potentially saved elsewhere
589
- direct_key = (env.get("GOOGLE_API_KEY") or "").strip()
585
+ direct_key = (env.get("GEMINI_API_KEY") or env.get("GOOGLE_API_KEY") or "").strip()
590
586
 
591
587
  if route == "matrx":
592
588
  if not mx_key:
593
589
  raise ValueError("No Matrx key available. Run: mtrx login matrx --key mx_... or set MTRX_KEY")
594
-
595
- # Clear existing Gemini config to force proxy usage
596
590
  env.pop("MTRX_KEY", None)
597
-
598
591
  group_id, project_id = _resolve_matrx_context_overrides(state, env)
599
592
  session_id = str(uuid.uuid4())
600
593
  runtime_agent_id = (
601
594
  (orchestration or {}).get("agent_id")
602
595
  or _runtime_agent_basename("gemini")[0]
603
596
  )
604
-
605
- # Build a project-aware proxy base URL so the proxy can identify the project
606
- # even though Gemini CLI doesn't support custom request headers via env vars.
607
- # We append matrx context as query params which the proxy reads.
608
- proxy_base_with_ctx = proxy_base
609
597
  ctx_params: list[str] = []
610
598
  if project_id:
611
599
  ctx_params.append(f"mtrx_project={project_id}")
@@ -613,31 +601,65 @@ def _build_gemini_env(
613
601
  ctx_params.append(f"mtrx_session={session_id}")
614
602
  if runtime_agent_id:
615
603
  ctx_params.append(f"mtrx_agent={runtime_agent_id}")
616
- if ctx_params:
617
- proxy_base_with_ctx = f"{proxy_base}?{'&'.join(ctx_params)}"
604
+ git_branch, git_commit = _capture_git_context(_workspace_cwd(env))
605
+ if git_branch:
606
+ ctx_params.append(f"mtrx_branch={git_branch}")
607
+ if git_commit:
608
+ ctx_params.append(f"mtrx_commit={git_commit}")
609
+
610
+ query_suffix = f"?{'&'.join(ctx_params)}" if ctx_params else ""
611
+ env_snap = _capture_env_snapshot()
612
+ env_b64 = base64.b64encode(json.dumps(env_snap).encode()).decode() if env_snap else ""
613
+ custom_headers = [
614
+ f"x-matrx-key: {mx_key}",
615
+ f"x-matrx-agent-id: {runtime_agent_id}",
616
+ "x-matrx-provider: gemini_code",
617
+ f"x-matrx-session-id: {session_id}",
618
+ ]
619
+ if group_id:
620
+ custom_headers.append(f"x-matrx-group: {group_id}")
621
+ if project_id:
622
+ custom_headers.append(f"x-matrx-project-id: {project_id}")
623
+ if git_branch:
624
+ custom_headers.append(f"x-matrx-branch: {git_branch}")
625
+ if git_commit:
626
+ custom_headers.append(f"x-matrx-commit: {git_commit}")
627
+ if env_b64:
628
+ custom_headers.append(f"x-matrx-env: {env_b64}")
618
629
 
619
- # Set Proxy Config
620
- env["GOOGLE_GEMINI_BASE_URL"] = proxy_base_with_ctx
621
- env["GEMINI_API_ENDPOINT"] = proxy_base_with_ctx
622
- env["GOOGLE_API_KEY"] = mx_key
630
+ env["GOOGLE_GEMINI_BASE_URL"] = f"{proxy_base}/v1beta{query_suffix}"
631
+ env["GOOGLE_VERTEX_BASE_URL"] = f"{proxy_base}/v1beta{query_suffix}"
632
+ env["GEMINI_API_ENDPOINT"] = env["GOOGLE_GEMINI_BASE_URL"]
633
+ env["CODE_ASSIST_ENDPOINT"] = proxy_base
634
+ env["GEMINI_CLI_CUSTOM_HEADERS"] = ", ".join(custom_headers)
635
+ env["GEMINI_API_KEY_AUTH_MECHANISM"] = "bearer"
623
636
 
624
637
  return env, matrx_auth_source
625
638
 
626
639
  # Direct route: clear any matrx-managed env vars
627
640
  env.pop("MTRX_KEY", None)
628
-
629
- # Clear proxy overrides
630
- _clear_if_matches(env, "GOOGLE_GEMINI_BASE_URL", proxy_base)
631
- _clear_if_matches(env, "GEMINI_API_ENDPOINT", proxy_base)
632
-
633
- # Clear key if it was the Matrx key
634
- current_key = (env.get("GOOGLE_API_KEY") or "").strip()
635
- if current_key == mx_key or current_key.startswith("mx_"):
636
- env.pop("GOOGLE_API_KEY", None)
637
-
638
- if env.get("GOOGLE_API_KEY"):
641
+ for key in (
642
+ "GOOGLE_GEMINI_BASE_URL",
643
+ "GOOGLE_VERTEX_BASE_URL",
644
+ "GEMINI_API_ENDPOINT",
645
+ "CODE_ASSIST_ENDPOINT",
646
+ ):
647
+ value = (env.get(key) or "").strip()
648
+ if "matrx" in value.lower() or "mtrx.so" in value.lower():
649
+ env.pop(key, None)
650
+
651
+ custom_headers = (env.get("GEMINI_CLI_CUSTOM_HEADERS") or "").strip().lower()
652
+ if "x-matrx-" in custom_headers:
653
+ env.pop("GEMINI_CLI_CUSTOM_HEADERS", None)
654
+ if (env.get("GEMINI_API_KEY_AUTH_MECHANISM") or "").strip().lower() == "bearer":
655
+ env.pop("GEMINI_API_KEY_AUTH_MECHANISM", None)
656
+
657
+ if env.get("GEMINI_API_KEY") or env.get("GOOGLE_API_KEY"):
639
658
  return env, "existing_google_env"
640
-
659
+
660
+ if direct_key:
661
+ return env, "existing_gemini_auth"
662
+
641
663
  return env, "missing_auth"
642
664
 
643
665
 
@@ -906,26 +928,40 @@ def _validate_gemini_launch_plan(plan: LaunchPlan, state: dict) -> None:
906
928
  return
907
929
 
908
930
  expected_base_url = ensure_v1_url(state.get("auth", {}).get("matrx", {}).get("base_url"))
931
+ expected_gemini_base = f"{expected_base_url}/v1beta"
909
932
 
910
933
  base_url = (plan.env.get("GOOGLE_GEMINI_BASE_URL") or "").strip()
911
934
  if not base_url:
912
935
  base_url = (plan.env.get("GEMINI_API_ENDPOINT") or "").strip()
913
936
 
914
937
  if not base_url:
915
- raise ValueError("Gemini Matrx route is missing GOOGLE_GEMINI_BASE_URL or GEMINI_API_ENDPOINT")
938
+ raise ValueError("Gemini Matrx route is missing GOOGLE_GEMINI_BASE_URL")
916
939
 
917
- # Strip query params before comparing (project_id context may be appended as ?mtrx_project=...)
918
940
  base_url_no_qs = base_url.split("?")[0].rstrip("/")
919
- expected_no_qs = expected_base_url.rstrip("/")
941
+ expected_no_qs = expected_gemini_base.rstrip("/")
920
942
  if base_url_no_qs != expected_no_qs:
921
943
  raise ValueError(
922
- "Gemini Matrx route must use the Matrx /v1 base URL. "
944
+ "Gemini Matrx route must use the Matrx Gemini-native base URL. "
923
945
  f"Got: {base_url}"
924
946
  )
925
947
 
926
- mx_key = (plan.env.get("GOOGLE_API_KEY") or "").strip()
927
- if not mx_key.startswith("mx_"):
928
- raise ValueError("Gemini Matrx route is missing a valid GOOGLE_API_KEY (should be mx_...)")
948
+ vertex_base = (plan.env.get("GOOGLE_VERTEX_BASE_URL") or "").strip()
949
+ if vertex_base and vertex_base.split("?")[0].rstrip("/") != expected_no_qs:
950
+ raise ValueError("Gemini Matrx route is missing a Matrx GOOGLE_VERTEX_BASE_URL")
951
+
952
+ code_assist_endpoint = (plan.env.get("CODE_ASSIST_ENDPOINT") or "").strip().rstrip("/")
953
+ if code_assist_endpoint != expected_base_url.rstrip("/"):
954
+ raise ValueError("Gemini Matrx route is missing a Matrx CODE_ASSIST_ENDPOINT")
955
+
956
+ custom_headers = (plan.env.get("GEMINI_CLI_CUSTOM_HEADERS") or "").strip().lower()
957
+ if "x-matrx-key:" not in custom_headers:
958
+ raise ValueError("Gemini Matrx route is missing GEMINI_CLI_CUSTOM_HEADERS with X-Matrx-Key")
959
+ if "x-matrx-provider: gemini_code" not in custom_headers:
960
+ raise ValueError("Gemini Matrx route is missing GEMINI_CLI_CUSTOM_HEADERS with X-Matrx-Provider=gemini_code")
961
+ if "x-matrx-session-id:" not in custom_headers:
962
+ raise ValueError("Gemini Matrx route is missing GEMINI_CLI_CUSTOM_HEADERS with X-Matrx-Session-Id")
963
+ if "x-matrx-agent-id:" not in custom_headers:
964
+ raise ValueError("Gemini Matrx route is missing GEMINI_CLI_CUSTOM_HEADERS with X-Matrx-Agent-Id")
929
965
 
930
966
 
931
967
  def _validate_codex_launch_plan(plan: LaunchPlan, state: dict) -> None:
@@ -991,10 +1027,13 @@ def describe_launch_plan(plan: LaunchPlan, state: dict) -> list[str]:
991
1027
  if plan.tool == "gemini":
992
1028
  base_url = ensure_v1_url(state.get("auth", {}).get("matrx", {}).get("base_url"))
993
1029
  _, project_id = _resolve_matrx_context_overrides(state, dict(plan.env))
1030
+ custom_headers = (plan.env.get("GEMINI_CLI_CUSTOM_HEADERS") or "").strip()
994
1031
  lines = [
995
1032
  "Launching gemini via Matrx",
996
- f" base_url: {base_url}",
1033
+ f" gemini_base_url: {plan.env.get('GOOGLE_GEMINI_BASE_URL') or ''}",
1034
+ f" code_assist_endpoint: {plan.env.get('CODE_ASSIST_ENDPOINT') or ''}",
997
1035
  f" auth_source: {plan.auth_source}",
1036
+ f" custom_headers_present: {bool(custom_headers)}",
998
1037
  " runtime_route: env injection",
999
1038
  " persistent_route: disabled",
1000
1039
  ]