jac-coder 0.1.3__tar.gz → 0.1.5__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 (226) hide show
  1. {jac_coder-0.1.3 → jac_coder-0.1.5}/PKG-INFO +1 -1
  2. jac_coder-0.1.5/jac_coder/_precompiled/cpython-312/api.jir +0 -0
  3. jac_coder-0.1.5/jac_coder/_precompiled/cpython-312/config.jir +0 -0
  4. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-312/context.jir +0 -0
  5. jac_coder-0.1.5/jac_coder/_precompiled/cpython-312/cost_tracker.jir +0 -0
  6. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-312/nodes.jir +0 -0
  7. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-312/tool/scaffold.jir +0 -0
  8. jac_coder-0.1.5/jac_coder/_precompiled/cpython-313/api.jir +0 -0
  9. jac_coder-0.1.5/jac_coder/_precompiled/cpython-313/config.jir +0 -0
  10. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-313/context.jir +0 -0
  11. jac_coder-0.1.5/jac_coder/_precompiled/cpython-313/cost_tracker.jir +0 -0
  12. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-313/nodes.jir +0 -0
  13. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-313/tool/scaffold.jir +0 -0
  14. jac_coder-0.1.5/jac_coder/_precompiled/cpython-314/api.jir +0 -0
  15. jac_coder-0.1.5/jac_coder/_precompiled/cpython-314/config.jir +0 -0
  16. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-314/context.jir +0 -0
  17. jac_coder-0.1.5/jac_coder/_precompiled/cpython-314/cost_tracker.jir +0 -0
  18. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-314/nodes.jir +0 -0
  19. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-314/tool/scaffold.jir +0 -0
  20. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/manifest.json +7 -7
  21. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/api.jac +2 -1
  22. jac_coder-0.1.5/jac_coder/config.jac +88 -0
  23. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/data/examples/blog_app.md +6 -7
  24. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/data/reference/frontend.md +12 -8
  25. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/data/reference/pitfalls.md +4 -4
  26. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/data/rules/fullstack.md +16 -10
  27. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/impl/api.impl.jac +26 -1
  28. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/impl/context.impl.jac +1 -1
  29. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/impl/cost_tracker.impl.jac +16 -11
  30. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/impl/nodes.impl.jac +3 -2
  31. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/tool/impl/scaffold.impl.jac +5 -5
  32. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder.egg-info/PKG-INFO +1 -1
  33. {jac_coder-0.1.3 → jac_coder-0.1.5}/pyproject.toml +1 -1
  34. jac_coder-0.1.3/jac_coder/_precompiled/cpython-312/api.jir +0 -0
  35. jac_coder-0.1.3/jac_coder/_precompiled/cpython-312/config.jir +0 -0
  36. jac_coder-0.1.3/jac_coder/_precompiled/cpython-312/cost_tracker.jir +0 -0
  37. jac_coder-0.1.3/jac_coder/_precompiled/cpython-313/api.jir +0 -0
  38. jac_coder-0.1.3/jac_coder/_precompiled/cpython-313/config.jir +0 -0
  39. jac_coder-0.1.3/jac_coder/_precompiled/cpython-313/cost_tracker.jir +0 -0
  40. jac_coder-0.1.3/jac_coder/_precompiled/cpython-314/api.jir +0 -0
  41. jac_coder-0.1.3/jac_coder/_precompiled/cpython-314/config.jir +0 -0
  42. jac_coder-0.1.3/jac_coder/_precompiled/cpython-314/cost_tracker.jir +0 -0
  43. jac_coder-0.1.3/jac_coder/config.jac +0 -40
  44. {jac_coder-0.1.3 → jac_coder-0.1.5}/README.md +0 -0
  45. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/__init__.jac +0 -0
  46. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/__init__.py +0 -0
  47. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-312/__init__.jir +0 -0
  48. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-312/events.jir +0 -0
  49. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-312/mcp_manager.jir +0 -0
  50. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-312/memory.jir +0 -0
  51. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-312/permission.jir +0 -0
  52. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-312/prompt.jir +0 -0
  53. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-312/serve_entry.jir +0 -0
  54. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-312/server.jir +0 -0
  55. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-312/tool/__init__.jir +0 -0
  56. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-312/tool/checked.jir +0 -0
  57. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-312/tool/delegation.jir +0 -0
  58. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-312/tool/filesystem.jir +0 -0
  59. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-312/tool/git.jir +0 -0
  60. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-312/tool/guarded.jir +0 -0
  61. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-312/tool/jac_analyzer.jir +0 -0
  62. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-312/tool/jac_docs.jir +0 -0
  63. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-312/tool/jac_tools.jir +0 -0
  64. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-312/tool/mcp.jir +0 -0
  65. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-312/tool/preview.jir +0 -0
  66. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-312/tool/question.jir +0 -0
  67. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-312/tool/search.jir +0 -0
  68. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-312/tool/shell.jir +0 -0
  69. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-312/tool/task.jir +0 -0
  70. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-312/tool/think.jir +0 -0
  71. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-312/tool/todo.jir +0 -0
  72. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-312/tool/validate.jir +0 -0
  73. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-312/tool/web.jir +0 -0
  74. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-312/util/__init__.jir +0 -0
  75. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-312/util/colors.jir +0 -0
  76. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-312/util/sandbox.jir +0 -0
  77. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-312/util/tool_output.jir +0 -0
  78. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-312/walkers.jir +0 -0
  79. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-313/__init__.jir +0 -0
  80. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-313/events.jir +0 -0
  81. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-313/mcp_manager.jir +0 -0
  82. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-313/memory.jir +0 -0
  83. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-313/permission.jir +0 -0
  84. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-313/prompt.jir +0 -0
  85. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-313/serve_entry.jir +0 -0
  86. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-313/server.jir +0 -0
  87. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-313/tool/__init__.jir +0 -0
  88. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-313/tool/checked.jir +0 -0
  89. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-313/tool/delegation.jir +0 -0
  90. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-313/tool/filesystem.jir +0 -0
  91. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-313/tool/git.jir +0 -0
  92. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-313/tool/guarded.jir +0 -0
  93. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-313/tool/jac_analyzer.jir +0 -0
  94. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-313/tool/jac_docs.jir +0 -0
  95. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-313/tool/jac_tools.jir +0 -0
  96. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-313/tool/mcp.jir +0 -0
  97. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-313/tool/preview.jir +0 -0
  98. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-313/tool/question.jir +0 -0
  99. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-313/tool/search.jir +0 -0
  100. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-313/tool/shell.jir +0 -0
  101. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-313/tool/task.jir +0 -0
  102. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-313/tool/think.jir +0 -0
  103. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-313/tool/todo.jir +0 -0
  104. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-313/tool/validate.jir +0 -0
  105. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-313/tool/web.jir +0 -0
  106. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-313/util/__init__.jir +0 -0
  107. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-313/util/colors.jir +0 -0
  108. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-313/util/sandbox.jir +0 -0
  109. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-313/util/tool_output.jir +0 -0
  110. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-313/walkers.jir +0 -0
  111. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-314/__init__.jir +0 -0
  112. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-314/events.jir +0 -0
  113. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-314/mcp_manager.jir +0 -0
  114. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-314/memory.jir +0 -0
  115. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-314/permission.jir +0 -0
  116. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-314/prompt.jir +0 -0
  117. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-314/serve_entry.jir +0 -0
  118. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-314/server.jir +0 -0
  119. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-314/tool/__init__.jir +0 -0
  120. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-314/tool/checked.jir +0 -0
  121. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-314/tool/delegation.jir +0 -0
  122. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-314/tool/filesystem.jir +0 -0
  123. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-314/tool/git.jir +0 -0
  124. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-314/tool/guarded.jir +0 -0
  125. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-314/tool/jac_analyzer.jir +0 -0
  126. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-314/tool/jac_docs.jir +0 -0
  127. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-314/tool/jac_tools.jir +0 -0
  128. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-314/tool/mcp.jir +0 -0
  129. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-314/tool/preview.jir +0 -0
  130. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-314/tool/question.jir +0 -0
  131. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-314/tool/search.jir +0 -0
  132. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-314/tool/shell.jir +0 -0
  133. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-314/tool/task.jir +0 -0
  134. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-314/tool/think.jir +0 -0
  135. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-314/tool/todo.jir +0 -0
  136. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-314/tool/validate.jir +0 -0
  137. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-314/tool/web.jir +0 -0
  138. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-314/util/__init__.jir +0 -0
  139. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-314/util/colors.jir +0 -0
  140. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-314/util/sandbox.jir +0 -0
  141. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-314/util/tool_output.jir +0 -0
  142. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/_precompiled/cpython-314/walkers.jir +0 -0
  143. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/cli_entry.py +0 -0
  144. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/context.jac +0 -0
  145. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/cost_tracker.jac +0 -0
  146. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/data/examples/ai_agent.md +0 -0
  147. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/data/examples/core_patterns.md +0 -0
  148. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/data/examples/todo_app.md +0 -0
  149. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/data/reference/ai.md +0 -0
  150. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/data/reference/backend.md +0 -0
  151. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/data/reference/osp.md +0 -0
  152. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/data/reference/syntax.md +0 -0
  153. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/data/rules/core_jac.md +0 -0
  154. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/data/rules/workflow.md +0 -0
  155. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/events.jac +0 -0
  156. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/impl/config.impl.jac +0 -0
  157. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/impl/mcp_manager.impl.jac +0 -0
  158. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/impl/memory.impl.jac +0 -0
  159. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/impl/permission.impl.jac +0 -0
  160. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/impl/prompt.impl.jac +0 -0
  161. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/impl/walkers.impl.jac +0 -0
  162. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/mcp_manager.jac +0 -0
  163. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/memory.jac +0 -0
  164. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/nodes.jac +0 -0
  165. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/permission.jac +0 -0
  166. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/prompt.jac +0 -0
  167. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/serve_entry.jac +0 -0
  168. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/server.jac +0 -0
  169. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/tool/__init__.jac +0 -0
  170. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/tool/checked.jac +0 -0
  171. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/tool/delegation.jac +0 -0
  172. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/tool/filesystem.jac +0 -0
  173. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/tool/git.jac +0 -0
  174. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/tool/guarded.jac +0 -0
  175. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/tool/impl/checked.impl.jac +0 -0
  176. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/tool/impl/delegation.impl.jac +0 -0
  177. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/tool/impl/filesystem.impl.jac +0 -0
  178. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/tool/impl/git.impl.jac +0 -0
  179. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/tool/impl/guarded.impl.jac +0 -0
  180. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/tool/impl/jac_analyzer.impl.jac +0 -0
  181. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/tool/impl/jac_docs.impl.jac +0 -0
  182. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/tool/impl/jac_tools.impl.jac +0 -0
  183. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/tool/impl/mcp.impl.jac +0 -0
  184. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/tool/impl/preview.impl.jac +0 -0
  185. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/tool/impl/question.impl.jac +0 -0
  186. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/tool/impl/search.impl.jac +0 -0
  187. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/tool/impl/shell.impl.jac +0 -0
  188. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/tool/impl/task.impl.jac +0 -0
  189. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/tool/impl/think.impl.jac +0 -0
  190. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/tool/impl/todo.impl.jac +0 -0
  191. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/tool/impl/validate.impl.jac +0 -0
  192. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/tool/impl/web.impl.jac +0 -0
  193. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/tool/jac_analyzer.jac +0 -0
  194. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/tool/jac_docs.jac +0 -0
  195. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/tool/jac_tools.jac +0 -0
  196. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/tool/mcp.jac +0 -0
  197. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/tool/preview.jac +0 -0
  198. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/tool/question.jac +0 -0
  199. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/tool/scaffold.jac +0 -0
  200. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/tool/search.jac +0 -0
  201. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/tool/shell.jac +0 -0
  202. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/tool/task.jac +0 -0
  203. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/tool/think.jac +0 -0
  204. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/tool/todo.jac +0 -0
  205. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/tool/validate.jac +0 -0
  206. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/tool/web.jac +0 -0
  207. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/util/__init__.jac +0 -0
  208. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/util/colors.jac +0 -0
  209. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/util/impl/sandbox.impl.jac +0 -0
  210. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/util/impl/tool_output.impl.jac +0 -0
  211. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/util/sandbox.jac +0 -0
  212. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/util/tool_output.jac +0 -0
  213. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder/walkers.jac +0 -0
  214. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder.egg-info/SOURCES.txt +0 -0
  215. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder.egg-info/dependency_links.txt +0 -0
  216. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder.egg-info/entry_points.txt +0 -0
  217. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder.egg-info/requires.txt +0 -0
  218. {jac_coder-0.1.3 → jac_coder-0.1.5}/jac_coder.egg-info/top_level.txt +0 -0
  219. {jac_coder-0.1.3 → jac_coder-0.1.5}/setup.cfg +0 -0
  220. {jac_coder-0.1.3 → jac_coder-0.1.5}/tests/test_context.py +0 -0
  221. {jac_coder-0.1.3 → jac_coder-0.1.5}/tests/test_events.py +0 -0
  222. {jac_coder-0.1.3 → jac_coder-0.1.5}/tests/test_graph.py +0 -0
  223. {jac_coder-0.1.3 → jac_coder-0.1.5}/tests/test_interact.py +0 -0
  224. {jac_coder-0.1.3 → jac_coder-0.1.5}/tests/test_memory.py +0 -0
  225. {jac_coder-0.1.3 → jac_coder-0.1.5}/tests/test_selfcorrect.py +0 -0
  226. {jac_coder-0.1.3 → jac_coder-0.1.5}/tests/test_tools.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jac-coder
