@agentconnect.md/daemon 1.0.0-rc.159 → 1.0.0-rc.160
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/index.js +405 -67
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -13629,6 +13629,8 @@ const WebchatStatus = object({
|
|
|
13629
13629
|
costAmount: number().optional(),
|
|
13630
13630
|
costCurrency: string().optional(),
|
|
13631
13631
|
models: array(string()).optional(),
|
|
13632
|
+
efforts: array(string()).optional(),
|
|
13633
|
+
fastModeAvailable: boolean().optional(),
|
|
13632
13634
|
sessionId: string().optional()
|
|
13633
13635
|
});
|
|
13634
13636
|
//#endregion
|
|
@@ -13682,6 +13684,16 @@ const FRAME_SCHEMAS = {
|
|
|
13682
13684
|
agentId: string().uuid(),
|
|
13683
13685
|
model: string()
|
|
13684
13686
|
}),
|
|
13687
|
+
"webchat/set-effort": object({
|
|
13688
|
+
conversationId: string().uuid(),
|
|
13689
|
+
agentId: string().uuid(),
|
|
13690
|
+
effort: string()
|
|
13691
|
+
}),
|
|
13692
|
+
"webchat/set-fast": object({
|
|
13693
|
+
conversationId: string().uuid(),
|
|
13694
|
+
agentId: string().uuid(),
|
|
13695
|
+
fastMode: boolean()
|
|
13696
|
+
}),
|
|
13685
13697
|
"webchat/cancel": object({ conversationId: string().uuid() }),
|
|
13686
13698
|
"route/assign": RouteAssign,
|
|
13687
13699
|
"route/assign/ack": RouteAssignAck,
|
|
@@ -13760,6 +13772,8 @@ discriminatedUnion("type", [
|
|
|
13760
13772
|
frame("webchat/done", FRAME_SCHEMAS["webchat/done"]),
|
|
13761
13773
|
frame("webchat/close", FRAME_SCHEMAS["webchat/close"]),
|
|
13762
13774
|
frame("webchat/set-model", FRAME_SCHEMAS["webchat/set-model"]),
|
|
13775
|
+
frame("webchat/set-effort", FRAME_SCHEMAS["webchat/set-effort"]),
|
|
13776
|
+
frame("webchat/set-fast", FRAME_SCHEMAS["webchat/set-fast"]),
|
|
13763
13777
|
frame("webchat/cancel", FRAME_SCHEMAS["webchat/cancel"]),
|
|
13764
13778
|
frame("route/assign", FRAME_SCHEMAS["route/assign"]),
|
|
13765
13779
|
frame("route/assign/ack", FRAME_SCHEMAS["route/assign/ack"]),
|
|
@@ -18183,6 +18197,11 @@ function planConfigSelection(configOptions, category, desired) {
|
|
|
18183
18197
|
value: desired
|
|
18184
18198
|
};
|
|
18185
18199
|
}
|
|
18200
|
+
/** Effort sentinel `'ultracode'` (matching Claude Code's own `ultracode` settings
|
|
18201
|
+
* key) meaning xhigh reasoning PLUS standing dynamic-workflow orchestration. It is
|
|
18202
|
+
* deliberately NOT a `thought_level` select value: the claude-acp runtime rejects
|
|
18203
|
+
* effort="ultracode" ("Invalid value"). See {@link claudeSessionMeta}. */
|
|
18204
|
+
const ULTRACODE_EFFORT = "ultracode";
|
|
18186
18205
|
/** The session `_meta` sent to a Claude runtime on session/new and session/load
|
|
18187
18206
|
* (`_meta.claudeCode.options` is spread into the SDK `query()` options layer), or
|
|
18188
18207
|
* undefined off Claude runtimes. Two things ride on it:
|
|
@@ -18225,6 +18244,39 @@ function modelOptionsFrom(configOptions) {
|
|
|
18225
18244
|
models
|
|
18226
18245
|
};
|
|
18227
18246
|
}
|
|
18247
|
+
/**
|
|
18248
|
+
* Extract the reasoning-effort selector from a session's `configOptions` (ACP
|
|
18249
|
+
* `category: "thought_level"`, `type: "select"`). Effort support is per-model: a runtime
|
|
18250
|
+
* only advertises this select for models that support effort (e.g. Opus/Sonnet, not
|
|
18251
|
+
* Haiku), so a missing/empty selector means the CURRENT model has no effort → returns
|
|
18252
|
+
* null and the picker is hidden. When the model DOES support effort, Claude runtimes get
|
|
18253
|
+
* the synthetic `max`/`ultracode` entries appended if not already offered (see
|
|
18254
|
+
* {@link ULTRACODE_EFFORT}) — never fabricated for a model that lacks effort entirely.
|
|
18255
|
+
*/
|
|
18256
|
+
function effortOptionsFrom(configOptions, isClaudeRuntime) {
|
|
18257
|
+
const opt = configOptions?.find((o) => o.category === "thought_level" && o.type === "select");
|
|
18258
|
+
if (!opt || opt.type !== "select") return null;
|
|
18259
|
+
const advertised = opt.options.flatMap((o) => "group" in o ? o.options : [o]).map((o) => o.value);
|
|
18260
|
+
if (advertised.length === 0) return null;
|
|
18261
|
+
const efforts = [...advertised];
|
|
18262
|
+
if (isClaudeRuntime) {
|
|
18263
|
+
for (const extra of ["max", ULTRACODE_EFFORT]) if (!efforts.includes(extra)) efforts.push(extra);
|
|
18264
|
+
}
|
|
18265
|
+
return {
|
|
18266
|
+
current: opt.currentValue,
|
|
18267
|
+
efforts
|
|
18268
|
+
};
|
|
18269
|
+
}
|
|
18270
|
+
/**
|
|
18271
|
+
* Extract the fast-mode toggle from a session's `configOptions` (ACP `category:
|
|
18272
|
+
* "model_config"`, `type: "select"` with on/off values). Returns null when the current
|
|
18273
|
+
* model advertises no fast toggle.
|
|
18274
|
+
*/
|
|
18275
|
+
function fastOptionFrom(configOptions) {
|
|
18276
|
+
const opt = configOptions?.find((o) => o.category === "model_config" && o.type === "select");
|
|
18277
|
+
if (!opt || opt.type !== "select") return null;
|
|
18278
|
+
return { current: opt.currentValue === "on" };
|
|
18279
|
+
}
|
|
18228
18280
|
var AcpHost = class {
|
|
18229
18281
|
runtime;
|
|
18230
18282
|
opts;
|
|
@@ -18235,6 +18287,8 @@ var AcpHost = class {
|
|
|
18235
18287
|
canLoad = false;
|
|
18236
18288
|
promptCaps = {};
|
|
18237
18289
|
lastModelOptions = null;
|
|
18290
|
+
lastEffortOptions = null;
|
|
18291
|
+
lastFastOption = null;
|
|
18238
18292
|
sessionConfigs = /* @__PURE__ */ new Map();
|
|
18239
18293
|
negotiatedProtocolVersion;
|
|
18240
18294
|
constructor(runtime, opts) {
|
|
@@ -18299,8 +18353,12 @@ var AcpHost = class {
|
|
|
18299
18353
|
promptSupports(kind) {
|
|
18300
18354
|
return Boolean(this.promptCaps[kind]);
|
|
18301
18355
|
}
|
|
18302
|
-
|
|
18303
|
-
|
|
18356
|
+
/** Create a fresh ACP session. `effortOverride` (the sticky per-session effort choice,
|
|
18357
|
+
* when set) takes the place of the agent default in the Claude `_meta` — the only
|
|
18358
|
+
* channel `ultracode` can ride (the `thought_level` select rejects it); select-based
|
|
18359
|
+
* effort/model/fast overrides are layered on afterward by the daemon at turn start. */
|
|
18360
|
+
async newSession(cwd, mcpServers = [], effortOverride) {
|
|
18361
|
+
const _meta = claudeSessionMeta(effortOverride ?? this.opts.configPrefs?.reasoningEffort, this.isClaudeRuntime());
|
|
18304
18362
|
const res = await this.conn.agent.request(methods.agent.session.new, {
|
|
18305
18363
|
cwd,
|
|
18306
18364
|
mcpServers,
|
|
@@ -18308,7 +18366,7 @@ var AcpHost = class {
|
|
|
18308
18366
|
});
|
|
18309
18367
|
this.live.add(res.sessionId);
|
|
18310
18368
|
const configOptions = await this.applySessionConfig(res.sessionId, res.configOptions);
|
|
18311
|
-
this.
|
|
18369
|
+
this.refreshOptionCaches(configOptions);
|
|
18312
18370
|
this.sessionConfigs.set(res.sessionId, configOptions);
|
|
18313
18371
|
return res.sessionId;
|
|
18314
18372
|
}
|
|
@@ -18350,23 +18408,38 @@ var AcpHost = class {
|
|
|
18350
18408
|
}
|
|
18351
18409
|
return options;
|
|
18352
18410
|
}
|
|
18353
|
-
/**
|
|
18354
|
-
|
|
18411
|
+
/** Re-derive the model / effort / fast selector caches from a reconciled option set. */
|
|
18412
|
+
refreshOptionCaches(configOptions) {
|
|
18413
|
+
this.lastModelOptions = modelOptionsFrom(configOptions);
|
|
18414
|
+
this.lastEffortOptions = effortOptionsFrom(configOptions, this.isClaudeRuntime());
|
|
18415
|
+
this.lastFastOption = fastOptionFrom(configOptions);
|
|
18416
|
+
}
|
|
18417
|
+
/** The model selector advertised by the most recent session/new|load, or null if the
|
|
18418
|
+
* agent exposed none. Used by the runtime probe + status bar to report models. */
|
|
18355
18419
|
modelOptions() {
|
|
18356
18420
|
return this.lastModelOptions;
|
|
18357
18421
|
}
|
|
18422
|
+
/** The reasoning-effort selector (incl. synthetic ultracode/max on Claude runtimes)
|
|
18423
|
+
* from the most recent session/new|load, or null if none is offered. */
|
|
18424
|
+
effortOptions() {
|
|
18425
|
+
return this.lastEffortOptions;
|
|
18426
|
+
}
|
|
18427
|
+
/** The fast-mode toggle from the most recent session/new|load, or null if the current
|
|
18428
|
+
* model offers no fast mode. */
|
|
18429
|
+
fastModeOption() {
|
|
18430
|
+
return this.lastFastOption;
|
|
18431
|
+
}
|
|
18358
18432
|
/**
|
|
18359
|
-
*
|
|
18360
|
-
*
|
|
18361
|
-
*
|
|
18362
|
-
*
|
|
18363
|
-
* it's already selected. Refreshes the cached options + `lastModelOptions` on success.
|
|
18433
|
+
* Apply one select config option to an ALREADY-RUNNING session via ACP
|
|
18434
|
+
* `session/set_config_option`, refreshing the cached option set + selector caches on
|
|
18435
|
+
* success. Returns true iff applied: false when the session isn't live here, the
|
|
18436
|
+
* runtime advertises no such selector, the value isn't offered, or it's already set.
|
|
18364
18437
|
*/
|
|
18365
|
-
async
|
|
18438
|
+
async setSessionConfig(sessionId, category, value) {
|
|
18366
18439
|
if (!this.live.has(sessionId)) return false;
|
|
18367
|
-
const plan = planConfigSelection(this.sessionConfigs.get(sessionId),
|
|
18440
|
+
const plan = planConfigSelection(this.sessionConfigs.get(sessionId), category, value);
|
|
18368
18441
|
if ("skip" in plan) {
|
|
18369
|
-
this.opts.log?.debug(`acp:
|
|
18442
|
+
this.opts.log?.debug(`acp: set ${category}="${value}" on ${sessionId} not applied — ${plan.skip}`);
|
|
18370
18443
|
return false;
|
|
18371
18444
|
}
|
|
18372
18445
|
const res = await this.conn.agent.request(methods.agent.session.setConfigOption, {
|
|
@@ -18375,10 +18448,28 @@ var AcpHost = class {
|
|
|
18375
18448
|
value: plan.value
|
|
18376
18449
|
});
|
|
18377
18450
|
this.sessionConfigs.set(sessionId, res.configOptions);
|
|
18378
|
-
this.
|
|
18379
|
-
this.opts.log?.info(`acp: session ${sessionId}
|
|
18451
|
+
this.refreshOptionCaches(res.configOptions);
|
|
18452
|
+
this.opts.log?.info(`acp: session ${sessionId} ${category} set to "${value}"`);
|
|
18380
18453
|
return true;
|
|
18381
18454
|
}
|
|
18455
|
+
/** Switch the model of an already-running session (ACP `model` select) — the
|
|
18456
|
+
* mid-session counterpart of the model applied at new/load. */
|
|
18457
|
+
async setSessionModel(sessionId, model) {
|
|
18458
|
+
return this.setSessionConfig(sessionId, "model", model);
|
|
18459
|
+
}
|
|
18460
|
+
/** Switch the reasoning effort of an already-running session (ACP `thought_level`
|
|
18461
|
+
* select). Returns false for `ultracode` — it isn't a select value and can only ride
|
|
18462
|
+
* session `_meta` at new/load, so the caller relies on the override being re-applied
|
|
18463
|
+
* when the session is next (re)created or resumed. */
|
|
18464
|
+
async setSessionEffort(sessionId, effort) {
|
|
18465
|
+
if (effort === "ultracode") return false;
|
|
18466
|
+
return this.setSessionConfig(sessionId, "thought_level", effort);
|
|
18467
|
+
}
|
|
18468
|
+
/** Toggle fast mode on an already-running session (ACP `model_config` on/off select).
|
|
18469
|
+
* False when the current model offers no fast toggle. */
|
|
18470
|
+
async setSessionFastMode(sessionId, on) {
|
|
18471
|
+
return this.setSessionConfig(sessionId, "model_config", on ? "on" : "off");
|
|
18472
|
+
}
|
|
18382
18473
|
/** The ACP protocol version negotiated at initialize, or undefined before the
|
|
18383
18474
|
* handshake completed. Used by the runtime probe to report ACP coverage. */
|
|
18384
18475
|
acpProtocolVersion() {
|
|
@@ -18396,10 +18487,10 @@ var AcpHost = class {
|
|
|
18396
18487
|
* restores its own history server-side; its replayed session/update stream is
|
|
18397
18488
|
* suppressed so it isn't re-posted. Throws if the agent can't load the id
|
|
18398
18489
|
* (caller falls back to newSession). */
|
|
18399
|
-
async loadSession(sessionId, cwd) {
|
|
18490
|
+
async loadSession(sessionId, cwd, effortOverride) {
|
|
18400
18491
|
this.loadingSessions.add(sessionId);
|
|
18401
18492
|
try {
|
|
18402
|
-
const _meta = claudeSessionMeta(this.opts.configPrefs?.reasoningEffort, this.isClaudeRuntime());
|
|
18493
|
+
const _meta = claudeSessionMeta(effortOverride ?? this.opts.configPrefs?.reasoningEffort, this.isClaudeRuntime());
|
|
18403
18494
|
const res = await this.conn.agent.request(methods.agent.session.load, {
|
|
18404
18495
|
sessionId,
|
|
18405
18496
|
cwd,
|
|
@@ -18408,7 +18499,7 @@ var AcpHost = class {
|
|
|
18408
18499
|
});
|
|
18409
18500
|
this.live.add(sessionId);
|
|
18410
18501
|
const configOptions = await this.applySessionConfig(sessionId, res.configOptions);
|
|
18411
|
-
this.
|
|
18502
|
+
this.refreshOptionCaches(configOptions);
|
|
18412
18503
|
this.sessionConfigs.set(sessionId, configOptions);
|
|
18413
18504
|
this.opts.log?.info(`acp: resumed session ${sessionId} via session/load`);
|
|
18414
18505
|
} catch (err) {
|
|
@@ -24173,7 +24264,8 @@ var LocalStore = class {
|
|
|
24173
24264
|
CREATE TABLE IF NOT EXISTS sessions (
|
|
24174
24265
|
key TEXT PRIMARY KEY, agentId TEXT, platform TEXT, channel TEXT, thread TEXT,
|
|
24175
24266
|
acpSessionId TEXT, state TEXT, lastDeliveredTs TEXT, updatedAt INTEGER,
|
|
24176
|
-
usage TEXT, muted INTEGER, triggeredBy TEXT, title TEXT, modelOverride TEXT
|
|
24267
|
+
usage TEXT, muted INTEGER, triggeredBy TEXT, title TEXT, modelOverride TEXT,
|
|
24268
|
+
effortOverride TEXT, fastModeOverride INTEGER, outputModeOverride TEXT
|
|
24177
24269
|
);
|
|
24178
24270
|
-- Platform id → human display name (Slack channel/user names, daemon-resolved
|
|
24179
24271
|
-- and cached here so session read-back can label ids without a Slack call).
|
|
@@ -24219,10 +24311,11 @@ var LocalStore = class {
|
|
|
24219
24311
|
ON transcript (channel, thread, tool_call_id) WHERE tool_call_id IS NOT NULL`);
|
|
24220
24312
|
}
|
|
24221
24313
|
/** Add the `sessions.usage` (JSON token accounting), `sessions.muted` (`!stop`
|
|
24222
|
-
* thread mute), `sessions.triggeredBy`, `sessions.title
|
|
24223
|
-
* (the sticky per-session
|
|
24224
|
-
*
|
|
24225
|
-
*
|
|
24314
|
+
* thread mute), `sessions.triggeredBy`, `sessions.title`, `sessions.modelOverride`,
|
|
24315
|
+
* `sessions.effortOverride` and `sessions.fastModeOverride` (the sticky per-session
|
|
24316
|
+
* model / reasoning-effort / fast-mode choices) columns to a pre-existing DB. CREATE
|
|
24317
|
+
* TABLE IF NOT EXISTS above adds them for fresh DBs but never alters an existing table,
|
|
24318
|
+
* so upgrade in place. No-op once the columns are present. */
|
|
24226
24319
|
migrateSessionUsage() {
|
|
24227
24320
|
const cols = this.db.prepare("PRAGMA table_info(sessions)").all();
|
|
24228
24321
|
if (!cols.some((c) => c.name === "usage")) this.db.exec("ALTER TABLE sessions ADD COLUMN usage TEXT");
|
|
@@ -24230,6 +24323,9 @@ var LocalStore = class {
|
|
|
24230
24323
|
if (!cols.some((c) => c.name === "triggeredBy")) this.db.exec("ALTER TABLE sessions ADD COLUMN triggeredBy TEXT");
|
|
24231
24324
|
if (!cols.some((c) => c.name === "title")) this.db.exec("ALTER TABLE sessions ADD COLUMN title TEXT");
|
|
24232
24325
|
if (!cols.some((c) => c.name === "modelOverride")) this.db.exec("ALTER TABLE sessions ADD COLUMN modelOverride TEXT");
|
|
24326
|
+
if (!cols.some((c) => c.name === "effortOverride")) this.db.exec("ALTER TABLE sessions ADD COLUMN effortOverride TEXT");
|
|
24327
|
+
if (!cols.some((c) => c.name === "fastModeOverride")) this.db.exec("ALTER TABLE sessions ADD COLUMN fastModeOverride INTEGER");
|
|
24328
|
+
if (!cols.some((c) => c.name === "outputModeOverride")) this.db.exec("ALTER TABLE sessions ADD COLUMN outputModeOverride TEXT");
|
|
24233
24329
|
}
|
|
24234
24330
|
/**
|
|
24235
24331
|
* Pre-`kind` transcript tables keyed on (channel, thread, ts) hold only conversational
|
|
@@ -24327,6 +24423,38 @@ var LocalStore = class {
|
|
|
24327
24423
|
setModelOverride(key, model) {
|
|
24328
24424
|
this.db.prepare("UPDATE sessions SET modelOverride = ? WHERE key = ?").run(model, key);
|
|
24329
24425
|
}
|
|
24426
|
+
/** The session-scoped reasoning-effort override (set via the status-bar effort picker),
|
|
24427
|
+
* or undefined if the session runs on the agent's default. Sticky across turns and
|
|
24428
|
+
* restarts, re-applied to the ACP session on each dispatch. */
|
|
24429
|
+
getEffortOverride(key) {
|
|
24430
|
+
return this.db.prepare("SELECT effortOverride FROM sessions WHERE key = ?").get(key)?.effortOverride ?? void 0;
|
|
24431
|
+
}
|
|
24432
|
+
/** Persist the session-scoped reasoning-effort override. No-op on an unknown key. */
|
|
24433
|
+
setEffortOverride(key, effort) {
|
|
24434
|
+
this.db.prepare("UPDATE sessions SET effortOverride = ? WHERE key = ?").run(effort, key);
|
|
24435
|
+
}
|
|
24436
|
+
/** The session-scoped fast-mode override (set via the status-bar fast toggle), or
|
|
24437
|
+
* undefined if the session runs on the agent's default. Stored as 0/1; sticky across
|
|
24438
|
+
* turns and restarts, re-applied to the ACP session on each dispatch. */
|
|
24439
|
+
getFastModeOverride(key) {
|
|
24440
|
+
const row = this.db.prepare("SELECT fastModeOverride FROM sessions WHERE key = ?").get(key);
|
|
24441
|
+
return row?.fastModeOverride === null || row?.fastModeOverride === void 0 ? void 0 : row.fastModeOverride === 1;
|
|
24442
|
+
}
|
|
24443
|
+
/** Persist the session-scoped fast-mode override. No-op on an unknown key. */
|
|
24444
|
+
setFastModeOverride(key, fastMode) {
|
|
24445
|
+
this.db.prepare("UPDATE sessions SET fastModeOverride = ? WHERE key = ?").run(fastMode ? 1 : 0, key);
|
|
24446
|
+
}
|
|
24447
|
+
/** The session-scoped Slack output-mode override (set via the status-bar output picker),
|
|
24448
|
+
* or undefined if the session uses the agent's default. Daemon-side rendering verbosity
|
|
24449
|
+
* (low/medium/high) — NOT an ACP setting; picked up by the next turn's OutputConverger. */
|
|
24450
|
+
getOutputModeOverride(key) {
|
|
24451
|
+
const v = this.db.prepare("SELECT outputModeOverride FROM sessions WHERE key = ?").get(key)?.outputModeOverride;
|
|
24452
|
+
return v === "low" || v === "medium" || v === "high" ? v : void 0;
|
|
24453
|
+
}
|
|
24454
|
+
/** Persist the session-scoped Slack output-mode override. No-op on an unknown key. */
|
|
24455
|
+
setOutputModeOverride(key, mode) {
|
|
24456
|
+
this.db.prepare("UPDATE sessions SET outputModeOverride = ? WHERE key = ?").run(mode, key);
|
|
24457
|
+
}
|
|
24330
24458
|
/** Current token accounting for a session (parsed from the `usage` JSON column),
|
|
24331
24459
|
* or `{}` if none has been recorded / the JSON is unreadable. */
|
|
24332
24460
|
getUsage(key) {
|
|
@@ -24589,6 +24717,7 @@ var SessionManager = class {
|
|
|
24589
24717
|
});
|
|
24590
24718
|
let rec = this.deps.store.getSession(key);
|
|
24591
24719
|
const host = await this.deps.hostFor(agentId);
|
|
24720
|
+
const effortOverride = this.deps.store.getEffortOverride(key);
|
|
24592
24721
|
if (!rec || !rec.acpSessionId) {
|
|
24593
24722
|
const cwd = await prepareWorkspace(agent);
|
|
24594
24723
|
const mcpServers = this.deps.mcpServersFor?.({
|
|
@@ -24596,7 +24725,7 @@ var SessionManager = class {
|
|
|
24596
24725
|
channel: msg.channel,
|
|
24597
24726
|
thread
|
|
24598
24727
|
}) ?? [];
|
|
24599
|
-
const acpSessionId = await host.newSession(cwd, mcpServers);
|
|
24728
|
+
const acpSessionId = await host.newSession(cwd, mcpServers, effortOverride);
|
|
24600
24729
|
rec = {
|
|
24601
24730
|
key,
|
|
24602
24731
|
agentId,
|
|
@@ -24616,7 +24745,7 @@ var SessionManager = class {
|
|
|
24616
24745
|
if (host.loadSupported?.()) {
|
|
24617
24746
|
this.deps.store.setSessionState(key, "resuming", Date.now());
|
|
24618
24747
|
try {
|
|
24619
|
-
await host.loadSession(rec.acpSessionId, cwd);
|
|
24748
|
+
await host.loadSession(rec.acpSessionId, cwd, effortOverride);
|
|
24620
24749
|
resumed = true;
|
|
24621
24750
|
} catch {}
|
|
24622
24751
|
}
|
|
@@ -24626,7 +24755,7 @@ var SessionManager = class {
|
|
|
24626
24755
|
channel: msg.channel,
|
|
24627
24756
|
thread
|
|
24628
24757
|
}) ?? [];
|
|
24629
|
-
const acpSessionId = await host.newSession(cwd, mcpServers);
|
|
24758
|
+
const acpSessionId = await host.newSession(cwd, mcpServers, effortOverride);
|
|
24630
24759
|
rec = {
|
|
24631
24760
|
...rec,
|
|
24632
24761
|
acpSessionId,
|
|
@@ -81400,25 +81529,20 @@ function compactCount(n) {
|
|
|
81400
81529
|
if (n < 1e6) return `${(n / 1e3).toFixed(n < 1e4 ? 1 : 0)}k`;
|
|
81401
81530
|
return `${(n / 1e6).toFixed(1)}M`;
|
|
81402
81531
|
}
|
|
81403
|
-
/** Render the
|
|
81404
|
-
* `:bar_chart: *opus-4.8* ·
|
|
81405
|
-
*
|
|
81406
|
-
*
|
|
81532
|
+
/** Render the compact in-thread status line as one `markdown` block — e.g.
|
|
81533
|
+
* `:bar_chart: *opus-4.8* · fast · ctx 120k/200k (60%) · 45.2k tok`. Deliberately narrow:
|
|
81534
|
+
* effort and cost are omitted here (they live in the ⚙ modal) to keep the line short in a
|
|
81535
|
+
* Slack thread. Pure: unknown fields are dropped so a partial snapshot still yields a clean
|
|
81536
|
+
* line, and an empty snapshot degrades to a bare `:bar_chart: —` placeholder. */
|
|
81407
81537
|
function renderStatusBar(info) {
|
|
81408
81538
|
const parts = [];
|
|
81409
81539
|
if (info.model) parts.push(`*${info.model}*`);
|
|
81410
|
-
if (info.effort) parts.push(info.effort);
|
|
81411
81540
|
if (info.fastMode) parts.push("fast");
|
|
81412
81541
|
if (info.contextUsed !== void 0 && info.contextSize !== void 0 && info.contextSize > 0) {
|
|
81413
81542
|
const pct = Math.round(info.contextUsed / info.contextSize * 100);
|
|
81414
81543
|
parts.push(`ctx ${compactCount(info.contextUsed)}/${compactCount(info.contextSize)} (${pct}%)`);
|
|
81415
81544
|
} else if (info.contextUsed !== void 0) parts.push(`ctx ${compactCount(info.contextUsed)}`);
|
|
81416
81545
|
if (info.totalTokens !== void 0) parts.push(`${compactCount(info.totalTokens)} tok`);
|
|
81417
|
-
if (info.costAmount !== void 0) {
|
|
81418
|
-
const cur = info.costCurrency && info.costCurrency !== "USD" ? ` ${info.costCurrency}` : "";
|
|
81419
|
-
const sym = !info.costCurrency || info.costCurrency === "USD" ? "$" : "";
|
|
81420
|
-
parts.push(`${sym}${info.costAmount.toFixed(info.costAmount < 1 ? 3 : 2)}${cur}`);
|
|
81421
|
-
}
|
|
81422
81546
|
return `:bar_chart: ${parts.length ? parts.join(" · ") : "—"}`;
|
|
81423
81547
|
}
|
|
81424
81548
|
/** Slack action_ids for the interactive status bar + modal (matched by the connection's
|
|
@@ -81426,6 +81550,9 @@ function renderStatusBar(info) {
|
|
|
81426
81550
|
const STATUS_ACTION = {
|
|
81427
81551
|
manage: "ac_manage",
|
|
81428
81552
|
setModel: "ac_set_model",
|
|
81553
|
+
setEffort: "ac_set_effort",
|
|
81554
|
+
setFast: "ac_set_fast",
|
|
81555
|
+
setOutput: "ac_set_output",
|
|
81429
81556
|
cancel: "ac_cancel",
|
|
81430
81557
|
view: "ac_view"
|
|
81431
81558
|
};
|
|
@@ -81452,23 +81579,24 @@ function buildStatusBlocks(info, sessionKey, link) {
|
|
|
81452
81579
|
action_id: STATUS_ACTION.manage,
|
|
81453
81580
|
text: {
|
|
81454
81581
|
type: "plain_text",
|
|
81455
|
-
text: ":gear:
|
|
81582
|
+
text: ":gear:",
|
|
81456
81583
|
emoji: true
|
|
81457
81584
|
},
|
|
81458
81585
|
value: sessionKey
|
|
81459
81586
|
}
|
|
81460
81587
|
}];
|
|
81461
81588
|
}
|
|
81462
|
-
/**
|
|
81463
|
-
function
|
|
81464
|
-
return n === void 0 ? void 0 :
|
|
81589
|
+
/** Format a token count with thousands separators for the modal's usage grid. */
|
|
81590
|
+
function fmtCount(n) {
|
|
81591
|
+
return n === void 0 ? void 0 : n.toLocaleString("en-US");
|
|
81465
81592
|
}
|
|
81466
81593
|
/**
|
|
81467
81594
|
* Build the controls modal opened from the ⚙ button (a snapshot — Slack modals don't
|
|
81468
81595
|
* stream). `private_metadata` carries the session key so the modal's `block_actions`
|
|
81469
|
-
* (model
|
|
81470
|
-
*
|
|
81471
|
-
* tokens ·
|
|
81596
|
+
* (model/effort/fast/output selects, Cancel) resolve the session. Blocks: the model /
|
|
81597
|
+
* effort / fast / output selectors (each omitted when not applicable), a labeled usage
|
|
81598
|
+
* grid (context · tokens · cost · per-type breakdown), and Cancel + View-session (URL,
|
|
81599
|
+
* when `link`). The modal has room, so each metric gets its own labeled cell. Pure.
|
|
81472
81600
|
*/
|
|
81473
81601
|
function buildStatusModal(info, sessionKey, link) {
|
|
81474
81602
|
const blocks = [];
|
|
@@ -81506,23 +81634,115 @@ function buildStatusModal(info, sessionKey, link) {
|
|
|
81506
81634
|
text: `*Model:* ${info.model}`
|
|
81507
81635
|
}
|
|
81508
81636
|
});
|
|
81509
|
-
const
|
|
81510
|
-
|
|
81511
|
-
|
|
81512
|
-
|
|
81513
|
-
|
|
81514
|
-
|
|
81515
|
-
|
|
81516
|
-
|
|
81517
|
-
|
|
81518
|
-
|
|
81637
|
+
const efforts = info.efforts ?? [];
|
|
81638
|
+
if (efforts.length > 0) {
|
|
81639
|
+
const opts = info.effort && !efforts.includes(info.effort) ? [info.effort, ...efforts] : efforts;
|
|
81640
|
+
const option = (e) => ({
|
|
81641
|
+
text: {
|
|
81642
|
+
type: "plain_text",
|
|
81643
|
+
text: clampTo(e, 75)
|
|
81644
|
+
},
|
|
81645
|
+
value: e
|
|
81646
|
+
});
|
|
81647
|
+
blocks.push({
|
|
81648
|
+
type: "section",
|
|
81649
|
+
text: {
|
|
81650
|
+
type: "mrkdwn",
|
|
81651
|
+
text: "*Effort*"
|
|
81652
|
+
},
|
|
81653
|
+
accessory: {
|
|
81654
|
+
type: "static_select",
|
|
81655
|
+
action_id: STATUS_ACTION.setEffort,
|
|
81656
|
+
placeholder: {
|
|
81657
|
+
type: "plain_text",
|
|
81658
|
+
text: "Effort"
|
|
81659
|
+
},
|
|
81660
|
+
...info.effort ? { initial_option: option(info.effort) } : {},
|
|
81661
|
+
options: opts.map(option)
|
|
81662
|
+
}
|
|
81663
|
+
});
|
|
81664
|
+
}
|
|
81665
|
+
if (info.fastModeAvailable) {
|
|
81666
|
+
const fastOpt = (v) => ({
|
|
81667
|
+
text: {
|
|
81668
|
+
type: "plain_text",
|
|
81669
|
+
text: v === "on" ? "On" : "Off"
|
|
81670
|
+
},
|
|
81671
|
+
value: v
|
|
81672
|
+
});
|
|
81673
|
+
const current = info.fastMode ? "on" : "off";
|
|
81674
|
+
blocks.push({
|
|
81675
|
+
type: "section",
|
|
81676
|
+
text: {
|
|
81677
|
+
type: "mrkdwn",
|
|
81678
|
+
text: "*Fast mode*"
|
|
81679
|
+
},
|
|
81680
|
+
accessory: {
|
|
81681
|
+
type: "static_select",
|
|
81682
|
+
action_id: STATUS_ACTION.setFast,
|
|
81683
|
+
placeholder: {
|
|
81684
|
+
type: "plain_text",
|
|
81685
|
+
text: "Fast mode"
|
|
81686
|
+
},
|
|
81687
|
+
initial_option: fastOpt(current),
|
|
81688
|
+
options: [fastOpt("on"), fastOpt("off")]
|
|
81689
|
+
}
|
|
81690
|
+
});
|
|
81691
|
+
}
|
|
81692
|
+
if (info.outputMode) {
|
|
81693
|
+
const modeOpt = (v) => ({
|
|
81694
|
+
text: {
|
|
81695
|
+
type: "plain_text",
|
|
81696
|
+
text: v
|
|
81697
|
+
},
|
|
81698
|
+
value: v
|
|
81699
|
+
});
|
|
81700
|
+
blocks.push({
|
|
81701
|
+
type: "section",
|
|
81702
|
+
text: {
|
|
81703
|
+
type: "mrkdwn",
|
|
81704
|
+
text: "*Output*"
|
|
81705
|
+
},
|
|
81706
|
+
accessory: {
|
|
81707
|
+
type: "static_select",
|
|
81708
|
+
action_id: STATUS_ACTION.setOutput,
|
|
81709
|
+
placeholder: {
|
|
81710
|
+
type: "plain_text",
|
|
81711
|
+
text: "Output"
|
|
81712
|
+
},
|
|
81713
|
+
initial_option: modeOpt(info.outputMode),
|
|
81714
|
+
options: [
|
|
81715
|
+
modeOpt("low"),
|
|
81716
|
+
modeOpt("medium"),
|
|
81717
|
+
modeOpt("high")
|
|
81718
|
+
]
|
|
81719
|
+
}
|
|
81720
|
+
});
|
|
81721
|
+
}
|
|
81722
|
+
const field = (label, value) => value === void 0 ? void 0 : {
|
|
81723
|
+
type: "mrkdwn",
|
|
81724
|
+
text: `*${label}*\n${value}`
|
|
81725
|
+
};
|
|
81726
|
+
let contextValue;
|
|
81727
|
+
if (info.contextUsed !== void 0) contextValue = info.contextSize && info.contextSize > 0 ? `${fmtCount(info.contextUsed)} / ${fmtCount(info.contextSize)} (${Math.round(info.contextUsed / info.contextSize * 100)}%)` : fmtCount(info.contextUsed);
|
|
81728
|
+
let costValue;
|
|
81729
|
+
if (info.costAmount !== void 0) {
|
|
81730
|
+
const cur = info.costCurrency && info.costCurrency !== "USD" ? ` ${info.costCurrency}` : "";
|
|
81731
|
+
costValue = `${!info.costCurrency || info.costCurrency === "USD" ? "$" : ""}${info.costAmount.toFixed(info.costAmount < 1 ? 3 : 2)}${cur}`;
|
|
81732
|
+
}
|
|
81733
|
+
const fields = [
|
|
81734
|
+
field("Context", contextValue),
|
|
81735
|
+
field("Total tokens", fmtCount(info.totalTokens)),
|
|
81736
|
+
field("Cost", costValue),
|
|
81737
|
+
field("Input", fmtCount(info.inputTokens)),
|
|
81738
|
+
field("Output", fmtCount(info.outputTokens)),
|
|
81739
|
+
field("Thought", fmtCount(info.thoughtTokens)),
|
|
81740
|
+
field("Cache read", fmtCount(info.cachedReadTokens)),
|
|
81741
|
+
field("Cache write", fmtCount(info.cachedWriteTokens))
|
|
81519
81742
|
].filter(Boolean);
|
|
81520
|
-
blocks.push({
|
|
81521
|
-
type: "
|
|
81522
|
-
|
|
81523
|
-
type: "mrkdwn",
|
|
81524
|
-
text: detail.join(" · ")
|
|
81525
|
-
}]
|
|
81743
|
+
if (fields.length) blocks.push({
|
|
81744
|
+
type: "section",
|
|
81745
|
+
fields
|
|
81526
81746
|
});
|
|
81527
81747
|
const actions = [{
|
|
81528
81748
|
type: "button",
|
|
@@ -81857,6 +82077,36 @@ var SlackConnection = class {
|
|
|
81857
82077
|
model
|
|
81858
82078
|
});
|
|
81859
82079
|
});
|
|
82080
|
+
this.app.action(STATUS_ACTION.setEffort, async ({ ack, action, body }) => {
|
|
82081
|
+
await ack();
|
|
82082
|
+
const sessionKey = body?.view?.private_metadata ?? action.block_id;
|
|
82083
|
+
const effort = action.selected_option?.value;
|
|
82084
|
+
if (sessionKey && effort) this.deps.onStatusAction?.({
|
|
82085
|
+
kind: "set-effort",
|
|
82086
|
+
sessionKey,
|
|
82087
|
+
effort
|
|
82088
|
+
});
|
|
82089
|
+
});
|
|
82090
|
+
this.app.action(STATUS_ACTION.setFast, async ({ ack, action, body }) => {
|
|
82091
|
+
await ack();
|
|
82092
|
+
const sessionKey = body?.view?.private_metadata ?? action.block_id;
|
|
82093
|
+
const value = action.selected_option?.value;
|
|
82094
|
+
if (sessionKey && value) this.deps.onStatusAction?.({
|
|
82095
|
+
kind: "set-fast",
|
|
82096
|
+
sessionKey,
|
|
82097
|
+
fastMode: value === "on"
|
|
82098
|
+
});
|
|
82099
|
+
});
|
|
82100
|
+
this.app.action(STATUS_ACTION.setOutput, async ({ ack, action, body }) => {
|
|
82101
|
+
await ack();
|
|
82102
|
+
const sessionKey = body?.view?.private_metadata ?? action.block_id;
|
|
82103
|
+
const mode = action.selected_option?.value;
|
|
82104
|
+
if (sessionKey && (mode === "low" || mode === "medium" || mode === "high")) this.deps.onStatusAction?.({
|
|
82105
|
+
kind: "set-output",
|
|
82106
|
+
sessionKey,
|
|
82107
|
+
outputMode: mode
|
|
82108
|
+
});
|
|
82109
|
+
});
|
|
81860
82110
|
this.app.action(STATUS_ACTION.cancel, async ({ ack, action, body }) => {
|
|
81861
82111
|
await ack();
|
|
81862
82112
|
const sessionKey = body?.view?.private_metadata ?? action.value;
|
|
@@ -83771,6 +84021,12 @@ var CpClient = class {
|
|
|
83771
84021
|
case "webchat/set-model":
|
|
83772
84022
|
this.deps.onWebchatSetModel?.(frame.payload);
|
|
83773
84023
|
return;
|
|
84024
|
+
case "webchat/set-effort":
|
|
84025
|
+
this.deps.onWebchatSetEffort?.(frame.payload);
|
|
84026
|
+
return;
|
|
84027
|
+
case "webchat/set-fast":
|
|
84028
|
+
this.deps.onWebchatSetFast?.(frame.payload);
|
|
84029
|
+
return;
|
|
83774
84030
|
case "webchat/cancel":
|
|
83775
84031
|
this.deps.onWebchatCancel?.(frame.payload);
|
|
83776
84032
|
return;
|
|
@@ -85264,10 +85520,68 @@ var Daemon = class Daemon {
|
|
|
85264
85520
|
if (!rec?.acpSessionId || !this.pending.has(rec.acpSessionId)) return;
|
|
85265
85521
|
this.interruptTurn(rec.agentId, rec.acpSessionId, key, "cancel");
|
|
85266
85522
|
}
|
|
85523
|
+
/** Switch a session's reasoning effort by its local key — the effort counterpart of
|
|
85524
|
+
* {@link setModelByKey}. Records the sticky override and, if the ACP session is warm,
|
|
85525
|
+
* applies it live via the `thought_level` select. `ultracode` can't ride the select
|
|
85526
|
+
* (setSessionEffort returns false); it's honored via session `_meta` when the session
|
|
85527
|
+
* is next (re)created or resumed, and the override still shows on the bar meanwhile. */
|
|
85528
|
+
setEffortByKey(key, effort) {
|
|
85529
|
+
const rec = this.store.getSession(key);
|
|
85530
|
+
if (!rec) return;
|
|
85531
|
+
this.store.setEffortOverride(key, effort);
|
|
85532
|
+
this.log.info(`session ${key} effort override → "${effort}"`);
|
|
85533
|
+
const acpSessionId = rec.acpSessionId;
|
|
85534
|
+
const host = this.hosts.get(rec.agentId);
|
|
85535
|
+
if (!acpSessionId || !host?.hasSession(acpSessionId)) {
|
|
85536
|
+
this.refreshStatusBarForKey(key);
|
|
85537
|
+
return;
|
|
85538
|
+
}
|
|
85539
|
+
host.setSessionEffort(acpSessionId, effort).then(() => this.refreshStatusBarForKey(key)).catch((err) => this.log.warn(`set-effort failed: ${err.message}`));
|
|
85540
|
+
}
|
|
85541
|
+
/** Toggle a session's fast mode by its local key — the fast-mode counterpart of
|
|
85542
|
+
* {@link setModelByKey}. Records the sticky override and applies it live when the
|
|
85543
|
+
* current model offers a fast toggle. */
|
|
85544
|
+
setFastByKey(key, fastMode) {
|
|
85545
|
+
const rec = this.store.getSession(key);
|
|
85546
|
+
if (!rec) return;
|
|
85547
|
+
this.store.setFastModeOverride(key, fastMode);
|
|
85548
|
+
this.log.info(`session ${key} fast-mode override → ${fastMode}`);
|
|
85549
|
+
const acpSessionId = rec.acpSessionId;
|
|
85550
|
+
const host = this.hosts.get(rec.agentId);
|
|
85551
|
+
if (!acpSessionId || !host?.hasSession(acpSessionId)) {
|
|
85552
|
+
this.refreshStatusBarForKey(key);
|
|
85553
|
+
return;
|
|
85554
|
+
}
|
|
85555
|
+
host.setSessionFastMode(acpSessionId, fastMode).then(() => this.refreshStatusBarForKey(key)).catch((err) => this.log.warn(`set-fast failed: ${err.message}`));
|
|
85556
|
+
}
|
|
85557
|
+
/** Re-emit the status bar for a session's in-flight turn (if any) so a config change
|
|
85558
|
+
* (model / effort / fast) is reflected. No-op when the session is idle. */
|
|
85559
|
+
refreshStatusBarForKey(key) {
|
|
85560
|
+
const rec = this.store.getSession(key);
|
|
85561
|
+
const p = rec?.acpSessionId ? this.pending.get(rec.acpSessionId) : void 0;
|
|
85562
|
+
if (p) this.emitStatusBar(p);
|
|
85563
|
+
}
|
|
85564
|
+
/** Set a session's Slack output verbosity by its local key. Purely daemon-side (no ACP):
|
|
85565
|
+
* the next turn's OutputConverger reads this override, so an in-flight turn keeps its
|
|
85566
|
+
* current verbosity and the change takes effect from the next turn. */
|
|
85567
|
+
setOutputModeByKey(key, mode) {
|
|
85568
|
+
if (!this.store.getSession(key)) return;
|
|
85569
|
+
this.store.setOutputModeOverride(key, mode);
|
|
85570
|
+
this.log.info(`session ${key} output-mode override → "${mode}"`);
|
|
85571
|
+
this.refreshStatusBarForKey(key);
|
|
85572
|
+
}
|
|
85267
85573
|
/** Handle a webchat in-session model switch (C→D `webchat/set-model`). */
|
|
85268
85574
|
handleWebchatSetModel(m) {
|
|
85269
85575
|
this.setModelByKey(this.webchatSessionKey(m.conversationId, m.agentId), m.model);
|
|
85270
85576
|
}
|
|
85577
|
+
/** Handle a webchat in-session effort switch (C→D `webchat/set-effort`). */
|
|
85578
|
+
handleWebchatSetEffort(m) {
|
|
85579
|
+
this.setEffortByKey(this.webchatSessionKey(m.conversationId, m.agentId), m.effort);
|
|
85580
|
+
}
|
|
85581
|
+
/** Handle a webchat in-session fast-mode toggle (C→D `webchat/set-fast`). */
|
|
85582
|
+
handleWebchatSetFast(m) {
|
|
85583
|
+
this.setFastByKey(this.webchatSessionKey(m.conversationId, m.agentId), m.fastMode);
|
|
85584
|
+
}
|
|
85271
85585
|
/** Handle a webchat cancel (C→D `webchat/cancel`) — the status-bar "Cancel". Interrupts
|
|
85272
85586
|
* the conversation's in-flight turn like `!cancel` (no mute; follow-ups still dispatch).
|
|
85273
85587
|
* Resolved by conversationId (the frame carries no agentId). No-op when idle. */
|
|
@@ -85278,11 +85592,20 @@ var Daemon = class Daemon {
|
|
|
85278
85592
|
}
|
|
85279
85593
|
this.log.debug(`webchat cancel: no in-flight turn for conversation ${m.conversationId}`);
|
|
85280
85594
|
}
|
|
85281
|
-
/** Route a Slack status-bar Block Kit interaction (model
|
|
85282
|
-
* shared key-based cores. `sessionKey` rides the block; no-op on
|
|
85595
|
+
/** Route a Slack status-bar Block Kit interaction (model / effort / fast select or the
|
|
85596
|
+
* Cancel button) to the shared key-based cores. `sessionKey` rides the block; no-op on
|
|
85597
|
+
* an unknown key. */
|
|
85283
85598
|
handleSlackStatusAction(a) {
|
|
85284
85599
|
if (a.kind === "cancel") this.cancelSessionByKey(a.sessionKey);
|
|
85285
|
-
else if (a.
|
|
85600
|
+
else if (a.kind === "set-model") {
|
|
85601
|
+
if (a.model) this.setModelByKey(a.sessionKey, a.model);
|
|
85602
|
+
} else if (a.kind === "set-effort") {
|
|
85603
|
+
if (a.effort) this.setEffortByKey(a.sessionKey, a.effort);
|
|
85604
|
+
} else if (a.kind === "set-fast") {
|
|
85605
|
+
if (a.fastMode !== void 0) this.setFastByKey(a.sessionKey, a.fastMode);
|
|
85606
|
+
} else if (a.kind === "set-output") {
|
|
85607
|
+
if (a.outputMode) this.setOutputModeByKey(a.sessionKey, a.outputMode);
|
|
85608
|
+
}
|
|
85286
85609
|
}
|
|
85287
85610
|
/** All of our own connections' bot identities (both `U…` user ids and `B…`
|
|
85288
85611
|
* bot_ids), so we recognize self-echoes regardless of which field Slack sends. */
|
|
@@ -85457,12 +85780,13 @@ var Daemon = class Daemon {
|
|
|
85457
85780
|
this.log.debug(`dispatch: skipped for agent "${agentId}" (draining)`);
|
|
85458
85781
|
return null;
|
|
85459
85782
|
}
|
|
85460
|
-
const
|
|
85783
|
+
const agent = this.agents.get(agentId);
|
|
85461
85784
|
const rec = new TranscriptRecorder();
|
|
85462
85785
|
const replyConn = msg.headless || webchat ? void 0 : this.replyConnFor(agentId, integrationId);
|
|
85463
85786
|
const wasRunning = this.hostStarts.has(agentId);
|
|
85464
85787
|
const statusThread = msg.thread ?? msg.msgId;
|
|
85465
85788
|
const key = sessionKey(msg.platform, msg.channel, statusThread, agentId);
|
|
85789
|
+
const conv = new OutputConverger(this.store.getOutputModeOverride(key) ?? agent.output.mode);
|
|
85466
85790
|
replyConn?.setStatus(msg.channel, statusThread, wasRunning ? "is thinking…" : "is starting up…");
|
|
85467
85791
|
let handled;
|
|
85468
85792
|
try {
|
|
@@ -85506,6 +85830,10 @@ var Daemon = class Daemon {
|
|
|
85506
85830
|
const host = await this.ensureHostAsync(agentId);
|
|
85507
85831
|
const override = this.store.getModelOverride(key);
|
|
85508
85832
|
if (override) await host.setSessionModel(sessionId, override).catch((err) => this.log.debug(`model override "${override}" not applied: ${err.message}`));
|
|
85833
|
+
const effortOverride = this.store.getEffortOverride(key);
|
|
85834
|
+
if (effortOverride) await host.setSessionEffort(sessionId, effortOverride).catch((err) => this.log.debug(`effort override "${effortOverride}" not applied: ${err.message}`));
|
|
85835
|
+
const fastOverride = this.store.getFastModeOverride(key);
|
|
85836
|
+
if (fastOverride !== void 0) await host.setSessionFastMode(sessionId, fastOverride).catch((err) => this.log.debug(`fast-mode override ${fastOverride} not applied: ${err.message}`));
|
|
85509
85837
|
if (!wasRunning) replyConn?.setStatus(msg.channel, statusThread, "is thinking…");
|
|
85510
85838
|
this.emitStatusBar(p);
|
|
85511
85839
|
const { stopReason, usage } = await host.prompt(sessionId, blocks);
|
|
@@ -85685,11 +86013,16 @@ var Daemon = class Daemon {
|
|
|
85685
86013
|
statusInfoFrom(agentId, sessionKey, acpSessionId, opts = {}) {
|
|
85686
86014
|
const agent = this.agents.get(agentId);
|
|
85687
86015
|
const usage = this.store.getUsage(sessionKey);
|
|
85688
|
-
const
|
|
86016
|
+
const host = this.hosts.get(agentId);
|
|
86017
|
+
const model = host?.modelOptions?.();
|
|
86018
|
+
const effort = host?.effortOptions?.();
|
|
86019
|
+
const fast = host?.fastModeOption?.();
|
|
86020
|
+
const effortOverride = this.store.getEffortOverride(sessionKey);
|
|
86021
|
+
const fastOverride = this.store.getFastModeOverride(sessionKey);
|
|
85689
86022
|
return {
|
|
85690
86023
|
model: model?.current ?? agent?.runtimeOverrides?.model,
|
|
85691
|
-
effort: agent?.reasoningEffort,
|
|
85692
|
-
fastMode: agent?.fastMode,
|
|
86024
|
+
effort: effortOverride ?? effort?.current ?? agent?.reasoningEffort,
|
|
86025
|
+
fastMode: fastOverride ?? fast?.current ?? agent?.fastMode,
|
|
85693
86026
|
contextUsed: usage.contextUsed,
|
|
85694
86027
|
contextSize: usage.contextSize,
|
|
85695
86028
|
totalTokens: usage.totalTokens,
|
|
@@ -85700,9 +86033,12 @@ var Daemon = class Daemon {
|
|
|
85700
86033
|
outputTokens: usage.outputTokens,
|
|
85701
86034
|
thoughtTokens: usage.thoughtTokens,
|
|
85702
86035
|
cachedReadTokens: usage.cachedReadTokens,
|
|
85703
|
-
cachedWriteTokens: usage.cachedWriteTokens
|
|
86036
|
+
cachedWriteTokens: usage.cachedWriteTokens,
|
|
86037
|
+
outputMode: this.store.getOutputModeOverride(sessionKey) ?? agent?.output?.mode
|
|
85704
86038
|
} : {},
|
|
85705
86039
|
...model?.models?.length ? { models: model.models } : {},
|
|
86040
|
+
...effort?.efforts?.length ? { efforts: effort.efforts } : {},
|
|
86041
|
+
...fast ? { fastModeAvailable: true } : {},
|
|
85706
86042
|
...acpSessionId ? { sessionId: acpSessionId } : {}
|
|
85707
86043
|
};
|
|
85708
86044
|
}
|
|
@@ -86304,6 +86640,8 @@ var Daemon = class Daemon {
|
|
|
86304
86640
|
onWebchatMessage: (m) => this.handleWebchatMessage(m),
|
|
86305
86641
|
onWebchatClose: (m) => this.handleWebchatClose(m),
|
|
86306
86642
|
onWebchatSetModel: (m) => this.handleWebchatSetModel(m),
|
|
86643
|
+
onWebchatSetEffort: (m) => this.handleWebchatSetEffort(m),
|
|
86644
|
+
onWebchatSetFast: (m) => this.handleWebchatSetFast(m),
|
|
86307
86645
|
onWebchatCancel: (m) => this.handleWebchatCancel(m),
|
|
86308
86646
|
clock: systemClock,
|
|
86309
86647
|
connect: () => ClientTransport.dial(url),
|