gemcode 0.3.115__tar.gz → 0.3.117__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 (167) hide show
  1. {gemcode-0.3.115/src/gemcode.egg-info → gemcode-0.3.117}/PKG-INFO +1 -1
  2. {gemcode-0.3.115 → gemcode-0.3.117}/pyproject.toml +1 -1
  3. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/kaira_daemon.py +85 -2
  4. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/kaira_ipc.py +4 -1
  5. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/kaira_job_store.py +5 -1
  6. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/tools/org_tools.py +18 -0
  7. {gemcode-0.3.115 → gemcode-0.3.117/src/gemcode.egg-info}/PKG-INFO +1 -1
  8. {gemcode-0.3.115 → gemcode-0.3.117}/LICENSE +0 -0
  9. {gemcode-0.3.115 → gemcode-0.3.117}/MANIFEST.in +0 -0
  10. {gemcode-0.3.115 → gemcode-0.3.117}/README.md +0 -0
  11. {gemcode-0.3.115 → gemcode-0.3.117}/setup.cfg +0 -0
  12. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/__init__.py +0 -0
  13. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/__main__.py +0 -0
  14. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/agent.py +0 -0
  15. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/audit.py +0 -0
  16. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/autocompact.py +0 -0
  17. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/automations.py +0 -0
  18. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/autotune.py +0 -0
  19. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/callbacks.py +0 -0
  20. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/capability_routing.py +0 -0
  21. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/checkpoints.py +0 -0
  22. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/cli.py +0 -0
  23. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/compaction.py +0 -0
  24. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/computer_use/__init__.py +0 -0
  25. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/computer_use/browser_computer.py +0 -0
  26. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/config.py +0 -0
  27. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/context_budget.py +0 -0
  28. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/context_warning.py +0 -0
  29. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/credentials.py +0 -0
  30. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/curated_memory.py +0 -0
  31. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/dynamic_policy.py +0 -0
  32. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/evals/harness.py +0 -0
  33. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/hitl_session.py +0 -0
  34. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/hooks.py +0 -0
  35. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/ide_protocol.py +0 -0
  36. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/ide_stdio.py +0 -0
  37. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/intent_classifier.py +0 -0
  38. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/interactions.py +0 -0
  39. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/invoke.py +0 -0
  40. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/kaira_client.py +0 -0
  41. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/learning.py +0 -0
  42. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/limits.py +0 -0
  43. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/live_audio_engine.py +0 -0
  44. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/logging_config.py +0 -0
  45. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/mcp_loader.py +0 -0
  46. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/memory/__init__.py +0 -0
  47. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/memory/embedding_memory_service.py +0 -0
  48. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/memory/file_memory_service.py +0 -0
  49. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/modality_tools.py +0 -0
  50. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/model_errors.py +0 -0
  51. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/model_routing.py +0 -0
  52. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/multimodal_input.py +0 -0
  53. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/openapi_loader.py +0 -0
  54. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/org.py +0 -0
  55. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/output_styles.py +0 -0
  56. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/paths.py +0 -0
  57. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/permissions.py +0 -0
  58. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/plugins/__init__.py +0 -0
  59. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/plugins/terminal_hooks_plugin.py +0 -0
  60. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/plugins/tool_recovery_plugin.py +0 -0
  61. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/policy_profile.py +0 -0
  62. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/pricing.py +0 -0
  63. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/prompt_suggestions.py +0 -0
  64. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/query/__init__.py +0 -0
  65. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/query/config.py +0 -0
  66. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/query/deps.py +0 -0
  67. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/query/engine.py +0 -0
  68. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/query/stop_hooks.py +0 -0
  69. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/query/token_budget.py +0 -0
  70. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/query/transitions.py +0 -0
  71. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/query_sanitizer.py +0 -0
  72. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/refine.py +0 -0
  73. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/repl_commands.py +0 -0
  74. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/repl_slash.py +0 -0
  75. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/review_agent.py +0 -0
  76. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/rules.py +0 -0
  77. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/session_runtime.py +0 -0
  78. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/session_store.py +0 -0
  79. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/session_summariser.py +0 -0
  80. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/skills.py +0 -0
  81. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/slash_commands.py +0 -0
  82. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/thinking.py +0 -0
  83. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/tool_prompt_manifest.py +0 -0
  84. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/tool_registry.py +0 -0
  85. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/tool_result_store.py +0 -0
  86. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/tools/__init__.py +0 -0
  87. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/tools/automations_tools.py +0 -0
  88. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/tools/bash.py +0 -0
  89. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/tools/browser.py +0 -0
  90. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/tools/compress_memory.py +0 -0
  91. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/tools/curated_memory.py +0 -0
  92. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/tools/edit.py +0 -0
  93. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/tools/filesystem.py +0 -0
  94. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/tools/notebook.py +0 -0
  95. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/tools/notes.py +0 -0
  96. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/tools/repo_map.py +0 -0
  97. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/tools/search.py +0 -0
  98. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/tools/shell.py +0 -0
  99. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/tools/shell_gate.py +0 -0
  100. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/tools/skills.py +0 -0
  101. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/tools/subtask.py +0 -0
  102. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/tools/tasks.py +0 -0
  103. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/tools/think.py +0 -0
  104. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/tools/todo.py +0 -0
  105. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/tools/user_choice.py +0 -0
  106. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/tools/veomem_tools.py +0 -0
  107. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/tools/web.py +0 -0
  108. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/tools/web_search.py +0 -0
  109. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/tools_inspector.py +0 -0
  110. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/trust.py +0 -0
  111. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/tui/input_handler.py +0 -0
  112. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/tui/scrollback.py +0 -0
  113. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/tui/spinner.py +0 -0
  114. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/tui/welcome_banner.py +0 -0
  115. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/tui/welcome_rich.py +0 -0
  116. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/veomem_bridge.py +0 -0
  117. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/version.py +0 -0
  118. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/vertex.py +0 -0
  119. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/wal.py +0 -0
  120. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/web/__init__.py +0 -0
  121. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/web/sse_adapter.py +0 -0
  122. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/web/terminal_repl.py +0 -0
  123. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/web/web_sse_compat.py +0 -0
  124. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode/workspace_hints.py +0 -0
  125. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode.egg-info/SOURCES.txt +0 -0
  126. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode.egg-info/dependency_links.txt +0 -0
  127. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode.egg-info/entry_points.txt +0 -0
  128. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode.egg-info/requires.txt +0 -0
  129. {gemcode-0.3.115 → gemcode-0.3.117}/src/gemcode.egg-info/top_level.txt +0 -0
  130. {gemcode-0.3.115 → gemcode-0.3.117}/tests/test_add_dir.py +0 -0
  131. {gemcode-0.3.115 → gemcode-0.3.117}/tests/test_agent_instruction.py +0 -0
  132. {gemcode-0.3.115 → gemcode-0.3.117}/tests/test_autocompact.py +0 -0
  133. {gemcode-0.3.115 → gemcode-0.3.117}/tests/test_automations.py +0 -0
  134. {gemcode-0.3.115 → gemcode-0.3.117}/tests/test_capability_routing.py +0 -0
  135. {gemcode-0.3.115 → gemcode-0.3.117}/tests/test_checkpoint_diff_command.py +0 -0
  136. {gemcode-0.3.115 → gemcode-0.3.117}/tests/test_cli_init.py +0 -0
  137. {gemcode-0.3.115 → gemcode-0.3.117}/tests/test_compress_memory_tool.py +0 -0
  138. {gemcode-0.3.115 → gemcode-0.3.117}/tests/test_computer_use_permissions.py +0 -0
  139. {gemcode-0.3.115 → gemcode-0.3.117}/tests/test_context_budget.py +0 -0
  140. {gemcode-0.3.115 → gemcode-0.3.117}/tests/test_context_warning.py +0 -0
  141. {gemcode-0.3.115 → gemcode-0.3.117}/tests/test_credentials.py +0 -0
  142. {gemcode-0.3.115 → gemcode-0.3.117}/tests/test_eval_harness_layout.py +0 -0
  143. {gemcode-0.3.115 → gemcode-0.3.117}/tests/test_ide_stdio_attachments.py +0 -0
  144. {gemcode-0.3.115 → gemcode-0.3.117}/tests/test_interactive_permission_ask.py +0 -0
  145. {gemcode-0.3.115 → gemcode-0.3.117}/tests/test_kaira_scheduler.py +0 -0
  146. {gemcode-0.3.115 → gemcode-0.3.117}/tests/test_modality_tools.py +0 -0
  147. {gemcode-0.3.115 → gemcode-0.3.117}/tests/test_model_error_retry.py +0 -0
  148. {gemcode-0.3.115 → gemcode-0.3.117}/tests/test_model_errors.py +0 -0
  149. {gemcode-0.3.115 → gemcode-0.3.117}/tests/test_model_routing.py +0 -0
  150. {gemcode-0.3.115 → gemcode-0.3.117}/tests/test_multimodal_input.py +0 -0
  151. {gemcode-0.3.115 → gemcode-0.3.117}/tests/test_output_styles_and_rules.py +0 -0
  152. {gemcode-0.3.115 → gemcode-0.3.117}/tests/test_paths.py +0 -0
  153. {gemcode-0.3.115 → gemcode-0.3.117}/tests/test_permissions.py +0 -0
  154. {gemcode-0.3.115 → gemcode-0.3.117}/tests/test_prompt_suggestions.py +0 -0
  155. {gemcode-0.3.115 → gemcode-0.3.117}/tests/test_repl_commands.py +0 -0
  156. {gemcode-0.3.115 → gemcode-0.3.117}/tests/test_repl_slash.py +0 -0
  157. {gemcode-0.3.115 → gemcode-0.3.117}/tests/test_session_runtime_cache.py +0 -0
  158. {gemcode-0.3.115 → gemcode-0.3.117}/tests/test_skills.py +0 -0
  159. {gemcode-0.3.115 → gemcode-0.3.117}/tests/test_slash_commands.py +0 -0
  160. {gemcode-0.3.115 → gemcode-0.3.117}/tests/test_slash_completion_registry.py +0 -0
  161. {gemcode-0.3.115 → gemcode-0.3.117}/tests/test_thinking_config.py +0 -0
  162. {gemcode-0.3.115 → gemcode-0.3.117}/tests/test_token_budget.py +0 -0
  163. {gemcode-0.3.115 → gemcode-0.3.117}/tests/test_tool_context_circulation.py +0 -0
  164. {gemcode-0.3.115 → gemcode-0.3.117}/tests/test_tools.py +0 -0
  165. {gemcode-0.3.115 → gemcode-0.3.117}/tests/test_tools_inspector.py +0 -0
  166. {gemcode-0.3.115 → gemcode-0.3.117}/tests/test_web_sse_adapter.py +0 -0
  167. {gemcode-0.3.115 → gemcode-0.3.117}/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.115