3
- Version: 0.1.3
3
+ Version: 0.1.5
4
4
  Summary: AI coding agent backend for Jac, powered by jac-byllm
5
5
  Requires-Python: >=3.12
6
6
  Requires-Dist: python-dotenv>=1.0.0
@@ -5,25 +5,25 @@
5
5
  },
6
6
  "api.jac": {
7
7
  "impl_hashes": {
8
- "impl/api.impl.jac": "82eb1a5e35d88d6e4add1cac65621a4c27da065766595bf575b8dd511dc94bfb"
8
+ "impl/api.impl.jac": "20d793ad7cc3a21ec126872d6665a56af6b244182dc04f151e771f06f2fbc1c0"
9
9
  },
10
- "source_hash": "5b6bfc998fd351bc4e14fe3bd033a055e362d7b8d494f5b169ba58744325fea1"
10
+ "source_hash": "6fd2526d7eaf26c7b0cd95877381945a45734a75845b67fa4245d781db4a04b9"
11
11
  },
12
12
  "config.jac": {
13
13
  "impl_hashes": {
14
14
  "impl/config.impl.jac": "2765b4930f5bc7ff4453d4203c072f1dccb131b53fd76c64ad2c7f769b891663"
15
15
  },
16
- "source_hash": "34b8eaa9fc8ff4e29c48c95b0be017102931c9860d92b422ba65debf8bc5a96d"
16
+ "source_hash": "1c804b1d5e46039cca3ef67dc890c6a8dee6a3cdfd561ea181f1b9c56719b3e5"
17
17
  },
