@north-light/crouter 0.3.261 → 0.3.263
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/api/dto/health.d.ts +2 -0
- package/dist/builtin-memory/internal/memory-loading.md +3 -3
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +4 -3
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +5 -3
- package/dist/clients/attach/input/controller.d.ts +4 -0
- package/dist/clients/attach/input/controller.js +8 -0
- package/dist/clients/attach/session/bindings.d.ts +3 -0
- package/dist/clients/attach/session/bindings.js +7 -0
- package/dist/clients/attach/session/keys.d.ts +2 -0
- package/dist/clients/attach/session/keys.js +3 -3
- package/dist/clients/attach/viewer.js +616 -616
- package/dist/commands/memory/read.js +15 -38
- package/dist/commands/memory/shared.d.ts +1 -1
- package/dist/commands/memory/shared.js +1 -1
- package/dist/commands/sys/context/admin/docs-panel.d.ts +3 -3
- package/dist/commands/sys/context/admin/model.d.ts +7 -2
- package/dist/commands/sys/context/admin/model.js +7 -1
- package/dist/commands/sys/context/admin/read-view.d.ts +5 -5
- package/dist/commands/sys/context/admin/read-view.js +9 -4
- package/dist/commands/sys/context/resolve.d.ts +32 -3
- package/dist/commands/sys/context/resolve.js +74 -25
- package/dist/commands/sys/panels/models-panel.d.ts +28 -5
- package/dist/commands/sys/panels/models-panel.js +558 -75
- package/dist/core/__tests__/integration/broker-sdk-wiring.test.js +1 -1
- package/dist/core/__tests__/model-routes-config.test.d.ts +1 -0
- package/dist/core/__tests__/model-routes-config.test.js +142 -0
- package/dist/core/__tests__/on-read-nested-store.test.js +8 -0
- package/dist/core/__tests__/profile-project-memory-delivery.test.js +264 -1
- package/dist/core/__tests__/seam/broker-provider-retry.test.js +2 -2
- package/dist/core/canvas/render-source.d.ts +1 -1
- package/dist/core/canvas/render-source.js +3 -2
- package/dist/core/config.d.ts +19 -2
- package/dist/core/config.js +162 -47
- package/dist/core/keybindings/catalog.js +9 -7
- package/dist/core/model-routes.js +10 -3
- package/dist/core/substrate/listings.d.ts +1 -1
- package/dist/core/substrate/listings.js +6 -2
- package/dist/core/substrate/on-read.d.ts +61 -5
- package/dist/core/substrate/on-read.js +129 -22
- package/dist/core/substrate/render.d.ts +3 -2
- package/dist/core/substrate/render.js +133 -38
- package/dist/daemon/api/__tests__/seam/api-server.test.js +34 -0
- package/dist/daemon/api/handlers/canvas.js +18 -2
- package/dist/daemon/api/handlers/health.js +17 -12
- package/dist/pi-extensions/__tests__/pre-command-gate.test.js +2 -2
- package/dist/types.d.ts +4 -2
- package/package.json +1 -1
- package/runtime.lock.json +2 -2
package/dist/api/dto/health.d.ts
CHANGED
|
@@ -15,6 +15,8 @@ export interface StatusDTO {
|
|
|
15
15
|
tick_interval_ms: number;
|
|
16
16
|
/** Node counts keyed by status. */
|
|
17
17
|
node_counts: Partial<Record<NodeStatusDTO, number>>;
|
|
18
|
+
/** Nodes genuinely mid-turn: their busy marker exists and their recorded pid is alive. Unlike `node_counts.active`, this excludes live-but-waiting, parked, or blocked engines. */
|
|
19
|
+
busy_node_count: number;
|
|
18
20
|
/** Bound listener addresses. `tcp` is null when the TCP listener is off. */
|
|
19
21
|
listeners: {
|
|
20
22
|
socket_path: string;
|
|
@@ -18,7 +18,7 @@ A doc with no `surfaces` does exactly one thing: appears in its directory's list
|
|
|
18
18
|
- **boot** — the frozen preference system snapshot and first-message knowledge catalog assembled when a context begins. No match; the entry's presence is the match.
|
|
19
19
|
- **workspace-open** — first-message context when cwd/profile mounts the doc's project store. Project stores only.
|
|
20
20
|
- **read** — a `read` tool call returned a matching file: path globs vs the file's absolute path and basename, `./`-anchored globs vs its path relative to the store's owning repo dir, `match-frontmatter` predicates over the read file's own YAML frontmatter.
|
|
21
|
-
- **memory-read** —
|
|
21
|
+
- **memory-read** — another doc's full body entered context, including `crtr memory read`: name globs vs its canonical name, `./` anchored to this doc's canonical routing anchor (a collapsed directory document anchors at its own directory name).
|
|
22
22
|
- **command** — a matching shell command ran: globs vs the whole command string, `*` crossing `/`. Delivery is post-execution — right for "you are now in this territory"; when the point is "don't run this at all," use `pre-command` instead.
|
|
23
23
|
- **pre-command** — a matching `bash` command is about to run. When the memory has not been read yet, the command does not execute — the memory comes back as the tool result instead, and the agent re-issues the command, which then runs. Use it to guarantee a memory is seen before a sensitive action is taken. Same globs as `command`, matched at command position; `match` is required. A guardrail against the faithful-but-uninformed action, not an enforcement boundary.
|
|
24
24
|
|
|
@@ -40,9 +40,9 @@ A document-level `gate` is the hard eligibility predicate over the node's own co
|
|
|
40
40
|
|
|
41
41
|
## Listings and dedup
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
A full-body delivery is a read: `crtr memory read <doc>` and every content-rung surface delivery expose, once per loaded context, the listing of the doc's directory and each ancestor — one routing line per member doc, one bare name per subdirectory — then fire matching `memory-read` routes. A directory document owns its canonical directory node, so its content delivery exposes its immediate members; `crtr memory read <dir>` returns that document's body followed by the directory's immediate listing without repeating the document, while a directory without a document returns its listing. Content-delivered companions are read in turn until the finite corpus reaches the ledger-deduplicated fixpoint. `unlisted: true` suppresses a doc from every listing. Store roots are never auto-listed — `crtr memory list` is the deliberate root browse.
|
|
44
44
|
|
|
45
|
-
Every delivery registers its document or listing identity and rung in the loaded context's exposure ledger. System and transcript ranks max-fold, so a higher rung pierces a lower one while a content delivery silences later lower-rung deliveries. A strict resume preserves that ledger and the byte-stable preference snapshot; yield or another new-context boundary replaces them with exactly the new system and first-message snapshots.
|
|
45
|
+
Every delivery registers its document or listing identity and rung in the loaded context's exposure ledger. System and transcript ranks max-fold, so a higher rung pierces a lower one while a content delivery silences later lower-rung deliveries and duplicate read attachments. A strict resume preserves that ledger and the byte-stable preference snapshot; yield or another new-context boundary replaces them with exactly the new system and first-message snapshots.
|
|
46
46
|
|
|
47
47
|
## Store mounting and precedence
|
|
48
48
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
2
|
import { createAssistantMessageEventStream, } from '@earendil-works/pi-ai';
|
|
3
|
-
import {
|
|
4
|
-
import { streamSimple as streamOpenAICodexResponses } from '@earendil-works/pi-ai/api/openai-codex-responses';
|
|
3
|
+
import { anthropicMessagesApi, openAICodexResponsesApi } from '@earendil-works/pi-ai/compat';
|
|
5
4
|
import { ANTHROPIC_PROVIDER_ID, OPENAI_CODEX_PROVIDER_ID, INVALID_REFRESH_TOKEN_BACKOFF_MS, formatStatusLine, getProviderLabel, isManagedProvider, isInvalidRefreshTokenError, addSubscription, enrichManagedLoginIdentity, markSubscriptionAuthenticationFailed, markSubscriptionRateLimited, markSubscriptionSuccess, parseRetryAfterHeader, promoteSubscription, readRotationConfig, readSubscriptionPool, refreshSubscriptionCredential, removeManagedAccount, resolveProviderCandidates, upsertSubscriptionWithUniqueAccount, } from '../../../core/subscription-state.js';
|
|
6
5
|
import { readMergedLaunchConfig } from '../../../core/config.js';
|
|
7
6
|
import { expandModelCandidates, modelRequestFromConfig, probeRouteAvailability } from '../../../core/model-routes.js';
|
|
@@ -24,6 +23,8 @@ const TRANSIENT_ROTATE_COOLDOWN_MS = 60 * 1000;
|
|
|
24
23
|
// remains busy, the provider call still proceeds. Subscription bookkeeping must never turn a
|
|
25
24
|
// healthy model response into a fatal generation fault.
|
|
26
25
|
const SUBSCRIPTION_LOCK_RETRY_BACKOFFS_MS = [25, 75, 150];
|
|
26
|
+
const { streamSimple: streamAnthropicMessages } = anthropicMessagesApi();
|
|
27
|
+
const { streamSimple: streamOpenAICodexResponses } = openAICodexResponsesApi();
|
|
27
28
|
function createProviderRotationState(options) {
|
|
28
29
|
return { delegatedProviderStreams: new Map(), transportOnlyExhaustedPasses: 0, ...(options === undefined ? {} : { options: { ...options } }) };
|
|
29
30
|
}
|
|
@@ -758,7 +759,7 @@ function parseProvider(value) {
|
|
|
758
759
|
}
|
|
759
760
|
function installDeclaredRouteProviders(state, pi, ctx) {
|
|
760
761
|
const config = readMergedLaunchConfig(ctx.cwd, configuredValue(state, 'profileId', 'CRTR_PROFILE_ID') || null);
|
|
761
|
-
const providerIds = new Set(Object.values(config.modelRoutes ?? {}).map((route) => route.providerId));
|
|
762
|
+
const providerIds = new Set(Object.values({ ...(config.modelRoutes ?? {}), ...(config.legacyModelRoutes ?? {}) }).map((route) => route.providerId));
|
|
762
763
|
for (const providerId of providerIds) {
|
|
763
764
|
if (isManagedProvider(providerId) || state.delegatedProviderStreams.has(providerId))
|
|
764
765
|
continue;
|
|
@@ -12,8 +12,7 @@ import {
|
|
|
12
12
|
type OAuthAuth,
|
|
13
13
|
type SimpleStreamOptions,
|
|
14
14
|
} from '@earendil-works/pi-ai';
|
|
15
|
-
import {
|
|
16
|
-
import { streamSimple as streamOpenAICodexResponses } from '@earendil-works/pi-ai/api/openai-codex-responses';
|
|
15
|
+
import { anthropicMessagesApi, openAICodexResponsesApi } from '@earendil-works/pi-ai/compat';
|
|
17
16
|
import {
|
|
18
17
|
ANTHROPIC_PROVIDER_ID,
|
|
19
18
|
OPENAI_CODEX_PROVIDER_ID,
|
|
@@ -67,6 +66,9 @@ const SUBSCRIPTION_LOCK_RETRY_BACKOFFS_MS = [25, 75, 150];
|
|
|
67
66
|
// installed would recurse back into the route driver.
|
|
68
67
|
type ProviderStream = (model: Model<any>, context: Context, options?: SimpleStreamOptions) => AssistantMessageEventStream;
|
|
69
68
|
|
|
69
|
+
const { streamSimple: streamAnthropicMessages } = anthropicMessagesApi();
|
|
70
|
+
const { streamSimple: streamOpenAICodexResponses } = openAICodexResponsesApi();
|
|
71
|
+
|
|
70
72
|
export interface ProviderRotationOptions {
|
|
71
73
|
modelIntent?: string;
|
|
72
74
|
nodeCwd?: string;
|
|
@@ -936,7 +938,7 @@ function parseProvider(value: string | undefined): ManagedProviderId | undefined
|
|
|
936
938
|
|
|
937
939
|
function installDeclaredRouteProviders(state: ProviderRotationState, pi: ExtensionAPI, ctx: ExtensionContext): void {
|
|
938
940
|
const config = readMergedLaunchConfig(ctx.cwd, configuredValue(state, 'profileId', 'CRTR_PROFILE_ID') || null);
|
|
939
|
-
const providerIds = new Set(Object.values(config.modelRoutes ?? {}).map((route) => route.providerId));
|
|
941
|
+
const providerIds = new Set(Object.values({ ...(config.modelRoutes ?? {}), ...(config.legacyModelRoutes ?? {}) }).map((route) => route.providerId));
|
|
940
942
|
for (const providerId of providerIds) {
|
|
941
943
|
if (isManagedProvider(providerId) || state.delegatedProviderStreams.has(providerId)) continue;
|
|
942
944
|
const provider = ctx.modelRegistry.getProvider?.(providerId);
|
|
@@ -53,6 +53,10 @@ export declare class InputController {
|
|
|
53
53
|
constructor(tui: TUI, editor: CustomEditor, keybindings: KeybindingsManager, hooks: InputControllerHooks, capabilities: ViewerCapabilities);
|
|
54
54
|
cycleLadder(direction: 'forward' | 'backward'): void;
|
|
55
55
|
sendInterrupting(text: string): boolean;
|
|
56
|
+
/** Cancel the running turn without sending a message — the ctrl+c "stop the
|
|
57
|
+
* agent" chord. Mirrors Esc's abort semantics. Returns false when nothing is
|
|
58
|
+
* streaming to cancel, so the caller can hint at detach instead. */
|
|
59
|
+
abortTurn(): boolean;
|
|
56
60
|
attachDialog(request: RpcExtensionUIRequest): void;
|
|
57
61
|
dismissDialog(id: string): void;
|
|
58
62
|
setState(state: BrokerSnapshot['state']): void;
|
|
@@ -48,6 +48,14 @@ export class InputController {
|
|
|
48
48
|
sendInterrupting(text) {
|
|
49
49
|
return this.emitDrive({ type: 'prompt', text, interrupt: true });
|
|
50
50
|
}
|
|
51
|
+
/** Cancel the running turn without sending a message — the ctrl+c "stop the
|
|
52
|
+
* agent" chord. Mirrors Esc's abort semantics. Returns false when nothing is
|
|
53
|
+
* streaming to cancel, so the caller can hint at detach instead. */
|
|
54
|
+
abortTurn() {
|
|
55
|
+
if (this.state?.isStreaming !== true)
|
|
56
|
+
return false;
|
|
57
|
+
return this.emitCommand({ type: 'abort' });
|
|
58
|
+
}
|
|
51
59
|
attachDialog(request) {
|
|
52
60
|
this.overlays.attachDialog(request);
|
|
53
61
|
}
|
|
@@ -11,6 +11,9 @@ export declare function dispatchAttachAction(id: AttachBindingId, actions: Attac
|
|
|
11
11
|
export declare function dispatchAttachBinding(bindings: AttachBindings, data: string, actions: AttachActions): boolean;
|
|
12
12
|
export declare function dispatchAttachViewportBinding(bindings: AttachBindings, data: string, actions: AttachViewportActions): boolean;
|
|
13
13
|
export declare function detachHint(bindings: AttachBindings): string | undefined;
|
|
14
|
+
/** The dedicated detach binding's spelling (ctrl+d), for pointing the user at
|
|
15
|
+
* detach now that a second ctrl+c cancels the running turn instead. */
|
|
16
|
+
export declare function detachBindingHint(bindings: AttachBindings): string | undefined;
|
|
14
17
|
/** Re-resolve the user's binding settings once and republish the same snapshot
|
|
15
18
|
* to every consumer: attach dispatch, the graph overlay, and tmux. Binding
|
|
16
19
|
* diagnostics must never fail an attach, so an install error is swallowed. */
|
|
@@ -48,6 +48,13 @@ export function detachHint(bindings) {
|
|
|
48
48
|
}
|
|
49
49
|
return undefined;
|
|
50
50
|
}
|
|
51
|
+
/** The dedicated detach binding's spelling (ctrl+d), for pointing the user at
|
|
52
|
+
* detach now that a second ctrl+c cancels the running turn instead. */
|
|
53
|
+
export function detachBindingHint(bindings) {
|
|
54
|
+
return bindings.gestures('crtr.attach.detach').length > 0
|
|
55
|
+
? formatBinding(bindings, 'crtr.attach.detach')
|
|
56
|
+
: undefined;
|
|
57
|
+
}
|
|
51
58
|
/** Re-resolve the user's binding settings once and republish the same snapshot
|
|
52
59
|
* to every consumer: attach dispatch, the graph overlay, and tmux. Binding
|
|
53
60
|
* diagnostics must never fail an attach, so an install error is swallowed. */
|
|
@@ -23,6 +23,8 @@ export interface KeyHooks {
|
|
|
23
23
|
rosterHandleKey: (data: string) => boolean;
|
|
24
24
|
setNotice: (message: string) => void;
|
|
25
25
|
detach: () => void;
|
|
26
|
+
/** Cancel the running turn (the second ctrl+c). Detach lives on its own binding. */
|
|
27
|
+
cancelTurn: () => void;
|
|
26
28
|
toggleGraph: () => void;
|
|
27
29
|
toggleHelp: () => void;
|
|
28
30
|
/** Toggle the mounted inbox surface. */
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
import { extractAttachControlInput } from '../../../core/keybindings/index.js';
|
|
11
11
|
import { dispatchAttachAction, dispatchAttachBinding, dispatchAttachViewportBinding, } from './bindings.js';
|
|
12
12
|
import { FOCUS_IN, FOCUS_OUT } from './focus-events.js';
|
|
13
|
-
/** Press the clear
|
|
13
|
+
/** Press the clear binding twice inside this window to cancel the running turn. */
|
|
14
14
|
const CLEAR_OR_DETACH_MS = 1000;
|
|
15
15
|
/** Install the listener; returns the remover, which teardown MUST call. */
|
|
16
16
|
export function installGlobalKeys(ctx, hooks) {
|
|
@@ -22,12 +22,12 @@ export function installGlobalKeys(ctx, hooks) {
|
|
|
22
22
|
const now = Date.now();
|
|
23
23
|
if (now - lastClearOrDetachAt < CLEAR_OR_DETACH_MS) {
|
|
24
24
|
lastClearOrDetachAt = 0;
|
|
25
|
-
hooks.
|
|
25
|
+
hooks.cancelTurn();
|
|
26
26
|
return;
|
|
27
27
|
}
|
|
28
28
|
lastClearOrDetachAt = now;
|
|
29
29
|
editor.setText('');
|
|
30
|
-
hooks.setNotice(`Editor cleared — press ${hooks.detachHint()} again to
|
|
30
|
+
hooks.setNotice(`Editor cleared — press ${hooks.detachHint()} again to cancel the agent`);
|
|
31
31
|
tui.requestRender();
|
|
32
32
|
},
|
|
33
33
|
'crtr.attach.graph.toggle': hooks.toggleGraph,
|