@hassangameryt/freeflow 0.6.0 → 0.7.1
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.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +3 -2
- package/.codex-plugin/plugin.json +5 -6
- package/.cursor-plugin/plugin.json +25 -0
- package/README.md +66 -56
- package/capabilities/cognitive-routing/SKILL.md +288 -130
- package/com.github.copilot/hooks/hooks.json +11 -0
- package/command-surface.json +0 -24
- package/gemini-extension.json +5 -0
- package/hooks/adapters/claude-session-start.mjs +16 -0
- package/hooks/adapters/codex-session-start.mjs +16 -0
- package/hooks/adapters/copilot-session-start.mjs +13 -0
- package/hooks/adapters/cursor-session-start.mjs +13 -0
- package/hooks/adapters/gemini-session-start.mjs +15 -0
- package/hooks/claude/hooks.json +18 -0
- package/hooks/codex/hooks.json +18 -0
- package/hooks/cursor/hooks.json +9 -0
- package/hooks/freeflow-runtime-context.mjs +3 -650
- package/hooks/hooks.json +4 -30
- package/hooks/shared/runtime-context.mjs +210 -0
- package/hooks/tests/check-host-adapters.test.mjs +82 -0
- package/hooks/tests/check-runtime-context-hook.sh +140 -320
- package/package.json +20 -4
- package/pi-extension/dist/cognitive-routing/commands.js +3 -3
- package/pi-extension/dist/cognitive-routing/config.js +16 -20
- package/pi-extension/dist/cognitive-routing/controller.js +478 -48
- package/pi-extension/dist/cognitive-routing/history.js +12 -0
- package/pi-extension/dist/cognitive-routing/host.js +74 -12
- package/pi-extension/dist/cognitive-routing/pi-routing-session.js +414 -0
- package/pi-extension/dist/cognitive-routing/pi-session-control.js +320 -0
- package/pi-extension/dist/cognitive-routing/tool.js +1 -0
- package/pi-extension/dist/cognitive-routing/types.js +1 -1
- package/pi-extension/dist/index.js +236 -219
- package/pi-extension/dist/runtime/runtime-context.js +126 -286
- package/pi-extension/dist/settings/settings-ui.js +52 -336
- package/pi-extension/src/cognitive-routing/commands.ts +15 -5
- package/pi-extension/src/cognitive-routing/config.ts +16 -20
- package/pi-extension/src/cognitive-routing/controller.ts +561 -51
- package/pi-extension/src/cognitive-routing/history.ts +12 -0
- package/pi-extension/src/cognitive-routing/host.ts +110 -16
- package/pi-extension/src/cognitive-routing/pi-routing-session.ts +538 -0
- package/pi-extension/src/cognitive-routing/pi-session-control.ts +444 -0
- package/pi-extension/src/cognitive-routing/tool.ts +1 -0
- package/pi-extension/src/cognitive-routing/types.ts +1 -1
- package/pi-extension/src/index.ts +249 -239
- package/pi-extension/src/runtime/runtime-context.ts +129 -305
- package/pi-extension/src/settings/settings-ui.ts +53 -371
- package/pi-extension/tests/cognitive-routing/commands.test.js +1 -1
- package/pi-extension/tests/cognitive-routing/controller.test.js +69 -40
- package/pi-extension/tests/cognitive-routing/extension-lifecycle.test.js +128 -57
- package/pi-extension/tests/cognitive-routing/pi-normal-lifecycle.test.js +434 -0
- package/pi-extension/tests/cognitive-routing/pi-session-control.test.js +174 -0
- package/pi-extension/tests/cognitive-routing/pi-session-history.test.js +91 -0
- package/pi-extension/tests/cognitive-routing/profile-resolution.test.js +47 -4
- package/pi-extension/tests/integration/mode-free-core.test.js +218 -0
- package/pi-extension/tests/integration/pi-extension.test.js +430 -2478
- package/pi-extension/tests/integration/prompt-architecture.test.js +124 -79
- package/pi-extension/tests/integration/unaffected-regressions.test.js +411 -0
- package/plugin.json +33 -0
- package/runtime/prompts/cognitive-routing.md +5 -4
- package/runtime/prompts/conversation-history.md +1 -1
- package/runtime/prompts/core.md +77 -6
- package/runtime/prompts/interaction-contract.md +6 -2
- package/skills/action-selection/SKILL.md +93 -44
- package/skills/action-selection/references/trajectory-stalls.md +71 -0
- package/skills/bypass/SKILL.md +109 -39
- package/skills/commit-work/SKILL.md +94 -55
- package/skills/commit-work/references/git-state-edges.md +94 -0
- package/skills/commit-work/references/simple-push.md +92 -0
- package/skills/commit-work/references/staging-decisions.md +79 -46
- package/skills/decision-gate/SKILL.md +80 -22
- package/skills/design-for-depth/SKILL.md +208 -43
- package/skills/design-for-depth/references/design-pressure-signals.md +108 -240
- package/skills/design-for-depth/references/interface-design-loop.md +77 -97
- package/skills/design-for-depth/references/module-and-dependency-design.md +147 -0
- package/skills/design-for-depth/references/software-design-philosophy.md +127 -173
- package/skills/design-for-depth/references/state-and-failure-boundaries.md +136 -0
- package/skills/diagnose-failure/SKILL.md +198 -52
- package/skills/diagnose-failure/references/diagnostic-loop-catalog.md +19 -5
- package/skills/diagnose-failure/references/flaky-and-performance-diagnosis.md +13 -5
- package/skills/discuss/SKILL.md +118 -76
- package/skills/discuss/references/discussion-continuity.md +84 -32
- package/skills/evaluate-skill/SKILL.md +166 -52
- package/skills/evaluate-skill/references/evaluation-definition-schema.md +2 -2
- package/skills/evaluate-skill/references/evaluation-design.md +56 -30
- package/skills/evaluate-skill/references/execution-and-evidence.md +1 -1
- package/skills/evaluate-skill/references/review-and-revision.md +62 -21
- package/skills/execute-work/SKILL.md +98 -59
- package/skills/execute-work/references/code-practices.md +4 -4
- package/skills/execute-work/references/execute-work-edges.md +42 -22
- package/skills/review-artifact/SKILL.md +132 -71
- package/skills/review-artifact/references/adjudicate-artifact-review.md +101 -0
- package/skills/review-artifact/references/independent-artifact-reviewer-contract.md +52 -41
- package/skills/review-work/SKILL.md +115 -72
- package/skills/review-work/references/adjudicate-work-review.md +97 -0
- package/skills/review-work/references/independent-work-reviewer-contract.md +40 -35
- package/skills/review-work/references/security-risk-lens.md +17 -15
- package/skills/setup-freeflow/SKILL.md +14 -17
- package/skills/setup-freeflow/references/activation-contract.md +24 -30
- package/skills/setup-freeflow/references/host-setup.md +6 -7
- package/skills/simplify-code/SKILL.md +97 -39
- package/skills/simplify-code/references/simplification-patterns.md +1 -1
- package/skills/tdd/SKILL.md +108 -41
- package/skills/tdd/references/test-design.md +1 -1
- package/skills/track-work/SKILL.md +133 -300
- package/skills/track-work/references/working-record-format.md +515 -0
- package/skills/track-work/scripts/lib/document.mjs +713 -0
- package/skills/track-work/scripts/lib/format.mjs +166 -0
- package/skills/track-work/scripts/lib/store.mjs +233 -0
- package/skills/track-work/scripts/lib/transitions.mjs +790 -0
- package/skills/track-work/scripts/lib/views.mjs +27 -430
- package/skills/track-work/scripts/working-record.mjs +292 -98
- package/skills/verify-work/SKILL.md +46 -20
- package/skills/verify-work/references/browser-runtime-evidence.md +1 -1
- package/skills/verify-work/references/integration-evidence.md +1 -7
- package/skills/verify-work/references/performance-evidence.md +1 -1
- package/skills/workflow/SKILL.md +110 -80
- package/skills/workflow/references/domain-skill-composition.md +24 -18
- package/skills/write-skill/SKILL.md +218 -62
- package/skills/write-skill/references/activation-boundaries.md +63 -21
- package/skills/write-skill/references/agent-first-instructions.md +61 -27
- package/skills/write-skill/references/progressive-disclosure.md +91 -41
- package/skills/write-skill/references/skill-dependency-graphs.md +190 -0
- package/runtime/prompts/skills.md +0 -65
- package/skills/mode-contract/SKILL.md +0 -104
- package/skills/track-work/scripts/lib/codec.mjs +0 -570
- package/skills/track-work/scripts/lib/commands.mjs +0 -568
- package/skills/track-work/scripts/lib/contract.mjs +0 -303
- package/skills/track-work/scripts/lib/model.mjs +0 -506
- package/skills/track-work/scripts/lib/operations.mjs +0 -965
- package/skills/track-work/scripts/lib/record-store.mjs +0 -264
- package/skills/track-work/scripts/lib/result.mjs +0 -37
- package/skills/track-work/scripts/lib/rewrites.mjs +0 -740
- package/skills/track-work/scripts/lib/schema.mjs +0 -277
- package/skills/track-work/scripts/lib/source-inventory.mjs +0 -162
- package/skills/track-work/scripts/lib/workspace.mjs +0 -134
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
import type { ExtensionAPI, ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
|
|
1
3
|
import {
|
|
2
4
|
COGNITIVE_ROUTING_CONTROL_ENTRY,
|
|
5
|
+
COGNITIVE_ROUTING_INACTIVE_ENTRY,
|
|
3
6
|
COGNITIVE_ROUTING_INTENT_ENTRY,
|
|
4
|
-
CognitiveRoutingController,
|
|
5
7
|
} from "./cognitive-routing/controller.js";
|
|
8
|
+
import { PiRoutingSession, type PiRoutingSessionSnapshot } from "./cognitive-routing/pi-routing-session.js";
|
|
6
9
|
import {
|
|
7
10
|
cognitiveRoutingProfileCompletions,
|
|
8
11
|
handleCognitiveRoutingProfileCommand,
|
|
@@ -23,21 +26,18 @@ import {
|
|
|
23
26
|
freeflowModelSkillPaths,
|
|
24
27
|
freeflowSkillPath,
|
|
25
28
|
getRuntimeContext,
|
|
29
|
+
hasUsableMandatoryPrompts,
|
|
30
|
+
isPromptAvailable,
|
|
26
31
|
readCapabilityState,
|
|
27
|
-
readModeState,
|
|
28
32
|
refreshRuntimeContext,
|
|
29
|
-
|
|
33
|
+
restoreSessionOverrides,
|
|
30
34
|
runtimeContext,
|
|
31
35
|
filterBootstrapMessage,
|
|
32
|
-
|
|
36
|
+
setFreeflowStatus,
|
|
33
37
|
skillPrompt,
|
|
34
38
|
withFreeflowRuntimeState,
|
|
35
39
|
} from "./runtime/runtime-context.js";
|
|
36
40
|
|
|
37
|
-
function startupSelectionSuppressesCognitiveRouting(ctx: any): boolean {
|
|
38
|
-
return ctx?.modelStateProvenance?.explicitModel === true || ctx?.modelStateProvenance?.explicitThinking === true;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
41
|
function unavailableCapability(capability: any, code: string, message: string): any {
|
|
42
42
|
return {
|
|
43
43
|
...capability,
|
|
@@ -48,15 +48,12 @@ function unavailableCapability(capability: any, code: string, message: string):
|
|
|
48
48
|
|
|
49
49
|
function modelFacingCapabilityState(
|
|
50
50
|
capabilityState: any,
|
|
51
|
-
ctx: any,
|
|
52
51
|
freeflowContext: any,
|
|
53
|
-
|
|
52
|
+
routingSnapshot: PiRoutingSessionSnapshot,
|
|
54
53
|
cognitiveRoutingActivationFailed = false,
|
|
55
54
|
): any {
|
|
56
55
|
const surfaceState = {
|
|
57
56
|
...capabilityState,
|
|
58
|
-
interactionContract: { ...capabilityState?.interactionContract },
|
|
59
|
-
skills: { ...capabilityState?.skills },
|
|
60
57
|
contextVirtualization: { ...capabilityState?.contextVirtualization },
|
|
61
58
|
conversationHistory: { ...capabilityState?.conversationHistory },
|
|
62
59
|
cognitiveRouting: { ...capabilityState?.cognitiveRouting },
|
|
@@ -69,53 +66,59 @@ function modelFacingCapabilityState(
|
|
|
69
66
|
}
|
|
70
67
|
};
|
|
71
68
|
|
|
72
|
-
if (!freeflowContext
|
|
73
|
-
for (const key of [
|
|
74
|
-
"
|
|
75
|
-
"skills",
|
|
76
|
-
"contextVirtualization",
|
|
77
|
-
"conversationHistory",
|
|
78
|
-
"cognitiveRouting",
|
|
79
|
-
]) {
|
|
80
|
-
markUnavailable(key, "Freeflow core prompt is unavailable.");
|
|
69
|
+
if (!hasUsableMandatoryPrompts(freeflowContext)) {
|
|
70
|
+
for (const key of ["contextVirtualization", "conversationHistory", "cognitiveRouting"]) {
|
|
71
|
+
markUnavailable(key, "Mandatory Freeflow prompt is unavailable.");
|
|
81
72
|
}
|
|
82
73
|
return surfaceState;
|
|
83
74
|
}
|
|
84
75
|
|
|
85
|
-
if (
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
markUnavailable("
|
|
76
|
+
if (
|
|
77
|
+
surfaceState.contextVirtualization?.effective === true &&
|
|
78
|
+
!isPromptAvailable(freeflowContext.contextVirtualizationPrompt)
|
|
79
|
+
) {
|
|
80
|
+
markUnavailable("contextVirtualization", "Context Virtualization prompt is unavailable.");
|
|
90
81
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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
|
-
}
|
|
82
|
+
if (
|
|
83
|
+
surfaceState.conversationHistory?.effective === true &&
|
|
84
|
+
!isPromptAvailable(freeflowContext.conversationHistoryPrompt)
|
|
85
|
+
) {
|
|
86
|
+
markUnavailable("conversationHistory", "Conversation History prompt is unavailable.");
|
|
103
87
|
}
|
|
104
88
|
|
|
105
89
|
if (surfaceState.cognitiveRouting?.effective === true) {
|
|
106
|
-
|
|
90
|
+
const controllerState = routingSnapshot.runtimeState;
|
|
91
|
+
if (routingSnapshot.disposition === "blocked") {
|
|
92
|
+
surfaceState.cognitiveRouting = unavailableCapability(
|
|
93
|
+
surfaceState.cognitiveRouting,
|
|
94
|
+
"runtime_blocked",
|
|
95
|
+
routingSnapshot.reason ?? "Cognitive Routing is blocked because its inactive state could not be persisted.",
|
|
96
|
+
);
|
|
97
|
+
} else if (routingSnapshot.startupSelectionSuppressed || routingSnapshot.disposition === "inactive") {
|
|
98
|
+
surfaceState.cognitiveRouting = unavailableCapability(
|
|
99
|
+
surfaceState.cognitiveRouting,
|
|
100
|
+
"runtime_inactive",
|
|
101
|
+
"Cognitive Routing is inactive because Pi owns the startup model or thinking level.",
|
|
102
|
+
);
|
|
103
|
+
} else if (controllerState?.runtimeStatus === "inactive") {
|
|
107
104
|
surfaceState.cognitiveRouting = unavailableCapability(
|
|
108
105
|
surfaceState.cognitiveRouting,
|
|
109
106
|
"runtime_inactive",
|
|
110
|
-
"Cognitive Routing is inactive because
|
|
107
|
+
controllerState.runtimeReason ?? "Cognitive Routing is inactive because Pi owns the current model state.",
|
|
108
|
+
);
|
|
109
|
+
} else if (controllerState?.runtimeStatus === "blocked") {
|
|
110
|
+
surfaceState.cognitiveRouting = unavailableCapability(
|
|
111
|
+
surfaceState.cognitiveRouting,
|
|
112
|
+
"runtime_blocked",
|
|
113
|
+
controllerState.runtimeReason ?? "Cognitive Routing is blocked because its state is not proven.",
|
|
111
114
|
);
|
|
112
|
-
} else if (cognitiveRoutingActivationFailed ||
|
|
115
|
+
} else if (cognitiveRoutingActivationFailed || controllerState?.effective === false) {
|
|
113
116
|
surfaceState.cognitiveRouting = unavailableCapability(
|
|
114
117
|
surfaceState.cognitiveRouting,
|
|
115
118
|
"unavailable",
|
|
116
119
|
"Cognitive Routing could not activate for this session.",
|
|
117
120
|
);
|
|
118
|
-
} else if (!freeflowContext.cognitiveRoutingPrompt) {
|
|
121
|
+
} else if (!isPromptAvailable(freeflowContext.cognitiveRoutingPrompt)) {
|
|
119
122
|
markUnavailable("cognitiveRouting", "Cognitive Routing prompt is unavailable.");
|
|
120
123
|
}
|
|
121
124
|
}
|
|
@@ -123,11 +126,6 @@ function modelFacingCapabilityState(
|
|
|
123
126
|
return surfaceState;
|
|
124
127
|
}
|
|
125
128
|
|
|
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
129
|
type SessionEntriesContext = {
|
|
132
130
|
sessionManager?: {
|
|
133
131
|
getBranch?: () => readonly unknown[];
|
|
@@ -150,7 +148,9 @@ function sessionHasConversationOrRoutingState(ctx: SessionEntriesContext | undef
|
|
|
150
148
|
}
|
|
151
149
|
return (
|
|
152
150
|
record.type === "custom" &&
|
|
153
|
-
(record.customType === COGNITIVE_ROUTING_INTENT_ENTRY ||
|
|
151
|
+
(record.customType === COGNITIVE_ROUTING_INTENT_ENTRY ||
|
|
152
|
+
record.customType === COGNITIVE_ROUTING_CONTROL_ENTRY ||
|
|
153
|
+
record.customType === COGNITIVE_ROUTING_INACTIVE_ENTRY)
|
|
154
154
|
);
|
|
155
155
|
});
|
|
156
156
|
} catch {
|
|
@@ -158,51 +158,17 @@ function sessionHasConversationOrRoutingState(ctx: SessionEntriesContext | undef
|
|
|
158
158
|
}
|
|
159
159
|
}
|
|
160
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
161
|
async function applyCapabilityToolVisibility(
|
|
198
162
|
pi: any,
|
|
199
163
|
ctx: any,
|
|
200
164
|
capabilityState = undefined,
|
|
201
|
-
|
|
165
|
+
routingSnapshot: PiRoutingSessionSnapshot = {
|
|
166
|
+
status: "available",
|
|
167
|
+
disposition: "available",
|
|
168
|
+
startupSelectionSuppressed: false,
|
|
169
|
+
},
|
|
202
170
|
): Promise<void> {
|
|
203
|
-
if (typeof pi?.setActiveTools !== "function" || typeof pi?.getAllTools !== "function")
|
|
204
|
-
return;
|
|
205
|
-
}
|
|
171
|
+
if (typeof pi?.setActiveTools !== "function" || typeof pi?.getAllTools !== "function") return;
|
|
206
172
|
|
|
207
173
|
const state = capabilityState ?? (await readCapabilityState(ctx.cwd, ctx, pi?.host));
|
|
208
174
|
const allToolNames = pi
|
|
@@ -216,12 +182,11 @@ async function applyCapabilityToolVisibility(
|
|
|
216
182
|
);
|
|
217
183
|
|
|
218
184
|
if (allToolNameSet.has(COGNITIVE_ROUTING_SWITCH_TOOL_NAME)) {
|
|
219
|
-
const controllerState =
|
|
185
|
+
const controllerState = routingSnapshot.runtimeState;
|
|
220
186
|
const routingToolActive =
|
|
221
187
|
state.cognitiveRouting?.effective === true &&
|
|
222
188
|
controllerState?.effective === true &&
|
|
223
|
-
controllerState.controlMode === "automatic"
|
|
224
|
-
!startupSelectionSuppressesCognitiveRouting(ctx);
|
|
189
|
+
controllerState.controlMode === "automatic";
|
|
225
190
|
if (routingToolActive) active.add(COGNITIVE_ROUTING_SWITCH_TOOL_NAME);
|
|
226
191
|
else active.delete(COGNITIVE_ROUTING_SWITCH_TOOL_NAME);
|
|
227
192
|
}
|
|
@@ -237,29 +202,6 @@ async function applyCapabilityToolVisibility(
|
|
|
237
202
|
pi.setActiveTools([...active]);
|
|
238
203
|
}
|
|
239
204
|
|
|
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
|
-
]);
|
|
250
|
-
await refreshRuntimeContext(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;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
205
|
function disabledToolCall(toolName: string, capability: string) {
|
|
264
206
|
const command = capability === "freeflow" ? "/freeflow settings" : `/${capability} settings`;
|
|
265
207
|
return {
|
|
@@ -268,7 +210,7 @@ function disabledToolCall(toolName: string, capability: string) {
|
|
|
268
210
|
};
|
|
269
211
|
}
|
|
270
212
|
|
|
271
|
-
function freeflowCompletions(prefix: string | undefined,
|
|
213
|
+
function freeflowCompletions(prefix: string | undefined, cognitiveRoutingAvailable = false) {
|
|
272
214
|
const query = prefix ?? "";
|
|
273
215
|
if (query.startsWith("settings ")) {
|
|
274
216
|
const settingsQuery = query.slice("settings ".length);
|
|
@@ -280,27 +222,12 @@ function freeflowCompletions(prefix: string | undefined, hostInfo = undefined) {
|
|
|
280
222
|
.filter((item) => item.value.startsWith(settingsQuery))
|
|
281
223
|
.map((item) => ({ ...item, value: `settings ${item.value}` }));
|
|
282
224
|
}
|
|
283
|
-
if (
|
|
225
|
+
if (cognitiveRoutingAvailable && query.startsWith("profile ")) {
|
|
284
226
|
return cognitiveRoutingProfileCompletions(query.slice("profile ".length)).map((item) => ({
|
|
285
227
|
...item,
|
|
286
228
|
value: `profile ${item.value}`,
|
|
287
229
|
}));
|
|
288
230
|
}
|
|
289
|
-
if (query.startsWith("mode ")) {
|
|
290
|
-
const modeQuery = query.slice("mode ".length);
|
|
291
|
-
return [
|
|
292
|
-
{ value: "conversation", label: "conversation", description: "Read-only discussion and inspection" },
|
|
293
|
-
{ value: "workflow", label: "workflow", description: "Adaptive workflow for consequential work" },
|
|
294
|
-
{ value: "strict-workflow", label: "strict-workflow", description: "Stronger pressure at high-risk boundaries" },
|
|
295
|
-
{
|
|
296
|
-
value: "reset",
|
|
297
|
-
label: "reset",
|
|
298
|
-
description: "Clear the session override and use the configured default",
|
|
299
|
-
},
|
|
300
|
-
]
|
|
301
|
-
.filter((item) => item.value.startsWith(modeQuery))
|
|
302
|
-
.map((item) => ({ ...item, value: `mode ${item.value}` }));
|
|
303
|
-
}
|
|
304
231
|
if (query.startsWith("context ")) {
|
|
305
232
|
const contextQuery = query.slice("context ".length);
|
|
306
233
|
return [
|
|
@@ -316,8 +243,7 @@ function freeflowCompletions(prefix: string | undefined, hostInfo = undefined) {
|
|
|
316
243
|
{ value: "settings", label: "settings", description: "Open personal override settings" },
|
|
317
244
|
{ value: "status", label: "status", description: "Show effective Freeflow state" },
|
|
318
245
|
{ value: "context", label: "context", description: "Inspect Freeflow Context" },
|
|
319
|
-
|
|
320
|
-
...(isPiFlowHost(hostInfo)
|
|
246
|
+
...(cognitiveRoutingAvailable
|
|
321
247
|
? [{ value: "profile", label: "profile", description: "Hold or release Cognitive Routing profile control" }]
|
|
322
248
|
: []),
|
|
323
249
|
{ value: "enable", label: "enable", description: "Enable Freeflow for this repository" },
|
|
@@ -333,10 +259,17 @@ function bypassCompletions(prefix: string | undefined) {
|
|
|
333
259
|
].filter((item) => item.value.startsWith(query));
|
|
334
260
|
}
|
|
335
261
|
|
|
336
|
-
|
|
262
|
+
type FreeflowExtensionAPI = ExtensionAPI & { host?: unknown };
|
|
263
|
+
|
|
264
|
+
async function sendSkillCommand(
|
|
265
|
+
pi: FreeflowExtensionAPI,
|
|
266
|
+
ctx: ExtensionCommandContext,
|
|
267
|
+
skill: string,
|
|
268
|
+
args: string | undefined,
|
|
269
|
+
) {
|
|
337
270
|
const state = await readCapabilityState(ctx.cwd, ctx, pi?.host);
|
|
338
271
|
if (skill === "setup-freeflow" && !state.configured) {
|
|
339
|
-
await pi.sendUserMessage(skillPrompt(skill, args));
|
|
272
|
+
await pi.sendUserMessage(skillPrompt(skill, args), { expandPromptTemplates: true });
|
|
340
273
|
return;
|
|
341
274
|
}
|
|
342
275
|
if (!state.configured) {
|
|
@@ -350,23 +283,27 @@ async function sendSkillCommand(pi: any, ctx: any, skill: string, args: string |
|
|
|
350
283
|
);
|
|
351
284
|
return;
|
|
352
285
|
}
|
|
353
|
-
|
|
354
|
-
|
|
286
|
+
const freeflowContext = await getRuntimeContext(state);
|
|
287
|
+
if (!hasUsableMandatoryPrompts(freeflowContext)) {
|
|
288
|
+
ctx.ui.notify("Freeflow core prompts are unavailable; the requested skill cannot be dispatched.", "warning");
|
|
355
289
|
return;
|
|
356
290
|
}
|
|
357
|
-
await pi.sendUserMessage(skillPrompt(skill, args));
|
|
291
|
+
await pi.sendUserMessage(skillPrompt(skill, args), { expandPromptTemplates: true });
|
|
358
292
|
}
|
|
359
293
|
|
|
360
|
-
export default function freeflow(pi) {
|
|
361
|
-
|
|
294
|
+
export default function freeflow(pi: FreeflowExtensionAPI) {
|
|
295
|
+
// SAFETY: These helpers register complete Pi tool definitions but retain legacy structural typing for PiFlow compatibility.
|
|
296
|
+
const toolRegistrar = pi as unknown as { registerTool(tool: Record<string, unknown>): void };
|
|
297
|
+
const routingSession = new PiRoutingSession({ pi, stockPi: !isPiFlowHost(pi?.host) });
|
|
362
298
|
let latestCognitiveRoutingContext: any;
|
|
363
299
|
let providerSurfaceSnapshot: { context: any; value: any } | undefined;
|
|
300
|
+
let runtimeStateRefreshRequired = true;
|
|
364
301
|
let freeflowContextRuntime: FreeflowContextRuntime | undefined;
|
|
365
302
|
let contextVirtualizationRuntime: ContextVirtualizationRuntime | undefined;
|
|
366
303
|
let conversationHistoryRuntime: ConversationHistoryRuntime | undefined;
|
|
367
304
|
const registerContextToolForState = (capabilityState: any) => {
|
|
368
305
|
registerFreeflowContextTool(
|
|
369
|
-
|
|
306
|
+
toolRegistrar,
|
|
370
307
|
() => contextVirtualizationRuntime,
|
|
371
308
|
() => conversationHistoryRuntime,
|
|
372
309
|
{
|
|
@@ -376,73 +313,86 @@ export default function freeflow(pi) {
|
|
|
376
313
|
);
|
|
377
314
|
};
|
|
378
315
|
const buildProviderSurface = async (ctx: any, activateCognitiveRouting = false): Promise<any> => {
|
|
379
|
-
const
|
|
380
|
-
readModeState(ctx.cwd),
|
|
381
|
-
readCapabilityState(ctx.cwd, ctx, pi?.host),
|
|
382
|
-
]);
|
|
316
|
+
const capabilityState = await readCapabilityState(ctx.cwd, ctx, pi?.host);
|
|
383
317
|
const freeflowContext = await getRuntimeContext(capabilityState);
|
|
384
318
|
const promptCapabilityState = modelFacingCapabilityState(
|
|
385
319
|
capabilityState,
|
|
386
|
-
ctx,
|
|
387
320
|
freeflowContext,
|
|
388
|
-
|
|
321
|
+
routingSession.snapshot(),
|
|
389
322
|
);
|
|
390
323
|
let activationAttempted = false;
|
|
391
324
|
if (
|
|
392
325
|
activateCognitiveRouting &&
|
|
393
|
-
(
|
|
326
|
+
routingSession.canAutoActivate() &&
|
|
327
|
+
(!routingSession.hasController() || promptCapabilityState.cognitiveRouting?.effective !== true)
|
|
394
328
|
) {
|
|
395
|
-
activationAttempted =
|
|
396
|
-
promptCapabilityState.cognitiveRouting?.effective === true && !startupSelectionSuppressesCognitiveRouting(ctx);
|
|
329
|
+
activationAttempted = promptCapabilityState.cognitiveRouting?.effective === true;
|
|
397
330
|
try {
|
|
398
|
-
|
|
399
|
-
pi,
|
|
331
|
+
await routingSession.reconcileController(
|
|
400
332
|
ctx,
|
|
401
333
|
promptCapabilityState,
|
|
402
|
-
|
|
334
|
+
routingSession.armed ? { ...routingSession.armed } : undefined,
|
|
403
335
|
);
|
|
336
|
+
if (routingSession.hasController()) {
|
|
337
|
+
routingSession.clearArmed();
|
|
338
|
+
if (routingSession.snapshot().status === "active") routingSession.markActive();
|
|
339
|
+
}
|
|
404
340
|
} catch {
|
|
405
|
-
|
|
341
|
+
routingSession.clearController();
|
|
406
342
|
}
|
|
407
343
|
}
|
|
408
344
|
const surfaceCapabilityState = modelFacingCapabilityState(
|
|
409
345
|
promptCapabilityState,
|
|
410
|
-
ctx,
|
|
411
346
|
freeflowContext,
|
|
412
|
-
|
|
413
|
-
activationAttempted && !
|
|
347
|
+
routingSession.snapshot(),
|
|
348
|
+
activationAttempted && !routingSession.hasController(),
|
|
414
349
|
);
|
|
350
|
+
const routingSnapshot = routingSession.snapshot();
|
|
415
351
|
return {
|
|
416
|
-
modeState: modelFacingModeState(modeState, surfaceCapabilityState),
|
|
417
352
|
capabilityState: surfaceCapabilityState,
|
|
418
353
|
freeflowContext,
|
|
419
|
-
cognitiveRoutingRuntime:
|
|
354
|
+
cognitiveRoutingRuntime: routingSnapshot.runtimeState,
|
|
420
355
|
configuredCapabilityState: capabilityState,
|
|
421
356
|
};
|
|
422
357
|
};
|
|
423
358
|
const applyLiveCapabilityStateForSession = async (
|
|
424
359
|
ctx: any,
|
|
425
|
-
options: { reconcileCognitiveRouting?: boolean } = {},
|
|
360
|
+
options: { reconcileCognitiveRouting?: boolean; materializeCognitiveRouting?: boolean } = {},
|
|
426
361
|
): Promise<void> => {
|
|
427
|
-
|
|
428
|
-
|
|
362
|
+
providerSurfaceSnapshot = undefined;
|
|
363
|
+
await routingSession.applyLiveCapabilityState(ctx, options);
|
|
364
|
+
const capabilityState = await readCapabilityState(ctx.cwd, ctx, pi?.host);
|
|
365
|
+
const freeflowContext = await getRuntimeContext(capabilityState);
|
|
366
|
+
const surfaceCapabilityState = modelFacingCapabilityState(
|
|
367
|
+
capabilityState,
|
|
368
|
+
freeflowContext,
|
|
369
|
+
routingSession.snapshot(),
|
|
370
|
+
);
|
|
371
|
+
const routingSnapshot = routingSession.snapshot();
|
|
372
|
+
setFreeflowStatus(ctx, surfaceCapabilityState, routingSnapshot.runtimeState, freeflowContext, {
|
|
373
|
+
startupSelectionSuppressed: routingSnapshot.startupSelectionSuppressed,
|
|
374
|
+
});
|
|
375
|
+
await applyCapabilityToolVisibility(pi, ctx, surfaceCapabilityState, routingSnapshot);
|
|
376
|
+
registerContextToolForState(surfaceCapabilityState);
|
|
429
377
|
};
|
|
430
378
|
|
|
431
|
-
if (
|
|
432
|
-
registerCognitiveRoutingTool(
|
|
433
|
-
registerCognitiveRoutingHistoryTool(
|
|
434
|
-
|
|
435
|
-
|
|
379
|
+
if (routingSession.supportsCognitiveRoutingRuntime()) {
|
|
380
|
+
registerCognitiveRoutingTool(toolRegistrar, () => routingSession.controllerForTool());
|
|
381
|
+
registerCognitiveRoutingHistoryTool(toolRegistrar, (options, context) => {
|
|
382
|
+
return (
|
|
383
|
+
routingSession.history(options) ??
|
|
384
|
+
readCognitiveRoutingHistory(context ?? latestCognitiveRoutingContext, options)
|
|
385
|
+
);
|
|
436
386
|
});
|
|
437
387
|
}
|
|
438
388
|
registerFreeflowContextTool(
|
|
439
|
-
|
|
389
|
+
toolRegistrar,
|
|
440
390
|
() => contextVirtualizationRuntime,
|
|
441
391
|
() => conversationHistoryRuntime,
|
|
442
392
|
{ contextVirtualization: false, conversationHistory: false },
|
|
443
393
|
);
|
|
444
394
|
|
|
445
|
-
if (
|
|
395
|
+
if (routingSession.supportsCognitiveRoutingRuntime() && typeof pi.registerShortcut === "function") {
|
|
446
396
|
pi.registerShortcut("ctrl+shift+r", {
|
|
447
397
|
description: "Cycle the Cognitive Routing manual standard/reasoning hold",
|
|
448
398
|
handler: async (ctx) => {
|
|
@@ -450,17 +400,27 @@ export default function freeflow(pi) {
|
|
|
450
400
|
ctx.ui?.notify?.("Freeflow settings and profile changes are available only while Pi is idle.", "warning");
|
|
451
401
|
return;
|
|
452
402
|
}
|
|
453
|
-
|
|
403
|
+
const armedCycle = routingSession.hasController() ? undefined : routingSession.cycleArmedManual();
|
|
404
|
+
if (armedCycle) {
|
|
405
|
+
routingSession.beginExplicitReactivation();
|
|
406
|
+
ctx.ui?.notify?.(`Cognitive Routing manual hold set to ${armedCycle.target}.`, "info");
|
|
407
|
+
await applyLiveCapabilityStateForSession(ctx, {
|
|
408
|
+
reconcileCognitiveRouting: true,
|
|
409
|
+
materializeCognitiveRouting: !isPiFlowHost(pi?.host),
|
|
410
|
+
});
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
if (!routingSession.hasController()) {
|
|
414
|
+
routingSession.beginExplicitReactivation();
|
|
454
415
|
await applyLiveCapabilityStateForSession(ctx, { reconcileCognitiveRouting: true });
|
|
455
416
|
}
|
|
456
|
-
const
|
|
457
|
-
if (!
|
|
417
|
+
const state = routingSession.snapshot().runtimeState;
|
|
418
|
+
if (!state) {
|
|
458
419
|
ctx.ui?.notify?.("Cognitive Routing is unavailable for this session.", "warning");
|
|
459
420
|
return;
|
|
460
421
|
}
|
|
461
|
-
const
|
|
462
|
-
const
|
|
463
|
-
const result = await controller.setManualProfile(target, "profile-shortcut");
|
|
422
|
+
const target = state.activeProfile === "reasoning" ? "standard" : "reasoning";
|
|
423
|
+
const result = await routingSession.setManualProfile(target, "profile-shortcut");
|
|
464
424
|
if (result.status === "active") {
|
|
465
425
|
ctx.ui?.notify?.(`Cognitive Routing manual hold set to ${target}.`, "info");
|
|
466
426
|
} else {
|
|
@@ -470,43 +430,74 @@ export default function freeflow(pi) {
|
|
|
470
430
|
},
|
|
471
431
|
});
|
|
472
432
|
pi.registerShortcut("ctrl+shift+a", {
|
|
473
|
-
description: "
|
|
433
|
+
description: "Set Cognitive Routing to automatic Reasoning control",
|
|
474
434
|
handler: async (ctx) => {
|
|
475
435
|
if (typeof ctx?.isIdle === "function" && !ctx.isIdle()) {
|
|
476
436
|
ctx.ui?.notify?.("Freeflow settings and profile changes are available only while Pi is idle.", "warning");
|
|
477
437
|
return;
|
|
478
438
|
}
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
439
|
+
const armedCycle = routingSession.hasController() ? undefined : routingSession.cycleArmedAutomatic();
|
|
440
|
+
if (armedCycle) {
|
|
441
|
+
if (!armedCycle.changed) {
|
|
442
|
+
ctx.ui?.notify?.("Cognitive Routing automatic control active.", "info");
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
ctx.ui?.notify?.("Cognitive Routing automatic control active.", "info");
|
|
446
|
+
routingSession.beginExplicitReactivation();
|
|
447
|
+
await applyLiveCapabilityStateForSession(ctx, {
|
|
448
|
+
reconcileCognitiveRouting: true,
|
|
449
|
+
materializeCognitiveRouting: !isPiFlowHost(pi?.host),
|
|
450
|
+
});
|
|
485
451
|
return;
|
|
486
452
|
}
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
target,
|
|
493
|
-
`Cycle automatic profile to ${target}.`,
|
|
494
|
-
"user",
|
|
495
|
-
"profile-shortcut",
|
|
496
|
-
)
|
|
497
|
-
: await controller.setAutomaticControl("profile-shortcut");
|
|
453
|
+
if (!routingSession.hasController()) {
|
|
454
|
+
routingSession.beginExplicitReactivation();
|
|
455
|
+
await applyLiveCapabilityStateForSession(ctx, { reconcileCognitiveRouting: true });
|
|
456
|
+
}
|
|
457
|
+
const result = await routingSession.setAutomaticControl("profile-shortcut");
|
|
498
458
|
if (result.status === "automatic") {
|
|
499
459
|
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
460
|
} else {
|
|
503
|
-
ctx.ui?.notify?.(`Cognitive Routing could not
|
|
461
|
+
ctx.ui?.notify?.(`Cognitive Routing could not change control: ${result.reason}.`, "warning");
|
|
504
462
|
}
|
|
505
463
|
await applyLiveCapabilityStateForSession(ctx);
|
|
506
464
|
},
|
|
507
465
|
});
|
|
508
466
|
}
|
|
509
467
|
|
|
468
|
+
if (!isPiFlowHost(pi?.host) && routingSession.supportsCognitiveRoutingRuntime()) {
|
|
469
|
+
pi.on("model_select", async (event, ctx) => {
|
|
470
|
+
if (!routingSession.hasController()) {
|
|
471
|
+
if (!routingSession.armed) return;
|
|
472
|
+
routingSession.clearArmed();
|
|
473
|
+
routingSession.observeArmedNativeChange(ctx, "Pi model selection");
|
|
474
|
+
await applyLiveCapabilityStateForSession(ctx);
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
const result = await routingSession.observeNativeChange("Pi model selection", event?.source);
|
|
478
|
+
if (result.status !== "ignored") {
|
|
479
|
+
latestCognitiveRoutingContext = ctx;
|
|
480
|
+
providerSurfaceSnapshot = undefined;
|
|
481
|
+
await applyLiveCapabilityStateForSession(ctx);
|
|
482
|
+
}
|
|
483
|
+
});
|
|
484
|
+
pi.on("thinking_level_select", async (_event, ctx) => {
|
|
485
|
+
if (!routingSession.hasController()) {
|
|
486
|
+
if (!routingSession.armed) return;
|
|
487
|
+
routingSession.clearArmed();
|
|
488
|
+
routingSession.observeArmedNativeChange(ctx, "Pi thinking-level selection");
|
|
489
|
+
await applyLiveCapabilityStateForSession(ctx);
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
const result = await routingSession.observeNativeChange("Pi thinking-level selection");
|
|
493
|
+
if (result.status !== "ignored") {
|
|
494
|
+
latestCognitiveRoutingContext = ctx;
|
|
495
|
+
providerSurfaceSnapshot = undefined;
|
|
496
|
+
await applyLiveCapabilityStateForSession(ctx);
|
|
497
|
+
}
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
|
|
510
501
|
pi.on("resources_discover", async (event, ctx) => {
|
|
511
502
|
const cwd = ctx?.cwd ?? event?.cwd ?? process.cwd();
|
|
512
503
|
const snapshot =
|
|
@@ -517,16 +508,18 @@ export default function freeflow(pi) {
|
|
|
517
508
|
if (!state.configured) {
|
|
518
509
|
return { skillPaths: [freeflowSkillPath("setup-freeflow")] };
|
|
519
510
|
}
|
|
520
|
-
if (!state.enabled || !
|
|
511
|
+
if (!state.enabled || !hasUsableMandatoryPrompts(snapshot.freeflowContext)) {
|
|
521
512
|
return { skillPaths: [] };
|
|
522
513
|
}
|
|
523
514
|
return { skillPaths: freeflowModelSkillPaths(state) };
|
|
524
515
|
});
|
|
525
516
|
|
|
526
|
-
pi.on("session_start", async (
|
|
517
|
+
pi.on("session_start", async (event, ctx) => {
|
|
518
|
+
routingSession.resetForSession(ctx, event);
|
|
527
519
|
latestCognitiveRoutingContext = ctx;
|
|
528
520
|
providerSurfaceSnapshot = undefined;
|
|
529
|
-
|
|
521
|
+
runtimeStateRefreshRequired = true;
|
|
522
|
+
restoreSessionOverrides(ctx);
|
|
530
523
|
freeflowContextRuntime = new FreeflowContextRuntime(ctx);
|
|
531
524
|
contextVirtualizationRuntime = new ContextVirtualizationRuntime(pi, ctx, freeflowContextRuntime);
|
|
532
525
|
conversationHistoryRuntime = new ConversationHistoryRuntime(
|
|
@@ -537,41 +530,51 @@ export default function freeflow(pi) {
|
|
|
537
530
|
await contextVirtualizationRuntime.recover(ctx);
|
|
538
531
|
const capabilityState = await readCapabilityState(ctx.cwd, ctx, pi?.host);
|
|
539
532
|
await refreshRuntimeContext(capabilityState);
|
|
533
|
+
routingSession.ensureStartupInactive(ctx, capabilityState.cognitiveRouting?.effective === true);
|
|
534
|
+
routingSession.reconcileNativeEntries(ctx);
|
|
540
535
|
const hasSessionState = sessionHasConversationOrRoutingState(ctx);
|
|
541
536
|
const snapshot = await buildProviderSurface(ctx, hasSessionState);
|
|
542
|
-
|
|
543
|
-
snapshot.capabilityState?.cognitiveRouting?.effective === true &&
|
|
537
|
+
if (
|
|
544
538
|
!hasSessionState &&
|
|
545
|
-
|
|
539
|
+
snapshot.capabilityState?.cognitiveRouting?.effective === true &&
|
|
540
|
+
routingSession.canAutoActivate()
|
|
541
|
+
) {
|
|
542
|
+
routingSession.armFromCapability(snapshot.capabilityState.cognitiveRouting);
|
|
543
|
+
} else {
|
|
544
|
+
routingSession.clearArmed();
|
|
545
|
+
}
|
|
546
546
|
registerContextToolForState(snapshot.capabilityState);
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
547
|
+
const routingSnapshot = routingSession.snapshot();
|
|
548
|
+
setFreeflowStatus(
|
|
549
|
+
ctx,
|
|
550
|
+
snapshot.capabilityState,
|
|
551
|
+
snapshot.cognitiveRoutingRuntime ?? routingSnapshot.runtimeState,
|
|
552
|
+
snapshot.freeflowContext,
|
|
553
|
+
{ startupSelectionSuppressed: routingSnapshot.startupSelectionSuppressed },
|
|
554
|
+
);
|
|
555
|
+
await applyCapabilityToolVisibility(pi, ctx, snapshot.capabilityState, routingSnapshot);
|
|
551
556
|
});
|
|
552
557
|
|
|
553
558
|
pi.on("agent_settled", async (_event, ctx) => {
|
|
554
|
-
if (!
|
|
559
|
+
if (!routingSession.hasController()) return undefined;
|
|
555
560
|
await applyLiveCapabilityStateForSession(ctx);
|
|
556
561
|
return undefined;
|
|
557
562
|
});
|
|
558
563
|
|
|
559
564
|
pi.on("session_shutdown", async (event) => {
|
|
565
|
+
await routingSession.shutdown(event?.reason);
|
|
560
566
|
providerSurfaceSnapshot = undefined;
|
|
561
|
-
const controller = cognitiveRoutingController;
|
|
562
|
-
cognitiveRoutingController = undefined;
|
|
563
567
|
freeflowContextRuntime = undefined;
|
|
564
568
|
contextVirtualizationRuntime = undefined;
|
|
565
569
|
conversationHistoryRuntime = undefined;
|
|
566
|
-
if (controller) await controller.shutdown(event?.reason);
|
|
567
570
|
});
|
|
568
571
|
|
|
569
572
|
pi.on("session_tree", async (_event, ctx) => {
|
|
570
573
|
latestCognitiveRoutingContext = ctx;
|
|
571
574
|
providerSurfaceSnapshot = undefined;
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
+
runtimeStateRefreshRequired = true;
|
|
576
|
+
restoreSessionOverrides(ctx);
|
|
577
|
+
await routingSession.reconcileBranch();
|
|
575
578
|
if (contextVirtualizationRuntime) {
|
|
576
579
|
contextVirtualizationRuntime.setContext(ctx);
|
|
577
580
|
await contextVirtualizationRuntime.recover(ctx);
|
|
@@ -583,21 +586,14 @@ export default function freeflow(pi) {
|
|
|
583
586
|
pi.on("session_compact", async (_event, ctx) => {
|
|
584
587
|
latestCognitiveRoutingContext = ctx;
|
|
585
588
|
providerSurfaceSnapshot = undefined;
|
|
586
|
-
|
|
587
|
-
|
|
589
|
+
runtimeStateRefreshRequired = true;
|
|
590
|
+
await routingSession.reconcileBranch("session-compact");
|
|
588
591
|
if (contextVirtualizationRuntime) {
|
|
589
592
|
contextVirtualizationRuntime.setContext(ctx);
|
|
590
593
|
await contextVirtualizationRuntime.recover(ctx);
|
|
591
594
|
}
|
|
592
595
|
conversationHistoryRuntime?.setContext(ctx);
|
|
593
|
-
|
|
594
|
-
readModeState(ctx.cwd),
|
|
595
|
-
readCapabilityState(ctx.cwd, ctx, pi?.host),
|
|
596
|
-
]);
|
|
597
|
-
await refreshRuntimeContext(capabilityState);
|
|
598
|
-
registerContextToolForState(capabilityState);
|
|
599
|
-
setModeStatus(ctx, modeState, capabilityState, cognitiveRoutingController?.state());
|
|
600
|
-
await applyCapabilityToolVisibility(pi, ctx, capabilityState, cognitiveRoutingController);
|
|
596
|
+
await applyLiveCapabilityStateForSession(ctx);
|
|
601
597
|
});
|
|
602
598
|
|
|
603
599
|
pi.on("before_agent_start", async (event, ctx) => {
|
|
@@ -605,8 +601,11 @@ export default function freeflow(pi) {
|
|
|
605
601
|
const snapshot = await buildProviderSurface(ctx, true);
|
|
606
602
|
providerSurfaceSnapshot = { context: ctx, value: snapshot };
|
|
607
603
|
registerContextToolForState(snapshot.capabilityState);
|
|
608
|
-
|
|
609
|
-
|
|
604
|
+
const routingSnapshot = routingSession.snapshot();
|
|
605
|
+
setFreeflowStatus(ctx, snapshot.capabilityState, snapshot.cognitiveRoutingRuntime, snapshot.freeflowContext, {
|
|
606
|
+
startupSelectionSuppressed: routingSnapshot.startupSelectionSuppressed,
|
|
607
|
+
});
|
|
608
|
+
await applyCapabilityToolVisibility(pi, ctx, snapshot.capabilityState, routingSnapshot);
|
|
610
609
|
const freeflowRuntimeContext = runtimeContext(snapshot.freeflowContext, snapshot.capabilityState);
|
|
611
610
|
const systemPrompt = freeflowRuntimeContext
|
|
612
611
|
? `${event.systemPrompt}\n\n${freeflowRuntimeContext}`
|
|
@@ -620,7 +619,6 @@ export default function freeflow(pi) {
|
|
|
620
619
|
if (providerSurfaceSnapshot?.context === ctx) providerSurfaceSnapshot = undefined;
|
|
621
620
|
const cognitiveRoutingRuntime = snapshot.cognitiveRoutingRuntime;
|
|
622
621
|
const surfaceCapabilityState = snapshot.capabilityState;
|
|
623
|
-
const surfaceModeState = snapshot.modeState;
|
|
624
622
|
let changed = false;
|
|
625
623
|
let messages = event.messages
|
|
626
624
|
.map((message) => {
|
|
@@ -644,14 +642,19 @@ export default function freeflow(pi) {
|
|
|
644
642
|
conversationHistoryRuntime.setContext(ctx);
|
|
645
643
|
conversationHistoryRuntime.capture(surfaceCapabilityState.contextVirtualization?.effective === true);
|
|
646
644
|
}
|
|
645
|
+
const forceRuntimeStateRefresh = runtimeStateRefreshRequired;
|
|
647
646
|
const nextMessages = withFreeflowRuntimeState(
|
|
648
647
|
messages,
|
|
649
|
-
surfaceModeState,
|
|
650
648
|
surfaceCapabilityState,
|
|
651
649
|
cognitiveRoutingRuntime,
|
|
650
|
+
snapshot.freeflowContext,
|
|
651
|
+
{ force: forceRuntimeStateRefresh },
|
|
652
652
|
);
|
|
653
|
-
|
|
654
|
-
|
|
653
|
+
if (nextMessages !== messages) {
|
|
654
|
+
changed = true;
|
|
655
|
+
messages = nextMessages;
|
|
656
|
+
}
|
|
657
|
+
if (forceRuntimeStateRefresh) runtimeStateRefreshRequired = false;
|
|
655
658
|
return changed ? { messages } : undefined;
|
|
656
659
|
});
|
|
657
660
|
|
|
@@ -670,7 +673,7 @@ export default function freeflow(pi) {
|
|
|
670
673
|
|
|
671
674
|
pi.on("tool_result", async (event, ctx) => {
|
|
672
675
|
const toolName = typeof event?.toolName === "string" ? event.toolName : "";
|
|
673
|
-
if (
|
|
676
|
+
if (routingSession.supportsCognitiveRoutingRuntime() && toolName === COGNITIVE_ROUTING_SWITCH_TOOL_NAME) {
|
|
674
677
|
await applyLiveCapabilityStateForSession(ctx);
|
|
675
678
|
}
|
|
676
679
|
return undefined;
|
|
@@ -697,7 +700,7 @@ export default function freeflow(pi) {
|
|
|
697
700
|
|
|
698
701
|
pi.registerCommand("freeflow", {
|
|
699
702
|
description: "Open unified Freeflow settings or print compact status",
|
|
700
|
-
getArgumentCompletions: (prefix) => freeflowCompletions(prefix,
|
|
703
|
+
getArgumentCompletions: (prefix) => freeflowCompletions(prefix, routingSession.supportsCognitiveRoutingRuntime()),
|
|
701
704
|
handler: async (args, ctx) => {
|
|
702
705
|
const contextInput = (args ?? "").trim();
|
|
703
706
|
if (contextInput === "context" || contextInput.startsWith("context ")) {
|
|
@@ -711,23 +714,30 @@ export default function freeflow(pi) {
|
|
|
711
714
|
);
|
|
712
715
|
return;
|
|
713
716
|
}
|
|
714
|
-
if (
|
|
717
|
+
if (routingSession.supportsCognitiveRoutingRuntime() && /^profile(?:\s|$)/i.test((args ?? "").trim())) {
|
|
715
718
|
const profileCommandContext = {
|
|
716
719
|
isIdle: ctx?.isIdle,
|
|
717
720
|
ui: ctx?.ui,
|
|
718
|
-
history: (options) =>
|
|
719
|
-
cognitiveRoutingController?.history(options) ?? readCognitiveRoutingHistory(ctx, options),
|
|
721
|
+
history: (options) => routingSession.history(options) ?? readCognitiveRoutingHistory(ctx, options),
|
|
720
722
|
};
|
|
721
723
|
const historyCommand = /^profile\s+history(?:\s|$)/i.test((args ?? "").trim());
|
|
722
724
|
if (historyCommand) {
|
|
723
|
-
await handleCognitiveRoutingProfileCommand(args, profileCommandContext,
|
|
725
|
+
await handleCognitiveRoutingProfileCommand(args, profileCommandContext, routingSession.commandController());
|
|
724
726
|
return;
|
|
725
727
|
}
|
|
726
|
-
if (!
|
|
728
|
+
if (!routingSession.hasController() && !routingSession.armed) {
|
|
729
|
+
routingSession.beginExplicitReactivation();
|
|
727
730
|
await applyLiveCapabilityStateForSession(ctx, { reconcileCognitiveRouting: true });
|
|
728
731
|
}
|
|
729
|
-
|
|
730
|
-
|
|
732
|
+
const profileController = routingSession.commandController();
|
|
733
|
+
if (await handleCognitiveRoutingProfileCommand(args, profileCommandContext, profileController)) {
|
|
734
|
+
if (profileController) {
|
|
735
|
+
routingSession.beginExplicitReactivation();
|
|
736
|
+
await applyLiveCapabilityStateForSession(ctx, {
|
|
737
|
+
reconcileCognitiveRouting: routingSession.armed !== undefined,
|
|
738
|
+
materializeCognitiveRouting: routingSession.armed !== undefined && !isPiFlowHost(pi?.host),
|
|
739
|
+
});
|
|
740
|
+
}
|
|
731
741
|
return;
|
|
732
742
|
}
|
|
733
743
|
}
|
|
@@ -740,7 +750,7 @@ export default function freeflow(pi) {
|
|
|
740
750
|
});
|
|
741
751
|
},
|
|
742
752
|
pi,
|
|
743
|
-
|
|
753
|
+
routingSession.commandController(),
|
|
744
754
|
);
|
|
745
755
|
},
|
|
746
756
|
});
|