gentle-pi 4.2.0 → 4.4.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/README.md +340 -138
- package/assets/agents/gentle-ai-explore.md +1 -0
- package/assets/agents/gentle-ai-verify.md +6 -4
- package/assets/agents/gentle-ai-worker.md +7 -1
- package/assets/design-canvas/canvas.css +648 -0
- package/assets/design-canvas/canvas.js +1497 -0
- package/assets/design-canvas/index.html +88 -0
- package/assets/design-canvas/inspector.js +290 -0
- package/assets/orchestrator-delegation-reference.md +163 -0
- package/assets/orchestrator-delegation.md +25 -176
- package/assets/orchestrator-tracking.md +1 -1
- package/assets/orchestrator-verification.md +14 -8
- package/assets/orchestrator-writer.md +5 -1
- package/assets/orchestrator.md +11 -11
- package/bin/engram-guard +1 -1
- package/bin/gentle-shell.mjs +237 -139
- package/contracts/review-provider-contract-mirror/provider-contract.lock.json +8 -7
- package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/bundle/README.md +7 -0
- package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/bundle/manifest.json +11 -2
- package/contracts/review-provider-contract-mirror/v1.4.0/bundle/routing/pi.md +92 -0
- package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/generated/provider-capabilities.baseline.json +8 -1
- package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/generated/provider-roles.baseline.json +1 -1
- package/docs/assets/diagrams/agent-orchestration.svg +54 -15
- package/docs/assets/diagrams/gentleman-workflow.svg +69 -11
- package/docs/assets/diagrams/measured-routing.svg +49 -0
- package/docs/assets/diagrams/native-review.svg +52 -12
- package/docs/assets/diagrams/odd-workflow.svg +128 -66
- package/docs/assets/diagrams/permission-modes.svg +51 -0
- package/docs/assets/features/audio-notifications.png +0 -0
- package/docs/assets/features/command-palette.png +0 -0
- package/docs/bundled-install.md +65 -30
- package/docs/delegated-verification.md +16 -8
- package/docs/gentle-agents-activity.md +16 -6
- package/docs/gentle-music.md +61 -0
- package/docs/gentle-shell-uninstall.md +8 -1
- package/docs/gentle-shell.md +80 -9
- package/docs/install-wizard.md +37 -6
- package/docs/permission-modes.md +8 -3
- package/docs/readme-reference.md +120 -28
- package/docs/session-profile-format.md +26 -0
- package/docs/voice.md +259 -0
- package/docs/yolo-mode.md +38 -10
- package/extensions/ask-user-choice.ts +4 -1
- package/extensions/codegraph-tools.ts +68 -6
- package/extensions/gentle-agents.ts +270 -48
- package/extensions/gentle-ai.ts +490 -113
- package/extensions/gentle-design.ts +158 -0
- package/extensions/gentle-herdr-activity.ts +2 -3
- package/extensions/gentle-music.ts +289 -0
- package/extensions/gentle-shell.ts +359 -85
- package/extensions/gentle-todo.ts +43 -9
- package/extensions/gentle-voice.ts +11 -0
- package/extensions/quiet-tools.ts +1 -1
- package/extensions/session-scratch.ts +384 -0
- package/extensions/skill-registry.ts +63 -8
- package/extensions/startup-banner.ts +2 -3
- package/lib/agent-home.ts +8 -3
- package/lib/agent-profiles.ts +26 -0
- package/lib/agents-config.ts +35 -0
- package/lib/agents-protocol.ts +60 -1
- package/lib/agents-runner.ts +107 -9
- package/lib/agents-session-transport.ts +101 -6
- package/lib/agents-view.ts +3 -1
- package/lib/agents-widget.ts +14 -1
- package/lib/auto-permission-memory.ts +48 -18
- package/lib/auto-permission-runtime.ts +21 -6
- package/lib/bounded-writer-admission.ts +51 -0
- package/lib/clipboard-image.ts +147 -0
- package/lib/command-palette-catalog.ts +2 -4
- package/lib/commit-slice-signal.ts +100 -0
- package/lib/context-backstop.ts +120 -0
- package/lib/delivered-test-lint.ts +80 -0
- package/lib/design-canvas-server.ts +947 -0
- package/lib/design-comments.ts +437 -0
- package/lib/design-handoffs.ts +313 -0
- package/lib/design-open-browser.ts +58 -0
- package/lib/design-sources.ts +120 -0
- package/lib/destructive-command-guard.ts +120 -9
- package/lib/external-editor.ts +31 -0
- package/lib/gauge-theme.ts +146 -0
- package/lib/gentle-ai-binary.ts +28 -7
- package/lib/gentle-design.ts +513 -0
- package/lib/gentle-shell-bundled.ts +146 -36
- package/lib/gentle-shell-import-pi.ts +233 -0
- package/lib/gentle-shell-launcher.ts +154 -15
- package/lib/gentle-shell-startup-update.ts +61 -9
- package/lib/gentle-shell-uninstall.ts +51 -2
- package/lib/herdr-activity.ts +24 -0
- package/lib/image-attachments.ts +150 -0
- package/lib/inprocess-reviewer.ts +33 -2
- package/lib/nan-provider.ts +3 -0
- package/lib/native-review-cli.ts +20 -5
- package/lib/notification-audio-native.ts +149 -13
- package/lib/notification-audio.ts +4 -0
- package/lib/notification-pulse-worker.ts +82 -18
- package/lib/notification-service.ts +5 -1
- package/lib/orchestrator-discovery.ts +5 -1
- package/lib/orchestrator-presence.ts +87 -8
- package/lib/orchestrator-scope.ts +31 -3
- package/lib/orchestrator-state.ts +11 -3
- package/lib/permission-mode-policy.ts +2 -2
- package/lib/provider-contract-bundle.ts +99 -53
- package/lib/review-candidate-view-owner.ts +29 -19
- package/lib/review-candidate-view.ts +36 -2
- package/lib/review-host-relay.ts +11 -2
- package/lib/review-reminder-receipt.ts +24 -1
- package/lib/review-risk-assessment.ts +43 -38
- package/lib/review-session-standing-permission.ts +3 -1
- package/lib/session-profile-append-controller.ts +713 -0
- package/lib/session-profile-disk-reader.ts +182 -0
- package/lib/session-profile-freeze.ts +30 -1
- package/lib/session-profile-persistence.ts +15 -7
- package/lib/session-scratch.ts +523 -0
- package/lib/session-worktree-registry.ts +7 -0
- package/lib/shell-bar.ts +29 -28
- package/lib/shell-changes-view.ts +80 -13
- package/lib/shell-changes.ts +81 -5
- package/lib/shell-gauge.ts +49 -6
- package/lib/shell-prompt.ts +4 -4
- package/lib/shell-sidebar-layout.ts +26 -6
- package/lib/shell-todo.ts +24 -5
- package/lib/shell-usage-view.ts +5 -1
- package/lib/shell-usage.ts +7 -7
- package/lib/verifier-admission.ts +30 -0
- package/lib/vim-editor-adapter.ts +11 -8
- package/lib/voice-artifacts.ts +188 -0
- package/lib/voice-command.ts +576 -0
- package/lib/voice-install.ts +455 -0
- package/lib/voice-platform.ts +99 -0
- package/lib/voice-push-to-talk.ts +262 -0
- package/lib/voice-session.ts +460 -0
- package/lib/voice-settings.ts +50 -0
- package/lib/voice-ui.ts +158 -0
- package/lib/yolo-session-policy.ts +58 -22
- package/lib/yolo-temp-scratch.ts +69 -0
- package/package.json +1 -2
- package/runtime/gentle-ai-binary.mjs +28 -7
- package/runtime/gentle-shell-bundled.mjs +145 -35
- package/runtime/gentle-shell-import-pi.mjs +234 -0
- package/runtime/gentle-shell-launcher.mjs +152 -13
- package/runtime/gentle-shell-startup-update.mjs +61 -9
- package/runtime/gentle-shell-uninstall.mjs +51 -2
- package/runtime/native-review-cli.mjs +19 -4
- package/runtime/review-risk-assessment.mjs +43 -38
- package/scripts/build-runtime-modules.mjs +1 -0
- package/scripts/bundled-engram-migration.mjs +119 -0
- package/scripts/gentle-ai-installer.mjs +10 -10
- package/scripts/installer-downloads.mjs +7 -7
- package/scripts/installer-preflight.mjs +5 -3
- package/scripts/installer-server.mjs +14 -4
- package/scripts/installer-windows.mjs +37 -7
- package/scripts/main-channel.mjs +94 -19
- package/scripts/pi-update.mjs +34 -6
- package/scripts/run-test-suite.mjs +5 -0
- package/scripts/verify-package-files.mjs +43 -13
- package/scripts/voice-worker.cjs +476 -0
- package/skills/design/SKILL.md +110 -0
- package/skills/gentle-ai/SKILL.md +3 -3
- package/skills/work-unit-commits/SKILL.md +5 -3
- package/tests/agent-profiles.test.ts +24 -0
- package/tests/agent-risk-escalation.test.ts +37 -10
- package/tests/agents-config.test.ts +61 -0
- package/tests/agents-fake-child.ts +8 -1
- package/tests/agents-protocol.test.ts +32 -0
- package/tests/agents-runner.test.ts +485 -7
- package/tests/agents-session-transport.test.ts +53 -3
- package/tests/ask-user-choice.test.ts +30 -0
- package/tests/auto-mode.test.ts +17 -0
- package/tests/auto-permission-memory-diagnostics.test.ts +56 -0
- package/tests/auto-permission-runtime.test.ts +85 -1
- package/tests/autonomous-guard.test.ts +142 -0
- package/tests/bounded-writer-admission.test.ts +11 -3
- package/tests/bundled-install.test.ts +3 -3
- package/tests/card-content-policy.test.ts +19 -9
- package/tests/child-safety.test.ts +39 -0
- package/tests/clipboard-image.test.ts +114 -0
- package/tests/codegraph-tools.test.ts +123 -2
- package/tests/command-palette.test.ts +15 -5
- package/tests/commit-slice-signal.test.ts +162 -0
- package/tests/context-backstop.test.ts +225 -0
- package/tests/delegate-for-reason-contract.test.ts +92 -24
- package/tests/delivered-test-lint.test.ts +105 -0
- package/tests/design-canvas-assets.test.ts +710 -0
- package/tests/design-canvas-server.test.ts +1096 -0
- package/tests/design-comments.test.ts +201 -0
- package/tests/design-handoffs.test.ts +282 -0
- package/tests/design-open-browser.test.ts +70 -0
- package/tests/design-sources.test.ts +132 -0
- package/tests/destructive-command-guard.test.ts +85 -1
- package/tests/engram-safety.test.ts +132 -57
- package/tests/external-editor.test.ts +84 -0
- package/tests/fixtures/primary-session-prompt/gentleman.golden.md +143 -0
- package/tests/fixtures/provider-contract-bundle/v1.4.0/README.md +29 -0
- package/tests/fixtures/provider-contract-bundle/v1.4.0/manifest.json +83 -0
- package/tests/fixtures/provider-contract-bundle/v1.4.0/orchestration/pi.md +70 -0
- package/tests/fixtures/provider-contract-bundle/v1.4.0/routing/pi.md +92 -0
- package/tests/fixtures/provider-contract-bundle/v1.4.0/schemas/lens.schema.json +16 -0
- package/tests/fixtures/provider-contract-bundle/v1.4.0/schemas/refuter.schema.json +1 -0
- package/tests/fixtures/provider-contract-bundle/v1.4.0/schemas/targeted-validator.schema.json +1 -0
- package/tests/fixtures/provider-contract-bundle/v1.4.0/vectors/lens.json +1 -0
- package/tests/fixtures/provider-contract-bundle/v1.4.0/vectors/refuter.json +1 -0
- package/tests/fixtures/provider-contract-bundle/v1.4.0/vectors/targeted-validator.json +1 -0
- package/tests/gauge-theme.test.ts +120 -0
- package/tests/gentle-agents.test.ts +645 -21
- package/tests/gentle-ai-binary.test.ts +1 -1
- package/tests/gentle-ai-child-guards.test.ts +61 -0
- package/tests/gentle-ai-doctor-herdr.test.ts +94 -0
- package/tests/gentle-ai-installer.test.ts +51 -51
- package/tests/gentle-ai.test.ts +292 -13
- package/tests/gentle-design.test.ts +1313 -0
- package/tests/gentle-music.test.ts +335 -0
- package/tests/gentle-shell-bin.test.ts +163 -0
- package/tests/gentle-shell-bundled.test.ts +392 -176
- package/tests/gentle-shell-import-pi.test.ts +262 -0
- package/tests/gentle-shell-launcher.test.ts +107 -2
- package/tests/gentle-shell-startup-update.test.ts +77 -1
- package/tests/gentle-shell-uninstall.test.ts +89 -0
- package/tests/gentle-shell.test.ts +225 -17
- package/tests/gentle-todo.test.ts +190 -0
- package/tests/headless-delivery-question.test.ts +58 -0
- package/tests/herdr-activity.test.ts +34 -1
- package/tests/image-attachments.test.ts +119 -0
- package/tests/image-paste-chips.test.ts +236 -0
- package/tests/inprocess-reviewer.test.ts +55 -2
- package/tests/installer-bundles.test.ts +12 -6
- package/tests/installer-posix-bootstrap.test.ts +8 -8
- package/tests/installer-preflight.test.ts +16 -0
- package/tests/installer-server.test.ts +10 -2
- package/tests/installer-windows-bootstrap.test.ts +94 -7
- package/tests/installer-windows-diagnostics.test.ts +111 -0
- package/tests/main-channel-upgrade.test.ts +232 -2
- package/tests/main-channel.test.ts +140 -21
- package/tests/nan-provider.test.ts +36 -0
- package/tests/native-review-capability-contract.test.ts +17 -4
- package/tests/native-review-parity.test.ts +23 -2
- package/tests/no-self-pause-contract.test.ts +5 -2
- package/tests/notification-audio-native.test.ts +128 -9
- package/tests/notification-customize.test.ts +17 -5
- package/tests/odd-integration.test.ts +5 -1
- package/tests/odd-routing-canonical-ratchet.test.ts +128 -162
- package/tests/odd-routing-contract.test.ts +115 -30
- package/tests/orchestrator-budget.test.ts +22 -8
- package/tests/orchestrator-discovery.test.ts +29 -0
- package/tests/orchestrator-presence.test.ts +100 -2
- package/tests/orchestrator-rdd-ownership.test.ts +3 -1
- package/tests/orchestrator-scope.test.ts +80 -0
- package/tests/orchestrator-state.test.ts +29 -0
- package/tests/orchestrator-status-publication-contract.test.ts +12 -8
- package/tests/package-files.test.ts +34 -0
- package/tests/package-manifest.test.ts +24 -20
- package/tests/permission-mode-policy.test.ts +10 -1
- package/tests/pi-update-launcher.test.ts +21 -2
- package/tests/pi-update.test.ts +99 -4
- package/tests/primary-session-prompt.test.ts +101 -0
- package/tests/provider-contract-bundle.test.ts +118 -0
- package/tests/provider-contract-mirror.test.ts +24 -0
- package/tests/quiet-tool-rendering.test.ts +23 -0
- package/tests/rdd-aware-verification-contract.test.ts +29 -11
- package/tests/rdd-status-line.test.ts +79 -0
- package/tests/review-agent-end-preflight.test.ts +6 -0
- package/tests/review-candidate-view.test.ts +49 -0
- package/tests/review-contract-prompt.test.ts +5 -2
- package/tests/review-controller-native-routing.test.ts +14 -1
- package/tests/review-controller.test.ts +1 -1
- package/tests/review-host-relay-routing.test.ts +147 -3
- package/tests/review-host-relay.test.ts +9 -2
- package/tests/review-json-arguments.test.ts +20 -3
- package/tests/review-loadout-rdd-off-sdk.test.ts +258 -0
- package/tests/review-owner-identity.test.ts +132 -0
- package/tests/review-relay-transport-agent.test.ts +26 -0
- package/tests/review-reminder-receipt.test.ts +31 -1
- package/tests/review-risk-assessment.test.ts +163 -76
- package/tests/review-session-standing-permission-controller.test.ts +14 -1
- package/tests/review-session-standing-permission.test.ts +27 -1
- package/tests/run-test-suite.test.ts +15 -0
- package/tests/runtime-harness.mjs +16 -6
- package/tests/session-changes-shell.test.ts +1 -1
- package/tests/session-changes.test.ts +2 -1
- package/tests/session-profile-append-controller-fork.test.ts +458 -0
- package/tests/session-profile-append-controller-pi.test.ts +290 -0
- package/tests/session-profile-append-controller.test.ts +731 -0
- package/tests/session-profile-disk-reader-pi.test.ts +183 -0
- package/tests/session-profile-disk-reader.test.ts +311 -0
- package/tests/session-profile-freeze.test.ts +23 -0
- package/tests/session-scratch.test.ts +1011 -0
- package/tests/session-subject-routing-contract.test.ts +2 -1
- package/tests/session-worktree-registry.test.ts +13 -1
- package/tests/shell-bar.test.ts +21 -2
- package/tests/shell-changes-view.test.ts +137 -1
- package/tests/shell-changes.test.ts +148 -1
- package/tests/shell-gauge.test.ts +42 -0
- package/tests/shell-prompt.test.ts +3 -3
- package/tests/shell-render-cache.test.ts +134 -1
- package/tests/shell-sidebar-layout.test.ts +50 -0
- package/tests/short-check-routing-contract.test.ts +1 -1
- package/tests/skill-collision-prefixes.test.ts +3 -1
- package/tests/skill-registry-watcher.test.ts +17 -5
- package/tests/skill-registry.test.ts +47 -3
- package/tests/small-task-inline-contract.test.ts +37 -0
- package/tests/standalone-config-home.test.ts +324 -0
- package/tests/startup-banner.test.ts +5 -4
- package/tests/startup-home-repo.test.ts +34 -0
- package/tests/support/orchestrator-modules.ts +1 -0
- package/tests/task-size-routing-contract.test.ts +70 -10
- package/tests/test-scratch-contract.test.ts +102 -0
- package/tests/test-strength-contract.test.ts +36 -1
- package/tests/tool-batching-contract.test.ts +64 -0
- package/tests/verification-proportionality.test.ts +46 -0
- package/tests/verifier-admission.test.ts +154 -0
- package/tests/verify-agent-contract.test.ts +8 -8
- package/tests/voice-command.test.ts +773 -0
- package/tests/voice-install.test.ts +323 -0
- package/tests/voice-platform.test.ts +176 -0
- package/tests/voice-push-to-talk.test.ts +444 -0
- package/tests/voice-session.test.ts +434 -0
- package/tests/voice-settings.test.ts +49 -0
- package/tests/voice-ui.test.ts +97 -0
- package/tests/voice-worker.test.ts +445 -0
- package/tests/weak-model-economy-prompt.test.ts +32 -0
- package/tests/windows-hidden-processes.test.ts +30 -2
- package/tests/writer-edit-surface-scope.test.ts +3 -0
- package/tests/writer-feature-document-admission.test.ts +156 -0
- package/tests/yolo-customize.test.ts +5 -1
- package/tests/yolo-mode.test.ts +19 -1
- package/tests/yolo-session-policy-capture.test.ts +104 -0
- package/tests/yolo-temp-scratch.test.ts +71 -0
- package/scripts/mirror-odd-routing.mjs +0 -242
- /package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/bundle/orchestration/pi.md +0 -0
- /package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/bundle/schemas/lens.schema.json +0 -0
- /package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/bundle/schemas/refuter.schema.json +0 -0
- /package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/bundle/schemas/targeted-validator.schema.json +0 -0
- /package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/bundle/vectors/lens.json +0 -0
- /package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/bundle/vectors/refuter.json +0 -0
- /package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/bundle/vectors/targeted-validator.json +0 -0
|
@@ -5,15 +5,17 @@ import { createGentleAiExtension } from "../extensions/gentle-ai.ts";
|
|
|
5
5
|
import { NATIVE_REVIEW_MODE_SOURCE, type NativeReviewCli } from "../lib/native-review-cli.ts";
|
|
6
6
|
import {
|
|
7
7
|
decodeAgentRiskEscalation,
|
|
8
|
-
escalatedRisk,
|
|
9
8
|
HIGH_RISK_ITEMS,
|
|
10
9
|
REVIEW_ASSESSMENT_SCHEMA,
|
|
11
10
|
VERIFICATION_TIER,
|
|
11
|
+
verificationRisk,
|
|
12
12
|
} from "../lib/review-risk-assessment.ts";
|
|
13
13
|
|
|
14
14
|
// gentle-shell#1494 S6: the agent may raise a candidate's risk to high by
|
|
15
15
|
// citing one item of the shared high-risk list, never lower it. The raise
|
|
16
|
-
// travels inside the existing assess call; no new operation.
|
|
16
|
+
// travels inside the existing assess call; no new operation. Verification by
|
|
17
|
+
// named risk: that escalation is now the only way to get the independent
|
|
18
|
+
// verifier; a native high or unassessable tier informs only.
|
|
17
19
|
|
|
18
20
|
test("the high-risk list has exactly the six items of the always-on Task Size section", () => {
|
|
19
21
|
assert.deepEqual(Object.keys(HIGH_RISK_ITEMS).map(Number), [1, 2, 3, 4, 5, 6]);
|
|
@@ -45,23 +47,25 @@ test("decodeAgentRiskEscalation rejects unknown items, empty or oversized reason
|
|
|
45
47
|
}
|
|
46
48
|
});
|
|
47
49
|
|
|
48
|
-
|
|
50
|
+
// Replaces the escalatedRisk test: the plan risk is high only with an
|
|
51
|
+
// escalation; without one a native high or unassessable tier becomes medium.
|
|
52
|
+
test("verificationRisk makes every escalated tier high and maps the rest to passive or medium", () => {
|
|
49
53
|
const escalation = { item: 3 as const, reason: "changes a published export" };
|
|
50
|
-
assert.equal(
|
|
51
|
-
assert.equal(
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
54
|
+
for (const tier of Object.values(VERIFICATION_TIER)) assert.equal(verificationRisk(tier, escalation), VERIFICATION_TIER.HIGH, tier);
|
|
55
|
+
assert.equal(verificationRisk(VERIFICATION_TIER.PASSIVE, undefined), VERIFICATION_TIER.PASSIVE);
|
|
56
|
+
for (const tier of [VERIFICATION_TIER.MEDIUM, VERIFICATION_TIER.HIGH, VERIFICATION_TIER.UNASSESSABLE]) {
|
|
57
|
+
assert.equal(verificationRisk(tier, undefined), VERIFICATION_TIER.MEDIUM, tier);
|
|
58
|
+
}
|
|
55
59
|
});
|
|
56
60
|
|
|
57
|
-
function assessTool(): { execute: (id: string, params: Record<string, unknown>, signal: AbortSignal | undefined, onUpdate: undefined, ctx: ExtensionContext) => Promise<{ details: unknown }> } {
|
|
61
|
+
function assessTool(nativeRisk: "passive" | "medium" | "high" = "medium"): { execute: (id: string, params: Record<string, unknown>, signal: AbortSignal | undefined, onUpdate: undefined, ctx: ExtensionContext) => Promise<{ details: unknown }> } {
|
|
58
62
|
const tools = new Map<string, any>();
|
|
59
63
|
const pi = { on() {}, registerCommand() {}, registerTool(tool: { name: string }) { tools.set(tool.name, tool); } } as unknown as ExtensionAPI;
|
|
60
64
|
const nativeReviewCli: Partial<NativeReviewCli> = {
|
|
61
65
|
reviewMode: async () => ({ operation: "status", scope: "clone", status: { global: "off", cloneLocal: "off", effective: "off", source: NATIVE_REVIEW_MODE_SOURCE.GLOBAL } }),
|
|
62
66
|
assess: async () => ({
|
|
63
67
|
schema: REVIEW_ASSESSMENT_SCHEMA,
|
|
64
|
-
risk:
|
|
68
|
+
risk: nativeRisk,
|
|
65
69
|
reasons: [],
|
|
66
70
|
changedPaths: 1,
|
|
67
71
|
changedLines: 3,
|
|
@@ -121,3 +125,26 @@ test("gentle_review assess: agentEscalation says whether the escalation changed
|
|
|
121
125
|
const { details } = await tool.execute("esc-5", { operation: "assess", input }, undefined, undefined, ctx);
|
|
122
126
|
assert.equal((details as { agentEscalation: { applied: boolean } }).agentEscalation.applied, true, "medium raised to high is applied");
|
|
123
127
|
});
|
|
128
|
+
|
|
129
|
+
test("gentle_review assess: a native high without an escalation informs only and adds no verifier", async () => {
|
|
130
|
+
const tool = assessTool("high");
|
|
131
|
+
for (const writer of [{ writerModelId: "openai/gpt-6.1-sol", writerEffort: "high" }, { writerModelId: "openai/gpt-5-mini", writerEffort: "low" }]) {
|
|
132
|
+
const { details } = await tool.execute("esc-6", { operation: "assess", input: JSON.stringify(writer) }, undefined, undefined, ctx);
|
|
133
|
+
const plan = details as { risk: string; nativeRisk: string; plan: { independentVerifier: boolean; writerSelfVerification: boolean } };
|
|
134
|
+
assert.equal(plan.nativeRisk, VERIFICATION_TIER.HIGH);
|
|
135
|
+
assert.equal(plan.risk, VERIFICATION_TIER.MEDIUM, writer.writerModelId);
|
|
136
|
+
assert.equal(plan.plan.writerSelfVerification, true);
|
|
137
|
+
assert.equal(plan.plan.independentVerifier, false, `${writer.writerModelId}: neither a native high nor the writer's model adds a verifier`);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
test("gentle_review assess: an escalation over a native high is what adds the verifier", async () => {
|
|
142
|
+
const tool = assessTool("high");
|
|
143
|
+
const input = JSON.stringify({ escalate: { item: 1, reason: "rewrites stored records" } });
|
|
144
|
+
const { details } = await tool.execute("esc-7", { operation: "assess", input }, undefined, undefined, ctx);
|
|
145
|
+
const plan = details as { risk: string; nativeRisk: string; agentEscalation: { applied: boolean }; plan: { independentVerifier: boolean } };
|
|
146
|
+
assert.equal(plan.nativeRisk, VERIFICATION_TIER.HIGH);
|
|
147
|
+
assert.equal(plan.risk, VERIFICATION_TIER.HIGH);
|
|
148
|
+
assert.equal(plan.agentEscalation.applied, true, "without the escalation the plan would be medium");
|
|
149
|
+
assert.equal(plan.plan.independentVerifier, true);
|
|
150
|
+
});
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
parseFrontmatter,
|
|
15
15
|
parseModelRef,
|
|
16
16
|
resolveAgentProfile,
|
|
17
|
+
unmatchedProfileKeys,
|
|
17
18
|
withPinnedModelProfiles,
|
|
18
19
|
} from "../lib/agents-config.ts";
|
|
19
20
|
import { THINKING_LEVELS } from "../lib/model-routing-authority.ts";
|
|
@@ -247,3 +248,63 @@ test("a pinned profile replaces subagent routing and leaves every other default
|
|
|
247
248
|
// repository can pin "everything inherits" without touching the global store.
|
|
248
249
|
assert.deepEqual(withPinnedModelProfiles(global, {}).modelProfiles, {});
|
|
249
250
|
});
|
|
251
|
+
|
|
252
|
+
// Issue #2196 rework (PR #2233 maintainer decision): role keys that name no
|
|
253
|
+
// discovered agent must be reported, with a did-you-mean suggestion, instead of
|
|
254
|
+
// being silently ignored while the child inherits the orchestrator model.
|
|
255
|
+
test("unmatchedProfileKeys reports profile keys that match no discovered agent", () => {
|
|
256
|
+
const worker = {
|
|
257
|
+
name: "gentle-ai-worker",
|
|
258
|
+
description: "",
|
|
259
|
+
filePath: "/x/worker.md",
|
|
260
|
+
scope: "global" as const,
|
|
261
|
+
instructions: "",
|
|
262
|
+
model: undefined,
|
|
263
|
+
thinking: undefined,
|
|
264
|
+
mode: undefined,
|
|
265
|
+
tools: [],
|
|
266
|
+
};
|
|
267
|
+
const explore = { ...worker, name: "gentle-ai-explore" };
|
|
268
|
+
const profiles = {
|
|
269
|
+
worker: { model: { provider: "nan", id: "glm5.3" }, thinking: undefined },
|
|
270
|
+
WORKER: { model: { provider: "nan", id: "glm5.3" }, thinking: undefined },
|
|
271
|
+
review_risk: { model: undefined, thinking: "high" as const },
|
|
272
|
+
explore: { model: undefined, thinking: undefined },
|
|
273
|
+
};
|
|
274
|
+
assert.deepEqual(unmatchedProfileKeys(profiles, [worker, explore]), [
|
|
275
|
+
{ key: "worker", suggestion: "gentle-ai-worker" },
|
|
276
|
+
{ key: "WORKER", suggestion: "gentle-ai-worker" },
|
|
277
|
+
{ key: "review_risk", suggestion: undefined },
|
|
278
|
+
{ key: "explore", suggestion: "gentle-ai-explore" },
|
|
279
|
+
]);
|
|
280
|
+
// A key that exactly matches an agent name never reports, and an empty
|
|
281
|
+
// profile set reports nothing.
|
|
282
|
+
assert.deepEqual(unmatchedProfileKeys({ "gentle-ai-worker": { model: undefined, thinking: undefined } }, [worker]), []);
|
|
283
|
+
assert.deepEqual(unmatchedProfileKeys({}, [worker]), []);
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
// Cortex QA adversarial follow-up (R5 pin): the did-you-mean mapping exists to
|
|
287
|
+
// make a misconfiguration visible, never to resolve; a short key must keep
|
|
288
|
+
// yielding an unresolved profile so the role inherits frontmatter and default
|
|
289
|
+
// routing exactly as before the fix.
|
|
290
|
+
test("resolveAgentProfile never resolves through the suggestion mapping", () => {
|
|
291
|
+
const worker = {
|
|
292
|
+
name: "gentle-ai-worker",
|
|
293
|
+
description: "",
|
|
294
|
+
filePath: "/x/worker.md",
|
|
295
|
+
scope: "global" as const,
|
|
296
|
+
instructions: "",
|
|
297
|
+
model: { provider: "openai-codex", id: "gpt-5.6-terra" },
|
|
298
|
+
thinking: undefined,
|
|
299
|
+
mode: undefined,
|
|
300
|
+
tools: [],
|
|
301
|
+
};
|
|
302
|
+
const config = parseAgentsConfig(
|
|
303
|
+
{ model_profiles: { worker: { model: "nan/glm5.3", effort: "high" } } },
|
|
304
|
+
undefined,
|
|
305
|
+
);
|
|
306
|
+
const resolved = resolveAgentProfile(worker, config);
|
|
307
|
+
assert.equal(resolved.model?.provider, "openai-codex", "the short key must not route; the agent frontmatter model wins");
|
|
308
|
+
assert.equal(resolved.source.model, "definition");
|
|
309
|
+
assert.ok(unmatchedProfileKeys(config.modelProfiles, [worker]).some((entry) => entry.key === "worker" && entry.suggestion === "gentle-ai-worker"), "the same short key is still reported with its suggestion");
|
|
310
|
+
});
|
|
@@ -17,7 +17,7 @@ export interface FakeChild {
|
|
|
17
17
|
message(event: Record<string, unknown>): void;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
export function fakeChild(options: { exitOnKill?: boolean; pid?: number } = {}): FakeChild {
|
|
20
|
+
export function fakeChild(options: { exitOnKill?: boolean; exitOnStdinEnd?: boolean; pid?: number } = {}): FakeChild {
|
|
21
21
|
const emitter = new EventEmitter();
|
|
22
22
|
const stdin = new PassThrough();
|
|
23
23
|
const stdout = new PassThrough();
|
|
@@ -38,6 +38,13 @@ export function fakeChild(options: { exitOnKill?: boolean; pid?: number } = {}):
|
|
|
38
38
|
stdout.write(`${JSON.stringify({ type: "response", id: command.id, command: command.type, success: true, data })}\n`);
|
|
39
39
|
}
|
|
40
40
|
});
|
|
41
|
+
const origEnd = stdin.end.bind(stdin);
|
|
42
|
+
stdin.end = ((...args: unknown[]) => {
|
|
43
|
+
const res = (origEnd as Function)(...args);
|
|
44
|
+
// Preserve existing fixtures while allowing EOF and signal exits to vary independently.
|
|
45
|
+
if (options.exitOnStdinEnd ?? options.exitOnKill ?? true) queueMicrotask(() => emitter.emit("exit", 0, null));
|
|
46
|
+
return res;
|
|
47
|
+
}) as typeof stdin.end;
|
|
41
48
|
const child: ChildLike = {
|
|
42
49
|
pid: options.pid,
|
|
43
50
|
stdin,
|
|
@@ -10,7 +10,9 @@ import {
|
|
|
10
10
|
TASK_STATUS,
|
|
11
11
|
taskLabel,
|
|
12
12
|
TaskStore,
|
|
13
|
+
TERMINAL_RETENTION,
|
|
13
14
|
THREAD_ITEM,
|
|
15
|
+
isFinished,
|
|
14
16
|
type TaskRecord,
|
|
15
17
|
} from "../lib/agents-protocol.ts";
|
|
16
18
|
|
|
@@ -274,6 +276,36 @@ test("TaskStore notifies only the listeners of the task that changed and keeps s
|
|
|
274
276
|
assert.deepEqual(store.thread("missing"), emptyThread());
|
|
275
277
|
});
|
|
276
278
|
|
|
279
|
+
// Finished tasks must release their weight: a bounded window of the most
|
|
280
|
+
// recent ones stays readable, older ones leave the store entirely, and a
|
|
281
|
+
// terminal task's listeners go quiet after the one final transition.
|
|
282
|
+
test("TaskStore keeps a bounded window of finished tasks and silences terminal listeners", () => {
|
|
283
|
+
const store = new TaskStore();
|
|
284
|
+
const seen: string[] = [];
|
|
285
|
+
store.add(record({ id: "watched", status: TASK_STATUS.RUNNING, lastActivityAt: 1 }));
|
|
286
|
+
store.add(record({ id: "filler", status: TASK_STATUS.RUNNING, lastActivityAt: 2 }));
|
|
287
|
+
store.subscribe("watched", (task) => seen.push(task.status));
|
|
288
|
+
// `watched` completes the window once it finishes, so the next terminal
|
|
289
|
+
// task evicts exactly the oldest one.
|
|
290
|
+
for (let index = 0; index < TERMINAL_RETENTION - 1; index += 1) {
|
|
291
|
+
store.add(record({ id: `done-${index}`, status: TASK_STATUS.COMPLETED, lastActivityAt: 10 + index }));
|
|
292
|
+
}
|
|
293
|
+
assert.equal(store.list().filter((task) => isFinished(task.status)).length, TERMINAL_RETENTION - 1, "retained finished tasks stay at the cap");
|
|
294
|
+
assert.ok(store.get("watched") && store.get("filler"), "running tasks are never evicted");
|
|
295
|
+
store.update("watched", { status: TASK_STATUS.COMPLETED, endedAt: 50 });
|
|
296
|
+
assert.deepEqual(seen, ["completed"], "the terminal transition itself still notifies exactly once");
|
|
297
|
+
store.apply("watched", { type: TASK_EVENT.TEXT, text: "late" }, 60);
|
|
298
|
+
assert.deepEqual(seen, ["completed"], "a terminal task's listener stays quiet afterwards");
|
|
299
|
+
store.add(record({ id: "newest", status: TASK_STATUS.COMPLETED, lastActivityAt: 1_000 }));
|
|
300
|
+
assert.equal(store.get("done-0"), undefined, "the oldest finished task is evicted");
|
|
301
|
+
assert.ok(store.get("done-1") && store.get("newest"), "recent finished tasks remain readable");
|
|
302
|
+
assert.ok(store.get("filler"), "running tasks survive eviction");
|
|
303
|
+
assert.equal(store.list().filter((task) => isFinished(task.status)).length, TERMINAL_RETENTION);
|
|
304
|
+
assert.deepEqual(store.thread("done-0"), emptyThread(), "an evicted task's thread weight is released");
|
|
305
|
+
assert.ok(store.thread("done-1").limits.maxItems > 0, "a retained finished task stays renderable");
|
|
306
|
+
assert.equal(store.summary().finished, TERMINAL_RETENTION, "summaries reflect the bounded window");
|
|
307
|
+
});
|
|
308
|
+
|
|
277
309
|
test("TaskStore.apply moves the task to waiting on ask, back to running on any later event, and counts turns", () => {
|
|
278
310
|
const store = new TaskStore();
|
|
279
311
|
store.add(record({ id: "a", status: TASK_STATUS.RUNNING }));
|