@leanandmean/coding-agent 0.74.1-scramjet.7 → 0.74.1-scramjet.71
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/CHANGELOG.md +32 -0
- package/LICENSE +202 -0
- package/README.md +37 -9
- package/dist/cli/args.d.ts +2 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +45 -1
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/initial-message.d.ts +1 -0
- package/dist/cli/initial-message.d.ts.map +1 -1
- package/dist/cli/initial-message.js +3 -0
- package/dist/cli/initial-message.js.map +1 -1
- package/dist/cli/list-models.d.ts +2 -0
- package/dist/cli/list-models.d.ts.map +1 -1
- package/dist/cli/list-models.js +4 -1
- package/dist/cli/list-models.js.map +1 -1
- package/dist/config.d.ts +9 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +33 -22
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts +12 -3
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +64 -38
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session-services.d.ts +2 -0
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +3 -0
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session.d.ts +84 -17
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +1082 -209
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +21 -17
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +3 -5
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +43 -10
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/exec.d.ts +12 -0
- package/dist/core/exec.d.ts.map +1 -1
- package/dist/core/exec.js +74 -28
- package/dist/core/exec.js.map +1 -1
- package/dist/core/export-html/template.js +4 -0
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +9 -5
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +160 -3
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +85 -8
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/keybindings.d.ts +8 -0
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/model-registry.d.ts +103 -0
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +272 -28
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +24 -6
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/output-throughput-history.d.ts +25 -0
- package/dist/core/output-throughput-history.d.ts.map +1 -0
- package/dist/core/output-throughput-history.js +240 -0
- package/dist/core/output-throughput-history.js.map +1 -0
- package/dist/core/output-throughput.d.ts +43 -0
- package/dist/core/output-throughput.d.ts.map +1 -0
- package/dist/core/output-throughput.js +161 -0
- package/dist/core/output-throughput.js.map +1 -0
- package/dist/core/resource-loader.d.ts +6 -0
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +76 -21
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/scramjet-command-parser.d.ts +4 -0
- package/dist/core/scramjet-command-parser.d.ts.map +1 -1
- package/dist/core/scramjet-command-parser.js +72 -1
- package/dist/core/scramjet-command-parser.js.map +1 -1
- package/dist/core/sdk.d.ts +4 -0
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +70 -11
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts +11 -3
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +46 -11
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +19 -6
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +131 -17
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +6 -2
- package/dist/core/skills.js.map +1 -1
- package/dist/core/system-prompt.d.ts +2 -0
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +5 -2
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +4 -3
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts +119 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +113 -11
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/armin.d.ts +4 -2
- package/dist/modes/interactive/components/armin.d.ts.map +1 -1
- package/dist/modes/interactive/components/armin.js +14 -8
- package/dist/modes/interactive/components/armin.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts +3 -1
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +19 -8
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/daxnuts.d.ts +4 -1
- package/dist/modes/interactive/components/daxnuts.d.ts.map +1 -1
- package/dist/modes/interactive/components/daxnuts.js +14 -6
- package/dist/modes/interactive/components/daxnuts.js.map +1 -1
- package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-editor.js +5 -3
- package/dist/modes/interactive/components/extension-editor.js.map +1 -1
- package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-selector.js +4 -3
- package/dist/modes/interactive/components/extension-selector.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts +4 -0
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +24 -20
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts +3 -3
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +10 -7
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.d.ts +3 -1
- package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.js +8 -2
- package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +17 -3
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +87 -16
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.js +2 -1
- package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +19 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +129 -36
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message.js +3 -2
- package/dist/modes/interactive/components/user-message.js.map +1 -1
- package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -1
- package/dist/modes/interactive/components/visual-truncate.js +2 -2
- package/dist/modes/interactive/components/visual-truncate.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +37 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +902 -177
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/spellcheck.d.ts +26 -0
- package/dist/modes/interactive/spellcheck.d.ts.map +1 -0
- package/dist/modes/interactive/spellcheck.js +144 -0
- package/dist/modes/interactive/spellcheck.js.map +1 -0
- package/dist/modes/interactive/theme/{dark.json → pi-dark.json} +3 -2
- package/dist/modes/interactive/theme/{light.json → pi-light.json} +27 -26
- package/dist/modes/interactive/theme/theme-schema.json +6 -1
- package/dist/modes/interactive/theme/theme.d.ts +24 -4
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +123 -22
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +5 -0
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +3 -1
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +6 -1
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/package-manager-cli.d.ts.map +1 -1
- package/dist/package-manager-cli.js +33 -14
- package/dist/package-manager-cli.js.map +1 -1
- package/dist/utils/clipboard-native.d.ts +1 -0
- package/dist/utils/clipboard-native.d.ts.map +1 -1
- package/dist/utils/clipboard-native.js.map +1 -1
- package/dist/utils/clipboard.d.ts +6 -0
- package/dist/utils/clipboard.d.ts.map +1 -1
- package/dist/utils/clipboard.js +278 -10
- package/dist/utils/clipboard.js.map +1 -1
- package/dist/utils/tools-manager.d.ts +1 -1
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +7 -6
- package/dist/utils/tools-manager.js.map +1 -1
- package/dist/utils/version-check.d.ts +17 -5
- package/dist/utils/version-check.d.ts.map +1 -1
- package/dist/utils/version-check.js +88 -21
- package/dist/utils/version-check.js.map +1 -1
- package/docs/compaction.md +21 -3
- package/docs/custom-provider.md +33 -4
- package/docs/extensions.md +150 -24
- package/docs/json.md +8 -0
- package/docs/keybindings.md +25 -1
- package/docs/models.md +103 -4
- package/docs/packages.md +2 -0
- package/docs/prompt-templates.md +2 -0
- package/docs/quickstart.md +1 -4
- package/docs/rpc.md +16 -6
- package/docs/sdk.md +48 -3
- package/docs/session-format.md +5 -1
- package/docs/settings.md +19 -5
- package/docs/skills.md +7 -5
- package/docs/terminal-setup.md +79 -2
- package/docs/terminal-verification.md +71 -0
- package/docs/themes.md +63 -10
- package/docs/tui.md +120 -25
- package/docs/usage.md +6 -4
- package/examples/extensions/border-status-editor.ts +2 -3
- package/examples/extensions/doom-overlay/doom-component.ts +3 -3
- package/examples/extensions/mac-system-theme.ts +3 -2
- package/examples/extensions/modal-editor.ts +13 -8
- package/examples/extensions/overlay-qa-tests.ts +22 -9
- package/examples/extensions/overlay-test.ts +5 -3
- package/examples/extensions/snake.ts +3 -1
- package/examples/extensions/space-invaders.ts +6 -3
- package/examples/extensions/subagent/index.ts +20 -17
- package/package.json +69 -58
package/docs/extensions.md
CHANGED
|
@@ -288,8 +288,13 @@ user sends prompt ────────────────────
|
|
|
288
288
|
│ ┌─── turn (repeats while LLM calls tools) ───┐ │
|
|
289
289
|
│ │ │ │
|
|
290
290
|
│ ├─► turn_start │ │
|
|
291
|
+
│ ├─► routing refresh │ │
|
|
291
292
|
│ ├─► context (can modify messages) │ │
|
|
293
|
+
│ ├─► before_provider_call (can replace request-local system prompt)
|
|
294
|
+
│ ├─► provider serialization │ │
|
|
292
295
|
│ ├─► before_provider_request (can inspect or replace payload)
|
|
296
|
+
│ ├─► provider_request_tool_inventory (observe final tool names)
|
|
297
|
+
│ ├─► transport │ │
|
|
293
298
|
│ ├─► after_provider_response (status + headers, before stream consume)
|
|
294
299
|
│ │ │ │
|
|
295
300
|
│ │ LLM responds, may call tools: │ │
|
|
@@ -336,6 +341,16 @@ exit (Ctrl+C, Ctrl+D, SIGHUP, SIGTERM)
|
|
|
336
341
|
└─► session_shutdown
|
|
337
342
|
```
|
|
338
343
|
|
|
344
|
+
### Required Scramjet Builtin
|
|
345
|
+
|
|
346
|
+
Scramjet initializes as a **required builtin** through the resource loader (`builtinInit`), separately from optional disk-discovered extensions. Its successful initialization is a product invariant across **startup, reload, and every session replacement** (`/new`, resume, fork, clone, import):
|
|
347
|
+
|
|
348
|
+
- The candidate runtime's loader is validated **before** any irreversible live mutation. On reload the loader runs before `session_shutdown` and `resetApiProviders()`; on session replacement the candidate is prepared before the current session is torn down.
|
|
349
|
+
- If the Scramjet builtin fails to initialize, the loader throws a product-attributed `RequiredBuiltinInitError` (preserving the original failure as `cause`). The transition aborts, no `session_shutdown` fires, and the current runtime — runner, resources, providers — is left intact. At initial startup the same failure is fatal and exits non-zero.
|
|
350
|
+
- This is distinct from optional-extension failures: a throwing disk or inline extension remains a non-fatal diagnostic and never aborts the session. Only the required product builtin fails fast.
|
|
351
|
+
|
|
352
|
+
Extension authors do not interact with this directly, but it explains why a broken product init never leaves a session running without Scramjet.
|
|
353
|
+
|
|
339
354
|
### Resource Events
|
|
340
355
|
|
|
341
356
|
#### resources_discover
|
|
@@ -477,7 +492,7 @@ pi.on("before_agent_start", async (event, ctx) => {
|
|
|
477
492
|
// (includes changes from earlier before_agent_start handlers)
|
|
478
493
|
// event.systemPromptSections - read-only view of the base system prompt
|
|
479
494
|
// sections for this turn, before extension contributions; the volatile
|
|
480
|
-
// environment tail (current date/cwd) is the section with
|
|
495
|
+
// environment tail (current date/cwd/session journal) is the section with
|
|
481
496
|
// cacheRetention: "none"
|
|
482
497
|
// event.systemPromptOptions - structured options used to build the system prompt
|
|
483
498
|
// .customPrompt - any custom system prompt (from --system-prompt, SYSTEM.md, or custom templates)
|
|
@@ -486,6 +501,7 @@ pi.on("before_agent_start", async (event, ctx) => {
|
|
|
486
501
|
// .promptGuidelines - custom guideline bullets
|
|
487
502
|
// .appendSystemPrompt - text from --append-system-prompt flags
|
|
488
503
|
// .cwd - working directory
|
|
504
|
+
// .sessionFile - current session file path (undefined when sessions are disabled)
|
|
489
505
|
// .contextFiles - AGENTS.md files and other loaded context files
|
|
490
506
|
// .skills - loaded skills
|
|
491
507
|
|
|
@@ -510,7 +526,7 @@ Inside `before_agent_start`, `event.systemPrompt` and `ctx.getSystemPrompt()` bo
|
|
|
510
526
|
|
|
511
527
|
##### System prompt sections
|
|
512
528
|
|
|
513
|
-
Scramjet assembles the system prompt as ordered sections (`SystemPromptSection { id, text, cacheRetention?: "none" }` from `@leanandmean/ai`; ids are informational, and `"none"` is the only per-section retention — request-level retention applies otherwise) so providers can cache the stable prefix independently of the volatile tail. The last base section holds the current date
|
|
529
|
+
Scramjet assembles the system prompt as ordered sections (`SystemPromptSection { id, text, cacheRetention?: "none" }` from `@leanandmean/ai`; ids are informational, and `"none"` is the only per-section retention — request-level retention applies otherwise) so providers can cache the stable prefix independently of the volatile tail. The last base section holds the current date, working directory, and session journal path and is marked `cacheRetention: "none"`; on Anthropic, everything before it is folded into a single cached system block and the volatile tail trails uncached.
|
|
514
530
|
|
|
515
531
|
Returning `systemPromptSection` contributes a section for the current turn without replacing Scramjet's prompt assembly:
|
|
516
532
|
|
|
@@ -619,14 +635,29 @@ pi.on("context", async (event, ctx) => {
|
|
|
619
635
|
});
|
|
620
636
|
```
|
|
621
637
|
|
|
638
|
+
#### before_provider_call
|
|
639
|
+
|
|
640
|
+
Fired after request routing and message-context transformation, immediately before provider serialization. `event.model` is an immutable, handler-isolated snapshot of the exact model routed for this call, and `event.systemPrompt` is its request-local provider-neutral prompt (`string` or `SystemPromptSection[]`). Return `{ systemPrompt }` to replace only this call's prompt. Replacements chain in extension load order and never accumulate in session state.
|
|
641
|
+
|
|
642
|
+
```typescript
|
|
643
|
+
pi.on("before_provider_call", (event) => {
|
|
644
|
+
return {
|
|
645
|
+
systemPrompt: typeof event.systemPrompt === "string"
|
|
646
|
+
? `${event.systemPrompt}\n\nRequest routed to ${event.model.provider}/${event.model.id}`
|
|
647
|
+
: [...event.systemPrompt, { id: "routed-model", text: `\n\nRequest routed to ${event.model.provider}/${event.model.id}` }],
|
|
648
|
+
};
|
|
649
|
+
});
|
|
650
|
+
```
|
|
651
|
+
|
|
622
652
|
#### before_provider_request
|
|
623
653
|
|
|
624
|
-
Fired after the provider-specific payload is built, right before
|
|
654
|
+
Fired after the provider-specific payload is built, right before transport. `event.model` is a fresh immutable snapshot of the same exact routed model exposed by `before_provider_call`; mutating one handler's snapshot cannot affect later handlers or transport routing. Handlers run in extension load order. Returning `undefined` keeps the payload unchanged. Returning any other value replaces the payload for later handlers and for the actual request.
|
|
625
655
|
|
|
626
|
-
This hook can rewrite provider-level system instructions or remove them entirely. Those payload-level changes are not reflected by `ctx.getSystemPrompt()`, which reports Scramjet's system prompt string rather than the final serialized provider payload.
|
|
656
|
+
This hook can rewrite provider-level system instructions or remove them entirely. Those payload-level changes are not reflected by `ctx.getSystemPrompt()`, which reports Scramjet's stored system prompt string rather than request-local `before_provider_call` changes or the final serialized provider payload.
|
|
627
657
|
|
|
628
658
|
```typescript
|
|
629
|
-
pi.on("before_provider_request", (event
|
|
659
|
+
pi.on("before_provider_request", (event) => {
|
|
660
|
+
console.log(`${event.model.provider}/${event.model.id}`);
|
|
630
661
|
console.log(JSON.stringify(event.payload, null, 2));
|
|
631
662
|
|
|
632
663
|
// Optional: replace payload
|
|
@@ -634,7 +665,34 @@ pi.on("before_provider_request", (event, ctx) => {
|
|
|
634
665
|
});
|
|
635
666
|
```
|
|
636
667
|
|
|
637
|
-
This is mainly useful for debugging provider serialization
|
|
668
|
+
The complete request order is routing refresh → `context` transformation → `before_provider_call` → provider serialization → public `Agent.onPayload` callback → `before_provider_request` → `provider_request_tool_inventory` → transport. The public callback runs exactly once; `undefined` keeps its input unchanged, while any other return value becomes the input to extension payload handlers. One extension runner is bound when `before_provider_call` begins and owns the request through preparation, payload hooks, and observation. If reload supersedes it during provider-neutral preparation or before payload dispatch begins, the public callback still runs but the old request skips extension rewriting and observation instead of entering the replacement runtime. This is mainly useful for request-local prompt preparation and debugging provider serialization or cache behavior.
|
|
669
|
+
|
|
670
|
+
#### provider_request_tool_inventory
|
|
671
|
+
|
|
672
|
+
Fired after the complete `before_provider_request` replacement chain and before the final payload is returned to provider transport. This event is observation-only: handlers have no return value and cannot change the outgoing request.
|
|
673
|
+
|
|
674
|
+
```typescript
|
|
675
|
+
pi.on("provider_request_tool_inventory", (event) => {
|
|
676
|
+
// Immutable, bounded identity of the exact routed model.
|
|
677
|
+
console.log(`${event.model.provider}/${event.model.id} (${event.model.api})`);
|
|
678
|
+
// Frozen copy from this request's provider-neutral context.
|
|
679
|
+
console.log(event.requestContextToolNames);
|
|
680
|
+
|
|
681
|
+
if (event.inventory.status === "observed") {
|
|
682
|
+
// Sorted, deduplicated names from the final serialized payload.
|
|
683
|
+
console.log(event.inventory.toolNames);
|
|
684
|
+
} else {
|
|
685
|
+
// "malformed" includes a bounded reason; "unsupported" does not inspect payload fields.
|
|
686
|
+
console.log(event.inventory.status);
|
|
687
|
+
}
|
|
688
|
+
});
|
|
689
|
+
```
|
|
690
|
+
|
|
691
|
+
The event and all nested fields are frozen. The model snapshot contains only `provider`, `id`, and `api`; it excludes model headers, credentials, URLs, and other configuration. Supported built-in shape families are OpenAI Responses/Azure/Codex, OpenAI completions, Mistral conversations, Anthropic messages, Google Generative AI/Vertex function declarations, and Bedrock tool specifications. A missing optional tool container or valid empty list is observed as an empty inventory; malformed known shapes report only a bounded reason, never raw payload content. Custom API identifiers report `unsupported` when their provider invokes `onPayload`; a custom provider that does not invoke `onPayload` produces no final-schema observation.
|
|
692
|
+
|
|
693
|
+
This boundary proves only what was present in the final pre-transport payload value after the public callback and extension rewrite chain. It does not prove transport success, response parsing, assistant completion, persistence, or model tool selection. If successful reload replaces the request's extension runner during provider-neutral preparation or before payload dispatch begins, extension rewriting and observation are skipped while the independent public callback still applies. If replacement occurs while the old runner's rewrite chain is already in flight, its completed replacement is preserved and the observation is suppressed. Observer failures use normal extension error isolation and do not alter the outgoing payload.
|
|
694
|
+
|
|
695
|
+
**TypeScript compatibility:** Adding this event extends the exported `ExtensionEvent` union. Consumers with exhaustive switches over that union must add this member or a default/unknown-event branch; ordinary `pi.on(...)` registrations remain compatible.
|
|
638
696
|
|
|
639
697
|
#### after_provider_response
|
|
640
698
|
|
|
@@ -880,7 +938,7 @@ UI methods for user interaction. See [Custom UI](#custom-ui) for full details.
|
|
|
880
938
|
|
|
881
939
|
### ctx.hasUI
|
|
882
940
|
|
|
883
|
-
`false` in print mode (`-p`) and JSON mode. `true` in interactive and RPC mode. In RPC mode, dialog methods (`select`, `confirm`, `input`, `editor`) work via the extension UI sub-protocol, and fire-and-forget methods (`notify`, `setStatus`, `setWidget`, `setTitle`, `setEditorText`) emit requests to the client
|
|
941
|
+
`false` in print mode (`-p`) and JSON mode. `true` in interactive and RPC mode. This is a transport-level signal, not a guarantee that every UI method is supported. In RPC mode, dialog methods (`select`, `confirm`, `input`, `editor`) work via the extension UI sub-protocol, and fire-and-forget methods (`notify`, `setStatus`, `setWidget`, `setTitle`, `setEditorText`) emit requests to the client, but TUI-only `custom()` resolves `undefined`. Other TUI-specific methods are no-ops or return defaults (see [rpc.md](rpc.md#extension-ui-protocol)). Extensions that require a specific UI method must handle that method's documented unsupported result.
|
|
884
942
|
|
|
885
943
|
### ctx.cwd
|
|
886
944
|
|
|
@@ -955,14 +1013,16 @@ Returns current context usage for the active model. Uses last assistant usage wh
|
|
|
955
1013
|
|
|
956
1014
|
```typescript
|
|
957
1015
|
const usage = ctx.getContextUsage();
|
|
958
|
-
if (usage && usage.tokens >
|
|
1016
|
+
if (usage && usage.tokens !== null && usage.tokens > usage.contextWindow * 0.8) {
|
|
959
1017
|
// ...
|
|
960
1018
|
}
|
|
961
1019
|
```
|
|
962
1020
|
|
|
1021
|
+
`usage.contextWindow` is maximum supported total context and the denominator of `usage.percent`. Tokens and percent remain `null` when usage is unknown after compaction. The former `contextWindowBudget` field and `getContextWindowBudget()` export are removed; replace those reads with `contextWindow`. Model registrations may separately represent a genuine provider input constraint with `maxInputTokens`, not a discretionary budget. See [models.md](models.md#breaking-migration-from-context-budgets) for the breaking migration, validation, and preserved configuration/OAuth fallback behavior.
|
|
1022
|
+
|
|
963
1023
|
### ctx.compact()
|
|
964
1024
|
|
|
965
|
-
Trigger compaction without awaiting completion. Use `onComplete` and `onError` for follow-up actions.
|
|
1025
|
+
Trigger compaction without awaiting completion. Use `onComplete` and `onError` for follow-up actions. Competing manual/automatic compaction, branch summarization, or executing idle-origin harness work causes immediate refusal through `onError`; retry deliberately after conflicting work and its persistence settle. The admitted owner drains final `message_end` hooks and persistence while suppressing queued/new run/turn lifecycle continuation. New session harness invocations reject during manual ownership. See [manual admission and terminal drain](compaction.md#manual-admission-and-terminal-drain).
|
|
966
1026
|
|
|
967
1027
|
```typescript
|
|
968
1028
|
ctx.compact({
|
|
@@ -982,6 +1042,7 @@ Returns Scramjet's current system prompt string.
|
|
|
982
1042
|
|
|
983
1043
|
- During `before_agent_start`, this reflects chained system-prompt changes made so far for the current turn.
|
|
984
1044
|
- It does not include later `context` message mutations.
|
|
1045
|
+
- It does not include request-local `before_provider_call` prompt replacements.
|
|
985
1046
|
- It does not include `before_provider_request` payload rewrites.
|
|
986
1047
|
- If later-loaded extensions run after yours, they can still change what is ultimately sent.
|
|
987
1048
|
|
|
@@ -1516,10 +1577,17 @@ if (pi.getFlag("plan")) {
|
|
|
1516
1577
|
Execute a shell command.
|
|
1517
1578
|
|
|
1518
1579
|
```typescript
|
|
1519
|
-
const result = await pi.exec("
|
|
1520
|
-
|
|
1580
|
+
const result = await pi.exec("gh", ["api", "--method", "POST", "--input", "-", endpoint], {
|
|
1581
|
+
signal,
|
|
1582
|
+
timeout: 5000,
|
|
1583
|
+
stdin: JSON.stringify(payload),
|
|
1584
|
+
});
|
|
1585
|
+
// result.stdout, result.stderr, result.code, result.killed,
|
|
1586
|
+
// result.spawnError, result.stdinError, result.stdoutError, result.stderrError
|
|
1521
1587
|
```
|
|
1522
1588
|
|
|
1589
|
+
When `stdin` is supplied, `pi.exec` writes that exact UTF-8 string once and closes standard input without adding a newline. `spawnError` is present only when the command failed before spawning; `stdinError` reports a write or close failure; `stdoutError` and `stderrError` report output-pipe failures after spawn. Each error contains a safe `message` and optional system `code`, never stdin or process output content. Once the child has spawned, callers must use command-specific semantics to decide whether a failed execution may have produced side effects.
|
|
1590
|
+
|
|
1523
1591
|
### pi.getActiveTools() / pi.getAllTools() / pi.setActiveTools(names)
|
|
1524
1592
|
|
|
1525
1593
|
Manage active tools. This works for both built-in tools and dynamically registered tools.
|
|
@@ -1539,6 +1607,8 @@ const extensionTools = all.filter((t) => t.sourceInfo.source !== "builtin" && t.
|
|
|
1539
1607
|
pi.setActiveTools(["read", "bash"]); // Switch to read-only
|
|
1540
1608
|
```
|
|
1541
1609
|
|
|
1610
|
+
Changes made by an awaited `turn_end` handler settle before the next provider request snapshots active tools and generated guidance.
|
|
1611
|
+
|
|
1542
1612
|
`pi.getAllTools()` returns `name`, `description`, `parameters`, and `sourceInfo`.
|
|
1543
1613
|
|
|
1544
1614
|
Typical `sourceInfo.source` values:
|
|
@@ -1546,6 +1616,24 @@ Typical `sourceInfo.source` values:
|
|
|
1546
1616
|
- `sdk` for tools passed via `createAgentSession({ customTools })`
|
|
1547
1617
|
- extension source metadata for tools registered by extensions
|
|
1548
1618
|
|
|
1619
|
+
### pi.invokeHarnessTool(name, args, options?)
|
|
1620
|
+
|
|
1621
|
+
Execute a registered tool as a **harness-originated** call — one the harness makes itself, not one the model requested. The tool runs through the identical prepare/execute/finalize pipeline as a model tool call: it produces the same live `tool_execution_*`/message events, persisted session entries, and `tool_call`/`tool_result` hooks, but emits **no** run/turn framing (`agent_start`/`turn_*`/`agent_end`), so it is invisible to `agent_end`-keyed logic. The tool is resolved from the full registry, so a `"harness-only"` tool (never provider-visible) can still be executed. When the agent is idle the call executes immediately; mid-run it is queued and drained before the next intra-run LLM call.
|
|
1622
|
+
|
|
1623
|
+
```typescript
|
|
1624
|
+
// Record a harness-originated event as a real, replayable tool row, then proceed only once it exists.
|
|
1625
|
+
await pi.invokeHarnessTool("my_notice_tool", { text: "model changed to X" });
|
|
1626
|
+
// The tool-result row is now persisted in the session transcript.
|
|
1627
|
+
```
|
|
1628
|
+
|
|
1629
|
+
The returned promise **resolves only after the resulting tool-result message has been persisted** to the session — a stronger guarantee than "the tool ran". A consumer that must not replace or tear down the session (e.g. before starting a fresh session) until the record row exists can safely `await` it. The promise **rejects** if no tool with `name` is registered, if a matching event fails to process/persist, if the session is disposed before it settles or is called after disposal, or if an explicit `options.toolCallId` is malformed or already pending. Rejection means the pipeline did not complete — it does **not** prove the artifact is absent (state and persistence may have partially completed), so do not blindly retry. A tool's own `execute()` error is not a rejection: it resolves normally as an `isError` result.
|
|
1630
|
+
|
|
1631
|
+
New invocations also reject during manual compaction ownership, before allocating an id or persistence acknowledgement or executing a tool. Already-admitted active-run/queued invocations drain normally; manual compaction refuses existing idle-origin execution rather than pretending `Agent.waitForIdle()` covers it. This session-local admission policy does not guard direct underlying Agent calls.
|
|
1632
|
+
|
|
1633
|
+
`options.toolCallId` (optional) sets an explicit tool-call id (must be provider-safe: 1-64 characters of `[a-zA-Z0-9_-]`); a provider-safe id is generated when omitted.
|
|
1634
|
+
|
|
1635
|
+
Do not `await` this from work whose return is required for the agent to reach the mid-run drain point or for the event queue to persist the result (a model-callable `execute`, `beforeToolBatch`/`beforeToolCall`/`afterToolCall`/`prepareNextTurn`, or an awaited event handler) — that would deadlock. Start the promise, return from the gating callback, and await it from an independent continuation.
|
|
1636
|
+
|
|
1549
1637
|
### pi.setModel(model)
|
|
1550
1638
|
|
|
1551
1639
|
Set the current model. Returns `false` if no API key is available for the model. See [models.md](models.md) for configuring custom models.
|
|
@@ -1798,7 +1886,13 @@ pi.registerTool({
|
|
|
1798
1886
|
});
|
|
1799
1887
|
```
|
|
1800
1888
|
|
|
1801
|
-
**Signaling errors:**
|
|
1889
|
+
**Signaling errors:** Throw an error from `execute`, or return `isError: true` alongside `content` and `details`. Returned failures retain their structured details and are reported to the LLM as errors. Omitted `isError` preserves normal success; `tool_result` hooks may still override the final error flag.
|
|
1890
|
+
|
|
1891
|
+
**Reported cost:** Results and `onUpdate` partials may include `cost: number`, the invocation's cumulative reported USD including descendants but excluding the requesting assistant. Each finite, nonnegative report replaces the previous amount; zero is authoritative, omission is not a new report, and malformed values are ignored. The latest reported cost survives a final result that omits it and `tool_result` content/details patches; hooks cannot override cost through their patch interface. On an execution throw, the latest cost-bearing partial's details and cost accompany the error text, even after a content-only update. On an after-tool hook failure, executed accounting-bearing details and cost accompany the error text. Neither failure inherits a termination hint. Non-accounting throws retain their existing empty-details behavior.
|
|
1892
|
+
|
|
1893
|
+
**Historical cost interpretation:** A tool definition may supply synchronous, read-only `getHistoricalCost(details: unknown): number | undefined` to recover costs from older saved details. It must tolerate untrusted historical data, return only a finite nonnegative amount or `undefined`, and never execute work or call a renderer. It stays on the definition, not the executable Agent tool; consumers own aggregation and prefer valid generic message cost, including zero, over this fallback. `AgentSession.getRecordedSessionCost()` and the default footer include all journal assistant/tool costs plus live reports awaiting final append. The interpreter remains available on discovered definitions even when a tool is inactive or excluded by the execution allowlist, following the same definition collision winners without enabling execution. Missing definitions cannot recover legacy schemas. Interpreter exceptions use the extension error channel and do not break presentation.
|
|
1894
|
+
|
|
1895
|
+
Session accounting captures scalar reports before asynchronous event hooks. A final `message_end` replacement can change tool content/details but cannot override the captured cost. Live cost transfers to recorded cost only after a successful append; append failure retains the observation in memory and uses existing persistence/settlement error reporting, without automatic retry or a durability claim. Disposal clears live ownership; ordinary abort does not discard it. Compaction/tree navigation retain whole-journal recorded totals, and forks count only copied records. This does not redefine `/session`, RPC statistics, or custom footers.
|
|
1802
1896
|
|
|
1803
1897
|
**Early termination:** Return `terminate: true` from `execute()` to hint that the automatic follow-up LLM call should be skipped after the current tool batch. This only takes effect when every finalized tool result in that batch is terminating. See [examples/extensions/structured-output.ts](../examples/extensions/structured-output.ts) for a minimal example where the agent ends on a final structured-output tool call.
|
|
1804
1898
|
|
|
@@ -2151,6 +2245,16 @@ Extensions can interact with users via `ctx.ui` methods and customize how messag
|
|
|
2151
2245
|
- Autocomplete providers layered on top of built-in slash/path completion (addAutocompleteProvider)
|
|
2152
2246
|
- Custom footers (setFooter)
|
|
2153
2247
|
|
|
2248
|
+
### Retained viewport and input ownership
|
|
2249
|
+
|
|
2250
|
+
InteractiveMode uses the existing component presentation in an alternate-screen retained viewport. Ordinary `render(width)`, tool `renderCall`/`renderResult`, result/session schemas and HTML export contracts are unchanged. Render the complete logical text rather than clipping it to terminal height. Components receive terminal width minus the reserved scrollbar column; images alone may use the optional `setViewportHeight` bound. Standard Container/Box propagate it; custom image wrappers must forward it. Unrecognized custom graphics envelopes display a placeholder rather than an unsafe clipped placement.
|
|
2251
|
+
|
|
2252
|
+
`ctx.ui.onTerminalInput()` listeners run after the viewport listener. They do not receive consumed pointer packets, selection-copy keys, Ctrl+Home/Ctrl+End transcript navigation or detached PageUp/PageDown/Escape when the input owner permits viewport navigation. Ordinary Home/End pass through for editor line-start/end behavior. Do not use raw listeners to compete for transcript pointer ownership. Focused overlays keep keyboard precedence, and conflicting selector bindings precede configurable Alt+PageUp/Alt+PageDown transcript actions. Focus-in/out reports are consumed rather than delivered as ordinary input. The viewport keeps no session-journal state; session reconstruction discards browsing/selection state.
|
|
2253
|
+
|
|
2254
|
+
The input area is docked by default, with widgets preserving their above/below-editor placement. Docking can change live without replacing component instances. Non-fitting extension content remains reachable in an explained undocked retained flow. Custom editors can implement `setHeightLimit(limits)`, where the callback returns `{ rows, text }` for the current total input budget and maximum wrapped text rows. Respect the budget without losing draft content, keep the cursor and active completion choice visible, and use the effective text-window height for paging. This is separate from the image-only `setViewportHeight` API. Editors with completion menus can also expose optional `isShowingAutocomplete(): boolean`; InteractiveMode then reveals a hidden editor slot independently of its hardware cursor and consumes acceptance until the slot is visible and its current paint has flushed. Built-in `CustomEditor` inherits this capability. See [tui.md](tui.md#retained-viewport-api) for projection, selection and geometry contracts.
|
|
2255
|
+
|
|
2256
|
+
Kitty-capable viewport terminals explicitly encode printable keys as well as modified keys. Match actions against raw input with `matchesKey()`/the injected keybinding manager before using `decodeKittyPrintable(data) ?? data` for printable-mode mappings; decoding first can obscure special-key identities such as keypad Enter. Do not assume a printable key is one raw byte. Raw listeners must ignore `isKeyRelease(data)` unless they intentionally handle releases; focused components filter releases by default. The shipped [modal editor](../examples/extensions/modal-editor.ts) demonstrates the printable-key migration. No blanket compatibility claim is made for external raw-byte listeners or graphics wrappers; see [tui.md](tui.md) for exact viewport APIs and [terminal-setup.md](terminal-setup.md#native-compatibility-evidence) for tested configurations.
|
|
2257
|
+
|
|
2154
2258
|
### Dialogs
|
|
2155
2259
|
|
|
2156
2260
|
```typescript
|
|
@@ -2369,18 +2473,18 @@ See [github-issue-autocomplete.ts](../examples/extensions/github-issue-autocompl
|
|
|
2369
2473
|
For complex UI, use `ctx.ui.custom()`. This temporarily replaces the editor with your component until `done()` is called:
|
|
2370
2474
|
|
|
2371
2475
|
```typescript
|
|
2372
|
-
import { Text
|
|
2476
|
+
import { Text } from "@leanandmean/tui";
|
|
2373
2477
|
|
|
2374
|
-
const result = await ctx.ui.custom<boolean>((
|
|
2478
|
+
const result = await ctx.ui.custom<boolean>((_tui, _theme, keybindings, done) => {
|
|
2375
2479
|
const text = new Text("Press Enter to confirm, Escape to cancel", 1, 1);
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2480
|
+
return {
|
|
2481
|
+
render: (width) => text.render(width),
|
|
2482
|
+
invalidate: () => text.invalidate(),
|
|
2483
|
+
handleInput(data) {
|
|
2484
|
+
if (keybindings.matches(data, "tui.select.confirm")) done(true);
|
|
2485
|
+
else if (keybindings.matches(data, "tui.select.cancel")) done(false);
|
|
2486
|
+
},
|
|
2381
2487
|
};
|
|
2382
|
-
|
|
2383
|
-
return text;
|
|
2384
2488
|
});
|
|
2385
2489
|
|
|
2386
2490
|
if (result) {
|
|
@@ -2394,6 +2498,28 @@ The callback receives:
|
|
|
2394
2498
|
- `keybindings` - App keybinding manager (for checking shortcuts)
|
|
2395
2499
|
- `done(value)` - Call to close component and return value
|
|
2396
2500
|
|
|
2501
|
+
Ordinary editor-slot custom UI can opt into actual layout allocation with `ctx.ui.custom(factory, { onAvailableHeight(rows) { maximumRows = rows; } })`, where `maximumRows` is invocation-local state read during rendering. The callback receives `undefined` at mounting/release and a numeric row budget before each allocated render; it can run more than once per frame. It must not request another render or change focus, and allocation does not certify docking, visibility or flushing. Retained undocked rendering can allocate rows too; committed rendering has no numeric allocation. Below-minimum geometry skips rendering rather than delivering a temporary budget, and recovery supplies a fresh allocation. Other components are unchanged unless they explicitly opt in. The option is incompatible with overlays and tool-attached context and is rejected before the factory runs; it is separate from image-only `setViewportHeight` and editor text-height preferences. Allocation-notification errors reject the owning custom UI request and release/dispose its control; release-notification errors are reported without stranding completion. See [allocated custom input height](tui.md#allocated-custom-input-height).
|
|
2502
|
+
|
|
2503
|
+
A pending sequential tool can attach immutable long-form context to its own tool row before compact controls become interactive. Pass the current `toolCallId` from the tool's `execute()` method:
|
|
2504
|
+
|
|
2505
|
+
```typescript
|
|
2506
|
+
const result = await ctx.ui.custom(
|
|
2507
|
+
(_tui, _theme, _keybindings, done) => new ApprovalSelector(done),
|
|
2508
|
+
{
|
|
2509
|
+
toolAttachedContext: {
|
|
2510
|
+
toolCallId,
|
|
2511
|
+
render: (_tui, theme) => new Text(theme.fg("muted", completeContext), 0, 0),
|
|
2512
|
+
},
|
|
2513
|
+
},
|
|
2514
|
+
);
|
|
2515
|
+
```
|
|
2516
|
+
|
|
2517
|
+
The complete immutable context is installed at that pending tool's transcript position. In both renderer modes, the editor is defocused and a required initial flush must succeed before controls receive focus. Missing/non-leading/settled tool rows, context replaced before that flush settles, and missing or failed flushing reject the request through attachment cleanup. Context is visual-only, not persisted or sent to the model. Use this only from the sequential tool whose id is supplied.
|
|
2518
|
+
|
|
2519
|
+
In default **retained mode**, the context remains browseable through Scramjet's scrollbar even when taller than the screen; it need not all be simultaneously visible or emitted into native scrollback. Controls require current-paint flush evidence, complete rendering of the full context and controls, and whole-control visibility. Clipped context (including offscreen rows) or controls that cannot fit fail closed. If browsing hides controls, the first activation reveals and flushes them without approving; only subsequent input can authorize. Attachment currentness and these presentation guards are rechecked on input.
|
|
2520
|
+
|
|
2521
|
+
With startup-only **`tuiMode: "committed"`**, `commitNow({ requireFlush: true })` emits the complete context into committed native history and waits for the initial flush before focusing controls. The mutable canvas remains tail-windowed; this mode does **not** provide Scramjet scrollbar access, retained render-completeness/whole-control-visibility checks, or reveal-before-subsequent-activation protection. Do not rely on those retained-only guarantees when supporting committed compatibility mode.
|
|
2522
|
+
|
|
2397
2523
|
See [tui.md](tui.md) for the full component API.
|
|
2398
2524
|
|
|
2399
2525
|
#### Overlay Mode (Experimental)
|
|
@@ -2438,7 +2564,7 @@ class VimEditor extends CustomEditor {
|
|
|
2438
2564
|
this.mode = "normal";
|
|
2439
2565
|
return;
|
|
2440
2566
|
}
|
|
2441
|
-
if (this.mode === "normal" && data
|
|
2567
|
+
if (this.mode === "normal" && matchesKey(data, "i")) {
|
|
2442
2568
|
this.mode = "insert";
|
|
2443
2569
|
return;
|
|
2444
2570
|
}
|
|
@@ -2541,14 +2667,14 @@ const highlighted = highlightCode(code, lang, theme);
|
|
|
2541
2667
|
|
|
2542
2668
|
- Extension errors are logged, agent continues
|
|
2543
2669
|
- `tool_call` errors block the tool (fail-safe)
|
|
2544
|
-
- Tool `execute` errors
|
|
2670
|
+
- Tool `execute` errors may be signaled by throwing or returning `isError: true`; failures are reported to the LLM and execution continues unless the finalized batch explicitly terminates
|
|
2545
2671
|
|
|
2546
2672
|
## Mode Behavior
|
|
2547
2673
|
|
|
2548
2674
|
| Mode | UI Methods | Notes |
|
|
2549
2675
|
|------|-----------|-------|
|
|
2550
2676
|
| Interactive | Full TUI | Normal operation |
|
|
2551
|
-
| RPC (`--mode rpc`) | JSON protocol | Host handles UI
|
|
2677
|
+
| RPC (`--mode rpc`) | JSON protocol | Host handles supported UI methods; TUI-only `custom()` resolves `undefined`, see [rpc.md](rpc.md) |
|
|
2552
2678
|
| JSON (`--mode json`) | No-op | Event stream to stdout, see [json.md](json.md) |
|
|
2553
2679
|
| Print (`-p`) | No-op | Extensions run but can't prompt |
|
|
2554
2680
|
|
package/docs/json.md
CHANGED
|
@@ -6,6 +6,12 @@ scramjet --mode json "Your prompt"
|
|
|
6
6
|
|
|
7
7
|
Outputs all session events as JSON lines to stdout. Useful for integrating Scramjet into other tools or custom UIs.
|
|
8
8
|
|
|
9
|
+
## Invocation-scoped models and failures
|
|
10
|
+
|
|
11
|
+
`--mode json` accepts `--model-definition '<JSON>'` or `--model-definition-env NAME` for a process-local compatible route. See [the complete contract](models.md#invocation-scoped-headless-models) for required deployment-evidenced limits, strict environment credentials, conflicts and persistence. The definition is not automatically activated by ambient environment variables.
|
|
12
|
+
|
|
13
|
+
Invalid definition/environment input fails startup with nonzero status. Generation failures may still exit zero in JSON mode: inspect finalized assistant `message_end` entries for `stopReason: "error"`/`"aborted"`, their `errorMessage`/diagnostics, and retry outcomes rather than treating process exit or `agent_end` as success. Explicit request failures do not silently switch routes; existing same-route recovery remains. Text print errors retain nonzero status; [RPC](rpc.md) separately distinguishes prompt acceptance from generation success. No new event shape or exit policy is introduced.
|
|
14
|
+
|
|
9
15
|
## Event Types
|
|
10
16
|
|
|
11
17
|
Events are defined in [`AgentSessionEvent`](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/agent-session.ts#L102):
|
|
@@ -55,6 +61,8 @@ Extended messages from [`packages/coding-agent/src/core/messages.ts`](https://gi
|
|
|
55
61
|
- `BranchSummaryMessage` (line 55)
|
|
56
62
|
- `CompactionSummaryMessage` (line 62)
|
|
57
63
|
|
|
64
|
+
Tool execution updates (`partialResult.cost`), execution-end results (`result.cost`), and final `toolResult` messages (`message.cost`) may carry optional finite, nonnegative cumulative invocation USD, including descendants but excluding the requesting assistant. Reports replace prior amounts rather than representing additional expenditures; zero is authoritative and omission is not a new report. Final costs remain present for reported failures (`isError: true`). These are additive fields in JSON and RPC events; closed-schema clients must allow them. Existing tools may omit them.
|
|
65
|
+
|
|
58
66
|
## Output Format
|
|
59
67
|
|
|
60
68
|
Each line is a JSON object. The first line is the session header:
|
package/docs/keybindings.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Keybindings
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Action keybindings can be customized via `~/.scramjet/agent/keybindings.json`. Each action can be bound to one or more keys.
|
|
4
4
|
|
|
5
5
|
The config file uses the same namespaced keybinding ids that Scramjet uses internally and that extension authors use in `keyHint()` and injected `keybindings` managers.
|
|
6
6
|
|
|
@@ -20,8 +20,30 @@ After editing `keybindings.json`, run `/reload` in Scramjet to apply the changes
|
|
|
20
20
|
|
|
21
21
|
Modifier combinations: `ctrl+shift+x`, `alt+ctrl+x`, `ctrl+shift+alt+x`, `ctrl+1`, etc.
|
|
22
22
|
|
|
23
|
+
## Transcript browsing precedence
|
|
24
|
+
|
|
25
|
+
Interactive mode's retained viewport owns mouse wheel/trackpad scrolling, the rightmost draggable scrollbar and ordinary drag selection. Right-click a nonempty selection or use `tui.input.copy` (Ctrl+C by default) to copy displayed text. Without a transcript selection, the same key keeps its focused-component/application behavior. Escape clears selection and returns to the live tail.
|
|
26
|
+
|
|
27
|
+
While detached from the tail with the editor owning input, the viewport consumes this fixed set before editor bindings; focused selectors retain their own navigation and cancellation bindings:
|
|
28
|
+
|
|
29
|
+
| Key | Browsing action |
|
|
30
|
+
|-----|-----------------|
|
|
31
|
+
| PageUp / PageDown | Scroll one viewport page |
|
|
32
|
+
| Escape | Return to the live tail |
|
|
33
|
+
|
|
34
|
+
Home/End retain editor line-start/end behavior at every transcript position. Ctrl+Home goes to the transcript beginning and Ctrl+End goes to its bottom and resumes following, whether currently following or detached. Docked input and configured tool/thinking presentation toggles preserve the transcript anchor; undocked ordinary editing reveals the editor cursor. Submitting nonempty editor input resumes following before command routing or queueing, including Enter and Alt+Enter. New user-message delivery also resumes following; passive output does not. At the tail, unmodified paging retains its editor/list meanings. Focused overlays take precedence, and focused selector bindings take precedence over both fixed and configurable viewport actions. In particular, Escape cancels a focused settings selector rather than merely returning its transcript to the tail. If tool-attached approval controls are hidden by browsing, the first activation reveals and flushes them without approving; a later activation can approve.
|
|
35
|
+
|
|
36
|
+
The fixed detached-only keys above remain separate from `tui.viewport.pageUp` and `tui.viewport.pageDown`, which default to Alt+PageUp and Alt+PageDown and work from the tail as well as while browsing. Terminal/desktop interception can require remapping these configurable actions. See [terminal-setup.md](terminal-setup.md#transcript-browsing-and-copying) for terminal-menu and clipboard requirements.
|
|
37
|
+
|
|
23
38
|
## All Actions
|
|
24
39
|
|
|
40
|
+
### Transcript Navigation
|
|
41
|
+
|
|
42
|
+
| Keybinding id | Default | Description |
|
|
43
|
+
|--------|---------|-------------|
|
|
44
|
+
| `tui.viewport.pageUp` | `alt+pageUp` | Browse one transcript page upward, including from the tail |
|
|
45
|
+
| `tui.viewport.pageDown` | `alt+pageDown` | Browse one transcript page downward |
|
|
46
|
+
|
|
25
47
|
### TUI Editor Cursor Movement
|
|
26
48
|
|
|
27
49
|
| Keybinding id | Default | Description |
|
|
@@ -114,6 +136,8 @@ Modifier combinations: `ctrl+shift+x`, `alt+ctrl+x`, `ctrl+shift+alt+x`, `ctrl+1
|
|
|
114
136
|
| `app.thinking.cycle` | `shift+tab` | Cycle thinking level |
|
|
115
137
|
| `app.thinking.toggle` | `ctrl+t` | Collapse or expand thinking blocks |
|
|
116
138
|
|
|
139
|
+
`app.thinking.cycle` also works while Scramjet next-step and structured confirm/select dialogs are open. Those dialogs display the usable configured shortcut, apply effort changes immediately, and retain them when cancelled. Dialog navigation, confirmation, cancellation, and next-step model arrows take precedence if bindings conflict; freetext and headless interactions are unchanged.
|
|
140
|
+
|
|
117
141
|
### Display and Message Queue
|
|
118
142
|
|
|
119
143
|
| Keybinding id | Default | Description |
|
package/docs/models.md
CHANGED
|
@@ -4,6 +4,7 @@ Add custom providers and models (Ollama, vLLM, LM Studio, proxies) via `~/.scram
|
|
|
4
4
|
|
|
5
5
|
## Table of Contents
|
|
6
6
|
|
|
7
|
+
- [Invocation-scoped Headless Models](#invocation-scoped-headless-models)
|
|
7
8
|
- [Minimal Example](#minimal-example)
|
|
8
9
|
- [Full Example](#full-example)
|
|
9
10
|
- [Supported APIs](#supported-apis)
|
|
@@ -14,6 +15,72 @@ Add custom providers and models (Ollama, vLLM, LM Studio, proxies) via `~/.scram
|
|
|
14
15
|
- [Anthropic Messages Compatibility](#anthropic-messages-compatibility)
|
|
15
16
|
- [OpenAI Compatibility](#openai-compatibility)
|
|
16
17
|
|
|
18
|
+
## Invocation-scoped Headless Models
|
|
19
|
+
|
|
20
|
+
Use one model definition for a single headless invocation without editing `models.json` or installing an extension:
|
|
21
|
+
|
|
22
|
+
- `--model-definition '<JSON>'` supplies strict JSON directly.
|
|
23
|
+
- `--model-definition-env NAME` reads strict JSON from the named environment variable only when explicitly selected.
|
|
24
|
+
|
|
25
|
+
Both selectors accept `=value` forms. Missing values, repeated selectors, using both selectors, or combining either with `--provider`, `--model`, `--models` or `--api-key` are errors. Ambient definition variables alone never activate a route. Use `--thinking` separately: the model `id` is a nonblank literal backend ID, preserving case, slashes and colons without fuzzy matching, provider-prefix parsing or thinking-suffix interpretation.
|
|
26
|
+
|
|
27
|
+
Supported execution modes are `--print`, `--mode json`, `--mode rpc`, and print mode selected by redirected stdin. Actual interactive execution is rejected. Help/version need no credentials; `--list-models` can inspect a supplied definition without resolving its credential.
|
|
28
|
+
|
|
29
|
+
### Definition fields
|
|
30
|
+
|
|
31
|
+
| Field | Requirement and meaning |
|
|
32
|
+
|-------|-------------------------|
|
|
33
|
+
| `api` | Required: `openai-completions`, `openai-responses`, `anthropic-messages`, or `google-generative-ai` |
|
|
34
|
+
| `baseUrl` | Required absolute HTTP(S) URL with a host; no userinfo, query, fragment, controls or whitespace. Supply the adapter-appropriate base path; there is no endpoint/version discovery. |
|
|
35
|
+
| `id` | Required nonblank literal backend model ID |
|
|
36
|
+
| `apiKeyEnv` | Required environment variable identifier containing a nonblank credential at startup |
|
|
37
|
+
| `contextWindow` | Required positive finite maximum supported total context; positive fractional values remain accepted |
|
|
38
|
+
| `maxTokens` | Required positive safe-integer maximum output allowance |
|
|
39
|
+
| `name` | Optional nonempty label; defaults to `id` |
|
|
40
|
+
| `reasoning` | Optional boolean; defaults to `false` |
|
|
41
|
+
| `input` | Optional array of `text`/`image` modalities; defaults to `["text"]` |
|
|
42
|
+
| `thinkingLevelMap` | Optional existing [thinking-level mapping](#thinking-level-map) |
|
|
43
|
+
| `compat` | Optional existing API-valid [OpenAI](#openai-compatibility) or [Anthropic](#anthropic-messages-compatibility) compatibility overrides; API-incompatible fields are rejected |
|
|
44
|
+
| `cost` | Optional complete finite-number `input`, `output`, `cacheRead`, `cacheWrite` estimates per million tokens; defaults to zero estimates |
|
|
45
|
+
| `maxInputTokens` | Optional positive finite independent input constraint, evidenced for the supplied route |
|
|
46
|
+
| `requestLimits` | Optional nonempty array of existing [joint endpoint constraints](#joint-endpoint-constraints) |
|
|
47
|
+
|
|
48
|
+
Unknown fields, including nested unsupported keys/values, are rejected. Credential literals, headers, provider identity, OAuth, custom stream functions, provider collections/overrides, file references and discovery configuration are not supported. JSON comments and trailing commas are rejected; input is never loaded from a file or evaluated as a shell command.
|
|
49
|
+
|
|
50
|
+
Obtain limits and capabilities from the actual deployment's applicable documentation/account metadata. `contextWindow` stays the total-context denominator; input constraints and output allocation remain separate. Output need not be less than total context: existing request-local allocation bounds feasible output without changing either scalar maximum. These estimates/checks do not establish backend acceptance, entitlement or exact serialized token counts. Omitted capabilities are client defaults, not capability evidence; zero cost estimates do not mean free billing. Existing adapter compatibility defaults still apply.
|
|
51
|
+
|
|
52
|
+
### Example using caller deployment metadata
|
|
53
|
+
|
|
54
|
+
For a deployment confirmed to implement Chat Completions, set `DEPLOYMENT_BASE_URL`, `DEPLOYMENT_MODEL_ID`, `DEPLOYMENT_CONTEXT_WINDOW` and `DEPLOYMENT_MAX_OUTPUT` from its metadata, and export `ROUTE_API_KEY` from your credential source. Then, using `jq` to construct JSON:
|
|
55
|
+
|
|
56
|
+
```sh
|
|
57
|
+
export ROUTE_DEFINITION="$(jq -n \
|
|
58
|
+
--arg baseUrl "$DEPLOYMENT_BASE_URL" \
|
|
59
|
+
--arg id "$DEPLOYMENT_MODEL_ID" \
|
|
60
|
+
--argjson contextWindow "$DEPLOYMENT_CONTEXT_WINDOW" \
|
|
61
|
+
--argjson maxTokens "$DEPLOYMENT_MAX_OUTPUT" \
|
|
62
|
+
'{api:"openai-completions",baseUrl:$baseUrl,id:$id,apiKeyEnv:"ROUTE_API_KEY",contextWindow:$contextWindow,maxTokens:$maxTokens}')"
|
|
63
|
+
scramjet --print --model-definition-env ROUTE_DEFINITION "Summarize this project"
|
|
64
|
+
# Equivalent inline selector, without putting the credential in JSON:
|
|
65
|
+
scramjet --mode json --model-definition "$ROUTE_DEFINITION" "Summarize this project"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Both environment names must be valid identifiers with nonblank values. The credential is captured once, preserving its bytes; it is never interpreted as a shell command, second variable name or literal fallback. Missing credentials fail startup instead of borrowing saved/provider credentials. For an unauthenticated server, the caller may supply a nonblank placeholder in the named credential variable; Scramjet does not invent one. Definition metadata, including the URL, is nonsecret and normally visible through RPC/model output. Controlled input errors omit raw JSON, rejected URL contents and credential values; arbitrary remote echoes and trusted extensions are not covered by a universal redaction guarantee.
|
|
69
|
+
|
|
70
|
+
### Lifetime, selection and persistence
|
|
71
|
+
|
|
72
|
+
Each invocation registers a fresh non-vendor `invocation-<UUID>` provider identity in memory and selects its exact model, bypassing saved startup defaults and scopes. Discover this generated identity through RPC `get_state`/`get_available_models`; concurrent invocations using the same backend ID remain independent. Credentials stay in runtime auth overrides, not model metadata or configuration.
|
|
73
|
+
|
|
74
|
+
Refresh/reload retain the registration. Replacement registries re-register the same captured definition/key. `new_session` inherits the live model/thinking after a deliberate switch; non-inherited session switch/fork/import selection uses the supplied definition. Explicit later model switching remains allowed: this is not a route lock or protection against arbitrary trusted extensions. No automatic forwarding of the complete route to subagents is provided.
|
|
75
|
+
|
|
76
|
+
All sessions created by a definition invocation opt out of saving model/thinking defaults, including later setters/cycling, replacements and switches to other models. Live state, events and ordinary journal model/thinking entries still change. Auth/model configuration remains unchanged; unrelated settings, journals and observational files may still be written. Use `--no-session` to disable journal saving, not as a general filesystem sandbox.
|
|
77
|
+
|
|
78
|
+
Endpoints/keys/limits are not revived from journal model identity. Resupply the definition in each fresh process. Reopening without selectors uses ordinary unavailable-model restoration warnings and default/available-model fallback; it is **not** fail-closed ordinary resume. An explicit invocation startup records its effective branch-local model/thinking identity using existing journal shapes.
|
|
79
|
+
|
|
80
|
+
Invalid definition/environment input fails before migrations/runtime construction with nonzero status. Explicit registration or request failures do not silently select a substitute route; existing retries/compaction may retry the same selected route. Text generation failures report errors and nonzero status. JSON generation errors can accompany exit zero: inspect finalized assistant error events. RPC prompt acceptance is not generation success: inspect subsequent events. See [JSON](json.md), [RPC](rpc.md) and [SDK preference persistence](sdk.md#model-preference-persistence).
|
|
81
|
+
|
|
82
|
+
`google-generative-ai` explicitly pins the generic API even when `GOOGLE_GENAI_USE_VERTEXAI` or `GOOGLE_GENAI_USE_ENTERPRISE` is set. This also applies to configured/dynamic models and direct generic AI streams. Vertex routing requires the existing explicit `google-vertex` API/configuration, which is outside invocation-definition support. Compatibility with every enterprise endpoint is not established; ambient cloud flags are not a supported migration mechanism.
|
|
83
|
+
|
|
17
84
|
## Minimal Example
|
|
18
85
|
|
|
19
86
|
For local models (Ollama, LM Studio, vLLM), only `id` is required per model:
|
|
@@ -91,6 +158,8 @@ Override defaults when you need specific values:
|
|
|
91
158
|
|
|
92
159
|
The file reloads each time you open `/model`. Edit during session; no restart needed.
|
|
93
160
|
|
|
161
|
+
When valid history exists, `/model` and `/scoped-models` append a recent median output-rate estimate to the requested provider/model row. The estimate uses normalized final output usage over first-to-last generated output, excluding time to first token and trailing completion latency; no placeholder is shown for models without history.
|
|
162
|
+
|
|
94
163
|
## Google AI Studio Example
|
|
95
164
|
|
|
96
165
|
Use `google-generative-ai` with a `baseUrl` to add models from Google AI Studio, including custom Gemma 4 entries:
|
|
@@ -194,24 +263,54 @@ If your command is slow, expensive, rate-limited, or should keep using a previou
|
|
|
194
263
|
| `reasoning` | No | `false` | Supports extended thinking |
|
|
195
264
|
| `thinkingLevelMap` | No | omitted | Maps scramjet thinking levels to provider values and marks unsupported levels (see below) |
|
|
196
265
|
| `input` | No | `["text"]` | Input types: `["text"]` or `["text", "image"]` |
|
|
197
|
-
| `contextWindow` | No | `128000` |
|
|
266
|
+
| `contextWindow` | No | `128000` | Maximum supported total context for this provider/model, in tokens |
|
|
267
|
+
| `maxInputTokens` | No | omitted | Genuine independently enforced provider input limit, only when evidenced for this route |
|
|
268
|
+
| `requestLimits` | No | omitted | Non-empty array of provider-declared joint endpoint token constraints (see below) |
|
|
198
269
|
| `maxTokens` | No | `16384` | Maximum output tokens |
|
|
199
270
|
| `cost` | No | all zeros | `{"input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0}` (per million tokens) |
|
|
200
271
|
| `compat` | No | provider `compat` | Provider compatibility overrides. Merged with provider-level `compat` when both are set. |
|
|
201
272
|
|
|
273
|
+
`contextWindow` is the sole total-context authority for usage percentages, the footer, listings, and compaction. Do not reduce it for pricing, presumed quality, or speculative conservatism. `maxTokens` is an independent output allowance; configurable compaction reserves remain separate. Custom-model defaults are client defaults, not evidence of your backend's maximum—set the actual deployment value.
|
|
274
|
+
|
|
275
|
+
Final `contextWindow` and any `maxInputTokens` must be positive finite numbers after configuration merges, dynamic registration, and OAuth transformations; positive fractional context values remain accepted. An input constraint above total context is non-binding, not a reason to increase total context. Only assign input constraints from applicable provider evidence, never by subtracting maximum output or copying an old budget. Aggregate endpoint maxima may not be jointly available under custom routing or account restrictions. OpenRouter generation reads endpoint input constraints and retains the largest permitted input across all reported routes, only when that is independently below total context. A route without a separate input limit contributes its total context, not a guessed output reservation. Empty endpoint lists provide no input-limit evidence. This does not guarantee that the maximum input, output, tools, and other requested capabilities are jointly available on one endpoint.
|
|
276
|
+
|
|
277
|
+
### Joint endpoint constraints
|
|
278
|
+
|
|
279
|
+
`requestLimits` preserves input/output combinations that independent scalar maxima cannot express. Each entry has required positive finite `maxTotalTokens` and boolean `supportsTools`, plus optional positive finite `maxInputTokens` and `maxOutputTokens`. These are endpoint request constraints, not another model context denominator. Omitted input/output fields add no independent bound; they are not output reservations or proof of unlimited backend capacity. An absent array adds no joint check; an empty or malformed array is rejected at configuration, dynamic/OAuth registration, and Faux boundaries.
|
|
280
|
+
|
|
281
|
+
For example, a long-context endpoint can accept 98,304 input tokens but only 8,192 output tokens, while another endpoint allows longer output only within a 40,960-token total. Coding-agent sessions and both built-in summarizers filter these declarations by estimated input and required tool support, then cap explicit output at the largest remaining allowance from a compatible entry. They reject requests with no compatible entry rather than selecting a provider, truncating the prompt, or globally reducing `contextWindow` or `maxTokens`. Ordinary OpenRouter output remains omitted when not explicitly requested. Direct AI streams and ordinary standalone Agent/AgentHarness streams do not automatically run this allocation; their callers own request constraints.
|
|
282
|
+
|
|
283
|
+
OpenRouter and Vercel generation deduplicates equivalent declarations and omits joint metadata when a tool-capable endpoint already admits the entire scalar envelope. Empty or unavailable discovery is not a verified envelope. These declarations do not encode custom routing preferences, account restrictions, modalities, or every requested capability, and do not guarantee provider acceptance. If changing the route, supply applicable constraints through an override or replace the model definition rather than assuming inherited declarations describe the new backend. Overrides replace the entire array, not individual entries.
|
|
284
|
+
|
|
285
|
+
### Breaking migration from context budgets
|
|
286
|
+
|
|
287
|
+
`contextWindowBudget` and the exported `getContextWindowBudget()` resolver have been removed, without aliases. Replace resolver calls and usage-budget reads with `contextWindow`; `ContextUsage` is now `{ tokens, percent, contextWindow }`. Remove the obsolete key from model definitions, `models.json` overrides, dynamic providers, Faux definitions, and OAuth-produced models—even when it equals total context. Registration/configuration diagnostics identify the provider/model and explain removal. No user files are rewritten and no old value is automatically copied into `contextWindow` or `maxInputTokens`.
|
|
288
|
+
|
|
289
|
+
Invalid configuration retains built-ins while rejecting its request settings; an invalid OAuth transformation is diagnosed and its untransformed candidate models remain. This preserves existing fallback behavior, not a guarantee that requests are blocked until configuration is repaired.
|
|
290
|
+
|
|
291
|
+
Built-in metadata is not proof of endpoint acceptance. The provider audit in [issue #525](https://github.com/LeanAndMean/scramjet/issues/525) retains unresolved numerical/route dispositions, including some Codex maxima and aggregate input/output combinations; retained values are not newly verified by this migration. Tests use static metadata and synthetic usage, not paid maximum-context requests. Built-in `cost` values are scalar usage **estimates**, not billing guarantees: the September 2026 refresh reused same-route Pi or prior catalog values where source cache prices were absent. A zero estimate is not proof that a provider bills nothing for cache activity; check the applicable provider/account pricing when monetary accuracy matters. Some built-in model IDs retired or disappeared from both the live source and upstream Pi; a missing feed entry does not prove a custom deployment or account has retired it. Removed IDs no longer appear in selectors: saved selections may fall back to another available model, a configured default that no longer resolves reports the missing ID and chosen fallback at startup, unmatched scopes are skipped, and `modelOverrides` cannot recreate an absent built-in. If a custom deployment still serves one, define it in `models.json` with applicable API, limits and cost metadata, then update saved selections and scopes rather than assuming an alias. An Azure Responses listing for `gpt-realtime-2.1` was removed from an intermediate PR head (it was absent from the committed baseline). Azure Responses GPT-6 Astra, Luna and Sol are now built-ins because Microsoft's own Responses model list, model-limit table and deployment-tier pricing supply route-specific evidence; direct OpenAI limits and prices were not used as Azure proof. Azure region and deployment entitlement still vary. See the [built-in catalog provenance](../../ai/catalog-provenance.md) for dated sources, scoped removal groups, retentions, and exclusions.
|
|
292
|
+
|
|
293
|
+
GPT-6 Astra through the public OpenAI API stores the standard scalar rates of $10 input, $50 output, $1 cache read, and $12.50 cache write per million tokens. Requests above 272,000 input tokens use higher rates for the whole request, which the current scalar estimator cannot represent, so its monetary estimate may be too low while its token counts remain valid. The September 2026 refresh likewise uses the current [OpenAI base-tier prices](https://developers.openai.com/api/docs/pricing) for public GPT-5.6 Sol ($4/$20 input/output), Terra ($2/$12) and Luna ($0.20/$1.20) per million tokens; their long-context tiers can cost more without reducing their 1.05M total context. The `openai-codex` and `github-copilot` records carry scalar values only as usage estimates; those subscription providers do not imply marginal per-request API charges.
|
|
294
|
+
|
|
295
|
+
`openai-codex/gpt-6-sol` and `/gpt-6-luna` use the Codex OAuth route and its published 872K maximum context, not the direct API's 1.05M. Codex's public model catalog does not declare their maximum output; their 128K `maxTokens` values are an explicitly authorized, **provisional** reuse of the direct-API allowance, not a verified Codex-route ceiling. Scalar dollar costs likewise proxy public API usage, not Codex subscription credits or account entitlement. `gpt-5.4` and `gpt-5.4-mini` retired from Codex with ChatGPT sign-in; saved Codex selections of either ID may fall back, with a warning where enabled, but direct OpenAI remains a distinct route. Google's Vertex-specific audit added six tool-capable 3.x models and removed its two documented-retired 2.0 models; the 3.6–3.8 Flash introductory rates expire after December 2026. See the [route audit](../../ai/catalog-provenance.md#hand-maintained-and-derived-route-audit-2026-09-24) for source and retention qualifications.
|
|
296
|
+
|
|
297
|
+
The GitHub Copilot records for `gpt-6-sol`, `gpt-6-luna`, and `claude-opus-5.5` use models.dev and an authenticated individual-account Copilot `GET /models` response observed on 2026-09-23. Where those sources conflicted, the account-scoped Copilot route governed: each record uses 1,000,000 total context, an independent 872,000 input limit, and a 128,000 output limit. These are metadata observations, not paid invocation or maximum-boundary acceptance tests.
|
|
298
|
+
|
|
299
|
+
GitHub Copilot catalog visibility requires configured Copilot authentication, but a listed model is not proof that the current account is entitled to use it or that the endpoint will accept a request. Copilot prices are scalar default/low-context usage estimates for a subscription route, not guaranteed marginal charges, and cannot encode separately reported long-context tiers. Grok's separate long-context rates likewise cannot be represented by the scalar estimator, so estimates for long requests may be too low while token counts remain valid.
|
|
300
|
+
|
|
202
301
|
Current behavior:
|
|
203
302
|
- `/model` and `--list-models` list entries by model `id`.
|
|
204
303
|
- The configured `name` is used for model matching and detail/status text.
|
|
205
304
|
|
|
206
305
|
### Thinking Level Map
|
|
207
306
|
|
|
208
|
-
Use `thinkingLevelMap` on a model to describe model-specific thinking controls. Keys are scramjet thinking levels: `off`, `minimal`, `low`, `medium`, `high`, `xhigh`.
|
|
307
|
+
Use `thinkingLevelMap` on a model to describe model-specific thinking controls. Keys are scramjet thinking levels: `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max`.
|
|
209
308
|
|
|
210
309
|
Values are tristate:
|
|
211
310
|
|
|
212
311
|
| Value | Meaning |
|
|
213
312
|
|-------|---------|
|
|
214
|
-
| omitted |
|
|
313
|
+
| omitted | Ordinary levels use the provider's default mapping; `xhigh` and `max` require explicit string mappings to be supported |
|
|
215
314
|
| string | Level is supported and this value is sent to the provider |
|
|
216
315
|
| `null` | Level is unsupported and hidden/skipped/clamped away |
|
|
217
316
|
|
|
@@ -305,7 +404,7 @@ Use `modelOverrides` to customize specific built-in models without replacing the
|
|
|
305
404
|
}
|
|
306
405
|
```
|
|
307
406
|
|
|
308
|
-
`modelOverrides` supports these fields per model: `name`, `reasoning`, `input`, `cost` (partial), `contextWindow`, `maxTokens`, `headers`, `compat`.
|
|
407
|
+
`modelOverrides` supports these fields per model: `name`, `reasoning`, `input`, `cost` (partial), `contextWindow`, `maxInputTokens`, `requestLimits`, `maxTokens`, `headers`, `compat`.
|
|
309
408
|
|
|
310
409
|
Behavior notes:
|
|
311
410
|
- `modelOverrides` are applied to built-in provider models.
|
package/docs/packages.md
CHANGED
|
@@ -38,6 +38,8 @@ scramjet update --extension npm:@foo/bar
|
|
|
38
38
|
|
|
39
39
|
By default, `install` and `remove` write to global settings (`~/.scramjet/agent/settings.json`). Use `-l` to write to project settings (`.scramjet/settings.json`) instead. Project settings can be shared with your team, and scramjet installs any missing packages automatically on startup.
|
|
40
40
|
|
|
41
|
+
For a globally package-manager-managed CLI, self-update resolves one current npm release, installs that exact package version with the owning package manager, and verifies the managed package metadata before reporting success. This verification does not inspect or repair duplicate installations selected through `PATH`.
|
|
42
|
+
|
|
41
43
|
To try a package without installing it, use `--extension` or `-e`. This installs to a temporary directory for the current run only:
|
|
42
44
|
|
|
43
45
|
```bash
|
package/docs/prompt-templates.md
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
Prompt templates are Markdown snippets that expand into full prompts. Type `/name` in the editor to invoke a template, where `name` is the filename without `.md`.
|
|
6
6
|
|
|
7
|
+
A template expansion is an ordinary user prompt, not a Scramjet command. It does not receive `<scramjet-command>` framing, command lifecycle association, declared next-step behavior, or a guarantee that the agent must execute it as an active command. Skills are on-demand capability packages rather than ordinary prompt expansions, but they likewise do not carry the Scramjet command guarantee. When template-derived information supports an active command, that command's explicit Goals (or inferred outcomes for a legacy command), user decisions, trust boundaries, consumer contracts, and required side effects remain controlling. See the [Scramjet command authoring guide](../../scramjet/docs/command-authoring.md) for the command contract.
|
|
8
|
+
|
|
7
9
|
## Locations
|
|
8
10
|
|
|
9
11
|
Scramjet loads prompt templates from:
|