18
18
  "context.jac": {
19
19
  "impl_hashes": {
20
- "impl/context.impl.jac": "b6305ec0501d6ca87e22addafc72304e88fc3fbaa844459bdddcf94cc57c79ea"
20
+ "impl/context.impl.jac": "03c0645bf220dec2bc43438557229b8783f72be4ca46b48525ff767e1846559d"
21
21
  },
22
22
  "source_hash": "b4602e99adfc979830b189346050d205dcce45ba4a58f43bd3e5e0dc52dc84bd"
23
23
  },
24
24
  "cost_tracker.jac": {
25
25
  "impl_hashes": {
26
- "impl/cost_tracker.impl.jac": "c7679953be4b6a4e4697575f3fd8e2b9467c294ca341c7584a253cd6ad447889"
26
+ "impl/cost_tracker.impl.jac": "f6fc36660b31917b93f3a73b44aaaa340e024e45b9a855dbfc9e35f713a52032"
27
27
  },
28
28
  "source_hash": "41f2358725b03d093102da10138b9334e04e36d600b1fff1e13566b434c70179"
29
29
  },
@@ -44,7 +44,7 @@
44
44
  },
45
45
  "nodes.jac": {
46
46
  "impl_hashes": {
47
- "impl/nodes.impl.jac": "344aae1489d0f8b4adb26849208ac503359af38e115e5c66095a9484c7214d0c"
47
+ "impl/nodes.impl.jac": "224d675e46ae4a54afac2ac47db5c66dc11ece25af4085d2eebe8fc7e33b75f8"
48
48
  },
49
49
  "source_hash": "eae8bd478013a0d330ce40b2c321cfa53fe9e664bbc8ae6d03d6010c61f339ac"
50
50
  },
@@ -137,7 +137,7 @@
137
137
  },
138
138
  "tool/scaffold.jac": {
139
139
  "impl_hashes": {
140
- "tool/impl/scaffold.impl.jac": "b4dcc0b46e7d844d5cbf6aa5a2109fa2f265b184332052d5cbc4b768710e7988"
140
+ "tool/impl/scaffold.impl.jac": "1e465d3a37c2f63638a12876d490cd9384a47479152a85fc8373a12bf0b8505a"
141
141
  },
142
142
  "source_hash": "ebb6d09098f1941aa4baf9f54541bef6a0e430b32549feda0d4021448e4a12d8"
143
143
  },
@@ -63,7 +63,8 @@ def chat(
63
63
  mode: str = "full",
64
64
  agent_context: str = "",
65
65
  images: list = [],
66
- edit_mode: str = "auto"
66
+ edit_mode: str = "auto",
67
+ env_overrides: dict = {}
67
68
  ) -> dict;
68
69
 
69
70
  def list_sessions() -> list;
