muonroi-cli 1.7.2 → 1.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/packages/agent-harness-core/src/event-filter.js +1 -0
- package/dist/packages/agent-harness-core/src/event-redact.js +8 -0
- package/dist/packages/agent-harness-core/src/mcp-server.d.ts +16 -0
- package/dist/packages/agent-harness-core/src/mcp-server.js +88 -10
- package/dist/packages/agent-harness-core/src/protocol.d.ts +15 -0
- package/dist/packages/agent-harness-core/src/selector.js +2 -2
- package/dist/packages/agent-harness-core/src/transports/sidechannel.js +1 -1
- package/dist/packages/agent-harness-opentui/src/agent-mode.js +1 -1
- package/dist/packages/agent-harness-opentui/src/install.js +1 -1
- package/dist/src/__test-stubs__/vitest-setup.js +4 -0
- package/dist/src/agent-harness/__tests__/mock-model.spec.js +54 -0
- package/dist/src/agent-harness/mock-model.d.ts +1 -1
- package/dist/src/agent-harness/mock-model.js +143 -6
- package/dist/src/agent-harness/test-spawn.js +3 -1
- package/dist/src/chat/chat-keychain.js +9 -1
- package/dist/src/cli/cost-forensics.js +7 -4
- package/dist/src/cli/keys.d.ts +2 -2
- package/dist/src/cli/keys.js +107 -28
- package/dist/src/cli/usage-report.js +2 -2
- package/dist/src/council/__tests__/abort-threading.test.d.ts +1 -0
- package/dist/src/council/__tests__/abort-threading.test.js +193 -0
- package/dist/src/council/__tests__/clarification-prompt.test.js +21 -1
- package/dist/src/council/__tests__/council-turn-length-emit.test.d.ts +1 -0
- package/dist/src/council/__tests__/council-turn-length-emit.test.js +130 -0
- package/dist/src/council/__tests__/debate-round-budget.test.d.ts +1 -0
- package/dist/src/council/__tests__/debate-round-budget.test.js +45 -0
- package/dist/src/council/__tests__/evaluator-metrics.test.js +3 -0
- package/dist/src/council/__tests__/post-debate-recommendation.test.d.ts +1 -0
- package/dist/src/council/__tests__/post-debate-recommendation.test.js +58 -0
- package/dist/src/council/__tests__/research-tools.test.js +4 -0
- package/dist/src/council/__tests__/round-tools.test.js +6 -0
- package/dist/src/council/clarifier-question-cap.test.d.ts +12 -0
- package/dist/src/council/clarifier-question-cap.test.js +73 -0
- package/dist/src/council/clarifier.d.ts +29 -1
- package/dist/src/council/clarifier.js +64 -1
- package/dist/src/council/debate-planner.d.ts +2 -1
- package/dist/src/council/debate-planner.js +5 -3
- package/dist/src/council/debate.d.ts +9 -0
- package/dist/src/council/debate.js +88 -8
- package/dist/src/council/index.d.ts +46 -1
- package/dist/src/council/index.js +125 -19
- package/dist/src/council/llm.js +41 -13
- package/dist/src/council/prompts.js +36 -1
- package/dist/src/council/types.d.ts +14 -1
- package/dist/src/ee/__tests__/export-transcripts.test.js +1 -1
- package/dist/src/ee/bridge.d.ts +3 -1
- package/dist/src/ee/bridge.js +9 -3
- package/dist/src/ee/bridge.test.js +1 -2
- package/dist/src/ee/client.js +15 -2
- package/dist/src/ee/recall-ledger.d.ts +20 -0
- package/dist/src/ee/recall-ledger.js +40 -1
- package/dist/src/ee/search.d.ts +25 -0
- package/dist/src/ee/search.js +73 -0
- package/dist/src/ee/types.d.ts +15 -1
- package/dist/src/ee/who-am-i.d.ts +41 -0
- package/dist/src/ee/who-am-i.js +143 -0
- package/dist/src/ee/who-am-i.test.d.ts +1 -0
- package/dist/src/ee/who-am-i.test.js +101 -0
- package/dist/src/flow/compaction/index.d.ts +1 -0
- package/dist/src/flow/compaction/index.js +4 -0
- package/dist/src/generated/version.d.ts +1 -1
- package/dist/src/generated/version.js +1 -1
- package/dist/src/headless/council-answers.js +1 -0
- package/dist/src/headless/output.d.ts +30 -1
- package/dist/src/headless/output.js +180 -0
- package/dist/src/headless/output.test.js +61 -1
- package/dist/src/hooks/index.js +48 -2
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +59 -62
- package/dist/src/lsp/client-normalize.test.d.ts +12 -0
- package/dist/src/lsp/client-normalize.test.js +34 -0
- package/dist/src/lsp/client.d.ts +1 -0
- package/dist/src/lsp/client.js +10 -2
- package/dist/src/lsp/manager.d.ts +1 -1
- package/dist/src/lsp/manager.js +13 -5
- package/dist/src/lsp/manager.test.js +41 -2
- package/dist/src/lsp/runtime.d.ts +1 -1
- package/dist/src/lsp/runtime.js +2 -2
- package/dist/src/maintain/__tests__/gh-create-pr.test.js +7 -3
- package/dist/src/maintain/__tests__/pr-builder.test.js +7 -3
- package/dist/src/mcp/__tests__/client-pool.spec.js +3 -3
- package/dist/src/mcp/__tests__/ee-tools.test.js +42 -14
- package/dist/src/mcp/__tests__/forensics-tools.test.js +3 -3
- package/dist/src/mcp/__tests__/lsp-tools.test.js +4 -4
- package/dist/src/mcp/auto-setup.js +0 -8
- package/dist/src/mcp/client-pool.d.ts +1 -1
- package/dist/src/mcp/client-pool.js +25 -9
- package/dist/src/mcp/ee-tools.d.ts +10 -0
- package/dist/src/mcp/ee-tools.js +34 -0
- package/dist/src/mcp/self-verify-jobs.d.ts +1 -0
- package/dist/src/mcp/self-verify-jobs.js +1 -3
- package/dist/src/mcp/self-verify-runner.js +1 -1
- package/dist/src/models/catalog-gemini.test.js +12 -10
- package/dist/src/models/catalog.json +106 -38
- package/dist/src/orchestrator/__tests__/auto-commit.test.d.ts +1 -0
- package/dist/src/orchestrator/__tests__/auto-commit.test.js +142 -0
- package/dist/src/orchestrator/__tests__/batch-turn-runner.test.js +3 -0
- package/dist/src/orchestrator/__tests__/delegations.test.d.ts +1 -0
- package/dist/src/orchestrator/__tests__/delegations.test.js +96 -0
- package/dist/src/orchestrator/__tests__/message-processor.test.js +2 -0
- package/dist/src/orchestrator/__tests__/prompts.test.d.ts +1 -0
- package/dist/src/orchestrator/__tests__/prompts.test.js +88 -0
- package/dist/src/orchestrator/__tests__/stream-runner.test.js +29 -0
- package/dist/src/orchestrator/__tests__/sub-session-delegation.test.d.ts +1 -0
- package/dist/src/orchestrator/__tests__/sub-session-delegation.test.js +507 -0
- package/dist/src/orchestrator/agent.test.js +5 -2
- package/dist/src/orchestrator/auto-commit.d.ts +110 -0
- package/dist/src/orchestrator/auto-commit.js +366 -0
- package/dist/src/orchestrator/batch-turn-runner.d.ts +3 -2
- package/dist/src/orchestrator/batch-turn-runner.js +2 -1
- package/dist/src/orchestrator/compaction-proposer-prompt.d.ts +8 -0
- package/dist/src/orchestrator/compaction-proposer-prompt.js +43 -0
- package/dist/src/orchestrator/compaction.d.ts +22 -0
- package/dist/src/orchestrator/compaction.js +42 -0
- package/dist/src/orchestrator/delegations.d.ts +1 -0
- package/dist/src/orchestrator/delegations.js +41 -0
- package/dist/src/orchestrator/error-utils.js +27 -2
- package/dist/src/orchestrator/message-processor.d.ts +23 -5
- package/dist/src/orchestrator/message-processor.js +226 -2573
- package/dist/src/orchestrator/orchestrator.d.ts +11 -2
- package/dist/src/orchestrator/orchestrator.js +530 -43
- package/dist/src/orchestrator/pending-calls.js +2 -1
- package/dist/src/orchestrator/preprocessor.d.ts +13 -0
- package/dist/src/orchestrator/preprocessor.js +146 -0
- package/dist/src/orchestrator/prompts.d.ts +16 -0
- package/dist/src/orchestrator/prompts.js +130 -67
- package/dist/src/orchestrator/safety-askcard.d.ts +66 -0
- package/dist/src/orchestrator/safety-askcard.js +74 -0
- package/dist/src/orchestrator/sandbox.test.js +8 -5
- package/dist/src/orchestrator/scope-ceiling.js +1 -1
- package/dist/src/orchestrator/stall-watchdog.d.ts +47 -0
- package/dist/src/orchestrator/stall-watchdog.js +23 -0
- package/dist/src/orchestrator/stall-watchdog.test.js +36 -1
- package/dist/src/orchestrator/stream-runner.js +52 -30
- package/dist/src/orchestrator/sub-agent-cap.d.ts +2 -0
- package/dist/src/orchestrator/sub-agent-cap.js +12 -4
- package/dist/src/orchestrator/sub-agent-model-tier.js +1 -1
- package/dist/src/orchestrator/subagent-compactor.d.ts +21 -0
- package/dist/src/orchestrator/subagent-compactor.js +148 -24
- package/dist/src/orchestrator/subagent-compactor.spec.js +249 -1
- package/dist/src/orchestrator/text-tool-call-detector.d.ts +9 -5
- package/dist/src/orchestrator/text-tool-call-detector.js +16 -12
- package/dist/src/orchestrator/text-tool-call-detector.test.js +66 -8
- package/dist/src/orchestrator/tool-args-repair.js +1 -1
- package/dist/src/orchestrator/tool-engine.d.ts +153 -0
- package/dist/src/orchestrator/tool-engine.js +3138 -0
- package/dist/src/orchestrator/turn-runner-deps.d.ts +3 -0
- package/dist/src/pil/__tests__/discovery-types.test.js +15 -4
- package/dist/src/pil/__tests__/discovery.test.js +89 -145
- package/dist/src/pil/__tests__/dual-run.test.js +2 -0
- package/dist/src/pil/__tests__/layer1-intent-trace.test.js +3 -0
- package/dist/src/pil/__tests__/layer1-intent.test.js +3 -0
- package/dist/src/pil/__tests__/layer16-clarity.test.js +35 -32
- package/dist/src/pil/__tests__/layer18-acceptance.test.js +1 -78
- package/dist/src/pil/__tests__/layer2_5-ponytail.test.d.ts +1 -0
- package/dist/src/pil/__tests__/layer2_5-ponytail.test.js +53 -0
- package/dist/src/pil/__tests__/layer3-ee-injection.test.js +67 -4
- package/dist/src/pil/__tests__/layer3-injected-chunk.test.js +14 -2
- package/dist/src/pil/__tests__/layer4-gsd.test.js +30 -0
- package/dist/src/pil/__tests__/layer5-context.test.js +39 -1
- package/dist/src/pil/__tests__/layer6-output.test.js +30 -2
- package/dist/src/pil/__tests__/llm-classify.test.js +79 -1
- package/dist/src/pil/__tests__/orchestrator-integration.test.js +3 -1
- package/dist/src/pil/__tests__/pipeline.test.js +11 -8
- package/dist/src/pil/__tests__/response-tools.test.js +52 -0
- package/dist/src/pil/agent-operating-contract.d.ts +1 -1
- package/dist/src/pil/agent-operating-contract.js +5 -3
- package/dist/src/pil/agent-operating-contract.test.js +2 -2
- package/dist/src/pil/cheap-model-playbook.d.ts +1 -1
- package/dist/src/pil/cheap-model-playbook.js +1 -1
- package/dist/src/pil/cheap-model-workbooks.d.ts +1 -1
- package/dist/src/pil/cheap-model-workbooks.js +1 -1
- package/dist/src/pil/config.d.ts +20 -0
- package/dist/src/pil/config.js +35 -0
- package/dist/src/pil/discovery-types.d.ts +32 -9
- package/dist/src/pil/discovery.d.ts +3 -3
- package/dist/src/pil/discovery.js +138 -244
- package/dist/src/pil/index.d.ts +1 -1
- package/dist/src/pil/index.js +1 -1
- package/dist/src/pil/layer1-intent.d.ts +9 -1
- package/dist/src/pil/layer1-intent.js +62 -7
- package/dist/src/pil/layer1-intent.test.js +112 -2
- package/dist/src/pil/layer15-context-scan.js +1 -1
- package/dist/src/pil/layer16-clarity.d.ts +21 -25
- package/dist/src/pil/layer16-clarity.js +52 -88
- package/dist/src/pil/layer18-acceptance.d.ts +13 -3
- package/dist/src/pil/layer18-acceptance.js +1 -75
- package/dist/src/pil/layer2-personality.js +7 -8
- package/dist/src/pil/layer2_5-ponytail.d.ts +2 -0
- package/dist/src/pil/layer2_5-ponytail.js +41 -0
- package/dist/src/pil/layer3-ee-injection.js +180 -14
- package/dist/src/pil/layer4-gsd.js +22 -8
- package/dist/src/pil/layer5-context.d.ts +1 -0
- package/dist/src/pil/layer5-context.js +26 -11
- package/dist/src/pil/layer6-output.js +23 -5
- package/dist/src/pil/llm-classify.d.ts +11 -0
- package/dist/src/pil/llm-classify.js +196 -3
- package/dist/src/pil/native-capabilities-workbook.d.ts +1 -1
- package/dist/src/pil/native-capabilities-workbook.js +4 -3
- package/dist/src/pil/pipeline.js +15 -1
- package/dist/src/pil/response-tools.d.ts +16 -0
- package/dist/src/pil/response-tools.js +41 -0
- package/dist/src/pil/schema.d.ts +8 -0
- package/dist/src/pil/schema.js +24 -3
- package/dist/src/pil/task-tier-map.js +7 -7
- package/dist/src/pil/types.d.ts +9 -3
- package/dist/src/product-loop/__tests__/discovery-interview.test.js +103 -1
- package/dist/src/product-loop/__tests__/gather-selectable-alts.test.js +34 -0
- package/dist/src/product-loop/__tests__/sprint-self-verify.test.js +12 -12
- package/dist/src/product-loop/discovery-interview.d.ts +20 -0
- package/dist/src/product-loop/discovery-interview.js +121 -7
- package/dist/src/product-loop/gather.js +19 -5
- package/dist/src/product-loop/loop-driver.js +2 -2
- package/dist/src/product-loop/sprint-self-verify.js +2 -2
- package/dist/src/providers/__tests__/reasoning-roundtrip.test.js +12 -0
- package/dist/src/providers/auth/__tests__/gemini-oauth.test.d.ts +1 -5
- package/dist/src/providers/auth/__tests__/gemini-oauth.test.js +1 -5
- package/dist/src/providers/auth/gcloud.d.ts +28 -0
- package/dist/src/providers/auth/gcloud.js +102 -0
- package/dist/src/providers/auth/gemini-oauth.d.ts +46 -19
- package/dist/src/providers/auth/gemini-oauth.js +292 -105
- package/dist/src/providers/auth/grok-oauth.d.ts +1 -1
- package/dist/src/providers/auth/grok-oauth.js +1 -1
- package/dist/src/providers/auth/registry.js +28 -6
- package/dist/src/providers/gemini.d.ts +1 -1
- package/dist/src/providers/gemini.js +10 -3
- package/dist/src/providers/keychain.d.ts +2 -2
- package/dist/src/providers/keychain.js +20 -2
- package/dist/src/providers/openai.js +5 -1
- package/dist/src/providers/runtime.d.ts +1 -1
- package/dist/src/providers/runtime.js +11 -2
- package/dist/src/providers/siliconflow-sse-repair.js +1 -1
- package/dist/src/providers/strategies/google.strategy.d.ts +9 -2
- package/dist/src/providers/strategies/google.strategy.js +159 -9
- package/dist/src/providers/strategies/thinking-mode.js +19 -6
- package/dist/src/providers/types.d.ts +1 -1
- package/dist/src/router/decide.test.js +40 -8
- package/dist/src/router/step-router.d.ts +20 -0
- package/dist/src/router/step-router.js +73 -0
- package/dist/src/self-qa/agentic-loop.js +30 -21
- package/dist/src/self-qa/orchestrator.js +5 -5
- package/dist/src/self-qa/scenario-planner.js +1 -1
- package/dist/src/self-qa/spec-emitter.js +4 -4
- package/dist/src/storage/__tests__/hierarchical-session.test.d.ts +1 -0
- package/dist/src/storage/__tests__/hierarchical-session.test.js +161 -0
- package/dist/src/storage/__tests__/sweep-stale-pending.test.js +2 -2
- package/dist/src/storage/index.d.ts +1 -1
- package/dist/src/storage/index.js +1 -1
- package/dist/src/storage/migrations.js +13 -1
- package/dist/src/storage/transcript-response-entry.test.js +18 -5
- package/dist/src/storage/transcript-view.js +7 -1
- package/dist/src/storage/transcript.d.ts +3 -0
- package/dist/src/storage/transcript.js +254 -73
- package/dist/src/storage/ui-interaction-log.d.ts +17 -0
- package/dist/src/storage/usage.js +22 -5
- package/dist/src/tools/__tests__/native-tools.test.js +6 -0
- package/dist/src/tools/bash.d.ts +36 -23
- package/dist/src/tools/bash.js +59 -301
- package/dist/src/tools/bash.test.js +2 -257
- package/dist/src/tools/file-tracker.d.ts +5 -0
- package/dist/src/tools/file-tracker.js +14 -0
- package/dist/src/tools/file.js +2 -0
- package/dist/src/tools/git-safety.d.ts +38 -1
- package/dist/src/tools/git-safety.js +94 -4
- package/dist/src/tools/git-safety.test.js +45 -1
- package/dist/src/tools/native-tools.d.ts +1 -1
- package/dist/src/tools/native-tools.js +66 -1
- package/dist/src/tools/registry-bash-empty-command.test.js +4 -3
- package/dist/src/tools/registry-git-safety.test.js +17 -6
- package/dist/src/tools/registry.d.ts +6 -0
- package/dist/src/tools/registry.js +215 -13
- package/dist/src/types/index.d.ts +8 -2
- package/dist/src/ui/app.d.ts +1 -0
- package/dist/src/ui/app.js +0 -0
- package/dist/src/ui/components/council-question-card.js +1 -0
- package/dist/src/ui/components/message-view.js +37 -3
- package/dist/src/ui/components/structured-response-view.js +7 -0
- package/dist/src/ui/components/task-list-panel.js +3 -12
- package/dist/src/ui/containers/chat-feed.d.ts +40 -0
- package/dist/src/ui/containers/chat-feed.js +66 -0
- package/dist/src/ui/containers/modals-layer.d.ts +87 -0
- package/dist/src/ui/containers/modals-layer.js +18 -0
- package/dist/src/ui/slash/__tests__/menu-parity.test.d.ts +1 -0
- package/dist/src/ui/slash/__tests__/menu-parity.test.js +1 -0
- package/dist/src/ui/slash/__tests__/ponytail.test.d.ts +1 -0
- package/dist/src/ui/slash/__tests__/ponytail.test.js +37 -0
- package/dist/src/ui/slash/expand.js +14 -1
- package/dist/src/ui/slash/export.js +16 -1
- package/dist/src/ui/slash/menu-items.js +1 -0
- package/dist/src/ui/slash/ponytail.d.ts +2 -0
- package/dist/src/ui/slash/ponytail.js +19 -0
- package/dist/src/ui/status-bar/store.js +0 -1
- package/dist/src/ui/status-bar/store.test.js +2 -2
- package/dist/src/ui/use-app-logic.d.ts +26 -0
- package/dist/src/ui/use-app-logic.js +0 -0
- package/dist/src/ui/utils/relaunch.js +1 -1
- package/dist/src/ui/utils/text.d.ts +11 -0
- package/dist/src/ui/utils/text.js +21 -1
- package/dist/src/ui/utils/text.test.js +25 -1
- package/dist/src/ui/utils/tools.js +3 -1
- package/dist/src/usage/cost-log.js +2 -2
- package/dist/src/usage/estimator.d.ts +14 -0
- package/dist/src/usage/estimator.js +22 -0
- package/dist/src/utils/__tests__/compaction-caps.test.d.ts +21 -0
- package/dist/src/utils/__tests__/compaction-caps.test.js +187 -0
- package/dist/src/utils/__tests__/llm-deadline-abort.test.d.ts +1 -0
- package/dist/src/utils/__tests__/llm-deadline-abort.test.js +33 -0
- package/dist/src/utils/__tests__/llm-deadline.test.js +16 -4
- package/dist/src/utils/__tests__/logger.test.d.ts +1 -0
- package/dist/src/utils/__tests__/logger.test.js +115 -0
- package/dist/src/utils/__tests__/settings-agent-first.test.d.ts +1 -0
- package/dist/src/utils/__tests__/settings-agent-first.test.js +48 -0
- package/dist/src/utils/install-manager.d.ts +1 -0
- package/dist/src/utils/install-manager.js +76 -7
- package/dist/src/utils/install-manager.test.js +43 -1
- package/dist/src/utils/llm-deadline.d.ts +9 -1
- package/dist/src/utils/llm-deadline.js +31 -2
- package/dist/src/utils/logger.d.ts +28 -0
- package/dist/src/utils/logger.js +171 -0
- package/dist/src/utils/permission-mode.d.ts +33 -0
- package/dist/src/utils/permission-mode.js +164 -3
- package/dist/src/utils/permission-mode.test.js +92 -1
- package/dist/src/utils/settings.d.ts +36 -32
- package/dist/src/utils/settings.js +151 -123
- package/dist/src/utils/update-checker.test.js +5 -1
- package/package.json +1 -1
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { truncateToBudget } from "./budget.js";
|
|
2
|
+
import { isPonytailModeEnabled } from "./config.js";
|
|
3
|
+
const PONYTAIL_INSTRUCTION = `[LAZY SENIOR / PONYTAIL MODE ACTIVE]
|
|
4
|
+
"The best code is the code you never wrote." You MUST adhere to the following Decision Ladder:
|
|
5
|
+
1. Standard Library first.
|
|
6
|
+
2. Native platform features next.
|
|
7
|
+
3. 1-line solution next.
|
|
8
|
+
4. YAGNI: Do not write it if not strictly necessary.
|
|
9
|
+
5. Smallest correct change.
|
|
10
|
+
|
|
11
|
+
DOCUMENTATION RULE: If you bypass a complex/scalable pattern in favor of a simple one to adhere to this rule, you MUST add a comment in the code starting exactly with "// Intentional simplification: [Reason]".`;
|
|
12
|
+
export async function layer2_5Ponytail(ctx) {
|
|
13
|
+
// If task is not coding/action-related (e.g., chitchat), we might not need it, but pipeline.ts already skips layers if taskType is null.
|
|
14
|
+
if (!isPonytailModeEnabled()) {
|
|
15
|
+
return {
|
|
16
|
+
...ctx,
|
|
17
|
+
layers: [
|
|
18
|
+
...ctx.layers,
|
|
19
|
+
{
|
|
20
|
+
name: "ponytail-mode",
|
|
21
|
+
applied: false,
|
|
22
|
+
delta: "skipped:disabled-by-config",
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
const trimmed = truncateToBudget(PONYTAIL_INSTRUCTION, Math.floor(ctx.tokenBudget * 0.15));
|
|
28
|
+
return {
|
|
29
|
+
...ctx,
|
|
30
|
+
enriched: `${ctx.enriched}\n\n${trimmed}`,
|
|
31
|
+
layers: [
|
|
32
|
+
...ctx.layers,
|
|
33
|
+
{
|
|
34
|
+
name: "ponytail-mode",
|
|
35
|
+
applied: true,
|
|
36
|
+
delta: `chars=${trimmed.length}`,
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=layer2_5-ponytail.js.map
|
|
@@ -17,10 +17,18 @@
|
|
|
17
17
|
import { createHash } from "node:crypto";
|
|
18
18
|
import { searchByText } from "../ee/bridge.js";
|
|
19
19
|
import { updateLastSurfacedState } from "../ee/intercept.js";
|
|
20
|
+
import { formatPendingReminder, isRecallLedgerEnabled, sessionRecallLedger } from "../ee/recall-ledger.js";
|
|
20
21
|
import { getRenderSink } from "../ee/render.js";
|
|
21
22
|
import { logInteraction } from "../storage/interaction-log.js";
|
|
22
23
|
import { classifyEeError, logEeFailure, readTimeoutEnv } from "../utils/ee-logger.js";
|
|
23
24
|
import { truncateToBudget } from "./budget.js";
|
|
25
|
+
/**
|
|
26
|
+
* Session-scoped cross-turn dedup: records which pending recall IDs have
|
|
27
|
+
* already been surfaced via the feedback nudge in a previous turn. Prevents
|
|
28
|
+
* the same unrated [id] list from consuming input tokens turn after turn.
|
|
29
|
+
* Cleared on session reset (process exit or ledger.reset()).
|
|
30
|
+
*/
|
|
31
|
+
const _surfacedPendingIds = new Map();
|
|
24
32
|
// Budget for the HTTP/in-process search round-trip. 60ms (legacy) was tuned for
|
|
25
33
|
// localhost Ollama and routinely tripped the abort on VPS thin-client setups
|
|
26
34
|
// where embedding goes through SiliconFlow.
|
|
@@ -117,8 +125,13 @@ function isT1Proven(p) {
|
|
|
117
125
|
return false;
|
|
118
126
|
}
|
|
119
127
|
}
|
|
120
|
-
async function queryEeBridge(raw) {
|
|
128
|
+
async function queryEeBridge(raw, taskType) {
|
|
121
129
|
try {
|
|
130
|
+
// Enrich query with task context so EE embedding is more precise.
|
|
131
|
+
// e.g. "analyze: vậy ở...fix?" vs generic "vậy ở...fix?" — the prefix
|
|
132
|
+
// shifts the embedding toward task-relevant entries and away from generic
|
|
133
|
+
// action-oriented behavioral patterns that score highly on any NL query.
|
|
134
|
+
const queryWithTask = taskType ? `[${taskType}] ${raw}` : raw;
|
|
122
135
|
// Parallel queries: T0 principles (lower floor, pre-validated abstractions)
|
|
123
136
|
// and T1/T2 behavioral (standard floor, contextual patterns). Running both
|
|
124
137
|
// concurrently keeps total latency at ~1500ms rather than ~3000ms.
|
|
@@ -126,8 +139,8 @@ async function queryEeBridge(raw) {
|
|
|
126
139
|
// prior "Progress ✔ DONE / elided" without the agent having to ask "task finished?".
|
|
127
140
|
const signal = AbortSignal.timeout(PIL_SEARCH_TIMEOUT_MS);
|
|
128
141
|
const [principleRaw, behavioralRaw, checkpointRaw] = await Promise.all([
|
|
129
|
-
searchByText(
|
|
130
|
-
searchByText(
|
|
142
|
+
searchByText(queryWithTask, ["experience-principles"], 3, signal),
|
|
143
|
+
searchByText(queryWithTask, ["experience-behavioral"], 4, signal),
|
|
131
144
|
searchByText('Context checkpoint summary OR "compaction checkpoint" recent Progress DONE elided OR tool-artifact OR "tool result id="', ["experience-behavioral"], 3, signal).catch(() => []),
|
|
132
145
|
]);
|
|
133
146
|
const principlePoints = principleRaw.filter((p) => (p.score ?? 0) >= PIL_PRINCIPLES_FLOOR);
|
|
@@ -192,23 +205,113 @@ export async function layer3EeInjection(ctx) {
|
|
|
192
205
|
const behavioralBudget = Math.floor(ctx.tokenBudget * 0.15);
|
|
193
206
|
const parts = [];
|
|
194
207
|
const deltas = [];
|
|
195
|
-
|
|
196
|
-
|
|
208
|
+
// Collection fallback by array position mirrors the legacy path's arm→collection
|
|
209
|
+
// mapping (t0 = principles, t2 = behavioral). The server (PIL schema_version
|
|
210
|
+
// 1.1+) may override per-point — e.g. a selfqa hit merged into the behavioral
|
|
211
|
+
// bucket carries collection="experience-selfqa" so ee_feedback resolves it.
|
|
212
|
+
let principleItems = ctx._brainData.t0_principles.map((p) => ({
|
|
213
|
+
...p,
|
|
214
|
+
collection: p.collection ?? "experience-principles",
|
|
215
|
+
}));
|
|
216
|
+
let behavioralItems = ctx._brainData.t2_patterns.map((p) => ({
|
|
217
|
+
...p,
|
|
218
|
+
collection: p.collection ?? "experience-behavioral",
|
|
219
|
+
}));
|
|
220
|
+
// Suppress already-fedback entries so they don't re-inject as noise.
|
|
221
|
+
if (isRecallLedgerEnabled()) {
|
|
222
|
+
principleItems = principleItems.filter((p) => !sessionRecallLedger.wasCleared(String(p.id)));
|
|
223
|
+
behavioralItems = behavioralItems.filter((p) => !sessionRecallLedger.wasCleared(String(p.id)));
|
|
224
|
+
}
|
|
225
|
+
// Render the [id:..] handle inline (mirrors formatPrincipleRules/Hints) so the
|
|
226
|
+
// [id collection] reminder below refers to handles the agent can actually see.
|
|
227
|
+
const renderLine = (p) => p.id ? `- ${p.text.slice(0, 120)} [id:${p.id}]` : `- ${p.text.slice(0, 120)}`;
|
|
228
|
+
if (principleItems.length > 0) {
|
|
229
|
+
const lines = principleItems.map(renderLine);
|
|
197
230
|
const block = truncateToBudget(`[principles: Generalized principles from past work]\n${lines.join("\n")}`, principlesBudget);
|
|
198
231
|
parts.push(block);
|
|
199
|
-
deltas.push(`principles=${
|
|
232
|
+
deltas.push(`principles=${principleItems.length}`);
|
|
200
233
|
}
|
|
201
|
-
if (
|
|
202
|
-
const lines =
|
|
234
|
+
if (behavioralItems.length > 0) {
|
|
235
|
+
const lines = behavioralItems.map(renderLine);
|
|
203
236
|
const block = truncateToBudget(`[experience: Relevant patterns from past work]\n${lines.join("\n")}`, behavioralBudget);
|
|
204
237
|
parts.push(block);
|
|
205
|
-
deltas.push(`behavioral=${
|
|
238
|
+
deltas.push(`behavioral=${behavioralItems.length}`);
|
|
206
239
|
}
|
|
207
240
|
deltas.push(`t1=${ctx._brainData.t1_rules.length}`);
|
|
208
241
|
deltas.push(`src=unified`);
|
|
242
|
+
// Close BOTH arms of the recall loop on the unified path, symmetric with the
|
|
243
|
+
// legacy path below (previously this formatter rendered text only — invisible
|
|
244
|
+
// to both arms). NEGATIVE arm: register surfaced ids for prompt-stale decay.
|
|
245
|
+
// POSITIVE arm: record the rateable points (those carrying an id from
|
|
246
|
+
// schema_version 1.1+) into the SAME session ledger the native ee_feedback
|
|
247
|
+
// builtin clears, then surface a dynamic [id collection] reminder so an
|
|
248
|
+
// explicit ee_feedback(followed) can credit the injection. No auto verdict is
|
|
249
|
+
// emitted (that would pollute Gate-4 precision). Points without an id (older
|
|
250
|
+
// server) fall through to the static nudge — rendered, but unrateable.
|
|
251
|
+
const ledgerEnabled = isRecallLedgerEnabled();
|
|
252
|
+
let ledgerRecorded = 0;
|
|
253
|
+
const rateable = [...principleItems, ...behavioralItems].filter((p) => p.id);
|
|
254
|
+
if (rateable.length > 0) {
|
|
255
|
+
updateLastSurfacedState(rateable.map((p) => String(p.id)));
|
|
256
|
+
if (ledgerEnabled) {
|
|
257
|
+
sessionRecallLedger.record(rateable.map((p) => ({ id: String(p.id), collection: p.collection })), `passive-injection (unified): ${ctx.raw.slice(0, 80)}`);
|
|
258
|
+
ledgerRecorded = rateable.length;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
if (parts.length > 0 && principleItems.length + behavioralItems.length > 0) {
|
|
262
|
+
const pending = ledgerEnabled ? sessionRecallLedger.pending() : [];
|
|
263
|
+
if (pending.length > 0) {
|
|
264
|
+
// Cross-turn dedup: only surface pending IDs NOT already shown in a prior
|
|
265
|
+
// turn. Once the agent has seen the [id collection] handle, re-listing it
|
|
266
|
+
// every turn is pure input noise.
|
|
267
|
+
const sid = ctx.sessionId ?? "_anon";
|
|
268
|
+
let surfaced = _surfacedPendingIds.get(sid);
|
|
269
|
+
if (!surfaced) {
|
|
270
|
+
surfaced = new Set();
|
|
271
|
+
_surfacedPendingIds.set(sid, surfaced);
|
|
272
|
+
}
|
|
273
|
+
const newPending = pending.filter((p) => !surfaced.has(p.id));
|
|
274
|
+
if (newPending.length > 0) {
|
|
275
|
+
for (const p of newPending)
|
|
276
|
+
surfaced.add(p.id);
|
|
277
|
+
parts.push(formatPendingReminder(newPending, { max: 5 }));
|
|
278
|
+
}
|
|
279
|
+
// else: all pending IDs were already surfaced — skip the nudge.
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
parts.push(RECALL_FEEDBACK_NUDGE);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
const injected = parts.join("\n");
|
|
286
|
+
try {
|
|
287
|
+
if (ctx.sessionId && parts.length > 0) {
|
|
288
|
+
logInteraction(ctx.sessionId, "ee_injection", {
|
|
289
|
+
eventSubtype: "injected",
|
|
290
|
+
data: {
|
|
291
|
+
phase: "pil_enrichment",
|
|
292
|
+
role: "knowledge_retriever",
|
|
293
|
+
source: "unified",
|
|
294
|
+
principleCount: principleItems.length,
|
|
295
|
+
behavioralCount: behavioralItems.length,
|
|
296
|
+
t1RuleCount: ctx._brainData.t1_rules.length,
|
|
297
|
+
pointIds: rateable.map((p) => String(p.id)),
|
|
298
|
+
injectedChars: injected.length,
|
|
299
|
+
// Recall-loop closure observability (harness verification reads these):
|
|
300
|
+
// rateable points recorded as pending debt this turn + total unrated.
|
|
301
|
+
ledgerRecorded,
|
|
302
|
+
ledgerPending: sessionRecallLedger.pendingCount(),
|
|
303
|
+
taskType: ctx.taskType ?? null,
|
|
304
|
+
domain: ctx.domain ?? null,
|
|
305
|
+
},
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
catch {
|
|
310
|
+
/* fail-open — never break injection path */
|
|
311
|
+
}
|
|
209
312
|
return {
|
|
210
313
|
...ctx,
|
|
211
|
-
enriched: parts.length > 0 ? `${ctx.enriched}\n${
|
|
314
|
+
enriched: parts.length > 0 ? `${ctx.enriched}\n${injected}` : ctx.enriched,
|
|
212
315
|
t1Rules: ctx._brainData.t1_rules,
|
|
213
316
|
layers: [
|
|
214
317
|
...ctx.layers,
|
|
@@ -221,7 +324,7 @@ export async function layer3EeInjection(ctx) {
|
|
|
221
324
|
};
|
|
222
325
|
}
|
|
223
326
|
// Legacy path: existing logic continues below — unchanged.
|
|
224
|
-
const result = await queryEeBridge(ctx.raw);
|
|
327
|
+
const result = await queryEeBridge(ctx.raw, ctx.taskType);
|
|
225
328
|
const { principlePoints, behavioralPoints, t1Rules } = result;
|
|
226
329
|
const totalPoints = principlePoints.length + behavioralPoints.length;
|
|
227
330
|
if (result.error) {
|
|
@@ -294,9 +397,39 @@ export async function layer3EeInjection(ctx) {
|
|
|
294
397
|
return text.length === 0 || !checkpointMarkerShas.has(payloadSha16(text));
|
|
295
398
|
})
|
|
296
399
|
: result.checkpointPoints || [];
|
|
297
|
-
|
|
400
|
+
// Feedback-cleared suppression: skip points that were already rated via ee_feedback in an earlier turn.
|
|
401
|
+
// This prevents already-judged entries from being re-injected as noise.
|
|
402
|
+
const ledgerEnabled = isRecallLedgerEnabled();
|
|
403
|
+
const clearedFilteredPrinciples = deduplicatedPrinciples.filter((p) => !(ledgerEnabled && sessionRecallLedger.wasCleared(String(p.id))));
|
|
404
|
+
const clearedFilteredBehavioral = deduplicatedBehavioral.filter((p) => !(ledgerEnabled && sessionRecallLedger.wasCleared(String(p.id))));
|
|
405
|
+
const clearedFilteredCheckpoints = deduplicatedCheckpoints.filter((p) => !(ledgerEnabled && sessionRecallLedger.wasCleared(String(p.id))));
|
|
406
|
+
const allPoints = [...clearedFilteredPrinciples, ...clearedFilteredBehavioral, ...clearedFilteredCheckpoints];
|
|
298
407
|
// STALE-01: Register injected point IDs for prompt-stale reconciliation.
|
|
299
408
|
updateLastSurfacedState(allPoints.map((p) => String(p.id)));
|
|
409
|
+
// Close the POSITIVE arm of the recall loop in-process. Record the RATEABLE
|
|
410
|
+
// injected points (principles + behavioral; checkpoints are artifacts, not
|
|
411
|
+
// recall verdicts) into the SAME session ledger the native ee_feedback builtin
|
|
412
|
+
// clears. Before this, the ledger was only ever populated by the external MCP
|
|
413
|
+
// ee.query, so in-CLI ee_feedback.clear() was a guaranteed no-op and nothing
|
|
414
|
+
// surfaced pending debt to the agent — leaving passive injections with an
|
|
415
|
+
// automatic NEGATIVE signal (prompt-stale decay every turn) but no positive
|
|
416
|
+
// one. Recording here makes a passive injection real, rateable debt that the
|
|
417
|
+
// dynamic reminder below names and an explicit ee_feedback(followed) resolves —
|
|
418
|
+
// the signal the brain needs to learn which injections were gold. No auto
|
|
419
|
+
// verdict is emitted (that would pollute Gate-4 precision); the agent rates
|
|
420
|
+
// deliberately. Collection is the search arm (deterministic), which is what
|
|
421
|
+
// ee_feedback requires.
|
|
422
|
+
let ledgerRecorded = 0;
|
|
423
|
+
if (ledgerEnabled) {
|
|
424
|
+
const rateableEntries = [
|
|
425
|
+
...deduplicatedPrinciples.map((p) => ({ id: String(p.id), collection: "experience-principles" })),
|
|
426
|
+
...deduplicatedBehavioral.map((p) => ({ id: String(p.id), collection: "experience-behavioral" })),
|
|
427
|
+
].filter((e) => e.id);
|
|
428
|
+
if (rateableEntries.length > 0) {
|
|
429
|
+
sessionRecallLedger.record(rateableEntries, `passive-injection: ${ctx.raw.slice(0, 80)}`);
|
|
430
|
+
ledgerRecorded = rateableEntries.length;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
300
433
|
// CQ-16b: Emit experience_injected StreamChunk so TUI can show collapsible block.
|
|
301
434
|
// Carry per-point {id, title, tier} so the TUI can show WHAT was injected, not
|
|
302
435
|
// just how many (the data already exists here; previously only the count + ids
|
|
@@ -341,7 +474,7 @@ export async function layer3EeInjection(ctx) {
|
|
|
341
474
|
if (cpText) {
|
|
342
475
|
const marker = `<!-- ee-checkpoint-injected:${payloadSha16(cpText)} -->`;
|
|
343
476
|
// Idea 5: raised from 0.08 to 0.12 for higher fidelity on critical progress + artifact refs.
|
|
344
|
-
parts.push(truncateToBudget(cpText
|
|
477
|
+
parts.push(truncateToBudget(`${cpText}\n${marker}`, Math.floor(ctx.tokenBudget * 0.12)));
|
|
345
478
|
}
|
|
346
479
|
// Close the recall feedback loop at the injection site: passively-injected
|
|
347
480
|
// experience (the agent did not ee_query for it) otherwise carries no feedback
|
|
@@ -350,8 +483,36 @@ export async function layer3EeInjection(ctx) {
|
|
|
350
483
|
// on long sessions; this nudge rides next to the [id:..] handles it refers to.
|
|
351
484
|
// Gated on rateable experience (principles/behavioral) — checkpoints are task
|
|
352
485
|
// artifacts, not recall verdicts.
|
|
486
|
+
// Dynamic, token-bounded reminder of accumulated unrated debt (this turn's
|
|
487
|
+
// fresh injections + any earlier still-unrated ones), naming the actual
|
|
488
|
+
// [id collection] so ee_feedback is actionable — the static nudge named no ids,
|
|
489
|
+
// so the model could not complete a rating even when willing. Falls back to the
|
|
490
|
+
// static nudge when the ledger is disabled. Gated on rateable experience.
|
|
491
|
+
// Cross-turn dedup: only surface pending IDs NOT already shown in a prior
|
|
492
|
+
// turn. Once surfaced, the agent has seen the [id collection] handle and can
|
|
493
|
+
// act on it (ee_feedback) or ignore it — re-listing the same IDs every turn
|
|
494
|
+
// is pure input noise with no new signal. If nothing is new, skip the nudge.
|
|
353
495
|
if (deduplicatedPrinciples.length + deduplicatedBehavioral.length > 0) {
|
|
354
|
-
|
|
496
|
+
const pending = ledgerEnabled ? sessionRecallLedger.pending() : [];
|
|
497
|
+
if (pending.length > 0) {
|
|
498
|
+
const sid = ctx.sessionId ?? "_anon";
|
|
499
|
+
let surfaced = _surfacedPendingIds.get(sid);
|
|
500
|
+
if (!surfaced) {
|
|
501
|
+
surfaced = new Set();
|
|
502
|
+
_surfacedPendingIds.set(sid, surfaced);
|
|
503
|
+
}
|
|
504
|
+
const newPending = pending.filter((p) => !surfaced.has(p.id));
|
|
505
|
+
if (newPending.length > 0) {
|
|
506
|
+
for (const p of newPending)
|
|
507
|
+
surfaced.add(p.id);
|
|
508
|
+
parts.push(formatPendingReminder(newPending, { max: 5 }));
|
|
509
|
+
}
|
|
510
|
+
// else: all pending IDs were already surfaced — skip the nudge entirely.
|
|
511
|
+
}
|
|
512
|
+
else {
|
|
513
|
+
// No pending debt at all; fall back to the generic static nudge.
|
|
514
|
+
parts.push(RECALL_FEEDBACK_NUDGE);
|
|
515
|
+
}
|
|
355
516
|
}
|
|
356
517
|
const injected = parts.join("\n");
|
|
357
518
|
try {
|
|
@@ -367,6 +528,11 @@ export async function layer3EeInjection(ctx) {
|
|
|
367
528
|
t1RuleCount: t1Rules.length,
|
|
368
529
|
pointIds: allPoints.map((p) => String(p.id)),
|
|
369
530
|
injectedChars: injected.length,
|
|
531
|
+
// Recall-loop closure observability (harness verification reads these
|
|
532
|
+
// from the interaction log): how many rateable points were recorded as
|
|
533
|
+
// pending debt this turn, and the total still-unrated debt afterwards.
|
|
534
|
+
ledgerRecorded,
|
|
535
|
+
ledgerPending: sessionRecallLedger.pendingCount(),
|
|
370
536
|
taskType: ctx.taskType ?? null,
|
|
371
537
|
domain: ctx.domain ?? null,
|
|
372
538
|
},
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* (questions surfaced via AskUserQuestion) is localised — at render time, by
|
|
17
17
|
* the agent, into the user's language.
|
|
18
18
|
*/
|
|
19
|
-
import { routeTask } from "../ee/bridge.js";
|
|
19
|
+
import { getWhoAmIProfile, routeTask } from "../ee/bridge.js";
|
|
20
20
|
import { buildDirective } from "../playbook/directives.js";
|
|
21
21
|
import { classifyEeError, logEeFailure } from "../utils/ee-logger.js";
|
|
22
22
|
import { truncateToBudget } from "./budget.js";
|
|
@@ -43,13 +43,16 @@ const DIRECTIVE_BUDGET_FRACTION = 0.25;
|
|
|
43
43
|
// value that fits it whole (truncateToBudget multiplies by CHARS_PER_TOKEN=4 →
|
|
44
44
|
// 700 tokens ≈ 2.8K chars). The fraction still wins when tokenBudget is large.
|
|
45
45
|
const DIRECTIVE_MIN_TOKENS = 700;
|
|
46
|
-
//
|
|
47
|
-
//
|
|
48
|
-
//
|
|
49
|
-
//
|
|
50
|
-
//
|
|
51
|
-
//
|
|
52
|
-
//
|
|
46
|
+
// WhoAmI v4.0 (wired): work_patterns.delegation_style="autonomous" biases the route
|
|
47
|
+
// toward "direct" — a resolved 'discuss' phase is dropped so the agent isn't funnelled
|
|
48
|
+
// into a clarify round the user didn't want (see the phase-resolution block below).
|
|
49
|
+
// Fail-open: absent dim → no change; only 'discuss' is affected (execute is untouched —
|
|
50
|
+
// autonomy is about skipping clarification, not skipping execution).
|
|
51
|
+
// TODO(WhoAmI-L4): still deferred — decision_speed="fast-intuitive" → trim heavy-tier
|
|
52
|
+
// directive: decision_speed IS available via getWhoAmIProfile, but trimming the HEAVY
|
|
53
|
+
// directive is risky (see DIRECTIVE_MIN_TOKENS below — past truncation dropped the
|
|
54
|
+
// rubric), so it stays manual pending a measured approach. Also: cache routeTask result
|
|
55
|
+
// per (taskType, domain) — unblocked by the provider, future.
|
|
53
56
|
export async function layer4Gsd(ctx) {
|
|
54
57
|
// Short-circuit: chitchat / pure-greeting inputs (detected by layer1) should
|
|
55
58
|
// NOT be wrapped in a GSD directive. Injecting "STANDARD task — apply
|
|
@@ -86,6 +89,17 @@ export async function layer4Gsd(ctx) {
|
|
|
86
89
|
// the directive reads cleanly without a phase hint.
|
|
87
90
|
routeSource = "none";
|
|
88
91
|
}
|
|
92
|
+
else if (phase === "discuss") {
|
|
93
|
+
// WhoAmI v4.0: an autonomous delegator ("cứ làm / just do it / don't ask") does
|
|
94
|
+
// not want to be funnelled into a clarify-first 'discuss' round. Drop the hint so
|
|
95
|
+
// the directive reads neutrally (bias toward the 'direct' path). getWhoAmIProfile
|
|
96
|
+
// is cached + fail-open → absent dim leaves the discuss phase exactly as-is.
|
|
97
|
+
const delegation = getWhoAmIProfile()?.dims["work_patterns.delegation_style"]?.value;
|
|
98
|
+
if (delegation === "autonomous") {
|
|
99
|
+
phase = null;
|
|
100
|
+
routeSource = `${routeSource}+autonomous:skip-discuss`;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
89
103
|
// Work depth is decided by the model in layer1's classify call (the 5th
|
|
90
104
|
// word → ctx.modelDepthTier). The regex `scoreComplexity` scorer has been
|
|
91
105
|
// removed from this decision path: depth must reflect what the task actually
|
|
@@ -1,15 +1,26 @@
|
|
|
1
1
|
import { promises as fs } from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
-
import { searchByText } from "../ee/bridge.js";
|
|
3
|
+
import { getWhoAmIProfile, searchByText } from "../ee/bridge.js";
|
|
4
4
|
import { truncateToBudget } from "./budget.js";
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
// skip that collection here to avoid double-injection.
|
|
5
|
+
// WhoAmI v4.0 (wired): `work_patterns.session_length` (short|medium|long), reachable
|
|
6
|
+
// via ../ee/bridge.js → who-am-i.ts, tunes the resume-digest staleness window below.
|
|
7
|
+
// TODO(WhoAmI-L5): `work_patterns.multitasking` (sequential-deep | task-switcher) IS
|
|
8
|
+
// also emitted and could tune recall freshness similarly — deferred until measured.
|
|
9
|
+
// Also: deduplicate with L3 — if L3 already injected experience-principles, skip that
|
|
10
|
+
// collection here to avoid double-injection.
|
|
12
11
|
const STALE_THRESHOLD_MS = 30 * 60 * 1000;
|
|
12
|
+
// session_length → resume-digest staleness window. Long deep-work sessions keep a
|
|
13
|
+
// resume digest relevant longer (relax to 60m); short bursts go stale sooner (tighten
|
|
14
|
+
// to 15m). medium / absent → the 30m default, so a machine with no committed
|
|
15
|
+
// session_length dim (the common case — needs N>=10 sessions) behaves byte-identically
|
|
16
|
+
// to pre-v4.0: zero regression. Pure + exported for deterministic unit testing.
|
|
17
|
+
export function staleThresholdMsForSessionLength(value) {
|
|
18
|
+
if (value === "long")
|
|
19
|
+
return 60 * 60 * 1000;
|
|
20
|
+
if (value === "short")
|
|
21
|
+
return 15 * 60 * 1000;
|
|
22
|
+
return STALE_THRESHOLD_MS;
|
|
23
|
+
}
|
|
13
24
|
// Single round-trip for both collections via /api/search; topK=5 yields
|
|
14
25
|
// up to 2 principles + 3 behavioral after server-side scoring.
|
|
15
26
|
const LAYER5_SEARCH_TIMEOUT_MS = 1500;
|
|
@@ -105,15 +116,19 @@ export async function layer5Context(ctx) {
|
|
|
105
116
|
else {
|
|
106
117
|
deltaSegments.push("principles=skipped-l1-unified");
|
|
107
118
|
}
|
|
108
|
-
// 2. Resume digest (5% budget)
|
|
119
|
+
// 2. Resume digest (5% budget). Staleness window is profile-tuned by session_length
|
|
120
|
+
// (fail-open: absent dim → 30m default, identical to pre-v4.0). getWhoAmIProfile
|
|
121
|
+
// is cached + fail-open, so this never adds latency or a failure path here.
|
|
109
122
|
const digest = ctx.resumeDigest;
|
|
110
123
|
if (digest?.trim()) {
|
|
111
|
-
const
|
|
124
|
+
const staleMs = staleThresholdMsForSessionLength(getWhoAmIProfile()?.dims["work_patterns.session_length"]?.value);
|
|
125
|
+
const isStale = typeof ctx.digestAgeMs === "number" && ctx.digestAgeMs > staleMs;
|
|
112
126
|
const stalePrefix = isStale ? "(stale — verify before relying)\n" : "";
|
|
113
127
|
const hint = `[flow-context: Resume]\n${stalePrefix}${digest.trim()}`;
|
|
114
128
|
const trimmed = truncateToBudget(hint, Math.floor(ctx.tokenBudget * 0.05));
|
|
115
129
|
parts.push(trimmed);
|
|
116
|
-
|
|
130
|
+
const windowTag = staleMs !== STALE_THRESHOLD_MS ? `,window=${staleMs / 60000}m` : "";
|
|
131
|
+
deltaSegments.push(`digest=${trimmed.length}ch${isStale ? ",stale" : ""}${windowTag}`);
|
|
117
132
|
}
|
|
118
133
|
// 3. Flow state (5% budget)
|
|
119
134
|
const flowBudget = Math.floor(ctx.tokenBudget * 0.05);
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* Resolved style is propagated back onto ctx.outputStyle so the orchestrator
|
|
13
13
|
* picks it up via applyPilSuffix without falling back to the hard "concise" default.
|
|
14
14
|
*/
|
|
15
|
-
import { classifyViaBrain } from "../ee/bridge.js";
|
|
15
|
+
import { classifyViaBrain, getWhoAmIProfile } from "../ee/bridge.js";
|
|
16
16
|
import { getProviderCapabilities } from "../providers/capabilities.js";
|
|
17
17
|
import { buildResponseTools } from "./response-tools.js";
|
|
18
18
|
const VALID_STYLES = ["concise", "balanced", "detailed"];
|
|
@@ -120,6 +120,12 @@ const NO_PREAMBLE_RULE = `\nFORBIDDEN OPENERS: do not start with "I'll", "I will
|
|
|
120
120
|
// noise. Applied only to non-question turns — question turns already get the same
|
|
121
121
|
// guidance from the Layer 4 QUESTION directive (buildQuestion).
|
|
122
122
|
const NO_BOOKKEEPING_NOTE = `\nWRITE FOR THE READER: the answer is for the human who asked. Do NOT append a provenance / compliance footer (e.g. "evidence only from this turn", "did not infer unopened files", token-budget notes) and do NOT restate internal rule / contract / layer / tool names as compliance — those are your operating rules, invisible to the reader. End on the answer's last substantive point.`;
|
|
123
|
+
// WhoAmI v4.0: a precise-correction feedback style means the user corrects with
|
|
124
|
+
// surgical edits, not rewrites. Bias code-producing tasks toward an AUDITABLE
|
|
125
|
+
// presentation so a follow-up correction can target one line. This is orthogonal to
|
|
126
|
+
// brevity (answer length) and delegation_style (clarify rounds) — it shapes the FORMAT
|
|
127
|
+
// of changes, not their length or whether to ask first.
|
|
128
|
+
const CORRECTION_AFFORDANCE_RULE = `\nAUDITABLE CHANGES: show exactly what changed — a unified diff or before/after for each edit, file:line anchored — and keep edits small and individually reviewable so a precise correction can target a single change.`;
|
|
123
129
|
const SUFFIXES = {
|
|
124
130
|
refactor: {
|
|
125
131
|
concise: `\nOUTPUT RULES (refactor): Show only changed code. Prefer unified diff or replacement function. No prose unless architecture changes. One sentence max if explanation needed. No preamble.`,
|
|
@@ -164,10 +170,13 @@ const SUFFIXES = {
|
|
|
164
170
|
detailed: `\nAnswer thoroughly. Use rich markdown structure (headings, lists, bold text, code blocks) to organize complex information so it is easy to scan and read.`,
|
|
165
171
|
},
|
|
166
172
|
};
|
|
167
|
-
//
|
|
168
|
-
//
|
|
169
|
-
//
|
|
170
|
-
//
|
|
173
|
+
// WhoAmI v4.0 (wired): brevity → ctx.outputStyle (layer1-intent.ts) drives answer
|
|
174
|
+
// length; feedback_style="precise-correction" → CORRECTION_AFFORDANCE_RULE on code
|
|
175
|
+
// tasks (auditable diffs, see applyPilSuffix below). The originally-assumed
|
|
176
|
+
// feedback_style="explicit" → gate-NO_PREAMBLE arm was dropped on purpose: EE emits
|
|
177
|
+
// implicit | precise-correction (no "explicit"), and gating preamble on it would
|
|
178
|
+
// double-count brevity's verbosity axis. The "implicit" value is likewise left
|
|
179
|
+
// unwired — its signal is already carried by brevity + delegation_style.
|
|
171
180
|
export function applyPilSuffix(systemPrompt, ctx, responseToolsActive = false) {
|
|
172
181
|
// Chitchat: layer6Output already skipped suffix work; mirror that here so
|
|
173
182
|
// direct callers (e.g. orchestrator) don't accidentally re-inject rules.
|
|
@@ -237,6 +246,15 @@ export function applyPilSuffix(systemPrompt, ctx, responseToolsActive = false) {
|
|
|
237
246
|
if (!isQuestionTurn) {
|
|
238
247
|
result += NO_BOOKKEEPING_NOTE;
|
|
239
248
|
}
|
|
249
|
+
// WhoAmI v4.0: precise-correctors get an auditable-changes nudge on code tasks.
|
|
250
|
+
// Fail-open: getWhoAmIProfile is cached + returns null when absent → unchanged.
|
|
251
|
+
// We intentionally do NOT wire feedback_style="implicit" — its signal (terseness /
|
|
252
|
+
// proceed-without-confirm) is already carried by brevity + delegation_style, so a
|
|
253
|
+
// second knob would double-count. Only the precise-correction arm is non-redundant.
|
|
254
|
+
if (ACTION_TASKS.has(ctx.taskType) &&
|
|
255
|
+
getWhoAmIProfile()?.dims["communication.feedback_style"]?.value === "precise-correction") {
|
|
256
|
+
result += CORRECTION_AFFORDANCE_RULE;
|
|
257
|
+
}
|
|
240
258
|
// T1 behavioral rules (proven-tier EE points set by Layer 3). These are
|
|
241
259
|
// project-specific reflexes the model MUST follow — injected as instructions,
|
|
242
260
|
// not as context hints, so they carry imperative weight rather than suggestion weight.
|
|
@@ -76,3 +76,14 @@ export type LlmClassifyFn = (prompt: string, signal?: AbortSignal) => Promise<Ll
|
|
|
76
76
|
* fail-open (keep prior taskType, do not block the turn).
|
|
77
77
|
*/
|
|
78
78
|
export declare function createLlmClassifier(factory: ProviderFactory, modelId: string): LlmClassifyFn;
|
|
79
|
+
export type SubSessionAction = "DIRECT_ANSWER" | "ROTATE_SESSION" | "SPAWN_SUB_SESSION";
|
|
80
|
+
export interface SubSessionRouteResult {
|
|
81
|
+
action: SubSessionAction;
|
|
82
|
+
confidence: number;
|
|
83
|
+
reason: string;
|
|
84
|
+
}
|
|
85
|
+
export declare function classifySubSessionActionHeuristic(prompt: string): SubSessionRouteResult | null;
|
|
86
|
+
export declare function classifySubSessionAction(factory: ProviderFactory, modelId: string, prompt: string, contextInfo?: {
|
|
87
|
+
currentChars: number;
|
|
88
|
+
threshold: number;
|
|
89
|
+
}, signal?: AbortSignal): Promise<SubSessionRouteResult | null>;
|