@intent-systems/nexus 2026.1.5-4 → 2026.1.5-5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/agent-id.js +41 -0
- package/dist/agents/auth-profiles.js +114 -25
- package/dist/agents/identity-state.js +79 -0
- package/dist/agents/model-auth.js +1 -0
- package/dist/agents/model-fallback.js +15 -9
- package/dist/agents/model-selection.js +1 -1
- package/dist/agents/models-config.js +17 -11
- package/dist/agents/pi-embedded-runner.js +101 -9
- package/dist/agents/sandbox.js +12 -3
- package/dist/agents/skill-runner.js +29 -4
- package/dist/agents/skill-usage.js +114 -11
- package/dist/agents/skills-status.js +4 -4
- package/dist/agents/skills.js +18 -7
- package/dist/agents/subagent-registry.js +25 -11
- package/dist/agents/system-prompt.js +16 -0
- package/dist/agents/tool-policy.js +19 -3
- package/dist/agents/tools/browser-tool.js +5 -2
- package/dist/agents/tools/image-tool.js +93 -8
- package/dist/agents/tools/sessions-announce-target.js +5 -1
- package/dist/agents/workspace.js +55 -46
- package/dist/auto-reply/command-detection.js +2 -1
- package/dist/auto-reply/reply/directive-handling.js +153 -28
- package/dist/auto-reply/reply/directives.js +17 -2
- package/dist/auto-reply/reply/model-selection.js +8 -3
- package/dist/auto-reply/reply/queue.js +2 -2
- package/dist/auto-reply/reply.js +1 -1
- package/dist/auto-reply/thinking.js +15 -0
- package/dist/browser/chrome.js +1 -1
- package/dist/browser/client.js +2 -0
- package/dist/browser/config.js +6 -2
- package/dist/browser/pw-tools-core.js +3 -0
- package/dist/browser/routes/agent.js +14 -0
- package/dist/canvas-host/server.js +1 -1
- package/dist/capabilities/detector.js +46 -15
- package/dist/capabilities/registry.js +2 -1
- package/dist/cli/cloud-cli.js +12 -7
- package/dist/cli/credential-cli.js +139 -17
- package/dist/cli/gateway-cli.js +1 -1
- package/dist/cli/log-cli.js +25 -0
- package/dist/cli/pairing-cli.js +1 -1
- package/dist/cli/program.js +58 -6
- package/dist/cli/run-main.js +1 -1
- package/dist/cli/skills-cli.js +144 -21
- package/dist/cli/skills-hub-cli.js +59 -29
- package/dist/cli/tool-connector-cli.js +99 -24
- package/dist/cli/upstream-sync-cli.js +253 -96
- package/dist/cli/usage-cli.js +14 -0
- package/dist/commands/auth-choice-options.js +6 -1
- package/dist/commands/auth-choice.js +157 -5
- package/dist/commands/bootstrap-preset.js +10 -6
- package/dist/commands/capabilities.js +33 -6
- package/dist/commands/claude-md.js +3 -2
- package/dist/commands/config-view.js +1 -1
- package/dist/commands/configure.js +4 -4
- package/dist/commands/credential.js +497 -36
- package/dist/commands/cursor-rules.js +39 -19
- package/dist/commands/doctor.js +5 -4
- package/dist/commands/identity.js +28 -31
- package/dist/commands/init.js +15 -18
- package/dist/commands/log.js +134 -0
- package/dist/commands/models/fallbacks.js +1 -1
- package/dist/commands/models/image-fallbacks.js +1 -1
- package/dist/commands/models/list.js +1 -1
- package/dist/commands/models/scan.js +1 -1
- package/dist/commands/onboard-auth.js +27 -2
- package/dist/commands/onboard-eve-identity.js +7 -8
- package/dist/commands/onboard-non-interactive.js +4 -2
- package/dist/commands/onboard-quickstart.js +18 -11
- package/dist/commands/quest-state.js +271 -0
- package/dist/commands/quest.js +53 -13
- package/dist/commands/reset.js +1 -1
- package/dist/commands/sessions-ingest.js +5 -4
- package/dist/commands/setup.js +4 -2
- package/dist/commands/skills-manifest.js +2 -2
- package/dist/commands/status.js +179 -61
- package/dist/commands/suggestions.js +1 -1
- package/dist/commands/usage-tracking.js +32 -0
- package/dist/commands/usage-upload.js +6 -1
- package/dist/config/defaults.js +1 -3
- package/dist/config/includes.js +5 -7
- package/dist/config/io.js +88 -16
- package/dist/config/legacy.js +4 -2
- package/dist/config/paths.js +16 -0
- package/dist/config/sessions.js +9 -5
- package/dist/config/zod-schema.js +4 -3
- package/dist/control-plane/broker/broker.js +131 -78
- package/dist/control-plane/compaction.js +3 -5
- package/dist/control-plane/factory.js +2 -2
- package/dist/control-plane/index.js +2 -2
- package/dist/control-plane/odu/agents.js +28 -23
- package/dist/control-plane/odu/interaction-tools.js +62 -50
- package/dist/control-plane/odu/prompt-loader.js +8 -8
- package/dist/control-plane/odu/runtime.js +87 -75
- package/dist/control-plane/odu-control-plane.js +14 -12
- package/dist/control-plane/single-agent.js +13 -13
- package/dist/credentials/store.js +133 -7
- package/dist/gateway/server-browser.js +5 -4
- package/dist/gateway/server-methods/cron.js +11 -1
- package/dist/gateway/server.js +14 -7
- package/dist/infra/bonjour.js +1 -1
- package/dist/infra/event-log.js +8 -2
- package/dist/infra/path-env.js +1 -2
- package/dist/infra/provider-usage.auth.js +5 -3
- package/dist/infra/provider-usage.fetch.claude.js +16 -6
- package/dist/infra/provider-usage.fetch.minimax.js +8 -3
- package/dist/infra/provider-usage.js +9 -5
- package/dist/infra/restart.js +2 -2
- package/dist/infra/usage-settings.js +78 -0
- package/dist/infra/usage-suggestions.js +17 -5
- package/dist/infra/usage-upload.js +38 -1
- package/dist/infra/voicewake.js +2 -2
- package/dist/media/image-ops.js +3 -1
- package/dist/memory/index.js +2 -381
- package/dist/pairing/pairing-store.js +24 -0
- package/dist/providers/github-copilot-auth.js +1 -1
- package/dist/routing/resolve-route.js +6 -6
- package/dist/routing/session-key.js +3 -1
- package/dist/sessions/send-policy.js +5 -5
- package/dist/slack/monitor.js +22 -1
- package/dist/telegram/reaction-level.js +2 -1
- package/dist/utils.js +4 -3
- package/dist/wizard/onboarding.js +29 -7
- package/package.json +1 -1
|
@@ -1,18 +1,92 @@
|
|
|
1
1
|
import { complete, } from "@mariozechner/pi-ai";
|
|
2
2
|
import { discoverAuthStorage, discoverModels, } from "@mariozechner/pi-coding-agent";
|
|
3
3
|
import { Type } from "@sinclair/typebox";
|
|
4
|
+
import { listCredentialEntriesSync } from "../../credentials/store.js";
|
|
4
5
|
import { resolveUserPath } from "../../utils.js";
|
|
5
6
|
import { loadWebMedia } from "../../web/media.js";
|
|
6
|
-
import {
|
|
7
|
+
import { DEFAULT_PROVIDER } from "../defaults.js";
|
|
8
|
+
import { getApiKeyForModel, getCustomProviderApiKey, resolveEnvApiKey, } from "../model-auth.js";
|
|
7
9
|
import { runWithImageModelFallback } from "../model-fallback.js";
|
|
10
|
+
import { normalizeProviderId, parseModelRef } from "../model-selection.js";
|
|
8
11
|
import { ensureNexusModelsJson } from "../models-config.js";
|
|
9
12
|
import { extractAssistantText } from "../pi-embedded-utils.js";
|
|
10
13
|
const DEFAULT_PROMPT = "Describe the image.";
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
const DEFAULT_IMAGE_MODELS = {
|
|
15
|
+
minimax: "minimax-vl-01",
|
|
16
|
+
openai: "gpt-5-mini",
|
|
17
|
+
anthropic: "claude-opus-4-5",
|
|
18
|
+
};
|
|
19
|
+
function normalizeImageModelConfig(value) {
|
|
20
|
+
if (typeof value === "string") {
|
|
21
|
+
const primary = value.trim();
|
|
22
|
+
return primary ? { primary } : null;
|
|
23
|
+
}
|
|
24
|
+
if (!value || typeof value !== "object")
|
|
25
|
+
return null;
|
|
26
|
+
const primary = typeof value.primary === "string" ? value.primary.trim() : "";
|
|
27
|
+
const fallbacks = Array.isArray(value.fallbacks)
|
|
28
|
+
? value.fallbacks.map((raw) => String(raw ?? "").trim()).filter(Boolean)
|
|
29
|
+
: [];
|
|
30
|
+
if (!primary && fallbacks.length === 0)
|
|
31
|
+
return null;
|
|
32
|
+
return fallbacks.length > 0 ? { primary, fallbacks } : { primary };
|
|
33
|
+
}
|
|
34
|
+
function hasAuthForProvider(provider, cfg) {
|
|
35
|
+
const normalized = normalizeProviderId(provider);
|
|
36
|
+
if (resolveEnvApiKey(normalized))
|
|
37
|
+
return true;
|
|
38
|
+
if (getCustomProviderApiKey(cfg, normalized))
|
|
39
|
+
return true;
|
|
40
|
+
const entries = listCredentialEntriesSync();
|
|
41
|
+
return entries.some((entry) => normalizeProviderId(entry.service) === normalized);
|
|
42
|
+
}
|
|
43
|
+
function resolveImageModelFromConfig(cfg, provider) {
|
|
44
|
+
const providers = cfg?.models?.providers ?? {};
|
|
45
|
+
const entry = providers[provider];
|
|
46
|
+
for (const model of entry?.models ?? []) {
|
|
47
|
+
if (!model?.id)
|
|
48
|
+
continue;
|
|
49
|
+
if (Array.isArray(model.input) && model.input.includes("image")) {
|
|
50
|
+
return model.id;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
export function resolveImageModelConfigForTool(params) {
|
|
56
|
+
void params.agentDir;
|
|
57
|
+
const explicit = normalizeImageModelConfig(params.cfg?.agent?.imageModel);
|
|
58
|
+
if (explicit)
|
|
59
|
+
return explicit;
|
|
60
|
+
const rawPrimary = typeof params.cfg?.agent?.model === "string"
|
|
61
|
+
? params.cfg?.agent?.model
|
|
62
|
+
: params.cfg?.agent?.model?.primary;
|
|
63
|
+
if (!rawPrimary?.trim())
|
|
64
|
+
return null;
|
|
65
|
+
const parsed = parseModelRef(rawPrimary, DEFAULT_PROVIDER);
|
|
66
|
+
if (!parsed)
|
|
67
|
+
return null;
|
|
68
|
+
const provider = normalizeProviderId(parsed.provider);
|
|
69
|
+
const configImageModel = resolveImageModelFromConfig(params.cfg, provider);
|
|
70
|
+
const mapped = DEFAULT_IMAGE_MODELS[provider];
|
|
71
|
+
const primaryModelId = configImageModel ?? mapped;
|
|
72
|
+
if (!primaryModelId)
|
|
73
|
+
return null;
|
|
74
|
+
if (!hasAuthForProvider(provider, params.cfg))
|
|
75
|
+
return null;
|
|
76
|
+
const fallbacks = [];
|
|
77
|
+
for (const fallbackProvider of ["openai", "anthropic"]) {
|
|
78
|
+
if (fallbackProvider === provider)
|
|
79
|
+
continue;
|
|
80
|
+
const fallbackModelId = DEFAULT_IMAGE_MODELS[fallbackProvider];
|
|
81
|
+
if (!fallbackModelId)
|
|
82
|
+
continue;
|
|
83
|
+
if (hasAuthForProvider(fallbackProvider, params.cfg)) {
|
|
84
|
+
fallbacks.push(`${fallbackProvider}/${fallbackModelId}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return fallbacks.length > 0
|
|
88
|
+
? { primary: `${provider}/${primaryModelId}`, fallbacks }
|
|
89
|
+
: { primary: `${provider}/${primaryModelId}` };
|
|
16
90
|
}
|
|
17
91
|
function pickMaxBytes(cfg, maxBytesMb) {
|
|
18
92
|
if (typeof maxBytesMb === "number" &&
|
|
@@ -80,12 +154,23 @@ async function runImagePrompt(params) {
|
|
|
80
154
|
};
|
|
81
155
|
}
|
|
82
156
|
export function createImageTool(options) {
|
|
83
|
-
|
|
157
|
+
const resolvedConfig = resolveImageModelConfigForTool({
|
|
158
|
+
cfg: options?.config,
|
|
159
|
+
agentDir: options?.agentDir,
|
|
160
|
+
});
|
|
161
|
+
if (!resolvedConfig)
|
|
84
162
|
return null;
|
|
85
163
|
const agentDir = options?.agentDir;
|
|
86
164
|
if (!agentDir?.trim()) {
|
|
87
165
|
throw new Error("createImageTool requires agentDir when enabled");
|
|
88
166
|
}
|
|
167
|
+
const cfgWithImageModel = (() => {
|
|
168
|
+
const cfg = options?.config ?? {};
|
|
169
|
+
const agent = cfg.agent ?? {};
|
|
170
|
+
if (normalizeImageModelConfig(agent.imageModel))
|
|
171
|
+
return cfg;
|
|
172
|
+
return { ...cfg, agent: { ...agent, imageModel: resolvedConfig } };
|
|
173
|
+
})();
|
|
89
174
|
return {
|
|
90
175
|
label: "Image",
|
|
91
176
|
name: "image",
|
|
@@ -121,7 +206,7 @@ export function createImageTool(options) {
|
|
|
121
206
|
const mimeType = media.contentType ?? "image/png";
|
|
122
207
|
const base64 = media.buffer.toString("base64");
|
|
123
208
|
const result = await runImagePrompt({
|
|
124
|
-
cfg:
|
|
209
|
+
cfg: cfgWithImageModel,
|
|
125
210
|
agentDir,
|
|
126
211
|
modelOverride,
|
|
127
212
|
prompt: promptRaw,
|
|
@@ -20,7 +20,11 @@ export async function resolveAnnounceTarget(params) {
|
|
|
20
20
|
const sessions = Array.isArray(list?.sessions) ? list.sessions : [];
|
|
21
21
|
const match = sessions.find((entry) => entry?.key === params.sessionKey) ??
|
|
22
22
|
sessions.find((entry) => entry?.key === params.displayKey);
|
|
23
|
-
const provider = typeof match?.
|
|
23
|
+
const provider = typeof match?.lastChannel === "string"
|
|
24
|
+
? match.lastChannel
|
|
25
|
+
: typeof match?.lastProvider === "string"
|
|
26
|
+
? match.lastProvider
|
|
27
|
+
: undefined;
|
|
24
28
|
const to = typeof match?.lastTo === "string" ? match.lastTo : undefined;
|
|
25
29
|
const accountId = typeof match?.lastAccountId === "string"
|
|
26
30
|
? match.lastAccountId
|
package/dist/agents/workspace.js
CHANGED
|
@@ -2,8 +2,8 @@ import fs from "node:fs/promises";
|
|
|
2
2
|
import os from "node:os";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
|
-
import { resolveStateDir } from "../config/paths.js";
|
|
6
|
-
import { NEXUS_ROOT, resolveUserPath } from "../utils.js";
|
|
5
|
+
import { resolveBootstrapPath, resolveStateDir } from "../config/paths.js";
|
|
6
|
+
import { MANAGED_SKILLS_DIR, NEXUS_ROOT, resolveUserPath } from "../utils.js";
|
|
7
7
|
export function resolveDefaultAgentWorkspaceDir(env = process.env, homedir = os.homedir) {
|
|
8
8
|
const profile = env.NEXUS_PROFILE?.trim();
|
|
9
9
|
if (profile && profile.toLowerCase() !== "default") {
|
|
@@ -68,47 +68,36 @@ It does not define which tools exist; Nexus provides built-in tools internally.
|
|
|
68
68
|
|
|
69
69
|
Add whatever else you want the assistant to know about your local toolchain.
|
|
70
70
|
`;
|
|
71
|
-
const DEFAULT_BOOTSTRAP_TEMPLATE = `# BOOTSTRAP.md -
|
|
71
|
+
const DEFAULT_BOOTSTRAP_TEMPLATE = `# BOOTSTRAP.md - Welcome to Nexus
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
This workspace needs identity setup before agents can help.
|
|
74
74
|
|
|
75
|
-
##
|
|
76
|
-
Start a short
|
|
77
|
-
-
|
|
78
|
-
- What
|
|
79
|
-
-
|
|
80
|
-
- How should I call you?
|
|
75
|
+
## For humans
|
|
76
|
+
Start a short conversation with your AI assistant. Share:
|
|
77
|
+
- Your name (and how you'd like to be addressed)
|
|
78
|
+
- What you're hoping to accomplish with AI
|
|
79
|
+
- Any preferences for tone, boundaries, or style
|
|
81
80
|
|
|
82
|
-
|
|
83
|
-
Say:
|
|
84
|
-
"Hello! I was just born. Who am I? What am I? Who are you? How should I call you?"
|
|
81
|
+
The agent will write identity files as you chat (takes ~5 min).
|
|
85
82
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
- 3-5 creature/vibe combos.
|
|
89
|
-
- 5 emoji ideas.
|
|
83
|
+
## For agents
|
|
84
|
+
You are beginning the bootstrap conversation. Goals:
|
|
90
85
|
|
|
91
|
-
|
|
92
|
-
|
|
86
|
+
1) Learn the user's name
|
|
87
|
+
→ Write: state/user/identity/PROFILE.md
|
|
93
88
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
- Creature
|
|
97
|
-
- Vibe
|
|
98
|
-
- Emoji
|
|
89
|
+
2) Let the user name you
|
|
90
|
+
→ Write: state/agents/{agent}/identity/IDENTITY.md
|
|
99
91
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
- Preferred address
|
|
103
|
-
- Pronouns (optional)
|
|
104
|
-
- Timezone (optional)
|
|
105
|
-
- Notes
|
|
92
|
+
3) Define personality and boundaries
|
|
93
|
+
→ Write: state/agents/{agent}/identity/SOUL.md
|
|
106
94
|
|
|
107
|
-
|
|
108
|
-
|
|
95
|
+
4) Initialize long-term memory
|
|
96
|
+
→ Write: state/agents/{agent}/identity/MEMORY.md
|
|
109
97
|
|
|
110
|
-
|
|
111
|
-
|
|
98
|
+
Be warm, curious, and conversational. Don't rush a checklist.
|
|
99
|
+
|
|
100
|
+
When complete, run \`nexus status\` to show what's unlocked.
|
|
112
101
|
`;
|
|
113
102
|
const DEFAULT_IDENTITY_TEMPLATE = `# IDENTITY.md - Agent Identity
|
|
114
103
|
|
|
@@ -125,6 +114,11 @@ const DEFAULT_USER_TEMPLATE = `# PROFILE.md - User Profile
|
|
|
125
114
|
- Timezone (optional):
|
|
126
115
|
- Notes:
|
|
127
116
|
`;
|
|
117
|
+
const DEFAULT_MEMORY_TEMPLATE = `# MEMORY.md - Long-Term Memory
|
|
118
|
+
|
|
119
|
+
This file stores distilled, long-term insights about the user and context.
|
|
120
|
+
Keep it concise and updated as you learn important facts.
|
|
121
|
+
`;
|
|
128
122
|
const TEMPLATE_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../docs/templates");
|
|
129
123
|
function stripFrontMatter(content) {
|
|
130
124
|
if (!content.startsWith("---"))
|
|
@@ -165,42 +159,52 @@ export async function ensureAgentWorkspace(params) {
|
|
|
165
159
|
? params.dir.trim()
|
|
166
160
|
: DEFAULT_AGENT_WORKSPACE_DIR;
|
|
167
161
|
const dir = resolveUserPath(rawDir);
|
|
162
|
+
const createHomeLayout = params?.createHomeLayout ?? false;
|
|
168
163
|
await fs.mkdir(dir, { recursive: true });
|
|
169
|
-
|
|
170
|
-
|
|
164
|
+
if (createHomeLayout) {
|
|
165
|
+
await fs.mkdir(path.join(dir, "memory"), { recursive: true });
|
|
166
|
+
await fs.mkdir(path.join(dir, "projects"), { recursive: true });
|
|
167
|
+
}
|
|
168
|
+
await fs.mkdir(NEXUS_ROOT, { recursive: true });
|
|
171
169
|
const stateDir = resolveStateDir();
|
|
172
170
|
const nexusStateDir = path.join(stateDir, "nexus");
|
|
173
171
|
const agentId = process.env.NEXUS_AGENT_ID?.trim() || "default";
|
|
174
172
|
const agentIdentityDir = path.join(stateDir, "agents", agentId, "identity");
|
|
175
173
|
const userIdentityDir = path.join(stateDir, "user", "identity");
|
|
176
|
-
const skillsStateDir =
|
|
177
|
-
const onboardingDir = path.join(nexusStateDir, "onboarding");
|
|
174
|
+
const skillsStateDir = MANAGED_SKILLS_DIR;
|
|
178
175
|
const credentialsDir = path.join(stateDir, "credentials");
|
|
179
176
|
await fs.mkdir(nexusStateDir, { recursive: true });
|
|
180
177
|
await fs.mkdir(agentIdentityDir, { recursive: true });
|
|
181
178
|
await fs.mkdir(userIdentityDir, { recursive: true });
|
|
182
179
|
await fs.mkdir(skillsStateDir, { recursive: true });
|
|
183
|
-
await fs.mkdir(onboardingDir, { recursive: true });
|
|
184
180
|
await fs.mkdir(credentialsDir, { recursive: true });
|
|
185
181
|
const agentsPath = path.join(NEXUS_ROOT, DEFAULT_AGENTS_FILENAME);
|
|
186
182
|
const soulPath = path.join(agentIdentityDir, DEFAULT_SOUL_FILENAME);
|
|
187
183
|
const toolsPath = path.join(dir, DEFAULT_TOOLS_FILENAME);
|
|
188
184
|
const identityPath = path.join(agentIdentityDir, DEFAULT_IDENTITY_FILENAME);
|
|
185
|
+
const memoryPath = path.join(agentIdentityDir, "MEMORY.md");
|
|
189
186
|
const userPath = path.join(userIdentityDir, DEFAULT_USER_FILENAME);
|
|
190
|
-
const bootstrapPath =
|
|
187
|
+
const bootstrapPath = resolveBootstrapPath();
|
|
191
188
|
const agentsTemplate = await loadTemplate(DEFAULT_AGENTS_FILENAME, DEFAULT_AGENTS_TEMPLATE);
|
|
192
189
|
await writeFileIfMissing(agentsPath, agentsTemplate);
|
|
193
190
|
if (params?.ensureBootstrapFiles) {
|
|
191
|
+
const bootstrapMode = params.bootstrapMode ?? "full";
|
|
194
192
|
const soulTemplate = await loadTemplate(DEFAULT_SOUL_FILENAME, DEFAULT_SOUL_TEMPLATE);
|
|
195
193
|
const toolsTemplate = await loadTemplate(DEFAULT_TOOLS_FILENAME, DEFAULT_TOOLS_TEMPLATE);
|
|
196
194
|
const identityTemplate = await loadTemplate(DEFAULT_IDENTITY_FILENAME, DEFAULT_IDENTITY_TEMPLATE);
|
|
197
195
|
const userTemplate = await loadTemplate(DEFAULT_USER_FILENAME, DEFAULT_USER_TEMPLATE);
|
|
196
|
+
const memoryTemplate = DEFAULT_MEMORY_TEMPLATE;
|
|
198
197
|
const bootstrapTemplate = await loadTemplate(DEFAULT_BOOTSTRAP_FILENAME, DEFAULT_BOOTSTRAP_TEMPLATE);
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
await writeFileIfMissing(userPath, userTemplate);
|
|
198
|
+
if (createHomeLayout) {
|
|
199
|
+
await writeFileIfMissing(toolsPath, toolsTemplate);
|
|
200
|
+
}
|
|
203
201
|
await writeFileIfMissing(bootstrapPath, bootstrapTemplate);
|
|
202
|
+
await writeFileIfMissing(soulPath, soulTemplate);
|
|
203
|
+
if (bootstrapMode === "full") {
|
|
204
|
+
await writeFileIfMissing(identityPath, identityTemplate);
|
|
205
|
+
await writeFileIfMissing(memoryPath, memoryTemplate);
|
|
206
|
+
await writeFileIfMissing(userPath, userTemplate);
|
|
207
|
+
}
|
|
204
208
|
}
|
|
205
209
|
return {
|
|
206
210
|
dir,
|
|
@@ -208,6 +212,7 @@ export async function ensureAgentWorkspace(params) {
|
|
|
208
212
|
soulPath,
|
|
209
213
|
toolsPath,
|
|
210
214
|
identityPath,
|
|
215
|
+
memoryPath,
|
|
211
216
|
userPath,
|
|
212
217
|
bootstrapPath,
|
|
213
218
|
};
|
|
@@ -218,7 +223,7 @@ export async function loadWorkspaceBootstrapFiles(dir) {
|
|
|
218
223
|
const agentId = process.env.NEXUS_AGENT_ID?.trim() || "default";
|
|
219
224
|
const agentIdentityDir = path.join(stateDir, "agents", agentId, "identity");
|
|
220
225
|
const userIdentityDir = path.join(stateDir, "user", "identity");
|
|
221
|
-
const
|
|
226
|
+
const bootstrapPath = resolveBootstrapPath();
|
|
222
227
|
const entries = [
|
|
223
228
|
{
|
|
224
229
|
name: DEFAULT_AGENTS_FILENAME,
|
|
@@ -236,13 +241,17 @@ export async function loadWorkspaceBootstrapFiles(dir) {
|
|
|
236
241
|
name: DEFAULT_IDENTITY_FILENAME,
|
|
237
242
|
filePath: path.join(agentIdentityDir, DEFAULT_IDENTITY_FILENAME),
|
|
238
243
|
},
|
|
244
|
+
{
|
|
245
|
+
name: "MEMORY.md",
|
|
246
|
+
filePath: path.join(agentIdentityDir, "MEMORY.md"),
|
|
247
|
+
},
|
|
239
248
|
{
|
|
240
249
|
name: DEFAULT_USER_FILENAME,
|
|
241
250
|
filePath: path.join(userIdentityDir, DEFAULT_USER_FILENAME),
|
|
242
251
|
},
|
|
243
252
|
{
|
|
244
253
|
name: DEFAULT_BOOTSTRAP_FILENAME,
|
|
245
|
-
filePath:
|
|
254
|
+
filePath: bootstrapPath,
|
|
246
255
|
},
|
|
247
256
|
];
|
|
248
257
|
const result = [];
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
const CONTROL_COMMAND_RE = /(?:^|\s)\/(?:status|help|thinking|think|t|verbose|v|elevated|elev|model|queue|activation|send|restart|reset|new|compact)(?=$|\s|:)\b/i;
|
|
1
|
+
const CONTROL_COMMAND_RE = /(?:^|\s)\/(?:status|help|thinking|think|t|reasoning|reason|verbose|v|elevated|elev|model|queue|activation|send|restart|reset|new|compact)(?=$|\s|:)\b/i;
|
|
2
2
|
const CONTROL_COMMAND_EXACT = new Set([
|
|
3
3
|
"/help",
|
|
4
4
|
"/status",
|
|
5
5
|
"/restart",
|
|
6
6
|
"/activation",
|
|
7
7
|
"/send",
|
|
8
|
+
"/reasoning",
|
|
8
9
|
"/reset",
|
|
9
10
|
"/new",
|
|
10
11
|
"/compact",
|
|
@@ -1,35 +1,45 @@
|
|
|
1
|
+
import { resolveNexusAgentDir } from "../../agents/agent-paths.js";
|
|
2
|
+
import { loadModelCatalog } from "../../agents/model-catalog.js";
|
|
1
3
|
import { resolveAuthProfileDisplayLabel, resolveAuthStorePathForDisplay, } from "../../agents/auth-profiles.js";
|
|
2
4
|
import { lookupContextTokens } from "../../agents/context.js";
|
|
3
5
|
import { DEFAULT_CONTEXT_TOKENS, DEFAULT_MODEL, DEFAULT_PROVIDER, } from "../../agents/defaults.js";
|
|
4
6
|
import { ensureAuthProfileStore, getCustomProviderApiKey, resolveAuthProfileOrder, resolveEnvApiKey, } from "../../agents/model-auth.js";
|
|
5
|
-
import { buildModelAliasIndex, modelKey, normalizeProviderId, resolveConfiguredModelRef, resolveModelRefFromString, } from "../../agents/model-selection.js";
|
|
6
|
-
import { resolveNexusAgentDir } from "../../agents/agent-paths.js";
|
|
7
|
+
import { buildModelAliasIndex, modelKey, normalizeProviderId, resolveConfiguredModelRef, resolveModelRefFromString, resolveThinkingDefault, } from "../../agents/model-selection.js";
|
|
7
8
|
import { saveSessionStore } from "../../config/sessions.js";
|
|
8
9
|
import { enqueueSystemEvent } from "../../infra/system-events.js";
|
|
9
10
|
import { DEFAULT_AGENT_ID } from "../../routing/session-key.js";
|
|
10
11
|
import { shortenHomePath } from "../../utils.js";
|
|
11
12
|
import { extractModelDirective } from "../model.js";
|
|
12
|
-
import { extractElevatedDirective, extractStatusDirective, extractThinkDirective, extractVerboseDirective, } from "./directives.js";
|
|
13
|
+
import { extractElevatedDirective, extractReasoningDirective, extractStatusDirective, extractThinkDirective, extractVerboseDirective, } from "./directives.js";
|
|
13
14
|
import { stripMentions, stripStructuralPrefixes } from "./mentions.js";
|
|
14
15
|
import { resolveModelDirectiveSelection, } from "./model-selection.js";
|
|
15
16
|
import { extractQueueDirective, } from "./queue.js";
|
|
16
17
|
const SYSTEM_MARK = "⚙️";
|
|
17
18
|
const formatOptionsLine = (options) => `Options: ${options}.`;
|
|
18
|
-
const
|
|
19
|
-
const
|
|
19
|
+
const _withOptions = (line, options) => `${line}\n${formatOptionsLine(options)}`;
|
|
20
|
+
const _formatElevatedRuntimeHint = () => `${SYSTEM_MARK} Runtime is direct; sandboxing does not apply.`;
|
|
20
21
|
const formatPath = (value) => shortenHomePath(value);
|
|
21
22
|
const activeAgentId = DEFAULT_AGENT_ID;
|
|
22
|
-
const
|
|
23
|
+
const _formatElevatedEvent = (level) => level === "on"
|
|
23
24
|
? "Elevated ON — exec runs on host; set elevated:false to stay sandboxed."
|
|
24
25
|
: "Elevated OFF — exec stays in sandbox.";
|
|
25
|
-
const
|
|
26
|
+
const _formatReasoningEvent = (level) => {
|
|
26
27
|
if (level === "stream")
|
|
27
28
|
return "Reasoning STREAM — emit live <think>.";
|
|
28
29
|
if (level === "on")
|
|
29
30
|
return "Reasoning ON — include <think>.";
|
|
30
31
|
return "Reasoning OFF — hide <think>.";
|
|
31
32
|
};
|
|
32
|
-
|
|
33
|
+
const _formatListWithOr = (items) => {
|
|
34
|
+
if (items.length === 0)
|
|
35
|
+
return "";
|
|
36
|
+
if (items.length === 1)
|
|
37
|
+
return items[0] ?? "";
|
|
38
|
+
if (items.length === 2)
|
|
39
|
+
return `${items[0]} or ${items[1]}`;
|
|
40
|
+
return `${items.slice(0, -1).join(", ")} or ${items[items.length - 1]}`;
|
|
41
|
+
};
|
|
42
|
+
function _formatElevatedUnavailableText(params) {
|
|
33
43
|
const lines = [];
|
|
34
44
|
lines.push(`elevated is not available right now (runtime=${params.runtimeSandboxed ? "sandboxed" : "direct"}).`);
|
|
35
45
|
const failures = params.failures ?? [];
|
|
@@ -140,6 +150,15 @@ const MODEL_PICK_PROVIDER_PREFERENCE = [
|
|
|
140
150
|
"xai",
|
|
141
151
|
"lmstudio",
|
|
142
152
|
];
|
|
153
|
+
const XHIGH_THINKING_MODELS = [
|
|
154
|
+
"openai/gpt-5.2",
|
|
155
|
+
"openai-codex/gpt-5.2-codex",
|
|
156
|
+
"openai-codex/gpt-5.1-codex",
|
|
157
|
+
];
|
|
158
|
+
function isXhighThinkingAllowed(provider, model) {
|
|
159
|
+
const key = `${normalizeProviderId(provider)}/${model}`;
|
|
160
|
+
return XHIGH_THINKING_MODELS.includes(key);
|
|
161
|
+
}
|
|
143
162
|
function normalizeModelFamilyId(id) {
|
|
144
163
|
const trimmed = id.trim();
|
|
145
164
|
if (!trimmed)
|
|
@@ -161,7 +180,7 @@ function sortProvidersForPicker(providers) {
|
|
|
161
180
|
return a.localeCompare(b);
|
|
162
181
|
});
|
|
163
182
|
}
|
|
164
|
-
function
|
|
183
|
+
function _buildModelPickerItems(catalog) {
|
|
165
184
|
const byModel = new Map();
|
|
166
185
|
for (const entry of catalog) {
|
|
167
186
|
const provider = normalizeProviderId(entry.provider);
|
|
@@ -183,7 +202,7 @@ function buildModelPickerItems(catalog) {
|
|
|
183
202
|
out.sort((a, b) => a.model.toLowerCase().localeCompare(b.model.toLowerCase()));
|
|
184
203
|
return out;
|
|
185
204
|
}
|
|
186
|
-
function
|
|
205
|
+
function _pickProviderForModel(params) {
|
|
187
206
|
const preferred = params.preferredProvider
|
|
188
207
|
? normalizeProviderId(params.preferredProvider)
|
|
189
208
|
: undefined;
|
|
@@ -201,7 +220,7 @@ function pickProviderForModel(params) {
|
|
|
201
220
|
model: params.item.providerModels[first] ?? params.item.model,
|
|
202
221
|
};
|
|
203
222
|
}
|
|
204
|
-
function
|
|
223
|
+
function _resolveProviderEndpointLabel(provider, cfg) {
|
|
205
224
|
const normalized = normalizeProviderId(provider);
|
|
206
225
|
const providers = (cfg.models?.providers ?? {});
|
|
207
226
|
const entry = providers[normalized];
|
|
@@ -214,7 +233,8 @@ function resolveProviderEndpointLabel(provider, cfg) {
|
|
|
214
233
|
}
|
|
215
234
|
export function parseInlineDirectives(body) {
|
|
216
235
|
const { cleaned: thinkCleaned, thinkLevel, rawLevel: rawThinkLevel, hasDirective: hasThinkDirective, } = extractThinkDirective(body);
|
|
217
|
-
const { cleaned:
|
|
236
|
+
const { cleaned: reasoningCleaned, reasoningLevel, rawLevel: rawReasoningLevel, hasDirective: hasReasoningDirective, } = extractReasoningDirective(thinkCleaned);
|
|
237
|
+
const { cleaned: verboseCleaned, verboseLevel, rawLevel: rawVerboseLevel, hasDirective: hasVerboseDirective, } = extractVerboseDirective(reasoningCleaned);
|
|
218
238
|
const { cleaned: elevatedCleaned, elevatedLevel, rawLevel: rawElevatedLevel, hasDirective: hasElevatedDirective, } = extractElevatedDirective(verboseCleaned);
|
|
219
239
|
const { cleaned: statusCleaned, hasDirective: hasStatusDirective } = extractStatusDirective(elevatedCleaned);
|
|
220
240
|
const { cleaned: modelCleaned, rawModel, rawProfile, hasDirective: hasModelDirective, } = extractModelDirective(statusCleaned);
|
|
@@ -224,6 +244,9 @@ export function parseInlineDirectives(body) {
|
|
|
224
244
|
hasThinkDirective,
|
|
225
245
|
thinkLevel,
|
|
226
246
|
rawThinkLevel,
|
|
247
|
+
hasReasoningDirective,
|
|
248
|
+
reasoningLevel,
|
|
249
|
+
rawReasoningLevel,
|
|
227
250
|
hasVerboseDirective,
|
|
228
251
|
verboseLevel,
|
|
229
252
|
rawVerboseLevel,
|
|
@@ -250,6 +273,7 @@ export function parseInlineDirectives(body) {
|
|
|
250
273
|
export function isDirectiveOnly(params) {
|
|
251
274
|
const { directives, cleanedBody, ctx, cfg, isGroup } = params;
|
|
252
275
|
if (!directives.hasThinkDirective &&
|
|
276
|
+
!directives.hasReasoningDirective &&
|
|
253
277
|
!directives.hasVerboseDirective &&
|
|
254
278
|
!directives.hasElevatedDirective &&
|
|
255
279
|
!directives.hasModelDirective &&
|
|
@@ -260,22 +284,37 @@ export function isDirectiveOnly(params) {
|
|
|
260
284
|
return noMentions.length === 0;
|
|
261
285
|
}
|
|
262
286
|
export async function handleDirectiveOnly(params) {
|
|
263
|
-
const { directives, sessionEntry, sessionStore, sessionKey, storePath, elevatedEnabled, elevatedAllowed, defaultProvider, defaultModel, aliasIndex, allowedModelKeys, allowedModelCatalog, resetModelOverride, initialModelLabel, formatModelSwitchEvent, } = params;
|
|
287
|
+
const { directives, sessionEntry, sessionStore, sessionKey, storePath, elevatedEnabled, elevatedAllowed, defaultProvider, defaultModel, aliasIndex, allowedModelKeys, allowedModelCatalog, resetModelOverride, provider, model, initialModelLabel, formatModelSwitchEvent, } = params;
|
|
264
288
|
if (directives.hasModelDirective) {
|
|
265
|
-
const
|
|
266
|
-
const
|
|
267
|
-
|
|
289
|
+
const rawModelDirective = directives.rawModelDirective?.trim();
|
|
290
|
+
const modelDirective = rawModelDirective?.toLowerCase();
|
|
291
|
+
const isModelStatus = modelDirective === "status";
|
|
292
|
+
const isModelList = modelDirective === "list";
|
|
293
|
+
if (!rawModelDirective || isModelList) {
|
|
294
|
+
if (allowedModelCatalog.length === 0) {
|
|
295
|
+
return { text: "No models available." };
|
|
296
|
+
}
|
|
297
|
+
const items = _buildModelPickerItems(allowedModelCatalog);
|
|
298
|
+
const lines = ["Pick: /model <#> or /model <provider/model>"];
|
|
299
|
+
for (const [idx, item] of items.entries()) {
|
|
300
|
+
lines.push(`${idx + 1}) ${item.model} — ${item.providers.join(", ")}`);
|
|
301
|
+
}
|
|
302
|
+
return { text: lines.join("\n") };
|
|
303
|
+
}
|
|
304
|
+
if (isModelStatus) {
|
|
268
305
|
if (allowedModelCatalog.length === 0) {
|
|
269
306
|
return { text: "No models available." };
|
|
270
307
|
}
|
|
271
308
|
const agentDir = resolveNexusAgentDir();
|
|
272
309
|
const modelsPath = `${agentDir}/models.json`;
|
|
273
310
|
const authByProvider = new Map();
|
|
311
|
+
const endpointByProvider = new Map();
|
|
274
312
|
for (const entry of allowedModelCatalog) {
|
|
275
313
|
if (authByProvider.has(entry.provider))
|
|
276
314
|
continue;
|
|
277
315
|
const auth = await resolveAuthLabel(entry.provider, params.cfg, modelsPath);
|
|
278
316
|
authByProvider.set(entry.provider, formatAuthLabel(auth));
|
|
317
|
+
endpointByProvider.set(entry.provider, _resolveProviderEndpointLabel(entry.provider, params.cfg));
|
|
279
318
|
}
|
|
280
319
|
const current = `${params.provider}/${params.model}`;
|
|
281
320
|
const defaultLabel = `${defaultProvider}/${defaultModel}`;
|
|
@@ -288,6 +327,16 @@ export async function handleDirectiveOnly(params) {
|
|
|
288
327
|
if (resetModelOverride) {
|
|
289
328
|
lines.push(`(previous selection reset to default)`);
|
|
290
329
|
}
|
|
330
|
+
const providers = Array.from(authByProvider.keys()).sort((a, b) => a.localeCompare(b));
|
|
331
|
+
for (const provider of providers) {
|
|
332
|
+
const authLabel = authByProvider.get(provider) ?? "missing";
|
|
333
|
+
const endpoint = endpointByProvider.get(provider);
|
|
334
|
+
const endpointSuffix = endpoint?.endpoint
|
|
335
|
+
? ` endpoint: ${endpoint.endpoint}`
|
|
336
|
+
: "";
|
|
337
|
+
const apiSuffix = endpoint?.api ? ` api: ${endpoint.api}` : "";
|
|
338
|
+
lines.push(`[${provider}]${endpointSuffix}${apiSuffix} auth: ${authLabel}`);
|
|
339
|
+
}
|
|
291
340
|
for (const entry of allowedModelCatalog) {
|
|
292
341
|
const label = `${entry.provider}/${entry.id}`;
|
|
293
342
|
const aliases = aliasIndex.byKey.get(label);
|
|
@@ -305,9 +354,41 @@ export async function handleDirectiveOnly(params) {
|
|
|
305
354
|
throw new Error("Auth profile override requires a model selection.");
|
|
306
355
|
}
|
|
307
356
|
}
|
|
308
|
-
if (directives.hasThinkDirective &&
|
|
357
|
+
if (directives.hasThinkDirective &&
|
|
358
|
+
directives.rawThinkLevel &&
|
|
359
|
+
!directives.thinkLevel) {
|
|
360
|
+
return {
|
|
361
|
+
text: `Unrecognized thinking level "${directives.rawThinkLevel ?? ""}". Valid levels: off, minimal, low, medium, high, xhigh.`,
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
if (directives.hasThinkDirective && !directives.rawThinkLevel) {
|
|
365
|
+
const catalog = allowedModelCatalog.length > 0
|
|
366
|
+
? allowedModelCatalog
|
|
367
|
+
: await loadModelCatalog({ config: params.cfg });
|
|
368
|
+
const current = sessionEntry?.thinkingLevel ??
|
|
369
|
+
resolveThinkingDefault({
|
|
370
|
+
cfg: params.cfg,
|
|
371
|
+
provider,
|
|
372
|
+
model,
|
|
373
|
+
catalog,
|
|
374
|
+
});
|
|
375
|
+
const options = isXhighThinkingAllowed(provider, model)
|
|
376
|
+
? "off, minimal, low, medium, high, xhigh"
|
|
377
|
+
: "off, minimal, low, medium, high";
|
|
378
|
+
return {
|
|
379
|
+
text: `Current thinking level: ${current}.\n${formatOptionsLine(options)}`,
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
if (directives.hasThinkDirective && directives.thinkLevel === "xhigh") {
|
|
383
|
+
if (!isXhighThinkingAllowed(provider, model)) {
|
|
384
|
+
return {
|
|
385
|
+
text: `Thinking level "xhigh" is only supported for ${_formatListWithOr(XHIGH_THINKING_MODELS)}.`,
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
if (directives.hasReasoningDirective && !directives.reasoningLevel) {
|
|
309
390
|
return {
|
|
310
|
-
text: `Unrecognized
|
|
391
|
+
text: `Unrecognized reasoning level "${directives.rawReasoningLevel ?? ""}". Valid levels: off, on, stream.`,
|
|
311
392
|
};
|
|
312
393
|
}
|
|
313
394
|
if (directives.hasVerboseDirective && !directives.verboseLevel) {
|
|
@@ -359,17 +440,44 @@ export async function handleDirectiveOnly(params) {
|
|
|
359
440
|
let modelSelection;
|
|
360
441
|
let profileOverride;
|
|
361
442
|
if (directives.hasModelDirective && directives.rawModelDirective) {
|
|
362
|
-
const
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
443
|
+
const rawDirective = directives.rawModelDirective.trim();
|
|
444
|
+
const parsedIndex = Number.parseInt(rawDirective, 10);
|
|
445
|
+
if (Number.isFinite(parsedIndex) && String(parsedIndex) === rawDirective) {
|
|
446
|
+
const items = _buildModelPickerItems(allowedModelCatalog);
|
|
447
|
+
const item = items[parsedIndex - 1];
|
|
448
|
+
if (!item) {
|
|
449
|
+
return {
|
|
450
|
+
text: `Unrecognized model "${rawDirective}". Use /model to list available models.`,
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
const picked = _pickProviderForModel({
|
|
454
|
+
item,
|
|
455
|
+
preferredProvider: provider,
|
|
456
|
+
});
|
|
457
|
+
if (picked) {
|
|
458
|
+
const alias = aliasIndex.byKey.get(modelKey(picked.provider, picked.model))?.[0];
|
|
459
|
+
modelSelection = {
|
|
460
|
+
provider: picked.provider,
|
|
461
|
+
model: picked.model,
|
|
462
|
+
isDefault: picked.provider === defaultProvider &&
|
|
463
|
+
picked.model === defaultModel,
|
|
464
|
+
...(alias ? { alias } : undefined),
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
if (!modelSelection) {
|
|
469
|
+
const resolved = resolveModelDirectiveSelection({
|
|
470
|
+
raw: rawDirective,
|
|
471
|
+
defaultProvider,
|
|
472
|
+
defaultModel,
|
|
473
|
+
aliasIndex,
|
|
474
|
+
allowedModelKeys,
|
|
475
|
+
});
|
|
476
|
+
if (resolved.error) {
|
|
477
|
+
return { text: resolved.error };
|
|
478
|
+
}
|
|
479
|
+
modelSelection = resolved.selection;
|
|
371
480
|
}
|
|
372
|
-
modelSelection = resolved.selection;
|
|
373
481
|
if (modelSelection) {
|
|
374
482
|
if (directives.rawModelProfile) {
|
|
375
483
|
const profileResolved = resolveProfileOverride({
|
|
@@ -453,6 +561,20 @@ export async function handleDirectiveOnly(params) {
|
|
|
453
561
|
await saveSessionStore(storePath, sessionStore);
|
|
454
562
|
}
|
|
455
563
|
}
|
|
564
|
+
if (directives.hasElevatedDirective && directives.elevatedLevel && sessionKey) {
|
|
565
|
+
enqueueSystemEvent(_formatElevatedEvent(directives.elevatedLevel), {
|
|
566
|
+
contextKey: `elevated:${directives.elevatedLevel}`,
|
|
567
|
+
sessionKey,
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
if (directives.hasReasoningDirective &&
|
|
571
|
+
directives.reasoningLevel &&
|
|
572
|
+
sessionKey) {
|
|
573
|
+
enqueueSystemEvent(_formatReasoningEvent(directives.reasoningLevel), {
|
|
574
|
+
contextKey: `reasoning:${directives.reasoningLevel}`,
|
|
575
|
+
sessionKey,
|
|
576
|
+
});
|
|
577
|
+
}
|
|
456
578
|
const parts = [];
|
|
457
579
|
if (directives.hasThinkDirective && directives.thinkLevel) {
|
|
458
580
|
parts.push(directives.thinkLevel === "off"
|
|
@@ -469,6 +591,9 @@ export async function handleDirectiveOnly(params) {
|
|
|
469
591
|
? `${SYSTEM_MARK} Elevated mode disabled.`
|
|
470
592
|
: `${SYSTEM_MARK} Elevated mode enabled.`);
|
|
471
593
|
}
|
|
594
|
+
if (directives.hasReasoningDirective && directives.reasoningLevel) {
|
|
595
|
+
parts.push(`${SYSTEM_MARK} Reasoning ${directives.reasoningLevel.toUpperCase()}.`);
|
|
596
|
+
}
|
|
472
597
|
if (modelSelection) {
|
|
473
598
|
const label = `${modelSelection.provider}/${modelSelection.model}`;
|
|
474
599
|
const labelWithAlias = modelSelection.alias
|