gemcode 0.3.98__tar.gz → 0.3.100__tar.gz

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.
Files changed (157) hide show
  1. {gemcode-0.3.98/src/gemcode.egg-info → gemcode-0.3.100}/PKG-INFO +1 -1
  2. {gemcode-0.3.98 → gemcode-0.3.100}/pyproject.toml +1 -1
  3. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/repl_slash.py +0 -3
  4. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/session_summariser.py +53 -13
  5. {gemcode-0.3.98 → gemcode-0.3.100/src/gemcode.egg-info}/PKG-INFO +1 -1
  6. {gemcode-0.3.98 → gemcode-0.3.100}/LICENSE +0 -0
  7. {gemcode-0.3.98 → gemcode-0.3.100}/MANIFEST.in +0 -0
  8. {gemcode-0.3.98 → gemcode-0.3.100}/README.md +0 -0
  9. {gemcode-0.3.98 → gemcode-0.3.100}/setup.cfg +0 -0
  10. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/__init__.py +0 -0
  11. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/__main__.py +0 -0
  12. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/agent.py +0 -0
  13. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/audit.py +0 -0
  14. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/autocompact.py +0 -0
  15. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/autotune.py +0 -0
  16. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/callbacks.py +0 -0
  17. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/capability_routing.py +0 -0
  18. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/checkpoints.py +0 -0
  19. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/cli.py +0 -0
  20. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/compaction.py +0 -0
  21. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/computer_use/__init__.py +0 -0
  22. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/computer_use/browser_computer.py +0 -0
  23. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/config.py +0 -0
  24. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/context_budget.py +0 -0
  25. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/context_warning.py +0 -0
  26. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/credentials.py +0 -0
  27. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/curated_memory.py +0 -0
  28. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/dynamic_policy.py +0 -0
  29. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/evals/harness.py +0 -0
  30. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/hitl_session.py +0 -0
  31. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/hooks.py +0 -0
  32. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/ide_protocol.py +0 -0
  33. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/ide_stdio.py +0 -0
  34. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/intent_classifier.py +0 -0
  35. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/interactions.py +0 -0
  36. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/invoke.py +0 -0
  37. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/kaira_daemon.py +0 -0
  38. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/learning.py +0 -0
  39. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/limits.py +0 -0
  40. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/live_audio_engine.py +0 -0
  41. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/logging_config.py +0 -0
  42. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/mcp_loader.py +0 -0
  43. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/memory/__init__.py +0 -0
  44. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/memory/embedding_memory_service.py +0 -0
  45. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/memory/file_memory_service.py +0 -0
  46. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/modality_tools.py +0 -0
  47. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/model_errors.py +0 -0
  48. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/model_routing.py +0 -0
  49. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/multimodal_input.py +0 -0
  50. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/openapi_loader.py +0 -0
  51. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/output_styles.py +0 -0
  52. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/paths.py +0 -0
  53. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/permissions.py +0 -0
  54. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/plugins/__init__.py +0 -0
  55. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/plugins/terminal_hooks_plugin.py +0 -0
  56. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/plugins/tool_recovery_plugin.py +0 -0
  57. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/policy_profile.py +0 -0
  58. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/pricing.py +0 -0
  59. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/prompt_suggestions.py +0 -0
  60. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/query/__init__.py +0 -0
  61. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/query/config.py +0 -0
  62. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/query/deps.py +0 -0
  63. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/query/engine.py +0 -0
  64. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/query/stop_hooks.py +0 -0
  65. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/query/token_budget.py +0 -0
  66. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/query/transitions.py +0 -0
  67. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/query_sanitizer.py +0 -0
  68. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/refine.py +0 -0
  69. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/repl_commands.py +0 -0
  70. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/review_agent.py +0 -0
  71. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/rules.py +0 -0
  72. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/session_runtime.py +0 -0
  73. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/session_store.py +0 -0
  74. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/skills.py +0 -0
  75. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/slash_commands.py +0 -0
  76. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/thinking.py +0 -0
  77. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/tool_prompt_manifest.py +0 -0
  78. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/tool_registry.py +0 -0
  79. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/tool_result_store.py +0 -0
  80. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/tools/__init__.py +0 -0
  81. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/tools/bash.py +0 -0
  82. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/tools/browser.py +0 -0
  83. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/tools/compress_memory.py +0 -0
  84. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/tools/curated_memory.py +0 -0
  85. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/tools/edit.py +0 -0
  86. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/tools/filesystem.py +0 -0
  87. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/tools/notebook.py +0 -0
  88. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/tools/notes.py +0 -0
  89. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/tools/repo_map.py +0 -0
  90. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/tools/search.py +0 -0
  91. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/tools/shell.py +0 -0
  92. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/tools/shell_gate.py +0 -0
  93. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/tools/skills.py +0 -0
  94. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/tools/subtask.py +0 -0
  95. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/tools/tasks.py +0 -0
  96. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/tools/think.py +0 -0
  97. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/tools/todo.py +0 -0
  98. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/tools/veomem_tools.py +0 -0
  99. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/tools/web.py +0 -0
  100. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/tools/web_search.py +0 -0
  101. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/tools_inspector.py +0 -0
  102. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/trust.py +0 -0
  103. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/tui/input_handler.py +0 -0
  104. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/tui/scrollback.py +0 -0
  105. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/tui/spinner.py +0 -0
  106. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/tui/welcome_banner.py +0 -0
  107. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/tui/welcome_rich.py +0 -0
  108. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/veomem_bridge.py +0 -0
  109. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/version.py +0 -0
  110. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/vertex.py +0 -0
  111. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/wal.py +0 -0
  112. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/web/__init__.py +0 -0
  113. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/web/sse_adapter.py +0 -0
  114. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/web/terminal_repl.py +0 -0
  115. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/web/web_sse_compat.py +0 -0
  116. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode/workspace_hints.py +0 -0
  117. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode.egg-info/SOURCES.txt +0 -0
  118. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode.egg-info/dependency_links.txt +0 -0
  119. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode.egg-info/entry_points.txt +0 -0
  120. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode.egg-info/requires.txt +0 -0
  121. {gemcode-0.3.98 → gemcode-0.3.100}/src/gemcode.egg-info/top_level.txt +0 -0
  122. {gemcode-0.3.98 → gemcode-0.3.100}/tests/test_add_dir.py +0 -0
  123. {gemcode-0.3.98 → gemcode-0.3.100}/tests/test_agent_instruction.py +0 -0
  124. {gemcode-0.3.98 → gemcode-0.3.100}/tests/test_autocompact.py +0 -0
  125. {gemcode-0.3.98 → gemcode-0.3.100}/tests/test_capability_routing.py +0 -0
  126. {gemcode-0.3.98 → gemcode-0.3.100}/tests/test_checkpoint_diff_command.py +0 -0
  127. {gemcode-0.3.98 → gemcode-0.3.100}/tests/test_cli_init.py +0 -0
  128. {gemcode-0.3.98 → gemcode-0.3.100}/tests/test_compress_memory_tool.py +0 -0
  129. {gemcode-0.3.98 → gemcode-0.3.100}/tests/test_computer_use_permissions.py +0 -0
  130. {gemcode-0.3.98 → gemcode-0.3.100}/tests/test_context_budget.py +0 -0
  131. {gemcode-0.3.98 → gemcode-0.3.100}/tests/test_context_warning.py +0 -0
  132. {gemcode-0.3.98 → gemcode-0.3.100}/tests/test_credentials.py +0 -0
  133. {gemcode-0.3.98 → gemcode-0.3.100}/tests/test_eval_harness_layout.py +0 -0
  134. {gemcode-0.3.98 → gemcode-0.3.100}/tests/test_ide_stdio_attachments.py +0 -0
  135. {gemcode-0.3.98 → gemcode-0.3.100}/tests/test_interactive_permission_ask.py +0 -0
  136. {gemcode-0.3.98 → gemcode-0.3.100}/tests/test_kaira_scheduler.py +0 -0
  137. {gemcode-0.3.98 → gemcode-0.3.100}/tests/test_modality_tools.py +0 -0
  138. {gemcode-0.3.98 → gemcode-0.3.100}/tests/test_model_error_retry.py +0 -0
  139. {gemcode-0.3.98 → gemcode-0.3.100}/tests/test_model_errors.py +0 -0
  140. {gemcode-0.3.98 → gemcode-0.3.100}/tests/test_model_routing.py +0 -0
  141. {gemcode-0.3.98 → gemcode-0.3.100}/tests/test_multimodal_input.py +0 -0
  142. {gemcode-0.3.98 → gemcode-0.3.100}/tests/test_output_styles_and_rules.py +0 -0
  143. {gemcode-0.3.98 → gemcode-0.3.100}/tests/test_paths.py +0 -0
  144. {gemcode-0.3.98 → gemcode-0.3.100}/tests/test_permissions.py +0 -0
  145. {gemcode-0.3.98 → gemcode-0.3.100}/tests/test_prompt_suggestions.py +0 -0
  146. {gemcode-0.3.98 → gemcode-0.3.100}/tests/test_repl_commands.py +0 -0
  147. {gemcode-0.3.98 → gemcode-0.3.100}/tests/test_repl_slash.py +0 -0
  148. {gemcode-0.3.98 → gemcode-0.3.100}/tests/test_skills.py +0 -0
  149. {gemcode-0.3.98 → gemcode-0.3.100}/tests/test_slash_commands.py +0 -0
  150. {gemcode-0.3.98 → gemcode-0.3.100}/tests/test_slash_completion_registry.py +0 -0
  151. {gemcode-0.3.98 → gemcode-0.3.100}/tests/test_thinking_config.py +0 -0
  152. {gemcode-0.3.98 → gemcode-0.3.100}/tests/test_token_budget.py +0 -0
  153. {gemcode-0.3.98 → gemcode-0.3.100}/tests/test_tool_context_circulation.py +0 -0
  154. {gemcode-0.3.98 → gemcode-0.3.100}/tests/test_tools.py +0 -0
  155. {gemcode-0.3.98 → gemcode-0.3.100}/tests/test_tools_inspector.py +0 -0
  156. {gemcode-0.3.98 → gemcode-0.3.100}/tests/test_web_sse_adapter.py +0 -0
  157. {gemcode-0.3.98 → gemcode-0.3.100}/tests/test_workspace_hints.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gemcode
