@hassangameryt/freeflow 0.4.0 → 0.6.0

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 (285) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +2 -1
  3. package/.codex-plugin/plugin.json +2 -1
  4. package/README.md +150 -155
  5. package/capabilities/cognitive-routing/SKILL.md +229 -0
  6. package/capabilities/context-virtualization/SKILL.md +103 -0
  7. package/capabilities/conversation-history/SKILL.md +53 -0
  8. package/command-surface.json +17 -13
  9. package/hooks/freeflow-runtime-context.mjs +393 -159
  10. package/hooks/hooks.json +26 -1
  11. package/hooks/tests/check-runtime-context-hook.sh +223 -54
  12. package/package.json +25 -16
  13. package/pi-extension/dist/cognitive-routing/commands.js +96 -0
  14. package/pi-extension/dist/cognitive-routing/config.js +236 -0
  15. package/pi-extension/dist/cognitive-routing/controller.js +862 -0
  16. package/pi-extension/dist/cognitive-routing/history.js +439 -0
  17. package/pi-extension/dist/cognitive-routing/host.js +126 -0
  18. package/pi-extension/dist/cognitive-routing/runtime.js +43 -0
  19. package/pi-extension/dist/cognitive-routing/tool.js +211 -0
  20. package/pi-extension/dist/cognitive-routing/types.js +6 -0
  21. package/pi-extension/dist/context-virtualization/commands.js +89 -0
  22. package/pi-extension/dist/context-virtualization/projector.js +42 -0
  23. package/pi-extension/dist/context-virtualization/runtime.js +356 -0
  24. package/pi-extension/dist/context-virtualization/state.js +57 -0
  25. package/pi-extension/dist/context-virtualization/types.js +10 -0
  26. package/pi-extension/dist/conversation-history/passages.js +66 -0
  27. package/pi-extension/dist/conversation-history/ranking.js +105 -0
  28. package/pi-extension/dist/conversation-history/runtime.js +226 -0
  29. package/pi-extension/dist/conversation-history/search.js +56 -0
  30. package/pi-extension/dist/conversation-history/types.js +1 -0
  31. package/pi-extension/dist/freeflow-context/resolver.js +120 -0
  32. package/pi-extension/dist/freeflow-context/runtime.js +80 -0
  33. package/pi-extension/dist/freeflow-context/source-projector.js +95 -0
  34. package/pi-extension/dist/freeflow-context/tool.js +308 -0
  35. package/pi-extension/dist/freeflow-context/types.js +12 -0
  36. package/pi-extension/dist/freeflow-context/visibility.js +28 -0
  37. package/pi-extension/dist/index.js +516 -98
  38. package/pi-extension/dist/runtime/runtime-context.js +318 -271
  39. package/pi-extension/dist/runtime/runtime-identity.js +5 -0
  40. package/pi-extension/dist/settings/settings-tui.js +78 -0
  41. package/pi-extension/dist/settings/settings-ui.js +593 -563
  42. package/pi-extension/dist/ui/text-component.js +57 -0
  43. package/pi-extension/src/cognitive-routing/commands.ts +119 -0
  44. package/pi-extension/src/cognitive-routing/config.ts +307 -0
  45. package/pi-extension/src/cognitive-routing/controller.ts +1118 -0
  46. package/pi-extension/src/cognitive-routing/history.ts +638 -0
  47. package/pi-extension/src/cognitive-routing/host.ts +172 -0
  48. package/pi-extension/src/cognitive-routing/runtime.ts +57 -0
  49. package/pi-extension/src/cognitive-routing/tool.ts +272 -0
  50. package/pi-extension/src/cognitive-routing/types.ts +89 -0
  51. package/pi-extension/src/context-virtualization/commands.ts +111 -0
  52. package/pi-extension/src/context-virtualization/projector.ts +62 -0
  53. package/pi-extension/src/context-virtualization/runtime.ts +406 -0
  54. package/pi-extension/src/context-virtualization/state.ts +79 -0
  55. package/pi-extension/src/context-virtualization/types.ts +92 -0
  56. package/pi-extension/src/conversation-history/passages.ts +81 -0
  57. package/pi-extension/src/conversation-history/ranking.ts +155 -0
  58. package/pi-extension/src/conversation-history/runtime.ts +250 -0
  59. package/pi-extension/src/conversation-history/search.ts +79 -0
  60. package/pi-extension/src/conversation-history/types.ts +31 -0
  61. package/pi-extension/src/freeflow-context/resolver.ts +139 -0
  62. package/pi-extension/src/freeflow-context/runtime.ts +100 -0
  63. package/pi-extension/src/freeflow-context/source-projector.ts +106 -0
  64. package/pi-extension/src/freeflow-context/tool.ts +360 -0
  65. package/pi-extension/src/freeflow-context/types.ts +70 -0
  66. package/pi-extension/src/freeflow-context/visibility.ts +53 -0
  67. package/pi-extension/src/index.ts +553 -101
  68. package/pi-extension/src/runtime/runtime-context.ts +339 -281
  69. package/pi-extension/src/runtime/runtime-identity.ts +8 -0
  70. package/pi-extension/src/settings/settings-tui.ts +93 -0
  71. package/pi-extension/src/settings/settings-ui.ts +700 -613
  72. package/pi-extension/src/ui/text-component.ts +66 -0
  73. package/pi-extension/tests/cognitive-routing/commands.test.js +134 -0
  74. package/pi-extension/tests/cognitive-routing/controller.test.js +1099 -0
  75. package/pi-extension/tests/cognitive-routing/extension-lifecycle.test.js +1071 -0
  76. package/pi-extension/tests/cognitive-routing/history.test.js +274 -0
  77. package/pi-extension/tests/cognitive-routing/host-fixture.js +4 -0
  78. package/pi-extension/tests/cognitive-routing/host-identity.test.js +63 -0
  79. package/pi-extension/tests/cognitive-routing/profile-resolution.test.js +236 -0
  80. package/pi-extension/tests/cognitive-routing/tool.test.js +230 -0
  81. package/pi-extension/tests/context-virtualization/extension.test.js +749 -0
  82. package/pi-extension/tests/context-virtualization/projector.test.js +110 -0
  83. package/pi-extension/tests/context-virtualization/runtime.test.js +216 -0
  84. package/pi-extension/tests/conversation-history/runtime.test.js +98 -0
  85. package/pi-extension/tests/conversation-history/search.test.js +97 -0
  86. package/pi-extension/tests/integration/pi-extension.test.js +928 -2047
  87. package/pi-extension/tests/integration/prompt-architecture.test.js +305 -0
  88. package/runtime/prompts/cognitive-routing.md +9 -0
  89. package/runtime/prompts/context-virtualization.md +3 -0
  90. package/runtime/prompts/conversation-history.md +3 -0
  91. package/runtime/prompts/core.md +13 -0
  92. package/runtime/prompts/interaction-contract.md +7 -0
  93. package/runtime/prompts/skills.md +65 -0
  94. package/skills/action-selection/SKILL.md +91 -0
  95. package/skills/bypass/SKILL.md +3 -2
  96. package/skills/commit-work/SKILL.md +1 -1
  97. package/skills/commit-work/references/staging-decisions.md +1 -1
  98. package/skills/decision-gate/SKILL.md +1 -1
  99. package/skills/design-for-depth/SKILL.md +14 -33
  100. package/skills/design-for-depth/references/design-pressure-signals.md +1 -1
  101. package/skills/design-for-depth/references/interface-design-loop.md +1 -1
  102. package/skills/design-for-depth/references/software-design-philosophy.md +1 -1
  103. package/skills/diagnose-failure/SKILL.md +20 -14
  104. package/skills/diagnose-failure/references/diagnostic-loop-catalog.md +1 -3
  105. package/skills/diagnose-failure/references/{flaky-and-performance.md → flaky-and-performance-diagnosis.md} +1 -1
  106. package/skills/discuss/SKILL.md +34 -22
  107. package/skills/discuss/references/discussion-continuity.md +71 -0
  108. package/skills/evaluate-skill/SKILL.md +5 -5
  109. package/skills/evaluate-skill/references/{definition-schema.md → evaluation-definition-schema.md} +42 -2
  110. package/skills/evaluate-skill/references/execution-and-evidence.md +8 -3
  111. package/skills/evaluate-skill/scripts/lib/definitions.mjs +114 -3
  112. package/skills/evaluate-skill/scripts/lib/grade-interaction.mjs +156 -1
  113. package/skills/evaluate-skill/scripts/lib/grade.mjs +9 -1
  114. package/skills/evaluate-skill/scripts/lib/pi.mjs +147 -32
  115. package/skills/evaluate-skill/scripts/lib/rpc.mjs +4 -4
  116. package/skills/evaluate-skill/scripts/lib/runner.mjs +36 -14
  117. package/skills/evaluate-skill/scripts/lib/sandbox.mjs +92 -0
  118. package/skills/evaluate-skill/scripts/pi-guard.mjs +1 -1
  119. package/skills/evaluate-skill/scripts/pi-observer.mjs +66 -0
  120. package/skills/evaluate-skill/scripts/skill-eval.mjs +6 -5
  121. package/skills/execute-work/SKILL.md +18 -15
  122. package/skills/execute-work/references/code-practices.md +1 -1
  123. package/skills/execute-work/references/execute-work-edges.md +42 -0
  124. package/skills/finish-branch/SKILL.md +2 -2
  125. package/skills/finish-branch/references/integration-options.md +1 -1
  126. package/skills/handoff/SKILL.md +3 -3
  127. package/skills/launch-work/SKILL.md +1 -1
  128. package/skills/launch-work/references/launch-readiness.md +2 -2
  129. package/skills/migration-work/SKILL.md +2 -2
  130. package/skills/migration-work/references/migration-lifecycle.md +1 -1
  131. package/skills/mode-contract/SKILL.md +32 -10
  132. package/skills/release-work/SKILL.md +1 -1
  133. package/skills/release-work/references/release-evidence.md +1 -1
  134. package/skills/review-artifact/SKILL.md +28 -26
  135. package/skills/review-work/SKILL.md +28 -26
  136. package/skills/review-work/references/{reviewer-prompt.md → independent-work-reviewer-contract.md} +1 -1
  137. package/skills/review-work/references/security-risk-lens.md +1 -1
  138. package/skills/setup-freeflow/SKILL.md +6 -10
  139. package/skills/setup-freeflow/references/activation-contract.md +5 -10
  140. package/skills/setup-freeflow/references/host-setup.md +3 -7
  141. package/skills/simplify-code/SKILL.md +1 -1
  142. package/skills/simplify-code/references/simplification-patterns.md +1 -1
  143. package/skills/tdd/SKILL.md +18 -38
  144. package/skills/tdd/references/test-design.md +2 -2
  145. package/skills/track-work/SKILL.md +362 -58
  146. package/skills/track-work/scripts/lib/codec.mjs +570 -0
  147. package/skills/track-work/scripts/lib/commands.mjs +568 -0
  148. package/skills/track-work/scripts/lib/contract.mjs +303 -0
  149. package/skills/track-work/scripts/lib/model.mjs +506 -0
  150. package/skills/track-work/scripts/lib/operations.mjs +965 -0
  151. package/skills/track-work/scripts/lib/record-store.mjs +264 -0
  152. package/skills/track-work/scripts/lib/result.mjs +37 -0
  153. package/skills/track-work/scripts/lib/rewrites.mjs +740 -0
  154. package/skills/track-work/scripts/lib/schema.mjs +277 -0
  155. package/skills/track-work/scripts/lib/source-inventory.mjs +162 -0
  156. package/skills/track-work/scripts/lib/views.mjs +443 -0
  157. package/skills/track-work/scripts/lib/workspace.mjs +134 -0
  158. package/skills/track-work/scripts/working-record.mjs +122 -0
  159. package/skills/verify-work/SKILL.md +14 -2
  160. package/skills/verify-work/references/browser-runtime-evidence.md +1 -1
  161. package/skills/verify-work/references/integration-evidence.md +1 -1
  162. package/skills/verify-work/references/performance-evidence.md +1 -1
  163. package/skills/workflow/SKILL.md +105 -53
  164. package/skills/workflow/references/domain-skill-composition.md +22 -42
  165. package/skills/write-plan/SKILL.md +1 -1
  166. package/skills/write-skill/SKILL.md +3 -2
  167. package/skills/write-skill/references/progressive-disclosure.md +17 -3
  168. package/pi-extension/dist/output-router/host-producer-identification.js +0 -232
  169. package/pi-extension/dist/output-router/native-safety-net.js +0 -216
  170. package/pi-extension/dist/output-router/observed-tool-routing.js +0 -122
  171. package/pi-extension/dist/output-router/renderers.js +0 -1023
  172. package/pi-extension/dist/output-router/router-tools.js +0 -554
  173. package/pi-extension/dist/output-router/schemas.js +0 -383
  174. package/pi-extension/dist/output-router/status.js +0 -744
  175. package/pi-extension/dist/output-router/utils.js +0 -502
  176. package/pi-extension/src/output-router/host-producer-identification.ts +0 -256
  177. package/pi-extension/src/output-router/native-safety-net.ts +0 -248
  178. package/pi-extension/src/output-router/observed-tool-routing.ts +0 -134
  179. package/pi-extension/src/output-router/renderers.ts +0 -1108
  180. package/pi-extension/src/output-router/router-tools.ts +0 -579
  181. package/pi-extension/src/output-router/schemas.ts +0 -387
  182. package/pi-extension/src/output-router/status.ts +0 -791
  183. package/pi-extension/src/output-router/utils.ts +0 -554
  184. package/pi-extension/tests/output-router/observed-producers.test.js +0 -132
  185. package/pi-extension/tests/output-router/search.test.js +0 -722
  186. package/router/dist/benchmarks/benchmark-harness.d.ts +0 -35
  187. package/router/dist/benchmarks/benchmark-harness.js +0 -92
  188. package/router/dist/benchmarks/benchmarks.d.ts +0 -109
  189. package/router/dist/benchmarks/benchmarks.js +0 -979
  190. package/router/dist/benchmarks/codex-qa-benchmarks.d.ts +0 -95
  191. package/router/dist/benchmarks/codex-qa-benchmarks.js +0 -500
  192. package/router/dist/benchmarks/command-benchmarks.d.ts +0 -143
  193. package/router/dist/benchmarks/command-benchmarks.js +0 -698
  194. package/router/dist/benchmarks/context-mode-normalized-benchmarks.d.ts +0 -82
  195. package/router/dist/benchmarks/context-mode-normalized-benchmarks.js +0 -773
  196. package/router/dist/benchmarks/context-mode-real-deep-benchmark.d.ts +0 -132
  197. package/router/dist/benchmarks/context-mode-real-deep-benchmark.js +0 -1380
  198. package/router/dist/benchmarks/context-saving-baseline.d.ts +0 -60
  199. package/router/dist/benchmarks/context-saving-baseline.js +0 -470
  200. package/router/dist/benchmarks/index-benchmarks.d.ts +0 -103
  201. package/router/dist/benchmarks/index-benchmarks.js +0 -862
  202. package/router/dist/benchmarks/storage-policy-benchmarks.d.ts +0 -101
  203. package/router/dist/benchmarks/storage-policy-benchmarks.js +0 -618
  204. package/router/dist/benchmarks/vault-index-benchmarks.d.ts +0 -56
  205. package/router/dist/benchmarks/vault-index-benchmarks.js +0 -322
  206. package/router/dist/config/config.d.ts +0 -103
  207. package/router/dist/config/config.js +0 -632
  208. package/router/dist/config/router-contract.d.ts +0 -10
  209. package/router/dist/config/router-contract.js +0 -54
  210. package/router/dist/config/schema.d.ts +0 -27
  211. package/router/dist/config/schema.js +0 -648
  212. package/router/dist/config/types.d.ts +0 -573
  213. package/router/dist/config/types.js +0 -41
  214. package/router/dist/evidence/bounded-evidence.d.ts +0 -40
  215. package/router/dist/evidence/bounded-evidence.js +0 -323
  216. package/router/dist/evidence/evidence-range-selector.d.ts +0 -24
  217. package/router/dist/evidence/evidence-range-selector.js +0 -232
  218. package/router/dist/evidence/evidence-search.d.ts +0 -27
  219. package/router/dist/evidence/evidence-search.js +0 -490
  220. package/router/dist/evidence/evidence.d.ts +0 -38
  221. package/router/dist/evidence/evidence.js +0 -200
  222. package/router/dist/evidence/failure-contracts.d.ts +0 -37
  223. package/router/dist/evidence/failure-contracts.js +0 -166
  224. package/router/dist/evidence/line-ranges.d.ts +0 -24
  225. package/router/dist/evidence/line-ranges.js +0 -22
  226. package/router/dist/experiments/local-index.d.ts +0 -64
  227. package/router/dist/experiments/local-index.js +0 -581
  228. package/router/dist/index.d.ts +0 -30
  229. package/router/dist/index.js +0 -32
  230. package/router/dist/local/local-traversal.d.ts +0 -18
  231. package/router/dist/local/local-traversal.js +0 -334
  232. package/router/dist/processing/engine.d.ts +0 -132
  233. package/router/dist/processing/engine.js +0 -533
  234. package/router/dist/processing/reducers.d.ts +0 -280
  235. package/router/dist/processing/reducers.js +0 -1673
  236. package/router/dist/processing/renderers.d.ts +0 -31
  237. package/router/dist/processing/renderers.js +0 -195
  238. package/router/dist/processing/scripts.d.ts +0 -91
  239. package/router/dist/processing/scripts.js +0 -386
  240. package/router/dist/repo/repo-traversal.d.ts +0 -18
  241. package/router/dist/repo/repo-traversal.js +0 -245
  242. package/router/dist/routing/observed-reducers.d.ts +0 -41
  243. package/router/dist/routing/observed-reducers.js +0 -661
  244. package/router/dist/routing/observed-routing.d.ts +0 -26
  245. package/router/dist/routing/observed-routing.js +0 -378
  246. package/router/dist/routing/parsers.d.ts +0 -16
  247. package/router/dist/routing/parsers.js +0 -521
  248. package/router/dist/routing/run-filters.d.ts +0 -60
  249. package/router/dist/routing/run-filters.js +0 -238
  250. package/router/dist/routing/run-reducers.d.ts +0 -49
  251. package/router/dist/routing/run-reducers.js +0 -122
  252. package/router/dist/sandbox/adapter-roots.d.ts +0 -46
  253. package/router/dist/sandbox/adapter-roots.js +0 -66
  254. package/router/dist/sandbox/eryx-python-adapter.d.ts +0 -13
  255. package/router/dist/sandbox/eryx-python-adapter.js +0 -868
  256. package/router/dist/sandbox/jq-wasm-adapter.d.ts +0 -9
  257. package/router/dist/sandbox/jq-wasm-adapter.js +0 -429
  258. package/router/dist/sandbox/quickjs-wasi-adapter.d.ts +0 -13
  259. package/router/dist/sandbox/quickjs-wasi-adapter.js +0 -384
  260. package/router/dist/sandbox/script-sandbox.d.ts +0 -134
  261. package/router/dist/sandbox/script-sandbox.js +0 -337
  262. package/router/dist/setup/script-transform-adapters.d.ts +0 -32
  263. package/router/dist/setup/script-transform-adapters.js +0 -278
  264. package/router/dist/tools/batch.d.ts +0 -33
  265. package/router/dist/tools/batch.js +0 -586
  266. package/router/dist/tools/run.d.ts +0 -62
  267. package/router/dist/tools/run.js +0 -1304
  268. package/router/dist/tools/search.d.ts +0 -66
  269. package/router/dist/tools/search.js +0 -1364
  270. package/router/dist/transform/engine.d.ts +0 -168
  271. package/router/dist/transform/engine.js +0 -2072
  272. package/router/dist/vault/vault-index.d.ts +0 -125
  273. package/router/dist/vault/vault-index.js +0 -416
  274. package/router/dist/vault/vault.d.ts +0 -138
  275. package/router/dist/vault/vault.js +0 -630
  276. package/runtime/interaction-contract.md +0 -16
  277. package/skills/discuss/references/checkpoints.md +0 -66
  278. package/skills/execute-work/references/execution-loop.md +0 -77
  279. package/skills/output-router/SKILL.md +0 -206
  280. package/skills/output-router/references/safety-policy.md +0 -40
  281. package/skills/setup-freeflow/references/output-router-setup.md +0 -110
  282. package/skills/track-work/references/working-record-schema.md +0 -378
  283. package/skills/workflow/references/workflow-loop.md +0 -92
  284. /package/skills/handoff/references/{templates.md → handoff-templates.md} +0 -0
  285. /package/skills/review-artifact/references/{reviewer-prompt.md → independent-artifact-reviewer-contract.md} +0 -0