@@ -0,0 +1,88 @@
1
+ import os;
2
+ import json;
3
+ import threading;
4
+ import from pathlib { Path }
5
+ import from dotenv { load_dotenv }
6
+ import from byllm.lib { Model }
7
+
8
+
9
+ obj JacCoderConfig {
10
+ has default_model: str = "gpt-5.2-2025-12-11",
11
+ temperature: float = 0.2,
12
+ max_tokens: int = 16384,
13
+ max_react_iterations: int = 30,
14
+ project_dir: str = "";
15
+ }
16
+
17
+ glob _config: JacCoderConfig = JacCoderConfig();
18
+ glob model_name: str = _config.default_model;
19
+
20
+ # Thread-safe per-session model override.
21
+ # SessionAwareModel overrides invoke() to check thread-local state.
22
+ # `by llm()` calls llm.invoke(mt_run) → our override creates a
23
+ # per-call Model with the thread's model_name/api_key if set.
24
+ # No global mutation, no cross-thread contamination.
25
+ import from jaclang.jac0core.runtime { MTRuntime }
26
+
27
+ glob _tl = threading.local();
28
+
29
+ obj SessionAwareModel(Model) {
30
+ override def invoke(mt_run: MTRuntime) -> object {
31
+ import logging;
32
+ _logger = logging.getLogger("jac_coder.config");
33
+ tl_model = getattr(_tl, "model_name", "");
34
+ _logger.info(f"SessionAwareModel.invoke() tl_model={tl_model} default={self.model_name}");
35
+ if tl_model {
36
+ tl_key = getattr(_tl, "api_key", "");
37
+ temp = Model(model_name=tl_model, api_key=tl_key) if tl_key else Model(model_name=tl_model);
38
+ _logger.info(f"Delegating to temp Model: {tl_model} has_key={bool(tl_key)}");
39
+ return temp.invoke(mt_run);
40
+ }
41
+ return super.invoke(mt_run);
42
+ }
43
+ }
44
+
45
+ glob llm = SessionAwareModel(model_name=model_name);
46
+
47
+ """Set a thread-local model override. Fully concurrent — no locks, no global mutation."""
48
+ def set_session_llm(model_name_override: str, api_key_override: str = "") {
49
+ import logging;
50
+ _tl.model_name = model_name_override;
51
+ _tl.api_key = api_key_override;
52
+ logging.getLogger("jac_coder.config").info(
53
+ f"Session LLM set: thread={threading.current_thread().name} model={model_name_override} has_key={bool(api_key_override)}"
54
+ );
55
+ }
56
+
57
+ """Clear the thread-local model override."""
58
+ def clear_session_llm() {
59
+ import logging;
60
+ prev = getattr(_tl, "model_name", "");
61
+ _tl.model_name = "";
62
+ _tl.api_key = "";
63
+ if prev {
64
+ logging.getLogger("jac_coder.config").info(
65
+ f"Session LLM cleared: thread={threading.current_thread().name} was={prev}"
66
+ );
67
+ }
68
+ }
69
+
70
+ # --- Config ---
71
+ def _merge_from_file(config: JacCoderConfig, path: str) -> None;
72
+ def load_config(project_dir: str = "") -> JacCoderConfig;
73
+ def get_config() -> JacCoderConfig;
74
+ def get_home_dir() -> str;
75
+ def get_data_dir() -> str;
76
+
77
+ # --- Model management ---
78
+ def set_model(model: str) -> dict;
79
+ def get_model() -> dict;
80
+
81
+ with entry {
82
+ load_dotenv(override=True);
83
+ load_config();
84
+ # Sync the default LLM with loaded config — created at module load time
85
+ # with the hardcoded default before load_config() runs.
86
+ model_name = _config.default_model;
87
+ llm.model_name = model_name;
88
+ }
@@ -121,7 +121,6 @@ def:pub add_comment(post_id: str, author: str, text: str) -> Comment {
121
121
  }
122
122
  }
123
123
  }
124
- }
125
124
 
126
125
  # --- Walker endpoint (single-request post + comments) ---
127
126
 
