Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions joke-bot/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,22 @@ async function handleSlackMention(ctx: WorkforceCtx, event: AgentEvent): Promise
ctx.log?.('info', 'joke-bot.slack-no-target', { reason: 'missing channel/ts' });
return;
}
// Channel guard: only ever reply in the configured channel. The slack trigger
// wakes across channels (broad slack scope feeds the wake-path match, and the
// trigger `match` gate isn't enforced cloud-side yet), so without this joke-bot
// would answer @mentions in ANY channel. Fail CLOSED — if SLACK_CHANNEL is
// unset/miswired, don't reply at all (matching the relay/cron paths), rather
// than falling through to the event's channel. Normalize `id__name` → `id`.
const want = input(ctx, 'SLACK_CHANNEL');
const chanId = channel.split('__')[0];
if (!want) {
ctx.log?.('warn', 'joke-bot.slack-no-channel', { reason: 'SLACK_CHANNEL not set; failing closed' });
return;
}
if (chanId !== want) {
ctx.log?.('info', 'joke-bot.slack-wrong-channel', { channel: chanId, want });
return;
}
if (data.is_bot === true || data.bot_id || (typeof data.subtype === 'string' && data.subtype)) {
ctx.log?.('info', 'joke-bot.slack-skip', { reason: 'bot or non-plain message' });
return;
Expand Down
13 changes: 6 additions & 7 deletions joke-bot/persona.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,12 @@ export default definePersona({
'A conversational joke bot: DM it via the relay inbox and it replies in Slack with a pop-culture / current-events joke. Exists to confirm conversational agents + multi-turn threading work, and to test the claude/codex/opencode harnesses.',
cloud: true,

// sandbox:true (default) is required: the reply is a Slack WRITEBACK
// (slackClient().post → relayfile mount), and sandbox:false bypasses the
// relayfile mount, so the reply can't be written. The run is still fast — the
// handler answers via ctx.llm.complete (one LLM call), NOT ctx.harness.run
// (which boots a full CLI session and took minutes). Cost is just the box
// cold-start; trigger `match` (once cloud enforces it) limits when it provisions.
sandbox: true,
// No Daytona box. The handler answers via ctx.llm.complete (one LLM call) and
// the Slack writeback now goes over the relayfile HTTP API instead of the FS
// mount (relay-helpers ≥0.4.1 → adapter-core ≥0.4.2 routes writeJsonFile to
// RelayFileClient when there's no mount, using the injected RELAYFILE_TOKEN/URL).
// So no mount is needed → handler runs in the persona runner (ms), no cold start.
sandbox: false,

// ctx.llm.complete() resolves against the deployer's connected subscription
// credential (rides in providerEnv; the deploy log shows it selected for ctx.llm).
Expand Down
18 changes: 9 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"@agentworkforce/persona-kit": "^4.0.0",
"@agentworkforce/runtime": "^4.0.0",
"@relayfile/adapter-daytona": "^0.1.1",
"@relayfile/relay-helpers": "0.3.42"
"@relayfile/relay-helpers": "^0.4.1"
},
"devDependencies": {
"@types/node": "^22",
Expand Down