@@ -1,35 +1,182 @@
1
- import { handleNativeToolSafetyNet } from "./output-router/native-safety-net.js";
2
- import { handleObservedToolRouting } from "./output-router/observed-tool-routing.js";
3
- import { registerRouterTools } from "./output-router/router-tools.js";
4
- import { handleFreeflowCommand, handleOutputRouterCommand } from "./settings/settings-ui.js";
1
+ import {
2
+ COGNITIVE_ROUTING_CONTROL_ENTRY,
3
+ COGNITIVE_ROUTING_INTENT_ENTRY,
4
+ CognitiveRoutingController,
5
+ } from "./cognitive-routing/controller.js";
6
+ import {
7
+ cognitiveRoutingProfileCompletions,
8
+ handleCognitiveRoutingProfileCommand,
9
+ } from "./cognitive-routing/commands.js";
10
+ import { registerCognitiveRoutingHistoryTool, registerCognitiveRoutingTool } from "./cognitive-routing/tool.js";
11
+ import { readCognitiveRoutingHistory } from "./cognitive-routing/history.js";
12
+ import { ConversationHistoryRuntime } from "./conversation-history/runtime.js";
13
+ import { FreeflowContextRuntime } from "./freeflow-context/runtime.js";
14
+ import { CONTEXT_VIRTUALIZATION_TOOL_NAME, registerFreeflowContextTool } from "./freeflow-context/tool.js";
15
+ import { handleContextCommand } from "./context-virtualization/commands.js";
16
+ import { ContextVirtualizationRuntime } from "./context-virtualization/runtime.js";
17
+ import { handleFreeflowCommand } from "./settings/settings-ui.js";
18
+ import { isPiFlowHost } from "./runtime/runtime-identity.js";
5
19
  import {
6
20
  CONTRIBUTOR_COMMANDS,
21
+ COGNITIVE_ROUTING_SWITCH_TOOL_NAME,
7
22
  WORKFLOW_COMMANDS,
8
- WORKFLOW_BOOTSTRAP_MESSAGE_TYPE,
9
- FREEFLOW_STATUS_TOOL_NAME,
10
23
  freeflowModelSkillPaths,
11
24
  freeflowSkillPath,
12
25
  getRuntimeContext,
13
- OUTPUT_ROUTER_TOOL_NAMES,
14
26
  readCapabilityState,
15
27
  readModeState,
16
- readOutputRouterConfig,
17
28
  refreshRuntimeContext,
18
29
  restoreModeOverride,
19
30
  runtimeContext,
20
- workflowBootstrapMessage,
31
+ filterBootstrapMessage,
21
32
  setModeStatus,
22
33
  skillPrompt,
23
- notifyRouterConfigWarnings,
34
+ withFreeflowRuntimeState,
24
35
  } from "./runtime/runtime-context.js";