3
- Version: 0.3.98
3
+ Version: 0.3.100
4
4
  Summary: Local-first coding agent on Google Gemini + ADK
5
5
  Author: GemCode Contributors
6
6
  License: Apache License
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "gemcode"
7
- version = "0.3.98"
7
+ version = "0.3.100"
8
8
  description = "Local-first coding agent on Google Gemini + ADK"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -618,9 +618,6 @@ async def process_repl_slash(
618
618
 
619
619
  # ── /add-dir (safe multi-root access) ──────────────────────────────────────
620
620
  if name in ("add-dir", "add_dir", "adddir"):
621
- import os
622
- from pathlib import Path
623
-
624
621
  args = (sc.args or "").strip()
625
622
  added: dict[str, Path] = getattr(cfg, "_added_dirs", None) or {}
626
623
  setattr(cfg, "_added_dirs", added)
@@ -100,16 +100,51 @@ def _build_prompt(transcript_lines: list[str], *, focus: str = "") -> str:
100
100
  )
101
101
 
102
102
 
103
- def _call_summary_model(*, model: str, prompt: str) -> dict[str, Any]:
103
+ def _extract_json_object(text: str) -> dict[str, Any] | None:
104
+ """
105
+ Best-effort parse:
106
+ - strict JSON object
107
+ - JSON object embedded in extra text (common model behavior)
108
+ """
109
+ raw = (text or "").strip()
110
+ if not raw:
111
+ return None
112
+ try:
113
+ obj = json.loads(raw)
114
+ return obj if isinstance(obj, dict) else None
115
+ except Exception:
116
+ pass
117
+
118
+ # Try to recover embedded JSON: find the largest {...} span.
119
+ start = raw.find("{")
120
+ end = raw.rfind("}")
121
+ if start == -1 or end == -1 or end <= start:
122
+ return None
123
+ candidate = raw[start : end + 1].strip()
124
+ try:
125
+ obj = json.loads(candidate)
126
+ return obj if isinstance(obj, dict) else None
127
+ except Exception:
128
+ return None
129
+
130
+
131
+ def _call_summary_model(*, model: str, prompt: str) -> tuple[dict[str, Any] | None, str]:
104
132
  api_key = os.environ.get("GOOGLE_API_KEY")