3
+ Version: 0.3.117
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.115"
7
+ version = "0.3.117"
8
8
  description = "Local-first coding agent on Google Gemini + ADK"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -151,6 +151,7 @@ class KairaJob:
151
151
  prompt: str
152
152
  priority: int
153
153
  session_id: str
154
+ meta: dict | None = None
154
155
 
155
156
 
156
157
  class KairaDaemon:
@@ -415,6 +416,7 @@ class KairaDaemon:
415
416
  prompt: str,
416
417
  priority: int | None = None,
417
418
  session_id: str,
419
+ meta: dict | None = None,
418
420
  ) -> str:
419
421
  """Enqueue a new job into the priority queue and return job_id."""
420
422
  job_id = f"job_{uuid.uuid4().hex[:10]}"
@@ -425,9 +427,10 @@ class KairaDaemon:
425
427
  prompt=prompt,
426
428
  priority=pr,
427
429
  session_id=session_id,
430
+ meta=meta or None,
428
431
  )
429
432
  try:
430
- rec = new_job_record(job_id=job_id, session_id=session_id, priority=pr, prompt=prompt)
433
+ rec = new_job_record(job_id=job_id, session_id=session_id, priority=pr, prompt=prompt, meta=meta or None)
431
434
  self._job_records[job_id] = rec