25
- function isOutputRouterToolName(name) {
26
- return OUTPUT_ROUTER_TOOL_NAMES.includes(name);
36
+ function startupSelectionSuppressesCognitiveRouting(ctx) {
37
+ return ctx?.modelStateProvenance?.explicitModel === true || ctx?.modelStateProvenance?.explicitThinking === true;
38
+ }
39
+ function unavailableCapability(capability, code, message) {
40
+ return {
41
+ ...capability,
42
+ effective: false,
43
+ blockingReason: { code, message },
44
+ };
45
+ }
46
+ function modelFacingCapabilityState(
47
+ capabilityState,
48
+ ctx,
49
+ freeflowContext,
50
+ cognitiveRoutingController,
51
+ cognitiveRoutingActivationFailed = false,
52
+ ) {
53
+ const surfaceState = {
54
+ ...capabilityState,
55
+ interactionContract: { ...capabilityState?.interactionContract },
56
+ skills: { ...capabilityState?.skills },
57
+ contextVirtualization: { ...capabilityState?.contextVirtualization },
58
+ conversationHistory: { ...capabilityState?.conversationHistory },
59
+ cognitiveRouting: { ...capabilityState?.cognitiveRouting },
60
+ };
61
+ if (surfaceState.enabled !== true) return surfaceState;
62
+ const markUnavailable = (key, message) => {
63
+ if (surfaceState[key]?.effective === true) {
64
+ surfaceState[key] = unavailableCapability(surfaceState[key], "unavailable", message);
65
+ }
66
+ };
67
+ if (!freeflowContext?.corePrompt) {
68
+ for (const key of [
69
+ "interactionContract",
70
+ "skills",
71
+ "contextVirtualization",
72
+ "conversationHistory",
73
+ "cognitiveRouting",
74
+ ]) {
75
+ markUnavailable(key, "Freeflow core prompt is unavailable.");
76
+ }
77
+ return surfaceState;
78
+ }
79
+ if (surfaceState.interactionContract?.effective === true && !freeflowContext.interactionContractPrompt) {
80
+ markUnavailable("interactionContract", "Interaction Contract prompt is unavailable.");
81
+ }
82
+ if (surfaceState.skills?.effective === true && !freeflowContext.skillsPrompt) {
83
+ markUnavailable("skills", "Skills prompt is unavailable.");
84
+ }
85
+ if (surfaceState.skills?.effective === true) {
86
+ if (surfaceState.contextVirtualization?.effective === true && !freeflowContext.contextVirtualizationPrompt) {
87
+ markUnavailable("contextVirtualization", "Context Virtualization prompt is unavailable.");
88
+ }
89
+ if (surfaceState.conversationHistory?.effective === true && !freeflowContext.conversationHistoryPrompt) {
90
+ markUnavailable("conversationHistory", "Conversation History prompt is unavailable.");
91
+ }
92
+ } else {
93
+ for (const key of ["contextVirtualization", "conversationHistory", "cognitiveRouting"]) {
94
+ markUnavailable(key, "Skills prompt is unavailable.");
95
+ }
96
+ }
97
+ if (surfaceState.cognitiveRouting?.effective === true) {
98
+ if (startupSelectionSuppressesCognitiveRouting(ctx)) {
99
+ surfaceState.cognitiveRouting = unavailableCapability(
100
+ surfaceState.cognitiveRouting,
101
+ "runtime_inactive",
102
+ "Cognitive Routing is inactive because the host selected the startup model or thinking level.",
103
+ );
104
+ } else if (cognitiveRoutingActivationFailed || cognitiveRoutingController?.state()?.effective === false) {
105
+ surfaceState.cognitiveRouting = unavailableCapability(
106
+ surfaceState.cognitiveRouting,
107
+ "unavailable",
108
+ "Cognitive Routing could not activate for this session.",
109
+ );
110
+ } else if (!freeflowContext.cognitiveRoutingPrompt) {
111
+ markUnavailable("cognitiveRouting", "Cognitive Routing prompt is unavailable.");
112
+ }
113
+ }
114
+ return surfaceState;
27
115
  }
28
- async function applyCapabilityToolVisibility(pi, ctx, capabilityState = undefined) {
116
+ function modelFacingModeState(modeState, capabilityState) {
117
+ if (capabilityState?.skills?.effective === true) return modeState;
118
+ return { ...modeState, active: false, effectiveMode: null };
119
+ }
120
+ function sessionHasConversationOrRoutingState(ctx) {
121
+ try {
122
+ const entries = ctx?.sessionManager?.getBranch?.() ?? ctx?.sessionManager?.getEntries?.() ?? [];
123
+ if (!Array.isArray(entries)) return false;
124
+ return entries.some((entry) => {
125
+ if (!entry || typeof entry !== "object") return false;
126
+ const record = entry;
127
+ if (
128
+ typeof record.type === "string" &&
129
+ ["message", "custom_message", "compaction", "branch_summary"].includes(record.type)
130
+ ) {
131
+ return true;
132
+ }
133
+ return (
134
+ record.type === "custom" &&
135
+ (record.customType === COGNITIVE_ROUTING_INTENT_ENTRY || record.customType === COGNITIVE_ROUTING_CONTROL_ENTRY)
136
+ );
137
+ });
138
+ } catch {
139
+ return false;
140
+ }
141
+ }
142
+ function hasCognitiveRoutingHost(pi, ctx) {
143
+ return (
144
+ isPiFlowHost(pi?.host) &&
145
+ typeof pi?.appendEntryDurable === "function" &&
146
+ typeof pi?.acquireModelStateControl === "function" &&
147
+ typeof ctx?.modelRegistry?.getApiKeyAndHeaders === "function"
148
+ );
149
+ }
150
+ async function reconcileCognitiveRoutingController(pi, ctx, capabilityState, previous) {
151
+ const cognitiveRouting = capabilityState?.cognitiveRouting;
152
+ if (
153
+ !isPiFlowHost(pi?.host) ||
154
+ !cognitiveRouting?.effective ||
155
+ startupSelectionSuppressesCognitiveRouting(ctx) ||
156
+ !hasCognitiveRoutingHost(pi, ctx)
157
+ ) {
158
+ if (previous) await previous.deactivate();
159
+ return undefined;
160
+ }
161
+ const controller = new CognitiveRoutingController({ capabilityState: cognitiveRouting, pi, ctx });
162
+ const recovered = await controller.recover();
163
+ if (recovered.status === "pending") return controller;
164
+ if (recovered.status !== "active") {
165
+ const activated = await controller.activate();
166
+ return activated.status === "active" ? controller : undefined;
167
+ }
168
+ return controller;
169
+ }
170
+ async function applyCapabilityToolVisibility(
171
+ pi,
172
+ ctx,
173
+ capabilityState = undefined,
174
+ cognitiveRoutingController = undefined,
175
+ ) {
29
176
  if (typeof pi?.setActiveTools !== "function" || typeof pi?.getAllTools !== "function") {
30
177
  return;
31
178
  }
32
- const state = capabilityState ?? (await readCapabilityState(ctx.cwd));
179
+ const state = capabilityState ?? (await readCapabilityState(ctx.cwd, ctx, pi?.host));
33
180
  const allToolNames = pi
34
181
  .getAllTools()
35
182
  .map((tool) => tool?.name)
@@ -39,22 +186,41 @@ async function applyCapabilityToolVisibility(pi, ctx, capabilityState = undefine
39
186
  const active = new Set(
40
187
  (Array.isArray(currentActive) ? currentActive : allToolNames).filter((name) => allToolNameSet.has(name)),
41
188
  );
42
- if (allToolNameSet.has(FREEFLOW_STATUS_TOOL_NAME)) {
43
- if (state.configured && state.enabled) active.add(FREEFLOW_STATUS_TOOL_NAME);
44
- else active.delete(FREEFLOW_STATUS_TOOL_NAME);
189
+ if (allToolNameSet.has(COGNITIVE_ROUTING_SWITCH_TOOL_NAME)) {
190
+ const controllerState = cognitiveRoutingController?.state();
191
+ const routingToolActive =
192
+ state.cognitiveRouting?.effective === true &&
193
+ controllerState?.effective === true &&
194
+ controllerState.controlMode === "automatic" &&
195
+ !startupSelectionSuppressesCognitiveRouting(ctx);
196
+ if (routingToolActive) active.add(COGNITIVE_ROUTING_SWITCH_TOOL_NAME);
197
+ else active.delete(COGNITIVE_ROUTING_SWITCH_TOOL_NAME);
45
198
  }
46
- for (const toolName of OUTPUT_ROUTER_TOOL_NAMES) {
47
- if (!allToolNameSet.has(toolName)) continue;
48
- if (state.outputRouter.enabled) active.add(toolName);
49
- else active.delete(toolName);
199
+ if (allToolNameSet.has(CONTEXT_VIRTUALIZATION_TOOL_NAME)) {
200
+ if (state.contextVirtualization?.effective === true || state.conversationHistory?.effective === true) {
201
+ active.add(CONTEXT_VIRTUALIZATION_TOOL_NAME);
202
+ } else {
203
+ active.delete(CONTEXT_VIRTUALIZATION_TOOL_NAME);
204
+ }
50
205
  }
51
206
  pi.setActiveTools([...active]);
52
207
  }
53
- async function applyLiveCapabilityState(pi, ctx) {
54
- const [modeState, capabilityState] = await Promise.all([readModeState(ctx.cwd), readCapabilityState(ctx.cwd)]);
208
+ async function applyLiveCapabilityState(pi, ctx, cognitiveRoutingController, options = {}) {
209
+ const [modeState, capabilityState] = await Promise.all([
210
+ readModeState(ctx.cwd),
211
+ readCapabilityState(ctx.cwd, ctx, pi?.host),
212
+ ]);
55
213
  await refreshRuntimeContext(capabilityState);
56
- setModeStatus(ctx, modeState, capabilityState);
57
- await applyCapabilityToolVisibility(pi, ctx, capabilityState);
214
+ let nextController = cognitiveRoutingController;
215
+ if (
216
+ options.reconcileCognitiveRouting &&
217
+ (nextController === undefined || capabilityState.cognitiveRouting?.effective !== true)
218
+ ) {
219
+ nextController = await reconcileCognitiveRoutingController(pi, ctx, capabilityState, nextController);
220
+ }
221
+ setModeStatus(ctx, modeState, capabilityState, nextController?.state());
222
+ await applyCapabilityToolVisibility(pi, ctx, capabilityState, nextController);
223
+ return nextController;
58
224
  }
59
225
  function disabledToolCall(toolName, capability) {
60
226
  const command = capability === "freeflow" ? "/freeflow settings" : `/${capability} settings`;
@@ -63,16 +229,7 @@ function disabledToolCall(toolName, capability) {
63
229
  reason: `${toolName} is disabled by Freeflow config. Configure ${capability} with ${command}.`,
64
230
  };
65
231
  }
66
- function capabilityCompletions(prefix) {
67
- const query = prefix ?? "";
68
- return [
69
- { value: "settings", label: "settings", description: "Open repository Output Router settings" },
70
- { value: "status", label: "status", description: "Show effective Output Router state" },
71
- { value: "enable", label: "enable", description: "Enable Output Router for this repository" },
72
- { value: "disable", label: "disable", description: "Disable Output Router for this repository" },
73
- ].filter((item) => item.value.startsWith(query));
74
- }
75
- function freeflowCompletions(prefix) {
232
+ function freeflowCompletions(prefix, hostInfo = undefined) {
76
233
  const query = prefix ?? "";
77
234
  if (query.startsWith("settings ")) {
78
235
  const settingsQuery = query.slice("settings ".length);
@@ -84,6 +241,12 @@ function freeflowCompletions(prefix) {
84
241
  .filter((item) => item.value.startsWith(settingsQuery))
85
242
  .map((item) => ({ ...item, value: `settings ${item.value}` }));
86
243
  }
244
+ if (isPiFlowHost(hostInfo) && query.startsWith("profile ")) {
245
+ return cognitiveRoutingProfileCompletions(query.slice("profile ".length)).map((item) => ({
246
+ ...item,
247
+ value: `profile ${item.value}`,
248
+ }));
249
+ }
87
250
  if (query.startsWith("mode ")) {
88
251
  const modeQuery = query.slice("mode ".length);
89
252
  return [
@@ -99,10 +262,25 @@ function freeflowCompletions(prefix) {
99
262
  .filter((item) => item.value.startsWith(modeQuery))
100
263
  .map((item) => ({ ...item, value: `mode ${item.value}` }));
101
264
  }
265
+ if (query.startsWith("context ")) {
266
+ const contextQuery = query.slice("context ".length);
267
+ return [
268
+ { value: "status", label: "status", description: "Show Freeflow Context state" },
269
+ { value: "list", label: "list", description: "List archived context projections" },
270
+ { value: "restore", label: "restore", description: "Restore one or more context references" },
271
+ { value: "reset all", label: "reset all", description: "Reset projection decisions on the active branch" },
272
+ ]
273
+ .filter((item) => item.value.startsWith(contextQuery))
274
+ .map((item) => ({ ...item, value: `context ${item.value}` }));
275
+ }
102
276
  return [
103
277
  { value: "settings", label: "settings", description: "Open personal override settings" },
104
278
  { value: "status", label: "status", description: "Show effective Freeflow state" },
279
+ { value: "context", label: "context", description: "Inspect Freeflow Context" },
105
280
  { value: "mode", label: "mode", description: "Select a temporary session mode" },
281
+ ...(isPiFlowHost(hostInfo)
282
+ ? [{ value: "profile", label: "profile", description: "Hold or release Cognitive Routing profile control" }]
283
+ : []),
106
284
  { value: "enable", label: "enable", description: "Enable Freeflow for this repository" },
107
285
  { value: "disable", label: "disable", description: "Disable Freeflow for this repository" },
108
286
  ].filter((item) => item.value.startsWith(query));
@@ -115,7 +293,7 @@ function bypassCompletions(prefix) {
115
293
  ].filter((item) => item.value.startsWith(query));
116
294
  }
117
295
  async function sendSkillCommand(pi, ctx, skill, args) {
118
- const state = await readCapabilityState(ctx.cwd);
296
+ const state = await readCapabilityState(ctx.cwd, ctx, pi?.host);
119
297
  if (skill === "setup-freeflow" && !state.configured) {
120
298
  await pi.sendUserMessage(skillPrompt(skill, args));
121
299
  return;
@@ -138,93 +316,307 @@ async function sendSkillCommand(pi, ctx, skill, args) {
138
316
  await pi.sendUserMessage(skillPrompt(skill, args));
139
317
  }
140
318
  export default function freeflow(pi) {
141
- registerRouterTools(pi);
319
+ let cognitiveRoutingController;
320
+ let latestCognitiveRoutingContext;
321
+ let providerSurfaceSnapshot;
322
+ let freeflowContextRuntime;
323
+ let contextVirtualizationRuntime;
324
+ let conversationHistoryRuntime;
325
+ const registerContextToolForState = (capabilityState) => {
326
+ registerFreeflowContextTool(
327
+ pi,
328
+ () => contextVirtualizationRuntime,
329
+ () => conversationHistoryRuntime,
330
+ {
331
+ contextVirtualization: capabilityState?.contextVirtualization?.effective === true,
332
+ conversationHistory: capabilityState?.conversationHistory?.effective === true,
333
+ },
334
+ );
335
+ };
336
+ const buildProviderSurface = async (ctx, activateCognitiveRouting = false) => {
337
+ const [modeState, capabilityState] = await Promise.all([
338
+ readModeState(ctx.cwd),
339
+ readCapabilityState(ctx.cwd, ctx, pi?.host),
340
+ ]);
341
+ const freeflowContext = await getRuntimeContext(capabilityState);
342
+ const promptCapabilityState = modelFacingCapabilityState(
343
+ capabilityState,
344
+ ctx,
345
+ freeflowContext,
346
+ cognitiveRoutingController,
347
+ );
348
+ let activationAttempted = false;
349
+ if (
350
+ activateCognitiveRouting &&
351
+ (cognitiveRoutingController === undefined || promptCapabilityState.cognitiveRouting?.effective !== true)
352
+ ) {
353
+ activationAttempted =
354
+ promptCapabilityState.cognitiveRouting?.effective === true && !startupSelectionSuppressesCognitiveRouting(ctx);
355
+ try {
356
+ cognitiveRoutingController = await reconcileCognitiveRoutingController(
357
+ pi,
358
+ ctx,
359
+ promptCapabilityState,
360
+ cognitiveRoutingController,
361
+ );
362
+ } catch {
363
+ cognitiveRoutingController = undefined;
364
+ }
365
+ }
366
+ const surfaceCapabilityState = modelFacingCapabilityState(
367
+ promptCapabilityState,
368
+ ctx,
369
+ freeflowContext,
370
+ cognitiveRoutingController,
371
+ activationAttempted && !cognitiveRoutingController,
372
+ );
373
+ return {
374
+ modeState: modelFacingModeState(modeState, surfaceCapabilityState),
375
+ capabilityState: surfaceCapabilityState,
376
+ freeflowContext,
377
+ cognitiveRoutingRuntime: cognitiveRoutingController?.state(),
378
+ configuredCapabilityState: capabilityState,
379
+ };
380
+ };
381
+ const applyLiveCapabilityStateForSession = async (ctx, options = {}) => {
382
+ cognitiveRoutingController = await applyLiveCapabilityState(pi, ctx, cognitiveRoutingController, options);
383
+ registerContextToolForState(await readCapabilityState(ctx.cwd, ctx, pi?.host));
384
+ };
385
+ if (isPiFlowHost(pi?.host)) {
386
+ registerCognitiveRoutingTool(pi, () => cognitiveRoutingController);
387
+ registerCognitiveRoutingHistoryTool(pi, (options, context) => {
388
+ if (cognitiveRoutingController) return cognitiveRoutingController.history(options);
389
+ return readCognitiveRoutingHistory(context ?? latestCognitiveRoutingContext, options);
390
+ });
391
+ }
392
+ registerFreeflowContextTool(
393
+ pi,
394
+ () => contextVirtualizationRuntime,
395
+ () => conversationHistoryRuntime,
396
+ { contextVirtualization: false, conversationHistory: false },
397
+ );
398
+ if (isPiFlowHost(pi?.host) && typeof pi.registerShortcut === "function") {
399
+ pi.registerShortcut("ctrl+shift+r", {
400
+ description: "Cycle the Cognitive Routing manual standard/reasoning hold",
401
+ handler: async (ctx) => {
402
+ if (typeof ctx?.isIdle === "function" && !ctx.isIdle()) {
403
+ ctx.ui?.notify?.("Freeflow settings and profile changes are available only while Pi is idle.", "warning");
404
+ return;
405
+ }
406
+ if (!cognitiveRoutingController) {
407
+ await applyLiveCapabilityStateForSession(ctx, { reconcileCognitiveRouting: true });
408
+ }
409
+ const controller = cognitiveRoutingController;
410
+ if (!controller) {
411
+ ctx.ui?.notify?.("Cognitive Routing is unavailable for this session.", "warning");
412
+ return;
413
+ }
414
+ const current = controller.state().activeProfile;
415
+ const target = current === "reasoning" ? "standard" : "reasoning";
416
+ const result = await controller.setManualProfile(target, "profile-shortcut");
417
+ if (result.status === "active") {
418
+ ctx.ui?.notify?.(`Cognitive Routing manual hold set to ${target}.`, "info");
419
+ } else {
420
+ ctx.ui?.notify?.(`Cognitive Routing could not set the manual profile: ${result.reason}.`, "warning");
421
+ }
422
+ await applyLiveCapabilityStateForSession(ctx);
423
+ },
424
+ });
425
+ pi.registerShortcut("ctrl+shift+a", {
426
+ description: "Cycle the Cognitive Routing automatic standard/reasoning profile",
427
+ handler: async (ctx) => {
428
+ if (typeof ctx?.isIdle === "function" && !ctx.isIdle()) {
429
+ ctx.ui?.notify?.("Freeflow settings and profile changes are available only while Pi is idle.", "warning");
430
+ return;
431
+ }
432
+ if (!cognitiveRoutingController) {
433
+ await applyLiveCapabilityStateForSession(ctx, { reconcileCognitiveRouting: true });
434
+ }
435
+ const controller = cognitiveRoutingController;
436
+ if (!controller) {
437
+ ctx.ui?.notify?.("Cognitive Routing is unavailable for this session.", "warning");
438
+ return;
439
+ }
440
+ const state = controller.state();
441
+ const target = state.activeProfile === "reasoning" ? "standard" : "reasoning";
442
+ const result =
443
+ state.controlMode === "automatic" && state.activeProfile
444
+ ? await controller.switchAutomaticProfile(
445
+ target,
446
+ `Cycle automatic profile to ${target}.`,
447
+ "user",
448
+ "profile-shortcut",
449
+ )
450
+ : await controller.setAutomaticControl("profile-shortcut");
451
+ if (result.status === "automatic") {
452
+ ctx.ui?.notify?.("Cognitive Routing automatic control active.", "info");
453
+ } else if (result.status === "active") {
454
+ ctx.ui?.notify?.(`Cognitive Routing automatic profile set to ${result.profile}.`, "info");
455
+ } else {
456
+ ctx.ui?.notify?.(`Cognitive Routing could not cycle the automatic profile: ${result.reason}.`, "warning");
457
+ }
458
+ await applyLiveCapabilityStateForSession(ctx);
459
+ },
460
+ });
461
+ }
142
462
  pi.on("resources_discover", async (event, ctx) => {
143
463
  const cwd = ctx?.cwd ?? event?.cwd ?? process.cwd();
144
- const state = await readCapabilityState(cwd);
464
+ const snapshot =
465
+ providerSurfaceSnapshot?.context === ctx
466
+ ? providerSurfaceSnapshot.value
467
+ : await buildProviderSurface(ctx ?? { cwd }, false);
468
+ const state = snapshot.capabilityState;
145
469
  if (!state.configured) {
146
470
  return { skillPaths: [freeflowSkillPath("setup-freeflow")] };
147
471
  }
148
472
  if (!state.enabled || !state.skills.effective) {
149
473
  return { skillPaths: [] };
150
474
  }
151
- return { skillPaths: freeflowModelSkillPaths() };
475
+ return { skillPaths: freeflowModelSkillPaths(state) };
152
476
  });
153
477
  pi.on("session_start", async (_event, ctx) => {
478
+ latestCognitiveRoutingContext = ctx;
479
+ providerSurfaceSnapshot = undefined;
154
480
  restoreModeOverride(ctx);
155
- const [modeState, routerConfigResult, capabilityState] = await Promise.all([
156
- readModeState(ctx.cwd),
157
- readOutputRouterConfig(ctx.cwd),
158
- readCapabilityState(ctx.cwd),
159
- ]);
481
+ freeflowContextRuntime = new FreeflowContextRuntime(ctx);
482
+ contextVirtualizationRuntime = new ContextVirtualizationRuntime(pi, ctx, freeflowContextRuntime);
483
+ conversationHistoryRuntime = new ConversationHistoryRuntime(
484
+ ctx,
485
+ (entryId) => contextVirtualizationRuntime?.isSourceFullyProjected(entryId) ?? true,
486
+ freeflowContextRuntime,
487
+ );
488
+ await contextVirtualizationRuntime.recover(ctx);
489
+ const capabilityState = await readCapabilityState(ctx.cwd, ctx, pi?.host);
160
490
  await refreshRuntimeContext(capabilityState);
161
- setModeStatus(ctx, modeState, capabilityState);
162
- notifyRouterConfigWarnings(ctx, routerConfigResult);
163
- await applyCapabilityToolVisibility(pi, ctx, capabilityState);
491
+ const hasSessionState = sessionHasConversationOrRoutingState(ctx);
492
+ const snapshot = await buildProviderSurface(ctx, hasSessionState);
493
+ const cognitiveRoutingStartupPending =
494
+ snapshot.capabilityState?.cognitiveRouting?.effective === true &&
495
+ !hasSessionState &&
496
+ !startupSelectionSuppressesCognitiveRouting(ctx);
497
+ registerContextToolForState(snapshot.capabilityState);
498
+ setModeStatus(ctx, snapshot.modeState, snapshot.capabilityState, snapshot.cognitiveRoutingRuntime, {
499
+ cognitiveRoutingStartupPending,
500
+ });
501
+ await applyCapabilityToolVisibility(pi, ctx, snapshot.capabilityState, cognitiveRoutingController);
502
+ });
503
+ pi.on("agent_settled", async (_event, ctx) => {
504
+ if (!cognitiveRoutingController) return undefined;
505
+ await applyLiveCapabilityStateForSession(ctx);
506
+ return undefined;
507
+ });
508
+ pi.on("session_shutdown", async (event) => {
509
+ providerSurfaceSnapshot = undefined;
510
+ const controller = cognitiveRoutingController;
511
+ cognitiveRoutingController = undefined;
512
+ freeflowContextRuntime = undefined;
513
+ contextVirtualizationRuntime = undefined;
514
+ conversationHistoryRuntime = undefined;
515
+ if (controller) await controller.shutdown(event?.reason);
164
516
  });
165
517
  pi.on("session_tree", async (_event, ctx) => {
518
+ latestCognitiveRoutingContext = ctx;
519
+ providerSurfaceSnapshot = undefined;
166
520
  restoreModeOverride(ctx);
167
- await applyLiveCapabilityState(pi, ctx);
521
+ const controller = cognitiveRoutingController;
522
+ if (controller) await controller.reconcileBranch();
523
+ if (contextVirtualizationRuntime) {
524
+ contextVirtualizationRuntime.setContext(ctx);
525
+ await contextVirtualizationRuntime.recover(ctx);
526
+ }
527
+ conversationHistoryRuntime?.setContext(ctx);
528
+ await applyLiveCapabilityStateForSession(ctx);
168
529
  });
169
530
  pi.on("session_compact", async (_event, ctx) => {
170
- const [modeState, routerConfigResult, capabilityState] = await Promise.all([
531
+ latestCognitiveRoutingContext = ctx;
532
+ providerSurfaceSnapshot = undefined;
533
+ const controller = cognitiveRoutingController;
534
+ if (controller) await controller.reconcileBranch("session-compact");
535
+ if (contextVirtualizationRuntime) {
536
+ contextVirtualizationRuntime.setContext(ctx);
537
+ await contextVirtualizationRuntime.recover(ctx);
538
+ }
539
+ conversationHistoryRuntime?.setContext(ctx);
540
+ const [modeState, capabilityState] = await Promise.all([
171
541
  readModeState(ctx.cwd),
172
- readOutputRouterConfig(ctx.cwd),
173
- readCapabilityState(ctx.cwd),
542
+ readCapabilityState(ctx.cwd, ctx, pi?.host),
174
543
  ]);
175
544
  await refreshRuntimeContext(capabilityState);
176
- setModeStatus(ctx, modeState, capabilityState);
177
- notifyRouterConfigWarnings(ctx, routerConfigResult);
178
- await applyCapabilityToolVisibility(pi, ctx, capabilityState);
545
+ registerContextToolForState(capabilityState);
546
+ setModeStatus(ctx, modeState, capabilityState, cognitiveRoutingController?.state());
547
+ await applyCapabilityToolVisibility(pi, ctx, capabilityState, cognitiveRoutingController);
179
548
  });
180
549
  pi.on("before_agent_start", async (event, ctx) => {
181
- const [modeState, routerConfigResult, capabilityState] = await Promise.all([
182
- readModeState(ctx.cwd),
183
- readOutputRouterConfig(ctx.cwd),
184
- readCapabilityState(ctx.cwd),
185
- ]);
186
- const freeflowContext = await getRuntimeContext(capabilityState);
187
- setModeStatus(ctx, modeState, capabilityState);
188
- notifyRouterConfigWarnings(ctx, routerConfigResult);
189
- await applyCapabilityToolVisibility(pi, ctx, capabilityState);
190
- const freeflowRuntimeContext = runtimeContext(modeState, freeflowContext, routerConfigResult, capabilityState);
191
- const workflowMessage = workflowBootstrapMessage(freeflowContext, capabilityState, ctx.sessionManager);
550
+ latestCognitiveRoutingContext = ctx;
551
+ const snapshot = await buildProviderSurface(ctx, true);
552
+ providerSurfaceSnapshot = { context: ctx, value: snapshot };
553
+ registerContextToolForState(snapshot.capabilityState);
554
+ setModeStatus(ctx, snapshot.modeState, snapshot.capabilityState, snapshot.cognitiveRoutingRuntime);
555
+ await applyCapabilityToolVisibility(pi, ctx, snapshot.capabilityState, cognitiveRoutingController);
556
+ const freeflowRuntimeContext = runtimeContext(snapshot.freeflowContext, snapshot.capabilityState);
192
557
  const systemPrompt = freeflowRuntimeContext
193
558
  ? `${event.systemPrompt}\n\n${freeflowRuntimeContext}`
194
559
  : event.systemPrompt;
195
- return { message: workflowMessage, systemPrompt };
560
+ return { systemPrompt };
196
561
  });
197
562
  pi.on("context", async (event, ctx) => {
198
- const capabilityState = await readCapabilityState(ctx.cwd);
199
- if (capabilityState.skills.effective) {
200
- return undefined;
563
+ const snapshot =
564
+ providerSurfaceSnapshot?.context === ctx ? providerSurfaceSnapshot.value : await buildProviderSurface(ctx, false);
565
+ if (providerSurfaceSnapshot?.context === ctx) providerSurfaceSnapshot = undefined;
566
+ const cognitiveRoutingRuntime = snapshot.cognitiveRoutingRuntime;
567
+ const surfaceCapabilityState = snapshot.capabilityState;
568
+ const surfaceModeState = snapshot.modeState;
569
+ let changed = false;
570
+ let messages = event.messages
571
+ .map((message) => {
572
+ const filtered = filterBootstrapMessage(message);
573
+ if (filtered !== message) changed = true;
574
+ return filtered;
575
+ })
576
+ .filter((message) => message !== undefined);
577
+ if (contextVirtualizationRuntime) {
578
+ contextVirtualizationRuntime.setContext(ctx);
579
+ const projected = await contextVirtualizationRuntime.project(
580
+ messages,
581
+ surfaceCapabilityState.contextVirtualization?.effective === true,
582
+ );
583
+ if (projected.changed) {
584
+ changed = true;
585
+ messages = projected.messages;
586
+ }
587
+ }
588
+ if (conversationHistoryRuntime && surfaceCapabilityState.conversationHistory?.effective === true) {
589
+ conversationHistoryRuntime.setContext(ctx);
590
+ conversationHistoryRuntime.capture(surfaceCapabilityState.contextVirtualization?.effective === true);
201
591
  }
202
- const messages = event.messages.filter(
203
- (message) => !(message?.role === "custom" && message?.customType === WORKFLOW_BOOTSTRAP_MESSAGE_TYPE),
592
+ const nextMessages = withFreeflowRuntimeState(
593
+ messages,
594
+ surfaceModeState,
595
+ surfaceCapabilityState,
596
+ cognitiveRoutingRuntime,
204
597
  );
205
- return messages.length === event.messages.length ? undefined : { messages };
598
+ changed = true;
599
+ messages = nextMessages;
600
+ return changed ? { messages } : undefined;
206
601
  });
207
602
  pi.on("tool_call", async (event, ctx) => {
208
- const capabilityState = await readCapabilityState(ctx.cwd);
603
+ const capabilityState = await readCapabilityState(ctx.cwd, ctx, pi?.host);
209
604
  const toolName = typeof event?.toolName === "string" ? event.toolName : "";
210
- if ((!capabilityState.configured || !capabilityState.enabled) && toolName === FREEFLOW_STATUS_TOOL_NAME) {
211
- return disabledToolCall(toolName, "freeflow");
212
- }
213
- if (!capabilityState.outputRouter.enabled && isOutputRouterToolName(toolName)) {
214
- return disabledToolCall(toolName, "output-router");
605
+ if (
606
+ capabilityState.contextVirtualization?.effective !== true &&
607
+ capabilityState.conversationHistory?.effective !== true &&
608
+ toolName === CONTEXT_VIRTUALIZATION_TOOL_NAME
609
+ ) {
610
+ return disabledToolCall(toolName, "context");
215
611
  }
216
612
  return undefined;
217
613
  });
218
614
  pi.on("tool_result", async (event, ctx) => {
219
- const capabilityState = await readCapabilityState(ctx.cwd);
220
- if (!capabilityState.outputRouter.enabled) {
221
- return undefined;
222
- }
223
- const observed = await handleObservedToolRouting(event, ctx);
224
- if (observed) {
225
- return observed;
615
+ const toolName = typeof event?.toolName === "string" ? event.toolName : "";
616
+ if (isPiFlowHost(pi?.host) && toolName === COGNITIVE_ROUTING_SWITCH_TOOL_NAME) {
617
+ await applyLiveCapabilityStateForSession(ctx);
226
618
  }
227
- return handleNativeToolSafetyNet(event, ctx);
619
+ return undefined;
228
620
  });
229
621
  for (const { command, skill } of WORKFLOW_COMMANDS) {
230
622
  pi.registerCommand(command, {
@@ -245,25 +637,51 @@ export default function freeflow(pi) {
245
637
  }
246
638
  pi.registerCommand("freeflow", {
247
639
  description: "Open unified Freeflow settings or print compact status",
248
- getArgumentCompletions: freeflowCompletions,
640
+ getArgumentCompletions: (prefix) => freeflowCompletions(prefix, pi?.host),
249
641
  handler: async (args, ctx) => {
642
+ const contextInput = (args ?? "").trim();
643
+ if (contextInput === "context" || contextInput.startsWith("context ")) {
644
+ const capabilityState = await readCapabilityState(ctx.cwd, ctx, pi?.host);
645
+ await handleContextCommand(
646
+ contextInput.slice("context".length).trim(),
647
+ ctx,
648
+ contextVirtualizationRuntime,
649
+ capabilityState.contextVirtualization?.effective === true,
650
+ capabilityState.conversationHistory?.effective === true,
651
+ );
652
+ return;
653
+ }
654
+ if (isPiFlowHost(pi?.host) && /^profile(?:\s|$)/i.test((args ?? "").trim())) {
655
+ const profileCommandContext = {
656
+ isIdle: ctx?.isIdle,
657
+ ui: ctx?.ui,
658
+ history: (options) =>
659
+ cognitiveRoutingController?.history(options) ?? readCognitiveRoutingHistory(ctx, options),
660
+ };
661
+ const historyCommand = /^profile\s+history(?:\s|$)/i.test((args ?? "").trim());
662
+ if (historyCommand) {
663
+ await handleCognitiveRoutingProfileCommand(args, profileCommandContext, cognitiveRoutingController);
664
+ return;
665
+ }
666
+ if (!cognitiveRoutingController) {
667
+ await applyLiveCapabilityStateForSession(ctx, { reconcileCognitiveRouting: true });
668
+ }
669
+ if (await handleCognitiveRoutingProfileCommand(args, profileCommandContext, cognitiveRoutingController)) {
670
+ await applyLiveCapabilityStateForSession(ctx);
671
+ return;
672
+ }
673
+ }
250
674
  await handleFreeflowCommand(
251
675
  args,
252
676
  ctx,
253
- async () => {
254
- await applyLiveCapabilityState(pi, ctx);
677
+ async (_changed, options = {}) => {
678
+ await applyLiveCapabilityStateForSession(ctx, {
679
+ reconcileCognitiveRouting: options.reconcileCognitiveRouting ?? true,
680
+ });
255
681
  },
256
682
  pi,
683
+ cognitiveRoutingController,
257
684
  );
258
685
  },
259
686
  });
260
- pi.registerCommand("output-router", {
261
- description: "Open Freeflow Output Router settings or print compact status",
262
- getArgumentCompletions: capabilityCompletions,
263
- handler: async (args, ctx) => {
264
- await handleOutputRouterCommand(args, ctx, async () => {
265
- await applyLiveCapabilityState(pi, ctx);
266
- });
267
- },
268
- });
269
687
  }