gentle-pi 4.2.0 → 4.3.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 +336 -137
- 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/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 +9 -9
- package/bin/gentle-shell.mjs +170 -22
- 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 +33 -3
- package/docs/delegated-verification.md +10 -8
- package/docs/gentle-agents-activity.md +11 -5
- package/docs/gentle-shell-uninstall.md +8 -1
- package/docs/gentle-shell.md +5 -4
- package/docs/install-wizard.md +8 -1
- package/docs/permission-modes.md +1 -1
- package/docs/readme-reference.md +107 -19
- package/docs/yolo-mode.md +21 -8
- package/extensions/codegraph-tools.ts +68 -6
- package/extensions/gentle-agents.ts +99 -12
- package/extensions/gentle-ai.ts +284 -52
- package/extensions/gentle-herdr-activity.ts +2 -3
- package/extensions/gentle-shell.ts +27 -12
- package/extensions/gentle-todo.ts +43 -9
- package/extensions/quiet-tools.ts +1 -1
- package/extensions/session-scratch.ts +365 -0
- package/extensions/startup-banner.ts +2 -3
- package/lib/agent-home.ts +8 -3
- package/lib/agents-protocol.ts +3 -0
- package/lib/agents-runner.ts +55 -6
- package/lib/agents-view.ts +3 -1
- package/lib/bounded-writer-admission.ts +51 -0
- package/lib/command-palette-catalog.ts +0 -4
- package/lib/commit-slice-signal.ts +100 -0
- package/lib/context-backstop.ts +84 -0
- package/lib/delivered-test-lint.ts +80 -0
- package/lib/destructive-command-guard.ts +120 -9
- package/lib/gauge-theme.ts +146 -0
- package/lib/gentle-ai-binary.ts +28 -7
- package/lib/gentle-shell-bundled.ts +39 -3
- package/lib/gentle-shell-import-pi.ts +233 -0
- package/lib/gentle-shell-launcher.ts +145 -11
- package/lib/gentle-shell-uninstall.ts +18 -1
- package/lib/herdr-activity.ts +24 -0
- package/lib/native-review-cli.ts +9 -1
- package/lib/orchestrator-discovery.ts +5 -1
- package/lib/orchestrator-presence.ts +9 -0
- package/lib/orchestrator-scope.ts +21 -3
- 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-risk-assessment.ts +43 -38
- package/lib/review-session-standing-permission.ts +3 -1
- package/lib/session-profile-freeze.ts +30 -1
- package/lib/session-scratch.ts +474 -0
- package/lib/shell-bar.ts +25 -25
- package/lib/shell-changes-view.ts +80 -13
- package/lib/shell-gauge.ts +49 -6
- package/lib/shell-todo.ts +23 -4
- package/lib/shell-usage-view.ts +5 -1
- package/lib/shell-usage.ts +7 -7
- package/lib/verifier-admission.ts +29 -0
- 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 +38 -2
- package/runtime/gentle-shell-import-pi.mjs +234 -0
- package/runtime/gentle-shell-launcher.mjs +143 -9
- package/runtime/gentle-shell-uninstall.mjs +18 -1
- package/runtime/native-review-cli.mjs +8 -0
- package/runtime/review-risk-assessment.mjs +43 -38
- package/scripts/build-runtime-modules.mjs +1 -0
- package/scripts/bundled-engram-migration.mjs +125 -0
- package/scripts/gentle-ai-installer.mjs +10 -10
- package/scripts/installer-server.mjs +14 -4
- package/scripts/main-channel.mjs +3 -2
- package/scripts/run-test-suite.mjs +5 -0
- package/scripts/verify-package-files.mjs +19 -13
- package/skills/gentle-ai/SKILL.md +3 -3
- package/skills/work-unit-commits/SKILL.md +5 -3
- package/tests/agent-risk-escalation.test.ts +37 -10
- package/tests/agents-runner.test.ts +260 -3
- package/tests/autonomous-guard.test.ts +122 -0
- package/tests/bounded-writer-admission.test.ts +11 -3
- package/tests/card-content-policy.test.ts +19 -9
- package/tests/child-safety.test.ts +39 -0
- package/tests/codegraph-tools.test.ts +123 -2
- package/tests/command-palette.test.ts +14 -4
- package/tests/commit-slice-signal.test.ts +162 -0
- package/tests/context-backstop.test.ts +159 -0
- package/tests/delegate-for-reason-contract.test.ts +91 -24
- package/tests/delivered-test-lint.test.ts +105 -0
- package/tests/destructive-command-guard.test.ts +85 -1
- package/tests/engram-safety.test.ts +1 -1
- 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 +282 -3
- 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-shell-bin.test.ts +163 -0
- package/tests/gentle-shell-bundled.test.ts +169 -6
- package/tests/gentle-shell-import-pi.test.ts +262 -0
- package/tests/gentle-shell-launcher.test.ts +79 -0
- package/tests/gentle-shell-uninstall.test.ts +30 -0
- package/tests/gentle-shell.test.ts +42 -9
- package/tests/gentle-todo.test.ts +179 -0
- package/tests/headless-delivery-question.test.ts +58 -0
- package/tests/herdr-activity.test.ts +34 -1
- package/tests/installer-server.test.ts +10 -2
- package/tests/installer-windows-bootstrap.test.ts +33 -4
- package/tests/native-review-capability-contract.test.ts +7 -1
- package/tests/native-review-parity.test.ts +22 -1
- package/tests/no-self-pause-contract.test.ts +5 -2
- package/tests/odd-integration.test.ts +5 -1
- package/tests/odd-routing-canonical-ratchet.test.ts +127 -162
- package/tests/odd-routing-contract.test.ts +115 -30
- package/tests/orchestrator-budget.test.ts +19 -8
- package/tests/orchestrator-discovery.test.ts +29 -0
- package/tests/orchestrator-rdd-ownership.test.ts +3 -1
- package/tests/orchestrator-scope.test.ts +66 -0
- package/tests/orchestrator-status-publication-contract.test.ts +12 -8
- package/tests/package-manifest.test.ts +24 -20
- package/tests/pi-update-launcher.test.ts +21 -2
- 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 +59 -2
- package/tests/review-loadout-rdd-off-sdk.test.ts +237 -0
- package/tests/review-owner-identity.test.ts +132 -0
- 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-profile-freeze.test.ts +23 -0
- package/tests/session-scratch.test.ts +945 -0
- package/tests/session-subject-routing-contract.test.ts +2 -1
- package/tests/shell-bar.test.ts +7 -0
- package/tests/shell-changes-view.test.ts +137 -1
- package/tests/shell-gauge.test.ts +42 -0
- 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 +69 -9
- 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 +137 -0
- package/tests/verify-agent-contract.test.ts +8 -8
- package/tests/windows-hidden-processes.test.ts +5 -0
- package/tests/writer-edit-surface-scope.test.ts +3 -0
- package/tests/writer-feature-document-admission.test.ts +156 -0
- package/tests/yolo-mode.test.ts +18 -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
|
@@ -26,8 +26,9 @@ import { VISUAL_SETTINGS_CHANGED } from "../lib/shell-sidebar.ts";
|
|
|
26
26
|
import { resolveVisualSettings } from "../lib/visual-customization-policy.ts";
|
|
27
27
|
import { createCompletionQueue } from "../lib/agents-completion-delivery.ts";
|
|
28
28
|
import { createAgentMessageQueue, type PendingAgentMessage } from "../lib/agents-message-delivery.ts";
|
|
29
|
-
import { AGENT_MODE, discoverAgents, formatModelRef, loadAgentsConfig, resolveAgentProfile, withPinnedModelProfiles, type AgentDefinition, type AgentMode } from "../lib/agents-config.ts";
|
|
30
|
-
import { freezeSessionProfileAtStartup, inheritedProfileDriftNotice, resolveSessionProfile, sessionProfileRoutingAt } from "../lib/session-profile-freeze.ts";
|
|
29
|
+
import { AGENT_MODE, PROFILE_SOURCE, discoverAgents, formatModelRef, loadAgentsConfig, resolveAgentProfile, withPinnedModelProfiles, type AgentDefinition, type AgentMode, type ProfileSource } from "../lib/agents-config.ts";
|
|
30
|
+
import { freezeSessionProfileAtStartup, inheritedProfileDriftNotice, resolveSessionProfile, sessionProfileRoutingAt, type InheritedProfileOptions, type SessionProfileResolution } from "../lib/session-profile-freeze.ts";
|
|
31
|
+
import { resolveProfilePin, resolveUnversionedProjectProfile } from "../lib/agent-profile-pin.ts";
|
|
31
32
|
import { resolveBackgroundSubagentsPolicy } from "../lib/background-subagents-policy.ts";
|
|
32
33
|
import { installBackgroundCacheWarming } from "../lib/background-cache-warming.ts";
|
|
33
34
|
import { isFinished, MISSING_TOOLS_NOTE_PREFIX, TASK_EVENT, TASK_STATUS, TaskStore, type AskRequest, type TaskRecord } from "../lib/agents-protocol.ts";
|
|
@@ -49,6 +50,7 @@ import { discoverOrchestrators } from "../lib/orchestrator-discovery.ts";
|
|
|
49
50
|
import { consultPublishedMetadata, unavailableMetadata, type MetadataReceipt } from "../lib/orchestrator-consultation.ts";
|
|
50
51
|
import { HelperCostPermission } from "../lib/orchestrator-helper-consent.ts";
|
|
51
52
|
import { OrchestratorStateCache } from "../lib/orchestrator-state.ts";
|
|
53
|
+
import { TODO_PROGRESS_EVENT, type TodoProgress } from "../lib/shell-todo.ts";
|
|
52
54
|
import { normalizeTaskSubject } from "../lib/orchestrator-alias.ts";
|
|
53
55
|
import { decodeWorkDescriptor } from "../lib/orchestrator-work.ts";
|
|
54
56
|
import { validateWorkFilter, searchPublishedWork } from "../lib/orchestrator-work-search.ts";
|
|
@@ -186,6 +188,44 @@ function childExtensionRequest(env: NodeJS.ProcessEnv, curated: string[] | undef
|
|
|
186
188
|
return curated && curated.length > 0 ? { extensionPaths: [...curated] } : {};
|
|
187
189
|
}
|
|
188
190
|
|
|
191
|
+
// gentle-shell#2180: a short, stable token for the profile layer that supplied
|
|
192
|
+
// the launch's model, recorded next to the model in the TaskRecord so every
|
|
193
|
+
// task card shows which layer won and stale disk edits below a frozen session
|
|
194
|
+
// become visible. Derived from the resolution the request already performed;
|
|
195
|
+
// the only profile reads are the pin/declaration lookups in the paths where
|
|
196
|
+
// `sessionProfileRoutingAt` itself reads the target's own layers without
|
|
197
|
+
// carrying the origin (a foreign target under a session frozen without a
|
|
198
|
+
// profile, and `follow`/child launches), so no layer is resolved twice to route.
|
|
199
|
+
function modelSourceToken(
|
|
200
|
+
source: ProfileSource,
|
|
201
|
+
resolution: SessionProfileResolution,
|
|
202
|
+
routingTarget: InheritedProfileOptions & { foreignRepository?: boolean },
|
|
203
|
+
): string | undefined {
|
|
204
|
+
if (source === PROFILE_SOURCE.DEFINITION) return "definition";
|
|
205
|
+
// Unresolved means no layer supplied a model at all: the card already shows
|
|
206
|
+
// `default`, and naming a layer next to it would only be noise.
|
|
207
|
+
if (source === PROFILE_SOURCE.UNRESOLVED) return undefined;
|
|
208
|
+
if (source !== PROFILE_SOURCE.PROFILE) return "default";
|
|
209
|
+
if (resolution.kind === "explicit") return "binding";
|
|
210
|
+
if (resolution.kind === "inherited") {
|
|
211
|
+
if (resolution.profile !== undefined) return `frozen:${resolution.profile.origin}`;
|
|
212
|
+
// Frozen without a profile: a foreign target keeps only its own pin
|
|
213
|
+
// layers, so a winning pin there is named from the same read
|
|
214
|
+
// `sessionProfileRoutingAt` just performed; otherwise the session keeps
|
|
215
|
+
// the materialized config routing.
|
|
216
|
+
if (routingTarget.foreignRepository === true) {
|
|
217
|
+
const pin = resolveProfilePin(routingTarget);
|
|
218
|
+
return pin === undefined ? "profile" : `pin:${pin.source}`;
|
|
219
|
+
}
|
|
220
|
+
return "profile";
|
|
221
|
+
}
|
|
222
|
+
// `follow` and live child launches read the target's own defaults
|
|
223
|
+
// (pin → declaration → global active); name the layer the same read chose.
|
|
224
|
+
const pin = resolveProfilePin(routingTarget);
|
|
225
|
+
if (pin !== undefined) return `pin:${pin.source}`;
|
|
226
|
+
return resolveUnversionedProjectProfile(routingTarget.cwd, routingTarget.configHome) !== undefined ? "declaration" : "profile";
|
|
227
|
+
}
|
|
228
|
+
|
|
189
229
|
export function agentRuntimePaths(home: string, agentHome = join(home, ".pi", "agent")): { sessions: string; transcripts: string } {
|
|
190
230
|
const root = join(agentHome, "gentle-agents");
|
|
191
231
|
return { sessions: join(root, "sessions"), transcripts: join(root, "transcripts") };
|
|
@@ -549,6 +589,28 @@ export default function gentleAgents(pi: ExtensionAPI, env: NodeJS.ProcessEnv =
|
|
|
549
589
|
scopeCache.clear();
|
|
550
590
|
publishActivity();
|
|
551
591
|
});
|
|
592
|
+
// The todo list is the session's progress: publish it for peers so the model
|
|
593
|
+
// spends no turn on orchestrator_session_id. Merged into the owner's curated
|
|
594
|
+
// state; a publication that cannot be made never fails the todo write.
|
|
595
|
+
// Counts only: a todo title is private work text, never published to peers.
|
|
596
|
+
// The last automatic line survives an owner publication that omits `progress`.
|
|
597
|
+
let automaticProgress: { sessionId: string; text: string } | undefined;
|
|
598
|
+
const unsubscribeTodoProgress = pi.events.on(TODO_PROGRESS_EVENT, (event) => {
|
|
599
|
+
const progress = event as Partial<TodoProgress> | undefined;
|
|
600
|
+
if (!sessions || progress?.sessionId !== sessions.getSessionId() || typeof progress.done !== "number" || typeof progress.total !== "number") return;
|
|
601
|
+
const text = `${progress.done}/${progress.total} done`;
|
|
602
|
+
try {
|
|
603
|
+
const owned = stateCache.get(sessions);
|
|
604
|
+
// A state the owner withdrew stays withdrawn until the owner publishes again.
|
|
605
|
+
if (owned?.state === null) return;
|
|
606
|
+
const { progress: previous, ...curated } = owned?.state ?? {};
|
|
607
|
+
// A cleared list has no progress to report: drop the line, publish nothing new.
|
|
608
|
+
if (progress.total === 0 && previous === undefined) return;
|
|
609
|
+
stateCache.publish(sessions, progress.total === 0 ? curated : { ...curated, progress: text }, (type, data) => pi.appendEntry(type, data));
|
|
610
|
+
automaticProgress = progress.total === 0 ? undefined : { sessionId: progress.sessionId, text };
|
|
611
|
+
publishActivity();
|
|
612
|
+
} catch { /* stale session or over the state budget: keep the previous publication */ }
|
|
613
|
+
});
|
|
552
614
|
let worktrees: SessionWorktreeRegistry | undefined;
|
|
553
615
|
let worktreeManager: ExtensionContext["sessionManager"] | undefined;
|
|
554
616
|
let worktreeAuthority: (() => boolean) | undefined;
|
|
@@ -594,6 +656,7 @@ export default function gentleAgents(pi: ExtensionAPI, env: NodeJS.ProcessEnv =
|
|
|
594
656
|
clearTaskMetrics();
|
|
595
657
|
unsubscribeMetrics();
|
|
596
658
|
unsubscribeScope();
|
|
659
|
+
unsubscribeTodoProgress();
|
|
597
660
|
scopeCache.clear();
|
|
598
661
|
});
|
|
599
662
|
let stopAllConfirmation: Promise<void> | undefined;
|
|
@@ -1641,14 +1704,17 @@ export default function gentleAgents(pi: ExtensionAPI, env: NodeJS.ProcessEnv =
|
|
|
1641
1704
|
// included; only `follow` reads the defaults of the target. The profile is
|
|
1642
1705
|
// resolved here, at task-request creation, so queued and running children
|
|
1643
1706
|
// keep the routing frozen into their requests even if the session rebinds.
|
|
1707
|
+
// The routing target this launch reads (#1064), reused to name the winning
|
|
1708
|
+
// layer (#2180) so both answers come from one resolution.
|
|
1709
|
+
const routingTarget = {
|
|
1710
|
+
cwd: target ?? parentCwd,
|
|
1711
|
+
configHome: profileConfigHome,
|
|
1712
|
+
resolveWorktree: pinIdentity,
|
|
1713
|
+
foreignRepository: foreign,
|
|
1714
|
+
};
|
|
1644
1715
|
const config = withPinnedModelProfiles(
|
|
1645
1716
|
loadAgentsConfig(roots(ctx)),
|
|
1646
|
-
sessionProfileRoutingAt(sessionProfile,
|
|
1647
|
-
cwd: target ?? parentCwd,
|
|
1648
|
-
configHome: profileConfigHome,
|
|
1649
|
-
resolveWorktree: pinIdentity,
|
|
1650
|
-
foreignRepository: foreign,
|
|
1651
|
-
}),
|
|
1717
|
+
sessionProfileRoutingAt(sessionProfile, routingTarget),
|
|
1652
1718
|
);
|
|
1653
1719
|
// Drift is measured against the defaults of the session's own directory,
|
|
1654
1720
|
// where the profile was frozen, never against a delegated target.
|
|
@@ -1663,6 +1729,9 @@ export default function gentleAgents(pi: ExtensionAPI, env: NodeJS.ProcessEnv =
|
|
|
1663
1729
|
if (drift !== undefined) ctx.ui.notify(drift, "info");
|
|
1664
1730
|
}
|
|
1665
1731
|
const profile = resolveAgentProfile(agent, config);
|
|
1732
|
+
// #2180: the winning layer is named from the resolution and routing this
|
|
1733
|
+
// request already performed, never by re-resolving them.
|
|
1734
|
+
const modelSource = modelSourceToken(profile.source.model, sessionProfile, routingTarget);
|
|
1666
1735
|
if (admittedModel !== undefined) {
|
|
1667
1736
|
const model = profile.model ?? ctx.model;
|
|
1668
1737
|
const catalogModel = model?.provider ? ctx.modelRegistry?.find(model.provider, model.id) : ctx.modelRegistry?.getAll().find(candidate => candidate.id === model?.id);
|
|
@@ -1703,6 +1772,7 @@ export default function gentleAgents(pi: ExtensionAPI, env: NodeJS.ProcessEnv =
|
|
|
1703
1772
|
} } : {}),
|
|
1704
1773
|
...(target === undefined || foreign ? {} : { onLaunch: () => { registry.register(target, "subagent:spawn"); } }),
|
|
1705
1774
|
model: profile.model,
|
|
1775
|
+
...(modelSource === undefined ? {} : { modelSource }),
|
|
1706
1776
|
thinking: profile.thinking,
|
|
1707
1777
|
sessionDir,
|
|
1708
1778
|
resumeSessionPath: resume,
|
|
@@ -1842,7 +1912,7 @@ export default function gentleAgents(pi: ExtensionAPI, env: NodeJS.ProcessEnv =
|
|
|
1842
1912
|
pi.registerTool({
|
|
1843
1913
|
name: "orchestrator_session_id",
|
|
1844
1914
|
label: "Orchestrator session ID",
|
|
1845
|
-
description: "Return this host session's stable routing ID, Initial alias (FIRST TASK), Current alias (CURRENT TASK), and separate human Session name. Explicit subjects update Current even when named; Initial stays the first declared branch topic, unknown for legacy history. Before delegation or cross-session coordination, declare a short recognizable subject here. Do not require a subject declaration for small direct tasks; do not query all peers. Names never authenticate. Existing Pi names and human renames are preserved. Use a concise non-sensitive label, not a prompt.
|
|
1915
|
+
description: "Return this host session's stable routing ID, Initial alias (FIRST TASK), Current alias (CURRENT TASK), and separate human Session name. Explicit subjects update Current even when named; Initial stays the first declared branch topic, unknown for legacy history. Before delegation or cross-session coordination, declare a short recognizable subject here. Do not require a subject declaration for small direct tasks; do not query all peers. Names never authenticate. Existing Pi names and human renames are preserved. Use a concise non-sensitive label, not a prompt. Progress is published automatically from the todo list; publish state here only for objective, decisions, blockers, or work, never just to report progress. Owner-curated state (2048 UTF-8 bytes total): null withdraws, omission leaves unchanged. Never include credentials, internal instructions, or raw prompts. Historical notes are not consent or an owner reply.",
|
|
1846
1916
|
...orchestratorToolRenderers("session", expandHint),
|
|
1847
1917
|
parameters: { type: "object", additionalProperties: false, properties: {
|
|
1848
1918
|
subject: { type: "string", maxLength: 120, description: "Optional short task subject; updates task aliases independently of human names. Also names an unnamed Pi session." },
|
|
@@ -1864,7 +1934,20 @@ export default function gentleAgents(pi: ExtensionAPI, env: NodeJS.ProcessEnv =
|
|
|
1864
1934
|
if (!transport) return text("Error: session messaging is not ready.", { error: "not ready" });
|
|
1865
1935
|
const { subject, state } = params as { subject?: unknown; state?: unknown };
|
|
1866
1936
|
const declared = normalizeTaskSubject(subject);
|
|
1867
|
-
|
|
1937
|
+
// An owner object without `progress` keeps the automatic todo progress still on
|
|
1938
|
+
// display; null and an explicit `progress` win, and an over-budget merge does not fail the call.
|
|
1939
|
+
const shown = stateCache.get(ctx.sessionManager)?.state?.progress;
|
|
1940
|
+
const merged = state && typeof state === "object" && !Array.isArray(state) && !Object.hasOwn(state, "progress")
|
|
1941
|
+
&& automaticProgress?.sessionId === ctx.sessionManager.getSessionId() && shown === automaticProgress.text
|
|
1942
|
+
? { ...state, progress: shown } : undefined;
|
|
1943
|
+
const append = (type: string, data: unknown) => pi.appendEntry(type, data);
|
|
1944
|
+
if (merged) {
|
|
1945
|
+
try { stateCache.publish(ctx.sessionManager, merged, append, Date.now(), declared); }
|
|
1946
|
+
catch (error) {
|
|
1947
|
+
if ((error as Error).message !== "invalid-published-state") throw error;
|
|
1948
|
+
stateCache.publish(ctx.sessionManager, state, append, Date.now(), declared);
|
|
1949
|
+
}
|
|
1950
|
+
} else if (state !== undefined || declared) stateCache.publish(ctx.sessionManager, state, append, Date.now(), declared);
|
|
1868
1951
|
if (activeTransportFor(ctx) !== transport) throw new Error("stale-published-state");
|
|
1869
1952
|
if (declared && !ctx.sessionManager.getSessionName?.()) pi.setSessionName(declared);
|
|
1870
1953
|
const alias = sanitizeDisplayLabel(ctx.sessionManager.getSessionName?.() ?? "");
|
|
@@ -1977,13 +2060,17 @@ export default function gentleAgents(pi: ExtensionAPI, env: NodeJS.ProcessEnv =
|
|
|
1977
2060
|
? `repository: ${fact.root} · clone: ${fact.cloneHash} · Git resolved at: ${fact.resolvedAt} (${fact.source})`
|
|
1978
2061
|
: "repository: unknown";
|
|
1979
2062
|
const rows = peers.map(peer => {
|
|
1980
|
-
const context = peer.freshness === "recent" ? ` · ${peer.aliases?.currentAlias || peer.label || "unnamed"} · Session name: ${peer.label || "unnamed"} · Current alias (CURRENT TASK): ${peer.aliases?.currentAlias ?? "unknown"} · Initial alias (FIRST TASK): ${peer.aliases?.initialAlias ?? "unknown"} · recorded workspace: ${peer.workspace || "unknown"}` :
|
|
2063
|
+
const context = peer.freshness === "recent" ? ` · ${peer.aliases?.currentAlias || peer.label || "unnamed"} · Session name: ${peer.label || "unnamed"} · Current alias (CURRENT TASK): ${peer.aliases?.currentAlias ?? "unknown"} · Initial alias (FIRST TASK): ${peer.aliases?.initialAlias ?? "unknown"} · recorded workspace: ${peer.workspace || "unknown"}` : peer.legacyLabel !== undefined
|
|
2064
|
+
? ` · ${peer.legacyLabel || "unnamed"} · context: legacy (this session predates discovery publication; restart it to publish its workspace and repository)`
|
|
2065
|
+
: " · context: unknown";
|
|
1981
2066
|
const tasks = peer.tasks?.map(task => `\n - ${task.label || task.id} [${task.status}] · launch workspace: ${task.workspace || "unknown"} · ${repository(peer.scope?.tasks.find(t => t.id === task.id)?.repository)}`).join("") ?? "";
|
|
1982
2067
|
const registered = peer.scope?.registered.map(fact => `\n registered: ${repository(fact)}`).join("") ?? "";
|
|
1983
2068
|
const gaps = peer.scope && !peer.scope.complete ? `\n (scope incomplete: ${peer.scope.omittedTasks} tasks, ${peer.scope.omittedRegistered} registered roots omitted)` : "";
|
|
1984
2069
|
const catalog = peer.catalog ? `\n recorded catalog (not Git identity): ${JSON.stringify(peer.catalog)}` : "\n recorded catalog: unknown";
|
|
1985
2070
|
const note = params.recipient_session_id ? `\n owner-curated recorded state (not consent or owner reply; authority none): ${peer.state ? JSON.stringify(peer.state) : "unknown"}` : "";
|
|
1986
|
-
|
|
2071
|
+
// A legacy peer never publishes its scope: say so instead of reporting an unknown.
|
|
2072
|
+
const legacy = peer.legacyLabel !== undefined;
|
|
2073
|
+
return `- ${peer.sessionId}${context} · ${legacy ? "repository: not published" : repository(peer.scope?.host)} · metadata: ${legacy ? "legacy" : peer.freshness}${tasks}${registered}${gaps}${catalog}${note}${peer.omitted ? `\n (${peer.omitted} more tasks omitted)` : ""}`;
|
|
1987
2074
|
});
|
|
1988
2075
|
return peers.length === 0 ? text("No other sessions are currently advertised. Advertisements have unknown reachability and do not guarantee a live session.") : text(`Advertised sessions (reachability is unknown):\n${rows.join("\n")}`, { gentleAgents: { candidates: peers } });
|
|
1989
2076
|
} catch {
|