switchroom 0.19.39 → 0.19.41
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/agent-scheduler/index.js +10 -1
- package/dist/auth-broker/index.js +12 -3
- package/dist/cli/notion-write-pretool.mjs +10 -1
- package/dist/cli/switchroom.js +562 -196
- package/dist/host-control/main.js +287 -20
- package/dist/vault/approvals/kernel-server.js +12 -3
- package/dist/vault/broker/server.js +12 -3
- package/package.json +1 -1
- package/profiles/_base/start.sh.hbs +10 -0
- package/telegram-plugin/bridge/bridge.ts +2 -2
- package/telegram-plugin/dist/bridge/bridge.js +10 -2
- package/telegram-plugin/dist/gateway/gateway.js +549 -232
- package/telegram-plugin/dist/server.js +10 -2
- package/telegram-plugin/gateway/backstop-delivery.ts +48 -0
- package/telegram-plugin/gateway/checklist-fallback.ts +370 -0
- package/telegram-plugin/gateway/compaction-marker.ts +84 -0
- package/telegram-plugin/gateway/gateway.ts +72 -72
- package/telegram-plugin/gateway/liveness-wiring.ts +15 -0
- package/telegram-plugin/gateway/outbound-send-path.ts +20 -0
- package/telegram-plugin/gateway/outbox-sweep.ts +116 -18
- package/telegram-plugin/gateway/silence-poke-session-event.ts +13 -0
- package/telegram-plugin/gateway/stream-render.ts +39 -1
- package/telegram-plugin/gateway/turn-record-status.ts +80 -0
- package/telegram-plugin/hooks/compaction-marker-precompact.mjs +70 -0
- package/telegram-plugin/hooks/hooks.json +11 -0
- package/telegram-plugin/session-tail.ts +20 -0
- package/telegram-plugin/silence-poke.ts +28 -0
- package/telegram-plugin/tests/checklist-fallback.test.ts +317 -0
- package/telegram-plugin/tests/gateway-outbound-redact.test.ts +10 -6
- package/telegram-plugin/tests/outbox-delivery.test.ts +38 -1
- package/telegram-plugin/tests/outbox-flush-ack-claim-race.test.ts +213 -0
- package/telegram-plugin/tests/outbox-reply-then-recap-e2e.test.ts +1 -1
- package/telegram-plugin/tests/outbox-sweep-flood-breaker.test.ts +4 -4
- package/telegram-plugin/tests/outbox-sweep-listen-button.test.ts +71 -8
- package/telegram-plugin/tests/send-reply-golden.test.ts +47 -0
- package/telegram-plugin/tests/silence-poke-compaction.test.ts +222 -0
- package/telegram-plugin/tests/turn-record-status.test.ts +62 -0
|
@@ -4013,7 +4013,7 @@ var init_zod = __esm(() => {
|
|
|
4013
4013
|
});
|
|
4014
4014
|
|
|
4015
4015
|
// src/memory/observation-scopes.ts
|
|
4016
|
-
var OBSERVATION_SCOPES;
|
|
4016
|
+
var OBSERVATION_SCOPES, OBSERVATION_SCOPE_STRATEGIES;
|
|
4017
4017
|
var init_observation_scopes = __esm(() => {
|
|
4018
4018
|
OBSERVATION_SCOPES = [
|
|
4019
4019
|
"per_tag",
|
|
@@ -4021,10 +4021,16 @@ var init_observation_scopes = __esm(() => {
|
|
|
4021
4021
|
"all_combinations",
|
|
4022
4022
|
"shared"
|
|
4023
4023
|
];
|
|
4024
|
+
OBSERVATION_SCOPE_STRATEGIES = [
|
|
4025
|
+
"curated",
|
|
4026
|
+
"shared",
|
|
4027
|
+
"combined",
|
|
4028
|
+
"off"
|
|
4029
|
+
];
|
|
4024
4030
|
});
|
|
4025
4031
|
|
|
4026
4032
|
// src/config/schema.ts
|
|
4027
|
-
var CodeRepoEntrySchema, AgentBindMountSchema, HttpDiffPollSchema, PollSpecSchema, TelegramMessageActionSchema, WebhookActionSchema, ActionSpecSchema, ScheduleEntrySchema, AgentSoulSchema, AgentToolsSchema, ObservationScopesSchema, AgentMemorySchema, HookEntrySchema, AgentHooksSchema, SubagentSchema, SessionSchema, SessionContinuitySchema, webhookDispatchRule, TelegramChannelSchema, ChannelsSchema, TIMEZONE_REGEX, ApproverIdSchema, GoogleWorkspaceTierSchema, GoogleWorkspaceConfigSchema, LiteLLMConfigSchema, HindsightPerOpLlmSchema, HindsightConfigSchema, MicrosoftWorkspaceConfigSchema, NotionWorkspaceConfigSchema, AgentGoogleWorkspaceConfigSchema, MicrosoftAccountEmailSchema, MicrosoftToolTokenSchema, MicrosoftAccountBindingSchema, AgentMicrosoftWorkspaceConfigSchema, AgentNotionWorkspaceConfigSchema, ReactionsSchema, ReactionDispatchSchema, releaseBlockFields, ReleaseBlock, RootReleaseBlock, NetworkIsolationSchema, servesField, knowsField, profileFields, ProfileSchema, _omitExtends, defaultsFields, AgentDefaultsSchema, AgentSchema, TelegramConfigSchema, MemoryBackendConfigSchema, VaultConfigSchema, QuotaConfigSchema, AutoReleaseCheckSchema, HostControlConfigSchema, WebServiceConfigSchema, FleetHealthConfigSchema, HostdConfigSchema, CronEgressSchema, CronConfigSchema, UserSchema, SwitchroomConfigSchema;
|
|
4033
|
+
var CodeRepoEntrySchema, AgentBindMountSchema, HttpDiffPollSchema, PollSpecSchema, TelegramMessageActionSchema, WebhookActionSchema, ActionSpecSchema, ScheduleEntrySchema, AgentSoulSchema, AgentToolsSchema, ObservationScopesSchema, ObservationScopeStrategySchema, AgentMemorySchema, HookEntrySchema, AgentHooksSchema, SubagentSchema, SessionSchema, SessionContinuitySchema, webhookDispatchRule, TelegramChannelSchema, ChannelsSchema, TIMEZONE_REGEX, ApproverIdSchema, GoogleWorkspaceTierSchema, GoogleWorkspaceConfigSchema, LiteLLMConfigSchema, HindsightPerOpLlmSchema, HindsightConfigSchema, MicrosoftWorkspaceConfigSchema, NotionWorkspaceConfigSchema, AgentGoogleWorkspaceConfigSchema, MicrosoftAccountEmailSchema, MicrosoftToolTokenSchema, MicrosoftAccountBindingSchema, AgentMicrosoftWorkspaceConfigSchema, AgentNotionWorkspaceConfigSchema, ReactionsSchema, ReactionDispatchSchema, releaseBlockFields, ReleaseBlock, RootReleaseBlock, NetworkIsolationSchema, servesField, knowsField, profileFields, ProfileSchema, _omitExtends, defaultsFields, AgentDefaultsSchema, AgentSchema, TelegramConfigSchema, MemoryBackendConfigSchema, VaultConfigSchema, QuotaConfigSchema, AutoReleaseCheckSchema, HostControlConfigSchema, WebServiceConfigSchema, FleetHealthConfigSchema, HostdConfigSchema, CronEgressSchema, CronConfigSchema, UserSchema, SwitchroomConfigSchema;
|
|
4028
4034
|
var init_schema = __esm(() => {
|
|
4029
4035
|
init_zod();
|
|
4030
4036
|
init_observation_scopes();
|
|
@@ -4139,7 +4145,8 @@ var init_schema = __esm(() => {
|
|
|
4139
4145
|
allow: exports_external.array(exports_external.string()).default([]).describe("Allowed tools (use ['all'] for unrestricted)"),
|
|
4140
4146
|
deny: exports_external.array(exports_external.string()).default([]).describe("Denied tools (overrides allow)")
|
|
4141
4147
|
}).optional();
|
|
4142
|
-
ObservationScopesSchema = exports_external.enum(OBSERVATION_SCOPES).optional().describe("
|
|
4148
|
+
ObservationScopesSchema = exports_external.enum(OBSERVATION_SCOPES).optional().describe("Operator PIN for the per-row observation scope, overriding the " + 'default `curated` strategy (see docs/configuration.md). "shared" ' + "forces Hindsight's consolidation to write EVERY observation into ONE " + "global untagged scope — what several agents pooling one bank want so " + "their observations merge rather than sitting in parallel silos. " + '"combined" is the pin form of opting out (restores the pre-#4035 ' + "engine default). UNSET does NOT mean 'nothing on the wire': the " + "`curated` strategy still computes a scope per retain. Applies to " + "every retain path (Stop hook, " + "sidechain, boot reconcile, queue drain, backfill, session-handoff " + "mirror) and is carried on the queued payload, so a retain that fails " + "now and drains later still lands in this scope. Accepted values: " + `${OBSERVATION_SCOPES.join(", ")}. ` + "Cascade: override (per-agent wins over default).");
|
|
4149
|
+
ObservationScopeStrategySchema = exports_external.enum(OBSERVATION_SCOPE_STRATEGIES).optional().describe("Per-retain strategy that decides how the observation scope is " + 'computed when no `observation_scopes` pin is set. "curated" ' + "(the default since #4035) strips volatile per-session provenance " + "tags from each retain's consolidation scope — keeping the stable " + "semantic ones on the source fact — so an agent's observations dedup " + "and merge across sessions instead of pocketing one-per-session. " + '"shared" sends every retain to the one global untagged scope. ' + '"combined" / "off" opt OUT: no per-row scope goes on the wire, ' + "restoring the pre-feature engine default (byte-identical to an " + "unconfigured client). OMITTED BY DEFAULT: unset leaves the plugin's " + "own default (`curated`) in force. A manual `observation_scopes` pin " + "wins over this strategy. Accepted values: " + `${OBSERVATION_SCOPE_STRATEGIES.join(", ")}. ` + "Cascade: override (per-agent wins over default).");
|
|
4143
4150
|
AgentMemorySchema = exports_external.object({
|
|
4144
4151
|
collection: exports_external.string().describe("Hindsight collection name for this agent"),
|
|
4145
4152
|
auto_recall: exports_external.boolean().default(true).describe("Auto-search memories before each response"),
|
|
@@ -4175,6 +4182,7 @@ var init_schema = __esm(() => {
|
|
|
4175
4182
|
}).optional().describe("Personality traits (1-5 each) steering how this bank frames recall, " + "reflect, and observation synthesis — a coach leans empathy-high, a " + "lawyer/analyst leans skepticism/literalism-high. Maps to the engine's " + "flat `disposition_skepticism`/`_literalism`/`_empathy` fields. " + "Cascade: per-key merge (an agent overrides individual traits and " + "inherits the rest, matching `recall`)."),
|
|
4176
4183
|
directive_capture_nudge: exports_external.boolean().optional().describe("Deterministic directive-capture nudge (issue #2848 Stage B). When " + "on (switchroom default true — Stage A measured a ~55% miss rate on " + "durable corrections), the auto-recall hook regex-detects correction " + '/ standing-rule-shaped inbound ("always/never …", "from now on …", ' + `"stop doing …", a stated preference, "that's wrong, it's …") and ` + "appends a terse advisory to the turn's context telling the model to " + "persist the rule with mcp__hindsight__create_directive if it IS " + "durable. Detection is pure regex — the model does the judgment " + "in-session and calls create_directive itself (no model callsite, no " + "silent hook-side write). Set false to disable per-agent. " + "Cascade: override (per-agent wins over default)."),
|
|
4177
4184
|
observation_scopes: ObservationScopesSchema,
|
|
4185
|
+
observation_scope_strategy: ObservationScopeStrategySchema,
|
|
4178
4186
|
recall: exports_external.object({
|
|
4179
4187
|
max_memories: exports_external.number().int().min(0).optional().describe("Cap on the number of memories injected into the prompt by " + "auto-recall, regardless of token budget. Plugin default is 12. " + "0 disables the cap (all memories Hindsight returns are injected)."),
|
|
4180
4188
|
cache_ttl_secs: exports_external.number().int().min(0).optional().describe("Per-session recall cache TTL in seconds. When > 0, identical " + "(prompt, bank) within the same session reuse the cached recall " + "result instead of round-tripping to Hindsight. 0 disables. " + "Default is 600 (10 min) for switchroom-managed agents."),
|
|
@@ -4575,6 +4583,7 @@ var init_schema = __esm(() => {
|
|
|
4575
4583
|
isolation: exports_external.enum(["default", "strict"]).optional(),
|
|
4576
4584
|
directive_capture_nudge: exports_external.boolean().optional(),
|
|
4577
4585
|
observation_scopes: ObservationScopesSchema,
|
|
4586
|
+
observation_scope_strategy: ObservationScopeStrategySchema,
|
|
4578
4587
|
recall: exports_external.object({
|
|
4579
4588
|
max_memories: exports_external.number().int().min(0).optional(),
|
|
4580
4589
|
cache_ttl_secs: exports_external.number().int().min(0).optional(),
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "switchroom",
|
|
3
3
|
"//version": "NOT the release version — source of truth is the git tag, resolved by scripts/build.mjs:resolveVersion() (see CLAUDE.md > Standard release process). This field is stale by design and only the Layer-4 dev/non-tag fallback for build.mjs + src/cli/resolve-version.ts; do NOT bump it expecting a release to pick it up. npm-pack tarball naming needs a real version — do that as an UNCOMMITTED pack-time bump (see release step 6), never a committed one.",
|
|
4
|
-
"version": "0.19.
|
|
4
|
+
"version": "0.19.41",
|
|
5
5
|
"description": "Run Claude Code 24/7 on your Claude Pro/Max subscription over Telegram. Open-source alternative to OpenClaw and NanoClaw — no API keys.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
@@ -1018,6 +1018,16 @@ export HINDSIGHT_DIRECTIVE_CAPTURE_NUDGE={{hindsightDirectiveCaptureNudge}}
|
|
|
1018
1018
|
{{#if hindsightObservationScopesQ}}
|
|
1019
1019
|
export HINDSIGHT_OBSERVATION_SCOPES={{{hindsightObservationScopesQ}}}
|
|
1020
1020
|
{{/if}}
|
|
1021
|
+
# Per-retain observation-scope STRATEGY (memory.observation_scope_strategy
|
|
1022
|
+
# cascade). Selects curated-vs-not: "curated" (plugin default) strips volatile
|
|
1023
|
+
# per-session provenance tags so observations dedup across sessions; "shared"
|
|
1024
|
+
# forces the one global untagged scope; "combined"/"off" opt out (no per-row
|
|
1025
|
+
# scope on the wire, pre-feature engine default). Export ONLY when the operator
|
|
1026
|
+
# set it: unset leaves the plugin's on-by-default `curated` in force. A pinned
|
|
1027
|
+
# per-row scope (memory.observation_scopes) still wins over this in the resolver.
|
|
1028
|
+
{{#if hindsightObservationScopeStrategyQ}}
|
|
1029
|
+
export HINDSIGHT_OBSERVATION_SCOPE_STRATEGY={{{hindsightObservationScopeStrategyQ}}}
|
|
1030
|
+
{{/if}}
|
|
1021
1031
|
# PR6 — supergroup-mode topic tagging. JSON map of {alias: thread_id}
|
|
1022
1032
|
# parsed by retain.py + recall.py to (a) stamp chat_id/thread_id/topic_alias
|
|
1023
1033
|
# into retained memory metadata and (b) emit a "Current topic: …" preamble
|
|
@@ -268,7 +268,7 @@ const TOOL_SCHEMAS = [
|
|
|
268
268
|
{
|
|
269
269
|
name: 'send_checklist',
|
|
270
270
|
description:
|
|
271
|
-
'Send a
|
|
271
|
+
'Send a checklist (task list) to a chat. Native interactive Telegram checklists require a Business-account connection, which most deployments do not have — in that normal case the checklist is sent as a formatted TEXT message (bold title + ✅/⬜ task lines) and the result carries degraded:"text": tasks are NOT tappable, and you tick them yourself via update_checklist (task ids are 1..N in send order). With a Business connection configured, the checklist is sent natively and tick events arrive as channel events with kind="checklist_task_changed". Returns JSON with message_id and mode. Limit: 30 tasks.',
|
|
272
272
|
inputSchema: {
|
|
273
273
|
type: 'object',
|
|
274
274
|
properties: {
|
|
@@ -357,7 +357,7 @@ const TOOL_SCHEMAS = [
|
|
|
357
357
|
{
|
|
358
358
|
name: 'update_checklist',
|
|
359
359
|
description:
|
|
360
|
-
'Patch
|
|
360
|
+
'Patch a checklist previously sent with send_checklist: update the title, append tasks, or mark tasks done/undone. Tasks with an id target existing items (ids are 1..N in send order for text-mode checklists); tasks without an id are appended. Removal is not supported. The edit re-renders in the mode the checklist was sent in (text for most deployments). Returns JSON { ok, ... }; after a gateway restart the stored task state may be gone — then it returns ok:false with reason "unknown_checklist" unless you pass a full replacement (title + every task\'s text).',
|
|
361
361
|
inputSchema: {
|
|
362
362
|
type: 'object',
|
|
363
363
|
properties: {
|
|
@@ -23543,6 +23543,14 @@ function projectTranscriptLine(line) {
|
|
|
23543
23543
|
{ kind: "turn_end", durationMs: obj.durationMs ?? 0 }
|
|
23544
23544
|
];
|
|
23545
23545
|
}
|
|
23546
|
+
if (type === "system" && obj.subtype === "compact_boundary") {
|
|
23547
|
+
const meta = obj.compactMetadata;
|
|
23548
|
+
return [{
|
|
23549
|
+
kind: "compact_boundary",
|
|
23550
|
+
trigger: typeof meta?.trigger === "string" ? meta.trigger : null,
|
|
23551
|
+
compactDurationMs: typeof meta?.durationMs === "number" ? meta.durationMs : null
|
|
23552
|
+
}];
|
|
23553
|
+
}
|
|
23546
23554
|
return [];
|
|
23547
23555
|
}
|
|
23548
23556
|
function projectSubagentLine(line, agentId, state) {
|
|
@@ -25233,7 +25241,7 @@ var TOOL_SCHEMAS = [
|
|
|
25233
25241
|
},
|
|
25234
25242
|
{
|
|
25235
25243
|
name: "send_checklist",
|
|
25236
|
-
description: 'Send a
|
|
25244
|
+
description: 'Send a checklist (task list) to a chat. Native interactive Telegram checklists require a Business-account connection, which most deployments do not have \u2014 in that normal case the checklist is sent as a formatted TEXT message (bold title + \u2705/\u2B1C task lines) and the result carries degraded:"text": tasks are NOT tappable, and you tick them yourself via update_checklist (task ids are 1..N in send order). With a Business connection configured, the checklist is sent natively and tick events arrive as channel events with kind="checklist_task_changed". Returns JSON with message_id and mode. Limit: 30 tasks.',
|
|
25237
25245
|
inputSchema: {
|
|
25238
25246
|
type: "object",
|
|
25239
25247
|
properties: {
|
|
@@ -25318,7 +25326,7 @@ var TOOL_SCHEMAS = [
|
|
|
25318
25326
|
},
|
|
25319
25327
|
{
|
|
25320
25328
|
name: "update_checklist",
|
|
25321
|
-
description:
|
|
25329
|
+
description: `Patch a checklist previously sent with send_checklist: update the title, append tasks, or mark tasks done/undone. Tasks with an id target existing items (ids are 1..N in send order for text-mode checklists); tasks without an id are appended. Removal is not supported. The edit re-renders in the mode the checklist was sent in (text for most deployments). Returns JSON { ok, ... }; after a gateway restart the stored task state may be gone \u2014 then it returns ok:false with reason "unknown_checklist" unless you pass a full replacement (title + every task's text).`,
|
|
25322
25330
|
inputSchema: {
|
|
25323
25331
|
type: "object",
|
|
25324
25332
|
properties: {
|