105
133
  if not api_key:
106
134
  raise RuntimeError("GOOGLE_API_KEY not set")
107
135
 
108
136
  client = Client(api_key=api_key)
137
+ cfg = types.GenerateContentConfig(temperature=0.2)
138
+ # Prefer structured JSON output when supported by the SDK/model.
139
+ try:
140
+ setattr(cfg, "response_mime_type", "application/json")
141
+ except Exception:
142
+ pass
143
+
109
144
  resp = client.models.generate_content(
110
- model=model,
111
- contents=[types.Content(role="user", parts=[types.Part(text=prompt)])],
112
- config=types.GenerateContentConfig(temperature=0.2),
145
+ model=model,
146
+ contents=[types.Content(role="user", parts=[types.Part(text=prompt)])],
147
+ config=cfg,
113
148
  )
114
149
 
115
150
  out_parts: list[str] = []
@@ -127,14 +162,7 @@ def _call_summary_model(*, model: str, prompt: str) -> dict[str, Any]:
127
162
  text = "".join(out_parts).strip()
128
163
  if not text:
129
164
  raise RuntimeError("session summariser returned empty text")
130
-
131
- try:
132
- data = json.loads(text)
133
- except Exception as e:
134
- raise RuntimeError(f"session summariser returned invalid JSON: {e}") from e
135
- if not isinstance(data, dict):
136
- raise RuntimeError("session summariser returned non-object JSON")
137
- return data
165
+ return _extract_json_object(text), text
138
166
 