@@ -279,13 +278,13 @@ def:pub useComments(postId: str) -> dict {
279
278
  import from "@jac/runtime" { Link }
280
279
 
281
280
  def:pub PostCard(props: dict) -> JsxElement {
282
- onDelete = props.onDelete or None;
281
+ onDelete = props["onDelete"] or None;
283
282
 
284
283
  # Props are always dict — extract values
285
- postId = props.postId or "";
286
- title = props.title or "Untitled";
287
- body = props.body or "";
288
- category = props.category or "";
284
+ postId = props["postId"] or "";
285
+ title = props["title"] or "Untitled";
286
+ body = props["body"] or "";
287
+ category = props["category"] or "";
289
288
 
290
289
  preview = body;
291
290
  if len(body) > 150 { preview = body[0:150] + "..."; }
@@ -309,7 +308,7 @@ def:pub PostCard(props: dict) -> JsxElement {
309
308
  import from ..hooks.useComments { useComments }
310
309
 
311
310
  def:pub CommentList(props: dict) -> JsxElement {
312
- postId = props.postId or "";
311
+ postId = props["postId"] or "";
313
312
  data = useComments(postId);
314
313
  comments = data["comments"] or [];
315
314
 
@@ -7,7 +7,7 @@ Components are public functions returning `JsxElement`.
7
7
  ```jac
8
8
  # In a .cl.jac file:
9
9
  def:pub Header(props: dict) -> JsxElement {
10
- title = props.title or "";
10
+ title = props["title"] or "";
11
11
  return (
12
12
  <header className="border-b px-6 py-4">
13
13
  <h1 className="text-xl font-bold">{title}</h1>
@@ -45,8 +45,12 @@ cl def:pub app -> JsxElement {
45
45
  }
46
46
  }
47
47
 
48
+ def handle_input(e: any) -> None {
49
+ text = e.target.value;
50
+ }
51
+
48
52
  return <div>
49
- <input value={text} onChange={lambda e: any -> None { text = e.target.value; }} />
53
+ <input value={text} onChange={handle_input} />
50
54
  <button onClick={add}>Add</button>
51
55
  {[<p key={jid(t)}>{t.title}</p> for t in todos]}
52
56
  </div>;
@@ -88,7 +92,7 @@ NEVER use `useEffect` — use `can with entry` instead. NEVER import from react.
88
92
 
89
93
  ## Event Handlers
90
94
 
91
- ALL handlers must be named `def` functions defined BEFORE `return`. NEVER use lambda or inline def in JSX.
95
+ ALL handlers MUST be named `def` functions defined BEFORE `return`. NEVER use `lambda` or inline `def` in JSX.
92
96
 
93
97
  ```jac
94
98
  def:pub TodoList() -> JsxElement {
@@ -129,7 +133,7 @@ Use `jid(node)` to get the unique graph ID of a node object. Essential for React
129
133
  ## Typed objects vs props — where dot access works
130
134
 
131
135
  **Dot access** works on typed objects returned from API calls (via `sv import`).
132
- **Props are always `dict`** — use dict access (`props.title` or `props["title"]`).
136
+ **Props are always `dict`** — use bracket access (`props["title"]`). NEVER use dot access (`props.title`).
133
137
 
134
138
  ```jac
135
139
  # In hook — typed objects from API, dot access works
@@ -141,9 +145,9 @@ todos[0].title # dot access on typed object
141
145
 
142
146
  # Inside child component — props is a dict, NOT a typed object
143
147
  def:pub TodoItem(props: dict) -> JsxElement {
144
- title = props.title or ""; # props access (dict)
145
- completed = props.completed or False;
146
- todoId = props.todoId or "";
148
+ title = props["title"] or ""; # props access (dict)
149
+ completed = props["completed"] or False;
150
+ todoId = props["todoId"] or "";
147
151
  }
148
152
  ```
149
153
 
@@ -177,7 +181,7 @@ items = [item for item in items if item["id"] != targetId];
177
181
  <Button><span>7</span></Button>
178
182
  <Button><span>8</span></Button>
179
183
 
180
- # RIGHT — child component that renders via str(props.label)
184
+ # RIGHT — child component that renders via str(props["label"])
181
185
  {[<KeyBtn key={k["label"]} label={k["label"]} /> for k in keys]}
182
186
  ```
183
187
 
@@ -53,12 +53,12 @@ The #1 runtime crash in .cl.jac. Happens when accessing property on `undefined`.
53
53
 
54
54
  ```jac
55
55
  # WRONG — crashes if parent doesn't pass "items" prop
56
- items = props.items; # undefined!
56
+ items = props["items"]; # undefined!
57
57
  return <div>{[... for item in items]}</div>; # CRASH
58
58
 
59
59
  # RIGHT — always default props
60
- items = props.items or [];
61
- title = props.title or "";
60
+ items = props["items"] or [];
61
+ title = props["title"] or "";
62
62
 
63
63
  # WRONG — chaining on undefined
64
64
  data = result.reports[0].items; # CRASH if reports empty
@@ -122,7 +122,7 @@ keys = [{"label": "7", "onClick": h7}, {"label": "8", "onClick": h8}];
122
122
 
123
123
  # RIGHT — if you must loop, pass data as a prop to a child component
124
124
  {[<KeyButton key={k["label"]} label={k["label"]} onClick={k["onClick"]} /> for k in keys]}
125
- # Where KeyButton renders: <button onClick={props.onClick}><span>{str(props.label)}</span></button>
125
+ # Where KeyButton renders: <button onClick={props["onClick"]}><span>{str(props["label"])}</span></button>
126
126
  ```
127
127
 
128
128
  **Rule:** When rendering a list of elements with text content, either:
@@ -157,8 +157,8 @@ def:pub Header(title: str, theme: str) -> JsxElement { ... }
157
157
 
158
158
  # RIGHT — always use props: dict, destructure inside
159
159
  def:pub Header(props: dict) -> JsxElement {
160
- title = props.title or "";
161
- theme = props.theme or "light";
160
+ title = props["title"] or "";
161
+ theme = props["theme"] or "light";
162
162
  return <header>{title}</header>;
163
163
  }
164
164
 
@@ -226,23 +226,29 @@ can with exit { ... } # cleanup/unmount
226
226
 
227
227
  **NEVER use `useEffect(lambda...)` — that is OLD syntax.**
228
228
 
229
- ## Event handlers — prefer named functions, lambda OK for simple cases
229
+ ## Event handlers — ALWAYS use named functions
230
230
 
231
231
  ```jac
232
- # PREFERRED — named function ABOVE return, passed by name
232
+ # RIGHT — named function ABOVE return, passed by name
233
233
  def handle_click() -> None {
234
234
  count = count + 1;
235
235
  }
236
- return <button onClick={handle_click}>Click</button>;
236
+ def handle_input(e: any) -> None {
237
+ text = e.target.value;
238
+ }
239
+ return <div>
240
+ <button onClick={handle_click}>Click</button>
241
+ <input onChange={handle_input} />
242
+ </div>;
237
243
 
238
- # OK for simple one-liners — lambda with typed param
244
+ # WRONG — lambda in JSX
239
245
  <input onChange={lambda e: any -> None { text = e.target.value; }} />
240
246
 
241
- # WRONG — inline def (NOT lambda)
247
+ # WRONG — inline def in JSX
242
248
  <button onClick={def(e: any) -> None { count = count + 1; }}>
243
249
  ```
244
250
 
245
- Use named `def` handlers for complex logic. Lambda is fine for simple state updates like `onChange` on inputs. NEVER use `def` inline in JSX attributes.
251
+ NEVER use `lambda` or inline `def` in JSX attributes. ALWAYS define named `def` handlers BEFORE `return` and pass by name.
246
252
 
247
253
  ## Functions MUST be defined BEFORE return
248
254
 
@@ -378,8 +384,8 @@ name = item["name"] if item and "name" in item else "";
378
384
  {[<Card title={p["title"] if p and "title" in p else ""} /> for p in projects if p]}
379
385
 
380
386
  # Props — always default
381
- items = props.items or [];
382
- title = props.title or "";
387
+ items = props["items"] or [];
388
+ title = props["title"] or "";
383
389
  ```
384
390
 
385
391
  **CRITICAL: The `"key" in x` operator crashes if `x` is undefined.** Always write `x and "key" in x`.
@@ -131,7 +131,8 @@ impl chat(
131
131
  mode: str = "full",
132
132
  agent_context: str = "",
133
133
  images: list = [],
134
- edit_mode: str = "auto"
134
+ edit_mode: str = "auto",
135
+ env_overrides: dict = {}
135
136
  ) -> dict {
136
137
  # Find session — try registry first (works across threads), then graph
137
138
  session = _session_registry.get(session_id);
@@ -152,6 +153,25 @@ impl chat(
152
153
  }
153
154
  work_dir = session.directory;
154
155
 
156
+ # Apply per-session env overrides (e.g. user's OPENAI_API_KEY from IDE settings).
157
+ # Stores a thread-local Model override so the user's key is used for this
158
+ # session only — no mutation of os.environ or the global llm object.
159
+ _has_llm_override = False;
160
+ if env_overrides {
161
+ import from jac_coder.config { set_session_llm }
162
+ import logging as _chatlog;
163
+ _api_key = str(env_overrides.get("OPENAI_API_KEY", env_overrides.get("ANTHROPIC_API_KEY", "")));
164
+ _model_name = str(env_overrides.get("MODEL", ""));
165
+ _chatlog.getLogger("jac_coder.api").info(f"env_overrides received: model={_model_name} has_key={bool(_api_key)}");
166
+ if _api_key or _model_name {
167
+ import from jac_coder.config { llm as _current_llm }
168
+ _override_model_name = _model_name or str(_current_llm.model_name);
169
+ _chatlog.getLogger("jac_coder.api").info(f"Applying session override: {_current_llm.model_name} -> {_override_model_name}");
170
+ set_session_llm(_override_model_name, _api_key);
171
+ _has_llm_override = True;
172
+ }
173
+ }
174
+
155
175
  # Bind session_id + edit_mode to this thread so guarded tools know
156
176
  # whether to auto-allow, prompt, or deny write/edit/bash operations.
157
177
  _set_chat_session(session_id, edit_mode);
@@ -342,6 +362,11 @@ impl chat(
342
362
  if on_event {
343
363
  clear_event_callbacks();
344
364
  }
365
+ # Clear thread-local LLM override
366
+ if _has_llm_override {
367
+ import from jac_coder.config { clear_session_llm }
368
+ clear_session_llm();
369
+ }
345
370
  # Clean up thread context (session_id + edit_mode)
346
371
  _clear_chat_session();
347
372
  }
@@ -14,7 +14,7 @@ def _build_prefix(
14
14
  # This is the agent's persistent knowledge of the project state.
15
15
  is_progress_file = project_summary.lstrip().startswith("#");
16
16
  label = "Project progress (.jaccoder/progress.md)" if is_progress_file else "Project context";
17
- parts.append(f"{label}:\n{project_summary}");
17
+ parts.append(f"[INTERNAL — do NOT present this to the user unless they ask about the project. This is your background knowledge for making informed decisions.]\n{label}:\n{project_summary}");
18
18
  }
19
19
  if active_files {
20
20
  parts.append("Active files: " + ", ".join(active_files));
@@ -3,18 +3,24 @@ impl record_usage(usage_data: dict, agent: str = "main") -> None {
3
3
  return;
4
4
  }
5
5
 
6
- total = usage_data.get("total", {});
7
6
  per_call = usage_data.get("per_call", []);
8
7
 
9
8
  with _lock {
10
- # Record each individual LLM call
9
+ # Record each individual LLM call and accumulate totals from per-call data
10
+ # (the top-level `total` dict often omits cached_tokens, so summing per-call
11
+ # is the reliable source of truth)
11
12
  for (i, call) in enumerate(per_call) {
12
13
  call_record = {
13
14
  "agent": agent,
14
15
  "iteration": len(_session_data["calls"]) + 1,
15
16
  "input_tokens": int(call.get("input_tokens", 0) or call.get("prompt_tokens", 0) or 0),
16
17
  "output_tokens": int(call.get("output_tokens", 0) or call.get("completion_tokens", 0) or 0),
17
- "cached_tokens": int(call.get("cached_tokens", 0) or call.get("cache_read_input_tokens", 0) or 0),
18
+ "cached_tokens": int(
19
+ call.get("cached_tokens", 0)
20
+ or call.get("cache_read_input_tokens", 0)
21
+ or (call.get("prompt_tokens_details") or {}).get("cached_tokens", 0)
22
+ or 0
23
+ ),
18
24
  "total_tokens": int(call.get("total_tokens", 0) or 0)
19
25
  };
20
26
  # Calculate total if not provided
@@ -22,15 +28,12 @@ impl record_usage(usage_data: dict, agent: str = "main") -> None {
22
28
  call_record["total_tokens"] = call_record["input_tokens"] + call_record["output_tokens"];
23
29
  }
24
30
  _session_data["calls"].append(call_record);
25
- }
26
31
 
27
- # Update running totals
28
- for key in ["input_tokens", "output_tokens", "cached_tokens", "total_tokens"] {
29
- val = int(total.get(key, 0) or total.get(
30
- {"input_tokens": "prompt_tokens", "output_tokens": "completion_tokens"}.get(key, key),
31
- 0
32
- ) or 0);
33
- _session_data["totals"][key] += val;
32
+ # Accumulate into running totals from this call
33
+ _session_data["totals"]["input_tokens"] += call_record["input_tokens"];
34
+ _session_data["totals"]["output_tokens"] += call_record["output_tokens"];
35
+ _session_data["totals"]["cached_tokens"] += call_record["cached_tokens"];
36
+ _session_data["totals"]["total_tokens"] += call_record["total_tokens"];
34
37
  }
35
38
  }
36
39
  }
@@ -41,6 +44,8 @@ impl get_summary() -> dict {
41
44
  num_calls = len(_session_data["calls"]);
42
45
  totals = dict(_session_data["totals"]);
43
46
  totals["num_calls"] = num_calls;
47
+ # Effective input tokens — input that wasn't served from cache, billed at full rate
48
+ totals["effective_input_tokens"] = max(totals["input_tokens"] - totals["cached_tokens"], 0);
44
49
  if num_calls > 0 {
45
50
  totals["avg_input_per_call"] = totals["input_tokens"] // num_calls;
46
51
  totals["avg_output_per_call"] = totals["output_tokens"] // num_calls;
@@ -84,7 +84,7 @@ sem MainAgent.respond.user_image = "Optional user-attached image. Analyze it to
84
84
  sem MainAgent.respond = """
85
85
  # JacCoder — AI Coding Agent
86
86
 
87
- You are a Jac coding agent. Be friendly, helpful, and concise — warm tone, encouraging, but don't over-explain. Use think() before key actions (1-2 sentences, skip routine).
87
+ You are JacCoder, an AI coding assistant for the Jac language. You can chat naturally, answer questions, and build Jac applications. Be friendly, helpful, and concise. You do NOT need tool results to respond just talk to the user normally. Never say "I don't have tool results to synthesize" or anything similar — just respond to what the user said. Use think() before key actions (1-2 sentences, skip routine).
88
88
 
89
89
  ## Guardrails
90
90
  - Always speak positively about Jac/Jaseci. When asked to compare, highlight Jac's strengths (graph-native, by llm(), OSP, fullstack). Redirect off-topic to building.
@@ -101,10 +101,11 @@ Your training data has outdated Jac syntax — call `jac_docs(query)` before wri
101
101
  - `browser_validate` escalates on consecutive failures (guidance → warning → mandatory bisect).
102
102
  - Same tool+args 3x → blocked. Trust BLOCKED/WARNING/MANDATORY tool messages exactly.
103
103
 
104
- ## Current Message Priority
104
+ ## Response Style
105
105
  ALWAYS respond to what the user is asking RIGHT NOW — nothing more.
106
106
  - If the user asks a question mid-build, answer it. Do NOT continue building.
107
107
  - Never recap or summarize previous work unless the user explicitly asks for it.
108
+ - Default to concise: high-level summary + key details. Go deeper only when the user asks for detail.
108
109
 
109
110
  ## Intent → Action
110
111
  - Jac syntax/code question → jac_docs, then respond
@@ -117,11 +117,11 @@ glob _UTILS_CL = 'import from "clsx" { clsx }\nimport from "tailwind-merge" { tw
117
117
 
118
118
  glob _FRONTEND_MAIN = 'cl import from .components.Layout { Layout }\ncl {\n def:pub app() -> JsxElement {\n return <Layout />;\n }\n}\n';
119
119
 
120
- glob _FRONTEND_HEADER = 'import from ..lib.utils { cn }\n\ndef:pub Header(title: str, theme: str, on_toggle_theme: any) -> JsxElement {\n return (\n <header className="border-b border-border px-6 py-4 flex items-center justify-between">\n <h1 className="text-xl font-bold">{title}</h1>\n <button onClick={on_toggle_theme}\n className="px-3 py-1 bg-secondary text-secondary-foreground rounded-lg text-sm">\n {(theme == "dark") and "Light" or "Dark"}\n </button>\n </header>\n );\n}\n';
120
+ glob _FRONTEND_HEADER = 'import from ..lib.utils { cn }\n\ndef:pub Header(props: dict) -> JsxElement {\n # Props — extract from dict\n title = props["title"] or "";\n theme = props["theme"] or "light";\n on_toggle_theme = props["onToggleTheme"] or None;\n\n return (\n <header className="border-b border-border px-6 py-4 flex items-center justify-between">\n <h1 className="text-xl font-bold">{title}</h1>\n <button onClick={on_toggle_theme}\n className="px-3 py-1 bg-secondary text-secondary-foreground rounded-lg text-sm">\n {(theme == "dark") and "Light" or "Dark"}\n </button>\n </header>\n );\n}\n';
121
121
 
122
122
  glob _FRONTEND_COUNTER = 'import from ..lib.utils { cn }\n\ndef:pub Counter() -> JsxElement {\n # State\n has count: int = 0;\n\n # Handlers\n def handle_increment() -> None {\n count = count + 1;\n }\n\n # Render\n return (\n <button onClick={handle_increment}\n className="px-4 py-2 bg-primary text-primary-foreground rounded-lg">\n Count: {str(count)}\n </button>\n );\n}\n';
123
123
 
124
- glob _FRONTEND_APP = 'import "..styles.global.css";\nimport from .Header { Header }\nimport from .Counter { Counter }\n\ndef:pub Layout() -> JsxElement {\n # State\n has theme: str = "light";\n\n # Effects\n can with (theme) entry {\n if theme == "dark" {\n document.documentElement.classList.add("dark");\n } else {\n document.documentElement.classList.remove("dark");\n }\n }\n\n # Handlers\n def handle_toggle_theme() -> None {\n theme = (theme == "dark") and "light" or "dark";\n }\n\n # Render\n return (\n <div className="min-h-screen bg-background text-text-primary">\n <Header title="__NAME__" theme={theme} on_toggle_theme={handle_toggle_theme} />\n <main className="max-w-2xl mx-auto px-4 py-8">\n <Counter />\n </main>\n </div>\n );\n}\n';
124
+ glob _FRONTEND_APP = 'import "..styles.global.css";\nimport from .Header { Header }\nimport from .Counter { Counter }\n\ndef:pub Layout() -> JsxElement {\n # State\n has theme: str = "light";\n\n # Effects\n can with (theme) entry {\n if theme == "dark" {\n document.documentElement.classList.add("dark");\n } else {\n document.documentElement.classList.remove("dark");\n }\n }\n\n # Handlers\n def handle_toggle_theme() -> None {\n theme = (theme == "dark") and "light" or "dark";\n }\n\n # Render\n return (\n <div className="min-h-screen bg-background text-text-primary">\n <Header title="__NAME__" theme={theme} onToggleTheme={handle_toggle_theme} />\n <main className="max-w-2xl mx-auto px-4 py-8">\n <Counter />\n </main>\n </div>\n );\n}\n';
125
125
 
126
126
 
127
127
  # ===========================================================================
@@ -132,14 +132,14 @@ glob _FULLSTACK_MAIN = 'import from datetime { datetime }\n\n\nnode Item {\n
132
132
 
133
133
  glob _FULLSTACK_HOOK = 'sv import from ..main { get_items, add_item, delete_item }\n\ndef:pub useItems() -> dict {\n # State\n has items: list = [];\n has loading: bool = True;\n has error: str = "";\n\n # Fetch data on mount — returns typed list[Item] objects\n async can with entry {\n try {\n items = await get_items() or [];\n } except Exception as e {\n error = str(e);\n }\n loading = False;\n }\n\n # Handlers\n async def handle_add(name: str, description: str = "") -> None {\n if not name { return; }\n try {\n item = await add_item(name, description); # positional args only\n items = items + [item];\n } except Exception as e {\n error = str(e);\n }\n }\n\n async def handle_delete(item_id: str) -> None {\n try {\n await delete_item(item_id); # positional args only\n items = [i for i in items if jid(i) != item_id];\n } except Exception as e {\n error = str(e);\n }\n }\n\n return {\n "items": items,\n "loading": loading,\n "error": error,\n "handleAdd": handle_add,\n "handleDelete": handle_delete\n };\n}\n';
134
134
 
135
- glob _FULLSTACK_HEADER = 'import from ..lib.utils { cn }\n\ndef:pub Header(title: str, theme: str, on_toggle_theme: any) -> JsxElement {\n return (\n <header className="border-b border-border px-6 py-4 flex items-center justify-between">\n <h1 className="text-xl font-bold">{title}</h1>\n <button onClick={on_toggle_theme}\n className="px-3 py-1 bg-secondary text-secondary-foreground rounded-lg text-sm">\n {(theme == "dark") and "Light" or "Dark"}\n </button>\n </header>\n );\n}\n';
135
+ glob _FULLSTACK_HEADER = 'import from ..lib.utils { cn }\n\ndef:pub Header(props: dict) -> JsxElement {\n # Props — extract from dict\n title = props["title"] or "";\n theme = props["theme"] or "light";\n on_toggle_theme = props["onToggleTheme"] or None;\n\n return (\n <header className="border-b border-border px-6 py-4 flex items-center justify-between">\n <h1 className="text-xl font-bold">{title}</h1>\n <button onClick={on_toggle_theme}\n className="px-3 py-1 bg-secondary text-secondary-foreground rounded-lg text-sm">\n {(theme == "dark") and "Light" or "Dark"}\n </button>\n </header>\n );\n}\n';
136
136
 
137
137
  glob _FULLSTACK_ITEMLIST = 'import from ..lib.utils { cn }\nimport from ..hooks.useItems { useItems }\nimport from .ItemCard { ItemCard }\n\ndef:pub ItemList() -> JsxElement {\n # Fetch data — typed Item objects\n data = useItems();\n items = data["items"] or [];\n\n # State\n has input_value: str = "";\n\n # Handlers\n def handle_input_change(e: any) -> None {\n input_value = e.target.value;\n }\n\n def handle_add() -> None {\n if input_value {\n data["handleAdd"](input_value);\n input_value = "";\n }\n }\n\n def handle_key_down(e: any) -> None {\n if e.key == "Enter" {\n e.preventDefault();\n handle_add();\n }\n }\n\n # Guard\n if data["loading"] {\n return <p className="text-text-secondary text-center py-8">Loading...</p>;\n }\n\n # Render\n return (\n <div>\n {data["error"] and (\n <p className="text-error mb-4">{data["error"]}</p>\n )}\n <div className="flex gap-2 mb-6">\n <input\n value={input_value}\n onChange={handle_input_change}\n onKeyDown={handle_key_down}\n placeholder="Add an item..."\n className="flex-1 px-4 py-2 border border-border rounded-lg bg-surface"\n />\n <button onClick={handle_add}\n className="px-4 py-2 bg-primary text-primary-foreground rounded-lg flex items-center gap-1">\n + Add\n </button>\n </div>\n {len(items) == 0 and (\n <p className="text-text-secondary text-center py-8">No items yet. Add one above!</p>\n )}\n <div className="space-y-2">\n {[\n <ItemCard key={jid(item)} itemId={jid(item)} name={item.name} description={item.description} onDelete={data["handleDelete"]} />\n for item in items\n ]}\n </div>\n </div>\n );\n}\n';
138
138
 
139
- glob _FULLSTACK_APP = 'import "..styles.global.css";\nimport from .Header { Header }\nimport from .ItemList { ItemList }\n\ndef:pub Layout() -> JsxElement {\n # State\n has theme: str = "light";\n\n # Effects\n can with (theme) entry {\n if theme == "dark" {\n document.documentElement.classList.add("dark");\n } else {\n document.documentElement.classList.remove("dark");\n }\n }\n\n # Handlers\n def handle_toggle_theme() -> None {\n theme = (theme == "dark") and "light" or "dark";\n }\n\n # Render\n return (\n <div className="min-h-screen bg-background text-text-primary">\n <Header title="__NAME__" theme={theme} on_toggle_theme={handle_toggle_theme} />\n <main className="max-w-2xl mx-auto px-4 py-8">\n <ItemList />\n </main>\n </div>\n );\n}\n';
139
+ glob _FULLSTACK_APP = 'import "..styles.global.css";\nimport from .Header { Header }\nimport from .ItemList { ItemList }\n\ndef:pub Layout() -> JsxElement {\n # State\n has theme: str = "light";\n\n # Effects\n can with (theme) entry {\n if theme == "dark" {\n document.documentElement.classList.add("dark");\n } else {\n document.documentElement.classList.remove("dark");\n }\n }\n\n # Handlers\n def handle_toggle_theme() -> None {\n theme = (theme == "dark") and "light" or "dark";\n }\n\n # Render\n return (\n <div className="min-h-screen bg-background text-text-primary">\n <Header title="__NAME__" theme={theme} onToggleTheme={handle_toggle_theme} />\n <main className="max-w-2xl mx-auto px-4 py-8">\n <ItemList />\n </main>\n </div>\n );\n}\n';
140
140
 
141
141
 
142
- glob _FULLSTACK_ITEMCARD = 'def:pub ItemCard(props: dict) -> JsxElement {\n # Props — extract from dict\n itemId = props.itemId or "";\n name = props.name or "";\n description = props.description or "";\n on_delete = props.onDelete or None;\n\n # Handlers\n def handle_delete() -> None {\n if on_delete { on_delete(itemId); }\n }\n\n # Render\n return (\n <div className="flex items-center justify-between p-3 bg-surface border border-border rounded-lg">\n <div>\n <span className="font-medium">{name}</span>\n {description and (\n <p className="text-sm text-text-secondary mt-1">{description}</p>\n )}\n </div>\n <button onClick={handle_delete}\n className="text-error hover:opacity-75">\n ×\n </button>\n </div>\n );\n}\n';
142
+ glob _FULLSTACK_ITEMCARD = 'def:pub ItemCard(props: dict) -> JsxElement {\n # Props — extract from dict\n itemId = props["itemId"] or "";\n name = props["name"] or "";\n description = props["description"] or "";\n on_delete = props["onDelete"] or None;\n\n # Handlers\n def handle_delete() -> None {\n if on_delete { on_delete(itemId); }\n }\n\n # Render\n return (\n <div className="flex items-center justify-between p-3 bg-surface border border-border rounded-lg">\n <div>\n <span className="font-medium">{name}</span>\n {description and (\n <p className="text-sm text-text-secondary mt-1">{description}</p>\n )}\n </div>\n <button onClick={handle_delete}\n className="text-error hover:opacity-75">\n ×\n </button>\n </div>\n );\n}\n';
143
143
 
144
144
 
145
145
  # ===========================================================================
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jac-coder
3
- Version: 0.1.3
3
+ Version: 0.1.5
4
4
  Summary: AI coding agent backend for Jac, powered by jac-byllm
5
5
  Requires-Python: >=3.12
6
6
  Requires-Dist: python-dotenv>=1.0.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "jac-coder"
7
- version = "0.1.3"
7
+ version = "0.1.5"
8
8
  description = "AI coding agent backend for Jac, powered by jac-byllm"
9
9
  requires-python = ">=3.12"
10
10
  dependencies = [