@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,38 +1,210 @@
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
36
 
26
- function isOutputRouterToolName(name: string): boolean {
27
- return OUTPUT_ROUTER_TOOL_NAMES.includes(name);
37
+ function startupSelectionSuppressesCognitiveRouting(ctx: any): boolean {
38
+ return ctx?.modelStateProvenance?.explicitModel === true || ctx?.modelStateProvenance?.explicitThinking === true;
28
39
  }
29
40
 
30
- async function applyCapabilityToolVisibility(pi: any, ctx: any, capabilityState = undefined): Promise<void> {
41
+ function unavailableCapability(capability: any, code: string, message: string): any {
42
+ return {
43
+ ...capability,
44
+ effective: false,
45
+ blockingReason: { code, message },
46
+ };
47
+ }
48
+
49
+ function modelFacingCapabilityState(
50
+ capabilityState: any,
51
+ ctx: any,
52
+ freeflowContext: any,
53
+ cognitiveRoutingController: CognitiveRoutingController | undefined,
54
+ cognitiveRoutingActivationFailed = false,
55
+ ): any {
56
+ const surfaceState = {
57
+ ...capabilityState,
58
+ interactionContract: { ...capabilityState?.interactionContract },
59
+ skills: { ...capabilityState?.skills },
60
+ contextVirtualization: { ...capabilityState?.contextVirtualization },
61
+ conversationHistory: { ...capabilityState?.conversationHistory },
62
+ cognitiveRouting: { ...capabilityState?.cognitiveRouting },
63
+ };
64
+ if (surfaceState.enabled !== true) return surfaceState;
65
+
66
+ const markUnavailable = (key: string, message: string) => {
67
+ if (surfaceState[key]?.effective === true) {
68
+ surfaceState[key] = unavailableCapability(surfaceState[key], "unavailable", message);
69
+ }
70
+ };
71
+
72
+ if (!freeflowContext?.corePrompt) {
73
+ for (const key of [
74
+ "interactionContract",
75
+ "skills",
76
+ "contextVirtualization",
77
+ "conversationHistory",
78
+ "cognitiveRouting",
79
+ ]) {
80
+ markUnavailable(key, "Freeflow core prompt is unavailable.");
81
+ }
82
+ return surfaceState;
83
+ }
84
+
85
+ if (surfaceState.interactionContract?.effective === true && !freeflowContext.interactionContractPrompt) {
86
+ markUnavailable("interactionContract", "Interaction Contract prompt is unavailable.");
87
+ }
88
+ if (surfaceState.skills?.effective === true && !freeflowContext.skillsPrompt) {
89
+ markUnavailable("skills", "Skills prompt is unavailable.");
90
+ }
91
+
92
+ if (surfaceState.skills?.effective === true) {
93
+ if (surfaceState.contextVirtualization?.effective === true && !freeflowContext.contextVirtualizationPrompt) {
94
+ markUnavailable("contextVirtualization", "Context Virtualization prompt is unavailable.");
95
+ }
96
+ if (surfaceState.conversationHistory?.effective === true && !freeflowContext.conversationHistoryPrompt) {
97
+ markUnavailable("conversationHistory", "Conversation History prompt is unavailable.");
98
+ }
99
+ } else {
100
+ for (const key of ["contextVirtualization", "conversationHistory", "cognitiveRouting"]) {
101
+ markUnavailable(key, "Skills prompt is unavailable.");
102
+ }
103
+ }
104
+
105
+ if (surfaceState.cognitiveRouting?.effective === true) {
106
+ if (startupSelectionSuppressesCognitiveRouting(ctx)) {
107
+ surfaceState.cognitiveRouting = unavailableCapability(
108
+ surfaceState.cognitiveRouting,
109
+ "runtime_inactive",
110
+ "Cognitive Routing is inactive because the host selected the startup model or thinking level.",
111
+ );
112
+ } else if (cognitiveRoutingActivationFailed || cognitiveRoutingController?.state()?.effective === false) {
113
+ surfaceState.cognitiveRouting = unavailableCapability(
114
+ surfaceState.cognitiveRouting,
115
+ "unavailable",
116
+ "Cognitive Routing could not activate for this session.",
117
+ );
118
+ } else if (!freeflowContext.cognitiveRoutingPrompt) {
119
+ markUnavailable("cognitiveRouting", "Cognitive Routing prompt is unavailable.");
120
+ }
121
+ }
122
+
123
+ return surfaceState;
124
+ }
125
+
126
+ function modelFacingModeState(modeState: any, capabilityState: any): any {
127
+ if (capabilityState?.skills?.effective === true) return modeState;
128
+ return { ...modeState, active: false, effectiveMode: null };
129
+ }
130
+
131
+ type SessionEntriesContext = {
132
+ sessionManager?: {
133
+ getBranch?: () => readonly unknown[];
134
+ getEntries?: () => readonly unknown[];
135
+ };
136
+ };
137
+
138
+ function sessionHasConversationOrRoutingState(ctx: SessionEntriesContext | undefined): boolean {
139
+ try {
140
+ const entries = ctx?.sessionManager?.getBranch?.() ?? ctx?.sessionManager?.getEntries?.() ?? [];
141
+ if (!Array.isArray(entries)) return false;
142
+ return entries.some((entry: unknown) => {
143
+ if (!entry || typeof entry !== "object") return false;
144
+ const record = entry as { type?: unknown; customType?: unknown };
145
+ if (
146
+ typeof record.type === "string" &&
147
+ ["message", "custom_message", "compaction", "branch_summary"].includes(record.type)
148
+ ) {
149
+ return true;
150
+ }
151
+ return (
152
+ record.type === "custom" &&
153
+ (record.customType === COGNITIVE_ROUTING_INTENT_ENTRY || record.customType === COGNITIVE_ROUTING_CONTROL_ENTRY)
154
+ );
155
+ });
156
+ } catch {
157
+ return false;
158
+ }
159
+ }
160
+
161
+ function hasCognitiveRoutingHost(pi: any, ctx: any): boolean {
162
+ return (
163
+ isPiFlowHost(pi?.host) &&
164
+ typeof pi?.appendEntryDurable === "function" &&
165
+ typeof pi?.acquireModelStateControl === "function" &&
166
+ typeof ctx?.modelRegistry?.getApiKeyAndHeaders === "function"
167
+ );
168
+ }
169
+
170
+ async function reconcileCognitiveRoutingController(
171
+ pi: any,
172
+ ctx: any,
173
+ capabilityState: any,
174
+ previous: CognitiveRoutingController | undefined,
175
+ ): Promise<CognitiveRoutingController | undefined> {
176
+ const cognitiveRouting = capabilityState?.cognitiveRouting;
177
+ if (
178
+ !isPiFlowHost(pi?.host) ||
179
+ !cognitiveRouting?.effective ||
180
+ startupSelectionSuppressesCognitiveRouting(ctx) ||
181
+ !hasCognitiveRoutingHost(pi, ctx)
182
+ ) {
183
+ if (previous) await previous.deactivate();
184
+ return undefined;
185
+ }
186
+
187
+ const controller = new CognitiveRoutingController({ capabilityState: cognitiveRouting, pi, ctx });
188
+ const recovered = await controller.recover();
189
+ if (recovered.status === "pending") return controller;
190
+ if (recovered.status !== "active") {
191
+ const activated = await controller.activate();
192
+ return activated.status === "active" ? controller : undefined;
193
+ }
194
+ return controller;
195
+ }
196
+
197
+ async function applyCapabilityToolVisibility(
198
+ pi: any,
199
+ ctx: any,
200
+ capabilityState = undefined,
201
+ cognitiveRoutingController: CognitiveRoutingController | undefined = undefined,
202
+ ): Promise<void> {
31
203
  if (typeof pi?.setActiveTools !== "function" || typeof pi?.getAllTools !== "function") {
32
204
  return;
33
205
  }
34
206
 
35
- const state = capabilityState ?? (await readCapabilityState(ctx.cwd));
207
+ const state = capabilityState ?? (await readCapabilityState(ctx.cwd, ctx, pi?.host));
36
208
  const allToolNames = pi
37
209
  .getAllTools()
38
210
  .map((tool: any) => tool?.name)
@@ -43,25 +215,49 @@ async function applyCapabilityToolVisibility(pi: any, ctx: any, capabilityState
43
215
  (Array.isArray(currentActive) ? currentActive : allToolNames).filter((name: string) => allToolNameSet.has(name)),
44
216
  );
45
217
 
46
- if (allToolNameSet.has(FREEFLOW_STATUS_TOOL_NAME)) {
47
- if (state.configured && state.enabled) active.add(FREEFLOW_STATUS_TOOL_NAME);
48
- else active.delete(FREEFLOW_STATUS_TOOL_NAME);
218
+ if (allToolNameSet.has(COGNITIVE_ROUTING_SWITCH_TOOL_NAME)) {
219
+ const controllerState = cognitiveRoutingController?.state();
220
+ const routingToolActive =
221
+ state.cognitiveRouting?.effective === true &&
222
+ controllerState?.effective === true &&
223
+ controllerState.controlMode === "automatic" &&
224
+ !startupSelectionSuppressesCognitiveRouting(ctx);
225
+ if (routingToolActive) active.add(COGNITIVE_ROUTING_SWITCH_TOOL_NAME);
226
+ else active.delete(COGNITIVE_ROUTING_SWITCH_TOOL_NAME);
49
227
  }
50
228
 
51
- for (const toolName of OUTPUT_ROUTER_TOOL_NAMES) {
52
- if (!allToolNameSet.has(toolName)) continue;
53
- if (state.outputRouter.enabled) active.add(toolName);
54
- else active.delete(toolName);
229
+ if (allToolNameSet.has(CONTEXT_VIRTUALIZATION_TOOL_NAME)) {
230
+ if (state.contextVirtualization?.effective === true || state.conversationHistory?.effective === true) {
231
+ active.add(CONTEXT_VIRTUALIZATION_TOOL_NAME);
232
+ } else {
233
+ active.delete(CONTEXT_VIRTUALIZATION_TOOL_NAME);
234
+ }
55
235
  }
56
236
 
57
237
  pi.setActiveTools([...active]);
58
238
  }
59
239
 
60
- async function applyLiveCapabilityState(pi: any, ctx: any): Promise<void> {
61
- const [modeState, capabilityState] = await Promise.all([readModeState(ctx.cwd), readCapabilityState(ctx.cwd)]);
240
+ async function applyLiveCapabilityState(
241
+ pi: any,
242
+ ctx: any,
243
+ cognitiveRoutingController: CognitiveRoutingController | undefined,
244
+ options: { reconcileCognitiveRouting?: boolean } = {},
245
+ ): Promise<CognitiveRoutingController | undefined> {
246
+ const [modeState, capabilityState] = await Promise.all([
247
+ readModeState(ctx.cwd),
248
+ readCapabilityState(ctx.cwd, ctx, pi?.host),
249
+ ]);
62
250
  await refreshRuntimeContext(capabilityState);
63
- setModeStatus(ctx, modeState, capabilityState);
64
- await applyCapabilityToolVisibility(pi, ctx, capabilityState);
251
+ let nextController = cognitiveRoutingController;
252
+ if (
253
+ options.reconcileCognitiveRouting &&
254
+ (nextController === undefined || capabilityState.cognitiveRouting?.effective !== true)
255
+ ) {
256
+ nextController = await reconcileCognitiveRoutingController(pi, ctx, capabilityState, nextController);
257
+ }
258
+ setModeStatus(ctx, modeState, capabilityState, nextController?.state());
259
+ await applyCapabilityToolVisibility(pi, ctx, capabilityState, nextController);
260
+ return nextController;
65
261
  }
66
262
 
67
263
  function disabledToolCall(toolName: string, capability: string) {
@@ -72,17 +268,7 @@ function disabledToolCall(toolName: string, capability: string) {
72
268
  };
73
269
  }
74
270
 
75
- function capabilityCompletions(prefix: string | undefined) {
76
- const query = prefix ?? "";
77
- return [
78
- { value: "settings", label: "settings", description: "Open repository Output Router settings" },
79
- { value: "status", label: "status", description: "Show effective Output Router state" },
80
- { value: "enable", label: "enable", description: "Enable Output Router for this repository" },
81
- { value: "disable", label: "disable", description: "Disable Output Router for this repository" },
82
- ].filter((item) => item.value.startsWith(query));
83
- }
84
-
85
- function freeflowCompletions(prefix: string | undefined) {
271
+ function freeflowCompletions(prefix: string | undefined, hostInfo = undefined) {
86
272
  const query = prefix ?? "";
87
273
  if (query.startsWith("settings ")) {
88
274
  const settingsQuery = query.slice("settings ".length);
@@ -94,6 +280,12 @@ function freeflowCompletions(prefix: string | undefined) {
94
280
  .filter((item) => item.value.startsWith(settingsQuery))
95
281
  .map((item) => ({ ...item, value: `settings ${item.value}` }));
96
282
  }
283
+ if (isPiFlowHost(hostInfo) && query.startsWith("profile ")) {
284
+ return cognitiveRoutingProfileCompletions(query.slice("profile ".length)).map((item) => ({
285
+ ...item,
286
+ value: `profile ${item.value}`,
287
+ }));
288
+ }
97
289
  if (query.startsWith("mode ")) {
98
290
  const modeQuery = query.slice("mode ".length);
99
291
  return [
@@ -109,10 +301,25 @@ function freeflowCompletions(prefix: string | undefined) {
109
301
  .filter((item) => item.value.startsWith(modeQuery))
110
302
  .map((item) => ({ ...item, value: `mode ${item.value}` }));
111
303
  }
304
+ if (query.startsWith("context ")) {
305
+ const contextQuery = query.slice("context ".length);
306
+ return [
307
+ { value: "status", label: "status", description: "Show Freeflow Context state" },
308
+ { value: "list", label: "list", description: "List archived context projections" },
309
+ { value: "restore", label: "restore", description: "Restore one or more context references" },
310
+ { value: "reset all", label: "reset all", description: "Reset projection decisions on the active branch" },
311
+ ]
312
+ .filter((item) => item.value.startsWith(contextQuery))
313
+ .map((item) => ({ ...item, value: `context ${item.value}` }));
314
+ }
112
315
  return [
113
316
  { value: "settings", label: "settings", description: "Open personal override settings" },
114
317
  { value: "status", label: "status", description: "Show effective Freeflow state" },
318
+ { value: "context", label: "context", description: "Inspect Freeflow Context" },
115
319
  { value: "mode", label: "mode", description: "Select a temporary session mode" },
320
+ ...(isPiFlowHost(hostInfo)
321
+ ? [{ value: "profile", label: "profile", description: "Hold or release Cognitive Routing profile control" }]
322
+ : []),
116
323
  { value: "enable", label: "enable", description: "Enable Freeflow for this repository" },
117
324
  { value: "disable", label: "disable", description: "Disable Freeflow for this repository" },
118
325
  ].filter((item) => item.value.startsWith(query));
@@ -127,7 +334,7 @@ function bypassCompletions(prefix: string | undefined) {
127
334
  }
128
335
 
129
336
  async function sendSkillCommand(pi: any, ctx: any, skill: string, args: string | undefined) {
130
- const state = await readCapabilityState(ctx.cwd);
337
+ const state = await readCapabilityState(ctx.cwd, ctx, pi?.host);
131
338
  if (skill === "setup-freeflow" && !state.configured) {
132
339
  await pi.sendUserMessage(skillPrompt(skill, args));
133
340
  return;
@@ -151,102 +358,322 @@ async function sendSkillCommand(pi: any, ctx: any, skill: string, args: string |
151
358
  }
152
359
 
153
360
  export default function freeflow(pi) {
154
- registerRouterTools(pi);
361
+ let cognitiveRoutingController: CognitiveRoutingController | undefined;
362
+ let latestCognitiveRoutingContext: any;
363
+ let providerSurfaceSnapshot: { context: any; value: any } | undefined;
364
+ let freeflowContextRuntime: FreeflowContextRuntime | undefined;
365
+ let contextVirtualizationRuntime: ContextVirtualizationRuntime | undefined;
366
+ let conversationHistoryRuntime: ConversationHistoryRuntime | undefined;
367
+ const registerContextToolForState = (capabilityState: any) => {
368
+ registerFreeflowContextTool(
369
+ pi,
370
+ () => contextVirtualizationRuntime,
371
+ () => conversationHistoryRuntime,
372
+ {
373
+ contextVirtualization: capabilityState?.contextVirtualization?.effective === true,
374
+ conversationHistory: capabilityState?.conversationHistory?.effective === true,
375
+ },
376
+ );
377
+ };
378
+ const buildProviderSurface = async (ctx: any, activateCognitiveRouting = false): Promise<any> => {
379
+ const [modeState, capabilityState] = await Promise.all([
380
+ readModeState(ctx.cwd),
381
+ readCapabilityState(ctx.cwd, ctx, pi?.host),
382
+ ]);
383
+ const freeflowContext = await getRuntimeContext(capabilityState);
384
+ const promptCapabilityState = modelFacingCapabilityState(
385
+ capabilityState,
386
+ ctx,
387
+ freeflowContext,
388
+ cognitiveRoutingController,
389
+ );
390
+ let activationAttempted = false;
391
+ if (
392
+ activateCognitiveRouting &&
393
+ (cognitiveRoutingController === undefined || promptCapabilityState.cognitiveRouting?.effective !== true)
394
+ ) {
395
+ activationAttempted =
396
+ promptCapabilityState.cognitiveRouting?.effective === true && !startupSelectionSuppressesCognitiveRouting(ctx);
397
+ try {
398
+ cognitiveRoutingController = await reconcileCognitiveRoutingController(
399
+ pi,
400
+ ctx,
401
+ promptCapabilityState,
402
+ cognitiveRoutingController,
403
+ );
404
+ } catch {
405
+ cognitiveRoutingController = undefined;
406
+ }
407
+ }
408
+ const surfaceCapabilityState = modelFacingCapabilityState(
409
+ promptCapabilityState,
410
+ ctx,
411
+ freeflowContext,
412
+ cognitiveRoutingController,
413
+ activationAttempted && !cognitiveRoutingController,
414
+ );
415
+ return {
416
+ modeState: modelFacingModeState(modeState, surfaceCapabilityState),
417
+ capabilityState: surfaceCapabilityState,
418
+ freeflowContext,
419
+ cognitiveRoutingRuntime: cognitiveRoutingController?.state(),
420
+ configuredCapabilityState: capabilityState,
421
+ };
422
+ };
423
+ const applyLiveCapabilityStateForSession = async (
424
+ ctx: any,
425
+ options: { reconcileCognitiveRouting?: boolean } = {},
426
+ ): Promise<void> => {
427
+ cognitiveRoutingController = await applyLiveCapabilityState(pi, ctx, cognitiveRoutingController, options);
428
+ registerContextToolForState(await readCapabilityState(ctx.cwd, ctx, pi?.host));
429
+ };
430
+
431
+ if (isPiFlowHost(pi?.host)) {
432
+ registerCognitiveRoutingTool(pi, () => cognitiveRoutingController);
433
+ registerCognitiveRoutingHistoryTool(pi, (options, context) => {
434
+ if (cognitiveRoutingController) return cognitiveRoutingController.history(options);
435
+ return readCognitiveRoutingHistory(context ?? latestCognitiveRoutingContext, options);
436
+ });
437
+ }
438
+ registerFreeflowContextTool(
439
+ pi,
440
+ () => contextVirtualizationRuntime,
441
+ () => conversationHistoryRuntime,
442
+ { contextVirtualization: false, conversationHistory: false },
443
+ );
444
+
445
+ if (isPiFlowHost(pi?.host) && typeof pi.registerShortcut === "function") {
446
+ pi.registerShortcut("ctrl+shift+r", {
447
+ description: "Cycle the Cognitive Routing manual standard/reasoning hold",
448
+ handler: async (ctx) => {
449
+ if (typeof ctx?.isIdle === "function" && !ctx.isIdle()) {
450
+ ctx.ui?.notify?.("Freeflow settings and profile changes are available only while Pi is idle.", "warning");
451
+ return;
452
+ }
453
+ if (!cognitiveRoutingController) {
454
+ await applyLiveCapabilityStateForSession(ctx, { reconcileCognitiveRouting: true });
455
+ }
456
+ const controller = cognitiveRoutingController;
457
+ if (!controller) {
458
+ ctx.ui?.notify?.("Cognitive Routing is unavailable for this session.", "warning");
459
+ return;
460
+ }
461
+ const current = controller.state().activeProfile;
462
+ const target = current === "reasoning" ? "standard" : "reasoning";
463
+ const result = await controller.setManualProfile(target, "profile-shortcut");
464
+ if (result.status === "active") {
465
+ ctx.ui?.notify?.(`Cognitive Routing manual hold set to ${target}.`, "info");
466
+ } else {
467
+ ctx.ui?.notify?.(`Cognitive Routing could not set the manual profile: ${result.reason}.`, "warning");
468
+ }
469
+ await applyLiveCapabilityStateForSession(ctx);
470
+ },
471
+ });
472
+ pi.registerShortcut("ctrl+shift+a", {
473
+ description: "Cycle the Cognitive Routing automatic standard/reasoning profile",
474
+ handler: async (ctx) => {
475
+ if (typeof ctx?.isIdle === "function" && !ctx.isIdle()) {
476
+ ctx.ui?.notify?.("Freeflow settings and profile changes are available only while Pi is idle.", "warning");
477
+ return;
478
+ }
479
+ if (!cognitiveRoutingController) {
480
+ await applyLiveCapabilityStateForSession(ctx, { reconcileCognitiveRouting: true });
481
+ }
482
+ const controller = cognitiveRoutingController;
483
+ if (!controller) {
484
+ ctx.ui?.notify?.("Cognitive Routing is unavailable for this session.", "warning");
485
+ return;
486
+ }
487
+ const state = controller.state();
488
+ const target = state.activeProfile === "reasoning" ? "standard" : "reasoning";
489
+ const result =
490
+ state.controlMode === "automatic" && state.activeProfile
491
+ ? await controller.switchAutomaticProfile(
492
+ target,
493
+ `Cycle automatic profile to ${target}.`,
494
+ "user",
495
+ "profile-shortcut",
496
+ )
497
+ : await controller.setAutomaticControl("profile-shortcut");
498
+ if (result.status === "automatic") {
499
+ ctx.ui?.notify?.("Cognitive Routing automatic control active.", "info");
500
+ } else if (result.status === "active") {
501
+ ctx.ui?.notify?.(`Cognitive Routing automatic profile set to ${result.profile}.`, "info");
502
+ } else {
503
+ ctx.ui?.notify?.(`Cognitive Routing could not cycle the automatic profile: ${result.reason}.`, "warning");
504
+ }
505
+ await applyLiveCapabilityStateForSession(ctx);
506
+ },
507
+ });
508
+ }
155
509
 
156
510
  pi.on("resources_discover", async (event, ctx) => {
157
511
  const cwd = ctx?.cwd ?? event?.cwd ?? process.cwd();
158
- const state = await readCapabilityState(cwd);
512
+ const snapshot =
513
+ providerSurfaceSnapshot?.context === ctx
514
+ ? providerSurfaceSnapshot.value
515
+ : await buildProviderSurface(ctx ?? { cwd }, false);
516
+ const state = snapshot.capabilityState;
159
517
  if (!state.configured) {
160
518
  return { skillPaths: [freeflowSkillPath("setup-freeflow")] };
161
519
  }
162
520
  if (!state.enabled || !state.skills.effective) {
163
521
  return { skillPaths: [] };
164
522
  }
165
- return { skillPaths: freeflowModelSkillPaths() };
523
+ return { skillPaths: freeflowModelSkillPaths(state) };
166
524
  });
167
525
 
168
526
  pi.on("session_start", async (_event, ctx) => {
527
+ latestCognitiveRoutingContext = ctx;
528
+ providerSurfaceSnapshot = undefined;
169
529
  restoreModeOverride(ctx);
170
- const [modeState, routerConfigResult, capabilityState] = await Promise.all([
171
- readModeState(ctx.cwd),
172
- readOutputRouterConfig(ctx.cwd),
173
- readCapabilityState(ctx.cwd),
174
- ]);
530
+ freeflowContextRuntime = new FreeflowContextRuntime(ctx);
531
+ contextVirtualizationRuntime = new ContextVirtualizationRuntime(pi, ctx, freeflowContextRuntime);
532
+ conversationHistoryRuntime = new ConversationHistoryRuntime(
533
+ ctx,
534
+ (entryId) => contextVirtualizationRuntime?.isSourceFullyProjected(entryId) ?? true,
535
+ freeflowContextRuntime,
536
+ );
537
+ await contextVirtualizationRuntime.recover(ctx);
538
+ const capabilityState = await readCapabilityState(ctx.cwd, ctx, pi?.host);
175
539
  await refreshRuntimeContext(capabilityState);
176
- setModeStatus(ctx, modeState, capabilityState);
177
- notifyRouterConfigWarnings(ctx, routerConfigResult);
178
- await applyCapabilityToolVisibility(pi, ctx, capabilityState);
540
+ const hasSessionState = sessionHasConversationOrRoutingState(ctx);
541
+ const snapshot = await buildProviderSurface(ctx, hasSessionState);
542
+ const cognitiveRoutingStartupPending =
543
+ snapshot.capabilityState?.cognitiveRouting?.effective === true &&
544
+ !hasSessionState &&
545
+ !startupSelectionSuppressesCognitiveRouting(ctx);
546
+ registerContextToolForState(snapshot.capabilityState);
547
+ setModeStatus(ctx, snapshot.modeState, snapshot.capabilityState, snapshot.cognitiveRoutingRuntime, {
548
+ cognitiveRoutingStartupPending,
549
+ });
550
+ await applyCapabilityToolVisibility(pi, ctx, snapshot.capabilityState, cognitiveRoutingController);
551
+ });
552
+
553
+ pi.on("agent_settled", async (_event, ctx) => {
554
+ if (!cognitiveRoutingController) return undefined;
555
+ await applyLiveCapabilityStateForSession(ctx);
556
+ return undefined;
557
+ });
558
+
559
+ pi.on("session_shutdown", async (event) => {
560
+ providerSurfaceSnapshot = undefined;
561
+ const controller = cognitiveRoutingController;
562
+ cognitiveRoutingController = undefined;
563
+ freeflowContextRuntime = undefined;
564
+ contextVirtualizationRuntime = undefined;
565
+ conversationHistoryRuntime = undefined;
566
+ if (controller) await controller.shutdown(event?.reason);
179
567
  });
180
568
 
181
569
  pi.on("session_tree", async (_event, ctx) => {
570
+ latestCognitiveRoutingContext = ctx;
571
+ providerSurfaceSnapshot = undefined;
182
572
  restoreModeOverride(ctx);
183
- await applyLiveCapabilityState(pi, ctx);
573
+ const controller = cognitiveRoutingController;
574
+ if (controller) await controller.reconcileBranch();
575
+ if (contextVirtualizationRuntime) {
576
+ contextVirtualizationRuntime.setContext(ctx);
577
+ await contextVirtualizationRuntime.recover(ctx);
578
+ }
579
+ conversationHistoryRuntime?.setContext(ctx);
580
+ await applyLiveCapabilityStateForSession(ctx);
184
581
  });
185
582
 
186
583
  pi.on("session_compact", async (_event, ctx) => {
187
- const [modeState, routerConfigResult, capabilityState] = await Promise.all([
584
+ latestCognitiveRoutingContext = ctx;
585
+ providerSurfaceSnapshot = undefined;
586
+ const controller = cognitiveRoutingController;
587
+ if (controller) await controller.reconcileBranch("session-compact");
588
+ if (contextVirtualizationRuntime) {
589
+ contextVirtualizationRuntime.setContext(ctx);
590
+ await contextVirtualizationRuntime.recover(ctx);
591
+ }
592
+ conversationHistoryRuntime?.setContext(ctx);
593
+ const [modeState, capabilityState] = await Promise.all([
188
594
  readModeState(ctx.cwd),
189
- readOutputRouterConfig(ctx.cwd),
190
- readCapabilityState(ctx.cwd),
595
+ readCapabilityState(ctx.cwd, ctx, pi?.host),
191
596
  ]);
192
597
  await refreshRuntimeContext(capabilityState);
193
- setModeStatus(ctx, modeState, capabilityState);
194
- notifyRouterConfigWarnings(ctx, routerConfigResult);
195
- await applyCapabilityToolVisibility(pi, ctx, capabilityState);
598
+ registerContextToolForState(capabilityState);
599
+ setModeStatus(ctx, modeState, capabilityState, cognitiveRoutingController?.state());
600
+ await applyCapabilityToolVisibility(pi, ctx, capabilityState, cognitiveRoutingController);
196
601
  });
197
602
 
198
603
  pi.on("before_agent_start", async (event, ctx) => {
199
- const [modeState, routerConfigResult, capabilityState] = await Promise.all([
200
- readModeState(ctx.cwd),
201
- readOutputRouterConfig(ctx.cwd),
202
- readCapabilityState(ctx.cwd),
203
- ]);
204
- const freeflowContext = await getRuntimeContext(capabilityState);
205
- setModeStatus(ctx, modeState, capabilityState);
206
- notifyRouterConfigWarnings(ctx, routerConfigResult);
207
- await applyCapabilityToolVisibility(pi, ctx, capabilityState);
208
- const freeflowRuntimeContext = runtimeContext(modeState, freeflowContext, routerConfigResult, capabilityState);
209
- const workflowMessage = workflowBootstrapMessage(freeflowContext, capabilityState, ctx.sessionManager);
604
+ latestCognitiveRoutingContext = ctx;
605
+ const snapshot = await buildProviderSurface(ctx, true);
606
+ providerSurfaceSnapshot = { context: ctx, value: snapshot };
607
+ registerContextToolForState(snapshot.capabilityState);
608
+ setModeStatus(ctx, snapshot.modeState, snapshot.capabilityState, snapshot.cognitiveRoutingRuntime);
609
+ await applyCapabilityToolVisibility(pi, ctx, snapshot.capabilityState, cognitiveRoutingController);
610
+ const freeflowRuntimeContext = runtimeContext(snapshot.freeflowContext, snapshot.capabilityState);
210
611
  const systemPrompt = freeflowRuntimeContext
211
612
  ? `${event.systemPrompt}\n\n${freeflowRuntimeContext}`
212
613
  : event.systemPrompt;
213
- return { message: workflowMessage, systemPrompt };
614
+ return { systemPrompt };
214
615
  });
215
616
 
216
617
  pi.on("context", async (event, ctx) => {
217
- const capabilityState = await readCapabilityState(ctx.cwd);
218
- if (capabilityState.skills.effective) {
219
- return undefined;
618
+ const snapshot =
619
+ providerSurfaceSnapshot?.context === ctx ? providerSurfaceSnapshot.value : await buildProviderSurface(ctx, false);
620
+ if (providerSurfaceSnapshot?.context === ctx) providerSurfaceSnapshot = undefined;
621
+ const cognitiveRoutingRuntime = snapshot.cognitiveRoutingRuntime;
622
+ const surfaceCapabilityState = snapshot.capabilityState;
623
+ const surfaceModeState = snapshot.modeState;
624
+ let changed = false;
625
+ let messages = event.messages
626
+ .map((message) => {
627
+ const filtered = filterBootstrapMessage(message);
628
+ if (filtered !== message) changed = true;
629
+ return filtered;
630
+ })
631
+ .filter((message) => message !== undefined);
632
+ if (contextVirtualizationRuntime) {
633
+ contextVirtualizationRuntime.setContext(ctx);
634
+ const projected = await contextVirtualizationRuntime.project(
635
+ messages,
636
+ surfaceCapabilityState.contextVirtualization?.effective === true,
637
+ );
638
+ if (projected.changed) {
639
+ changed = true;
640
+ messages = projected.messages;
641
+ }
220
642
  }
221
-
222
- const messages = event.messages.filter(
223
- (message) => !(message?.role === "custom" && message?.customType === WORKFLOW_BOOTSTRAP_MESSAGE_TYPE),
643
+ if (conversationHistoryRuntime && surfaceCapabilityState.conversationHistory?.effective === true) {
644
+ conversationHistoryRuntime.setContext(ctx);
645
+ conversationHistoryRuntime.capture(surfaceCapabilityState.contextVirtualization?.effective === true);
646
+ }
647
+ const nextMessages = withFreeflowRuntimeState(
648
+ messages,
649
+ surfaceModeState,
650
+ surfaceCapabilityState,
651
+ cognitiveRoutingRuntime,
224
652
  );
225
- return messages.length === event.messages.length ? undefined : { messages };
653
+ changed = true;
654
+ messages = nextMessages;
655
+ return changed ? { messages } : undefined;
226
656
  });
227
657
 
228
658
  pi.on("tool_call", async (event, ctx) => {
229
- const capabilityState = await readCapabilityState(ctx.cwd);
659
+ const capabilityState = await readCapabilityState(ctx.cwd, ctx, pi?.host);
230
660
  const toolName = typeof event?.toolName === "string" ? event.toolName : "";
231
- if ((!capabilityState.configured || !capabilityState.enabled) && toolName === FREEFLOW_STATUS_TOOL_NAME) {
232
- return disabledToolCall(toolName, "freeflow");
233
- }
234
- if (!capabilityState.outputRouter.enabled && isOutputRouterToolName(toolName)) {
235
- return disabledToolCall(toolName, "output-router");
661
+ if (
662
+ capabilityState.contextVirtualization?.effective !== true &&
663
+ capabilityState.conversationHistory?.effective !== true &&
664
+ toolName === CONTEXT_VIRTUALIZATION_TOOL_NAME
665
+ ) {
666
+ return disabledToolCall(toolName, "context");
236
667
  }
237
668
  return undefined;
238
669
  });
239
670
 
240
671
  pi.on("tool_result", async (event, ctx) => {
241
- const capabilityState = await readCapabilityState(ctx.cwd);
242
- if (!capabilityState.outputRouter.enabled) {
243
- return undefined;
244
- }
245
- const observed = await handleObservedToolRouting(event, ctx);
246
- if (observed) {
247
- return observed;
672
+ const toolName = typeof event?.toolName === "string" ? event.toolName : "";
673
+ if (isPiFlowHost(pi?.host) && toolName === COGNITIVE_ROUTING_SWITCH_TOOL_NAME) {
674
+ await applyLiveCapabilityStateForSession(ctx);
248
675
  }
249
- return handleNativeToolSafetyNet(event, ctx);
676
+ return undefined;
250
677
  });
251
678
 
252
679
  for (const { command, skill } of WORKFLOW_COMMANDS) {
@@ -270,26 +697,51 @@ export default function freeflow(pi) {
270
697
 
271
698
  pi.registerCommand("freeflow", {
272
699
  description: "Open unified Freeflow settings or print compact status",
273
- getArgumentCompletions: freeflowCompletions,
700
+ getArgumentCompletions: (prefix) => freeflowCompletions(prefix, pi?.host),
274
701
  handler: async (args, ctx) => {
702
+ const contextInput = (args ?? "").trim();
703
+ if (contextInput === "context" || contextInput.startsWith("context ")) {
704
+ const capabilityState = await readCapabilityState(ctx.cwd, ctx, pi?.host);
705
+ await handleContextCommand(
706
+ contextInput.slice("context".length).trim(),
707
+ ctx,
708
+ contextVirtualizationRuntime,
709
+ capabilityState.contextVirtualization?.effective === true,
710
+ capabilityState.conversationHistory?.effective === true,
711
+ );
712
+ return;
713
+ }
714
+ if (isPiFlowHost(pi?.host) && /^profile(?:\s|$)/i.test((args ?? "").trim())) {
715
+ const profileCommandContext = {
716
+ isIdle: ctx?.isIdle,
717
+ ui: ctx?.ui,
718
+ history: (options) =>
719
+ cognitiveRoutingController?.history(options) ?? readCognitiveRoutingHistory(ctx, options),
720
+ };
721
+ const historyCommand = /^profile\s+history(?:\s|$)/i.test((args ?? "").trim());
722
+ if (historyCommand) {
723
+ await handleCognitiveRoutingProfileCommand(args, profileCommandContext, cognitiveRoutingController);
724
+ return;
725
+ }
726
+ if (!cognitiveRoutingController) {
727
+ await applyLiveCapabilityStateForSession(ctx, { reconcileCognitiveRouting: true });
728
+ }
729
+ if (await handleCognitiveRoutingProfileCommand(args, profileCommandContext, cognitiveRoutingController)) {
730
+ await applyLiveCapabilityStateForSession(ctx);
731
+ return;
732
+ }
733
+ }
275
734
  await handleFreeflowCommand(
276
735
  args,
277
736
  ctx,
278
- async () => {
279
- await applyLiveCapabilityState(pi, ctx);
737
+ async (_changed, options = {}) => {
738
+ await applyLiveCapabilityStateForSession(ctx, {
739
+ reconcileCognitiveRouting: options.reconcileCognitiveRouting ?? true,
740
+ });
280
741
  },
281
742
  pi,
743
+ cognitiveRoutingController,
282
744
  );
283
745
  },
284
746
  });
285
-
286
- pi.registerCommand("output-router", {
287
- description: "Open Freeflow Output Router settings or print compact status",
288
- getArgumentCompletions: capabilityCompletions,
289
- handler: async (args, ctx) => {
290
- await handleOutputRouterCommand(args, ctx, async () => {
291
- await applyLiveCapabilityState(pi, ctx);
292
- });
293
- },
294
- });
295
747
  }