switchroom 0.15.7 → 0.15.8
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 +102 -5
- package/dist/auth-broker/index.js +18 -0
- package/dist/cli/notion-write-pretool.mjs +18 -0
- package/dist/cli/switchroom.js +113 -24
- package/dist/host-control/main.js +18 -0
- package/dist/vault/approvals/kernel-server.js +19 -1
- package/dist/vault/broker/server.js +19 -1
- package/package.json +1 -1
- package/profiles/_shared/agent-self-service.md.hbs +24 -5
- package/telegram-plugin/dist/gateway/gateway.js +171 -9
- package/telegram-plugin/gateway/gateway.ts +136 -2
- package/telegram-plugin/gateway/reaction-dispatch.ts +174 -0
- package/telegram-plugin/tests/reaction-dispatch.test.ts +137 -0
|
@@ -13967,6 +13967,10 @@ var ReactionsSchema = exports_external.object({
|
|
|
13967
13967
|
per_hour_cap: exports_external.number().int().nonnegative().optional().describe("Max reaction-triggered synthetic turns per chat per rolling hour. " + "Refusals are stderr-logged but not surfaced to the agent. " + "Default 10. Set to 0 to disable triggering via the cap path."),
|
|
13968
13968
|
group_admin_only: exports_external.boolean().optional().describe("In groups/supergroups (negative chat_id), only trigger a synthetic " + "turn when the reacter is a chat admin (creator or administrator). " + "Failing the lookup is treated as non-admin (fail-closed). " + "DMs are never affected by this flag — the reacter IS the user. " + "Default true.")
|
|
13969
13969
|
}).optional();
|
|
13970
|
+
var ReactionDispatchSchema = exports_external.object({
|
|
13971
|
+
enabled: exports_external.boolean().optional().describe("Master switch for the reaction-dispatch path. Default false — " + "with no reaction_dispatch block, reactions are persisted (and may " + "feed the `reactions` feedback path) but are NEVER dispatched as " + "event-driven inbound turns."),
|
|
13972
|
+
emojis: exports_external.array(exports_external.string()).optional().describe('Emoji allowlist that triggers a `<channel event="reaction">` ' + "inbound turn when reacted to any message. Default [] (nothing " + "fires). Cascade mode: REPLACE (not union) — a layer's list " + "replaces lower layers entirely so an operator can narrow per-agent.")
|
|
13973
|
+
}).optional();
|
|
13970
13974
|
var ReleaseBlock = exports_external.object({
|
|
13971
13975
|
channel: exports_external.enum(["dev", "rc", "latest"]).optional(),
|
|
13972
13976
|
pin: exports_external.string().regex(/^(sha-[0-9a-f]{7,40}|v\d+\.\d+\.\d+)$/).optional()
|
|
@@ -14002,6 +14006,7 @@ var profileFields = {
|
|
|
14002
14006
|
schedule: exports_external.array(ScheduleEntrySchema).optional(),
|
|
14003
14007
|
secrets: exports_external.array(exports_external.string().regex(/^[a-zA-Z0-9_\-/]+$/, "Secret key names must contain only alphanumeric characters, underscores, hyphens, and forward slashes")).optional().describe("Operator-granted STANDING vault keys this agent may read via the " + "broker — independent of any cron or MCP server. Use when an agent " + "needs a credential both interactively and in its own (agent-managed) " + "schedules, so the grant lives with the agent rather than welded to a " + "specific cron's `secrets[]`. OPERATOR-SET ONLY: agents cannot edit " + "switchroom.yaml or self-grant (reference/vision.md outcome 2 — 'you " + "hold the leash; only your tap grants it'). Exact key names. Cascades " + "UNION across defaults -> profile -> agent (see docs/configuration.md)."),
|
|
14004
14008
|
reactions: ReactionsSchema,
|
|
14009
|
+
reaction_dispatch: ReactionDispatchSchema,
|
|
14005
14010
|
model: exports_external.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._\-/\[\]:]*$/, "Model name must be alphanumeric with ._-/[]: only").optional(),
|
|
14006
14011
|
thinking_effort: exports_external.enum(["low", "medium", "high", "xhigh", "max"]).optional().describe("Adaptive-thinking effort level passed as --effort to the claude CLI. " + "lower = faster/cheaper, higher = more reasoning. Omit to use Claude's default."),
|
|
14007
14012
|
permission_mode: exports_external.enum(["acceptEdits", "auto", "bypassPermissions", "default", "dontAsk", "plan"]).optional().describe("Permission mode passed as --permission-mode to the claude CLI. " + "Omit to use Claude's default (acceptEdits for switchroom agents). " + "Warning: bypassPermissions and dontAsk skip all safety checks — use only in trusted sandboxes."),
|
|
@@ -14071,6 +14076,7 @@ var AgentSchema = exports_external.object({
|
|
|
14071
14076
|
schedule: exports_external.array(ScheduleEntrySchema).default([]),
|
|
14072
14077
|
secrets: exports_external.array(exports_external.string().regex(/^[a-zA-Z0-9_\-/]+$/, "Secret key names must contain only alphanumeric characters, underscores, hyphens, and forward slashes")).optional(),
|
|
14073
14078
|
reactions: ReactionsSchema,
|
|
14079
|
+
reaction_dispatch: ReactionDispatchSchema,
|
|
14074
14080
|
model: exports_external.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._\-/\[\]:]*$/, "Model name must be alphanumeric with ._-/[]: only (no spaces or shell specials)").optional().describe("Claude model override (e.g., 'claude-sonnet-4-6')"),
|
|
14075
14081
|
thinking_effort: exports_external.enum(["low", "medium", "high", "xhigh", "max"]).optional().describe("Adaptive-thinking effort level passed as --effort to the claude CLI. " + "Per-agent override wins over defaults.thinking_effort. " + "lower = faster/cheaper, higher = more reasoning. Omit to use Claude's default."),
|
|
14076
14082
|
permission_mode: exports_external.enum(["acceptEdits", "auto", "bypassPermissions", "default", "dontAsk", "plan"]).optional().describe("Permission mode passed as --permission-mode to the claude CLI. " + "Per-agent override wins over defaults.permission_mode. " + "Warning: bypassPermissions and dontAsk skip all safety checks — use only in trusted sandboxes."),
|
|
@@ -14746,6 +14752,18 @@ function mergeAgentConfig(defaultsIn, agentIn) {
|
|
|
14746
14752
|
}
|
|
14747
14753
|
merged.reactions = combined;
|
|
14748
14754
|
}
|
|
14755
|
+
const dReactionDispatch = defaults.reaction_dispatch;
|
|
14756
|
+
const mReactionDispatch = merged.reaction_dispatch;
|
|
14757
|
+
if (dReactionDispatch || mReactionDispatch) {
|
|
14758
|
+
const base = dReactionDispatch ?? {};
|
|
14759
|
+
const override = mReactionDispatch ?? {};
|
|
14760
|
+
const combined = { ...base };
|
|
14761
|
+
for (const [k, v] of Object.entries(override)) {
|
|
14762
|
+
if (v !== undefined)
|
|
14763
|
+
combined[k] = v;
|
|
14764
|
+
}
|
|
14765
|
+
merged.reaction_dispatch = combined;
|
|
14766
|
+
}
|
|
14749
14767
|
if (defaults.resources || merged.resources) {
|
|
14750
14768
|
const d = defaults.resources ?? {};
|
|
14751
14769
|
const a = merged.resources ?? {};
|
|
@@ -4293,6 +4293,18 @@ function mergeAgentConfig(defaultsIn, agentIn) {
|
|
|
4293
4293
|
}
|
|
4294
4294
|
merged.reactions = combined;
|
|
4295
4295
|
}
|
|
4296
|
+
const dReactionDispatch = defaults.reaction_dispatch;
|
|
4297
|
+
const mReactionDispatch = merged.reaction_dispatch;
|
|
4298
|
+
if (dReactionDispatch || mReactionDispatch) {
|
|
4299
|
+
const base = dReactionDispatch ?? {};
|
|
4300
|
+
const override = mReactionDispatch ?? {};
|
|
4301
|
+
const combined = { ...base };
|
|
4302
|
+
for (const [k, v] of Object.entries(override)) {
|
|
4303
|
+
if (v !== undefined)
|
|
4304
|
+
combined[k] = v;
|
|
4305
|
+
}
|
|
4306
|
+
merged.reaction_dispatch = combined;
|
|
4307
|
+
}
|
|
4296
4308
|
if (defaults.resources || merged.resources) {
|
|
4297
4309
|
const d = defaults.resources ?? {};
|
|
4298
4310
|
const a = merged.resources ?? {};
|
|
@@ -11277,7 +11289,7 @@ var init_dist = __esm(() => {
|
|
|
11277
11289
|
});
|
|
11278
11290
|
|
|
11279
11291
|
// src/config/schema.ts
|
|
11280
|
-
var CodeRepoEntrySchema, AgentBindMountSchema, HttpDiffPollSchema, TelegramReactionsPollSchema, PollSpecSchema, ScheduleEntrySchema, AgentSoulSchema, AgentToolsSchema, AgentMemorySchema, HookEntrySchema, AgentHooksSchema, SubagentSchema, SessionSchema, SessionContinuitySchema, webhookDispatchRule, TelegramChannelSchema, ChannelsSchema, TIMEZONE_REGEX, ApproverIdSchema, GoogleWorkspaceTierSchema, GoogleWorkspaceConfigSchema, MicrosoftWorkspaceConfigSchema, NotionWorkspaceConfigSchema, AgentGoogleWorkspaceConfigSchema, AgentMicrosoftWorkspaceConfigSchema, AgentNotionWorkspaceConfigSchema, ReactionsSchema, ReleaseBlock, NetworkIsolationSchema, profileFields, ProfileSchema, _omitExtends, defaultsFields, AgentDefaultsSchema, AgentSchema, TelegramConfigSchema, MemoryBackendConfigSchema, VaultConfigSchema, QuotaConfigSchema, AutoReleaseCheckSchema, HostControlConfigSchema, WebServiceConfigSchema, HostdConfigSchema, CronEgressSchema, CronConfigSchema, SwitchroomConfigSchema;
|
|
11292
|
+
var CodeRepoEntrySchema, AgentBindMountSchema, HttpDiffPollSchema, TelegramReactionsPollSchema, PollSpecSchema, ScheduleEntrySchema, AgentSoulSchema, AgentToolsSchema, AgentMemorySchema, HookEntrySchema, AgentHooksSchema, SubagentSchema, SessionSchema, SessionContinuitySchema, webhookDispatchRule, TelegramChannelSchema, ChannelsSchema, TIMEZONE_REGEX, ApproverIdSchema, GoogleWorkspaceTierSchema, GoogleWorkspaceConfigSchema, MicrosoftWorkspaceConfigSchema, NotionWorkspaceConfigSchema, AgentGoogleWorkspaceConfigSchema, AgentMicrosoftWorkspaceConfigSchema, AgentNotionWorkspaceConfigSchema, ReactionsSchema, ReactionDispatchSchema, ReleaseBlock, NetworkIsolationSchema, profileFields, ProfileSchema, _omitExtends, defaultsFields, AgentDefaultsSchema, AgentSchema, TelegramConfigSchema, MemoryBackendConfigSchema, VaultConfigSchema, QuotaConfigSchema, AutoReleaseCheckSchema, HostControlConfigSchema, WebServiceConfigSchema, HostdConfigSchema, CronEgressSchema, CronConfigSchema, SwitchroomConfigSchema;
|
|
11281
11293
|
var init_schema = __esm(() => {
|
|
11282
11294
|
init_zod();
|
|
11283
11295
|
CodeRepoEntrySchema = exports_external.object({
|
|
@@ -11553,6 +11565,10 @@ var init_schema = __esm(() => {
|
|
|
11553
11565
|
per_hour_cap: exports_external.number().int().nonnegative().optional().describe("Max reaction-triggered synthetic turns per chat per rolling hour. " + "Refusals are stderr-logged but not surfaced to the agent. " + "Default 10. Set to 0 to disable triggering via the cap path."),
|
|
11554
11566
|
group_admin_only: exports_external.boolean().optional().describe("In groups/supergroups (negative chat_id), only trigger a synthetic " + "turn when the reacter is a chat admin (creator or administrator). " + "Failing the lookup is treated as non-admin (fail-closed). " + "DMs are never affected by this flag — the reacter IS the user. " + "Default true.")
|
|
11555
11567
|
}).optional();
|
|
11568
|
+
ReactionDispatchSchema = exports_external.object({
|
|
11569
|
+
enabled: exports_external.boolean().optional().describe("Master switch for the reaction-dispatch path. Default false — " + "with no reaction_dispatch block, reactions are persisted (and may " + "feed the `reactions` feedback path) but are NEVER dispatched as " + "event-driven inbound turns."),
|
|
11570
|
+
emojis: exports_external.array(exports_external.string()).optional().describe('Emoji allowlist that triggers a `<channel event="reaction">` ' + "inbound turn when reacted to any message. Default [] (nothing " + "fires). Cascade mode: REPLACE (not union) — a layer's list " + "replaces lower layers entirely so an operator can narrow per-agent.")
|
|
11571
|
+
}).optional();
|
|
11556
11572
|
ReleaseBlock = exports_external.object({
|
|
11557
11573
|
channel: exports_external.enum(["dev", "rc", "latest"]).optional(),
|
|
11558
11574
|
pin: exports_external.string().regex(/^(sha-[0-9a-f]{7,40}|v\d+\.\d+\.\d+)$/).optional()
|
|
@@ -11588,6 +11604,7 @@ var init_schema = __esm(() => {
|
|
|
11588
11604
|
schedule: exports_external.array(ScheduleEntrySchema).optional(),
|
|
11589
11605
|
secrets: exports_external.array(exports_external.string().regex(/^[a-zA-Z0-9_\-/]+$/, "Secret key names must contain only alphanumeric characters, underscores, hyphens, and forward slashes")).optional().describe("Operator-granted STANDING vault keys this agent may read via the " + "broker — independent of any cron or MCP server. Use when an agent " + "needs a credential both interactively and in its own (agent-managed) " + "schedules, so the grant lives with the agent rather than welded to a " + "specific cron's `secrets[]`. OPERATOR-SET ONLY: agents cannot edit " + "switchroom.yaml or self-grant (reference/vision.md outcome 2 — 'you " + "hold the leash; only your tap grants it'). Exact key names. Cascades " + "UNION across defaults -> profile -> agent (see docs/configuration.md)."),
|
|
11590
11606
|
reactions: ReactionsSchema,
|
|
11607
|
+
reaction_dispatch: ReactionDispatchSchema,
|
|
11591
11608
|
model: exports_external.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._\-/\[\]:]*$/, "Model name must be alphanumeric with ._-/[]: only").optional(),
|
|
11592
11609
|
thinking_effort: exports_external.enum(["low", "medium", "high", "xhigh", "max"]).optional().describe("Adaptive-thinking effort level passed as --effort to the claude CLI. " + "lower = faster/cheaper, higher = more reasoning. Omit to use Claude's default."),
|
|
11593
11610
|
permission_mode: exports_external.enum(["acceptEdits", "auto", "bypassPermissions", "default", "dontAsk", "plan"]).optional().describe("Permission mode passed as --permission-mode to the claude CLI. " + "Omit to use Claude's default (acceptEdits for switchroom agents). " + "Warning: bypassPermissions and dontAsk skip all safety checks — use only in trusted sandboxes."),
|
|
@@ -11657,6 +11674,7 @@ var init_schema = __esm(() => {
|
|
|
11657
11674
|
schedule: exports_external.array(ScheduleEntrySchema).default([]),
|
|
11658
11675
|
secrets: exports_external.array(exports_external.string().regex(/^[a-zA-Z0-9_\-/]+$/, "Secret key names must contain only alphanumeric characters, underscores, hyphens, and forward slashes")).optional(),
|
|
11659
11676
|
reactions: ReactionsSchema,
|
|
11677
|
+
reaction_dispatch: ReactionDispatchSchema,
|
|
11660
11678
|
model: exports_external.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._\-/\[\]:]*$/, "Model name must be alphanumeric with ._-/[]: only (no spaces or shell specials)").optional().describe("Claude model override (e.g., 'claude-sonnet-4-6')"),
|
|
11661
11679
|
thinking_effort: exports_external.enum(["low", "medium", "high", "xhigh", "max"]).optional().describe("Adaptive-thinking effort level passed as --effort to the claude CLI. " + "Per-agent override wins over defaults.thinking_effort. " + "lower = faster/cheaper, higher = more reasoning. Omit to use Claude's default."),
|
|
11662
11680
|
permission_mode: exports_external.enum(["acceptEdits", "auto", "bypassPermissions", "default", "dontAsk", "plan"]).optional().describe("Permission mode passed as --permission-mode to the claude CLI. " + "Per-agent override wins over defaults.permission_mode. " + "Warning: bypassPermissions and dontAsk skip all safety checks — use only in trusted sandboxes."),
|
|
@@ -327,6 +327,18 @@ function mergeAgentConfig(defaultsIn, agentIn) {
|
|
|
327
327
|
}
|
|
328
328
|
merged.reactions = combined;
|
|
329
329
|
}
|
|
330
|
+
const dReactionDispatch = defaults.reaction_dispatch;
|
|
331
|
+
const mReactionDispatch = merged.reaction_dispatch;
|
|
332
|
+
if (dReactionDispatch || mReactionDispatch) {
|
|
333
|
+
const base = dReactionDispatch ?? {};
|
|
334
|
+
const override = mReactionDispatch ?? {};
|
|
335
|
+
const combined = { ...base };
|
|
336
|
+
for (const [k, v] of Object.entries(override)) {
|
|
337
|
+
if (v !== undefined)
|
|
338
|
+
combined[k] = v;
|
|
339
|
+
}
|
|
340
|
+
merged.reaction_dispatch = combined;
|
|
341
|
+
}
|
|
330
342
|
if (defaults.resources || merged.resources) {
|
|
331
343
|
const d = defaults.resources ?? {};
|
|
332
344
|
const a = merged.resources ?? {};
|
|
@@ -11277,7 +11289,7 @@ var init_zod = __esm(() => {
|
|
|
11277
11289
|
});
|
|
11278
11290
|
|
|
11279
11291
|
// src/config/schema.ts
|
|
11280
|
-
var CodeRepoEntrySchema, AgentBindMountSchema, HttpDiffPollSchema, TelegramReactionsPollSchema, PollSpecSchema, ScheduleEntrySchema, AgentSoulSchema, AgentToolsSchema, AgentMemorySchema, HookEntrySchema, AgentHooksSchema, SubagentSchema, SessionSchema, SessionContinuitySchema, webhookDispatchRule, TelegramChannelSchema, ChannelsSchema, TIMEZONE_REGEX, ApproverIdSchema, GoogleWorkspaceTierSchema, GoogleWorkspaceConfigSchema, MicrosoftWorkspaceConfigSchema, NotionWorkspaceConfigSchema, AgentGoogleWorkspaceConfigSchema, AgentMicrosoftWorkspaceConfigSchema, AgentNotionWorkspaceConfigSchema, ReactionsSchema, ReleaseBlock, NetworkIsolationSchema, profileFields, ProfileSchema, _omitExtends, defaultsFields, AgentDefaultsSchema, AgentSchema, TelegramConfigSchema, MemoryBackendConfigSchema, VaultConfigSchema, QuotaConfigSchema, AutoReleaseCheckSchema, HostControlConfigSchema, WebServiceConfigSchema, HostdConfigSchema, CronEgressSchema, CronConfigSchema, SwitchroomConfigSchema;
|
|
11292
|
+
var CodeRepoEntrySchema, AgentBindMountSchema, HttpDiffPollSchema, TelegramReactionsPollSchema, PollSpecSchema, ScheduleEntrySchema, AgentSoulSchema, AgentToolsSchema, AgentMemorySchema, HookEntrySchema, AgentHooksSchema, SubagentSchema, SessionSchema, SessionContinuitySchema, webhookDispatchRule, TelegramChannelSchema, ChannelsSchema, TIMEZONE_REGEX, ApproverIdSchema, GoogleWorkspaceTierSchema, GoogleWorkspaceConfigSchema, MicrosoftWorkspaceConfigSchema, NotionWorkspaceConfigSchema, AgentGoogleWorkspaceConfigSchema, AgentMicrosoftWorkspaceConfigSchema, AgentNotionWorkspaceConfigSchema, ReactionsSchema, ReactionDispatchSchema, ReleaseBlock, NetworkIsolationSchema, profileFields, ProfileSchema, _omitExtends, defaultsFields, AgentDefaultsSchema, AgentSchema, TelegramConfigSchema, MemoryBackendConfigSchema, VaultConfigSchema, QuotaConfigSchema, AutoReleaseCheckSchema, HostControlConfigSchema, WebServiceConfigSchema, HostdConfigSchema, CronEgressSchema, CronConfigSchema, SwitchroomConfigSchema;
|
|
11281
11293
|
var init_schema = __esm(() => {
|
|
11282
11294
|
init_zod();
|
|
11283
11295
|
CodeRepoEntrySchema = exports_external.object({
|
|
@@ -11553,6 +11565,10 @@ var init_schema = __esm(() => {
|
|
|
11553
11565
|
per_hour_cap: exports_external.number().int().nonnegative().optional().describe("Max reaction-triggered synthetic turns per chat per rolling hour. " + "Refusals are stderr-logged but not surfaced to the agent. " + "Default 10. Set to 0 to disable triggering via the cap path."),
|
|
11554
11566
|
group_admin_only: exports_external.boolean().optional().describe("In groups/supergroups (negative chat_id), only trigger a synthetic " + "turn when the reacter is a chat admin (creator or administrator). " + "Failing the lookup is treated as non-admin (fail-closed). " + "DMs are never affected by this flag — the reacter IS the user. " + "Default true.")
|
|
11555
11567
|
}).optional();
|
|
11568
|
+
ReactionDispatchSchema = exports_external.object({
|
|
11569
|
+
enabled: exports_external.boolean().optional().describe("Master switch for the reaction-dispatch path. Default false — " + "with no reaction_dispatch block, reactions are persisted (and may " + "feed the `reactions` feedback path) but are NEVER dispatched as " + "event-driven inbound turns."),
|
|
11570
|
+
emojis: exports_external.array(exports_external.string()).optional().describe('Emoji allowlist that triggers a `<channel event="reaction">` ' + "inbound turn when reacted to any message. Default [] (nothing " + "fires). Cascade mode: REPLACE (not union) — a layer's list " + "replaces lower layers entirely so an operator can narrow per-agent.")
|
|
11571
|
+
}).optional();
|
|
11556
11572
|
ReleaseBlock = exports_external.object({
|
|
11557
11573
|
channel: exports_external.enum(["dev", "rc", "latest"]).optional(),
|
|
11558
11574
|
pin: exports_external.string().regex(/^(sha-[0-9a-f]{7,40}|v\d+\.\d+\.\d+)$/).optional()
|
|
@@ -11588,6 +11604,7 @@ var init_schema = __esm(() => {
|
|
|
11588
11604
|
schedule: exports_external.array(ScheduleEntrySchema).optional(),
|
|
11589
11605
|
secrets: exports_external.array(exports_external.string().regex(/^[a-zA-Z0-9_\-/]+$/, "Secret key names must contain only alphanumeric characters, underscores, hyphens, and forward slashes")).optional().describe("Operator-granted STANDING vault keys this agent may read via the " + "broker — independent of any cron or MCP server. Use when an agent " + "needs a credential both interactively and in its own (agent-managed) " + "schedules, so the grant lives with the agent rather than welded to a " + "specific cron's `secrets[]`. OPERATOR-SET ONLY: agents cannot edit " + "switchroom.yaml or self-grant (reference/vision.md outcome 2 — 'you " + "hold the leash; only your tap grants it'). Exact key names. Cascades " + "UNION across defaults -> profile -> agent (see docs/configuration.md)."),
|
|
11590
11606
|
reactions: ReactionsSchema,
|
|
11607
|
+
reaction_dispatch: ReactionDispatchSchema,
|
|
11591
11608
|
model: exports_external.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._\-/\[\]:]*$/, "Model name must be alphanumeric with ._-/[]: only").optional(),
|
|
11592
11609
|
thinking_effort: exports_external.enum(["low", "medium", "high", "xhigh", "max"]).optional().describe("Adaptive-thinking effort level passed as --effort to the claude CLI. " + "lower = faster/cheaper, higher = more reasoning. Omit to use Claude's default."),
|
|
11593
11610
|
permission_mode: exports_external.enum(["acceptEdits", "auto", "bypassPermissions", "default", "dontAsk", "plan"]).optional().describe("Permission mode passed as --permission-mode to the claude CLI. " + "Omit to use Claude's default (acceptEdits for switchroom agents). " + "Warning: bypassPermissions and dontAsk skip all safety checks — use only in trusted sandboxes."),
|
|
@@ -11657,6 +11674,7 @@ var init_schema = __esm(() => {
|
|
|
11657
11674
|
schedule: exports_external.array(ScheduleEntrySchema).default([]),
|
|
11658
11675
|
secrets: exports_external.array(exports_external.string().regex(/^[a-zA-Z0-9_\-/]+$/, "Secret key names must contain only alphanumeric characters, underscores, hyphens, and forward slashes")).optional(),
|
|
11659
11676
|
reactions: ReactionsSchema,
|
|
11677
|
+
reaction_dispatch: ReactionDispatchSchema,
|
|
11660
11678
|
model: exports_external.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._\-/\[\]:]*$/, "Model name must be alphanumeric with ._-/[]: only (no spaces or shell specials)").optional().describe("Claude model override (e.g., 'claude-sonnet-4-6')"),
|
|
11661
11679
|
thinking_effort: exports_external.enum(["low", "medium", "high", "xhigh", "max"]).optional().describe("Adaptive-thinking effort level passed as --effort to the claude CLI. " + "Per-agent override wins over defaults.thinking_effort. " + "lower = faster/cheaper, higher = more reasoning. Omit to use Claude's default."),
|
|
11662
11680
|
permission_mode: exports_external.enum(["acceptEdits", "auto", "bypassPermissions", "default", "dontAsk", "plan"]).optional().describe("Permission mode passed as --permission-mode to the claude CLI. " + "Per-agent override wins over defaults.permission_mode. " + "Warning: bypassPermissions and dontAsk skip all safety checks — use only in trusted sandboxes."),
|
package/package.json
CHANGED
|
@@ -28,14 +28,33 @@ tools is to let you do the edit yourself.
|
|
|
28
28
|
|
|
29
29
|
### Tools
|
|
30
30
|
|
|
31
|
-
- **`schedule_add(cron_expr, prompt, name?, secrets?)`** —
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
- **`schedule_add(cron_expr, prompt, name?, secrets?, model?, context?)`** —
|
|
32
|
+
append a new schedule entry. Takes effect within **~30s** (the scheduler
|
|
33
|
+
hot-reloads — no restart needed). The `prompt` is what *you* (the agent) will
|
|
34
|
+
receive when the cron fires; phrase it from your future-self's perspective
|
|
35
|
+
(e.g. `"Time for the daily digest — pull yesterday's GitHub activity and DM
|
|
36
|
+
the summary to chat 12345"`, not `"please send the digest"`). Optional
|
|
36
37
|
`name` is a stable slug for `schedule_remove`; if omitted, a 12-hex hash
|
|
37
38
|
derived from the entry content is assigned.
|
|
38
39
|
|
|
40
|
+
**Mind the cost — pick the cheapest tier that does the job:**
|
|
41
|
+
- *Default (no `model`)* — the fire runs as a **full turn in your live
|
|
42
|
+
session**: your model, your whole context + memory. Right for work that
|
|
43
|
+
genuinely needs *you* (your persona, your conversation history). Costly for
|
|
44
|
+
routine checks — every fire pays your full context.
|
|
45
|
+
- *`model: "sonnet"`* (or `context: "fresh"`) — routes the fire to a **cheap,
|
|
46
|
+
minimal-context cron session** (Tier 1): a fresh Sonnet with just the
|
|
47
|
+
prompt, no heavy context. Use for light, self-contained recurring work
|
|
48
|
+
(summarise a feed, format a digest) where you don't need your memory. Much
|
|
49
|
+
cheaper per fire. *(Honoured only when the operator has enabled cheap-cron;
|
|
50
|
+
otherwise it still runs as a normal turn — never silently dropped.)*
|
|
51
|
+
- *"Only act when X changes"* — don't poll with a frequent prompt cron (every
|
|
52
|
+
fire is a wasted turn when nothing changed). Ask the **operator** to set up
|
|
53
|
+
a **poll** (model-free check, e.g. a webpage/API via `kind: poll`) or, for
|
|
54
|
+
reaction-triggered work, **`reaction_dispatch`** (an emoji reaction wakes
|
|
55
|
+
you instantly — zero polling). These need an operator config commit
|
|
56
|
+
(egress/identity gates), so request them rather than authoring them yourself.
|
|
57
|
+
|
|
39
58
|
- **`schedule_remove(name | cron_hash)`** — delete by `name` (the slug from
|
|
40
59
|
add) or by 12-hex `cron_hash` (shown in `cron_list` output). Both
|
|
41
60
|
arguments are accepted; pass one.
|
|
@@ -23802,7 +23802,7 @@ var init_dist = __esm(() => {
|
|
|
23802
23802
|
});
|
|
23803
23803
|
|
|
23804
23804
|
// ../src/config/schema.ts
|
|
23805
|
-
var CodeRepoEntrySchema, AgentBindMountSchema, HttpDiffPollSchema, TelegramReactionsPollSchema, PollSpecSchema, ScheduleEntrySchema, AgentSoulSchema, AgentToolsSchema, AgentMemorySchema, HookEntrySchema, AgentHooksSchema, SubagentSchema, SessionSchema, SessionContinuitySchema, webhookDispatchRule, TelegramChannelSchema, ChannelsSchema, TIMEZONE_REGEX, ApproverIdSchema, GoogleWorkspaceTierSchema, GoogleWorkspaceConfigSchema, MicrosoftWorkspaceConfigSchema, NotionWorkspaceConfigSchema, AgentGoogleWorkspaceConfigSchema, AgentMicrosoftWorkspaceConfigSchema, AgentNotionWorkspaceConfigSchema, ReactionsSchema, ReleaseBlock, NetworkIsolationSchema, profileFields, ProfileSchema, _omitExtends, defaultsFields, AgentDefaultsSchema, AgentSchema, TelegramConfigSchema, MemoryBackendConfigSchema, VaultConfigSchema, QuotaConfigSchema, AutoReleaseCheckSchema, HostControlConfigSchema, WebServiceConfigSchema, HostdConfigSchema, CronEgressSchema, CronConfigSchema, SwitchroomConfigSchema;
|
|
23805
|
+
var CodeRepoEntrySchema, AgentBindMountSchema, HttpDiffPollSchema, TelegramReactionsPollSchema, PollSpecSchema, ScheduleEntrySchema, AgentSoulSchema, AgentToolsSchema, AgentMemorySchema, HookEntrySchema, AgentHooksSchema, SubagentSchema, SessionSchema, SessionContinuitySchema, webhookDispatchRule, TelegramChannelSchema, ChannelsSchema, TIMEZONE_REGEX, ApproverIdSchema, GoogleWorkspaceTierSchema, GoogleWorkspaceConfigSchema, MicrosoftWorkspaceConfigSchema, NotionWorkspaceConfigSchema, AgentGoogleWorkspaceConfigSchema, AgentMicrosoftWorkspaceConfigSchema, AgentNotionWorkspaceConfigSchema, ReactionsSchema, ReactionDispatchSchema, ReleaseBlock, NetworkIsolationSchema, profileFields, ProfileSchema, _omitExtends, defaultsFields, AgentDefaultsSchema, AgentSchema, TelegramConfigSchema, MemoryBackendConfigSchema, VaultConfigSchema, QuotaConfigSchema, AutoReleaseCheckSchema, HostControlConfigSchema, WebServiceConfigSchema, HostdConfigSchema, CronEgressSchema, CronConfigSchema, SwitchroomConfigSchema;
|
|
23806
23806
|
var init_schema = __esm(() => {
|
|
23807
23807
|
init_zod();
|
|
23808
23808
|
CodeRepoEntrySchema = exports_external.object({
|
|
@@ -24078,6 +24078,10 @@ var init_schema = __esm(() => {
|
|
|
24078
24078
|
per_hour_cap: exports_external.number().int().nonnegative().optional().describe("Max reaction-triggered synthetic turns per chat per rolling hour. " + "Refusals are stderr-logged but not surfaced to the agent. " + "Default 10. Set to 0 to disable triggering via the cap path."),
|
|
24079
24079
|
group_admin_only: exports_external.boolean().optional().describe("In groups/supergroups (negative chat_id), only trigger a synthetic " + "turn when the reacter is a chat admin (creator or administrator). " + "Failing the lookup is treated as non-admin (fail-closed). " + "DMs are never affected by this flag \u2014 the reacter IS the user. " + "Default true.")
|
|
24080
24080
|
}).optional();
|
|
24081
|
+
ReactionDispatchSchema = exports_external.object({
|
|
24082
|
+
enabled: exports_external.boolean().optional().describe("Master switch for the reaction-dispatch path. Default false \u2014 " + "with no reaction_dispatch block, reactions are persisted (and may " + "feed the `reactions` feedback path) but are NEVER dispatched as " + "event-driven inbound turns."),
|
|
24083
|
+
emojis: exports_external.array(exports_external.string()).optional().describe('Emoji allowlist that triggers a `<channel event="reaction">` ' + "inbound turn when reacted to any message. Default [] (nothing " + "fires). Cascade mode: REPLACE (not union) \u2014 a layer's list " + "replaces lower layers entirely so an operator can narrow per-agent.")
|
|
24084
|
+
}).optional();
|
|
24081
24085
|
ReleaseBlock = exports_external.object({
|
|
24082
24086
|
channel: exports_external.enum(["dev", "rc", "latest"]).optional(),
|
|
24083
24087
|
pin: exports_external.string().regex(/^(sha-[0-9a-f]{7,40}|v\d+\.\d+\.\d+)$/).optional()
|
|
@@ -24113,6 +24117,7 @@ var init_schema = __esm(() => {
|
|
|
24113
24117
|
schedule: exports_external.array(ScheduleEntrySchema).optional(),
|
|
24114
24118
|
secrets: exports_external.array(exports_external.string().regex(/^[a-zA-Z0-9_\-/]+$/, "Secret key names must contain only alphanumeric characters, underscores, hyphens, and forward slashes")).optional().describe("Operator-granted STANDING vault keys this agent may read via the " + "broker \u2014 independent of any cron or MCP server. Use when an agent " + "needs a credential both interactively and in its own (agent-managed) " + "schedules, so the grant lives with the agent rather than welded to a " + "specific cron's `secrets[]`. OPERATOR-SET ONLY: agents cannot edit " + "switchroom.yaml or self-grant (reference/vision.md outcome 2 \u2014 'you " + "hold the leash; only your tap grants it'). Exact key names. Cascades " + "UNION across defaults -> profile -> agent (see docs/configuration.md)."),
|
|
24115
24119
|
reactions: ReactionsSchema,
|
|
24120
|
+
reaction_dispatch: ReactionDispatchSchema,
|
|
24116
24121
|
model: exports_external.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._\-/\[\]:]*$/, "Model name must be alphanumeric with ._-/[]: only").optional(),
|
|
24117
24122
|
thinking_effort: exports_external.enum(["low", "medium", "high", "xhigh", "max"]).optional().describe("Adaptive-thinking effort level passed as --effort to the claude CLI. " + "lower = faster/cheaper, higher = more reasoning. Omit to use Claude's default."),
|
|
24118
24123
|
permission_mode: exports_external.enum(["acceptEdits", "auto", "bypassPermissions", "default", "dontAsk", "plan"]).optional().describe("Permission mode passed as --permission-mode to the claude CLI. " + "Omit to use Claude's default (acceptEdits for switchroom agents). " + "Warning: bypassPermissions and dontAsk skip all safety checks \u2014 use only in trusted sandboxes."),
|
|
@@ -24182,6 +24187,7 @@ var init_schema = __esm(() => {
|
|
|
24182
24187
|
schedule: exports_external.array(ScheduleEntrySchema).default([]),
|
|
24183
24188
|
secrets: exports_external.array(exports_external.string().regex(/^[a-zA-Z0-9_\-/]+$/, "Secret key names must contain only alphanumeric characters, underscores, hyphens, and forward slashes")).optional(),
|
|
24184
24189
|
reactions: ReactionsSchema,
|
|
24190
|
+
reaction_dispatch: ReactionDispatchSchema,
|
|
24185
24191
|
model: exports_external.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._\-/\[\]:]*$/, "Model name must be alphanumeric with ._-/[]: only (no spaces or shell specials)").optional().describe("Claude model override (e.g., 'claude-sonnet-4-6')"),
|
|
24186
24192
|
thinking_effort: exports_external.enum(["low", "medium", "high", "xhigh", "max"]).optional().describe("Adaptive-thinking effort level passed as --effort to the claude CLI. " + "Per-agent override wins over defaults.thinking_effort. " + "lower = faster/cheaper, higher = more reasoning. Omit to use Claude's default."),
|
|
24187
24193
|
permission_mode: exports_external.enum(["acceptEdits", "auto", "bypassPermissions", "default", "dontAsk", "plan"]).optional().describe("Permission mode passed as --permission-mode to the claude CLI. " + "Per-agent override wins over defaults.permission_mode. " + "Warning: bypassPermissions and dontAsk skip all safety checks \u2014 use only in trusted sandboxes."),
|
|
@@ -24857,6 +24863,18 @@ function mergeAgentConfig(defaultsIn, agentIn) {
|
|
|
24857
24863
|
}
|
|
24858
24864
|
merged.reactions = combined;
|
|
24859
24865
|
}
|
|
24866
|
+
const dReactionDispatch = defaults.reaction_dispatch;
|
|
24867
|
+
const mReactionDispatch = merged.reaction_dispatch;
|
|
24868
|
+
if (dReactionDispatch || mReactionDispatch) {
|
|
24869
|
+
const base = dReactionDispatch ?? {};
|
|
24870
|
+
const override = mReactionDispatch ?? {};
|
|
24871
|
+
const combined = { ...base };
|
|
24872
|
+
for (const [k, v] of Object.entries(override)) {
|
|
24873
|
+
if (v !== undefined)
|
|
24874
|
+
combined[k] = v;
|
|
24875
|
+
}
|
|
24876
|
+
merged.reaction_dispatch = combined;
|
|
24877
|
+
}
|
|
24860
24878
|
if (defaults.resources || merged.resources) {
|
|
24861
24879
|
const d = defaults.resources ?? {};
|
|
24862
24880
|
const a = merged.resources ?? {};
|
|
@@ -45770,6 +45788,18 @@ function mergeAgentConfig2(defaultsIn, agentIn) {
|
|
|
45770
45788
|
}
|
|
45771
45789
|
merged.reactions = combined;
|
|
45772
45790
|
}
|
|
45791
|
+
const dReactionDispatch = defaults.reaction_dispatch;
|
|
45792
|
+
const mReactionDispatch = merged.reaction_dispatch;
|
|
45793
|
+
if (dReactionDispatch || mReactionDispatch) {
|
|
45794
|
+
const base = dReactionDispatch ?? {};
|
|
45795
|
+
const override = mReactionDispatch ?? {};
|
|
45796
|
+
const combined = { ...base };
|
|
45797
|
+
for (const [k, v] of Object.entries(override)) {
|
|
45798
|
+
if (v !== undefined)
|
|
45799
|
+
combined[k] = v;
|
|
45800
|
+
}
|
|
45801
|
+
merged.reaction_dispatch = combined;
|
|
45802
|
+
}
|
|
45773
45803
|
if (defaults.resources || merged.resources) {
|
|
45774
45804
|
const d = defaults.resources ?? {};
|
|
45775
45805
|
const a = merged.resources ?? {};
|
|
@@ -49848,6 +49878,50 @@ function escapeBody(s) {
|
|
|
49848
49878
|
return s.replace(/</g, "<").replace(/>/g, ">");
|
|
49849
49879
|
}
|
|
49850
49880
|
|
|
49881
|
+
// gateway/reaction-dispatch.ts
|
|
49882
|
+
var REACTION_DISPATCH_DEFAULTS = Object.freeze({
|
|
49883
|
+
enabled: false,
|
|
49884
|
+
emojis: Object.freeze(new Set)
|
|
49885
|
+
});
|
|
49886
|
+
function resolveReactionDispatchConfig(raw) {
|
|
49887
|
+
if (!raw)
|
|
49888
|
+
return REACTION_DISPATCH_DEFAULTS;
|
|
49889
|
+
return {
|
|
49890
|
+
enabled: raw.enabled ?? REACTION_DISPATCH_DEFAULTS.enabled,
|
|
49891
|
+
emojis: raw.emojis !== undefined ? new Set(raw.emojis) : REACTION_DISPATCH_DEFAULTS.emojis
|
|
49892
|
+
};
|
|
49893
|
+
}
|
|
49894
|
+
function evaluateReactionDispatch(cfg, c) {
|
|
49895
|
+
if (!cfg.enabled)
|
|
49896
|
+
return { ok: false, reason: "disabled" };
|
|
49897
|
+
if (c.emoji === null)
|
|
49898
|
+
return { ok: false, reason: "no_emoji" };
|
|
49899
|
+
if (!cfg.emojis.has(c.emoji))
|
|
49900
|
+
return { ok: false, reason: "emoji_not_in_allowlist" };
|
|
49901
|
+
return { ok: true };
|
|
49902
|
+
}
|
|
49903
|
+
function buildReactionDispatchInbound(input) {
|
|
49904
|
+
const safeEmoji = escapeAttr2(input.emoji);
|
|
49905
|
+
const safeUser = escapeAttr2(input.user);
|
|
49906
|
+
const safeChat = escapeAttr2(input.chatId);
|
|
49907
|
+
const body = escapeBody2(input.reactedText);
|
|
49908
|
+
const text = `<channel source="switchroom-telegram" event="reaction" ` + `emoji="${safeEmoji}" message_id="${input.messageId}" ` + `chat_id="${safeChat}" user="${safeUser}">` + body + `</channel>`;
|
|
49909
|
+
const meta = {
|
|
49910
|
+
source: "switchroom-telegram",
|
|
49911
|
+
event: "reaction",
|
|
49912
|
+
reaction_emoji: input.emoji,
|
|
49913
|
+
target_message_id: String(input.messageId),
|
|
49914
|
+
reacted_text: input.reactedText
|
|
49915
|
+
};
|
|
49916
|
+
return { text, meta };
|
|
49917
|
+
}
|
|
49918
|
+
function escapeAttr2(s) {
|
|
49919
|
+
return s.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
49920
|
+
}
|
|
49921
|
+
function escapeBody2(s) {
|
|
49922
|
+
return s.replace(/</g, "<").replace(/>/g, ">");
|
|
49923
|
+
}
|
|
49924
|
+
|
|
49851
49925
|
// gateway/pid-file.ts
|
|
49852
49926
|
import { writeFileSync as writeFileSync11, readFileSync as readFileSync18, unlinkSync as unlinkSync7, renameSync as renameSync6 } from "node:fs";
|
|
49853
49927
|
function writePidFile(path, record) {
|
|
@@ -53683,11 +53757,11 @@ function readTurnActiveMarkerAgeMs(stateDir, now) {
|
|
|
53683
53757
|
}
|
|
53684
53758
|
|
|
53685
53759
|
// ../src/build-info.ts
|
|
53686
|
-
var VERSION = "0.15.
|
|
53687
|
-
var COMMIT_SHA = "
|
|
53688
|
-
var COMMIT_DATE = "2026-06-
|
|
53689
|
-
var LATEST_PR =
|
|
53690
|
-
var COMMITS_AHEAD_OF_TAG =
|
|
53760
|
+
var VERSION = "0.15.8";
|
|
53761
|
+
var COMMIT_SHA = "318cb85f";
|
|
53762
|
+
var COMMIT_DATE = "2026-06-12T23:50:50Z";
|
|
53763
|
+
var LATEST_PR = 2296;
|
|
53764
|
+
var COMMITS_AHEAD_OF_TAG = 1;
|
|
53691
53765
|
|
|
53692
53766
|
// gateway/boot-version.ts
|
|
53693
53767
|
function formatRelativeAgo(iso) {
|
|
@@ -65034,6 +65108,84 @@ function getReactionDebounce() {
|
|
|
65034
65108
|
}
|
|
65035
65109
|
return reactionDebounce;
|
|
65036
65110
|
}
|
|
65111
|
+
var reactionDispatchCfg = null;
|
|
65112
|
+
function getReactionDispatchConfig() {
|
|
65113
|
+
if (reactionDispatchCfg)
|
|
65114
|
+
return reactionDispatchCfg;
|
|
65115
|
+
let raw = undefined;
|
|
65116
|
+
try {
|
|
65117
|
+
const cfg = loadConfig2();
|
|
65118
|
+
const agentName3 = process.env.SWITCHROOM_AGENT_NAME;
|
|
65119
|
+
if (agentName3) {
|
|
65120
|
+
const rawAgent = cfg.agents?.[agentName3];
|
|
65121
|
+
if (rawAgent) {
|
|
65122
|
+
const resolved = resolveAgentConfig2(cfg.defaults, cfg.profiles, rawAgent);
|
|
65123
|
+
raw = resolved.reaction_dispatch;
|
|
65124
|
+
}
|
|
65125
|
+
}
|
|
65126
|
+
} catch (err) {
|
|
65127
|
+
process.stderr.write(`telegram gateway: reaction_dispatch: config load failed, defaulting OFF: ${err.message}
|
|
65128
|
+
`);
|
|
65129
|
+
}
|
|
65130
|
+
reactionDispatchCfg = resolveReactionDispatchConfig(raw ?? null);
|
|
65131
|
+
return reactionDispatchCfg;
|
|
65132
|
+
}
|
|
65133
|
+
function maybeDispatchReaction(args) {
|
|
65134
|
+
const cfg = getReactionDispatchConfig();
|
|
65135
|
+
const decision = evaluateReactionDispatch(cfg, { emoji: args.emoji, action: args.action });
|
|
65136
|
+
if (!decision.ok) {
|
|
65137
|
+
if (decision.reason === "emoji_not_in_allowlist" && cfg.enabled) {
|
|
65138
|
+
process.stderr.write(`telegram gateway: reaction_dispatch.reject reason=allowlist_miss emoji=${args.emoji} chat=${args.chatId}
|
|
65139
|
+
`);
|
|
65140
|
+
}
|
|
65141
|
+
return;
|
|
65142
|
+
}
|
|
65143
|
+
const agentName3 = process.env.SWITCHROOM_AGENT_NAME;
|
|
65144
|
+
if (!agentName3) {
|
|
65145
|
+
process.stderr.write(`telegram gateway: reaction_dispatch: skipped \u2014 SWITCHROOM_AGENT_NAME unset
|
|
65146
|
+
`);
|
|
65147
|
+
return;
|
|
65148
|
+
}
|
|
65149
|
+
let reactedText = "";
|
|
65150
|
+
if (HISTORY_ENABLED) {
|
|
65151
|
+
try {
|
|
65152
|
+
const row = lookupMessageRoleAndText(args.chatId, args.messageId);
|
|
65153
|
+
reactedText = row?.text ?? "";
|
|
65154
|
+
} catch (err) {
|
|
65155
|
+
process.stderr.write(`telegram gateway: reaction_dispatch: history lookup failed: ${err}
|
|
65156
|
+
`);
|
|
65157
|
+
}
|
|
65158
|
+
}
|
|
65159
|
+
const { text, meta } = buildReactionDispatchInbound({
|
|
65160
|
+
emoji: args.emoji,
|
|
65161
|
+
chatId: args.chatId,
|
|
65162
|
+
messageId: args.messageId,
|
|
65163
|
+
user: args.user,
|
|
65164
|
+
userId: args.userId,
|
|
65165
|
+
reactedText,
|
|
65166
|
+
...typeof args.threadId === "number" ? { threadId: args.threadId } : {}
|
|
65167
|
+
});
|
|
65168
|
+
const ts = Date.now();
|
|
65169
|
+
const inbound = {
|
|
65170
|
+
type: "inbound",
|
|
65171
|
+
chatId: args.chatId,
|
|
65172
|
+
...typeof args.threadId === "number" ? { threadId: args.threadId } : {},
|
|
65173
|
+
messageId: ts,
|
|
65174
|
+
user: args.user,
|
|
65175
|
+
userId: args.userId,
|
|
65176
|
+
ts,
|
|
65177
|
+
text,
|
|
65178
|
+
meta
|
|
65179
|
+
};
|
|
65180
|
+
const delivered = ipcServer.sendToAgent(agentName3, inbound);
|
|
65181
|
+
if (delivered)
|
|
65182
|
+
markClaudeBusyForInbound(inbound);
|
|
65183
|
+
process.stderr.write(`telegram gateway: reaction_dispatch agent=${agentName3} chat=${args.chatId} emoji=${args.emoji} message_id=${args.messageId} delivered=${delivered}
|
|
65184
|
+
`);
|
|
65185
|
+
if (!delivered) {
|
|
65186
|
+
pendingInboundBuffer.push(agentName3, inbound);
|
|
65187
|
+
}
|
|
65188
|
+
}
|
|
65037
65189
|
function flushReactionBatch(batch) {
|
|
65038
65190
|
const agentName3 = process.env.SWITCHROOM_AGENT_NAME;
|
|
65039
65191
|
if (!agentName3) {
|
|
@@ -65109,11 +65261,21 @@ async function handleMessageReaction(ctx) {
|
|
|
65109
65261
|
`);
|
|
65110
65262
|
if (action === "remove" || emoji === null)
|
|
65111
65263
|
return;
|
|
65112
|
-
if (!HISTORY_ENABLED)
|
|
65113
|
-
return;
|
|
65114
65264
|
const reacter = update.user;
|
|
65115
65265
|
if (!reacter)
|
|
65116
65266
|
return;
|
|
65267
|
+
const reacterName = reacter.first_name ?? reacter.username ?? String(reacter.id);
|
|
65268
|
+
maybeDispatchReaction({
|
|
65269
|
+
chatId: chat_id,
|
|
65270
|
+
messageId: message_id,
|
|
65271
|
+
emoji,
|
|
65272
|
+
action,
|
|
65273
|
+
user: reacterName,
|
|
65274
|
+
userId: reacter.id,
|
|
65275
|
+
...typeof update.message_thread_id === "number" ? { threadId: update.message_thread_id } : {}
|
|
65276
|
+
});
|
|
65277
|
+
if (!HISTORY_ENABLED)
|
|
65278
|
+
return;
|
|
65117
65279
|
const cfg = getReactionsConfig();
|
|
65118
65280
|
if (!cfg.enabled)
|
|
65119
65281
|
return;
|
|
@@ -65163,7 +65325,7 @@ async function handleMessageReaction(ctx) {
|
|
|
65163
65325
|
ts: Date.now(),
|
|
65164
65326
|
preview,
|
|
65165
65327
|
userId: reacter.id,
|
|
65166
|
-
user:
|
|
65328
|
+
user: reacterName,
|
|
65167
65329
|
...typeof update.message_thread_id === "number" ? { threadId: update.message_thread_id } : {}
|
|
65168
65330
|
};
|
|
65169
65331
|
getReactionDebounce().enqueue(update.chat.id, pending2);
|