139
167
 
140
168
  def summarise_session(
@@ -149,7 +177,18 @@ def summarise_session(
149
177
  return {"error": "session transcript is empty", "session_id": session_id}
150
178
 
151
179
  prompt = _build_prompt(transcript_lines, focus=focus)
152
- data = _call_summary_model(model=model, prompt=prompt)
180
+ data, raw_text = _call_summary_model(model=model, prompt=prompt)
181
+ if data is None:
182
+ # Graceful fallback: save raw text as summary_markdown so /summarise never hard-fails
183
+ # due to JSON formatting drift.
184
+ data = {
185
+ "title": f"Session {session_id[:8]}",
186
+ "summary_markdown": raw_text[:20_000],
187
+ "memory_facts": [],
188
+ "user_facts": [],
189
+ "notes_markdown": "",
190
+ "open_items": [],
191
+ }
153
192
 
154
193
  title = str(data.get("title") or f"Session {session_id[:8]}").strip()[:120]
155
194
  summary_markdown = str(data.get("summary_markdown") or "").strip()
@@ -219,6 +258,7 @@ def summarise_session(
219
258
  "summary_path": str(out_path),
220
259
  "title": title,
221
260
  "summary_markdown": summary_markdown,
261
+ "used_json": bool(data is not None and _extract_json_object(raw_text) is not None),
222
262
  "memory_facts_saved": saved_memory,
223
263
  "user_facts_saved": saved_user,
224
264
  "notes_status": note_status,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gemcode
3
- Version: 0.3.98
3
+ Version: 0.3.100
4
4
  Summary: Local-first coding agent on Google Gemini + ADK
5
5
  Author: GemCode Contributors
6
6
  License: Apache License
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes