@rubytech/taskmaster 1.0.106 → 1.0.108
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/skills-status.js +23 -3
- package/dist/agents/skills.js +1 -0
- package/dist/agents/system-prompt.js +3 -0
- package/dist/agents/taskmaster-tools.js +5 -0
- package/dist/agents/tool-policy.js +2 -1
- package/dist/agents/tools/authorize-admin-tool.js +1 -1
- package/dist/agents/tools/memory-tool.js +2 -1
- package/dist/agents/tools/software-update-tool.js +114 -0
- package/dist/auto-reply/reply/commands-status.js +5 -9
- package/dist/auto-reply/reply/get-reply-run.js +1 -1
- package/dist/auto-reply/reply/get-reply.js +1 -1
- package/dist/auto-reply/reply/model-selection.js +1 -1
- package/dist/browser/routes/screencast.js +1 -1
- package/dist/browser/screencast.js +1 -1
- package/dist/build-info.json +3 -3
- package/dist/commands/agent.js +2 -2
- package/dist/config/zod-schema.js +12 -1
- package/dist/control-ui/assets/index-B2FEGOCu.css +1 -0
- package/dist/control-ui/assets/index-nLVF-pVT.js +3762 -0
- package/dist/control-ui/assets/index-nLVF-pVT.js.map +1 -0
- package/dist/control-ui/index.html +2 -2
- package/dist/control-ui/maxy-icon.png +0 -0
- package/dist/cron/isolated-agent/recipients.js +70 -0
- package/dist/cron/isolated-agent/run.js +43 -13
- package/dist/gateway/config-reload.js +1 -0
- package/dist/gateway/control-ui.js +111 -5
- package/dist/gateway/protocol/index.js +6 -1
- package/dist/gateway/protocol/schema/agents-models-skills.js +23 -0
- package/dist/gateway/protocol/schema/protocol-schemas.js +6 -1
- package/dist/gateway/server-http.js +6 -1
- package/dist/gateway/server-methods/access.js +3 -3
- package/dist/gateway/server-methods/brand.js +160 -0
- package/dist/gateway/server-methods/browser-screencast.js +3 -3
- package/dist/gateway/server-methods/skills.js +159 -3
- package/dist/gateway/server-methods/workspaces.js +7 -7
- package/dist/gateway/server-methods-list.js +5 -0
- package/dist/gateway/server-methods.js +2 -0
- package/dist/gateway/server.impl.js +1 -1
- package/dist/infra/heartbeat-runner.js +17 -0
- package/dist/infra/heartbeat-update-notify.js +120 -0
- package/dist/infra/tunnel.js +1 -1
- package/dist/memory/embeddings.js +0 -4
- package/dist/memory/manager.js +15 -6
- package/dist/web/inbound/media.js +1 -1
- package/dist/web/login-qr.js +0 -23
- package/dist/web/providers/cloud/receive.js +1 -1
- package/dist/web/providers/cloud/webhook.js +1 -1
- package/package.json +1 -1
- package/skills/skill-builder/SKILL.md +97 -0
- package/skills/skill-builder/references/lean-pattern.md +118 -0
- package/skills/zero-to-prototype/SKILL.md +35 -0
- package/skills/zero-to-prototype/references/discovery.md +64 -0
- package/skills/zero-to-prototype/references/prd.md +83 -0
- package/skills/zero-to-prototype/references/validation.md +67 -0
- package/taskmaster-docs/USER-GUIDE.md +65 -31
- package/templates/customer/agents/public/AGENTS.md +3 -10
- package/templates/taskmaster/agents/public/SOUL.md +0 -4
- package/templates/tradesupport/agents/public/AGENTS.md +3 -10
- package/dist/control-ui/assets/index-DjhCZlZd.css +0 -1
- package/dist/control-ui/assets/index-DtuDNTAC.js +0 -3539
- package/dist/control-ui/assets/index-DtuDNTAC.js.map +0 -1
- package/skills/taskmaster/SKILL.md +0 -164
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
1
2
|
import path from "node:path";
|
|
2
3
|
import { CONFIG_DIR } from "../utils.js";
|
|
3
|
-
import { hasBinary, isBundledSkillAllowed, isConfigPathTruthy, loadWorkspaceSkillEntries, resolveBundledAllowlist, resolveConfigPath, resolveSkillConfig, resolveSkillsInstallPreferences, } from "./skills.js";
|
|
4
|
+
import { hasBinary, isBundledSkillAllowed, isConfigPathTruthy, loadWorkspaceSkillEntries, resolveBundledAllowlist, resolveBundledSkillsDir, resolveConfigPath, resolveSkillConfig, resolveSkillsInstallPreferences, } from "./skills.js";
|
|
4
5
|
function resolveSkillKey(entry) {
|
|
5
6
|
return entry.taskmaster?.skillKey ?? entry.skill.name;
|
|
6
7
|
}
|
|
@@ -76,7 +77,7 @@ function normalizeInstallOptions(entry, prefs) {
|
|
|
76
77
|
return [];
|
|
77
78
|
return [toOption(preferred.spec, preferred.index)];
|
|
78
79
|
}
|
|
79
|
-
function buildSkillStatus(entry, config, prefs, eligibility) {
|
|
80
|
+
function buildSkillStatus(entry, config, prefs, eligibility, bundledSkillNames) {
|
|
80
81
|
const skillKey = resolveSkillKey(entry);
|
|
81
82
|
const skillConfig = resolveSkillConfig(config, skillKey);
|
|
82
83
|
const disabled = skillConfig?.enabled === false;
|
|
@@ -145,6 +146,9 @@ function buildSkillStatus(entry, config, prefs, eligibility) {
|
|
|
145
146
|
missing.env.length === 0 &&
|
|
146
147
|
missing.config.length === 0 &&
|
|
147
148
|
missing.os.length === 0));
|
|
149
|
+
const preloaded = bundledSkillNames
|
|
150
|
+
? bundledSkillNames.has(entry.skill.name)
|
|
151
|
+
: false;
|
|
148
152
|
return {
|
|
149
153
|
name: entry.skill.name,
|
|
150
154
|
description: entry.skill.description,
|
|
@@ -159,6 +163,7 @@ function buildSkillStatus(entry, config, prefs, eligibility) {
|
|
|
159
163
|
disabled,
|
|
160
164
|
blockedByAllowlist,
|
|
161
165
|
eligible,
|
|
166
|
+
preloaded,
|
|
162
167
|
requirements: {
|
|
163
168
|
bins: requiredBins,
|
|
164
169
|
anyBins: requiredAnyBins,
|
|
@@ -171,13 +176,28 @@ function buildSkillStatus(entry, config, prefs, eligibility) {
|
|
|
171
176
|
install: normalizeInstallOptions(entry, prefs ?? resolveSkillsInstallPreferences(config)),
|
|
172
177
|
};
|
|
173
178
|
}
|
|
179
|
+
function resolveBundledSkillNames() {
|
|
180
|
+
const dir = resolveBundledSkillsDir();
|
|
181
|
+
if (!dir)
|
|
182
|
+
return new Set();
|
|
183
|
+
try {
|
|
184
|
+
return new Set(fs
|
|
185
|
+
.readdirSync(dir, { withFileTypes: true })
|
|
186
|
+
.filter((d) => d.isDirectory())
|
|
187
|
+
.map((d) => d.name));
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
return new Set();
|
|
191
|
+
}
|
|
192
|
+
}
|
|
174
193
|
export function buildWorkspaceSkillStatus(workspaceDir, opts) {
|
|
175
194
|
const managedSkillsDir = opts?.managedSkillsDir ?? path.join(CONFIG_DIR, "skills");
|
|
176
195
|
const skillEntries = opts?.entries ?? loadWorkspaceSkillEntries(workspaceDir, opts);
|
|
177
196
|
const prefs = resolveSkillsInstallPreferences(opts?.config);
|
|
197
|
+
const bundledSkillNames = resolveBundledSkillNames();
|
|
178
198
|
return {
|
|
179
199
|
workspaceDir,
|
|
180
200
|
managedSkillsDir,
|
|
181
|
-
skills: skillEntries.map((entry) => buildSkillStatus(entry, opts?.config, prefs, opts?.eligibility)),
|
|
201
|
+
skills: skillEntries.map((entry) => buildSkillStatus(entry, opts?.config, prefs, opts?.eligibility, bundledSkillNames)),
|
|
182
202
|
};
|
|
183
203
|
}
|
package/dist/agents/skills.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { hasBinary, isBundledSkillAllowed, isConfigPathTruthy, resolveBundledAllowlist, resolveConfigPath, resolveRuntimePlatform, resolveSkillConfig, } from "./skills/config.js";
|
|
2
2
|
export { applySkillEnvOverrides, applySkillEnvOverridesFromSnapshot, } from "./skills/env-overrides.js";
|
|
3
|
+
export { resolveBundledSkillsDir } from "./skills/bundled-dir.js";
|
|
3
4
|
export { buildWorkspaceSkillSnapshot, buildWorkspaceSkillsPrompt, buildWorkspaceSkillCommandSpecs, filterWorkspaceSkillEntries, loadWorkspaceSkillEntries, resolveSkillsPromptForRun, syncSkillsToWorkspace, } from "./skills/workspace.js";
|
|
4
5
|
export function resolveSkillsInstallPreferences(config) {
|
|
5
6
|
const raw = config?.skills?.install;
|
|
@@ -91,6 +91,7 @@ function buildMessagingSection(params) {
|
|
|
91
91
|
"- For `action=send`, include `to` and `message`.",
|
|
92
92
|
`- If multiple channels are configured, pass \`channel\` (${params.messageChannelOptions}).`,
|
|
93
93
|
`- If you use \`message\` (\`action=send\`) to deliver your user-visible reply, respond with ONLY: ${SILENT_REPLY_TOKEN} (avoid duplicate replies).`,
|
|
94
|
+
"- CRITICAL: Your text output stays in this session — it does NOT reach end users on WhatsApp, iMessage, or other channels. The `message` tool is the ONLY way to deliver a message to someone outside this session. Never claim you sent a message unless the `message` tool returned a confirmed result.",
|
|
94
95
|
params.inlineButtonsEnabled
|
|
95
96
|
? "- Inline buttons supported. Use `action=send` with `buttons=[[{text,callback_data}]]` (callback_data routes back as a user message)."
|
|
96
97
|
: params.runtimeChannel
|
|
@@ -148,6 +149,7 @@ export function buildAgentSystemPrompt(params) {
|
|
|
148
149
|
cron: "Manage scheduled events and wake events (use for reminders; when scheduling a reminder, write the systemEvent text as something that will read like a reminder when it fires, and mention that it is a reminder depending on the time gap between setting and firing; include recent context in reminder text if appropriate)",
|
|
149
150
|
message: "Send messages and channel actions",
|
|
150
151
|
gateway: "Restart, apply config, or run updates on the running Taskmaster process",
|
|
152
|
+
software_update: "Check for software updates, install them, or restart the gateway",
|
|
151
153
|
agents_list: "List agent ids allowed for sessions_spawn",
|
|
152
154
|
sessions_list: "List other sessions (incl. sub-agents) with filters/last",
|
|
153
155
|
sessions_history: "Fetch history for another session/sub-agent",
|
|
@@ -176,6 +178,7 @@ export function buildAgentSystemPrompt(params) {
|
|
|
176
178
|
"cron",
|
|
177
179
|
"message",
|
|
178
180
|
"gateway",
|
|
181
|
+
"software_update",
|
|
179
182
|
"agents_list",
|
|
180
183
|
"sessions_list",
|
|
181
184
|
"sessions_history",
|
|
@@ -28,6 +28,7 @@ import { createRelayMessageTool } from "./tools/relay-message-tool.js";
|
|
|
28
28
|
import { createSkillReadTool } from "./tools/skill-read-tool.js";
|
|
29
29
|
import { createApiKeysTool } from "./tools/apikeys-tool.js";
|
|
30
30
|
import { createImageGenerateTool } from "./tools/image-generate-tool.js";
|
|
31
|
+
import { createSoftwareUpdateTool } from "./tools/software-update-tool.js";
|
|
31
32
|
export function createTaskmasterTools(options) {
|
|
32
33
|
const imageTool = options?.agentDir?.trim()
|
|
33
34
|
? createImageTool({
|
|
@@ -86,6 +87,10 @@ export function createTaskmasterTools(options) {
|
|
|
86
87
|
agentSessionKey: options?.agentSessionKey,
|
|
87
88
|
config: options?.config,
|
|
88
89
|
}),
|
|
90
|
+
createSoftwareUpdateTool({
|
|
91
|
+
agentSessionKey: options?.agentSessionKey,
|
|
92
|
+
config: options?.config,
|
|
93
|
+
}),
|
|
89
94
|
createAgentsListTool({
|
|
90
95
|
agentSessionKey: options?.agentSessionKey,
|
|
91
96
|
requesterAgentIdOverride: options?.requesterAgentIdOverride,
|
|
@@ -31,7 +31,7 @@ export const TOOL_GROUPS = {
|
|
|
31
31
|
// UI helpers
|
|
32
32
|
"group:ui": ["browser", "canvas"],
|
|
33
33
|
// Automation + infra
|
|
34
|
-
"group:automation": ["cron", "gateway", "api_keys"],
|
|
34
|
+
"group:automation": ["cron", "gateway", "api_keys", "software_update"],
|
|
35
35
|
// Messaging surface
|
|
36
36
|
"group:messaging": ["message"],
|
|
37
37
|
// Nodes + device tools
|
|
@@ -61,6 +61,7 @@ export const TOOL_GROUPS = {
|
|
|
61
61
|
"web_fetch",
|
|
62
62
|
"image",
|
|
63
63
|
"image_generate",
|
|
64
|
+
"software_update",
|
|
64
65
|
"current_time",
|
|
65
66
|
"authorize_admin",
|
|
66
67
|
"revoke_admin",
|
|
@@ -7,7 +7,7 @@ import { jsonResult } from "./common.js";
|
|
|
7
7
|
* Strips spaces, dashes, parens. Ensures leading +.
|
|
8
8
|
*/
|
|
9
9
|
function normalizePhoneNumber(input) {
|
|
10
|
-
const digits = input.replace(/[\s
|
|
10
|
+
const digits = input.replace(/[\s\-()]/g, "");
|
|
11
11
|
if (digits.startsWith("+"))
|
|
12
12
|
return digits;
|
|
13
13
|
return `+${digits}`;
|
|
@@ -144,7 +144,8 @@ export function createMemoryWriteTool(options) {
|
|
|
144
144
|
label: "Memory Write",
|
|
145
145
|
name: "memory_write",
|
|
146
146
|
description: "Write or append content to a file in the memory/ directory. " +
|
|
147
|
-
"Path must be within the session's allowed scope
|
|
147
|
+
"Path must be within the session's allowed scope. " +
|
|
148
|
+
"Phone numbers in paths MUST include the + prefix (e.g., memory/users/+447734875155/profile.md). " +
|
|
148
149
|
"Creates parent directories if needed. Use mode='append' to add to existing content.",
|
|
149
150
|
parameters: MemoryWriteSchema,
|
|
150
151
|
execute: async (_toolCallId, params) => {
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import { loadConfig } from "../../config/io.js";
|
|
3
|
+
import { resolveStorePath, loadSessionStore } from "../../config/sessions.js";
|
|
4
|
+
import { scheduleGatewaySigusr1Restart } from "../../infra/restart.js";
|
|
5
|
+
import { formatDoctorNonInteractiveHint, writeRestartSentinel, } from "../../infra/restart-sentinel.js";
|
|
6
|
+
import { stringEnum } from "../schema/typebox.js";
|
|
7
|
+
import { jsonResult, readStringParam } from "./common.js";
|
|
8
|
+
import { callGatewayTool } from "./gateway.js";
|
|
9
|
+
const SOFTWARE_UPDATE_ACTIONS = ["check", "run", "restart"];
|
|
10
|
+
const SoftwareUpdateToolSchema = Type.Object({
|
|
11
|
+
action: stringEnum(SOFTWARE_UPDATE_ACTIONS),
|
|
12
|
+
// restart
|
|
13
|
+
reason: Type.Optional(Type.String()),
|
|
14
|
+
// run
|
|
15
|
+
note: Type.Optional(Type.String()),
|
|
16
|
+
sessionKey: Type.Optional(Type.String()),
|
|
17
|
+
});
|
|
18
|
+
/**
|
|
19
|
+
* Narrowly scoped tool for software updates and gateway restarts.
|
|
20
|
+
* Unlike the full `gateway` tool, this exposes NO config mutation —
|
|
21
|
+
* only version checking, update execution, and restart.
|
|
22
|
+
*/
|
|
23
|
+
export function createSoftwareUpdateTool(opts) {
|
|
24
|
+
return {
|
|
25
|
+
label: "Software Update",
|
|
26
|
+
name: "software_update",
|
|
27
|
+
description: "Check for software updates, install them, or restart the gateway. " +
|
|
28
|
+
"Use 'check' to see if an update is available, 'run' to install it, " +
|
|
29
|
+
"or 'restart' to restart the gateway process.",
|
|
30
|
+
parameters: SoftwareUpdateToolSchema,
|
|
31
|
+
execute: async (_toolCallId, args) => {
|
|
32
|
+
const params = args;
|
|
33
|
+
const action = readStringParam(params, "action", { required: true });
|
|
34
|
+
if (action === "check") {
|
|
35
|
+
const result = await callGatewayTool("update.status", {}, {});
|
|
36
|
+
return jsonResult({ ok: true, result });
|
|
37
|
+
}
|
|
38
|
+
if (action === "run") {
|
|
39
|
+
const sessionKey = typeof params.sessionKey === "string" && params.sessionKey.trim()
|
|
40
|
+
? params.sessionKey.trim()
|
|
41
|
+
: opts?.agentSessionKey?.trim() || undefined;
|
|
42
|
+
const note = typeof params.note === "string" && params.note.trim() ? params.note.trim() : undefined;
|
|
43
|
+
const result = await callGatewayTool("update.run", {}, {
|
|
44
|
+
sessionKey,
|
|
45
|
+
note,
|
|
46
|
+
});
|
|
47
|
+
return jsonResult({ ok: true, result });
|
|
48
|
+
}
|
|
49
|
+
if (action === "restart") {
|
|
50
|
+
if (opts?.config?.commands?.restart !== true) {
|
|
51
|
+
throw new Error("Gateway restart is disabled. Set commands.restart=true to enable.");
|
|
52
|
+
}
|
|
53
|
+
const sessionKey = typeof params.sessionKey === "string" && params.sessionKey.trim()
|
|
54
|
+
? params.sessionKey.trim()
|
|
55
|
+
: opts?.agentSessionKey?.trim() || undefined;
|
|
56
|
+
const reason = typeof params.reason === "string" && params.reason.trim()
|
|
57
|
+
? params.reason.trim().slice(0, 200)
|
|
58
|
+
: undefined;
|
|
59
|
+
// Resolve delivery context for routing after restart
|
|
60
|
+
let deliveryContext;
|
|
61
|
+
let threadId;
|
|
62
|
+
if (sessionKey) {
|
|
63
|
+
const threadMarker = ":thread:";
|
|
64
|
+
const threadIndex = sessionKey.lastIndexOf(threadMarker);
|
|
65
|
+
const baseSessionKey = threadIndex === -1 ? sessionKey : sessionKey.slice(0, threadIndex);
|
|
66
|
+
const threadIdRaw = threadIndex === -1 ? undefined : sessionKey.slice(threadIndex + threadMarker.length);
|
|
67
|
+
threadId = threadIdRaw?.trim() || undefined;
|
|
68
|
+
try {
|
|
69
|
+
const cfg = loadConfig();
|
|
70
|
+
const storePath = resolveStorePath(cfg.session?.store);
|
|
71
|
+
const store = loadSessionStore(storePath);
|
|
72
|
+
let entry = store[sessionKey];
|
|
73
|
+
if (!entry?.deliveryContext && threadIndex !== -1 && baseSessionKey) {
|
|
74
|
+
entry = store[baseSessionKey];
|
|
75
|
+
}
|
|
76
|
+
if (entry?.deliveryContext) {
|
|
77
|
+
deliveryContext = {
|
|
78
|
+
channel: entry.deliveryContext.channel,
|
|
79
|
+
to: entry.deliveryContext.to,
|
|
80
|
+
accountId: entry.deliveryContext.accountId,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// best-effort
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const payload = {
|
|
89
|
+
kind: "restart",
|
|
90
|
+
status: "ok",
|
|
91
|
+
ts: Date.now(),
|
|
92
|
+
sessionKey,
|
|
93
|
+
deliveryContext,
|
|
94
|
+
threadId,
|
|
95
|
+
message: reason ?? null,
|
|
96
|
+
doctorHint: formatDoctorNonInteractiveHint(),
|
|
97
|
+
stats: {
|
|
98
|
+
mode: "gateway.restart",
|
|
99
|
+
reason,
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
try {
|
|
103
|
+
await writeRestartSentinel(payload);
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
// sentinel is best-effort
|
|
107
|
+
}
|
|
108
|
+
const scheduled = scheduleGatewaySigusr1Restart({ reason });
|
|
109
|
+
return jsonResult(scheduled);
|
|
110
|
+
}
|
|
111
|
+
throw new Error(`Unknown action: ${action}`);
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
}
|
|
@@ -7,7 +7,6 @@ import { getCustomProviderApiKey, resolveEnvApiKey } from "../../agents/model-au
|
|
|
7
7
|
import { resolveDefaultModelForAgent } from "../../agents/model-selection.js";
|
|
8
8
|
import { resolveInternalSessionKey, resolveMainSessionAlias, } from "../../agents/tools/sessions-helpers.js";
|
|
9
9
|
import { normalizeProviderId } from "../../agents/model-selection.js";
|
|
10
|
-
import { loadConfig } from "../../config/config.js";
|
|
11
10
|
import { logVerbose } from "../../globals.js";
|
|
12
11
|
import { formatUsageWindowSummary, loadProviderUsageSummary, resolveUsageProviderId, } from "../../infra/provider-usage.js";
|
|
13
12
|
import { normalizeGroupActivation } from "../group-activation.js";
|
|
@@ -74,21 +73,18 @@ export async function buildStatusReply(params) {
|
|
|
74
73
|
logVerbose(`Ignoring /status from unauthorized sender: ${command.senderId || "<unknown>"}`);
|
|
75
74
|
return undefined;
|
|
76
75
|
}
|
|
77
|
-
// Resolve model directly from config — fresh read, not from the passed-in cfg.
|
|
78
|
-
// Config is the single source of truth. No passed objects, no cache.
|
|
79
|
-
const freshCfg = loadConfig();
|
|
80
76
|
const statusAgentId = sessionKey
|
|
81
|
-
? resolveSessionAgentId({ sessionKey, config:
|
|
82
|
-
: resolveDefaultAgentId(
|
|
83
|
-
const configModel = resolveDefaultModelForAgent({ cfg
|
|
77
|
+
? resolveSessionAgentId({ sessionKey, config: cfg })
|
|
78
|
+
: resolveDefaultAgentId(cfg);
|
|
79
|
+
const configModel = resolveDefaultModelForAgent({ cfg, agentId: statusAgentId });
|
|
84
80
|
const provider = configModel.provider;
|
|
85
81
|
const model = configModel.model;
|
|
86
|
-
const contextTokens =
|
|
82
|
+
const contextTokens = cfg.agents?.defaults?.contextTokens ??
|
|
87
83
|
lookupContextTokens(model) ??
|
|
88
84
|
DEFAULT_CONTEXT_TOKENS;
|
|
89
85
|
// Diagnostic: log what status is resolving so we can trace mismatches
|
|
90
86
|
console.log(`[status-resolve] agentId=${statusAgentId} sessionKey=${sessionKey} model=${provider}/${model}` +
|
|
91
|
-
` agentList=${(
|
|
87
|
+
` agentList=${(cfg.agents?.list ?? []).map((a) => `${a.id}:${typeof a.model === "string" ? a.model : (a.model?.primary ?? "default")}`).join(",")}`);
|
|
92
88
|
const statusAgentDir = resolveAgentDir(cfg, statusAgentId);
|
|
93
89
|
const currentUsageProvider = (() => {
|
|
94
90
|
try {
|
|
@@ -23,7 +23,7 @@ import { ensureSkillSnapshot, prependSystemEvents } from "./session-updates.js";
|
|
|
23
23
|
import { resolveTypingMode } from "./typing-mode.js";
|
|
24
24
|
const BARE_SESSION_RESET_PROMPT = "A new session was started via /new or /reset. Say hi briefly (1-2 sentences) and ask what the user wants to do next. If the runtime model differs from default_model in the system prompt, mention the default model in the greeting. Do not mention internal steps, files, tools, or reasoning.";
|
|
25
25
|
export async function runPreparedReply(params) {
|
|
26
|
-
const { ctx, sessionCtx, cfg, agentId, agentDir, agentCfg, sessionCfg, commandAuthorized, command, commandSource, allowTextCommands, directives, defaultActivation, elevatedEnabled, elevatedAllowed, blockStreamingEnabled, blockReplyChunking, resolvedBlockStreamingBreak, modelState, perMessageQueueMode, perMessageQueueOptions, typing, opts, defaultProvider, defaultModel, timeoutMs, isNewSession, resetTriggered, systemSent, sessionKey, sessionId, storePath, workspaceDir, sessionStore, } = params;
|
|
26
|
+
const { ctx, sessionCtx, cfg, agentId: _agentId, agentDir, agentCfg, sessionCfg, commandAuthorized, command, commandSource, allowTextCommands, directives, defaultActivation, elevatedEnabled, elevatedAllowed, blockStreamingEnabled, blockReplyChunking, resolvedBlockStreamingBreak, modelState, perMessageQueueMode, perMessageQueueOptions, typing, opts, defaultProvider, defaultModel, timeoutMs, isNewSession, resetTriggered, systemSent, sessionKey, sessionId, storePath, workspaceDir, sessionStore, } = params;
|
|
27
27
|
// Model comes from config. Two params: config + agentId. Read fresh every time.
|
|
28
28
|
const llmCfg = loadConfig();
|
|
29
29
|
const llmAgentId = resolveSessionAgentId({ sessionKey, config: llmCfg });
|
|
@@ -36,7 +36,7 @@ export async function getReplyFromConfig(ctx, opts, configOverride) {
|
|
|
36
36
|
let model = defaultModel;
|
|
37
37
|
// Diagnostic: log agent/model resolution for every message so we can trace mismatches
|
|
38
38
|
console.log(`[model-resolve] agentId=${agentId} sessionKey=${agentSessionKey} model=${provider}/${model}` +
|
|
39
|
-
` agentList=${(cfg.agents?.list ?? []).map((a) => `${a.id}:${a.model ?? "default"}`).join(",")}`);
|
|
39
|
+
` agentList=${(cfg.agents?.list ?? []).map((a) => `${a.id}:${typeof a.model === "string" ? a.model : (a.model?.primary ?? "default")}`).join(",")}`);
|
|
40
40
|
if (opts?.isHeartbeat) {
|
|
41
41
|
const heartbeatRaw = agentCfg?.heartbeat?.model?.trim() ?? "";
|
|
42
42
|
const heartbeatRef = heartbeatRaw
|
|
@@ -124,7 +124,7 @@ function scoreFuzzyMatch(params) {
|
|
|
124
124
|
};
|
|
125
125
|
}
|
|
126
126
|
export async function createModelSelectionState(params) {
|
|
127
|
-
const { cfg, agentCfg, sessionEntry, sessionStore, sessionKey, parentSessionKey, storePath, defaultProvider, defaultModel, } = params;
|
|
127
|
+
const { cfg, agentCfg, sessionEntry, sessionStore, sessionKey, parentSessionKey: _parentSessionKey, storePath, defaultProvider, defaultModel, } = params;
|
|
128
128
|
// Model always comes from config (per-agent or global default).
|
|
129
129
|
// No session-level model overrides — the config is the single source of truth,
|
|
130
130
|
// applied to all conversations for the agent from that point forward.
|
|
@@ -99,7 +99,7 @@ export function registerBrowserScreencastRoutes(app, ctx) {
|
|
|
99
99
|
res.json({ ok: true, sessionId: session.id, label });
|
|
100
100
|
}
|
|
101
101
|
catch (err) {
|
|
102
|
-
log.error(`screencast start failed: ${err}`);
|
|
102
|
+
log.error(`screencast start failed: ${String(err)}`);
|
|
103
103
|
jsonError(res, 500, String(err));
|
|
104
104
|
}
|
|
105
105
|
});
|
|
@@ -108,7 +108,7 @@ export async function startScreencast(opts) {
|
|
|
108
108
|
send("Page.stopScreencast").catch(() => { });
|
|
109
109
|
pollInterval = setInterval(pollOnce, POLL_INTERVAL_MS);
|
|
110
110
|
// Fire one immediately so the UI gets a frame right away
|
|
111
|
-
pollOnce();
|
|
111
|
+
void pollOnce();
|
|
112
112
|
};
|
|
113
113
|
ws.on("message", (raw) => {
|
|
114
114
|
try {
|
package/dist/build-info.json
CHANGED
package/dist/commands/agent.js
CHANGED
|
@@ -191,7 +191,7 @@ export async function agentCommand(opts, runtime = defaultRuntime, deps = create
|
|
|
191
191
|
// Model always comes from config (per-agent or global default).
|
|
192
192
|
// No session-level model overrides.
|
|
193
193
|
const hasAllowlist = !!(agentCfg?.models && Object.keys(agentCfg.models).length > 0);
|
|
194
|
-
let
|
|
194
|
+
let _allowedModelKeys = new Set();
|
|
195
195
|
let allowedModelCatalog = [];
|
|
196
196
|
let modelCatalog = null;
|
|
197
197
|
if (hasAllowlist) {
|
|
@@ -202,7 +202,7 @@ export async function agentCommand(opts, runtime = defaultRuntime, deps = create
|
|
|
202
202
|
defaultProvider,
|
|
203
203
|
defaultModel,
|
|
204
204
|
});
|
|
205
|
-
|
|
205
|
+
_allowedModelKeys = allowed.allowedKeys;
|
|
206
206
|
allowedModelCatalog = allowed.allowedCatalog;
|
|
207
207
|
}
|
|
208
208
|
if (sessionEntry) {
|
|
@@ -538,7 +538,18 @@ export const TaskmasterSchema = z
|
|
|
538
538
|
.strict()
|
|
539
539
|
.optional(),
|
|
540
540
|
workspaces: z
|
|
541
|
-
.record(z.string(), z
|
|
541
|
+
.record(z.string(), z
|
|
542
|
+
.object({
|
|
543
|
+
displayName: z.string().optional(),
|
|
544
|
+
brand: z
|
|
545
|
+
.object({
|
|
546
|
+
accentColor: HexColorSchema.optional(),
|
|
547
|
+
backgroundColor: HexColorSchema.optional(),
|
|
548
|
+
})
|
|
549
|
+
.strict()
|
|
550
|
+
.optional(),
|
|
551
|
+
})
|
|
552
|
+
.strict())
|
|
542
553
|
.optional(),
|
|
543
554
|
apiKeys: z.record(z.string(), z.string()).optional(),
|
|
544
555
|
access: z
|