@hassangameryt/freeflow 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +2 -1
- package/.codex-plugin/plugin.json +2 -1
- package/README.md +150 -155
- package/capabilities/cognitive-routing/SKILL.md +229 -0
- package/capabilities/context-virtualization/SKILL.md +103 -0
- package/capabilities/conversation-history/SKILL.md +53 -0
- package/command-surface.json +17 -13
- package/hooks/freeflow-runtime-context.mjs +393 -159
- package/hooks/hooks.json +26 -1
- package/hooks/tests/check-runtime-context-hook.sh +223 -54
- package/package.json +25 -16
- package/pi-extension/dist/cognitive-routing/commands.js +96 -0
- package/pi-extension/dist/cognitive-routing/config.js +236 -0
- package/pi-extension/dist/cognitive-routing/controller.js +862 -0
- package/pi-extension/dist/cognitive-routing/history.js +439 -0
- package/pi-extension/dist/cognitive-routing/host.js +126 -0
- package/pi-extension/dist/cognitive-routing/runtime.js +43 -0
- package/pi-extension/dist/cognitive-routing/tool.js +211 -0
- package/pi-extension/dist/cognitive-routing/types.js +6 -0
- package/pi-extension/dist/context-virtualization/commands.js +89 -0
- package/pi-extension/dist/context-virtualization/projector.js +42 -0
- package/pi-extension/dist/context-virtualization/runtime.js +356 -0
- package/pi-extension/dist/context-virtualization/state.js +57 -0
- package/pi-extension/dist/context-virtualization/types.js +10 -0
- package/pi-extension/dist/conversation-history/passages.js +66 -0
- package/pi-extension/dist/conversation-history/ranking.js +105 -0
- package/pi-extension/dist/conversation-history/runtime.js +226 -0
- package/pi-extension/dist/conversation-history/search.js +56 -0
- package/pi-extension/dist/conversation-history/types.js +1 -0
- package/pi-extension/dist/freeflow-context/resolver.js +120 -0
- package/pi-extension/dist/freeflow-context/runtime.js +80 -0
- package/pi-extension/dist/freeflow-context/source-projector.js +95 -0
- package/pi-extension/dist/freeflow-context/tool.js +308 -0
- package/pi-extension/dist/freeflow-context/types.js +12 -0
- package/pi-extension/dist/freeflow-context/visibility.js +28 -0
- package/pi-extension/dist/index.js +516 -98
- package/pi-extension/dist/runtime/runtime-context.js +318 -271
- package/pi-extension/dist/runtime/runtime-identity.js +5 -0
- package/pi-extension/dist/settings/settings-tui.js +78 -0
- package/pi-extension/dist/settings/settings-ui.js +593 -563
- package/pi-extension/dist/ui/text-component.js +57 -0
- package/pi-extension/src/cognitive-routing/commands.ts +119 -0
- package/pi-extension/src/cognitive-routing/config.ts +307 -0
- package/pi-extension/src/cognitive-routing/controller.ts +1118 -0
- package/pi-extension/src/cognitive-routing/history.ts +638 -0
- package/pi-extension/src/cognitive-routing/host.ts +172 -0
- package/pi-extension/src/cognitive-routing/runtime.ts +57 -0
- package/pi-extension/src/cognitive-routing/tool.ts +272 -0
- package/pi-extension/src/cognitive-routing/types.ts +89 -0
- package/pi-extension/src/context-virtualization/commands.ts +111 -0
- package/pi-extension/src/context-virtualization/projector.ts +62 -0
- package/pi-extension/src/context-virtualization/runtime.ts +406 -0
- package/pi-extension/src/context-virtualization/state.ts +79 -0
- package/pi-extension/src/context-virtualization/types.ts +92 -0
- package/pi-extension/src/conversation-history/passages.ts +81 -0
- package/pi-extension/src/conversation-history/ranking.ts +155 -0
- package/pi-extension/src/conversation-history/runtime.ts +250 -0
- package/pi-extension/src/conversation-history/search.ts +79 -0
- package/pi-extension/src/conversation-history/types.ts +31 -0
- package/pi-extension/src/freeflow-context/resolver.ts +139 -0
- package/pi-extension/src/freeflow-context/runtime.ts +100 -0
- package/pi-extension/src/freeflow-context/source-projector.ts +106 -0
- package/pi-extension/src/freeflow-context/tool.ts +360 -0
- package/pi-extension/src/freeflow-context/types.ts +70 -0
- package/pi-extension/src/freeflow-context/visibility.ts +53 -0
- package/pi-extension/src/index.ts +553 -101
- package/pi-extension/src/runtime/runtime-context.ts +339 -281
- package/pi-extension/src/runtime/runtime-identity.ts +8 -0
- package/pi-extension/src/settings/settings-tui.ts +93 -0
- package/pi-extension/src/settings/settings-ui.ts +700 -613
- package/pi-extension/src/ui/text-component.ts +66 -0
- package/pi-extension/tests/cognitive-routing/commands.test.js +134 -0
- package/pi-extension/tests/cognitive-routing/controller.test.js +1099 -0
- package/pi-extension/tests/cognitive-routing/extension-lifecycle.test.js +1071 -0
- package/pi-extension/tests/cognitive-routing/history.test.js +274 -0
- package/pi-extension/tests/cognitive-routing/host-fixture.js +4 -0
- package/pi-extension/tests/cognitive-routing/host-identity.test.js +63 -0
- package/pi-extension/tests/cognitive-routing/profile-resolution.test.js +236 -0
- package/pi-extension/tests/cognitive-routing/tool.test.js +230 -0
- package/pi-extension/tests/context-virtualization/extension.test.js +749 -0
- package/pi-extension/tests/context-virtualization/projector.test.js +110 -0
- package/pi-extension/tests/context-virtualization/runtime.test.js +216 -0
- package/pi-extension/tests/conversation-history/runtime.test.js +98 -0
- package/pi-extension/tests/conversation-history/search.test.js +97 -0
- package/pi-extension/tests/integration/pi-extension.test.js +928 -2047
- package/pi-extension/tests/integration/prompt-architecture.test.js +305 -0
- package/runtime/prompts/cognitive-routing.md +9 -0
- package/runtime/prompts/context-virtualization.md +3 -0
- package/runtime/prompts/conversation-history.md +3 -0
- package/runtime/prompts/core.md +13 -0
- package/runtime/prompts/interaction-contract.md +7 -0
- package/runtime/prompts/skills.md +65 -0
- package/skills/action-selection/SKILL.md +91 -0
- package/skills/bypass/SKILL.md +3 -2
- package/skills/commit-work/SKILL.md +1 -1
- package/skills/commit-work/references/staging-decisions.md +1 -1
- package/skills/decision-gate/SKILL.md +1 -1
- package/skills/design-for-depth/SKILL.md +14 -33
- package/skills/design-for-depth/references/design-pressure-signals.md +1 -1
- package/skills/design-for-depth/references/interface-design-loop.md +1 -1
- package/skills/design-for-depth/references/software-design-philosophy.md +1 -1
- package/skills/diagnose-failure/SKILL.md +20 -14
- package/skills/diagnose-failure/references/diagnostic-loop-catalog.md +1 -3
- package/skills/diagnose-failure/references/{flaky-and-performance.md → flaky-and-performance-diagnosis.md} +1 -1
- package/skills/discuss/SKILL.md +34 -22
- package/skills/discuss/references/discussion-continuity.md +71 -0
- package/skills/evaluate-skill/SKILL.md +5 -5
- package/skills/evaluate-skill/references/{definition-schema.md → evaluation-definition-schema.md} +42 -2
- package/skills/evaluate-skill/references/execution-and-evidence.md +8 -3
- package/skills/evaluate-skill/scripts/lib/definitions.mjs +114 -3
- package/skills/evaluate-skill/scripts/lib/grade-interaction.mjs +156 -1
- package/skills/evaluate-skill/scripts/lib/grade.mjs +9 -1
- package/skills/evaluate-skill/scripts/lib/pi.mjs +147 -32
- package/skills/evaluate-skill/scripts/lib/rpc.mjs +4 -4
- package/skills/evaluate-skill/scripts/lib/runner.mjs +36 -14
- package/skills/evaluate-skill/scripts/lib/sandbox.mjs +92 -0
- package/skills/evaluate-skill/scripts/pi-guard.mjs +1 -1
- package/skills/evaluate-skill/scripts/pi-observer.mjs +66 -0
- package/skills/evaluate-skill/scripts/skill-eval.mjs +6 -5
- package/skills/execute-work/SKILL.md +18 -15
- package/skills/execute-work/references/code-practices.md +1 -1
- package/skills/execute-work/references/execute-work-edges.md +42 -0
- package/skills/finish-branch/SKILL.md +2 -2
- package/skills/finish-branch/references/integration-options.md +1 -1
- package/skills/handoff/SKILL.md +3 -3
- package/skills/launch-work/SKILL.md +1 -1
- package/skills/launch-work/references/launch-readiness.md +2 -2
- package/skills/migration-work/SKILL.md +2 -2
- package/skills/migration-work/references/migration-lifecycle.md +1 -1
- package/skills/mode-contract/SKILL.md +32 -10
- package/skills/release-work/SKILL.md +1 -1
- package/skills/release-work/references/release-evidence.md +1 -1
- package/skills/review-artifact/SKILL.md +28 -26
- package/skills/review-work/SKILL.md +28 -26
- package/skills/review-work/references/{reviewer-prompt.md → independent-work-reviewer-contract.md} +1 -1
- package/skills/review-work/references/security-risk-lens.md +1 -1
- package/skills/setup-freeflow/SKILL.md +6 -10
- package/skills/setup-freeflow/references/activation-contract.md +5 -10
- package/skills/setup-freeflow/references/host-setup.md +3 -7
- package/skills/simplify-code/SKILL.md +1 -1
- package/skills/simplify-code/references/simplification-patterns.md +1 -1
- package/skills/tdd/SKILL.md +18 -38
- package/skills/tdd/references/test-design.md +2 -2
- package/skills/track-work/SKILL.md +362 -58
- package/skills/track-work/scripts/lib/codec.mjs +570 -0
- package/skills/track-work/scripts/lib/commands.mjs +568 -0
- package/skills/track-work/scripts/lib/contract.mjs +303 -0
- package/skills/track-work/scripts/lib/model.mjs +506 -0
- package/skills/track-work/scripts/lib/operations.mjs +965 -0
- package/skills/track-work/scripts/lib/record-store.mjs +264 -0
- package/skills/track-work/scripts/lib/result.mjs +37 -0
- package/skills/track-work/scripts/lib/rewrites.mjs +740 -0
- package/skills/track-work/scripts/lib/schema.mjs +277 -0
- package/skills/track-work/scripts/lib/source-inventory.mjs +162 -0
- package/skills/track-work/scripts/lib/views.mjs +443 -0
- package/skills/track-work/scripts/lib/workspace.mjs +134 -0
- package/skills/track-work/scripts/working-record.mjs +122 -0
- package/skills/verify-work/SKILL.md +14 -2
- package/skills/verify-work/references/browser-runtime-evidence.md +1 -1
- package/skills/verify-work/references/integration-evidence.md +1 -1
- package/skills/verify-work/references/performance-evidence.md +1 -1
- package/skills/workflow/SKILL.md +105 -53
- package/skills/workflow/references/domain-skill-composition.md +22 -42
- package/skills/write-plan/SKILL.md +1 -1
- package/skills/write-skill/SKILL.md +3 -2
- package/skills/write-skill/references/progressive-disclosure.md +17 -3
- package/pi-extension/dist/output-router/host-producer-identification.js +0 -232
- package/pi-extension/dist/output-router/native-safety-net.js +0 -216
- package/pi-extension/dist/output-router/observed-tool-routing.js +0 -122
- package/pi-extension/dist/output-router/renderers.js +0 -1023
- package/pi-extension/dist/output-router/router-tools.js +0 -554
- package/pi-extension/dist/output-router/schemas.js +0 -383
- package/pi-extension/dist/output-router/status.js +0 -744
- package/pi-extension/dist/output-router/utils.js +0 -502
- package/pi-extension/src/output-router/host-producer-identification.ts +0 -256
- package/pi-extension/src/output-router/native-safety-net.ts +0 -248
- package/pi-extension/src/output-router/observed-tool-routing.ts +0 -134
- package/pi-extension/src/output-router/renderers.ts +0 -1108
- package/pi-extension/src/output-router/router-tools.ts +0 -579
- package/pi-extension/src/output-router/schemas.ts +0 -387
- package/pi-extension/src/output-router/status.ts +0 -791
- package/pi-extension/src/output-router/utils.ts +0 -554
- package/pi-extension/tests/output-router/observed-producers.test.js +0 -132
- package/pi-extension/tests/output-router/search.test.js +0 -722
- package/router/dist/benchmarks/benchmark-harness.d.ts +0 -35
- package/router/dist/benchmarks/benchmark-harness.js +0 -92
- package/router/dist/benchmarks/benchmarks.d.ts +0 -109
- package/router/dist/benchmarks/benchmarks.js +0 -979
- package/router/dist/benchmarks/codex-qa-benchmarks.d.ts +0 -95
- package/router/dist/benchmarks/codex-qa-benchmarks.js +0 -500
- package/router/dist/benchmarks/command-benchmarks.d.ts +0 -143
- package/router/dist/benchmarks/command-benchmarks.js +0 -698
- package/router/dist/benchmarks/context-mode-normalized-benchmarks.d.ts +0 -82
- package/router/dist/benchmarks/context-mode-normalized-benchmarks.js +0 -773
- package/router/dist/benchmarks/context-mode-real-deep-benchmark.d.ts +0 -132
- package/router/dist/benchmarks/context-mode-real-deep-benchmark.js +0 -1380
- package/router/dist/benchmarks/context-saving-baseline.d.ts +0 -60
- package/router/dist/benchmarks/context-saving-baseline.js +0 -470
- package/router/dist/benchmarks/index-benchmarks.d.ts +0 -103
- package/router/dist/benchmarks/index-benchmarks.js +0 -862
- package/router/dist/benchmarks/storage-policy-benchmarks.d.ts +0 -101
- package/router/dist/benchmarks/storage-policy-benchmarks.js +0 -618
- package/router/dist/benchmarks/vault-index-benchmarks.d.ts +0 -56
- package/router/dist/benchmarks/vault-index-benchmarks.js +0 -322
- package/router/dist/config/config.d.ts +0 -103
- package/router/dist/config/config.js +0 -632
- package/router/dist/config/router-contract.d.ts +0 -10
- package/router/dist/config/router-contract.js +0 -54
- package/router/dist/config/schema.d.ts +0 -27
- package/router/dist/config/schema.js +0 -648
- package/router/dist/config/types.d.ts +0 -573
- package/router/dist/config/types.js +0 -41
- package/router/dist/evidence/bounded-evidence.d.ts +0 -40
- package/router/dist/evidence/bounded-evidence.js +0 -323
- package/router/dist/evidence/evidence-range-selector.d.ts +0 -24
- package/router/dist/evidence/evidence-range-selector.js +0 -232
- package/router/dist/evidence/evidence-search.d.ts +0 -27
- package/router/dist/evidence/evidence-search.js +0 -490
- package/router/dist/evidence/evidence.d.ts +0 -38
- package/router/dist/evidence/evidence.js +0 -200
- package/router/dist/evidence/failure-contracts.d.ts +0 -37
- package/router/dist/evidence/failure-contracts.js +0 -166
- package/router/dist/evidence/line-ranges.d.ts +0 -24
- package/router/dist/evidence/line-ranges.js +0 -22
- package/router/dist/experiments/local-index.d.ts +0 -64
- package/router/dist/experiments/local-index.js +0 -581
- package/router/dist/index.d.ts +0 -30
- package/router/dist/index.js +0 -32
- package/router/dist/local/local-traversal.d.ts +0 -18
- package/router/dist/local/local-traversal.js +0 -334
- package/router/dist/processing/engine.d.ts +0 -132
- package/router/dist/processing/engine.js +0 -533
- package/router/dist/processing/reducers.d.ts +0 -280
- package/router/dist/processing/reducers.js +0 -1673
- package/router/dist/processing/renderers.d.ts +0 -31
- package/router/dist/processing/renderers.js +0 -195
- package/router/dist/processing/scripts.d.ts +0 -91
- package/router/dist/processing/scripts.js +0 -386
- package/router/dist/repo/repo-traversal.d.ts +0 -18
- package/router/dist/repo/repo-traversal.js +0 -245
- package/router/dist/routing/observed-reducers.d.ts +0 -41
- package/router/dist/routing/observed-reducers.js +0 -661
- package/router/dist/routing/observed-routing.d.ts +0 -26
- package/router/dist/routing/observed-routing.js +0 -378
- package/router/dist/routing/parsers.d.ts +0 -16
- package/router/dist/routing/parsers.js +0 -521
- package/router/dist/routing/run-filters.d.ts +0 -60
- package/router/dist/routing/run-filters.js +0 -238
- package/router/dist/routing/run-reducers.d.ts +0 -49
- package/router/dist/routing/run-reducers.js +0 -122
- package/router/dist/sandbox/adapter-roots.d.ts +0 -46
- package/router/dist/sandbox/adapter-roots.js +0 -66
- package/router/dist/sandbox/eryx-python-adapter.d.ts +0 -13
- package/router/dist/sandbox/eryx-python-adapter.js +0 -868
- package/router/dist/sandbox/jq-wasm-adapter.d.ts +0 -9
- package/router/dist/sandbox/jq-wasm-adapter.js +0 -429
- package/router/dist/sandbox/quickjs-wasi-adapter.d.ts +0 -13
- package/router/dist/sandbox/quickjs-wasi-adapter.js +0 -384
- package/router/dist/sandbox/script-sandbox.d.ts +0 -134
- package/router/dist/sandbox/script-sandbox.js +0 -337
- package/router/dist/setup/script-transform-adapters.d.ts +0 -32
- package/router/dist/setup/script-transform-adapters.js +0 -278
- package/router/dist/tools/batch.d.ts +0 -33
- package/router/dist/tools/batch.js +0 -586
- package/router/dist/tools/run.d.ts +0 -62
- package/router/dist/tools/run.js +0 -1304
- package/router/dist/tools/search.d.ts +0 -66
- package/router/dist/tools/search.js +0 -1364
- package/router/dist/transform/engine.d.ts +0 -168
- package/router/dist/transform/engine.js +0 -2072
- package/router/dist/vault/vault-index.d.ts +0 -125
- package/router/dist/vault/vault-index.js +0 -416
- package/router/dist/vault/vault.d.ts +0 -138
- package/router/dist/vault/vault.js +0 -630
- package/runtime/interaction-contract.md +0 -16
- package/skills/discuss/references/checkpoints.md +0 -66
- package/skills/execute-work/references/execution-loop.md +0 -77
- package/skills/output-router/SKILL.md +0 -206
- package/skills/output-router/references/safety-policy.md +0 -40
- package/skills/setup-freeflow/references/output-router-setup.md +0 -110
- package/skills/track-work/references/working-record-schema.md +0 -378
- package/skills/workflow/references/workflow-loop.md +0 -92
- /package/skills/handoff/references/{templates.md → handoff-templates.md} +0 -0
- /package/skills/review-artifact/references/{reviewer-prompt.md → independent-artifact-reviewer-contract.md} +0 -0
|
@@ -2,19 +2,19 @@ import { readFile } from "node:fs/promises";
|
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { resolveCognitiveRoutingState } from "../cognitive-routing/runtime.js";
|
|
6
|
+
import { isPiFlowHost } from "./runtime-identity.js";
|
|
6
7
|
|
|
7
8
|
export const VALID_MODES = new Set(["conversation", "workflow", "strict-workflow"]);
|
|
8
9
|
|
|
9
10
|
export const WORKFLOW_COMMANDS = [
|
|
10
11
|
{ command: "discuss", skill: "discuss" },
|
|
11
|
-
{ command: "
|
|
12
|
+
{ command: "action-selection", skill: "action-selection" },
|
|
12
13
|
{ command: "track-work", skill: "track-work" },
|
|
13
14
|
{ command: "write-spec", skill: "write-spec" },
|
|
14
15
|
{ command: "review-artifact", skill: "review-artifact" },
|
|
15
16
|
{ command: "write-plan", skill: "write-plan" },
|
|
16
17
|
{ command: "execute-work", skill: "execute-work" },
|
|
17
|
-
{ command: "execute-plan", skill: "execute-work" },
|
|
18
18
|
{ command: "simplify-code", skill: "simplify-code" },
|
|
19
19
|
{ command: "migration-work", skill: "migration-work" },
|
|
20
20
|
{ command: "diagnose-failure", skill: "diagnose-failure" },
|
|
@@ -31,6 +31,7 @@ export const WORKFLOW_COMMANDS = [
|
|
|
31
31
|
export const CONTRIBUTOR_COMMANDS = ["setup-freeflow", "write-skill", "evaluate-skill"];
|
|
32
32
|
|
|
33
33
|
export const FREEFLOW_MODEL_SKILL_NAMES = [
|
|
34
|
+
"action-selection",
|
|
34
35
|
"bypass",
|
|
35
36
|
"commit-work",
|
|
36
37
|
"decision-gate",
|
|
@@ -58,63 +59,121 @@ export const FREEFLOW_MODEL_SKILL_NAMES = [
|
|
|
58
59
|
"write-spec",
|
|
59
60
|
];
|
|
60
61
|
|
|
62
|
+
export const FREEFLOW_CAPABILITY_SKILL_NAMES = ["cognitive-routing", "context-virtualization", "conversation-history"];
|
|
63
|
+
|
|
61
64
|
export function freeflowSkillPath(skillName) {
|
|
62
65
|
return fileURLToPath(new URL(`../../../skills/${skillName}/SKILL.md`, import.meta.url));
|
|
63
66
|
}
|
|
64
67
|
|
|
65
|
-
export function
|
|
66
|
-
return
|
|
68
|
+
export function freeflowCapabilitySkillPath(skillName) {
|
|
69
|
+
return fileURLToPath(new URL(`../../../capabilities/${skillName}/SKILL.md`, import.meta.url));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function freeflowModelSkillPaths(capabilityState = undefined) {
|
|
73
|
+
const paths = FREEFLOW_MODEL_SKILL_NAMES.map((skillName) => freeflowSkillPath(skillName));
|
|
74
|
+
const capabilityStates = {
|
|
75
|
+
"cognitive-routing": capabilityState?.cognitiveRouting,
|
|
76
|
+
"context-virtualization": capabilityState?.contextVirtualization,
|
|
77
|
+
"conversation-history": capabilityState?.conversationHistory,
|
|
78
|
+
};
|
|
79
|
+
for (const skillName of FREEFLOW_CAPABILITY_SKILL_NAMES) {
|
|
80
|
+
if (capabilityStates[skillName]?.effective === true) {
|
|
81
|
+
paths.push(freeflowCapabilitySkillPath(skillName));
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return paths;
|
|
67
85
|
}
|
|
68
86
|
|
|
69
|
-
type SessionCoreKey =
|
|
87
|
+
type SessionCoreKey =
|
|
88
|
+
"enabled" | "interactionContract" | "skillsEnabled" | "contextVirtualization" | "conversationHistory";
|
|
70
89
|
type SessionCoreOverrides = Partial<Record<SessionCoreKey, boolean>>;
|
|
71
90
|
|
|
72
91
|
const MODE_STATE_ENTRY = "freeflow-mode";
|
|
73
92
|
const SESSION_OVERRIDES_ENTRY = "freeflow-session-overrides";
|
|
74
|
-
const SESSION_CORE_KEYS = new Set<SessionCoreKey>([
|
|
93
|
+
const SESSION_CORE_KEYS = new Set<SessionCoreKey>([
|
|
94
|
+
"enabled",
|
|
95
|
+
"interactionContract",
|
|
96
|
+
"skillsEnabled",
|
|
97
|
+
"contextVirtualization",
|
|
98
|
+
"conversationHistory",
|
|
99
|
+
]);
|
|
75
100
|
const RESET_MODE_ARGS = new Set(["reset"]);
|
|
76
101
|
|
|
77
|
-
export const
|
|
78
|
-
export const
|
|
102
|
+
export const COGNITIVE_ROUTING_SWITCH_TOOL_NAME = "freeflow_switch_profile";
|
|
103
|
+
export const FREEFLOW_RUNTIME_STATE_MESSAGE_TYPE = "freeflow-runtime-state";
|
|
104
|
+
export const COGNITIVE_ROUTING_RUNTIME_STATE_MESSAGE_TYPE = "freeflow-cognitive-routing-runtime-state";
|
|
79
105
|
export const WORKFLOW_BOOTSTRAP_MESSAGE_TYPE = "freeflow-workflow-bootstrap";
|
|
106
|
+
export const COGNITIVE_ROUTING_BOOTSTRAP_MESSAGE_TYPE = "freeflow-cognitive-routing-bootstrap";
|
|
107
|
+
export const FREEFLOW_BOOTSTRAP_MESSAGE_TYPE = "freeflow-bootstrap";
|
|
80
108
|
|
|
81
109
|
let runtimeContextCache = null;
|
|
82
110
|
let currentModeOverride = null;
|
|
83
111
|
let currentSessionOverrides: SessionCoreOverrides = {};
|
|
84
|
-
|
|
112
|
+
|
|
113
|
+
async function readPromptFile(url: URL): Promise<string | null> {
|
|
114
|
+
try {
|
|
115
|
+
return await readFile(url, "utf8");
|
|
116
|
+
} catch {
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
85
121
|
async function loadRuntimeContext(capabilityState = undefined) {
|
|
122
|
+
const freeflowEnabled = capabilityState?.enabled === true;
|
|
86
123
|
const interactionContractEnabled = capabilityState?.interactionContract?.effective === true;
|
|
87
124
|
const skillsEnabled = capabilityState?.skills?.effective === true;
|
|
88
|
-
const
|
|
89
|
-
const
|
|
125
|
+
const contextVirtualizationEnabled = capabilityState?.contextVirtualization?.effective === true;
|
|
126
|
+
const conversationHistoryEnabled = capabilityState?.conversationHistory?.effective === true;
|
|
127
|
+
const cognitiveRoutingEnabled = capabilityState?.cognitiveRouting?.effective === true;
|
|
128
|
+
const [
|
|
129
|
+
corePrompt,
|
|
130
|
+
interactionContractPrompt,
|
|
131
|
+
skillsPrompt,
|
|
132
|
+
cognitiveRoutingPrompt,
|
|
133
|
+
contextVirtualizationPrompt,
|
|
134
|
+
conversationHistoryPrompt,
|
|
135
|
+
] = await Promise.all([
|
|
136
|
+
freeflowEnabled
|
|
137
|
+
? readPromptFile(new URL("../../../runtime/prompts/core.md", import.meta.url))
|
|
138
|
+
: Promise.resolve(null),
|
|
90
139
|
interactionContractEnabled
|
|
91
|
-
?
|
|
140
|
+
? readPromptFile(new URL("../../../runtime/prompts/interaction-contract.md", import.meta.url))
|
|
92
141
|
: Promise.resolve(null),
|
|
93
142
|
skillsEnabled
|
|
94
|
-
?
|
|
143
|
+
? readPromptFile(new URL("../../../runtime/prompts/skills.md", import.meta.url))
|
|
144
|
+
: Promise.resolve(null),
|
|
145
|
+
cognitiveRoutingEnabled
|
|
146
|
+
? readPromptFile(new URL("../../../runtime/prompts/cognitive-routing.md", import.meta.url))
|
|
95
147
|
: Promise.resolve(null),
|
|
96
|
-
|
|
97
|
-
?
|
|
148
|
+
contextVirtualizationEnabled
|
|
149
|
+
? readPromptFile(new URL("../../../runtime/prompts/context-virtualization.md", import.meta.url))
|
|
150
|
+
: Promise.resolve(null),
|
|
151
|
+
conversationHistoryEnabled
|
|
152
|
+
? readPromptFile(new URL("../../../runtime/prompts/conversation-history.md", import.meta.url))
|
|
98
153
|
: Promise.resolve(null),
|
|
99
154
|
]);
|
|
100
155
|
|
|
101
|
-
return {
|
|
156
|
+
return {
|
|
157
|
+
corePrompt,
|
|
158
|
+
interactionContractPrompt,
|
|
159
|
+
skillsPrompt,
|
|
160
|
+
cognitiveRoutingPrompt,
|
|
161
|
+
contextVirtualizationPrompt,
|
|
162
|
+
conversationHistoryPrompt,
|
|
163
|
+
};
|
|
102
164
|
}
|
|
103
165
|
|
|
104
166
|
function runtimeContextCacheSatisfies(capabilityState) {
|
|
105
|
-
if (!runtimeContextCache)
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
return false;
|
|
116
|
-
}
|
|
117
|
-
return true;
|
|
167
|
+
if (!runtimeContextCache) return false;
|
|
168
|
+
const expected = {
|
|
169
|
+
corePrompt: capabilityState?.enabled === true,
|
|
170
|
+
interactionContractPrompt: capabilityState?.interactionContract?.effective === true,
|
|
171
|
+
skillsPrompt: capabilityState?.skills?.effective === true,
|
|
172
|
+
cognitiveRoutingPrompt: capabilityState?.cognitiveRouting?.effective === true,
|
|
173
|
+
contextVirtualizationPrompt: capabilityState?.contextVirtualization?.effective === true,
|
|
174
|
+
conversationHistoryPrompt: capabilityState?.conversationHistory?.effective === true,
|
|
175
|
+
};
|
|
176
|
+
return Object.entries(expected).every(([key, required]) => !required || Boolean(runtimeContextCache[key]));
|
|
118
177
|
}
|
|
119
178
|
|
|
120
179
|
export async function refreshRuntimeContext(capabilityState = undefined) {
|
|
@@ -129,44 +188,34 @@ export async function getRuntimeContext(capabilityState = undefined) {
|
|
|
129
188
|
return refreshRuntimeContext(capabilityState);
|
|
130
189
|
}
|
|
131
190
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
if (Array.isArray(entries)) {
|
|
137
|
-
return entries;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
if (typeof sessionManager?.getEntries === "function") {
|
|
141
|
-
const entries = sessionManager.getEntries();
|
|
142
|
-
if (Array.isArray(entries)) {
|
|
143
|
-
return entries;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
} catch {
|
|
147
|
-
// A missing session snapshot should reload useful context rather than suppress it.
|
|
148
|
-
}
|
|
149
|
-
return [];
|
|
150
|
-
}
|
|
191
|
+
const BOOTSTRAP_COMPONENTS = Object.freeze({
|
|
192
|
+
workflow: "workflow",
|
|
193
|
+
cognitiveRouting: "cognitive-routing",
|
|
194
|
+
});
|
|
151
195
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
196
|
+
function bootstrapEntryComponents(entry) {
|
|
197
|
+
const isCustomMessage = entry?.role === "custom" || entry?.type === "custom_message" || entry?.type === "custom";
|
|
198
|
+
if (!isCustomMessage) return [];
|
|
199
|
+
if (entry.customType === FREEFLOW_BOOTSTRAP_MESSAGE_TYPE) {
|
|
200
|
+
if (Array.isArray(entry.details?.components)) return entry.details.components;
|
|
201
|
+
return [
|
|
202
|
+
...(entry.content?.includes("<!-- freeflow-bootstrap:workflow -->") ? [BOOTSTRAP_COMPONENTS.workflow] : []),
|
|
203
|
+
...(entry.content?.includes("<!-- freeflow-bootstrap:cognitive-routing -->")
|
|
204
|
+
? [BOOTSTRAP_COMPONENTS.cognitiveRouting]
|
|
205
|
+
: []),
|
|
206
|
+
];
|
|
155
207
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
)
|
|
160
|
-
|
|
161
|
-
return undefined;
|
|
208
|
+
if (entry.customType === WORKFLOW_BOOTSTRAP_MESSAGE_TYPE) {
|
|
209
|
+
return [BOOTSTRAP_COMPONENTS.workflow];
|
|
210
|
+
}
|
|
211
|
+
if (entry.customType === COGNITIVE_ROUTING_BOOTSTRAP_MESSAGE_TYPE) {
|
|
212
|
+
return [BOOTSTRAP_COMPONENTS.cognitiveRouting];
|
|
162
213
|
}
|
|
214
|
+
return [];
|
|
215
|
+
}
|
|
163
216
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
content: `# Freeflow Workflow Bootstrap\n\n${freeflowContext.workflowSkill.trim()}`,
|
|
167
|
-
display: false,
|
|
168
|
-
details: { skill: "workflow", source: "first-turn-bootstrap" },
|
|
169
|
-
};
|
|
217
|
+
export function filterBootstrapMessage(message) {
|
|
218
|
+
return bootstrapEntryComponents(message).length === 0 ? message : undefined;
|
|
170
219
|
}
|
|
171
220
|
|
|
172
221
|
function isRecord(value) {
|
|
@@ -182,6 +231,14 @@ function validateCoreConfigFields(value) {
|
|
|
182
231
|
return "enabled must be a boolean";
|
|
183
232
|
}
|
|
184
233
|
|
|
234
|
+
if (value.contextVirtualization !== undefined && typeof value.contextVirtualization !== "boolean") {
|
|
235
|
+
return "contextVirtualization must be a boolean";
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if (value.conversationHistory !== undefined && typeof value.conversationHistory !== "boolean") {
|
|
239
|
+
return "conversationHistory must be a boolean";
|
|
240
|
+
}
|
|
241
|
+
|
|
185
242
|
if (value.interactionContract !== undefined && typeof value.interactionContract !== "boolean") {
|
|
186
243
|
return "interactionContract must be a boolean";
|
|
187
244
|
}
|
|
@@ -208,6 +265,7 @@ function validateFreeflowConfigShape(value) {
|
|
|
208
265
|
return "config must be a JSON object";
|
|
209
266
|
}
|
|
210
267
|
|
|
268
|
+
// Keep retired capability keys shape-tolerated so existing repositories remain activated; runtime behavior ignores them.
|
|
211
269
|
const allowedKeys = new Set([
|
|
212
270
|
"enabled",
|
|
213
271
|
"defaultMode",
|
|
@@ -216,6 +274,9 @@ function validateFreeflowConfigShape(value) {
|
|
|
216
274
|
"outputRouter",
|
|
217
275
|
"observedRouting",
|
|
218
276
|
"scriptTransform",
|
|
277
|
+
"cognitiveRouting",
|
|
278
|
+
"contextVirtualization",
|
|
279
|
+
"conversationHistory",
|
|
219
280
|
]);
|
|
220
281
|
for (const key of Object.keys(value)) {
|
|
221
282
|
if (!allowedKeys.has(key)) {
|
|
@@ -240,7 +301,16 @@ function validateFreeflowLocalConfigShape(value) {
|
|
|
240
301
|
return "local config must be a JSON object";
|
|
241
302
|
}
|
|
242
303
|
|
|
243
|
-
const allowedKeys = new Set([
|
|
304
|
+
const allowedKeys = new Set([
|
|
305
|
+
"enabled",
|
|
306
|
+
"defaultMode",
|
|
307
|
+
"interactionContract",
|
|
308
|
+
"skills",
|
|
309
|
+
"processing",
|
|
310
|
+
"cognitiveRouting",
|
|
311
|
+
"contextVirtualization",
|
|
312
|
+
"conversationHistory",
|
|
313
|
+
]);
|
|
244
314
|
for (const key of Object.keys(value)) {
|
|
245
315
|
if (!allowedKeys.has(key)) {
|
|
246
316
|
return `unsupported top-level local config key: ${key}`;
|
|
@@ -318,6 +388,8 @@ function resolveLayeredValue(repository, local, key, fallback) {
|
|
|
318
388
|
function resolveCoreConfig(repository, local) {
|
|
319
389
|
const enabled = resolveLayeredValue(repository, local, "enabled", true);
|
|
320
390
|
const interactionContract = resolveLayeredValue(repository, local, "interactionContract", true);
|
|
391
|
+
const contextVirtualization = resolveLayeredValue(repository, local, "contextVirtualization", false);
|
|
392
|
+
const conversationHistory = resolveLayeredValue(repository, local, "conversationHistory", false);
|
|
321
393
|
const defaultMode = resolveLayeredValue(repository, local, "defaultMode", "workflow");
|
|
322
394
|
const repositorySkills = isRecord(repository.skills) ? repository.skills : {};
|
|
323
395
|
const localSkills = isRecord(local.skills) ? local.skills : {};
|
|
@@ -327,12 +399,16 @@ function resolveCoreConfig(repository, local) {
|
|
|
327
399
|
config: {
|
|
328
400
|
enabled: enabled.value,
|
|
329
401
|
interactionContract: interactionContract.value,
|
|
402
|
+
contextVirtualization: contextVirtualization.value,
|
|
403
|
+
conversationHistory: conversationHistory.value,
|
|
330
404
|
skills: { enabled: skillsEnabled.value },
|
|
331
405
|
defaultMode: defaultMode.value,
|
|
332
406
|
},
|
|
333
407
|
sources: {
|
|
334
408
|
enabled: enabled.source,
|
|
335
409
|
interactionContract: interactionContract.source,
|
|
410
|
+
contextVirtualization: contextVirtualization.source,
|
|
411
|
+
conversationHistory: conversationHistory.source,
|
|
336
412
|
skillsEnabled: skillsEnabled.source,
|
|
337
413
|
defaultMode: defaultMode.source,
|
|
338
414
|
},
|
|
@@ -355,6 +431,8 @@ function resolveSessionCoreConfig(layers) {
|
|
|
355
431
|
const sources = layers.sources;
|
|
356
432
|
const enabled = currentSessionOverrides.enabled;
|
|
357
433
|
const interactionContract = currentSessionOverrides.interactionContract;
|
|
434
|
+
const contextVirtualization = currentSessionOverrides.contextVirtualization;
|
|
435
|
+
const conversationHistory = currentSessionOverrides.conversationHistory;
|
|
358
436
|
const skillsEnabled = currentSessionOverrides.skillsEnabled;
|
|
359
437
|
|
|
360
438
|
return {
|
|
@@ -362,12 +440,18 @@ function resolveSessionCoreConfig(layers) {
|
|
|
362
440
|
enabled: typeof enabled === "boolean" ? enabled : configured.enabled,
|
|
363
441
|
interactionContract:
|
|
364
442
|
typeof interactionContract === "boolean" ? interactionContract : configured.interactionContract,
|
|
443
|
+
contextVirtualization:
|
|
444
|
+
typeof contextVirtualization === "boolean" ? contextVirtualization : configured.contextVirtualization,
|
|
445
|
+
conversationHistory:
|
|
446
|
+
typeof conversationHistory === "boolean" ? conversationHistory : configured.conversationHistory,
|
|
365
447
|
skills: { enabled: typeof skillsEnabled === "boolean" ? skillsEnabled : configured.skills.enabled },
|
|
366
448
|
defaultMode: configured.defaultMode,
|
|
367
449
|
},
|
|
368
450
|
sources: {
|
|
369
451
|
enabled: typeof enabled === "boolean" ? "session" : sources.enabled,
|
|
370
452
|
interactionContract: typeof interactionContract === "boolean" ? "session" : sources.interactionContract,
|
|
453
|
+
contextVirtualization: typeof contextVirtualization === "boolean" ? "session" : sources.contextVirtualization,
|
|
454
|
+
conversationHistory: typeof conversationHistory === "boolean" ? "session" : sources.conversationHistory,
|
|
371
455
|
skillsEnabled: typeof skillsEnabled === "boolean" ? "session" : sources.skillsEnabled,
|
|
372
456
|
defaultMode: sources.defaultMode,
|
|
373
457
|
},
|
|
@@ -400,15 +484,60 @@ export async function readFreeflowConfigLayers(cwd) {
|
|
|
400
484
|
};
|
|
401
485
|
}
|
|
402
486
|
|
|
403
|
-
export async function readCapabilityState(cwd) {
|
|
487
|
+
export async function readCapabilityState(cwd, host = undefined, extensionHost = undefined) {
|
|
404
488
|
const layers = await readFreeflowConfigLayers(cwd);
|
|
405
|
-
const parsed = layers.repository.valid ? layers.repository.parsed : {};
|
|
406
|
-
const normalized = normalizeFreeflowConfig(parsed);
|
|
407
489
|
const effectiveCore = resolveSessionCoreConfig(layers);
|
|
408
490
|
const enabled = layers.configured && effectiveCore.config.enabled;
|
|
409
491
|
const interactionContractConfigEnabled = effectiveCore.config.interactionContract;
|
|
410
492
|
const skillsConfigEnabled = effectiveCore.config.skills.enabled;
|
|
411
|
-
const
|
|
493
|
+
const contextVirtualizationConfigEnabled = effectiveCore.config.contextVirtualization;
|
|
494
|
+
const conversationHistoryConfigEnabled = effectiveCore.config.conversationHistory;
|
|
495
|
+
const skillsEffective = enabled && skillsConfigEnabled;
|
|
496
|
+
const hostSupportsCognitiveRouting = isPiFlowHost(extensionHost);
|
|
497
|
+
const configuredCognitiveRouting = await resolveCognitiveRoutingState(
|
|
498
|
+
layers.repository.parsed,
|
|
499
|
+
layers.local.parsed,
|
|
500
|
+
hostSupportsCognitiveRouting ? host : undefined,
|
|
501
|
+
);
|
|
502
|
+
const disabledReason = enabled
|
|
503
|
+
? skillsEffective
|
|
504
|
+
? undefined
|
|
505
|
+
: { code: "disabled" as const, message: "Skills are disabled" }
|
|
506
|
+
: { code: "disabled" as const, message: "Freeflow is disabled" };
|
|
507
|
+
const childCapability = (configuredEnabled) => ({
|
|
508
|
+
enabled: configuredEnabled,
|
|
509
|
+
effective: skillsEffective && configuredEnabled,
|
|
510
|
+
...(disabledReason ? { blockingReason: disabledReason } : {}),
|
|
511
|
+
});
|
|
512
|
+
const cognitiveRouting = enabled
|
|
513
|
+
? skillsEffective
|
|
514
|
+
? !hostSupportsCognitiveRouting && configuredCognitiveRouting.configValid
|
|
515
|
+
? {
|
|
516
|
+
...configuredCognitiveRouting,
|
|
517
|
+
effective: false,
|
|
518
|
+
blockingReason: {
|
|
519
|
+
code: "runtime_disabled" as const,
|
|
520
|
+
message: "Cognitive Routing is disabled outside the PiFlow runtime",
|
|
521
|
+
},
|
|
522
|
+
}
|
|
523
|
+
: configuredCognitiveRouting
|
|
524
|
+
: {
|
|
525
|
+
...configuredCognitiveRouting,
|
|
526
|
+
effective: false,
|
|
527
|
+
blockingReason: {
|
|
528
|
+
code: "disabled" as const,
|
|
529
|
+
message: "Skills are disabled",
|
|
530
|
+
},
|
|
531
|
+
}
|
|
532
|
+
: {
|
|
533
|
+
...configuredCognitiveRouting,
|
|
534
|
+
enabled: false,
|
|
535
|
+
effective: false,
|
|
536
|
+
blockingReason: {
|
|
537
|
+
code: "disabled" as const,
|
|
538
|
+
message: "Freeflow is disabled",
|
|
539
|
+
},
|
|
540
|
+
};
|
|
412
541
|
return {
|
|
413
542
|
configured: layers.configured,
|
|
414
543
|
repositoryConfigured: layers.repositoryConfigured,
|
|
@@ -434,69 +563,15 @@ export async function readCapabilityState(cwd) {
|
|
|
434
563
|
enabled: skillsConfigEnabled,
|
|
435
564
|
effective: enabled && skillsConfigEnabled,
|
|
436
565
|
},
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
566
|
+
contextVirtualization: childCapability(contextVirtualizationConfigEnabled),
|
|
567
|
+
conversationHistory: childCapability(conversationHistoryConfigEnabled),
|
|
568
|
+
hostSupportsCognitiveRouting,
|
|
569
|
+
cognitiveRouting,
|
|
441
570
|
};
|
|
442
571
|
}
|
|
443
572
|
|
|
444
573
|
export const readRuntimeState = readCapabilityState;
|
|
445
574
|
|
|
446
|
-
export async function readOutputRouterConfig(cwd) {
|
|
447
|
-
const layers = await readFreeflowConfigLayers(cwd);
|
|
448
|
-
const parsed = layers.repository.valid ? layers.repository.parsed : {};
|
|
449
|
-
const localParsed = layers.local.valid ? layers.local.parsed : {};
|
|
450
|
-
const normalized = normalizeFreeflowConfig(parsed);
|
|
451
|
-
const local = normalizeLocalFreeflowConfig(localParsed);
|
|
452
|
-
const freeflowEnabled = layers.configured && layers.coreConfig.enabled;
|
|
453
|
-
const effectiveConfig = freeflowEnabled
|
|
454
|
-
? normalized.config
|
|
455
|
-
: {
|
|
456
|
-
...normalized.config,
|
|
457
|
-
outputRouter: { ...normalized.config.outputRouter, enabled: false },
|
|
458
|
-
observedRouting: {
|
|
459
|
-
...normalized.config.observedRouting,
|
|
460
|
-
enabled: false,
|
|
461
|
-
},
|
|
462
|
-
scriptTransform: {
|
|
463
|
-
...normalized.config.scriptTransform,
|
|
464
|
-
enabled: false,
|
|
465
|
-
},
|
|
466
|
-
};
|
|
467
|
-
const configWarnings = [...normalized.warnings];
|
|
468
|
-
if (layers.repository.exists && !layers.repository.valid) {
|
|
469
|
-
configWarnings.unshift(
|
|
470
|
-
`.freeflow/config.json could not be parsed; Freeflow runtime is inactive. ${layers.repository.parseError ?? ""}`.trim(),
|
|
471
|
-
);
|
|
472
|
-
}
|
|
473
|
-
if (layers.local.exists && !layers.local.valid) {
|
|
474
|
-
configWarnings.unshift(
|
|
475
|
-
`.freeflow/local.json could not be parsed; Freeflow runtime is inactive. ${layers.local.parseError ?? ""}`.trim(),
|
|
476
|
-
);
|
|
477
|
-
}
|
|
478
|
-
return {
|
|
479
|
-
config: effectiveConfig.outputRouter,
|
|
480
|
-
freeflowConfig: effectiveConfig,
|
|
481
|
-
localConfig: local.config,
|
|
482
|
-
warnings: [...configWarnings, ...local.warnings],
|
|
483
|
-
};
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
export function notifyRouterConfigWarnings(ctx, routerConfigResult) {
|
|
487
|
-
if (!routerConfigResult.warnings.length) {
|
|
488
|
-
return;
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
const key = routerConfigResult.warnings.join("\n");
|
|
492
|
-
if (key === lastRouterConfigWarningKey) {
|
|
493
|
-
return;
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
lastRouterConfigWarningKey = key;
|
|
497
|
-
ctx.ui.notify(`Freeflow config warning: ${routerConfigResult.warnings.join(" ")}`, "warning");
|
|
498
|
-
}
|
|
499
|
-
|
|
500
575
|
export function restoreModeOverride(ctx) {
|
|
501
576
|
currentModeOverride = null;
|
|
502
577
|
currentSessionOverrides = {};
|
|
@@ -538,7 +613,13 @@ export async function readModeState(cwd) {
|
|
|
538
613
|
};
|
|
539
614
|
}
|
|
540
615
|
|
|
541
|
-
export function setModeStatus(
|
|
616
|
+
export function setModeStatus(
|
|
617
|
+
ctx,
|
|
618
|
+
modeState,
|
|
619
|
+
capabilityState = undefined,
|
|
620
|
+
cognitiveRoutingRuntime = undefined,
|
|
621
|
+
options: { cognitiveRoutingStartupPending?: boolean } = {},
|
|
622
|
+
) {
|
|
542
623
|
if (capabilityState && !capabilityState.configured) {
|
|
543
624
|
ctx.ui.setStatus("freeflow", capabilityState.configExists ? "freeflow: config error" : "freeflow: setup needed");
|
|
544
625
|
return;
|
|
@@ -560,8 +641,39 @@ export function setModeStatus(ctx, modeState, capabilityState = undefined) {
|
|
|
560
641
|
} else if (capabilityState?.configSources?.skillsEnabled === "session") {
|
|
561
642
|
active.push("skills off (session)");
|
|
562
643
|
}
|
|
563
|
-
|
|
564
|
-
|
|
644
|
+
const cognitiveRouting = capabilityState?.cognitiveRouting;
|
|
645
|
+
const cognitiveRoutingActive = cognitiveRouting?.effective === true && cognitiveRoutingRuntime?.effective === true;
|
|
646
|
+
const startupSelectionSuppressesCognitiveRouting =
|
|
647
|
+
ctx?.modelStateProvenance?.explicitModel === true || ctx?.modelStateProvenance?.explicitThinking === true;
|
|
648
|
+
if (cognitiveRoutingActive) {
|
|
649
|
+
const profile = cognitiveRoutingRuntime.activeProfile;
|
|
650
|
+
const control =
|
|
651
|
+
cognitiveRoutingRuntime.controlMode === "manual-standard" ||
|
|
652
|
+
cognitiveRoutingRuntime.controlMode === "manual-reasoning"
|
|
653
|
+
? "manual hold"
|
|
654
|
+
: "automatic";
|
|
655
|
+
active.push(`${profile} · ${control}`);
|
|
656
|
+
} else if (cognitiveRouting?.enabled === true) {
|
|
657
|
+
if (cognitiveRouting.blockingReason?.code === "runtime_disabled") {
|
|
658
|
+
active.push("cognitive disabled · PiFlow only");
|
|
659
|
+
} else if (
|
|
660
|
+
cognitiveRouting.effective === true &&
|
|
661
|
+
cognitiveRoutingRuntime === undefined &&
|
|
662
|
+
options.cognitiveRoutingStartupPending === true &&
|
|
663
|
+
!startupSelectionSuppressesCognitiveRouting
|
|
664
|
+
) {
|
|
665
|
+
const startupProfile = cognitiveRouting.sessionStart?.profile ?? "standard";
|
|
666
|
+
active.push(`${startupProfile} · pending`);
|
|
667
|
+
} else {
|
|
668
|
+
const reason =
|
|
669
|
+
cognitiveRouting?.effective === true
|
|
670
|
+
? (cognitiveRoutingRuntime?.blockingReason?.code ?? "runtime_inactive")
|
|
671
|
+
: (cognitiveRouting.blockingReason?.code ?? "unavailable");
|
|
672
|
+
active.push(`cognitive blocked · ${reason}`);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
if (capabilityState?.contextVirtualization?.effective || capabilityState?.conversationHistory?.effective) {
|
|
676
|
+
active.push("context");
|
|
565
677
|
}
|
|
566
678
|
ctx.ui.setStatus("freeflow", `freeflow: ${active.length > 0 ? active.join(" · ") : "idle"}`);
|
|
567
679
|
}
|
|
@@ -585,175 +697,121 @@ export function skillPrompt(skill, args) {
|
|
|
585
697
|
return trimmed ? `/skill:${skill}\n\n${trimmed}` : `/skill:${skill}`;
|
|
586
698
|
}
|
|
587
699
|
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
return "conversation mode: keep routed-tool guidance soft; answer questions directly.";
|
|
594
|
-
}
|
|
595
|
-
if (mode === "strict-workflow") {
|
|
596
|
-
return "strict-workflow mode: strongest guidance; prefer exact, recoverable routed evidence for risky work.";
|
|
597
|
-
}
|
|
598
|
-
return "workflow mode: prefer routed tools for exploration and likely-large command output.";
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
function outputRouterContext(modeState, freeflowContext, routerConfigResult, capabilityState) {
|
|
602
|
-
const safetyNetText =
|
|
603
|
-
routerConfigResult.config.postToolRouting === "off"
|
|
604
|
-
? ""
|
|
605
|
-
: "\n\nOutput-router config note: large native read/bash outputs may be vaulted and replaced with labeled routed output. Use freeflow_search with the output id to recover exact content.";
|
|
606
|
-
|
|
607
|
-
return `## Loaded Output Router Skill
|
|
608
|
-
|
|
609
|
-
Mode guidance: ${outputRouterModeGuidance(modeState.effectiveMode, capabilityState.skills.effective)}${safetyNetText}
|
|
610
|
-
|
|
611
|
-
\`\`\`md
|
|
612
|
-
${freeflowContext.outputRouterSkill.trim()}
|
|
613
|
-
\`\`\``;
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
function capabilityContext(capabilityState) {
|
|
617
|
-
const sessionSuffix = (source) => (source === "session" ? " (session override)" : "");
|
|
618
|
-
const interactionContract = `${capabilityState.interactionContract.effective ? "enabled" : "disabled"}${sessionSuffix(
|
|
619
|
-
capabilityState.configSources.interactionContract,
|
|
620
|
-
)}`;
|
|
621
|
-
const skills = `${capabilityState.skills.effective ? "enabled" : "disabled"}${sessionSuffix(
|
|
622
|
-
capabilityState.configSources.skillsEnabled,
|
|
623
|
-
)}`;
|
|
624
|
-
const outputRouter = capabilityState.outputRouter.enabled ? "enabled" : "disabled";
|
|
625
|
-
return `## Freeflow Capabilities
|
|
700
|
+
type CognitiveRoutingRuntimeSnapshot = {
|
|
701
|
+
effective?: boolean;
|
|
702
|
+
activeProfile?: unknown;
|
|
703
|
+
controlMode?: unknown;
|
|
704
|
+
};
|
|
626
705
|
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
706
|
+
type FreeflowContextMessage = {
|
|
707
|
+
customType?: unknown;
|
|
708
|
+
[key: string]: unknown;
|
|
709
|
+
};
|
|
630
710
|
|
|
631
|
-
|
|
711
|
+
function publicCognitiveRoutingControl(controlMode) {
|
|
712
|
+
if (controlMode === "automatic") return "automatic";
|
|
713
|
+
if (controlMode === "manual-standard" || controlMode === "manual-reasoning") return "manual";
|
|
714
|
+
return "unavailable";
|
|
632
715
|
}
|
|
633
716
|
|
|
634
|
-
function
|
|
635
|
-
return
|
|
636
|
-
|
|
637
|
-
capabilityState.skills.effective ||
|
|
638
|
-
capabilityState.outputRouter.enabled
|
|
639
|
-
);
|
|
717
|
+
function publicCognitiveRoutingProfile(activeProfile, effective) {
|
|
718
|
+
if (effective !== true) return "unavailable";
|
|
719
|
+
return activeProfile === "standard" || activeProfile === "reasoning" ? activeProfile : "unavailable";
|
|
640
720
|
}
|
|
641
721
|
|
|
642
|
-
function
|
|
643
|
-
if (
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
Conversation mode is active and read-only.
|
|
649
|
-
|
|
650
|
-
Do not call write, edit, or mutating tools. Do not create, delete, commit, push, or change repository, system, external, or durable state.
|
|
651
|
-
|
|
652
|
-
A mutation request does not switch mode, and an execution skill does not override this boundary. Explain that conversation mode is read-only and ask the user to switch to workflow or strict-workflow.`;
|
|
653
|
-
}
|
|
654
|
-
|
|
655
|
-
if (mode === "strict-workflow") {
|
|
656
|
-
return `
|
|
657
|
-
|
|
658
|
-
## Strict Workflow Overlay
|
|
659
|
-
|
|
660
|
-
Strict Workflow is active. Use the adaptive Workflow, but increase decision, evidence, verification, and checkpoint pressure at high-risk or hard-to-reverse boundaries.
|
|
661
|
-
|
|
662
|
-
For work affecting security, privacy, billing, data loss, migrations, public interfaces, compatibility, deployment, or architecture:
|
|
663
|
-
|
|
664
|
-
- stop for any user-owned choice or source conflict;
|
|
665
|
-
- inspect the relevant risk surface before crossing the boundary;
|
|
666
|
-
- select only artifacts, checkpoints, and independent review that materially reduce risk;
|
|
667
|
-
- verify at the affected boundary before claiming success.
|
|
668
|
-
|
|
669
|
-
Do not manufacture ceremony for low-risk, reversible work. Strict Workflow does not authorize mutation, bypass safety, or make every implementation detail a user decision.`;
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
return "";
|
|
722
|
+
function publicCapabilityStatus(capability) {
|
|
723
|
+
if (capability?.effective === true) return "active";
|
|
724
|
+
if (!capability) return "unavailable";
|
|
725
|
+
const blockingCode = capability.blockingReason?.code;
|
|
726
|
+
if (blockingCode && blockingCode !== "disabled") return "unavailable";
|
|
727
|
+
return "inactive";
|
|
673
728
|
}
|
|
674
729
|
|
|
675
|
-
function
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
730
|
+
export function freeflowRuntimeStateMessage(
|
|
731
|
+
modeState,
|
|
732
|
+
capabilityState,
|
|
733
|
+
cognitiveRoutingRuntime: CognitiveRoutingRuntimeSnapshot | undefined = undefined,
|
|
734
|
+
) {
|
|
735
|
+
const cognitiveRoutingEffective = capabilityState?.cognitiveRouting?.effective === true;
|
|
736
|
+
const profile = publicCognitiveRoutingProfile(
|
|
737
|
+
cognitiveRoutingRuntime?.activeProfile,
|
|
738
|
+
cognitiveRoutingEffective && cognitiveRoutingRuntime?.effective === true,
|
|
739
|
+
);
|
|
740
|
+
const control =
|
|
741
|
+
profile === "unavailable" ? "unavailable" : publicCognitiveRoutingControl(cognitiveRoutingRuntime?.controlMode);
|
|
742
|
+
const defaultMode = modeState?.defaultMode ?? "workflow";
|
|
743
|
+
const activeMode = modeState?.effectiveMode ?? "inactive";
|
|
689
744
|
|
|
690
|
-
|
|
691
|
-
|
|
745
|
+
return {
|
|
746
|
+
role: "custom",
|
|
747
|
+
customType: FREEFLOW_RUNTIME_STATE_MESSAGE_TYPE,
|
|
748
|
+
content: [
|
|
749
|
+
"# Freeflow Runtime State",
|
|
750
|
+
"",
|
|
751
|
+
"This is extension-generated runtime state. Use it to interpret the stable Freeflow guidance.",
|
|
752
|
+
"",
|
|
753
|
+
`Default mode: \`${defaultMode}\``,
|
|
754
|
+
`Active mode: \`${activeMode}\``,
|
|
755
|
+
"",
|
|
756
|
+
"Capabilities:",
|
|
757
|
+
`- Interaction Contract: ${publicCapabilityStatus(capabilityState?.interactionContract)}`,
|
|
758
|
+
`- Skills: ${publicCapabilityStatus(capabilityState?.skills)}`,
|
|
759
|
+
`- Context Virtualization: ${publicCapabilityStatus(capabilityState?.contextVirtualization)}`,
|
|
760
|
+
`- Conversation History: ${publicCapabilityStatus(capabilityState?.conversationHistory)}`,
|
|
761
|
+
`- Cognitive Routing: ${publicCapabilityStatus(capabilityState?.cognitiveRouting)}`,
|
|
762
|
+
"",
|
|
763
|
+
"Cognitive Routing:",
|
|
764
|
+
`- Control: \`${control}\``,
|
|
765
|
+
`- Profile: \`${profile}\``,
|
|
766
|
+
].join("\n"),
|
|
767
|
+
display: false,
|
|
768
|
+
details: { source: "provider-request-runtime-state" },
|
|
769
|
+
};
|
|
692
770
|
}
|
|
693
771
|
|
|
694
|
-
function
|
|
695
|
-
return
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
Session mode override: \`${modeState.sessionMode ?? "none"}\`.
|
|
701
|
-
Resolved mode: \`${modeState.resolvedMode}\` (inactive because Skills are disabled).
|
|
702
|
-
Effective Freeflow mode: \`none\`.
|
|
703
|
-
|
|
704
|
-
Freeflow workflow modes are dormant until Skills are enabled with \`/freeflow settings\`.`;
|
|
772
|
+
export function withoutFreeflowRuntimeState(messages: readonly FreeflowContextMessage[] | undefined) {
|
|
773
|
+
return (Array.isArray(messages) ? messages : []).filter(
|
|
774
|
+
(message) =>
|
|
775
|
+
message?.customType !== FREEFLOW_RUNTIME_STATE_MESSAGE_TYPE &&
|
|
776
|
+
message?.customType !== COGNITIVE_ROUTING_RUNTIME_STATE_MESSAGE_TYPE,
|
|
777
|
+
);
|
|
705
778
|
}
|
|
706
779
|
|
|
707
|
-
function
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
Use \`/freeflow settings\` to enable the Interaction Contract, Skills, or Output Router. The read-only \`freeflow_status\` diagnostic may be available so the model can answer setup/status questions.`;
|
|
780
|
+
export function withFreeflowRuntimeState(
|
|
781
|
+
messages: readonly FreeflowContextMessage[] | undefined,
|
|
782
|
+
modeState,
|
|
783
|
+
capabilityState,
|
|
784
|
+
cognitiveRoutingRuntime: CognitiveRoutingRuntimeSnapshot | undefined = undefined,
|
|
785
|
+
) {
|
|
786
|
+
return [
|
|
787
|
+
...withoutFreeflowRuntimeState(messages),
|
|
788
|
+
freeflowRuntimeStateMessage(modeState, capabilityState, cognitiveRoutingRuntime),
|
|
789
|
+
];
|
|
718
790
|
}
|
|
719
791
|
|
|
720
|
-
export function runtimeContext(
|
|
721
|
-
if (
|
|
792
|
+
export function runtimeContext(freeflowContext, capabilityState) {
|
|
793
|
+
if (capabilityState?.configured !== true || capabilityState?.enabled !== true || !freeflowContext?.corePrompt) {
|
|
722
794
|
return "";
|
|
723
795
|
}
|
|
724
796
|
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
These instructions are context-loading only. They do not override user instructions, repo instructions, or host safety and approval policy.`;
|
|
797
|
+
const blocks = [];
|
|
798
|
+
if (freeflowContext?.corePrompt) blocks.push(freeflowContext.corePrompt.trim());
|
|
799
|
+
if (capabilityState.interactionContract?.effective === true && freeflowContext?.interactionContractPrompt) {
|
|
800
|
+
blocks.push(freeflowContext.interactionContractPrompt.trim());
|
|
731
801
|
}
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
return controlPlaneContext(modeState, capabilityState);
|
|
802
|
+
if (capabilityState.skills?.effective === true && freeflowContext?.skillsPrompt) {
|
|
803
|
+
blocks.push(freeflowContext.skillsPrompt.trim());
|
|
735
804
|
}
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
return `# Freeflow Runtime Context
|
|
747
|
-
|
|
748
|
-
Freeflow Pi extension loaded this before the agent turn.
|
|
749
|
-
Runtime delivery: confirmed for this Pi \`before_agent_start\` invocation.
|
|
750
|
-
These instructions are context-loading only. They do not override user instructions, repo instructions, or host safety and approval policy.
|
|
751
|
-
|
|
752
|
-
${modeText}
|
|
753
|
-
|
|
754
|
-
${capabilityContext(capabilityState)}${interactionContractText}${routerText}
|
|
755
|
-
|
|
756
|
-
This Pi extension loads enabled runtime context before every agent turn and routes commands only; it does not enforce policy, block tools, grant permissions, or create repo-local hooks.`;
|
|
805
|
+
if (capabilityState.cognitiveRouting?.effective === true && freeflowContext?.cognitiveRoutingPrompt) {
|
|
806
|
+
blocks.push(freeflowContext.cognitiveRoutingPrompt.trim());
|
|
807
|
+
}
|
|
808
|
+
if (capabilityState.contextVirtualization?.effective === true && freeflowContext?.contextVirtualizationPrompt) {
|
|
809
|
+
blocks.push(freeflowContext.contextVirtualizationPrompt.trim());
|
|
810
|
+
}
|
|
811
|
+
if (capabilityState.conversationHistory?.effective === true && freeflowContext?.conversationHistoryPrompt) {
|
|
812
|
+
blocks.push(freeflowContext.conversationHistoryPrompt.trim());
|
|
813
|
+
}
|
|
814
|
+
return blocks.filter(Boolean).join("\n\n");
|
|
757
815
|
}
|
|
758
816
|
|
|
759
817
|
export async function setSessionCoreOverride(key: SessionCoreKey, value: boolean | null, ctx, pi) {
|
|
@@ -781,7 +839,7 @@ export async function setSessionCoreOverride(key: SessionCoreKey, value: boolean
|
|
|
781
839
|
changed: true,
|
|
782
840
|
reloadRequired: key === "enabled" || key === "skillsEnabled",
|
|
783
841
|
sessionOverrides: { ...currentSessionOverrides },
|
|
784
|
-
capabilityState: await readCapabilityState(ctx.cwd),
|
|
842
|
+
capabilityState: await readCapabilityState(ctx.cwd, ctx, pi?.host),
|
|
785
843
|
};
|
|
786
844
|
}
|
|
787
845
|
|
|
@@ -819,7 +877,7 @@ export async function setSessionMode(mode, ctx, pi) {
|
|
|
819
877
|
|
|
820
878
|
export async function handleModeCommand(args, ctx, pi) {
|
|
821
879
|
const arg = args?.trim();
|
|
822
|
-
const capabilityState = await readCapabilityState(ctx.cwd);
|
|
880
|
+
const capabilityState = await readCapabilityState(ctx.cwd, ctx, pi?.host);
|
|
823
881
|
const inactiveModeState = await readModeState(ctx.cwd);
|
|
824
882
|
|
|
825
883
|
if (!capabilityState.configured) {
|