agent-sh 0.12.26 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -2
- package/dist/agent/agent-loop.d.ts +3 -5
- package/dist/agent/agent-loop.js +44 -100
- package/dist/agent/conversation-state.d.ts +9 -0
- package/dist/agent/conversation-state.js +38 -1
- package/dist/agent/history-file.d.ts +6 -0
- package/dist/agent/history-file.js +1 -1
- package/dist/agent/host-types.d.ts +125 -0
- package/dist/agent/index.d.ts +12 -4
- package/dist/agent/index.js +357 -6
- package/dist/agent/nuclear-form.d.ts +7 -0
- package/dist/{extensions → agent}/providers/deepseek.d.ts +2 -2
- package/dist/{extensions → agent}/providers/deepseek.js +5 -4
- package/dist/{extensions → agent}/providers/openai-compatible.d.ts +2 -2
- package/dist/{extensions → agent}/providers/openai.d.ts +2 -2
- package/dist/{extensions → agent}/providers/openai.js +3 -2
- package/dist/{extensions → agent}/providers/openrouter.d.ts +2 -2
- package/dist/{extensions → agent}/providers/openrouter.js +4 -3
- package/dist/agent/skills.js +51 -7
- package/dist/agent/subagent.d.ts +1 -1
- package/dist/agent/system-prompt.js +14 -17
- package/dist/agent/tool-protocol.d.ts +1 -1
- package/dist/agent/tool-protocol.js +5 -3
- package/dist/agent/tool-registry.d.ts +9 -4
- package/dist/agent/tool-registry.js +27 -4
- package/dist/agent/tools/bash.d.ts +1 -1
- package/dist/agent/tools/bash.js +3 -2
- package/dist/agent/tools/edit-file.js +0 -1
- package/dist/agent/tools/glob.js +1 -1
- package/dist/agent/tools/grep.js +1 -1
- package/dist/agent/tools/pwsh.d.ts +1 -1
- package/dist/agent/tools/pwsh.js +1 -2
- package/dist/agent/tools/read-file.js +7 -4
- package/dist/agent/tools/write-file.js +0 -1
- package/dist/agent/types.d.ts +17 -2
- package/dist/cli/auth/cli.d.ts +1 -0
- package/dist/cli/auth/cli.js +216 -0
- package/dist/cli/auth/keys.d.ts +31 -0
- package/dist/cli/auth/keys.js +102 -0
- package/dist/{index.js → cli/index.js} +29 -32
- package/dist/{init.js → cli/init.js} +1 -1
- package/dist/{install.js → cli/install.js} +114 -5
- package/dist/cli/subcommands.d.ts +1 -0
- package/dist/cli/subcommands.js +17 -0
- package/dist/{event-bus.d.ts → core/event-bus.d.ts} +7 -13
- package/dist/{extension-loader.d.ts → core/extension-loader.d.ts} +1 -1
- package/dist/{extension-loader.js → core/extension-loader.js} +62 -70
- package/dist/{core.d.ts → core/index.d.ts} +18 -15
- package/dist/{core.js → core/index.js} +18 -92
- package/dist/{settings.d.ts → core/settings.d.ts} +7 -0
- package/dist/{settings.js → core/settings.js} +1 -0
- package/dist/core/types.d.ts +49 -0
- package/dist/core/types.js +1 -0
- package/dist/extensions/file-autocomplete.d.ts +1 -1
- package/dist/extensions/index.d.ts +7 -14
- package/dist/extensions/index.js +2 -19
- package/dist/extensions/slash-commands.d.ts +1 -1
- package/dist/extensions/slash-commands.js +7 -2
- package/dist/shell/host-types.d.ts +114 -0
- package/dist/shell/host-types.js +1 -0
- package/dist/shell/index.d.ts +8 -7
- package/dist/shell/index.js +58 -9
- package/dist/shell/input-handler.d.ts +7 -1
- package/dist/shell/input-handler.js +5 -2
- package/dist/shell/output-parser.d.ts +1 -1
- package/dist/{extensions → shell}/shell-context.d.ts +1 -1
- package/dist/{extensions → shell}/shell-context.js +18 -12
- package/dist/shell/shell.d.ts +6 -4
- package/dist/shell/shell.js +33 -109
- package/dist/shell/strategies/bash.d.ts +2 -0
- package/dist/shell/strategies/bash.js +68 -0
- package/dist/shell/strategies/fish.d.ts +2 -0
- package/dist/shell/strategies/fish.js +65 -0
- package/dist/shell/strategies/index.d.ts +13 -0
- package/dist/shell/strategies/index.js +17 -0
- package/dist/shell/strategies/types.d.ts +50 -0
- package/dist/shell/strategies/types.js +9 -0
- package/dist/shell/strategies/zsh.d.ts +2 -0
- package/dist/shell/strategies/zsh.js +72 -0
- package/dist/shell/tui-input-view.js +14 -3
- package/dist/{extensions → shell}/tui-renderer.d.ts +1 -1
- package/dist/{extensions → shell}/tui-renderer.js +27 -55
- package/dist/utils/box-frame.d.ts +4 -0
- package/dist/utils/box-frame.js +17 -6
- package/dist/utils/compositor.d.ts +1 -1
- package/dist/utils/compositor.js +2 -1
- package/dist/{executor.js → utils/executor.js} +1 -1
- package/dist/utils/floating-panel.d.ts +17 -5
- package/dist/utils/floating-panel.js +218 -70
- package/dist/utils/llm-facade.d.ts +7 -3
- package/dist/utils/stream-transform.d.ts +1 -1
- package/dist/utils/terminal-buffer.d.ts +1 -1
- package/dist/utils/tool-display.js +4 -0
- package/dist/utils/tool-interactive.d.ts +1 -1
- package/dist/utils/tty.d.ts +7 -0
- package/dist/utils/tty.js +15 -0
- package/examples/extensions/ash-acp-bridge/README.md +4 -1
- package/examples/extensions/ash-acp-bridge/src/index.ts +654 -0
- package/examples/extensions/ash-mcp-bridge/index.ts +1 -1
- package/examples/extensions/ashi/README.md +250 -0
- package/examples/extensions/ashi/package.json +60 -0
- package/examples/extensions/ashi/src/autocomplete.ts +91 -0
- package/examples/extensions/ashi/src/capture.ts +34 -0
- package/examples/extensions/ashi/src/cli.ts +126 -0
- package/examples/extensions/ashi/src/commands.ts +82 -0
- package/examples/extensions/ashi/src/compaction.ts +157 -0
- package/examples/extensions/ashi/src/components.ts +332 -0
- package/examples/extensions/ashi/src/default-renderers.ts +153 -0
- package/examples/extensions/ashi/src/display-config.ts +62 -0
- package/examples/extensions/ashi/src/frontend.ts +735 -0
- package/examples/extensions/ashi/src/hooks.ts +136 -0
- package/examples/extensions/ashi/src/multi-session-store.ts +146 -0
- package/examples/extensions/ashi/src/session-commands.ts +76 -0
- package/examples/extensions/ashi/src/session-store.ts +264 -0
- package/examples/extensions/ashi/src/status-footer.ts +66 -0
- package/examples/extensions/ashi/src/theme.ts +151 -0
- package/examples/extensions/ashi/tsconfig.json +14 -0
- package/examples/extensions/emacs-buffer.ts +364 -0
- package/examples/extensions/interactive-prompts.ts +114 -69
- package/examples/extensions/latex-images.ts +3 -3
- package/examples/extensions/opencode-bridge/index.ts +1 -1
- package/examples/extensions/overlay-agent.ts +35 -10
- package/examples/extensions/peer-mesh.ts +1 -1
- package/examples/extensions/pi-bridge/index.ts +0 -1
- package/examples/extensions/questionnaire.ts +2 -1
- package/examples/extensions/rtk-proxy.ts +3 -3
- package/examples/extensions/solarized-theme.ts +3 -3
- package/examples/extensions/subagents.ts +6 -6
- package/examples/extensions/terminal-buffer.ts +174 -33
- package/examples/extensions/tmux-pane.ts +6 -4
- package/examples/extensions/tunnel-vision.ts +405 -0
- package/examples/extensions/user-shell.ts +1 -1
- package/examples/extensions/web-access.ts +8 -113
- package/package.json +26 -22
- package/dist/extensions/agent-backend.d.ts +0 -14
- package/dist/extensions/agent-backend.js +0 -307
- package/dist/types.d.ts +0 -227
- /package/dist/{types.js → agent/host-types.js} +0 -0
- /package/dist/{extensions → agent}/providers/openai-compatible.js +0 -0
- /package/dist/{index.d.ts → cli/index.d.ts} +0 -0
- /package/dist/{init.d.ts → cli/init.d.ts} +0 -0
- /package/dist/{install.d.ts → cli/install.d.ts} +0 -0
- /package/dist/{event-bus.js → core/event-bus.js} +0 -0
- /package/dist/{executor.d.ts → utils/executor.d.ts} +0 -0
package/package.json
CHANGED
|
@@ -1,34 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-sh",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "A shell-first terminal where AI is one keystroke away",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"main": "dist/core.js",
|
|
7
|
-
"types": "dist/core.d.ts",
|
|
6
|
+
"main": "dist/core/index.js",
|
|
7
|
+
"types": "dist/core/index.d.ts",
|
|
8
8
|
"bin": {
|
|
9
|
-
"agent-sh": "dist/index.js"
|
|
9
|
+
"agent-sh": "dist/cli/index.js"
|
|
10
10
|
},
|
|
11
11
|
"exports": {
|
|
12
12
|
".": {
|
|
13
|
-
"types": "./dist/core.d.ts",
|
|
14
|
-
"default": "./dist/core.js"
|
|
13
|
+
"types": "./dist/core/index.d.ts",
|
|
14
|
+
"default": "./dist/core/index.js"
|
|
15
15
|
},
|
|
16
16
|
"./core": {
|
|
17
|
-
"types": "./dist/core.d.ts",
|
|
18
|
-
"default": "./dist/core.js"
|
|
17
|
+
"types": "./dist/core/index.d.ts",
|
|
18
|
+
"default": "./dist/core/index.js"
|
|
19
19
|
},
|
|
20
20
|
"./utils/*": "./dist/utils/*",
|
|
21
21
|
"./types": {
|
|
22
|
-
"types": "./dist/
|
|
23
|
-
"default": "./dist/
|
|
22
|
+
"types": "./dist/core/index.d.ts",
|
|
23
|
+
"default": "./dist/core/index.js"
|
|
24
24
|
},
|
|
25
25
|
"./settings": {
|
|
26
|
-
"types": "./dist/settings.d.ts",
|
|
27
|
-
"default": "./dist/settings.js"
|
|
26
|
+
"types": "./dist/core/settings.d.ts",
|
|
27
|
+
"default": "./dist/core/settings.js"
|
|
28
28
|
},
|
|
29
29
|
"./extension-loader": {
|
|
30
|
-
"types": "./dist/extension-loader.d.ts",
|
|
31
|
-
"default": "./dist/extension-loader.js"
|
|
30
|
+
"types": "./dist/core/extension-loader.d.ts",
|
|
31
|
+
"default": "./dist/core/extension-loader.js"
|
|
32
32
|
},
|
|
33
33
|
"./extensions": {
|
|
34
34
|
"types": "./dist/extensions/index.d.ts",
|
|
@@ -46,6 +46,10 @@
|
|
|
46
46
|
"types": "./dist/utils/terminal-buffer.d.ts",
|
|
47
47
|
"default": "./dist/utils/terminal-buffer.js"
|
|
48
48
|
},
|
|
49
|
+
"./agent": {
|
|
50
|
+
"types": "./dist/agent/index.d.ts",
|
|
51
|
+
"default": "./dist/agent/index.js"
|
|
52
|
+
},
|
|
49
53
|
"./agent/types": {
|
|
50
54
|
"types": "./dist/agent/types.d.ts",
|
|
51
55
|
"default": "./dist/agent/types.js"
|
|
@@ -59,8 +63,8 @@
|
|
|
59
63
|
"default": "./dist/agent/agent-loop.js"
|
|
60
64
|
},
|
|
61
65
|
"./event-bus": {
|
|
62
|
-
"types": "./dist/event-bus.d.ts",
|
|
63
|
-
"default": "./dist/event-bus.js"
|
|
66
|
+
"types": "./dist/core/event-bus.d.ts",
|
|
67
|
+
"default": "./dist/core/event-bus.js"
|
|
64
68
|
},
|
|
65
69
|
"./utils/compositor": {
|
|
66
70
|
"types": "./dist/utils/compositor.d.ts",
|
|
@@ -83,8 +87,8 @@
|
|
|
83
87
|
"default": "./dist/agent/nuclear-form.js"
|
|
84
88
|
},
|
|
85
89
|
"./executor": {
|
|
86
|
-
"types": "./dist/executor.d.ts",
|
|
87
|
-
"default": "./dist/executor.js"
|
|
90
|
+
"types": "./dist/utils/executor.d.ts",
|
|
91
|
+
"default": "./dist/utils/executor.js"
|
|
88
92
|
}
|
|
89
93
|
},
|
|
90
94
|
"files": [
|
|
@@ -93,15 +97,15 @@
|
|
|
93
97
|
"examples/extensions/*/package.json",
|
|
94
98
|
"examples/extensions/*/tsconfig.json",
|
|
95
99
|
"examples/extensions/*/README.md",
|
|
96
|
-
"examples/extensions/*/src",
|
|
100
|
+
"examples/extensions/*/src/**",
|
|
97
101
|
"examples/extensions/*/index.ts",
|
|
98
102
|
"examples/extensions/*/index.js"
|
|
99
103
|
],
|
|
100
104
|
"scripts": {
|
|
101
|
-
"dev": "tsx src/index.ts",
|
|
105
|
+
"dev": "tsx src/cli/index.ts",
|
|
102
106
|
"build": "tsc",
|
|
103
|
-
"start": "node dist/index.js",
|
|
104
|
-
"prepare": "npm run build"
|
|
107
|
+
"start": "node dist/cli/index.js",
|
|
108
|
+
"prepare": "test -d dist || npm run build"
|
|
105
109
|
},
|
|
106
110
|
"keywords": [
|
|
107
111
|
"terminal",
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Built-in agent backend extension.
|
|
3
|
-
*
|
|
4
|
-
* Constructs the AgentLoop synchronously with a placeholder LlmClient,
|
|
5
|
-
* so core handlers (history:append, system-prompt:build, conversation:*)
|
|
6
|
-
* are defined before user extensions activate. Mode resolution is
|
|
7
|
-
* deferred to `core:extensions-loaded`, giving runtime-registered
|
|
8
|
-
* providers (e.g. openrouter) a chance to register before we look up
|
|
9
|
-
* settings.defaultProvider. Without this deferral, a persisted
|
|
10
|
-
* `defaultProvider: "openrouter"` loses to a cold-start race and the
|
|
11
|
-
* backend bails silently.
|
|
12
|
-
*/
|
|
13
|
-
import type { ExtensionContext } from "../types.js";
|
|
14
|
-
export default function agentBackend(ctx: ExtensionContext): void;
|
|
@@ -1,307 +0,0 @@
|
|
|
1
|
-
import { AgentLoop } from "../agent/agent-loop.js";
|
|
2
|
-
import { LlmClient } from "../utils/llm-client.js";
|
|
3
|
-
import { resolveProvider, getProviderNames, getSettings } from "../settings.js";
|
|
4
|
-
import { PACKAGE_VERSION } from "../utils/package-version.js";
|
|
5
|
-
import { discoverSkills } from "../agent/skills.js";
|
|
6
|
-
/** Read the user's persisted defaultModel for a provider, if any. */
|
|
7
|
-
function persistedModelFor(providerName) {
|
|
8
|
-
if (!providerName)
|
|
9
|
-
return undefined;
|
|
10
|
-
return getSettings().providers?.[providerName]?.defaultModel;
|
|
11
|
-
}
|
|
12
|
-
function defaultReasoningBuilder(level) {
|
|
13
|
-
return level === "off" ? {} : { reasoning_effort: level };
|
|
14
|
-
}
|
|
15
|
-
function mergeCaps(settingsCaps, payloadCaps, modelIds) {
|
|
16
|
-
if (!settingsCaps)
|
|
17
|
-
return payloadCaps.size > 0 ? payloadCaps : undefined;
|
|
18
|
-
const out = new Map();
|
|
19
|
-
for (const id of modelIds) {
|
|
20
|
-
const s = settingsCaps.get(id);
|
|
21
|
-
const p = payloadCaps.get(id);
|
|
22
|
-
if (!s && !p)
|
|
23
|
-
continue;
|
|
24
|
-
out.set(id, {
|
|
25
|
-
reasoning: s?.reasoning ?? p?.reasoning,
|
|
26
|
-
contextWindow: s?.contextWindow ?? p?.contextWindow,
|
|
27
|
-
maxTokens: s?.maxTokens ?? p?.maxTokens,
|
|
28
|
-
echoReasoning: s?.echoReasoning ?? p?.echoReasoning,
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
return out.size > 0 ? out : undefined;
|
|
32
|
-
}
|
|
33
|
-
export default function agentBackend(ctx) {
|
|
34
|
-
const { bus } = ctx;
|
|
35
|
-
const config = ctx.call("config:get-shell-config") ?? {};
|
|
36
|
-
// Immutable settings snapshot; provider:register payloads merge against it.
|
|
37
|
-
const providerRegistry = new Map();
|
|
38
|
-
const settingsProviders = new Map();
|
|
39
|
-
for (const name of getProviderNames()) {
|
|
40
|
-
const p = resolveProvider(name);
|
|
41
|
-
if (p) {
|
|
42
|
-
providerRegistry.set(name, p);
|
|
43
|
-
settingsProviders.set(name, p);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
const providerHooks = new Map();
|
|
47
|
-
// Bakes model id into the hook so AgentMode.buildReasoningParams keeps
|
|
48
|
-
// its (level) signature while the hook can branch on model.
|
|
49
|
-
const bindReasoning = (shapeId, model) => {
|
|
50
|
-
const hook = providerHooks.get(shapeId)?.reasoningParams;
|
|
51
|
-
return hook ? (level) => hook(level, model) : defaultReasoningBuilder;
|
|
52
|
-
};
|
|
53
|
-
const buildModes = () => {
|
|
54
|
-
const allModes = [];
|
|
55
|
-
for (const [id, p] of providerRegistry) {
|
|
56
|
-
if (!p.apiKey)
|
|
57
|
-
continue;
|
|
58
|
-
const shapeId = p.reasoningShape ?? id;
|
|
59
|
-
for (const model of p.models) {
|
|
60
|
-
const mc = p.modelCapabilities?.get(model);
|
|
61
|
-
allModes.push({
|
|
62
|
-
model,
|
|
63
|
-
provider: id,
|
|
64
|
-
providerConfig: { apiKey: p.apiKey, baseURL: p.baseURL },
|
|
65
|
-
contextWindow: mc?.contextWindow ?? p.contextWindow,
|
|
66
|
-
maxTokens: mc?.maxTokens ?? (mc?.contextWindow ? Math.min(Math.floor(mc.contextWindow * 0.4), 65536) : undefined),
|
|
67
|
-
reasoning: mc?.reasoning,
|
|
68
|
-
supportsReasoningEffort: p.supportsReasoningEffort,
|
|
69
|
-
echoReasoning: mc?.echoReasoning,
|
|
70
|
-
buildReasoningParams: bindReasoning(shapeId, model),
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
return allModes;
|
|
75
|
-
};
|
|
76
|
-
// Placeholder client — reconfigured at core:extensions-loaded. Any
|
|
77
|
-
// stream() call before then fails from the OpenAI SDK; start() won't
|
|
78
|
-
// wire the loop until we've resolved, so users never hit that path.
|
|
79
|
-
const llmClient = new LlmClient({ apiKey: "not-configured", model: "not-configured" });
|
|
80
|
-
ctx.define("llm:get-client", () => llmClient);
|
|
81
|
-
ctx.define("llm:invoke", (messages, opts) => {
|
|
82
|
-
return llmClient.complete({
|
|
83
|
-
messages: messages,
|
|
84
|
-
max_tokens: opts?.maxTokens,
|
|
85
|
-
model: opts?.model,
|
|
86
|
-
reasoning_effort: opts?.reasoningEffort,
|
|
87
|
-
});
|
|
88
|
-
});
|
|
89
|
-
let modes = [];
|
|
90
|
-
let initialModeIndex = 0;
|
|
91
|
-
let resolved = false;
|
|
92
|
-
// Gates late-registration reconcile so its config:switch-model emit doesn't misroute under a non-ash backend.
|
|
93
|
-
let ashActive = false;
|
|
94
|
-
bus.onPipe("config:get-initial-modes", () => ({ modes, initialModeIndex }));
|
|
95
|
-
// AgentLoop must be constructed *before* user extensions activate,
|
|
96
|
-
// because its ctor defines handlers (history:append, etc.) that
|
|
97
|
-
// extensions like superash call synchronously during their own
|
|
98
|
-
// activate. Advise-before-define works for advisers, but plain calls
|
|
99
|
-
// would hit a no-op stub.
|
|
100
|
-
const agentLoop = new AgentLoop({
|
|
101
|
-
bus,
|
|
102
|
-
llmClient,
|
|
103
|
-
handlers: { define: ctx.define, advise: ctx.advise, call: ctx.call, list: ctx.list },
|
|
104
|
-
modes,
|
|
105
|
-
initialModeIndex,
|
|
106
|
-
compositor: ctx.compositor,
|
|
107
|
-
instanceId: ctx.instanceId,
|
|
108
|
-
history: config.history,
|
|
109
|
-
});
|
|
110
|
-
let loadedExtensionNames = [];
|
|
111
|
-
bus.on("core:extensions-loaded", ({ names }) => {
|
|
112
|
-
loadedExtensionNames = names;
|
|
113
|
-
const settings = getSettings();
|
|
114
|
-
// If the user didn't pick a default, fall back to the first registered
|
|
115
|
-
// provider (built-in load order biases to openrouter → openai).
|
|
116
|
-
const providerName = config.provider ?? settings.defaultProvider
|
|
117
|
-
?? (providerRegistry.size > 0 ? providerRegistry.keys().next().value : undefined);
|
|
118
|
-
const activeProvider = providerName ? providerRegistry.get(providerName) ?? null : null;
|
|
119
|
-
// User's persisted defaultModel wins over the provider's declared
|
|
120
|
-
// default. Dynamic providers (openrouter) re-register with their
|
|
121
|
-
// hardcoded DEFAULT_MODELS[0] each startup, which would otherwise
|
|
122
|
-
// clobber the user's /model selection.
|
|
123
|
-
const effectiveApiKey = config.apiKey ?? activeProvider?.apiKey;
|
|
124
|
-
const effectiveBaseURL = config.baseURL ?? activeProvider?.baseURL;
|
|
125
|
-
const effectiveModel = config.model ?? persistedModelFor(providerName) ?? activeProvider?.defaultModel;
|
|
126
|
-
// No provider → don't register ash at all, so another backend (e.g.
|
|
127
|
-
// claude-code-bridge) can own activation. index.ts hard-fails only
|
|
128
|
-
// when no backend ended up registered.
|
|
129
|
-
if (!effectiveApiKey || !effectiveModel)
|
|
130
|
-
return;
|
|
131
|
-
modes = buildModes();
|
|
132
|
-
if (modes.length === 0)
|
|
133
|
-
modes = [{ model: effectiveModel }];
|
|
134
|
-
let foundIdx = modes.findIndex((m) => m.model === effectiveModel && (!activeProvider || m.provider === activeProvider.id));
|
|
135
|
-
// Persisted default may not be in the provider's curated list yet (e.g.
|
|
136
|
-
// openrouter's async catalog fetch hasn't returned). Prepend a stub so
|
|
137
|
-
// the initial config:set-modes activeIndex points at the real model —
|
|
138
|
-
// otherwise AgentLoop reconfigures llmClient back to modes[0].
|
|
139
|
-
if (foundIdx === -1 && activeProvider) {
|
|
140
|
-
modes = [
|
|
141
|
-
{
|
|
142
|
-
model: effectiveModel,
|
|
143
|
-
provider: activeProvider.id,
|
|
144
|
-
providerConfig: { apiKey: effectiveApiKey, baseURL: effectiveBaseURL },
|
|
145
|
-
supportsReasoningEffort: activeProvider.supportsReasoningEffort,
|
|
146
|
-
},
|
|
147
|
-
...modes,
|
|
148
|
-
];
|
|
149
|
-
foundIdx = 0;
|
|
150
|
-
}
|
|
151
|
-
initialModeIndex = Math.max(0, foundIdx);
|
|
152
|
-
llmClient.reconfigure({ apiKey: effectiveApiKey, baseURL: effectiveBaseURL, model: effectiveModel });
|
|
153
|
-
bus.emit("config:set-modes", { modes, activeIndex: initialModeIndex });
|
|
154
|
-
resolved = true;
|
|
155
|
-
bus.emit("agent:register-backend", {
|
|
156
|
-
name: "ash",
|
|
157
|
-
kill: () => {
|
|
158
|
-
ashActive = false;
|
|
159
|
-
bus.emit("command:unregister", { name: "/compact" });
|
|
160
|
-
bus.emit("command:unregister", { name: "/context" });
|
|
161
|
-
agentLoop.kill();
|
|
162
|
-
},
|
|
163
|
-
start: async () => {
|
|
164
|
-
agentLoop.wire();
|
|
165
|
-
ashActive = true;
|
|
166
|
-
bus.emit("command:register", {
|
|
167
|
-
name: "/compact",
|
|
168
|
-
description: "Compact conversation via the active compaction strategy",
|
|
169
|
-
handler: () => bus.emit("agent:compact-request", {}),
|
|
170
|
-
});
|
|
171
|
-
bus.emit("command:register", {
|
|
172
|
-
name: "/context",
|
|
173
|
-
description: "Show context budget usage",
|
|
174
|
-
handler: () => {
|
|
175
|
-
const stats = bus.emitPipe("context:get-stats", {
|
|
176
|
-
activeTokens: 0,
|
|
177
|
-
totalTokens: 0,
|
|
178
|
-
budgetTokens: 0,
|
|
179
|
-
});
|
|
180
|
-
const pct = stats.budgetTokens > 0
|
|
181
|
-
? Math.round((stats.activeTokens / stats.budgetTokens) * 100)
|
|
182
|
-
: 0;
|
|
183
|
-
bus.emit("ui:info", {
|
|
184
|
-
message: `Active context: ~${stats.activeTokens.toLocaleString()} tokens / ${stats.budgetTokens.toLocaleString()} budget (${pct}%)`,
|
|
185
|
-
});
|
|
186
|
-
},
|
|
187
|
-
});
|
|
188
|
-
bus.emit("agent:info", {
|
|
189
|
-
name: "ash",
|
|
190
|
-
version: PACKAGE_VERSION,
|
|
191
|
-
model: llmClient.model,
|
|
192
|
-
provider: modes[initialModeIndex]?.provider,
|
|
193
|
-
contextWindow: modes[initialModeIndex]?.contextWindow,
|
|
194
|
-
});
|
|
195
|
-
},
|
|
196
|
-
});
|
|
197
|
-
});
|
|
198
|
-
bus.on("provider:configure", ({ id, reasoningParams }) => {
|
|
199
|
-
const prev = providerHooks.get(id) ?? {};
|
|
200
|
-
if (reasoningParams !== undefined)
|
|
201
|
-
prev.reasoningParams = reasoningParams;
|
|
202
|
-
providerHooks.set(id, prev);
|
|
203
|
-
});
|
|
204
|
-
bus.on("provider:register", (p) => {
|
|
205
|
-
const rawModels = p.models ?? (p.defaultModel ? [p.defaultModel] : []);
|
|
206
|
-
const payloadModelIds = [];
|
|
207
|
-
const payloadCaps = new Map();
|
|
208
|
-
for (const m of rawModels) {
|
|
209
|
-
if (typeof m === "string") {
|
|
210
|
-
payloadModelIds.push(m);
|
|
211
|
-
}
|
|
212
|
-
else {
|
|
213
|
-
payloadModelIds.push(m.id);
|
|
214
|
-
payloadCaps.set(m.id, { reasoning: m.reasoning, contextWindow: m.contextWindow, maxTokens: m.maxTokens, echoReasoning: m.echoReasoning });
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
const settings = settingsProviders.get(p.id);
|
|
218
|
-
const modelIds = settings?.modelsExplicit && settings.models.length > 0 ? settings.models : payloadModelIds;
|
|
219
|
-
const mergedCaps = mergeCaps(settings?.modelCapabilities, payloadCaps, modelIds);
|
|
220
|
-
const merged = {
|
|
221
|
-
id: p.id,
|
|
222
|
-
apiKey: settings?.apiKey ?? p.apiKey,
|
|
223
|
-
baseURL: settings?.baseURL ?? p.baseURL,
|
|
224
|
-
defaultModel: settings?.defaultModel ?? p.defaultModel,
|
|
225
|
-
models: modelIds,
|
|
226
|
-
modelsExplicit: settings?.modelsExplicit ?? false,
|
|
227
|
-
contextWindow: settings?.contextWindow,
|
|
228
|
-
supportsReasoningEffort: settings?.supportsReasoningEffort ?? p.supportsReasoningEffort,
|
|
229
|
-
modelCapabilities: mergedCaps,
|
|
230
|
-
reasoningShape: settings?.reasoningShape,
|
|
231
|
-
};
|
|
232
|
-
providerRegistry.set(p.id, merged);
|
|
233
|
-
const addModes = modelIds.map((m) => {
|
|
234
|
-
const mc = mergedCaps?.get(m);
|
|
235
|
-
return {
|
|
236
|
-
model: m,
|
|
237
|
-
provider: p.id,
|
|
238
|
-
providerConfig: { apiKey: merged.apiKey ?? "", baseURL: merged.baseURL },
|
|
239
|
-
contextWindow: mc?.contextWindow,
|
|
240
|
-
maxTokens: mc?.maxTokens,
|
|
241
|
-
reasoning: mc?.reasoning,
|
|
242
|
-
supportsReasoningEffort: merged.supportsReasoningEffort,
|
|
243
|
-
echoReasoning: mc?.echoReasoning,
|
|
244
|
-
buildReasoningParams: bindReasoning(p.id, m),
|
|
245
|
-
};
|
|
246
|
-
});
|
|
247
|
-
bus.emit("config:add-modes", { modes: addModes });
|
|
248
|
-
// Late-registration reconcile: if this completes the user's persisted
|
|
249
|
-
// default (openrouter's async fetch delivers the full catalog after
|
|
250
|
-
// we've already fallen back to mode 0), quietly switch to it.
|
|
251
|
-
if (!resolved || !ashActive)
|
|
252
|
-
return;
|
|
253
|
-
const pendingProvider = getSettings().defaultProvider;
|
|
254
|
-
if (pendingProvider !== p.id)
|
|
255
|
-
return;
|
|
256
|
-
const pendingModel = persistedModelFor(pendingProvider);
|
|
257
|
-
if (pendingModel && modelIds.includes(pendingModel) && llmClient.model !== pendingModel) {
|
|
258
|
-
bus.emit("config:switch-model", { model: pendingModel });
|
|
259
|
-
}
|
|
260
|
-
});
|
|
261
|
-
bus.on("config:switch-provider", ({ provider: name }) => {
|
|
262
|
-
const p = providerRegistry.get(name);
|
|
263
|
-
if (!p) {
|
|
264
|
-
bus.emit("ui:error", { message: `Unknown provider: ${name}` });
|
|
265
|
-
return;
|
|
266
|
-
}
|
|
267
|
-
if (!p.apiKey) {
|
|
268
|
-
bus.emit("ui:error", { message: `Provider "${name}" has no API key configured` });
|
|
269
|
-
return;
|
|
270
|
-
}
|
|
271
|
-
const switchModel = p.defaultModel ?? p.models[0];
|
|
272
|
-
if (!switchModel) {
|
|
273
|
-
bus.emit("ui:error", { message: `Provider "${name}" has no models configured` });
|
|
274
|
-
return;
|
|
275
|
-
}
|
|
276
|
-
llmClient.reconfigure({ apiKey: p.apiKey, baseURL: p.baseURL, model: switchModel });
|
|
277
|
-
const newModes = p.models.map((m) => {
|
|
278
|
-
const mc = p.modelCapabilities?.get(m);
|
|
279
|
-
return {
|
|
280
|
-
model: m,
|
|
281
|
-
provider: name,
|
|
282
|
-
providerConfig: { apiKey: p.apiKey, baseURL: p.baseURL },
|
|
283
|
-
contextWindow: mc?.contextWindow ?? p.contextWindow,
|
|
284
|
-
maxTokens: mc?.maxTokens ?? (mc?.contextWindow ? Math.min(Math.floor(mc.contextWindow * 0.4), 65536) : undefined),
|
|
285
|
-
reasoning: mc?.reasoning,
|
|
286
|
-
supportsReasoningEffort: p.supportsReasoningEffort,
|
|
287
|
-
echoReasoning: mc?.echoReasoning,
|
|
288
|
-
};
|
|
289
|
-
});
|
|
290
|
-
bus.emit("config:set-modes", { modes: newModes });
|
|
291
|
-
bus.emit("agent:info", { name: "ash", version: PACKAGE_VERSION, model: switchModel, provider: name, contextWindow: p.contextWindow });
|
|
292
|
-
bus.emit("ui:info", { message: `Switched to ${name} (${switchModel})` });
|
|
293
|
-
bus.emit("config:changed", {});
|
|
294
|
-
});
|
|
295
|
-
bus.onPipe("banner:collect", (e) => {
|
|
296
|
-
if (e.activeBackend && e.activeBackend !== "ash")
|
|
297
|
-
return e;
|
|
298
|
-
if (loadedExtensionNames.length > 0) {
|
|
299
|
-
e.sections.push({ label: "Extensions", items: [...loadedExtensionNames] });
|
|
300
|
-
}
|
|
301
|
-
const skills = discoverSkills(ctx.call("cwd") ?? process.cwd());
|
|
302
|
-
if (skills.length > 0) {
|
|
303
|
-
e.sections.push({ label: "Skills", items: skills.map((s) => s.name) });
|
|
304
|
-
}
|
|
305
|
-
return e;
|
|
306
|
-
});
|
|
307
|
-
}
|
package/dist/types.d.ts
DELETED
|
@@ -1,227 +0,0 @@
|
|
|
1
|
-
import type { EventBus } from "./event-bus.js";
|
|
2
|
-
import type { ColorPalette } from "./utils/palette.js";
|
|
3
|
-
import type { BlockTransformOptions, FencedBlockTransformOptions } from "./utils/stream-transform.js";
|
|
4
|
-
import type { ToolDefinition } from "./agent/types.js";
|
|
5
|
-
import type { Compositor } from "./utils/compositor.js";
|
|
6
|
-
import type { HistoryAdapter } from "./agent/history-file.js";
|
|
7
|
-
export type { ContentBlock } from "./event-bus.js";
|
|
8
|
-
export type { BlockTransformOptions, FencedBlockTransformOptions } from "./utils/stream-transform.js";
|
|
9
|
-
export type { RenderSurface } from "./utils/compositor.js";
|
|
10
|
-
export interface RemoteSessionOptions {
|
|
11
|
-
/** The surface to render agent output to. */
|
|
12
|
-
surface: import("./utils/compositor.js").RenderSurface;
|
|
13
|
-
/** Suppress response borders (default: true). */
|
|
14
|
-
suppressBorders?: boolean;
|
|
15
|
-
/** Suppress user query box (default: false).
|
|
16
|
-
* True for sessions with their own input (rsplit, overlay).
|
|
17
|
-
* False for sessions where input comes from the main shell (split). */
|
|
18
|
-
suppressQueryBox?: boolean;
|
|
19
|
-
/** Suppress usage stats line (default: true). */
|
|
20
|
-
suppressUsage?: boolean;
|
|
21
|
-
}
|
|
22
|
-
export interface RemoteSession {
|
|
23
|
-
/** Submit a query to the agent from this session. */
|
|
24
|
-
submit(query: string): void;
|
|
25
|
-
/** The surface this session renders to. */
|
|
26
|
-
readonly surface: import("./utils/compositor.js").RenderSurface;
|
|
27
|
-
/** Whether this session is currently active. */
|
|
28
|
-
readonly active: boolean;
|
|
29
|
-
/** Tear down — restores all routing and advisors. */
|
|
30
|
-
close(): void;
|
|
31
|
-
}
|
|
32
|
-
/** A model entry in the cycling list, optionally tied to a provider. */
|
|
33
|
-
export interface AgentMode {
|
|
34
|
-
model: string;
|
|
35
|
-
/** Provider id — when cycling changes provider, LlmClient is reconfigured. */
|
|
36
|
-
provider?: string;
|
|
37
|
-
/** Provider-specific config for reconfiguring LlmClient on switch. */
|
|
38
|
-
providerConfig?: {
|
|
39
|
-
apiKey: string;
|
|
40
|
-
baseURL?: string;
|
|
41
|
-
};
|
|
42
|
-
/** Context window size in tokens (for usage display). */
|
|
43
|
-
contextWindow?: number;
|
|
44
|
-
/** Max output tokens for this mode. */
|
|
45
|
-
maxTokens?: number;
|
|
46
|
-
/** Model supports reasoning/thinking tokens. */
|
|
47
|
-
reasoning?: boolean;
|
|
48
|
-
/** Provider supports the reasoning_effort parameter. */
|
|
49
|
-
supportsReasoningEffort?: boolean;
|
|
50
|
-
/** Echo reasoning_content back on assistant turns. Required by DeepSeek;
|
|
51
|
-
* default off (leaky shims may forward it to the model as OOD input). */
|
|
52
|
-
echoReasoning?: boolean;
|
|
53
|
-
buildReasoningParams?: (level: string) => Record<string, unknown>;
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Backend-agnostic LLM interface exposed via `ctx.llm`. Backends fulfill it
|
|
57
|
-
* by defining an `llm:invoke` handler; those without an LLM leave
|
|
58
|
-
* `available` false and calls reject.
|
|
59
|
-
*/
|
|
60
|
-
export interface LlmMessage {
|
|
61
|
-
role: "system" | "user" | "assistant";
|
|
62
|
-
content: string;
|
|
63
|
-
}
|
|
64
|
-
export interface LlmSession {
|
|
65
|
-
send(message: string): Promise<string>;
|
|
66
|
-
history(): ReadonlyArray<LlmMessage>;
|
|
67
|
-
}
|
|
68
|
-
export interface LlmInterface {
|
|
69
|
-
readonly available: boolean;
|
|
70
|
-
/** `model` overrides the globally-configured model for this call only.
|
|
71
|
-
* Provider-specific identifier (e.g. "claude-haiku-4-5"). When omitted,
|
|
72
|
-
* the active provider's configured default is used.
|
|
73
|
-
*
|
|
74
|
-
* `reasoningEffort` controls thinking-model token allocation between
|
|
75
|
-
* reasoning and final content (e.g. "low", "medium", "high", or
|
|
76
|
-
* provider-specific). For non-reasoning models it is ignored. Set to
|
|
77
|
-
* "low" for cheap structured-output calls so reasoning doesn't exhaust
|
|
78
|
-
* the max-tokens budget and leave content empty. */
|
|
79
|
-
ask(opts: {
|
|
80
|
-
query: string;
|
|
81
|
-
system?: string;
|
|
82
|
-
maxTokens?: number;
|
|
83
|
-
model?: string;
|
|
84
|
-
reasoningEffort?: string;
|
|
85
|
-
}): Promise<string>;
|
|
86
|
-
session(opts?: {
|
|
87
|
-
system?: string;
|
|
88
|
-
maxTokens?: number;
|
|
89
|
-
model?: string;
|
|
90
|
-
reasoningEffort?: string;
|
|
91
|
-
}): LlmSession;
|
|
92
|
-
}
|
|
93
|
-
export interface AgentShellConfig {
|
|
94
|
-
shell?: string;
|
|
95
|
-
model?: string;
|
|
96
|
-
extensions?: string[];
|
|
97
|
-
/** API key for OpenAI-compatible provider. */
|
|
98
|
-
apiKey?: string;
|
|
99
|
-
/** Base URL for OpenAI-compatible API. */
|
|
100
|
-
baseURL?: string;
|
|
101
|
-
/** Named provider to use from settings.json. */
|
|
102
|
-
provider?: string;
|
|
103
|
-
/** Override settings.defaultBackend for this session only (does not persist). */
|
|
104
|
-
backend?: string;
|
|
105
|
-
/** Conversation history backend. Defaults to the on-disk HistoryFile. */
|
|
106
|
-
history?: HistoryAdapter;
|
|
107
|
-
}
|
|
108
|
-
/**
|
|
109
|
-
* Context passed to user/third-party extensions.
|
|
110
|
-
* Extensions interact with the system through the event bus — no direct
|
|
111
|
-
* frontend (Shell/TUI) dependencies. This enables headless, web, or
|
|
112
|
-
* alternative frontends without changing extensions.
|
|
113
|
-
*/
|
|
114
|
-
export interface ExtensionContext {
|
|
115
|
-
bus: EventBus;
|
|
116
|
-
/** Stable per-instance identifier (4-char hex). */
|
|
117
|
-
readonly instanceId: string;
|
|
118
|
-
quit: () => void;
|
|
119
|
-
/** Override color palette slots for theming. */
|
|
120
|
-
setPalette: (overrides: Partial<ColorPalette>) => void;
|
|
121
|
-
/** Register a delimiter-based content transform (e.g. $$...$$ → image). */
|
|
122
|
-
createBlockTransform: (opts: BlockTransformOptions) => void;
|
|
123
|
-
/** Register a fenced block transform (e.g. ```lang...``` → code-block). */
|
|
124
|
-
createFencedBlockTransform: (opts: FencedBlockTransformOptions) => void;
|
|
125
|
-
/** Read extension-namespaced settings from ~/.agent-sh/settings.json. */
|
|
126
|
-
getExtensionSettings: <T extends Record<string, unknown>>(namespace: string, defaults: T) => T;
|
|
127
|
-
/**
|
|
128
|
-
* Get (and lazily create) a per-extension storage directory under
|
|
129
|
-
* ~/.agent-sh/<namespace>/. Returns the absolute path. Lets extensions
|
|
130
|
-
* persist state without each one re-deriving the location.
|
|
131
|
-
*/
|
|
132
|
-
getStoragePath: (namespace: string) => string;
|
|
133
|
-
/** Register a slash command available in any input mode. */
|
|
134
|
-
registerCommand: (name: string, description: string, handler: (args: string) => Promise<void> | void) => void;
|
|
135
|
-
/** Register a tool for the built-in agent. No-op when using bridge backends. */
|
|
136
|
-
registerTool: (tool: ToolDefinition) => void;
|
|
137
|
-
/** Unregister a tool by name. */
|
|
138
|
-
unregisterTool: (name: string) => void;
|
|
139
|
-
/** Get all registered tools (for subagent tool subsets). Returns [] when using bridge backends. */
|
|
140
|
-
getTools: () => ToolDefinition[];
|
|
141
|
-
/** Register a named instruction block for the agent's system prompt. */
|
|
142
|
-
registerInstruction: (name: string, text: string) => void;
|
|
143
|
-
/** Remove a named instruction block from the system prompt. */
|
|
144
|
-
removeInstruction: (name: string) => void;
|
|
145
|
-
/** Register a skill (on-demand reference material) for the agent. */
|
|
146
|
-
registerSkill: (name: string, description: string, filePath: string) => void;
|
|
147
|
-
/** Remove a registered skill by name. */
|
|
148
|
-
removeSkill: (name: string) => void;
|
|
149
|
-
/**
|
|
150
|
-
* Register a context producer — a function that contributes a string
|
|
151
|
-
* (or `null` to skip) into one of two lifecycles:
|
|
152
|
-
*
|
|
153
|
-
* - `mode: "per-request"` (default) — fires on **every LLM request**,
|
|
154
|
-
* including each tool-loop iteration. Output is ephemerally wrapped
|
|
155
|
-
* in `<dynamic_context>` onto the trailing message at request time;
|
|
156
|
-
* never persisted. Use for "current state" signals (in-flight work,
|
|
157
|
-
* active mode, threshold warnings).
|
|
158
|
-
*
|
|
159
|
-
* - `mode: "per-query"` — fires **once at user-query start** in
|
|
160
|
-
* handleQuery. Output is wrapped in `<query_context>` and frozen into
|
|
161
|
-
* the user message; persists in conversation history. Use for
|
|
162
|
-
* "what happened between turns" signals (shell events, accumulated
|
|
163
|
-
* notifications, calendar/inbox deltas).
|
|
164
|
-
*
|
|
165
|
-
* In both modes producers run in registration order, non-null outputs
|
|
166
|
-
* joined with blank lines. When nothing contributes, no envelope tag
|
|
167
|
-
* is emitted.
|
|
168
|
-
*
|
|
169
|
-
* Returns a dispose fn that unregisters the producer.
|
|
170
|
-
*/
|
|
171
|
-
registerContextProducer: (name: string, producer: () => string | null, opts?: {
|
|
172
|
-
mode?: "per-request" | "per-query";
|
|
173
|
-
}) => () => void;
|
|
174
|
-
providers: {
|
|
175
|
-
configure: (id: string, opts: {
|
|
176
|
-
reasoningParams?: (level: string, model?: string) => Record<string, unknown>;
|
|
177
|
-
}) => void;
|
|
178
|
-
};
|
|
179
|
-
llm: LlmInterface;
|
|
180
|
-
/** Register a named handler. */
|
|
181
|
-
define: (name: string, fn: (...args: any[]) => any) => void;
|
|
182
|
-
/** Wrap a named handler. Receives `next` (original) + args. Returns an unadvise function. */
|
|
183
|
-
advise: (name: string, wrapper: (next: (...args: any[]) => any, ...args: any[]) => any) => () => void;
|
|
184
|
-
/** Call a named handler. */
|
|
185
|
-
call: (name: string, ...args: any[]) => any;
|
|
186
|
-
/** Names of all registered handlers — for diagnostic / introspection use. */
|
|
187
|
-
list: () => string[];
|
|
188
|
-
/**
|
|
189
|
-
* Routes named render streams ("agent", "query", "status") to surfaces.
|
|
190
|
-
* Extensions use `compositor.redirect()` to capture output (e.g. overlay panels).
|
|
191
|
-
*/
|
|
192
|
-
compositor: Compositor;
|
|
193
|
-
/** Teardown callback fired on /reload. For resources the scoped context
|
|
194
|
-
* can't track: process listeners, timers, watchers, sockets. */
|
|
195
|
-
onDispose: (fn: () => void) => void;
|
|
196
|
-
/**
|
|
197
|
-
* Create a remote session that routes agent output to a surface and
|
|
198
|
-
* optionally accepts queries. Handles all compositor routing, shell
|
|
199
|
-
* lifecycle advisors, and chrome suppression.
|
|
200
|
-
*
|
|
201
|
-
* const session = ctx.createRemoteSession({ surface });
|
|
202
|
-
* session.submit("what's on screen?");
|
|
203
|
-
* session.close(); // restores everything
|
|
204
|
-
*/
|
|
205
|
-
createRemoteSession: (opts: RemoteSessionOptions) => RemoteSession;
|
|
206
|
-
}
|
|
207
|
-
/**
|
|
208
|
-
* Configuration for a registered input mode.
|
|
209
|
-
* Extensions emit "input-mode:register" with this shape to add new modes.
|
|
210
|
-
*/
|
|
211
|
-
export interface InputModeConfig {
|
|
212
|
-
id: string;
|
|
213
|
-
trigger: string;
|
|
214
|
-
label: string;
|
|
215
|
-
promptIcon: string;
|
|
216
|
-
indicator: string;
|
|
217
|
-
onSubmit(query: string, bus: EventBus): void;
|
|
218
|
-
returnToSelf: boolean;
|
|
219
|
-
}
|
|
220
|
-
export interface TerminalSession {
|
|
221
|
-
id: string;
|
|
222
|
-
command: string;
|
|
223
|
-
output: string;
|
|
224
|
-
exitCode: number | null;
|
|
225
|
-
done: boolean;
|
|
226
|
-
resolve?: (value: void) => void;
|
|
227
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|