zettelforge 2.5.1__tar.gz → 2.5.2__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 (311) hide show
  1. {zettelforge-2.5.1 → zettelforge-2.5.2}/CHANGELOG.md +77 -0
  2. {zettelforge-2.5.1 → zettelforge-2.5.2}/PKG-INFO +1 -1
  3. {zettelforge-2.5.1 → zettelforge-2.5.2}/config.default.yaml +1 -1
  4. {zettelforge-2.5.1 → zettelforge-2.5.2}/pyproject.toml +1 -1
  5. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/__init__.py +1 -1
  6. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/config.py +1 -1
  7. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/entity_indexer.py +5 -2
  8. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/fact_extractor.py +3 -1
  9. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/llm_providers/ollama_provider.py +1 -1
  10. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/memory_evolver.py +2 -2
  11. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/note_constructor.py +9 -1
  12. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/synthesis_generator.py +5 -1
  13. {zettelforge-2.5.1 → zettelforge-2.5.2}/.github/CODEOWNERS +0 -0
  14. {zettelforge-2.5.1 → zettelforge-2.5.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  15. {zettelforge-2.5.1 → zettelforge-2.5.2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  16. {zettelforge-2.5.1 → zettelforge-2.5.2}/.github/SECURITY.md +0 -0
  17. {zettelforge-2.5.1 → zettelforge-2.5.2}/.github/dependabot.yml +0 -0
  18. {zettelforge-2.5.1 → zettelforge-2.5.2}/.github/pull_request_template.md +0 -0
  19. {zettelforge-2.5.1 → zettelforge-2.5.2}/.github/workflows/ci.yml +0 -0
  20. {zettelforge-2.5.1 → zettelforge-2.5.2}/.github/workflows/docs.yml +0 -0
  21. {zettelforge-2.5.1 → zettelforge-2.5.2}/.github/workflows/publish.yml +0 -0
  22. {zettelforge-2.5.1 → zettelforge-2.5.2}/.github/workflows/snyk-security.yml +0 -0
  23. {zettelforge-2.5.1 → zettelforge-2.5.2}/.gitignore +0 -0
  24. {zettelforge-2.5.1 → zettelforge-2.5.2}/ARCHITECTURE.md +0 -0
  25. {zettelforge-2.5.1 → zettelforge-2.5.2}/CODEOWNERS +0 -0
  26. {zettelforge-2.5.1 → zettelforge-2.5.2}/CODE_OF_CONDUCT.md +0 -0
  27. {zettelforge-2.5.1 → zettelforge-2.5.2}/CONTRIBUTING.md +0 -0
  28. {zettelforge-2.5.1 → zettelforge-2.5.2}/Dockerfile +0 -0
  29. {zettelforge-2.5.1 → zettelforge-2.5.2}/GOVERNANCE.md +0 -0
  30. {zettelforge-2.5.1 → zettelforge-2.5.2}/LICENSE +0 -0
  31. {zettelforge-2.5.1 → zettelforge-2.5.2}/MANIFEST.in +0 -0
  32. {zettelforge-2.5.1 → zettelforge-2.5.2}/README.md +0 -0
  33. {zettelforge-2.5.1 → zettelforge-2.5.2}/SECURITY.md +0 -0
  34. {zettelforge-2.5.1 → zettelforge-2.5.2}/benchmarks/BENCHMARK_REPORT.md +0 -0
  35. {zettelforge-2.5.1 → zettelforge-2.5.2}/benchmarks/LOCOMO_BENCHMARK_COMPARISON.md +0 -0
  36. {zettelforge-2.5.1 → zettelforge-2.5.2}/benchmarks/auto_ralph.py +0 -0
  37. {zettelforge-2.5.1 → zettelforge-2.5.2}/benchmarks/benchmark_harness.py +0 -0
  38. {zettelforge-2.5.1 → zettelforge-2.5.2}/benchmarks/cti_benchmark_v2.py +0 -0
  39. {zettelforge-2.5.1 → zettelforge-2.5.2}/benchmarks/cti_retrieval_benchmark.py +0 -0
  40. {zettelforge-2.5.1 → zettelforge-2.5.2}/benchmarks/cti_retrieval_results.json +0 -0
  41. {zettelforge-2.5.1 → zettelforge-2.5.2}/benchmarks/cti_v2_results.json +0 -0
  42. {zettelforge-2.5.1 → zettelforge-2.5.2}/benchmarks/ctibench_benchmark.py +0 -0
  43. {zettelforge-2.5.1 → zettelforge-2.5.2}/benchmarks/ctibench_results.json +0 -0
  44. {zettelforge-2.5.1 → zettelforge-2.5.2}/benchmarks/dataset.json +0 -0
  45. {zettelforge-2.5.1 → zettelforge-2.5.2}/benchmarks/enterprise-attack.json +0 -0
  46. {zettelforge-2.5.1 → zettelforge-2.5.2}/benchmarks/evolve_benchmark.py +0 -0
  47. {zettelforge-2.5.1 → zettelforge-2.5.2}/benchmarks/evolve_results.json +0 -0
  48. {zettelforge-2.5.1 → zettelforge-2.5.2}/benchmarks/graph_test.py +0 -0
  49. {zettelforge-2.5.1 → zettelforge-2.5.2}/benchmarks/locomo_benchmark.py +0 -0
  50. {zettelforge-2.5.1 → zettelforge-2.5.2}/benchmarks/locomo_results.json +0 -0
  51. {zettelforge-2.5.1 → zettelforge-2.5.2}/benchmarks/locomo_results_v1.3.0_baseline.json +0 -0
  52. {zettelforge-2.5.1 → zettelforge-2.5.2}/benchmarks/memoryagentbench.py +0 -0
  53. {zettelforge-2.5.1 → zettelforge-2.5.2}/benchmarks/memoryagentbench_results.json +0 -0
  54. {zettelforge-2.5.1 → zettelforge-2.5.2}/benchmarks/mempalace_benchmark.py +0 -0
  55. {zettelforge-2.5.1 → zettelforge-2.5.2}/benchmarks/mempalace_results.json +0 -0
  56. {zettelforge-2.5.1 → zettelforge-2.5.2}/benchmarks/naive_memory.py +0 -0
  57. {zettelforge-2.5.1 → zettelforge-2.5.2}/benchmarks/opencti_benchmark.py +0 -0
  58. {zettelforge-2.5.1 → zettelforge-2.5.2}/benchmarks/ragas_benchmark.py +0 -0
  59. {zettelforge-2.5.1 → zettelforge-2.5.2}/benchmarks/ragas_cti_results.json +0 -0
  60. {zettelforge-2.5.1 → zettelforge-2.5.2}/benchmarks/ragas_results.json +0 -0
  61. {zettelforge-2.5.1 → zettelforge-2.5.2}/benchmarks/results/benchmark_report.md +0 -0
  62. {zettelforge-2.5.1 → zettelforge-2.5.2}/benchmarks/results/ralph_optimization_log.json +0 -0
  63. {zettelforge-2.5.1 → zettelforge-2.5.2}/benchmarks/scale_benchmark.py +0 -0
  64. {zettelforge-2.5.1 → zettelforge-2.5.2}/benchmarks/scale_results.json +0 -0
  65. {zettelforge-2.5.1 → zettelforge-2.5.2}/config.example.yaml +0 -0
  66. {zettelforge-2.5.1 → zettelforge-2.5.2}/docker/docker-compose.yml +0 -0
  67. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/.well-known/security.txt +0 -0
  68. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/CNAME +0 -0
  69. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/THREAT_MODEL.md +0 -0
  70. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/architecture-diagram.mmd +0 -0
  71. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/archive/PACKAGE_SUMMARY.md +0 -0
  72. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/archive/README.md +0 -0
  73. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/archive/SKILL.md +0 -0
  74. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/assets/ZettelForge_Architecture.mmd +0 -0
  75. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/assets/architecture-overview.mmd +0 -0
  76. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/assets/architecture-read-path.mmd +0 -0
  77. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/assets/architecture-write-path.mmd +0 -0
  78. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/assets/cf-analytics.js +0 -0
  79. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/assets/demo.gif +0 -0
  80. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/assets/favicon-16.png +0 -0
  81. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/assets/favicon-32.png +0 -0
  82. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/assets/favicon-512.png +0 -0
  83. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/assets/favicon-64.png +0 -0
  84. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/assets/favicon-apple-touch.png +0 -0
  85. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/assets/favicon-old.svg +0 -0
  86. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/assets/favicon.svg +0 -0
  87. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/assets/logo.svg +0 -0
  88. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/assets/social-preview.png +0 -0
  89. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/assets/threatrecall-lockup-monogram.svg +0 -0
  90. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/assets/threatrecall-lockup.svg +0 -0
  91. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/assets/threatrecall-logo-flat.svg +0 -0
  92. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/assets/threatrecall-logo-philosophy.md +0 -0
  93. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/assets/threatrecall-logo.png +0 -0
  94. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/assets/threatrecall-mark.png +0 -0
  95. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/assets/zettelforge_architecture-light.svg +0 -0
  96. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/assets/zettelforge_architecture.svg +0 -0
  97. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/brand/brandIdentity.md +0 -0
  98. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/brand/colors_and_type.css +0 -0
  99. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/explanation/architecture.md +0 -0
  100. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/explanation/epistemic-tiers.md +0 -0
  101. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/explanation/stix-in-zettelforge.md +0 -0
  102. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/explanation/two-phase-pipeline.md +0 -0
  103. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/explanation/zettelkasten-philosophy.md +0 -0
  104. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/how-to/configure-lancedb.md +0 -0
  105. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/how-to/configure-opencti.md +0 -0
  106. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/how-to/configure-pii.md +0 -0
  107. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/how-to/configure-typedb.md +0 -0
  108. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/how-to/ingest-news-report.md +0 -0
  109. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/how-to/integrate-llm-agent.md +0 -0
  110. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/how-to/migrate-jsonl-to-sqlite.md +0 -0
  111. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/how-to/query-apt-tools.md +0 -0
  112. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/how-to/reproduce-benchmarks.md +0 -0
  113. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/how-to/resolve-aliases.md +0 -0
  114. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/how-to/run-temporal-query.md +0 -0
  115. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/how-to/store-threat-actor.md +0 -0
  116. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/how-to/troubleshoot.md +0 -0
  117. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/how-to/upgrade.md +0 -0
  118. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/human-evaluation-rubric.md +0 -0
  119. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/index.md +0 -0
  120. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/llms.txt +0 -0
  121. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/narrative/2026-04-16-the-memory-problem.md +0 -0
  122. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/overrides/main.html +0 -0
  123. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/reference/architecture-deep-dive.md +0 -0
  124. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/reference/configuration.md +0 -0
  125. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/reference/governance-controls.md +0 -0
  126. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/reference/memory-manager-api.md +0 -0
  127. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/reference/module-inventory.md +0 -0
  128. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/reference/retrieval-policies.md +0 -0
  129. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/reference/stix-schema.md +0 -0
  130. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/rfcs/RFC-001-conversational-entity-extractor.md +0 -0
  131. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/rfcs/RFC-002-universal-llm-provider.md +0 -0
  132. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/rfcs/RFC-003-adversarial-review.md +0 -0
  133. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/rfcs/RFC-003-read-path-depth-routing.md +0 -0
  134. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/rfcs/RFC-007-operational-telemetry.md +0 -0
  135. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/rfcs/RFC-009-enrichment-pipeline-v2.md +0 -0
  136. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/rfcs/RFC-010-enrichment-hotfix.md +0 -0
  137. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/rfcs/RFC-011-local-llm-backend-config.md +0 -0
  138. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/rfcs/RFC-012-litellm-unified-provider.md +0 -0
  139. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/rfcs/RFC-013-presidio-pii-detection.md +0 -0
  140. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/stylesheets/brand-tokens.css +0 -0
  141. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/stylesheets/extra.css +0 -0
  142. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/stylesheets/fonts/Neuropol.otf +0 -0
  143. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/superpowers/research/2026-04-09-ctibench-ragas-benchmarks.md +0 -0
  144. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/superpowers/research/2026-04-09-fastembed-local-embeddings.md +0 -0
  145. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/superpowers/research/2026-04-09-hybrid-typedb-lancedb-architecture.md +0 -0
  146. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/superpowers/research/2026-04-09-local-llm-llama-cpp.md +0 -0
  147. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/superpowers/research/2026-04-15-anti-aversion-cleanup.md +0 -0
  148. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/superpowers/research/2026-04-15-causal-graph.md +0 -0
  149. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/superpowers/research/2026-04-15-ctibench-ate-fix.md +0 -0
  150. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/superpowers/research/2026-04-15-format-stability.md +0 -0
  151. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/superpowers/research/2026-04-15-memory-evolution.md +0 -0
  152. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/superpowers/research/2026-04-15-merge-consolidation.md +0 -0
  153. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/superpowers/research/2026-04-15-persistence-semantics.md +0 -0
  154. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/superpowers/research/2026-04-15-sqlite-migration.md +0 -0
  155. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/superpowers/research/2026-04-17-test-suite-audit.md +0 -0
  156. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/superpowers/research/2026-04-24-phase-0.5-attribution-prelim.md +0 -0
  157. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/superpowers/research/2026-04-25-graph-retriever-silence.md +0 -0
  158. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/superpowers/research/2026-04-25-phase-0.5-attribution.md +0 -0
  159. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/superpowers/research/README.md +0 -0
  160. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/superpowers/specs/2026-04-15-p1-features-prd.md +0 -0
  161. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/tutorials/01-quickstart.md +0 -0
  162. {zettelforge-2.5.1 → zettelforge-2.5.2}/docs/tutorials/02-first-cti-report.md +0 -0
  163. {zettelforge-2.5.1 → zettelforge-2.5.2}/examples/athf_bridge.py +0 -0
  164. {zettelforge-2.5.1 → zettelforge-2.5.2}/examples/mcp_claude_code.md +0 -0
  165. {zettelforge-2.5.1 → zettelforge-2.5.2}/examples/quickstart.py +0 -0
  166. {zettelforge-2.5.1 → zettelforge-2.5.2}/governance/controls.yaml +0 -0
  167. {zettelforge-2.5.1 → zettelforge-2.5.2}/mkdocs.yml +0 -0
  168. {zettelforge-2.5.1 → zettelforge-2.5.2}/scripts/migrate_jsonl_to_sqlite.py +0 -0
  169. {zettelforge-2.5.1 → zettelforge-2.5.2}/scripts/rebuild_index.py +0 -0
  170. {zettelforge-2.5.1 → zettelforge-2.5.2}/scripts/record-demo.sh +0 -0
  171. {zettelforge-2.5.1 → zettelforge-2.5.2}/scripts/typedb-setup.sh +0 -0
  172. {zettelforge-2.5.1 → zettelforge-2.5.2}/scripts/zettelforge-rebuild.service +0 -0
  173. {zettelforge-2.5.1 → zettelforge-2.5.2}/scripts/zettelforge-rebuild.timer +0 -0
  174. {zettelforge-2.5.1 → zettelforge-2.5.2}/server.json +0 -0
  175. {zettelforge-2.5.1 → zettelforge-2.5.2}/skills/claude-code-skill.md +0 -0
  176. {zettelforge-2.5.1 → zettelforge-2.5.2}/skills/openclaw-skill.md +0 -0
  177. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/__main__.py +0 -0
  178. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/alias_resolver.py +0 -0
  179. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/backend_factory.py +0 -0
  180. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/blended_retriever.py +0 -0
  181. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/cache.py +0 -0
  182. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/consolidation.py +0 -0
  183. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/demo.py +0 -0
  184. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/detection/__init__.py +0 -0
  185. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/detection/base.py +0 -0
  186. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/detection/consumers.py +0 -0
  187. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/detection/explainer.py +0 -0
  188. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/edition.py +0 -0
  189. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/extensions.py +0 -0
  190. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/governance_validator.py +0 -0
  191. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/graph_retriever.py +0 -0
  192. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/integrations/__init__.py +0 -0
  193. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/integrations/langchain_retriever.py +0 -0
  194. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/intent_classifier.py +0 -0
  195. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/json_parse.py +0 -0
  196. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/knowledge_graph.py +0 -0
  197. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/lance_maintenance.py +0 -0
  198. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/llm_client.py +0 -0
  199. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/llm_providers/__init__.py +0 -0
  200. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/llm_providers/base.py +0 -0
  201. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/llm_providers/litellm_provider.py +0 -0
  202. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/llm_providers/local_provider.py +0 -0
  203. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/llm_providers/mock_provider.py +0 -0
  204. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/llm_providers/registry.py +0 -0
  205. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/log.py +0 -0
  206. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/mcp/__init__.py +0 -0
  207. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/mcp/__main__.py +0 -0
  208. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/mcp/server.py +0 -0
  209. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/memory_manager.py +0 -0
  210. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/memory_store.py +0 -0
  211. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/memory_updater.py +0 -0
  212. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/note_schema.py +0 -0
  213. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/observability.py +0 -0
  214. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/ocsf.py +0 -0
  215. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/ontology.py +0 -0
  216. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/pii_validator.py +0 -0
  217. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/retry.py +0 -0
  218. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/scripts/compact_lance.py +0 -0
  219. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/scripts/human_eval_sampler.py +0 -0
  220. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/scripts/telemetry_aggregator.py +0 -0
  221. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/scripts/telemetry_dashboard.py +0 -0
  222. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/sigma/__init__.py +0 -0
  223. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/sigma/cli.py +0 -0
  224. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/sigma/entities.py +0 -0
  225. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/sigma/ingest.py +0 -0
  226. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/sigma/parser.py +0 -0
  227. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/sigma/schemas/NOTICE.md +0 -0
  228. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/sigma/schemas/__init__.py +0 -0
  229. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/sigma/schemas/sigma-correlation-rules-schema.json +0 -0
  230. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/sigma/schemas/sigma-detection-rule-schema.json +0 -0
  231. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/sigma/schemas/sigma-filters-schema.json +0 -0
  232. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/sigma/tags.py +0 -0
  233. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/sqlite_backend.py +0 -0
  234. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/storage_backend.py +0 -0
  235. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/synthesis_validator.py +0 -0
  236. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/telemetry.py +0 -0
  237. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/vector_memory.py +0 -0
  238. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/vector_retriever.py +0 -0
  239. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/yara/__init__.py +0 -0
  240. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/yara/cccs_metadata.py +0 -0
  241. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/yara/cli.py +0 -0
  242. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/yara/entities.py +0 -0
  243. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/yara/ingest.py +0 -0
  244. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/yara/parser.py +0 -0
  245. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/yara/schemas/CCCS_YARA.yml +0 -0
  246. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/yara/schemas/CCCS_YARA_values.yml +0 -0
  247. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/yara/schemas/NOTICE.md +0 -0
  248. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/yara/schemas/__init__.py +0 -0
  249. {zettelforge-2.5.1 → zettelforge-2.5.2}/src/zettelforge/yara/tags.py +0 -0
  250. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/__init__.py +0 -0
  251. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/benchmark_scale.py +0 -0
  252. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/conftest.py +0 -0
  253. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/fixtures/sigma/cloud_example.yml +0 -0
  254. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/fixtures/sigma/correlation_example.yml +0 -0
  255. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/fixtures/sigma/process_creation_example.yml +0 -0
  256. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/fixtures/sigma/tagged_example.yml +0 -0
  257. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/fixtures/yara/malware_hash.yar +0 -0
  258. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/fixtures/yara/technique_loader.yar +0 -0
  259. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/fixtures/yara/webshell.yar +0 -0
  260. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_basic.py +0 -0
  261. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_blended_retriever.py +0 -0
  262. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_causal_extraction.py +0 -0
  263. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_config.py +0 -0
  264. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_consolidation.py +0 -0
  265. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_conversational_entities.py +0 -0
  266. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_core.py +0 -0
  267. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_cti_integration.py +0 -0
  268. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_detection_explainer.py +0 -0
  269. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_detection_rule_entities.py +0 -0
  270. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_edition.py +0 -0
  271. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_embedding.py +0 -0
  272. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_entity_indexer_races.py +0 -0
  273. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_extensions.py +0 -0
  274. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_fact_extractor.py +0 -0
  275. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_governance.py +0 -0
  276. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_governance_spec_drift.py +0 -0
  277. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_graph_retriever.py +0 -0
  278. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_human_eval_sampler.py +0 -0
  279. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_intent_classifier.py +0 -0
  280. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_json_parse.py +0 -0
  281. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_kg_edge_schema.py +0 -0
  282. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_lance_maintenance.py +0 -0
  283. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_langchain_retriever.py +0 -0
  284. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_llm_client.py +0 -0
  285. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_llm_providers.py +0 -0
  286. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_logging_compliance.py +0 -0
  287. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_mcp_server.py +0 -0
  288. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_memory_evolver.py +0 -0
  289. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_memory_updater.py +0 -0
  290. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_performance.py +0 -0
  291. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_pii_validator.py +0 -0
  292. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_recall_integration.py +0 -0
  293. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_sigma_entities.py +0 -0
  294. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_sigma_ingest.py +0 -0
  295. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_sigma_parser.py +0 -0
  296. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_sqlite_backend.py +0 -0
  297. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_sqlite_integration.py +0 -0
  298. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_storage_backend.py +0 -0
  299. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_telemetry_aggregator.py +0 -0
  300. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_telemetry_collector.py +0 -0
  301. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_telemetry_dashboard.py +0 -0
  302. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_telemetry_integration.py +0 -0
  303. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_temporal_graph.py +0 -0
  304. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_two_phase_e2e.py +0 -0
  305. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_typedb_client.py +0 -0
  306. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_yara_entities.py +0 -0
  307. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_yara_ingest.py +0 -0
  308. {zettelforge-2.5.1 → zettelforge-2.5.2}/tests/test_yara_parser.py +0 -0
  309. {zettelforge-2.5.1 → zettelforge-2.5.2}/web/app.py +0 -0
  310. {zettelforge-2.5.1 → zettelforge-2.5.2}/web/auth.py +0 -0
  311. {zettelforge-2.5.1 → zettelforge-2.5.2}/web/mcp_server.py +0 -0
@@ -6,6 +6,83 @@ Versioning follows [Semantic Versioning](https://semver.org/).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [2.5.2] - 2026-04-25
10
+
11
+ Hotfix release. Restores end-to-end functionality of synthesis, causal
12
+ triple extraction, fact extraction, LLM NER, and neighbor evolution
13
+ under any reasoning-style LLM (qwen3.5+, qwen3.6, nemotron-3, etc.).
14
+
15
+ ### Fixed
16
+
17
+ - **Reasoning-model token starvation across every LLM call site**.
18
+ Reasoning models emit hidden `<think>...</think>` tokens that count
19
+ against `num_predict` but never appear in the final `response` field
20
+ Ollama returns. Pre-2.5.2 token caps (`max_tokens=300`/`400`/`800`/
21
+ `1024`) were exhausted entirely by the thinking phase on these
22
+ models, leaving the JSON answer empty. Symptoms: synthesis fell back
23
+ to `"No specific answer found for: …"` on every query; causal triple
24
+ extraction persisted **0 edges** despite rich CTI text; LLM NER
25
+ silently no-opped; neighbor evolution `parse_failed{schema=...,
26
+ raw=""}` warnings flooded the log.
27
+
28
+ Bumped every `generate(..., max_tokens=...)` call site to give
29
+ reasoning models room to think *and* emit a final answer. Affected
30
+ files:
31
+
32
+ | File | Old cap | New cap |
33
+ |---|---|---|
34
+ | `note_constructor.py` (causal triples) | 300 | **8000** |
35
+ | `synthesis_generator.py` | 800 | 2500 |
36
+ | `fact_extractor.py` | 400 | 2500 |
37
+ | `entity_indexer.py` (NER) | 300 | 2500 |
38
+ | `memory_evolver.py` (2 sites) | 1024 | 2500 |
39
+
40
+ Causal extraction needs the largest budget because the prompt asks
41
+ the model to enumerate *every* causal relation in a passage; this
42
+ triggers the longest reasoning chains anywhere in the system.
43
+ Empirical against `qwen3.5:9b`: at 4000 tokens the call was
44
+ *stochastically* sufficient (eval_count varied 2.8k–4k+, ~70%
45
+ success), so 8000 is the conservative cap that keeps the success
46
+ rate above 95% on the same model. Other call sites converge with
47
+ less reasoning overhead so 2500 suffices.
48
+
49
+ - **LLM client timeout bumped 60s → 180s**. `LLMConfig.timeout` and
50
+ `OllamaProvider` constructor default were both 60 seconds — well
51
+ below the 60–120s wall-clock time of a 4000–8000 token reasoning
52
+ generation on a 9B-Q4_K_M model. `ReadTimeout` was firing during
53
+ causal extraction even when the model would have returned valid
54
+ JSON given another 30 seconds. Bumped both defaults plus
55
+ `config.default.yaml` to 180s.
56
+
57
+ Verified end-to-end on `qwen3.5:9b`:
58
+ - Synthesis: query "What CVE does DROPBEAR exploit?" returns
59
+ `"CVE-2024-3094"` with 1 source citation (was returning
60
+ `"No specific answer found for: …"` on every call pre-2.5.2).
61
+ - Causal extraction: corpus seeded with APT28/DROPBEAR/CVE-2024-3094
62
+ text yields a 4-triple JSON array in 137s wall time:
63
+ `APT28 → targets → manufacturing sector`,
64
+ `APT28 → uses → DROPBEAR`,
65
+ `DROPBEAR → exploits → CVE-2024-3094`,
66
+ `APT28 → attributed_to → Russian GRU Unit 26165`.
67
+
68
+ ### Operational note
69
+
70
+ Slow models. With 8000 tokens of reasoning budget, single causal
71
+ extraction calls now take 60–140s on a 9B model. `remember(sync=True)`
72
+ in this configuration will block 1–3 minutes per note. The default
73
+ async path (background enrichment queue) is the preferred mode.
74
+ Operators on faster hardware or smaller models can lower the caps via
75
+ config/env if needed, but the v2.5.2 defaults trade latency for
76
+ end-to-end correctness on the reference model.
77
+
78
+ ### Notes
79
+
80
+ This explains the `evolution_parse_failed` and `causal_triples
81
+ parse_failed` cascades documented in the v2.4.x Vigil incident. The
82
+ v2.4.2 PR #95 Tier 1/2 LLM observability surfaced the empty responses
83
+ but the root-cause attribution to token-cap-vs-thinking-budget waited
84
+ until the v2.5.1 perf-bench run made the failure reproducible end-to-end.
85
+
9
86
  ## [2.5.1] - 2026-04-25
10
87
 
11
88
  Hotfix release. Surfaced during the v2.5.0 perf benchmark run.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: zettelforge
3
- Version: 2.5.1
3
+ Version: 2.5.2
4
4
  Summary: ZettelForge: Agentic Memory System with vector search, knowledge graph, and synthesis
5
5
  Project-URL: Homepage, https://github.com/rolandpg/zettelforge
6
6
  Project-URL: Documentation, https://docs.threatrecall.ai
@@ -214,7 +214,7 @@ llm:
214
214
  url: http://localhost:11434
215
215
  api_key: ""
216
216
  temperature: 0.1
217
- timeout: 60.0
217
+ timeout: 180.0 # v2.5.2: bumped from 60s for reasoning-model headroom
218
218
  max_retries: 2
219
219
  fallback: ""
220
220
  local_backend: llama-cpp-python # used when provider=local (RFC-011)
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "zettelforge"
7
- version = "2.5.1"
7
+ version = "2.5.2"
8
8
  description = "ZettelForge: Agentic Memory System with vector search, knowledge graph, and synthesis"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -57,7 +57,7 @@ from zettelforge.vector_retriever import VectorRetriever
57
57
  # importable for advanced use but are not part of the advertised public API
58
58
  # and are therefore excluded from __all__ below.
59
59
 
60
- __version__ = "2.5.1"
60
+ __version__ = "2.5.2"
61
61
  __all__ = [
62
62
  # Ontology reference tables (TypedEntityStore / OntologyValidator are
63
63
  # importable from zettelforge.ontology but are not part of the public API
@@ -103,7 +103,7 @@ class LLMConfig:
103
103
  url: str = "http://localhost:11434"
104
104
  api_key: str = "" # supports ${ENV_VAR} references — never commit raw keys
105
105
  temperature: float = 0.1
106
- timeout: float = 60.0
106
+ timeout: float = 180.0 # v2.5.2: bumped from 60s — reasoning models at higher num_predict (4000 for causal triples) routinely exceed 60s on a 9B at Q4_K_M
107
107
  max_retries: int = 2
108
108
  fallback: str = "" # empty preserves implicit local→ollama fallback
109
109
  local_backend: str = "llama-cpp-python" # RFC-011: "llama-cpp-python" or "onnxruntime-genai"
@@ -271,9 +271,12 @@ class EntityExtractor:
271
271
  from zettelforge.llm_client import generate
272
272
 
273
273
  prompt = f"Extract named entities from this text:\n\n{text[:2000]}\n\nJSON:"
274
+ # 2500-token budget for reasoning-model headroom (v2.5.2; pre-fix
275
+ # 300 was exhausted by qwen3.5+ <think> tokens, leaving the NER
276
+ # JSON empty and entity extraction silently no-opping).
274
277
  output = generate(
275
278
  prompt,
276
- max_tokens=300,
279
+ max_tokens=2500,
277
280
  temperature=0.0,
278
281
  system=self.NER_SYSTEM_PROMPT,
279
282
  )
@@ -282,7 +285,7 @@ class EntityExtractor:
282
285
  if parsed is None and output and output.strip():
283
286
  _logger.info("retry_parse", site="entity_indexer_ner", attempt=2)
284
287
  retry_prompt = prompt + "\n\nRespond with valid JSON only."
285
- output = generate(retry_prompt, max_tokens=300, temperature=0.3, json_mode=True)
288
+ output = generate(retry_prompt, max_tokens=2500, temperature=0.3, json_mode=True)
286
289
  parsed = extract_json(output, expect="object")
287
290
  return self._parse_ner_output_from_parsed(parsed, output, conversational_types)
288
291
 
@@ -42,7 +42,9 @@ class FactExtractor:
42
42
  try:
43
43
  from zettelforge.llm_client import generate
44
44
 
45
- raw_output = generate(prompt, max_tokens=400, temperature=0.1)
45
+ # 2500-token budget for reasoning-model headroom (see v2.5.2
46
+ # CHANGELOG; pre-fix 400 was exhausted by qwen3.5+ <think> tokens).
47
+ raw_output = generate(prompt, max_tokens=2500, temperature=0.1)
46
48
  return self._parse_extraction_response(raw_output)
47
49
  except Exception:
48
50
  _logger.warning("llm_fact_extraction_failed", exc_info=True)
@@ -39,7 +39,7 @@ class OllamaProvider:
39
39
  self,
40
40
  model: str = "",
41
41
  url: str = "",
42
- timeout: float = 60.0,
42
+ timeout: float = 180.0, # see config.LLMConfig.timeout for rationale
43
43
  **_: Any,
44
44
  ) -> None:
45
45
  self._model = model or _DEFAULT_MODEL
@@ -93,7 +93,7 @@ class MemoryEvolver:
93
93
  )
94
94
 
95
95
  # First attempt
96
- output = generate(prompt, max_tokens=1024, temperature=0.2, json_mode=True)
96
+ output = generate(prompt, max_tokens=2500, temperature=0.2, json_mode=True)
97
97
  result = extract_json(output, expect="object")
98
98
 
99
99
  # Single retry on parse failure (AD-2). Capture what the model
@@ -108,7 +108,7 @@ class MemoryEvolver:
108
108
  raw_chars=len(output or ""),
109
109
  prompt_preview=prompt[:240],
110
110
  )
111
- output = generate(prompt, max_tokens=1024, temperature=0.1, json_mode=True)
111
+ output = generate(prompt, max_tokens=2500, temperature=0.1, json_mode=True)
112
112
  result = extract_json(output, expect="object")
113
113
 
114
114
  if result is None:
@@ -122,7 +122,15 @@ JSON:"""
122
122
  try:
123
123
  from zettelforge.llm_client import generate
124
124
 
125
- output = generate(prompt, max_tokens=300, temperature=0.1)
125
+ # 8000 tokens for causal extraction — the highest cap in the
126
+ # codebase. This prompt asks the model to enumerate every causal
127
+ # relation in a passage, which triggers the longest reasoning
128
+ # chains anywhere in the system. Empirical: qwen3.5:9b at
129
+ # num_predict=4000 was *stochastically* sufficient (~70% success
130
+ # rate), eval_count varied between 2.8k (success) and 4k+ (still
131
+ # in <think> tags when budget exhausted). 8000 keeps the
132
+ # success rate >95% on the same model. v2.5.2 CHANGELOG.
133
+ output = generate(prompt, max_tokens=8000, temperature=0.1)
126
134
 
127
135
  parsed = extract_json(output, expect="array")
128
136
  if parsed is None:
@@ -143,7 +143,11 @@ class SynthesisGenerator:
143
143
  try:
144
144
  from zettelforge.llm_client import generate
145
145
 
146
- raw = generate(full_prompt, max_tokens=800, temperature=0.1, system=system_prompt)
146
+ # 2500-token budget for reasoning-model headroom. Pre-2.5.2 the
147
+ # 800-token cap was exhausted by qwen3.5+/qwen3.6/nemotron-3
148
+ # <think> tokens before any JSON answer was emitted, dropping
149
+ # synthesis to its empty-result fallback on every call.
150
+ raw = generate(full_prompt, max_tokens=2500, temperature=0.1, system=system_prompt)
147
151
  result = extract_json(raw, expect="object")
148
152
  if result is None:
149
153
  _logger.warning("parse_failed", schema="synthesis", raw=(raw or "")[:200])
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