432
435
  self._store.upsert(rec)
433
436
  except Exception:
@@ -469,7 +472,11 @@ class KairaDaemon:
469
472
 
470
473
  try:
471
474
  rec = self._job_records.get(job.job_id) or new_job_record(
472
- job_id=job.job_id, session_id=job.session_id, priority=job.priority, prompt=job.prompt
475
+ job_id=job.job_id,
476
+ session_id=job.session_id,
477
+ priority=job.priority,
478
+ prompt=job.prompt,
479
+ meta=(job.meta if isinstance(getattr(job, "meta", None), dict) else None),
473
480
  )
474
481
  self._job_records[job.job_id] = rec
475
482
  self._store.upsert(mark_running(rec))
@@ -555,6 +562,46 @@ class KairaDaemon:
555
562
  },
556
563
  }
557
564
  )
565
+
566
+ # If this job was enqueued as an org delegation, automatically publish
567
+ # an org.report back to the manager (and any notify_chain).
568
+ try:
569
+ meta = getattr(rec2, "meta", None) if isinstance(rec2, JobRecord) else None
570
+ org = meta.get("org") if isinstance(meta, dict) else None
571
+ if isinstance(org, dict):
572
+ member = org.get("member")
573
+ task = str(org.get("task") or "").strip()
574
+ context = str(org.get("context") or "").strip()
575
+ notify_chain = org.get("notify_chain")
576
+ if not isinstance(notify_chain, list):
577
+ notify_chain = ["manager"]
578
+ payload = {
579
+ "member": member if isinstance(member, dict) else {},
580
+ "capabilities": org.get("capabilities") if isinstance(org.get("capabilities"), dict) else {},
581
+ "status": "finished",
582
+ "task": task,
583
+ "context": context,
584
+ "job_id": job.job_id,
585
+ "error": "",
586
+ "result": {
587
+ "report_json": report_obj,
588
+ "report": (text or "")[:8000],
589
+ },
590
+ "notify_chain": notify_chain,
591
+ }
592
+ for to_addr in notify_chain:
593
+ await self._ipc.broadcast(
594
+ {
595
+ "type": "event",
596
+ "event": "bus_message",
597
+ "topic": "org.report",
598
+ "to": str(to_addr or "manager"),
599
+ "from_addr": "runtime",
600
+ "payload": payload,
601
+ }
602
+ )
603
+ except Exception:
604
+ pass
558
605
  except Exception:
559
606
  pass
560
607
  except Exception:
@@ -618,6 +665,42 @@ class KairaDaemon:
618
665
  )
619
666
  except Exception:
620
667
  pass
668
+ # Also emit org.report failures for org-delegated jobs.
669
+ try:
670
+ recf = self._job_records.get(job.job_id)
671
+ meta = getattr(recf, "meta", None) if recf is not None else None
672
+ org = meta.get("org") if isinstance(meta, dict) else None
673
+ if isinstance(org, dict):
674
+ member = org.get("member")
675
+ task = str(org.get("task") or "").strip()
676
+ context = str(org.get("context") or "").strip()
677
+ notify_chain = org.get("notify_chain")
678
+ if not isinstance(notify_chain, list):
679
+ notify_chain = ["manager"]
680
+ payload = {
681
+ "member": member if isinstance(member, dict) else {},
682
+ "capabilities": org.get("capabilities") if isinstance(org.get("capabilities"), dict) else {},
683
+ "status": "failed",
684
+ "task": task,
685
+ "context": context,
686
+ "job_id": job.job_id,
687
+ "error": f"{type(e).__name__}: {e}",
688
+ "result": None,
689
+ "notify_chain": notify_chain,
690
+ }
691
+ for to_addr in notify_chain:
692
+ await self._ipc.broadcast(
693
+ {
694
+ "type": "event",
695
+ "event": "bus_message",
696
+ "topic": "org.report",
697
+ "to": str(to_addr or "manager"),
698
+ "from_addr": "runtime",
699
+ "payload": payload,
700
+ }
701
+ )
702
+ except Exception:
703
+ pass
621
704
  try:
622
705
  rec3 = self._job_records.get(job.job_id)
623
706
  if rec3 is not None:
