@hassangameryt/freeflow 0.7.3 → 0.8.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 +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.cursor-plugin/plugin.json +1 -1
- package/NOTICE +14 -0
- package/README.md +26 -31
- package/capabilities/cognitive-routing/SKILL.md +106 -161
- package/capabilities/cognitive-routing/references/both-mode.md +36 -0
- package/capabilities/cognitive-routing/references/executor-mode.md +48 -0
- package/capabilities/cognitive-routing/references/helper-mode.md +47 -0
- package/capabilities/compaction/SKILL.md +49 -0
- package/capabilities/compaction/references/summary-format.md +239 -0
- package/command-surface.json +4 -0
- package/gemini-extension.json +1 -1
- package/hooks/shared/runtime-context.mjs +28 -30
- package/licenses/Apache-2.0.txt +55 -0
- package/package.json +22 -9
- package/pi-extension/README.md +41 -0
- package/pi-extension/dist/cognitive-routing/assembler.js +393 -0
- package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/config.js +5 -2
- package/pi-extension/dist/cognitive-routing/economics.js +45 -0
- package/pi-extension/dist/cognitive-routing/event-schema.js +388 -0
- package/pi-extension/dist/{session-sources/events.js → cognitive-routing/event-store.js} +103 -40
- package/pi-extension/dist/cognitive-routing/gate.js +241 -0
- package/pi-extension/dist/cognitive-routing/handlers.js +899 -0
- package/pi-extension/dist/cognitive-routing/handoffs.js +350 -0
- package/pi-extension/dist/cognitive-routing/model-control.js +467 -0
- package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/projection.js +229 -56
- package/pi-extension/dist/cognitive-routing/provenance.js +81 -0
- package/pi-extension/dist/cognitive-routing/runtime.js +396 -0
- package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/schemas.js +43 -7
- package/pi-extension/dist/cognitive-routing/session.js +221 -0
- package/pi-extension/dist/{session-sources → cognitive-routing}/sources.js +99 -85
- package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/state.js +37 -378
- package/pi-extension/dist/cognitive-routing/status.js +80 -0
- package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/tools.js +12 -12
- package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/types.js +5 -11
- package/pi-extension/dist/compaction/carry.js +191 -0
- package/pi-extension/dist/compaction/config.js +22 -0
- package/pi-extension/dist/compaction/controller.js +471 -0
- package/pi-extension/dist/compaction/harness.js +77 -0
- package/pi-extension/dist/compaction/results.js +158 -0
- package/pi-extension/dist/compaction/thresholds.js +35 -0
- package/pi-extension/dist/compaction/tool.js +57 -0
- package/pi-extension/dist/host/branch.js +13 -0
- package/pi-extension/dist/host/canonical.js +12 -0
- package/pi-extension/dist/host/catalog.js +77 -0
- package/pi-extension/dist/host/config.js +374 -0
- package/pi-extension/dist/host/projection-tags.js +60 -0
- package/pi-extension/dist/host/prompts.js +82 -0
- package/pi-extension/dist/{session-sources → host}/read-only-session.js +112 -1
- package/pi-extension/dist/{runtime → host}/request-history.js +121 -39
- package/pi-extension/dist/host/runtime-state.js +189 -0
- package/pi-extension/dist/{settings/settings-ui.js → host/settings/freeflow-command.js} +620 -410
- package/pi-extension/dist/{settings/settings-tui.js → host/settings/settings-view.js} +186 -73
- package/pi-extension/dist/host/staging.js +28 -0
- package/pi-extension/dist/host/status.js +101 -0
- package/pi-extension/dist/index.js +423 -173
- package/pi-extension/dist/provider-support/cache/anchor.js +21 -0
- package/pi-extension/dist/provider-support/cache/anthropic.js +102 -0
- package/pi-extension/dist/provider-support/cache/health.js +73 -0
- package/pi-extension/dist/provider-support/cache/index.js +58 -0
- package/pi-extension/dist/provider-support/cache/keepalive.js +210 -0
- package/pi-extension/dist/provider-support/cache/monitor.js +17 -0
- package/pi-extension/dist/provider-support/cache/openai-responses.js +48 -0
- package/pi-extension/dist/provider-support/effort.js +13 -0
- package/pi-extension/dist/provider-support/index.js +44 -3
- package/pi-extension/dist/provider-support/{astra → openai}/adapter.js +46 -29
- package/pi-extension/dist/provider-support/{astra → openai}/history.js +10 -8
- package/pi-extension/dist/provider-support/{astra → openai}/index.js +8 -4
- package/pi-extension/dist/provider-support/{astra → openai}/session-state.js +29 -38
- package/pi-extension/dist/provider-support/routes.js +17 -0
- package/pi-extension/dist/tool-execution/apply-patch/grammar.js +23 -0
- package/pi-extension/dist/tool-execution/apply-patch/match.js +38 -0
- package/pi-extension/dist/tool-execution/apply-patch/parser.js +177 -0
- package/pi-extension/dist/tool-execution/apply-patch/plan.js +201 -0
- package/pi-extension/dist/tool-execution/apply-patch/tool.js +84 -0
- package/pi-extension/dist/tool-execution/background.js +238 -0
- package/pi-extension/dist/tool-execution/bash-guard.js +23 -0
- package/pi-extension/dist/tool-execution/config.js +22 -0
- package/pi-extension/dist/tool-execution/edit-messages.js +120 -0
- package/pi-extension/dist/tool-execution/file-state.js +138 -0
- package/pi-extension/dist/tool-execution/file-tracking.js +143 -0
- package/pi-extension/dist/tool-execution/prompt.js +54 -0
- package/pi-extension/dist/tool-execution/tools.js +16 -0
- package/pi-extension/freeflow/README.md +9 -0
- package/plugin.json +1 -1
- package/runtime/prompts/cognitive-routing.md +4 -4
- package/runtime/prompts/core.md +22 -75
- package/runtime/prompts/interaction-contract.md +15 -8
- package/runtime/prompts/tool-execution.md +38 -0
- package/runtime/prompts/working-method.md +108 -0
- package/skills/action-selection/SKILL.md +39 -47
- package/skills/action-selection/references/trajectory-stalls.md +2 -0
- package/skills/bypass/SKILL.md +2 -2
- package/skills/commit-work/SKILL.md +31 -83
- package/skills/commit-work/references/git-state-edges.md +1 -1
- package/skills/commit-work/references/simple-push.md +2 -0
- package/skills/commit-work/references/staging-decisions.md +1 -1
- package/skills/decision-gate/SKILL.md +31 -50
- package/skills/design-for-depth/SKILL.md +44 -53
- package/skills/design-for-depth/references/design-pressure-signals.md +46 -144
- package/skills/design-for-depth/references/implementation-decisions.md +1 -1
- package/skills/design-for-depth/references/interface-design-loop.md +5 -36
- package/skills/design-for-depth/references/module-and-dependency-design.md +2 -32
- package/skills/design-for-depth/references/state-and-failure-boundaries.md +2 -13
- package/skills/diagnose-failure/SKILL.md +39 -24
- package/skills/diagnose-failure/references/diagnostic-loop-catalog.md +2 -0
- package/skills/diagnose-failure/references/flaky-and-performance-diagnosis.md +2 -2
- package/skills/discuss/SKILL.md +35 -11
- package/skills/discuss/references/discussion-continuity.md +7 -27
- package/skills/evaluate-skill/SKILL.md +49 -80
- package/skills/evaluate-skill/references/evaluation-definition-schema.md +35 -5
- package/skills/evaluate-skill/references/evaluation-design.md +14 -14
- package/skills/evaluate-skill/references/execution-and-evidence.md +26 -5
- package/skills/evaluate-skill/references/review-and-revision.md +3 -1
- package/skills/evaluate-skill/scripts/lib/definitions.mjs +49 -8
- package/skills/evaluate-skill/scripts/lib/pi.mjs +14 -7
- package/skills/evaluate-skill/scripts/lib/review.mjs +196 -0
- package/skills/evaluate-skill/scripts/lib/runner.mjs +45 -8
- package/skills/evaluate-skill/scripts/lib/sandbox.mjs +2 -0
- package/skills/evaluate-skill/scripts/lib/trials.mjs +103 -0
- package/skills/evaluate-skill/scripts/lib/view.mjs +67 -1
- package/skills/evaluate-skill/scripts/pi-command-tool.mjs +144 -0
- package/skills/evaluate-skill/scripts/pi-guard.mjs +30 -13
- package/skills/evaluate-skill/scripts/skill-eval.mjs +114 -34
- package/skills/execute-work/SKILL.md +41 -9
- package/skills/execute-work/references/code-practices.md +2 -0
- package/skills/execute-work/references/execute-work-edges.md +11 -1
- package/skills/handoff/SKILL.md +1 -1
- package/skills/handoff/references/handoff-templates.md +1 -1
- package/skills/review-artifact/SKILL.md +42 -41
- package/skills/review-artifact/references/adjudicate-artifact-review.md +1 -1
- package/skills/review-artifact/references/independent-artifact-reviewer-contract.md +1 -1
- package/skills/review-work/SKILL.md +38 -32
- package/skills/review-work/references/adjudicate-work-review.md +1 -1
- package/skills/review-work/references/independent-work-reviewer-contract.md +1 -1
- package/skills/review-work/references/security-risk-lens.md +2 -4
- package/skills/setup-freeflow/SKILL.md +3 -1
- package/skills/setup-freeflow/references/activation-contract.md +7 -13
- package/skills/setup-freeflow/references/host-setup.md +3 -3
- package/skills/track-work/SKILL.md +113 -161
- package/skills/track-work/references/working-record-format.md +189 -350
- package/skills/track-work/scripts/lib/document.mjs +62 -6
- package/skills/track-work/scripts/lib/format.mjs +16 -1
- package/skills/track-work/scripts/lib/store.mjs +9 -8
- package/skills/track-work/scripts/lib/transitions.mjs +79 -4
- package/skills/track-work/scripts/working-record.mjs +34 -12
- package/skills/verify-work/SKILL.md +29 -20
- package/skills/verify-work/references/browser-runtime-evidence.md +1 -5
- package/skills/verify-work/references/integration-evidence.md +2 -0
- package/skills/verify-work/references/performance-evidence.md +3 -1
- package/skills/verify-work/references/test-design.md +3 -1
- package/skills/workflow/SKILL.md +65 -21
- package/skills/workflow/references/domain-skill-composition.md +5 -3
- package/skills/write-docs/SKILL.md +83 -0
- package/skills/write-docs/references/documentation-shapes.md +119 -0
- package/skills/write-docs/scripts/docs-check.mjs +139 -0
- package/skills/write-plan/SKILL.md +40 -40
- package/skills/write-plan/references/plan-shapes.md +1 -1
- package/skills/write-skill/SKILL.md +107 -147
- package/skills/write-skill/references/activation-boundaries.md +2 -0
- package/skills/write-skill/references/agent-first-instructions.md +22 -10
- package/skills/write-skill/references/progressive-disclosure.md +4 -2
- package/skills/write-skill/references/skill-dependency-graphs.md +2 -0
- package/skills/write-skill/scripts/lib/similarity.mjs +56 -0
- package/skills/write-skill/scripts/skill-author.mjs +18 -2
- package/skills/write-spec/SKILL.md +34 -41
- package/skills/write-spec/references/artifact-standards.md +1 -1
- package/skills/write-spec/references/decision-records.md +2 -0
- package/skills/write-spec/references/spec-shapes.md +1 -1
- package/capabilities/context-virtualization/SKILL.md +0 -103
- package/capabilities/conversation-history/SKILL.md +0 -53
- package/hooks/tests/check-host-adapters.test.mjs +0 -82
- package/hooks/tests/check-runtime-context-hook.sh +0 -212
- package/pi-extension/dist/cognitive-routing-v2/runtime.js +0 -2181
- package/pi-extension/dist/context-virtualization/commands.js +0 -89
- package/pi-extension/dist/context-virtualization/projector.js +0 -42
- package/pi-extension/dist/context-virtualization/runtime.js +0 -378
- package/pi-extension/dist/context-virtualization/state.js +0 -57
- package/pi-extension/dist/context-virtualization/types.js +0 -10
- package/pi-extension/dist/conversation-history/passages.js +0 -66
- package/pi-extension/dist/conversation-history/ranking.js +0 -105
- package/pi-extension/dist/conversation-history/runtime.js +0 -226
- package/pi-extension/dist/conversation-history/search.js +0 -56
- package/pi-extension/dist/conversation-history/types.js +0 -1
- package/pi-extension/dist/freeflow-context/resolver.js +0 -120
- package/pi-extension/dist/freeflow-context/runtime.js +0 -80
- package/pi-extension/dist/freeflow-context/source-projector.js +0 -95
- package/pi-extension/dist/freeflow-context/tool.js +0 -314
- package/pi-extension/dist/freeflow-context/types.js +0 -12
- package/pi-extension/dist/freeflow-context/visibility.js +0 -28
- package/pi-extension/dist/integrations/mcp-config.js +0 -29
- package/pi-extension/dist/runtime/runtime-context.js +0 -754
- package/pi-extension/dist/runtime/runtime-identity.js +0 -5
- package/pi-extension/dist/session-sources/provenance.js +0 -32
- package/pi-extension/dist/ui/text-component.js +0 -57
- package/pi-extension/src/cognitive-routing-v2/budget.ts +0 -42
- package/pi-extension/src/cognitive-routing-v2/config.ts +0 -173
- package/pi-extension/src/cognitive-routing-v2/projection.ts +0 -375
- package/pi-extension/src/cognitive-routing-v2/render.ts +0 -277
- package/pi-extension/src/cognitive-routing-v2/runtime.ts +0 -2241
- package/pi-extension/src/cognitive-routing-v2/schemas.ts +0 -180
- package/pi-extension/src/cognitive-routing-v2/state.ts +0 -839
- package/pi-extension/src/cognitive-routing-v2/tools.ts +0 -62
- package/pi-extension/src/cognitive-routing-v2/types.ts +0 -254
- package/pi-extension/src/context-virtualization/commands.ts +0 -111
- package/pi-extension/src/context-virtualization/projector.ts +0 -62
- package/pi-extension/src/context-virtualization/runtime.ts +0 -428
- package/pi-extension/src/context-virtualization/state.ts +0 -79
- package/pi-extension/src/context-virtualization/types.ts +0 -92
- package/pi-extension/src/conversation-history/passages.ts +0 -81
- package/pi-extension/src/conversation-history/ranking.ts +0 -155
- package/pi-extension/src/conversation-history/runtime.ts +0 -250
- package/pi-extension/src/conversation-history/search.ts +0 -79
- package/pi-extension/src/conversation-history/types.ts +0 -31
- package/pi-extension/src/freeflow-context/resolver.ts +0 -139
- package/pi-extension/src/freeflow-context/runtime.ts +0 -100
- package/pi-extension/src/freeflow-context/source-projector.ts +0 -106
- package/pi-extension/src/freeflow-context/tool.ts +0 -366
- package/pi-extension/src/freeflow-context/types.ts +0 -70
- package/pi-extension/src/freeflow-context/visibility.ts +0 -53
- package/pi-extension/src/index.ts +0 -390
- package/pi-extension/src/integrations/mcp-config.ts +0 -32
- package/pi-extension/src/provider-support/astra/adapter.ts +0 -108
- package/pi-extension/src/provider-support/astra/history.ts +0 -145
- package/pi-extension/src/provider-support/astra/index.ts +0 -12
- package/pi-extension/src/provider-support/astra/session-state.ts +0 -113
- package/pi-extension/src/provider-support/index.ts +0 -5
- package/pi-extension/src/runtime/request-history.ts +0 -243
- package/pi-extension/src/runtime/runtime-context.ts +0 -860
- package/pi-extension/src/runtime/runtime-identity.ts +0 -8
- package/pi-extension/src/session-sources/events.ts +0 -230
- package/pi-extension/src/session-sources/provenance.ts +0 -39
- package/pi-extension/src/session-sources/read-only-session.ts +0 -170
- package/pi-extension/src/session-sources/sources.ts +0 -334
- package/pi-extension/src/settings/settings-tui.ts +0 -501
- package/pi-extension/src/settings/settings-ui.ts +0 -1652
- package/pi-extension/src/ui/text-component.ts +0 -66
- package/pi-extension/tests/cache-reuse/history.test.js +0 -117
- package/pi-extension/tests/cache-reuse/native.test.js +0 -91
- package/pi-extension/tests/cache-reuse/settings.test.js +0 -211
- package/pi-extension/tests/cognitive-routing-v2/communication.test.js +0 -577
- package/pi-extension/tests/cognitive-routing-v2/compaction-input.test.js +0 -183
- package/pi-extension/tests/cognitive-routing-v2/delegation.test.js +0 -557
- package/pi-extension/tests/cognitive-routing-v2/native.test.js +0 -474
- package/pi-extension/tests/cognitive-routing-v2/performance.test.js +0 -87
- package/pi-extension/tests/cognitive-routing-v2/persistence.test.js +0 -300
- package/pi-extension/tests/cognitive-routing-v2/projection.test.js +0 -241
- package/pi-extension/tests/cognitive-routing-v2/recovery.test.js +0 -1034
- package/pi-extension/tests/cognitive-routing-v2/render.test.js +0 -244
- package/pi-extension/tests/cognitive-routing-v2/runtime.test.js +0 -423
- package/pi-extension/tests/cognitive-routing-v2/stabilization.test.js +0 -521
- package/pi-extension/tests/cognitive-routing-v2/state.test.js +0 -586
- package/pi-extension/tests/context-virtualization/extension.test.js +0 -775
- package/pi-extension/tests/context-virtualization/projector.test.js +0 -110
- package/pi-extension/tests/context-virtualization/runtime.test.js +0 -230
- package/pi-extension/tests/conversation-history/runtime.test.js +0 -98
- package/pi-extension/tests/conversation-history/search.test.js +0 -97
- package/pi-extension/tests/fixtures/pi-host.js +0 -4
- package/pi-extension/tests/fixtures/routing-native.js +0 -191
- package/pi-extension/tests/integration/mode-free-core.test.js +0 -220
- package/pi-extension/tests/integration/pi-extension.test.js +0 -1447
- package/pi-extension/tests/integration/prompt-architecture.test.js +0 -447
- package/pi-extension/tests/integration/unaffected-regressions.test.js +0 -478
- package/pi-extension/tests/provider-support/astra-boundaries.test.js +0 -75
- package/pi-extension/tests/provider-support/astra.test.js +0 -306
- package/pi-extension/tests/provider-support/cli.test.js +0 -92
- package/pi-extension/tests/provider-support/native.test.js +0 -183
- package/pi-extension/tests/settings/settings-tui.test.js +0 -243
- package/pi-extension/tsconfig.json +0 -16
- package/runtime/prompts/context-virtualization.md +0 -3
- package/runtime/prompts/conversation-history.md +0 -3
- package/skills/design-for-depth/references/software-design-philosophy.md +0 -202
- /package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/budget.js +0 -0
- /package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/render.js +0 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { resolve, sep } from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { estimateTokens } from "./carry.js";
|
|
4
|
+
import { currentCycle } from "./harness.js";
|
|
5
|
+
/**
|
|
6
|
+
* The result index: this cycle's larger tool results, each with an id the agent can carry by. Ids number tool results
|
|
7
|
+
* in branch order (r1, r2, ...), so they stay stable while the branch grows, and a result from an earlier cycle still
|
|
8
|
+
* resolves because its entry stays stored after compaction.
|
|
9
|
+
*/
|
|
10
|
+
const SIZE_FLOOR = 500;
|
|
11
|
+
const MAX_ROWS = 40;
|
|
12
|
+
/**
|
|
13
|
+
* The most tokens the rendered index can take: 40 rows of at most about 140 characters (an 80-character label plus
|
|
14
|
+
* id, tool, size and carried note) and a heading. Below the warning by more than this, the index cannot reach it.
|
|
15
|
+
*/
|
|
16
|
+
export const INDEX_TOKEN_BOUND = 2_000;
|
|
17
|
+
/** Freeflow's own control calls: no evidence to carry, as routing's evidence selection also excludes them. */
|
|
18
|
+
const CONTROL_TOOLS = new Set([
|
|
19
|
+
"freeflow_delegate",
|
|
20
|
+
"freeflow_return",
|
|
21
|
+
"freeflow_project",
|
|
22
|
+
"freeflow_unit",
|
|
23
|
+
"freeflow_compact",
|
|
24
|
+
]);
|
|
25
|
+
const resultText = (message) =>
|
|
26
|
+
(message?.content ?? [])
|
|
27
|
+
.map((part) => (part?.type === "text" ? part.text : part?.type === "image" ? "[image]" : ""))
|
|
28
|
+
.join("");
|
|
29
|
+
function label(name, input) {
|
|
30
|
+
const firstLine = (text) =>
|
|
31
|
+
text
|
|
32
|
+
.split("\n")
|
|
33
|
+
.map((line) => line.trim())
|
|
34
|
+
.find(Boolean) ?? "";
|
|
35
|
+
const value =
|
|
36
|
+
typeof input?.command === "string"
|
|
37
|
+
? input.command
|
|
38
|
+
: typeof input?.path === "string"
|
|
39
|
+
? input.path
|
|
40
|
+
: typeof input?.url === "string"
|
|
41
|
+
? input.url
|
|
42
|
+
: typeof input?.code === "string"
|
|
43
|
+
? `script: ${firstLine(input.code)}`
|
|
44
|
+
: Array.isArray(input?.queries)
|
|
45
|
+
? input.queries.join("; ")
|
|
46
|
+
: typeof input?.query === "string"
|
|
47
|
+
? input.query
|
|
48
|
+
: name;
|
|
49
|
+
const line = firstLine(String(value));
|
|
50
|
+
return line.length > 80 ? `${line.slice(0, 77)}...` : line;
|
|
51
|
+
}
|
|
52
|
+
/** The Freeflow package root: reads of its skills, references and prompts are instructions, not work to carry. */
|
|
53
|
+
const FREEFLOW_ROOT = fileURLToPath(new URL("../../../", import.meta.url));
|
|
54
|
+
const INSTRUCTION_DIRS = ["capabilities", "skills", "runtime"].map((dir) => resolve(FREEFLOW_ROOT, dir) + sep);
|
|
55
|
+
function isFreeflowInstruction(tool, input) {
|
|
56
|
+
if (tool !== "read" || typeof input?.path !== "string") return false;
|
|
57
|
+
const path = resolve(input.path);
|
|
58
|
+
return INSTRUCTION_DIRS.some((dir) => path.startsWith(dir));
|
|
59
|
+
}
|
|
60
|
+
/** Every tool result on the branch with its id, oldest first. */
|
|
61
|
+
function allResults(branch) {
|
|
62
|
+
const calls = new Map();
|
|
63
|
+
const results = [];
|
|
64
|
+
for (const entry of branch) {
|
|
65
|
+
const message = entry?.type === "message" ? entry.message : undefined;
|
|
66
|
+
if (message?.role === "assistant")
|
|
67
|
+
for (const block of message.content ?? [])
|
|
68
|
+
if (block?.type === "toolCall") calls.set(block.id, { name: block.name, input: block.arguments });
|
|
69
|
+
if (message?.role !== "toolResult") continue;
|
|
70
|
+
const call = calls.get(message.toolCallId);
|
|
71
|
+
const text = resultText(message);
|
|
72
|
+
const tool = call?.name ?? message.toolName ?? "tool";
|
|
73
|
+
results.push({
|
|
74
|
+
id: `r${results.length + 1}`,
|
|
75
|
+
tool,
|
|
76
|
+
label: label(tool, call?.input),
|
|
77
|
+
tokens: estimateTokens(text),
|
|
78
|
+
text,
|
|
79
|
+
...firstLineOf(tool, call?.input, message),
|
|
80
|
+
entry,
|
|
81
|
+
input: call?.input,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
return results;
|
|
85
|
+
}
|
|
86
|
+
/** A text read of a file starts at its offset (Pi's read is 1-based); an image or failed read has no lines. */
|
|
87
|
+
function firstLineOf(tool, input, message) {
|
|
88
|
+
if (tool !== "read" || typeof input?.path !== "string" || message?.isError) return {};
|
|
89
|
+
if ((message?.content ?? []).some((part) => part?.type === "image")) return {};
|
|
90
|
+
return { firstLine: Number.isInteger(input?.offset) && input.offset > 0 ? input.offset : 1 };
|
|
91
|
+
}
|
|
92
|
+
/** The first line of the read result in a session entry, for a result carried by routing ref. */
|
|
93
|
+
export function resultFirstLine(branch, entryId) {
|
|
94
|
+
return allResults(branch).find((result) => result.entry?.id === entryId)?.firstLine;
|
|
95
|
+
}
|
|
96
|
+
export function resolveResult(branch, id) {
|
|
97
|
+
const found = allResults(branch).find((result) => result.id === id);
|
|
98
|
+
if (!found) return undefined;
|
|
99
|
+
const { entry: _entry, input: _input, ...result } = found;
|
|
100
|
+
return result;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* The tool results of the work in progress, newest first: the current assignment's under Cognitive Routing (by
|
|
104
|
+
* routing ref), otherwise this cycle's (by r-id). Freeflow's control calls and reads of its own instructions are left
|
|
105
|
+
* out: they are how the agent works, not what it worked on.
|
|
106
|
+
*/
|
|
107
|
+
export function scopeResults(branch, assignment) {
|
|
108
|
+
const cycle = new Set(currentCycle(branch));
|
|
109
|
+
return allResults(branch)
|
|
110
|
+
.filter((result) => (assignment ? assignment.entryIds.has(result.entry.id) : cycle.has(result.entry)))
|
|
111
|
+
.filter((result) => !CONTROL_TOOLS.has(result.tool) && !isFreeflowInstruction(result.tool, result.input))
|
|
112
|
+
.reverse()
|
|
113
|
+
.map(({ entry, input, ...result }) => ({
|
|
114
|
+
...result,
|
|
115
|
+
id: assignment ? `ctx:${entry.id}` : result.id,
|
|
116
|
+
entryId: entry.id,
|
|
117
|
+
...(typeof input?.path === "string" ? { path: input.path } : {}),
|
|
118
|
+
}));
|
|
119
|
+
}
|
|
120
|
+
/** This cycle's results above the size floor, newest first, then results the last Freeflow compaction carried. */
|
|
121
|
+
export function resultIndex(branch) {
|
|
122
|
+
const cycle = new Set(currentCycle(branch));
|
|
123
|
+
const results = allResults(branch);
|
|
124
|
+
const rows = results
|
|
125
|
+
.filter(
|
|
126
|
+
(result) =>
|
|
127
|
+
cycle.has(result.entry) &&
|
|
128
|
+
result.tokens >= SIZE_FLOOR &&
|
|
129
|
+
!CONTROL_TOOLS.has(result.tool) &&
|
|
130
|
+
!isFreeflowInstruction(result.tool, result.input),
|
|
131
|
+
)
|
|
132
|
+
.reverse()
|
|
133
|
+
.map(({ id, tool, label, tokens }) => ({ id, tool, label, tokens }));
|
|
134
|
+
const latest = [...branch].reverse().find((entry) => entry?.type === "compaction" && entry.details?.freeflow);
|
|
135
|
+
for (const item of latest?.details?.freeflow?.carried ?? []) {
|
|
136
|
+
if (item?.kind !== "result" || rows.some((row) => row.id === item.ref)) continue;
|
|
137
|
+
const result = results.find((each) => each.id === item.ref);
|
|
138
|
+
if (result)
|
|
139
|
+
rows.push({
|
|
140
|
+
id: result.id,
|
|
141
|
+
tool: result.tool,
|
|
142
|
+
label: result.label,
|
|
143
|
+
tokens: result.tokens,
|
|
144
|
+
firstCycle: item.firstCycle,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
return rows.slice(0, MAX_ROWS);
|
|
148
|
+
}
|
|
149
|
+
export function renderIndex(rows) {
|
|
150
|
+
if (!rows.length) return "No tool results large enough to list; carry files by path.";
|
|
151
|
+
return [
|
|
152
|
+
"Results you can carry by id:",
|
|
153
|
+
...rows.map(
|
|
154
|
+
(row) =>
|
|
155
|
+
`- ${row.id} ${row.tool} ${row.label} ~${row.tokens} tokens${row.firstCycle ? ` (carried since cycle ${row.firstCycle})` : ""}`,
|
|
156
|
+
),
|
|
157
|
+
].join("\n");
|
|
158
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* When compaction is due. Pi compacts on its own once context passes the window minus its reserve, and stays as the
|
|
3
|
+
* fallback for a full context. Freeflow says "compact now" 25k tokens before that, leaving room to prepare after a
|
|
4
|
+
* safe point, and warns earlier still: at 70% of the window, and at least 20k tokens before "compact now", so the
|
|
5
|
+
* agent has room to reach a safe point first.
|
|
6
|
+
*/
|
|
7
|
+
export const DEFAULT_RESERVE_TOKENS = 16_384;
|
|
8
|
+
const WARNING_SHARE = 0.7;
|
|
9
|
+
const WARNING_LEAD = 20_000;
|
|
10
|
+
const COMPACT_NOW_HEADROOM = 25_000;
|
|
11
|
+
/** Pi's effective reserve for a model: its per-model override, else the ordinary setting, else Pi's default. */
|
|
12
|
+
export function reserveTokens(settings, model) {
|
|
13
|
+
const compaction = settings?.compaction ?? {};
|
|
14
|
+
const override = model ? compaction.modelOverrides?.[`${model.provider}/${model.id}`] : undefined;
|
|
15
|
+
const value = override?.reserveTokens ?? compaction.reserveTokens;
|
|
16
|
+
return Number.isSafeInteger(value) && value >= 0 ? value : DEFAULT_RESERVE_TOKENS;
|
|
17
|
+
}
|
|
18
|
+
export function thresholds(window, reserve) {
|
|
19
|
+
const trigger = Math.max(0, window - reserve);
|
|
20
|
+
const compactNow = Math.max(0, trigger - COMPACT_NOW_HEADROOM);
|
|
21
|
+
return {
|
|
22
|
+
window,
|
|
23
|
+
trigger,
|
|
24
|
+
warning: Math.max(0, Math.min(Math.floor(window * WARNING_SHARE), compactNow - WARNING_LEAD)),
|
|
25
|
+
compactNow,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/** The strictest thresholds across models that may receive the full history (the active model and routing workers). */
|
|
29
|
+
export function strictest(models, settings) {
|
|
30
|
+
const all = models
|
|
31
|
+
.filter((model) => typeof model?.contextWindow === "number" && model.contextWindow > 0)
|
|
32
|
+
.map((model) => thresholds(model.contextWindow, reserveTokens(settings, model)));
|
|
33
|
+
if (!all.length) return undefined;
|
|
34
|
+
return all.reduce((a, b) => (b.warning < a.warning ? b : a));
|
|
35
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export const FREEFLOW_COMPACT = "freeflow_compact";
|
|
2
|
+
const DESCRIPTION =
|
|
3
|
+
"Compact the conversation into a new cycle. Use only when Freeflow says compaction is due or the user asks, and read the compaction skill first. Pass your summary and what to carry; compaction happens at the end of this turn, and the run continues from the summary, the carried context and a recovery message.";
|
|
4
|
+
/** Registered once, declared only while Freeflow compaction is effective (see applyCompactionTools). */
|
|
5
|
+
export function registerCompactionTool(pi, controller) {
|
|
6
|
+
pi.registerTool({
|
|
7
|
+
name: FREEFLOW_COMPACT,
|
|
8
|
+
label: "Compact",
|
|
9
|
+
description: DESCRIPTION,
|
|
10
|
+
parameters: {
|
|
11
|
+
type: "object",
|
|
12
|
+
additionalProperties: false,
|
|
13
|
+
properties: {
|
|
14
|
+
summary: {
|
|
15
|
+
type: "string",
|
|
16
|
+
description:
|
|
17
|
+
"The next cycle's working state, for a reader with none of this conversation. The compaction skill says what it must keep.",
|
|
18
|
+
},
|
|
19
|
+
carry: {
|
|
20
|
+
type: "array",
|
|
21
|
+
description:
|
|
22
|
+
"What to carry into the next cycle, within the budget the notice gives: files by path (read fresh at compaction, optional line ranges) and tool results by id from the notice's index.",
|
|
23
|
+
items: {
|
|
24
|
+
type: "object",
|
|
25
|
+
additionalProperties: false,
|
|
26
|
+
properties: {
|
|
27
|
+
file: { type: "string" },
|
|
28
|
+
lines: { type: "array", items: { type: "integer" }, description: "[first, last], 1-based" },
|
|
29
|
+
result: {
|
|
30
|
+
type: "string",
|
|
31
|
+
description:
|
|
32
|
+
"A tool result: its routing ref (such as ctx:1a2b3c4d) when Cognitive Routing is on, otherwise its id from the notice's list (such as r12)",
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
required: ["summary"],
|
|
39
|
+
},
|
|
40
|
+
// Callable from codemode scripts as well: agents that look for tools there first concluded, when it was missing,
|
|
41
|
+
// that they could not compact. The compaction still happens at the end of the turn, after the script returns.
|
|
42
|
+
exposure: "direct",
|
|
43
|
+
defaultActive: false,
|
|
44
|
+
executionMode: "sequential",
|
|
45
|
+
async execute(_id, params, _signal, _update, ctx) {
|
|
46
|
+
return { content: [{ type: "text", text: await controller.request(params, ctx) }] };
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
/** Declare or withdraw freeflow_compact when compaction's effective state changes, keeping other tools in place. */
|
|
51
|
+
export function applyCompactionTools(pi, effective) {
|
|
52
|
+
if (typeof pi.getActiveTools !== "function" || typeof pi.setActiveTools !== "function") return;
|
|
53
|
+
const current = pi.getActiveTools();
|
|
54
|
+
const present = current.includes(FREEFLOW_COMPACT);
|
|
55
|
+
if (effective && !present) pi.setActiveTools([...current, FREEFLOW_COMPACT]);
|
|
56
|
+
if (!effective && present) pi.setActiveTools(current.filter((name) => name !== FREEFLOW_COMPACT));
|
|
57
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Keyed by the reader and its getBranch function, so a reader whose source is swapped is walked again.
|
|
2
|
+
const cache = new WeakMap();
|
|
3
|
+
export function cachedBranch(reader) {
|
|
4
|
+
if (!reader?.getBranch) return [];
|
|
5
|
+
// Without a leaf id the branch cannot be keyed; fall back to Pi's walk.
|
|
6
|
+
if (!reader.getLeafId) return reader.getBranch();
|
|
7
|
+
const leaf = reader.getLeafId();
|
|
8
|
+
const hit = cache.get(reader);
|
|
9
|
+
if (hit && hit.leaf === leaf && hit.source === reader.getBranch) return hit.branch;
|
|
10
|
+
const branch = Object.freeze([...reader.getBranch()]);
|
|
11
|
+
cache.set(reader, { leaf, source: reader.getBranch, branch });
|
|
12
|
+
return branch;
|
|
13
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const isObject = (value) => !!value && typeof value === "object" && !Array.isArray(value);
|
|
2
|
+
/** Deterministic JSON: object keys sorted, undefined properties omitted, so equal values serialize equally. */
|
|
3
|
+
export function canonical(value) {
|
|
4
|
+
if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
|
|
5
|
+
if (isObject(value))
|
|
6
|
+
return `{${Object.keys(value)
|
|
7
|
+
.filter((k) => value[k] !== undefined)
|
|
8
|
+
.sort()
|
|
9
|
+
.map((k) => `${JSON.stringify(k)}:${canonical(value[k])}`)
|
|
10
|
+
.join(",")}}`;
|
|
11
|
+
return JSON.stringify(value) ?? "null";
|
|
12
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { fileURLToPath } from "node:url";
|
|
2
|
+
/**
|
|
3
|
+
* Freeflow's fixed command and skill surface: the commands it registers, the skills it lists to the model, and where
|
|
4
|
+
* their files live.
|
|
5
|
+
*/
|
|
6
|
+
export const WORKFLOW_COMMANDS = [
|
|
7
|
+
{ command: "discuss", skill: "discuss" },
|
|
8
|
+
{ command: "action-selection", skill: "action-selection" },
|
|
9
|
+
{ command: "track-work", skill: "track-work" },
|
|
10
|
+
{ command: "write-spec", skill: "write-spec" },
|
|
11
|
+
{ command: "review-artifact", skill: "review-artifact" },
|
|
12
|
+
{ command: "write-plan", skill: "write-plan" },
|
|
13
|
+
{ command: "write-docs", skill: "write-docs" },
|
|
14
|
+
{ command: "execute-work", skill: "execute-work" },
|
|
15
|
+
{ command: "simplify-code", skill: "simplify-code" },
|
|
16
|
+
{ command: "migration-work", skill: "migration-work" },
|
|
17
|
+
{ command: "diagnose-failure", skill: "diagnose-failure" },
|
|
18
|
+
{ command: "verify-work", skill: "verify-work" },
|
|
19
|
+
{ command: "review-work", skill: "review-work" },
|
|
20
|
+
{ command: "commit-work", skill: "commit-work" },
|
|
21
|
+
{ command: "handoff", skill: "handoff" },
|
|
22
|
+
{ command: "finish-branch", skill: "finish-branch" },
|
|
23
|
+
{ command: "release-work", skill: "release-work" },
|
|
24
|
+
{ command: "launch-work", skill: "launch-work" },
|
|
25
|
+
{ command: "bypass", skill: "bypass" },
|
|
26
|
+
];
|
|
27
|
+
export const CONTRIBUTOR_COMMANDS = ["setup-freeflow", "write-skill", "evaluate-skill"];
|
|
28
|
+
const FREEFLOW_MODEL_SKILL_NAMES = [
|
|
29
|
+
"action-selection",
|
|
30
|
+
"bypass",
|
|
31
|
+
"commit-work",
|
|
32
|
+
"decision-gate",
|
|
33
|
+
"migration-work",
|
|
34
|
+
"design-for-depth",
|
|
35
|
+
"diagnose-failure",
|
|
36
|
+
"discuss",
|
|
37
|
+
"evaluate-skill",
|
|
38
|
+
"execute-work",
|
|
39
|
+
"finish-branch",
|
|
40
|
+
"handoff",
|
|
41
|
+
"release-work",
|
|
42
|
+
"review-artifact",
|
|
43
|
+
"review-work",
|
|
44
|
+
"setup-freeflow",
|
|
45
|
+
"launch-work",
|
|
46
|
+
"simplify-code",
|
|
47
|
+
"track-work",
|
|
48
|
+
"verify-work",
|
|
49
|
+
"workflow",
|
|
50
|
+
"write-docs",
|
|
51
|
+
"write-plan",
|
|
52
|
+
"write-skill",
|
|
53
|
+
"write-spec",
|
|
54
|
+
];
|
|
55
|
+
export const STABLE_FREEFLOW_SURFACE = Object.freeze({
|
|
56
|
+
enabled: true,
|
|
57
|
+
cognitiveRouting: { effective: true },
|
|
58
|
+
toolExecution: { effective: true },
|
|
59
|
+
compaction: { effective: true },
|
|
60
|
+
});
|
|
61
|
+
export function freeflowSkillPath(skillName) {
|
|
62
|
+
return fileURLToPath(new URL(`../../../skills/${skillName}/SKILL.md`, import.meta.url));
|
|
63
|
+
}
|
|
64
|
+
export function freeflowCapabilitySkillPath(skillName) {
|
|
65
|
+
return fileURLToPath(new URL(`../../../capabilities/${skillName}/SKILL.md`, import.meta.url));
|
|
66
|
+
}
|
|
67
|
+
export function freeflowModelSkillPaths(capabilityState = undefined) {
|
|
68
|
+
const paths = FREEFLOW_MODEL_SKILL_NAMES.map((skillName) => freeflowSkillPath(skillName));
|
|
69
|
+
if (capabilityState?.cognitiveRouting?.effective === true)
|
|
70
|
+
paths.push(freeflowCapabilitySkillPath("cognitive-routing"));
|
|
71
|
+
if (capabilityState?.compaction?.effective === true) paths.push(freeflowCapabilitySkillPath("compaction"));
|
|
72
|
+
return paths;
|
|
73
|
+
}
|
|
74
|
+
export function skillPrompt(skill, args) {
|
|
75
|
+
const trimmed = args?.trim();
|
|
76
|
+
return trimmed ? `/skill:${skill}\n\n${trimmed}` : `/skill:${skill}`;
|
|
77
|
+
}
|