@hassangameryt/freeflow 0.7.1 → 0.7.3
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 +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.cursor-plugin/plugin.json +1 -1
- package/README.md +153 -128
- package/capabilities/cognitive-routing/SKILL.md +126 -274
- package/command-surface.json +7 -1
- package/gemini-extension.json +1 -1
- package/package.json +4 -4
- package/pi-extension/dist/cognitive-routing-v2/budget.js +42 -0
- package/pi-extension/dist/cognitive-routing-v2/config.js +136 -0
- package/pi-extension/dist/cognitive-routing-v2/projection.js +330 -0
- package/pi-extension/dist/cognitive-routing-v2/render.js +252 -0
- package/pi-extension/dist/cognitive-routing-v2/runtime.js +2181 -0
- package/pi-extension/dist/cognitive-routing-v2/schemas.js +173 -0
- package/pi-extension/dist/cognitive-routing-v2/state.js +828 -0
- package/pi-extension/dist/cognitive-routing-v2/tools.js +60 -0
- package/pi-extension/dist/cognitive-routing-v2/types.js +48 -0
- package/pi-extension/dist/context-virtualization/runtime.js +29 -7
- package/pi-extension/dist/freeflow-context/tool.js +12 -6
- package/pi-extension/dist/index.js +302 -626
- package/pi-extension/dist/provider-support/astra/adapter.js +110 -0
- package/pi-extension/dist/provider-support/astra/history.js +125 -0
- package/pi-extension/dist/provider-support/astra/index.js +11 -0
- package/pi-extension/dist/provider-support/astra/session-state.js +114 -0
- package/pi-extension/dist/provider-support/index.js +4 -0
- package/pi-extension/dist/runtime/request-history.js +216 -0
- package/pi-extension/dist/runtime/runtime-context.js +85 -16
- package/pi-extension/dist/session-sources/events.js +217 -0
- package/pi-extension/dist/session-sources/provenance.js +32 -0
- package/pi-extension/dist/session-sources/read-only-session.js +148 -0
- package/pi-extension/dist/session-sources/sources.js +277 -0
- package/pi-extension/dist/settings/settings-ui.js +274 -147
- package/pi-extension/src/cognitive-routing-v2/budget.ts +42 -0
- package/pi-extension/src/cognitive-routing-v2/config.ts +173 -0
- package/pi-extension/src/cognitive-routing-v2/projection.ts +375 -0
- package/pi-extension/src/cognitive-routing-v2/render.ts +277 -0
- package/pi-extension/src/cognitive-routing-v2/runtime.ts +2241 -0
- package/pi-extension/src/cognitive-routing-v2/schemas.ts +180 -0
- package/pi-extension/src/cognitive-routing-v2/state.ts +839 -0
- package/pi-extension/src/cognitive-routing-v2/tools.ts +62 -0
- package/pi-extension/src/cognitive-routing-v2/types.ts +254 -0
- package/pi-extension/src/context-virtualization/runtime.ts +30 -8
- package/pi-extension/src/freeflow-context/tool.ts +12 -6
- package/pi-extension/src/index.ts +308 -675
- package/pi-extension/src/provider-support/astra/adapter.ts +108 -0
- package/pi-extension/src/provider-support/astra/history.ts +145 -0
- package/pi-extension/src/provider-support/astra/index.ts +12 -0
- package/pi-extension/src/provider-support/astra/session-state.ts +113 -0
- package/pi-extension/src/provider-support/index.ts +5 -0
- package/pi-extension/src/runtime/request-history.ts +243 -0
- package/pi-extension/src/runtime/runtime-context.ts +100 -17
- package/pi-extension/src/session-sources/events.ts +230 -0
- package/pi-extension/src/session-sources/provenance.ts +39 -0
- package/pi-extension/src/session-sources/read-only-session.ts +170 -0
- package/pi-extension/src/session-sources/sources.ts +334 -0
- package/pi-extension/src/settings/settings-ui.ts +311 -158
- package/pi-extension/tests/cache-reuse/history.test.js +117 -0
- package/pi-extension/tests/cache-reuse/native.test.js +91 -0
- package/pi-extension/tests/cache-reuse/settings.test.js +211 -0
- package/pi-extension/tests/cognitive-routing-v2/communication.test.js +577 -0
- package/pi-extension/tests/cognitive-routing-v2/compaction-input.test.js +183 -0
- package/pi-extension/tests/cognitive-routing-v2/delegation.test.js +557 -0
- package/pi-extension/tests/cognitive-routing-v2/native.test.js +474 -0
- package/pi-extension/tests/cognitive-routing-v2/performance.test.js +87 -0
- package/pi-extension/tests/cognitive-routing-v2/persistence.test.js +300 -0
- package/pi-extension/tests/cognitive-routing-v2/projection.test.js +241 -0
- package/pi-extension/tests/cognitive-routing-v2/recovery.test.js +1034 -0
- package/pi-extension/tests/cognitive-routing-v2/render.test.js +244 -0
- package/pi-extension/tests/cognitive-routing-v2/runtime.test.js +423 -0
- package/pi-extension/tests/cognitive-routing-v2/stabilization.test.js +521 -0
- package/pi-extension/tests/cognitive-routing-v2/state.test.js +586 -0
- package/pi-extension/tests/context-virtualization/extension.test.js +33 -7
- package/pi-extension/tests/context-virtualization/runtime.test.js +17 -3
- package/pi-extension/tests/fixtures/routing-native.js +191 -0
- package/pi-extension/tests/integration/mode-free-core.test.js +6 -4
- package/pi-extension/tests/integration/pi-extension.test.js +655 -59
- package/pi-extension/tests/integration/prompt-architecture.test.js +127 -30
- package/pi-extension/tests/integration/unaffected-regressions.test.js +78 -11
- package/pi-extension/tests/provider-support/astra-boundaries.test.js +75 -0
- package/pi-extension/tests/provider-support/astra.test.js +306 -0
- package/pi-extension/tests/provider-support/cli.test.js +92 -0
- package/pi-extension/tests/provider-support/native.test.js +183 -0
- package/plugin.json +1 -1
- package/runtime/prompts/cognitive-routing.md +4 -5
- package/runtime/prompts/core.md +51 -45
- package/runtime/prompts/interaction-contract.md +5 -5
- package/skills/action-selection/SKILL.md +57 -97
- package/skills/design-for-depth/SKILL.md +58 -193
- package/skills/design-for-depth/references/implementation-decisions.md +76 -0
- package/skills/diagnose-failure/SKILL.md +64 -196
- package/skills/discuss/SKILL.md +64 -123
- package/skills/discuss/references/discussion-continuity.md +7 -3
- package/skills/execute-work/SKILL.md +69 -88
- package/skills/execute-work/references/execute-work-edges.md +9 -3
- package/skills/handoff/SKILL.md +44 -54
- package/skills/handoff/references/handoff-templates.md +15 -6
- package/skills/review-artifact/SKILL.md +80 -127
- package/skills/review-artifact/references/independent-artifact-reviewer-contract.md +1 -1
- package/skills/review-work/SKILL.md +65 -115
- package/skills/review-work/references/independent-work-reviewer-contract.md +1 -1
- package/skills/simplify-code/SKILL.md +47 -100
- package/skills/track-work/SKILL.md +128 -119
- package/skills/track-work/references/working-record-format.md +14 -2
- package/skills/verify-work/SKILL.md +58 -62
- package/skills/verify-work/references/integration-evidence.md +4 -2
- package/skills/verify-work/references/test-design.md +89 -0
- package/skills/workflow/SKILL.md +73 -119
- package/skills/write-plan/SKILL.md +46 -77
- package/skills/write-plan/references/plan-shapes.md +5 -5
- package/skills/write-spec/SKILL.md +51 -63
- package/skills/write-spec/references/artifact-standards.md +2 -2
- package/skills/write-spec/references/decision-records.md +3 -2
- package/skills/write-spec/references/spec-shapes.md +15 -0
- package/pi-extension/dist/cognitive-routing/commands.js +0 -96
- package/pi-extension/dist/cognitive-routing/config.js +0 -232
- package/pi-extension/dist/cognitive-routing/controller.js +0 -1292
- package/pi-extension/dist/cognitive-routing/history.js +0 -451
- package/pi-extension/dist/cognitive-routing/host.js +0 -188
- package/pi-extension/dist/cognitive-routing/pi-routing-session.js +0 -414
- package/pi-extension/dist/cognitive-routing/pi-session-control.js +0 -320
- package/pi-extension/dist/cognitive-routing/runtime.js +0 -43
- package/pi-extension/dist/cognitive-routing/tool.js +0 -212
- package/pi-extension/dist/cognitive-routing/types.js +0 -6
- package/pi-extension/src/cognitive-routing/commands.ts +0 -129
- package/pi-extension/src/cognitive-routing/config.ts +0 -303
- package/pi-extension/src/cognitive-routing/controller.ts +0 -1628
- package/pi-extension/src/cognitive-routing/history.ts +0 -650
- package/pi-extension/src/cognitive-routing/host.ts +0 -266
- package/pi-extension/src/cognitive-routing/pi-routing-session.ts +0 -538
- package/pi-extension/src/cognitive-routing/pi-session-control.ts +0 -444
- package/pi-extension/src/cognitive-routing/runtime.ts +0 -57
- package/pi-extension/src/cognitive-routing/tool.ts +0 -273
- package/pi-extension/src/cognitive-routing/types.ts +0 -89
- package/pi-extension/tests/cognitive-routing/commands.test.js +0 -134
- package/pi-extension/tests/cognitive-routing/controller.test.js +0 -1128
- package/pi-extension/tests/cognitive-routing/extension-lifecycle.test.js +0 -1142
- package/pi-extension/tests/cognitive-routing/history.test.js +0 -274
- package/pi-extension/tests/cognitive-routing/host-identity.test.js +0 -63
- package/pi-extension/tests/cognitive-routing/pi-normal-lifecycle.test.js +0 -434
- package/pi-extension/tests/cognitive-routing/pi-session-control.test.js +0 -174
- package/pi-extension/tests/cognitive-routing/pi-session-history.test.js +0 -91
- package/pi-extension/tests/cognitive-routing/profile-resolution.test.js +0 -279
- package/pi-extension/tests/cognitive-routing/tool.test.js +0 -230
- package/skills/tdd/SKILL.md +0 -143
- package/skills/tdd/references/test-design.md +0 -96
- /package/pi-extension/tests/{cognitive-routing/host-fixture.js → fixtures/pi-host.js} +0 -0
|
@@ -1,15 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
} from "./cognitive-routing/
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
cognitiveRoutingProfileCompletions,
|
|
9
|
-
handleCognitiveRoutingProfileCommand,
|
|
10
|
-
} from "./cognitive-routing/commands.js";
|
|
11
|
-
import { registerCognitiveRoutingHistoryTool, registerCognitiveRoutingTool } from "./cognitive-routing/tool.js";
|
|
12
|
-
import { readCognitiveRoutingHistory } from "./cognitive-routing/history.js";
|
|
1
|
+
import { dirname, resolve } from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { RequestHistory } from "./runtime/request-history.js";
|
|
4
|
+
import { registerProviderSupport } from "./provider-support/index.js";
|
|
5
|
+
import { RoutingRuntime } from "./cognitive-routing-v2/runtime.js";
|
|
6
|
+
import { workersForDelegation } from "./cognitive-routing-v2/types.js";
|
|
7
|
+
import { applyRoutingToolVisibility, registerRoutingTools } from "./cognitive-routing-v2/tools.js";
|
|
13
8
|
import { ConversationHistoryRuntime } from "./conversation-history/runtime.js";
|
|
14
9
|
import { FreeflowContextRuntime } from "./freeflow-context/runtime.js";
|
|
15
10
|
import { CONTEXT_VIRTUALIZATION_TOOL_NAME, registerFreeflowContextTool } from "./freeflow-context/tool.js";
|
|
@@ -19,686 +14,367 @@ import { handleFreeflowCommand } from "./settings/settings-ui.js";
|
|
|
19
14
|
import { isPiFlowHost } from "./runtime/runtime-identity.js";
|
|
20
15
|
import {
|
|
21
16
|
CONTRIBUTOR_COMMANDS,
|
|
22
|
-
COGNITIVE_ROUTING_SWITCH_TOOL_NAME,
|
|
23
17
|
WORKFLOW_COMMANDS,
|
|
24
18
|
freeflowModelSkillPaths,
|
|
25
|
-
freeflowSkillPath,
|
|
26
19
|
getRuntimeContext,
|
|
27
20
|
hasUsableMandatoryPrompts,
|
|
28
21
|
isPromptAvailable,
|
|
29
22
|
readCapabilityState,
|
|
30
23
|
refreshRuntimeContext,
|
|
31
24
|
restoreSessionOverrides,
|
|
32
|
-
|
|
25
|
+
stableRuntimeContext,
|
|
26
|
+
STABLE_FREEFLOW_SURFACE,
|
|
33
27
|
filterBootstrapMessage,
|
|
34
28
|
setFreeflowStatus,
|
|
35
29
|
skillPrompt,
|
|
36
30
|
withFreeflowRuntimeState,
|
|
37
31
|
} from "./runtime/runtime-context.js";
|
|
38
|
-
function unavailableCapability(capability, code, message) {
|
|
39
|
-
return {
|
|
40
|
-
...capability,
|
|
41
|
-
effective: false,
|
|
42
|
-
blockingReason: { code, message },
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
function modelFacingCapabilityState(
|
|
46
|
-
capabilityState,
|
|
47
|
-
freeflowContext,
|
|
48
|
-
routingSnapshot,
|
|
49
|
-
cognitiveRoutingActivationFailed = false,
|
|
50
|
-
) {
|
|
51
|
-
const surfaceState = {
|
|
52
|
-
...capabilityState,
|
|
53
|
-
contextVirtualization: { ...capabilityState?.contextVirtualization },
|
|
54
|
-
conversationHistory: { ...capabilityState?.conversationHistory },
|
|
55
|
-
cognitiveRouting: { ...capabilityState?.cognitiveRouting },
|
|
56
|
-
};
|
|
57
|
-
if (surfaceState.enabled !== true) return surfaceState;
|
|
58
|
-
const markUnavailable = (key, message) => {
|
|
59
|
-
if (surfaceState[key]?.effective === true) {
|
|
60
|
-
surfaceState[key] = unavailableCapability(surfaceState[key], "unavailable", message);
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
if (!hasUsableMandatoryPrompts(freeflowContext)) {
|
|
64
|
-
for (const key of ["contextVirtualization", "conversationHistory", "cognitiveRouting"]) {
|
|
65
|
-
markUnavailable(key, "Mandatory Freeflow prompt is unavailable.");
|
|
66
|
-
}
|
|
67
|
-
return surfaceState;
|
|
68
|
-
}
|
|
69
|
-
if (
|
|
70
|
-
surfaceState.contextVirtualization?.effective === true &&
|
|
71
|
-
!isPromptAvailable(freeflowContext.contextVirtualizationPrompt)
|
|
72
|
-
) {
|
|
73
|
-
markUnavailable("contextVirtualization", "Context Virtualization prompt is unavailable.");
|
|
74
|
-
}
|
|
75
|
-
if (
|
|
76
|
-
surfaceState.conversationHistory?.effective === true &&
|
|
77
|
-
!isPromptAvailable(freeflowContext.conversationHistoryPrompt)
|
|
78
|
-
) {
|
|
79
|
-
markUnavailable("conversationHistory", "Conversation History prompt is unavailable.");
|
|
80
|
-
}
|
|
81
|
-
if (surfaceState.cognitiveRouting?.effective === true) {
|
|
82
|
-
const controllerState = routingSnapshot.runtimeState;
|
|
83
|
-
if (routingSnapshot.disposition === "blocked") {
|
|
84
|
-
surfaceState.cognitiveRouting = unavailableCapability(
|
|
85
|
-
surfaceState.cognitiveRouting,
|
|
86
|
-
"runtime_blocked",
|
|
87
|
-
routingSnapshot.reason ?? "Cognitive Routing is blocked because its inactive state could not be persisted.",
|
|
88
|
-
);
|
|
89
|
-
} else if (routingSnapshot.startupSelectionSuppressed || routingSnapshot.disposition === "inactive") {
|
|
90
|
-
surfaceState.cognitiveRouting = unavailableCapability(
|
|
91
|
-
surfaceState.cognitiveRouting,
|
|
92
|
-
"runtime_inactive",
|
|
93
|
-
"Cognitive Routing is inactive because Pi owns the startup model or thinking level.",
|
|
94
|
-
);
|
|
95
|
-
} else if (controllerState?.runtimeStatus === "inactive") {
|
|
96
|
-
surfaceState.cognitiveRouting = unavailableCapability(
|
|
97
|
-
surfaceState.cognitiveRouting,
|
|
98
|
-
"runtime_inactive",
|
|
99
|
-
controllerState.runtimeReason ?? "Cognitive Routing is inactive because Pi owns the current model state.",
|
|
100
|
-
);
|
|
101
|
-
} else if (controllerState?.runtimeStatus === "blocked") {
|
|
102
|
-
surfaceState.cognitiveRouting = unavailableCapability(
|
|
103
|
-
surfaceState.cognitiveRouting,
|
|
104
|
-
"runtime_blocked",
|
|
105
|
-
controllerState.runtimeReason ?? "Cognitive Routing is blocked because its state is not proven.",
|
|
106
|
-
);
|
|
107
|
-
} else if (cognitiveRoutingActivationFailed || controllerState?.effective === false) {
|
|
108
|
-
surfaceState.cognitiveRouting = unavailableCapability(
|
|
109
|
-
surfaceState.cognitiveRouting,
|
|
110
|
-
"unavailable",
|
|
111
|
-
"Cognitive Routing could not activate for this session.",
|
|
112
|
-
);
|
|
113
|
-
} else if (!isPromptAvailable(freeflowContext.cognitiveRoutingPrompt)) {
|
|
114
|
-
markUnavailable("cognitiveRouting", "Cognitive Routing prompt is unavailable.");
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
return surfaceState;
|
|
118
|
-
}
|
|
119
|
-
function sessionHasConversationOrRoutingState(ctx) {
|
|
120
|
-
try {
|
|
121
|
-
const entries = ctx?.sessionManager?.getBranch?.() ?? ctx?.sessionManager?.getEntries?.() ?? [];
|
|
122
|
-
if (!Array.isArray(entries)) return false;
|
|
123
|
-
return entries.some((entry) => {
|
|
124
|
-
if (!entry || typeof entry !== "object") return false;
|
|
125
|
-
const record = entry;
|
|
126
|
-
if (
|
|
127
|
-
typeof record.type === "string" &&
|
|
128
|
-
["message", "custom_message", "compaction", "branch_summary"].includes(record.type)
|
|
129
|
-
) {
|
|
130
|
-
return true;
|
|
131
|
-
}
|
|
132
|
-
return (
|
|
133
|
-
record.type === "custom" &&
|
|
134
|
-
(record.customType === COGNITIVE_ROUTING_INTENT_ENTRY ||
|
|
135
|
-
record.customType === COGNITIVE_ROUTING_CONTROL_ENTRY ||
|
|
136
|
-
record.customType === COGNITIVE_ROUTING_INACTIVE_ENTRY)
|
|
137
|
-
);
|
|
138
|
-
});
|
|
139
|
-
} catch {
|
|
140
|
-
return false;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
async function applyCapabilityToolVisibility(
|
|
144
|
-
pi,
|
|
145
|
-
ctx,
|
|
146
|
-
capabilityState = undefined,
|
|
147
|
-
routingSnapshot = {
|
|
148
|
-
status: "available",
|
|
149
|
-
disposition: "available",
|
|
150
|
-
startupSelectionSuppressed: false,
|
|
151
|
-
},
|
|
152
|
-
) {
|
|
153
|
-
if (typeof pi?.setActiveTools !== "function" || typeof pi?.getAllTools !== "function") return;
|
|
154
|
-
const state = capabilityState ?? (await readCapabilityState(ctx.cwd, ctx, pi?.host));
|
|
155
|
-
const allToolNames = pi
|
|
156
|
-
.getAllTools()
|
|
157
|
-
.map((tool) => tool?.name)
|
|
158
|
-
.filter(Boolean);
|
|
159
|
-
const allToolNameSet = new Set(allToolNames);
|
|
160
|
-
const currentActive = typeof pi.getActiveTools === "function" ? pi.getActiveTools() : undefined;
|
|
161
|
-
const active = new Set(
|
|
162
|
-
(Array.isArray(currentActive) ? currentActive : allToolNames).filter((name) => allToolNameSet.has(name)),
|
|
163
|
-
);
|
|
164
|
-
if (allToolNameSet.has(COGNITIVE_ROUTING_SWITCH_TOOL_NAME)) {
|
|
165
|
-
const controllerState = routingSnapshot.runtimeState;
|
|
166
|
-
const routingToolActive =
|
|
167
|
-
state.cognitiveRouting?.effective === true &&
|
|
168
|
-
controllerState?.effective === true &&
|
|
169
|
-
controllerState.controlMode === "automatic";
|
|
170
|
-
if (routingToolActive) active.add(COGNITIVE_ROUTING_SWITCH_TOOL_NAME);
|
|
171
|
-
else active.delete(COGNITIVE_ROUTING_SWITCH_TOOL_NAME);
|
|
172
|
-
}
|
|
173
|
-
if (allToolNameSet.has(CONTEXT_VIRTUALIZATION_TOOL_NAME)) {
|
|
174
|
-
if (state.contextVirtualization?.effective === true || state.conversationHistory?.effective === true) {
|
|
175
|
-
active.add(CONTEXT_VIRTUALIZATION_TOOL_NAME);
|
|
176
|
-
} else {
|
|
177
|
-
active.delete(CONTEXT_VIRTUALIZATION_TOOL_NAME);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
pi.setActiveTools([...active]);
|
|
181
|
-
}
|
|
182
|
-
function disabledToolCall(toolName, capability) {
|
|
183
|
-
const command = capability === "freeflow" ? "/freeflow settings" : `/${capability} settings`;
|
|
184
|
-
return {
|
|
185
|
-
block: true,
|
|
186
|
-
reason: `${toolName} is disabled by Freeflow config. Configure ${capability} with ${command}.`,
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
function freeflowCompletions(prefix, cognitiveRoutingAvailable = false) {
|
|
190
|
-
const query = prefix ?? "";
|
|
191
|
-
if (query.startsWith("settings ")) {
|
|
192
|
-
const settingsQuery = query.slice("settings ".length);
|
|
193
|
-
return [
|
|
194
|
-
{ value: "session", label: "session", description: "Override Freeflow for this Pi session" },
|
|
195
|
-
{ value: "local", label: "local", description: "Edit personal overrides for this repository" },
|
|
196
|
-
{ value: "repo", label: "repo", description: "Edit shared repository settings" },
|
|
197
|
-
]
|
|
198
|
-
.filter((item) => item.value.startsWith(settingsQuery))
|
|
199
|
-
.map((item) => ({ ...item, value: `settings ${item.value}` }));
|
|
200
|
-
}
|
|
201
|
-
if (cognitiveRoutingAvailable && query.startsWith("profile ")) {
|
|
202
|
-
return cognitiveRoutingProfileCompletions(query.slice("profile ".length)).map((item) => ({
|
|
203
|
-
...item,
|
|
204
|
-
value: `profile ${item.value}`,
|
|
205
|
-
}));
|
|
206
|
-
}
|
|
207
|
-
if (query.startsWith("context ")) {
|
|
208
|
-
const contextQuery = query.slice("context ".length);
|
|
209
|
-
return [
|
|
210
|
-
{ value: "status", label: "status", description: "Show Freeflow Context state" },
|
|
211
|
-
{ value: "list", label: "list", description: "List archived context projections" },
|
|
212
|
-
{ value: "restore", label: "restore", description: "Restore one or more context references" },
|
|
213
|
-
{ value: "reset all", label: "reset all", description: "Reset projection decisions on the active branch" },
|
|
214
|
-
]
|
|
215
|
-
.filter((item) => item.value.startsWith(contextQuery))
|
|
216
|
-
.map((item) => ({ ...item, value: `context ${item.value}` }));
|
|
217
|
-
}
|
|
218
|
-
return [
|
|
219
|
-
{ value: "settings", label: "settings", description: "Open personal override settings" },
|
|
220
|
-
{ value: "status", label: "status", description: "Show effective Freeflow state" },
|
|
221
|
-
{ value: "context", label: "context", description: "Inspect Freeflow Context" },
|
|
222
|
-
...(cognitiveRoutingAvailable
|
|
223
|
-
? [{ value: "profile", label: "profile", description: "Hold or release Cognitive Routing profile control" }]
|
|
224
|
-
: []),
|
|
225
|
-
{ value: "enable", label: "enable", description: "Enable Freeflow for this repository" },
|
|
226
|
-
{ value: "disable", label: "disable", description: "Disable Freeflow for this repository" },
|
|
227
|
-
].filter((item) => item.value.startsWith(query));
|
|
228
|
-
}
|
|
229
|
-
function bypassCompletions(prefix) {
|
|
230
|
-
const query = prefix ?? "";
|
|
231
|
-
return [
|
|
232
|
-
{ value: "next", label: "next", description: "Skip one optional step" },
|
|
233
|
-
{ value: "task", label: "task", description: "Reduce optional pressure for the current task" },
|
|
234
|
-
].filter((item) => item.value.startsWith(query));
|
|
235
|
-
}
|
|
236
32
|
async function sendSkillCommand(pi, ctx, skill, args) {
|
|
237
|
-
const state = await readCapabilityState(ctx.cwd, ctx, pi
|
|
33
|
+
const state = await readCapabilityState(ctx.cwd, ctx, pi.host);
|
|
238
34
|
if (skill === "setup-freeflow" && !state.configured) {
|
|
239
35
|
await pi.sendUserMessage(skillPrompt(skill, args), { expandPromptTemplates: true });
|
|
240
36
|
return;
|
|
241
37
|
}
|
|
242
|
-
if (!state.configured) {
|
|
243
|
-
ctx.ui.notify("
|
|
244
|
-
return;
|
|
245
|
-
}
|
|
246
|
-
if (!state.enabled) {
|
|
247
|
-
ctx.ui.notify(
|
|
248
|
-
"Freeflow is disabled for this repo. Use /freeflow enable or /freeflow settings to re-enable it.",
|
|
249
|
-
"warning",
|
|
250
|
-
);
|
|
38
|
+
if (!state.configured || !state.enabled) {
|
|
39
|
+
ctx.ui.notify("Run /setup-freeflow or enable Freeflow before dispatching this skill.", "warning");
|
|
251
40
|
return;
|
|
252
41
|
}
|
|
253
|
-
const
|
|
254
|
-
if (!hasUsableMandatoryPrompts(
|
|
42
|
+
const prompts = await getRuntimeContext(state);
|
|
43
|
+
if (!hasUsableMandatoryPrompts(prompts)) {
|
|
255
44
|
ctx.ui.notify("Freeflow core prompts are unavailable; the requested skill cannot be dispatched.", "warning");
|
|
256
45
|
return;
|
|
257
46
|
}
|
|
258
47
|
await pi.sendUserMessage(skillPrompt(skill, args), { expandPromptTemplates: true });
|
|
259
48
|
}
|
|
49
|
+
function freeflowCompletions(prefix, routingAvailable) {
|
|
50
|
+
const query = prefix ?? "";
|
|
51
|
+
const choices = query.startsWith("settings ")
|
|
52
|
+
? [
|
|
53
|
+
["settings session", "session", "Override Freeflow for this Pi session"],
|
|
54
|
+
["settings local", "local", "Edit personal overrides for this repository"],
|
|
55
|
+
["settings repo", "repo", "Edit shared repository settings"],
|
|
56
|
+
]
|
|
57
|
+
: query.startsWith("profile ") && routingAvailable
|
|
58
|
+
? [
|
|
59
|
+
["profile coordinator", "coordinator", "Hold Coordinator manually"],
|
|
60
|
+
["profile helper", "helper", "Hold Helper manually when enabled"],
|
|
61
|
+
["profile executor", "executor", "Hold Executor manually when enabled"],
|
|
62
|
+
["profile auto", "auto", "Return to automatic Coordinator reconciliation"],
|
|
63
|
+
["profile history", "history", "Read routing observations"],
|
|
64
|
+
]
|
|
65
|
+
: query.startsWith("context ")
|
|
66
|
+
? [
|
|
67
|
+
["context status", "status", "Show Freeflow Context state"],
|
|
68
|
+
["context list", "list", "List archived context projections"],
|
|
69
|
+
["context restore", "restore", "Restore one or more context references"],
|
|
70
|
+
["context reset all", "reset all", "Reset projection decisions on the active branch"],
|
|
71
|
+
]
|
|
72
|
+
: [
|
|
73
|
+
["settings", "settings", "Open personal override settings"],
|
|
74
|
+
["status", "status", "Show effective Freeflow state"],
|
|
75
|
+
["context", "context", "Inspect Freeflow Context"],
|
|
76
|
+
...(routingAvailable
|
|
77
|
+
? [
|
|
78
|
+
["profile", "profile", "Hold or release Cognitive Routing profile control"],
|
|
79
|
+
["resume", "resume", "Resume the current saved routing responsibility"],
|
|
80
|
+
]
|
|
81
|
+
: []),
|
|
82
|
+
["enable", "enable", "Enable Freeflow for this repository"],
|
|
83
|
+
["disable", "disable", "Disable Freeflow for this repository"],
|
|
84
|
+
];
|
|
85
|
+
return choices
|
|
86
|
+
.filter(([value]) => value.startsWith(query))
|
|
87
|
+
.map(([value, label, description]) => ({ value, label, description }));
|
|
88
|
+
}
|
|
260
89
|
export default function freeflow(pi) {
|
|
261
|
-
|
|
262
|
-
const
|
|
263
|
-
const
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
let
|
|
267
|
-
let
|
|
268
|
-
let
|
|
269
|
-
let
|
|
270
|
-
|
|
90
|
+
registerProviderSupport(pi);
|
|
91
|
+
const api = pi;
|
|
92
|
+
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
|
|
93
|
+
const routing = new RoutingRuntime(api, [packageRoot]);
|
|
94
|
+
const requestHistory = new RequestHistory(api);
|
|
95
|
+
let capability;
|
|
96
|
+
let prompts;
|
|
97
|
+
let context;
|
|
98
|
+
let virtualization;
|
|
99
|
+
let history;
|
|
100
|
+
let refreshState = true;
|
|
101
|
+
let sessionContext;
|
|
102
|
+
let surfaceGeneration = 0;
|
|
103
|
+
const unavailable = (state, message) => ({
|
|
104
|
+
...state,
|
|
105
|
+
effective: false,
|
|
106
|
+
blockingReason: { code: "unavailable", message },
|
|
107
|
+
});
|
|
108
|
+
async function loadSurface(ctx) {
|
|
109
|
+
const generation = surfaceGeneration;
|
|
110
|
+
const next = await readCapabilityState(ctx.cwd, ctx, pi.host);
|
|
111
|
+
const loaded = await getRuntimeContext(STABLE_FREEFLOW_SURFACE);
|
|
112
|
+
if (generation !== surfaceGeneration) throw new Error("Discarded surface preparation for a replaced session.");
|
|
113
|
+
if (!hasUsableMandatoryPrompts(loaded)) {
|
|
114
|
+
for (const key of ["cognitiveRouting", "contextVirtualization", "conversationHistory"])
|
|
115
|
+
next[key] = unavailable(next[key], "Mandatory Freeflow prompts are unavailable.");
|
|
116
|
+
}
|
|
117
|
+
if (next.cognitiveRouting.effective && !isPromptAvailable(loaded.cognitiveRoutingPrompt))
|
|
118
|
+
next.cognitiveRouting = unavailable(next.cognitiveRouting, "Routing bootstrap cue is unavailable.");
|
|
119
|
+
if (next.contextVirtualization.effective && !isPromptAvailable(loaded.contextVirtualizationPrompt))
|
|
120
|
+
next.contextVirtualization = unavailable(
|
|
121
|
+
next.contextVirtualization,
|
|
122
|
+
"Context Virtualization guidance is unavailable.",
|
|
123
|
+
);
|
|
124
|
+
if (next.conversationHistory.effective && !isPromptAvailable(loaded.conversationHistoryPrompt))
|
|
125
|
+
next.conversationHistory = unavailable(next.conversationHistory, "Conversation History guidance is unavailable.");
|
|
126
|
+
// The existing reduction engine is not the future Context Control port. Do not pretend
|
|
127
|
+
// its independent transform ordering has been qualified with the new projection.
|
|
128
|
+
if (
|
|
129
|
+
next.cognitiveRouting.effective &&
|
|
130
|
+
next.cognitiveRouting.projection &&
|
|
131
|
+
(next.contextVirtualization.effective || next.conversationHistory.effective)
|
|
132
|
+
)
|
|
133
|
+
next.cognitiveRouting = unavailable(
|
|
134
|
+
next.cognitiveRouting,
|
|
135
|
+
"New routing projection with legacy context transforms is not qualified. Disable that combination explicitly.",
|
|
136
|
+
);
|
|
137
|
+
if (next.cognitiveRouting.enabled && isPiFlowHost(pi.host))
|
|
138
|
+
next.cognitiveRouting = unavailable(
|
|
139
|
+
next.cognitiveRouting,
|
|
140
|
+
"The redesigned PiFlow adapter requires separate qualification.",
|
|
141
|
+
);
|
|
142
|
+
capability = next;
|
|
143
|
+
prompts = loaded;
|
|
144
|
+
sessionContext = ctx;
|
|
145
|
+
return next;
|
|
146
|
+
}
|
|
147
|
+
function contextTools() {
|
|
271
148
|
registerFreeflowContextTool(
|
|
272
|
-
|
|
273
|
-
() =>
|
|
274
|
-
() =>
|
|
149
|
+
api,
|
|
150
|
+
() => virtualization,
|
|
151
|
+
() => history,
|
|
275
152
|
{
|
|
276
|
-
contextVirtualization:
|
|
277
|
-
conversationHistory:
|
|
153
|
+
contextVirtualization: capability?.contextVirtualization?.effective === true,
|
|
154
|
+
conversationHistory: capability?.conversationHistory?.effective === true,
|
|
278
155
|
},
|
|
279
156
|
);
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
capabilityState,
|
|
286
|
-
freeflowContext,
|
|
287
|
-
routingSession.snapshot(),
|
|
288
|
-
);
|
|
289
|
-
let activationAttempted = false;
|
|
290
|
-
if (
|
|
291
|
-
activateCognitiveRouting &&
|
|
292
|
-
routingSession.canAutoActivate() &&
|
|
293
|
-
(!routingSession.hasController() || promptCapabilityState.cognitiveRouting?.effective !== true)
|
|
294
|
-
) {
|
|
295
|
-
activationAttempted = promptCapabilityState.cognitiveRouting?.effective === true;
|
|
296
|
-
try {
|
|
297
|
-
await routingSession.reconcileController(
|
|
298
|
-
ctx,
|
|
299
|
-
promptCapabilityState,
|
|
300
|
-
routingSession.armed ? { ...routingSession.armed } : undefined,
|
|
301
|
-
);
|
|
302
|
-
if (routingSession.hasController()) {
|
|
303
|
-
routingSession.clearArmed();
|
|
304
|
-
if (routingSession.snapshot().status === "active") routingSession.markActive();
|
|
305
|
-
}
|
|
306
|
-
} catch {
|
|
307
|
-
routingSession.clearController();
|
|
308
|
-
}
|
|
157
|
+
if (api.getActiveTools && api.setActiveTools) {
|
|
158
|
+
const current = new Set(api.getActiveTools());
|
|
159
|
+
current.add(CONTEXT_VIRTUALIZATION_TOOL_NAME);
|
|
160
|
+
const next = [...current];
|
|
161
|
+
if (JSON.stringify(next) !== JSON.stringify(api.getActiveTools())) api.setActiveTools(next);
|
|
309
162
|
}
|
|
310
|
-
const surfaceCapabilityState = modelFacingCapabilityState(
|
|
311
|
-
promptCapabilityState,
|
|
312
|
-
freeflowContext,
|
|
313
|
-
routingSession.snapshot(),
|
|
314
|
-
activationAttempted && !routingSession.hasController(),
|
|
315
|
-
);
|
|
316
|
-
const routingSnapshot = routingSession.snapshot();
|
|
317
|
-
return {
|
|
318
|
-
capabilityState: surfaceCapabilityState,
|
|
319
|
-
freeflowContext,
|
|
320
|
-
cognitiveRoutingRuntime: routingSnapshot.runtimeState,
|
|
321
|
-
configuredCapabilityState: capabilityState,
|
|
322
|
-
};
|
|
323
|
-
};
|
|
324
|
-
const applyLiveCapabilityStateForSession = async (ctx, options = {}) => {
|
|
325
|
-
providerSurfaceSnapshot = undefined;
|
|
326
|
-
await routingSession.applyLiveCapabilityState(ctx, options);
|
|
327
|
-
const capabilityState = await readCapabilityState(ctx.cwd, ctx, pi?.host);
|
|
328
|
-
const freeflowContext = await getRuntimeContext(capabilityState);
|
|
329
|
-
const surfaceCapabilityState = modelFacingCapabilityState(
|
|
330
|
-
capabilityState,
|
|
331
|
-
freeflowContext,
|
|
332
|
-
routingSession.snapshot(),
|
|
333
|
-
);
|
|
334
|
-
const routingSnapshot = routingSession.snapshot();
|
|
335
|
-
setFreeflowStatus(ctx, surfaceCapabilityState, routingSnapshot.runtimeState, freeflowContext, {
|
|
336
|
-
startupSelectionSuppressed: routingSnapshot.startupSelectionSuppressed,
|
|
337
|
-
});
|
|
338
|
-
await applyCapabilityToolVisibility(pi, ctx, surfaceCapabilityState, routingSnapshot);
|
|
339
|
-
registerContextToolForState(surfaceCapabilityState);
|
|
340
|
-
};
|
|
341
|
-
if (routingSession.supportsCognitiveRoutingRuntime()) {
|
|
342
|
-
registerCognitiveRoutingTool(toolRegistrar, () => routingSession.controllerForTool());
|
|
343
|
-
registerCognitiveRoutingHistoryTool(toolRegistrar, (options, context) => {
|
|
344
|
-
return (
|
|
345
|
-
routingSession.history(options) ??
|
|
346
|
-
readCognitiveRoutingHistory(context ?? latestCognitiveRoutingContext, options)
|
|
347
|
-
);
|
|
348
|
-
});
|
|
349
163
|
}
|
|
164
|
+
function status(ctx) {
|
|
165
|
+
applyRoutingToolVisibility(api, routing, capability?.cognitiveRouting?.effective === true);
|
|
166
|
+
setFreeflowStatus(ctx, capability, routing.state(), prompts);
|
|
167
|
+
}
|
|
168
|
+
async function update(ctx) {
|
|
169
|
+
const next = await loadSurface(ctx);
|
|
170
|
+
await routing.refresh(ctx, next.cognitiveRouting);
|
|
171
|
+
contextTools();
|
|
172
|
+
status(ctx);
|
|
173
|
+
refreshState = true;
|
|
174
|
+
}
|
|
175
|
+
registerRoutingTools(api, routing);
|
|
350
176
|
registerFreeflowContextTool(
|
|
351
|
-
|
|
352
|
-
() =>
|
|
353
|
-
() =>
|
|
177
|
+
api,
|
|
178
|
+
() => virtualization,
|
|
179
|
+
() => history,
|
|
354
180
|
{ contextVirtualization: false, conversationHistory: false },
|
|
355
181
|
);
|
|
356
|
-
if (routingSession.supportsCognitiveRoutingRuntime() && typeof pi.registerShortcut === "function") {
|
|
357
|
-
pi.registerShortcut("ctrl+shift+r", {
|
|
358
|
-
description: "Cycle the Cognitive Routing manual standard/reasoning hold",
|
|
359
|
-
handler: async (ctx) => {
|
|
360
|
-
if (typeof ctx?.isIdle === "function" && !ctx.isIdle()) {
|
|
361
|
-
ctx.ui?.notify?.("Freeflow settings and profile changes are available only while Pi is idle.", "warning");
|
|
362
|
-
return;
|
|
363
|
-
}
|
|
364
|
-
const armedCycle = routingSession.hasController() ? undefined : routingSession.cycleArmedManual();
|
|
365
|
-
if (armedCycle) {
|
|
366
|
-
routingSession.beginExplicitReactivation();
|
|
367
|
-
ctx.ui?.notify?.(`Cognitive Routing manual hold set to ${armedCycle.target}.`, "info");
|
|
368
|
-
await applyLiveCapabilityStateForSession(ctx, {
|
|
369
|
-
reconcileCognitiveRouting: true,
|
|
370
|
-
materializeCognitiveRouting: !isPiFlowHost(pi?.host),
|
|
371
|
-
});
|
|
372
|
-
return;
|
|
373
|
-
}
|
|
374
|
-
if (!routingSession.hasController()) {
|
|
375
|
-
routingSession.beginExplicitReactivation();
|
|
376
|
-
await applyLiveCapabilityStateForSession(ctx, { reconcileCognitiveRouting: true });
|
|
377
|
-
}
|
|
378
|
-
const state = routingSession.snapshot().runtimeState;
|
|
379
|
-
if (!state) {
|
|
380
|
-
ctx.ui?.notify?.("Cognitive Routing is unavailable for this session.", "warning");
|
|
381
|
-
return;
|
|
382
|
-
}
|
|
383
|
-
const target = state.activeProfile === "reasoning" ? "standard" : "reasoning";
|
|
384
|
-
const result = await routingSession.setManualProfile(target, "profile-shortcut");
|
|
385
|
-
if (result.status === "active") {
|
|
386
|
-
ctx.ui?.notify?.(`Cognitive Routing manual hold set to ${target}.`, "info");
|
|
387
|
-
} else {
|
|
388
|
-
ctx.ui?.notify?.(`Cognitive Routing could not set the manual profile: ${result.reason}.`, "warning");
|
|
389
|
-
}
|
|
390
|
-
await applyLiveCapabilityStateForSession(ctx);
|
|
391
|
-
},
|
|
392
|
-
});
|
|
393
|
-
pi.registerShortcut("ctrl+shift+a", {
|
|
394
|
-
description: "Set Cognitive Routing to automatic Reasoning control",
|
|
395
|
-
handler: async (ctx) => {
|
|
396
|
-
if (typeof ctx?.isIdle === "function" && !ctx.isIdle()) {
|
|
397
|
-
ctx.ui?.notify?.("Freeflow settings and profile changes are available only while Pi is idle.", "warning");
|
|
398
|
-
return;
|
|
399
|
-
}
|
|
400
|
-
const armedCycle = routingSession.hasController() ? undefined : routingSession.cycleArmedAutomatic();
|
|
401
|
-
if (armedCycle) {
|
|
402
|
-
if (!armedCycle.changed) {
|
|
403
|
-
ctx.ui?.notify?.("Cognitive Routing automatic control active.", "info");
|
|
404
|
-
return;
|
|
405
|
-
}
|
|
406
|
-
ctx.ui?.notify?.("Cognitive Routing automatic control active.", "info");
|
|
407
|
-
routingSession.beginExplicitReactivation();
|
|
408
|
-
await applyLiveCapabilityStateForSession(ctx, {
|
|
409
|
-
reconcileCognitiveRouting: true,
|
|
410
|
-
materializeCognitiveRouting: !isPiFlowHost(pi?.host),
|
|
411
|
-
});
|
|
412
|
-
return;
|
|
413
|
-
}
|
|
414
|
-
if (!routingSession.hasController()) {
|
|
415
|
-
routingSession.beginExplicitReactivation();
|
|
416
|
-
await applyLiveCapabilityStateForSession(ctx, { reconcileCognitiveRouting: true });
|
|
417
|
-
}
|
|
418
|
-
const result = await routingSession.setAutomaticControl("profile-shortcut");
|
|
419
|
-
if (result.status === "automatic") {
|
|
420
|
-
ctx.ui?.notify?.("Cognitive Routing automatic control active.", "info");
|
|
421
|
-
} else {
|
|
422
|
-
ctx.ui?.notify?.(`Cognitive Routing could not change control: ${result.reason}.`, "warning");
|
|
423
|
-
}
|
|
424
|
-
await applyLiveCapabilityStateForSession(ctx);
|
|
425
|
-
},
|
|
426
|
-
});
|
|
427
|
-
}
|
|
428
|
-
if (!isPiFlowHost(pi?.host) && routingSession.supportsCognitiveRoutingRuntime()) {
|
|
429
|
-
pi.on("model_select", async (event, ctx) => {
|
|
430
|
-
if (!routingSession.hasController()) {
|
|
431
|
-
if (!routingSession.armed) return;
|
|
432
|
-
routingSession.clearArmed();
|
|
433
|
-
routingSession.observeArmedNativeChange(ctx, "Pi model selection");
|
|
434
|
-
await applyLiveCapabilityStateForSession(ctx);
|
|
435
|
-
return;
|
|
436
|
-
}
|
|
437
|
-
const result = await routingSession.observeNativeChange("Pi model selection", event?.source);
|
|
438
|
-
if (result.status !== "ignored") {
|
|
439
|
-
latestCognitiveRoutingContext = ctx;
|
|
440
|
-
providerSurfaceSnapshot = undefined;
|
|
441
|
-
await applyLiveCapabilityStateForSession(ctx);
|
|
442
|
-
}
|
|
443
|
-
});
|
|
444
|
-
pi.on("thinking_level_select", async (_event, ctx) => {
|
|
445
|
-
if (!routingSession.hasController()) {
|
|
446
|
-
if (!routingSession.armed) return;
|
|
447
|
-
routingSession.clearArmed();
|
|
448
|
-
routingSession.observeArmedNativeChange(ctx, "Pi thinking-level selection");
|
|
449
|
-
await applyLiveCapabilityStateForSession(ctx);
|
|
450
|
-
return;
|
|
451
|
-
}
|
|
452
|
-
const result = await routingSession.observeNativeChange("Pi thinking-level selection");
|
|
453
|
-
if (result.status !== "ignored") {
|
|
454
|
-
latestCognitiveRoutingContext = ctx;
|
|
455
|
-
providerSurfaceSnapshot = undefined;
|
|
456
|
-
await applyLiveCapabilityStateForSession(ctx);
|
|
457
|
-
}
|
|
458
|
-
});
|
|
459
|
-
}
|
|
460
182
|
pi.on("resources_discover", async (event, ctx) => {
|
|
461
|
-
const
|
|
462
|
-
|
|
463
|
-
providerSurfaceSnapshot?.context === ctx
|
|
464
|
-
? providerSurfaceSnapshot.value
|
|
465
|
-
: await buildProviderSurface(ctx ?? { cwd }, false);
|
|
466
|
-
const state = snapshot.capabilityState;
|
|
467
|
-
if (!state.configured) {
|
|
468
|
-
return { skillPaths: [freeflowSkillPath("setup-freeflow")] };
|
|
469
|
-
}
|
|
470
|
-
if (!state.enabled || !hasUsableMandatoryPrompts(snapshot.freeflowContext)) {
|
|
471
|
-
return { skillPaths: [] };
|
|
472
|
-
}
|
|
473
|
-
return { skillPaths: freeflowModelSkillPaths(state) };
|
|
183
|
+
const state = capability ?? (await loadSurface(ctx ?? { cwd: event?.cwd ?? process.cwd() }));
|
|
184
|
+
return { skillPaths: freeflowModelSkillPaths(STABLE_FREEFLOW_SURFACE) };
|
|
474
185
|
});
|
|
475
186
|
pi.on("session_start", async (event, ctx) => {
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
187
|
+
const generation = ++surfaceGeneration;
|
|
188
|
+
requestHistory.reset();
|
|
189
|
+
routing.unbind();
|
|
190
|
+
capability = undefined;
|
|
191
|
+
prompts = undefined;
|
|
192
|
+
refreshState = true;
|
|
480
193
|
restoreSessionOverrides(ctx);
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
194
|
+
const initial = await readCapabilityState(ctx.cwd, ctx, pi.host);
|
|
195
|
+
await refreshRuntimeContext(STABLE_FREEFLOW_SURFACE);
|
|
196
|
+
if (generation !== surfaceGeneration) return;
|
|
197
|
+
await loadSurface(ctx);
|
|
198
|
+
context = new FreeflowContextRuntime(ctx);
|
|
199
|
+
virtualization = new ContextVirtualizationRuntime(pi, ctx, context);
|
|
200
|
+
history = new ConversationHistoryRuntime(
|
|
484
201
|
ctx,
|
|
485
|
-
(entryId) =>
|
|
486
|
-
|
|
202
|
+
(entryId) => virtualization?.isSourceFullyProjected(entryId) ?? true,
|
|
203
|
+
context,
|
|
487
204
|
);
|
|
488
|
-
await
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
routingSession.reconcileNativeEntries(ctx);
|
|
493
|
-
const hasSessionState = sessionHasConversationOrRoutingState(ctx);
|
|
494
|
-
const snapshot = await buildProviderSurface(ctx, hasSessionState);
|
|
495
|
-
if (
|
|
496
|
-
!hasSessionState &&
|
|
497
|
-
snapshot.capabilityState?.cognitiveRouting?.effective === true &&
|
|
498
|
-
routingSession.canAutoActivate()
|
|
499
|
-
) {
|
|
500
|
-
routingSession.armFromCapability(snapshot.capabilityState.cognitiveRouting);
|
|
501
|
-
} else {
|
|
502
|
-
routingSession.clearArmed();
|
|
503
|
-
}
|
|
504
|
-
registerContextToolForState(snapshot.capabilityState);
|
|
505
|
-
const routingSnapshot = routingSession.snapshot();
|
|
506
|
-
setFreeflowStatus(
|
|
507
|
-
ctx,
|
|
508
|
-
snapshot.capabilityState,
|
|
509
|
-
snapshot.cognitiveRoutingRuntime ?? routingSnapshot.runtimeState,
|
|
510
|
-
snapshot.freeflowContext,
|
|
511
|
-
{ startupSelectionSuppressed: routingSnapshot.startupSelectionSuppressed },
|
|
512
|
-
);
|
|
513
|
-
await applyCapabilityToolVisibility(pi, ctx, snapshot.capabilityState, routingSnapshot);
|
|
205
|
+
await virtualization.recover(ctx);
|
|
206
|
+
await routing.bind(ctx, capability.cognitiveRouting, event?.reason !== "reload");
|
|
207
|
+
contextTools();
|
|
208
|
+
status(ctx);
|
|
514
209
|
});
|
|
515
|
-
pi.on("
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
210
|
+
pi.on("session_shutdown", async () => {
|
|
211
|
+
surfaceGeneration++;
|
|
212
|
+
requestHistory.reset();
|
|
213
|
+
routing.unbind();
|
|
214
|
+
context = undefined;
|
|
215
|
+
virtualization = undefined;
|
|
216
|
+
history = undefined;
|
|
217
|
+
capability = undefined;
|
|
218
|
+
prompts = undefined;
|
|
219
|
+
sessionContext = undefined;
|
|
519
220
|
});
|
|
520
|
-
pi.on("
|
|
521
|
-
await
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
221
|
+
pi.on("before_agent_start", async (event, ctx) => {
|
|
222
|
+
await update(ctx);
|
|
223
|
+
await routing.beforeRun(ctx);
|
|
224
|
+
status(ctx);
|
|
225
|
+
const text = stableRuntimeContext(prompts);
|
|
226
|
+
return { systemPrompt: text ? `${event.systemPrompt}\n\n${text}` : event.systemPrompt };
|
|
526
227
|
});
|
|
527
|
-
pi.on("
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
}
|
|
537
|
-
conversationHistoryRuntime?.setContext(ctx);
|
|
538
|
-
await applyLiveCapabilityStateForSession(ctx);
|
|
228
|
+
pi.on("message_end", (event) => routing.messageEnd(event.message));
|
|
229
|
+
pi.on("tool_call", (event, ctx) => {
|
|
230
|
+
if (
|
|
231
|
+
event.toolName === CONTEXT_VIRTUALIZATION_TOOL_NAME &&
|
|
232
|
+
!capability?.contextVirtualization?.effective &&
|
|
233
|
+
!capability?.conversationHistory?.effective
|
|
234
|
+
)
|
|
235
|
+
return { block: true, reason: "Freeflow Context is disabled." };
|
|
236
|
+
return routing.preflight(event, ctx);
|
|
539
237
|
});
|
|
540
|
-
pi.on("
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
runtimeStateRefreshRequired = true;
|
|
544
|
-
await routingSession.reconcileBranch("session-compact");
|
|
545
|
-
if (contextVirtualizationRuntime) {
|
|
546
|
-
contextVirtualizationRuntime.setContext(ctx);
|
|
547
|
-
await contextVirtualizationRuntime.recover(ctx);
|
|
548
|
-
}
|
|
549
|
-
conversationHistoryRuntime?.setContext(ctx);
|
|
550
|
-
await applyLiveCapabilityStateForSession(ctx);
|
|
238
|
+
pi.on("turn_end", async (event, ctx) => {
|
|
239
|
+
await routing.turnEnd(event, ctx);
|
|
240
|
+
status(ctx);
|
|
551
241
|
});
|
|
552
|
-
pi.on("
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
await
|
|
562
|
-
|
|
563
|
-
const systemPrompt = freeflowRuntimeContext
|
|
564
|
-
? `${event.systemPrompt}\n\n${freeflowRuntimeContext}`
|
|
565
|
-
: event.systemPrompt;
|
|
566
|
-
return { systemPrompt };
|
|
242
|
+
pi.on("agent_settled", async (_event, ctx) => {
|
|
243
|
+
await routing.settled(ctx);
|
|
244
|
+
await update(ctx);
|
|
245
|
+
});
|
|
246
|
+
pi.on("model_select", async (_event, ctx) => {
|
|
247
|
+
await routing.nativeChange(ctx);
|
|
248
|
+
status(ctx);
|
|
249
|
+
});
|
|
250
|
+
pi.on("thinking_level_select", async (_event, ctx) => {
|
|
251
|
+
await routing.nativeChange(ctx);
|
|
252
|
+
status(ctx);
|
|
567
253
|
});
|
|
568
254
|
pi.on("context", async (event, ctx) => {
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
if (
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
let messages = event.messages
|
|
576
|
-
.map((message) => {
|
|
577
|
-
const filtered = filterBootstrapMessage(message);
|
|
578
|
-
if (filtered !== message) changed = true;
|
|
579
|
-
return filtered;
|
|
580
|
-
})
|
|
581
|
-
.filter((message) => message !== undefined);
|
|
582
|
-
if (contextVirtualizationRuntime) {
|
|
583
|
-
contextVirtualizationRuntime.setContext(ctx);
|
|
584
|
-
const projected = await contextVirtualizationRuntime.project(
|
|
585
|
-
messages,
|
|
586
|
-
surfaceCapabilityState.contextVirtualization?.effective === true,
|
|
587
|
-
);
|
|
588
|
-
if (projected.changed) {
|
|
589
|
-
changed = true;
|
|
590
|
-
messages = projected.messages;
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
if (conversationHistoryRuntime && surfaceCapabilityState.conversationHistory?.effective === true) {
|
|
594
|
-
conversationHistoryRuntime.setContext(ctx);
|
|
595
|
-
conversationHistoryRuntime.capture(surfaceCapabilityState.contextVirtualization?.effective === true);
|
|
596
|
-
}
|
|
597
|
-
const forceRuntimeStateRefresh = runtimeStateRefreshRequired;
|
|
598
|
-
const nextMessages = withFreeflowRuntimeState(
|
|
599
|
-
messages,
|
|
600
|
-
surfaceCapabilityState,
|
|
601
|
-
cognitiveRoutingRuntime,
|
|
602
|
-
snapshot.freeflowContext,
|
|
603
|
-
{ force: forceRuntimeStateRefresh },
|
|
604
|
-
);
|
|
605
|
-
if (nextMessages !== messages) {
|
|
606
|
-
changed = true;
|
|
607
|
-
messages = nextMessages;
|
|
255
|
+
if (!capability) await loadSurface(ctx);
|
|
256
|
+
let messages = event.messages.map(filterBootstrapMessage).filter(Boolean);
|
|
257
|
+
if (virtualization) {
|
|
258
|
+
virtualization.setContext(ctx);
|
|
259
|
+
const projected = await virtualization.project(messages, capability.contextVirtualization.effective);
|
|
260
|
+
messages = projected.messages;
|
|
608
261
|
}
|
|
609
|
-
if (
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
pi.on("tool_call", async (event, ctx) => {
|
|
613
|
-
const capabilityState = await readCapabilityState(ctx.cwd, ctx, pi?.host);
|
|
614
|
-
const toolName = typeof event?.toolName === "string" ? event.toolName : "";
|
|
615
|
-
if (
|
|
616
|
-
capabilityState.contextVirtualization?.effective !== true &&
|
|
617
|
-
capabilityState.conversationHistory?.effective !== true &&
|
|
618
|
-
toolName === CONTEXT_VIRTUALIZATION_TOOL_NAME
|
|
619
|
-
) {
|
|
620
|
-
return disabledToolCall(toolName, "context");
|
|
262
|
+
if (history && capability.conversationHistory.effective) {
|
|
263
|
+
history.setContext(ctx);
|
|
264
|
+
history.capture(capability.contextVirtualization.effective);
|
|
621
265
|
}
|
|
622
|
-
|
|
266
|
+
messages = withFreeflowRuntimeState(messages, capability, routing.state(), prompts, {
|
|
267
|
+
force: refreshState,
|
|
268
|
+
projectionFailure: routing.state().projectionFailure,
|
|
269
|
+
});
|
|
270
|
+
refreshState = false;
|
|
271
|
+
const routed = await routing.context(ctx, messages);
|
|
272
|
+
const projected = virtualization?.decorate(routed) ?? routed;
|
|
273
|
+
const state = routing.state();
|
|
274
|
+
if (projected.some((message) => message.details?.routingRequestBlocked === true)) return { messages: projected };
|
|
275
|
+
const view = routing.projectionEnabled && state.activeProfile === "coordinator" ? "coordinator" : "ordinary";
|
|
276
|
+
return {
|
|
277
|
+
messages: await requestHistory.assemble(projected, view, ctx, (assembled) =>
|
|
278
|
+
routing.budgetNotice(assembled, ctx),
|
|
279
|
+
),
|
|
280
|
+
};
|
|
623
281
|
});
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
282
|
+
const restore = async (ctx, navigation = true) => {
|
|
283
|
+
requestHistory.reset();
|
|
284
|
+
restoreSessionOverrides(ctx);
|
|
285
|
+
refreshState = true;
|
|
286
|
+
if (virtualization) {
|
|
287
|
+
virtualization.setContext(ctx);
|
|
288
|
+
await virtualization.recover(ctx);
|
|
628
289
|
}
|
|
629
|
-
|
|
290
|
+
history?.setContext(ctx);
|
|
291
|
+
await routing.ancestryChanged(ctx, navigation);
|
|
292
|
+
await update(ctx);
|
|
293
|
+
};
|
|
294
|
+
pi.on("session_tree", async (_event, ctx) => restore(ctx));
|
|
295
|
+
pi.on("session_compact", async (_event, ctx) => restore(ctx, false));
|
|
296
|
+
pi.on("session_compact_failed", async (_event, ctx) => {
|
|
297
|
+
refreshState = true;
|
|
298
|
+
status(ctx);
|
|
630
299
|
});
|
|
631
|
-
|
|
632
|
-
pi.
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
300
|
+
if (
|
|
301
|
+
typeof pi.registerShortcut === "function" &&
|
|
302
|
+
typeof api.appendEntry === "function" &&
|
|
303
|
+
typeof api.setModel === "function" &&
|
|
304
|
+
typeof api.setThinkingLevel === "function"
|
|
305
|
+
) {
|
|
306
|
+
pi.registerShortcut("ctrl+shift+r", {
|
|
307
|
+
description: "Cycle enabled Cognitive Routing manual holds",
|
|
308
|
+
handler: async (ctx) => {
|
|
309
|
+
if (!ctx.isIdle()) {
|
|
310
|
+
ctx.ui.notify("Wait for Pi to become idle before changing control.", "warning");
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
const state = routing.state();
|
|
314
|
+
const profiles = ["coordinator", ...workersForDelegation(state.delegation)];
|
|
315
|
+
const current = profiles.indexOf(state.activeProfile ?? "coordinator");
|
|
316
|
+
const target = profiles[(current + 1) % profiles.length];
|
|
317
|
+
ctx.ui.notify(JSON.stringify(await routing.setManualProfile(target)), "info");
|
|
318
|
+
await update(ctx);
|
|
319
|
+
},
|
|
320
|
+
});
|
|
321
|
+
pi.registerShortcut("ctrl+shift+a", {
|
|
322
|
+
description: "Release manual hold to Automatic Coordinator",
|
|
323
|
+
handler: async (ctx) => {
|
|
324
|
+
if (!ctx.isIdle()) {
|
|
325
|
+
ctx.ui.notify("Wait for Pi to become idle before changing control.", "warning");
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
ctx.ui.notify(JSON.stringify(await routing.setAutomaticControl()), "info");
|
|
329
|
+
await update(ctx);
|
|
637
330
|
},
|
|
638
331
|
});
|
|
639
332
|
}
|
|
640
|
-
for (const skill of
|
|
333
|
+
for (const { command, skill } of WORKFLOW_COMMANDS)
|
|
334
|
+
pi.registerCommand(command, {
|
|
335
|
+
description: command === skill ? `Run Freeflow ${skill}` : `Run Freeflow ${skill} via ${command}`,
|
|
336
|
+
...(command === "bypass"
|
|
337
|
+
? {
|
|
338
|
+
getArgumentCompletions: (prefix) =>
|
|
339
|
+
[
|
|
340
|
+
{ value: "next", label: "next", description: "Skip one optional step" },
|
|
341
|
+
{ value: "task", label: "task", description: "Reduce optional pressure for the current task" },
|
|
342
|
+
].filter((item) => item.value.startsWith(prefix ?? "")),
|
|
343
|
+
}
|
|
344
|
+
: {}),
|
|
345
|
+
handler: (args, ctx) => sendSkillCommand(pi, ctx, skill, args),
|
|
346
|
+
});
|
|
347
|
+
for (const skill of CONTRIBUTOR_COMMANDS)
|
|
641
348
|
pi.registerCommand(skill, {
|
|
642
349
|
description: `Run Freeflow ${skill}`,
|
|
643
|
-
handler:
|
|
644
|
-
await sendSkillCommand(pi, ctx, skill, args);
|
|
645
|
-
},
|
|
350
|
+
handler: (args, ctx) => sendSkillCommand(pi, ctx, skill, args),
|
|
646
351
|
});
|
|
647
|
-
}
|
|
648
352
|
pi.registerCommand("freeflow", {
|
|
649
|
-
description: "
|
|
650
|
-
getArgumentCompletions: (prefix) =>
|
|
353
|
+
description: "Freeflow settings, status, profile control, saved-operation resume, and context tools",
|
|
354
|
+
getArgumentCompletions: (prefix) =>
|
|
355
|
+
freeflowCompletions(
|
|
356
|
+
prefix,
|
|
357
|
+
typeof api.appendEntry === "function" &&
|
|
358
|
+
typeof api.setModel === "function" &&
|
|
359
|
+
typeof api.setThinkingLevel === "function",
|
|
360
|
+
),
|
|
651
361
|
handler: async (args, ctx) => {
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
362
|
+
if (await routing.command(args ?? "", ctx)) {
|
|
363
|
+
await update(ctx);
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
const input = (args ?? "").trim();
|
|
367
|
+
if (input === "context" || input.startsWith("context ")) {
|
|
655
368
|
await handleContextCommand(
|
|
656
|
-
|
|
369
|
+
input.slice(7).trim(),
|
|
657
370
|
ctx,
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
371
|
+
virtualization,
|
|
372
|
+
capability?.contextVirtualization.effective,
|
|
373
|
+
capability?.conversationHistory.effective,
|
|
661
374
|
);
|
|
662
375
|
return;
|
|
663
376
|
}
|
|
664
|
-
|
|
665
|
-
const profileCommandContext = {
|
|
666
|
-
isIdle: ctx?.isIdle,
|
|
667
|
-
ui: ctx?.ui,
|
|
668
|
-
history: (options) => routingSession.history(options) ?? readCognitiveRoutingHistory(ctx, options),
|
|
669
|
-
};
|
|
670
|
-
const historyCommand = /^profile\s+history(?:\s|$)/i.test((args ?? "").trim());
|
|
671
|
-
if (historyCommand) {
|
|
672
|
-
await handleCognitiveRoutingProfileCommand(args, profileCommandContext, routingSession.commandController());
|
|
673
|
-
return;
|
|
674
|
-
}
|
|
675
|
-
if (!routingSession.hasController() && !routingSession.armed) {
|
|
676
|
-
routingSession.beginExplicitReactivation();
|
|
677
|
-
await applyLiveCapabilityStateForSession(ctx, { reconcileCognitiveRouting: true });
|
|
678
|
-
}
|
|
679
|
-
const profileController = routingSession.commandController();
|
|
680
|
-
if (await handleCognitiveRoutingProfileCommand(args, profileCommandContext, profileController)) {
|
|
681
|
-
if (profileController) {
|
|
682
|
-
routingSession.beginExplicitReactivation();
|
|
683
|
-
await applyLiveCapabilityStateForSession(ctx, {
|
|
684
|
-
reconcileCognitiveRouting: routingSession.armed !== undefined,
|
|
685
|
-
materializeCognitiveRouting: routingSession.armed !== undefined && !isPiFlowHost(pi?.host),
|
|
686
|
-
});
|
|
687
|
-
}
|
|
688
|
-
return;
|
|
689
|
-
}
|
|
690
|
-
}
|
|
691
|
-
await handleFreeflowCommand(
|
|
692
|
-
args,
|
|
693
|
-
ctx,
|
|
694
|
-
async (_changed, options = {}) => {
|
|
695
|
-
await applyLiveCapabilityStateForSession(ctx, {
|
|
696
|
-
reconcileCognitiveRouting: options.reconcileCognitiveRouting ?? true,
|
|
697
|
-
});
|
|
698
|
-
},
|
|
699
|
-
pi,
|
|
700
|
-
routingSession.commandController(),
|
|
701
|
-
);
|
|
377
|
+
await handleFreeflowCommand(args, ctx, async () => update(ctx), pi, routing);
|
|
702
378
|
},
|
|
703
379
|
});
|
|
704
380
|
}
|