@@ -250,7 +250,10 @@ class KairaIpcServer:
250
250
  try:
251
251
  pr = msg.get("priority", None)
252
252
  sid = str(msg.get("session_id") or "").strip()
253
- job_id = self._enqueue_fn(prompt=prompt, priority=pr, session_id=sid)
253
+ meta = msg.get("meta", None)
254
+ if not isinstance(meta, dict):
255
+ meta = None
256
+ job_id = self._enqueue_fn(prompt=prompt, priority=pr, session_id=sid, meta=meta)
254
257
  client.emitter.send(make_response(id=req_id, ok=True, job_id=job_id))
255
258
  except Exception as e:
256
259
  client.emitter.send(
@@ -35,6 +35,7 @@ class JobRecord:
35
35
  finished_ms: int | None = None
36
36
  error: str | None = None
37
37
  last_text: str = ""
38
+ meta: dict[str, Any] | None = None
38
39
 
39
40
  def to_dict(self) -> dict[str, Any]:
40
41
  return {
@@ -42,6 +43,7 @@ class JobRecord:
42
43
  "session_id": self.session_id,
43
44
  "priority": int(self.priority),
44
45
  "prompt": self.prompt,
46
+ "meta": (self.meta or None),
45
47
  "status": self.status,
46
48
  "created_ms": int(self.created_ms),
47
49
  "updated_ms": int(self.updated_ms),
@@ -83,6 +85,7 @@ class KairaJobStore:
83
85
  session_id=str(obj.get("session_id") or ""),
84
86
  priority=int(obj.get("priority") or 0),
85
87
  prompt=str(obj.get("prompt") or ""),
88
+ meta=(obj.get("meta") if isinstance(obj.get("meta"), dict) else None),
86
89
  status=str(obj.get("status") or "queued"), # type: ignore[arg-type]
87
90
  created_ms=int(obj.get("created_ms") or 0),
88
91
  updated_ms=int(obj.get("updated_ms") or 0),
@@ -110,13 +113,14 @@ class KairaJobStore:
110
113
  return out
111
114
 
112
115
 
113
- def new_job_record(*, job_id: str, session_id: str, priority: int, prompt: str) -> JobRecord:
116
+ def new_job_record(*, job_id: str, session_id: str, priority: int, prompt: str, meta: dict[str, Any] | None = None) -> JobRecord:
114
117
  now = _now_ms()
115
118
  return JobRecord(
116
119
  job_id=job_id,
117
120
  session_id=session_id,
118
121
  priority=int(priority),
119
122
  prompt=prompt,
123
+ meta=meta or None,
120
124
  status="queued",
121
125
  created_ms=now,
122
126
  updated_ms=now,
@@ -220,11 +220,29 @@ def make_org_tools(cfg: GemCodeConfig) -> list:
220
220
  client = await KairaIpcClient.connect(socket_path=sock_s)
221
221
  try:
222
222
  session_id = str(getattr(cfg, "_active_session_id", "") or "")
223
+ notify_chain = _ancestor_addresses_for(m)
224
+ # Attach org metadata so the runtime can auto-publish org.report when
225
+ # the job finishes/fails (default, no extra prompting needed).
226
+ meta = {
227
+ "org": {
228
+ "member": (m.to_dict() if hasattr(m, "to_dict") else {}),
229
+ "capabilities": {
230
+ "kind": getattr(m, "kind", ""),
231
+ "address": getattr(m, "address", "") or getattr(m, "name", ""),
232
+ "workspace_rel": getattr(m, "workspace_rel", "") or "",
233
+ "reports_to": getattr(m, "reports_to", "") or "",
234
+ },
235
+ "task": task,
236
+ "context": ctx,
237
+ "notify_chain": notify_chain,
238
+ }
239
+ }
223
240
  res = await client.request(
224
241
  action="enqueue",
225
242
  prompt=prompt,
226
243
  priority=0,
227
244
  session_id=session_id,
245
+ meta=meta,
228
246
  )
229
247
  if not res.get("ok"):
230
248
  await _publish_org_report(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gemcode
3
- Version: 0.3.115
3
+ Version: 0.3.117
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