openbot 0.5.10 → 0.5.11

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/app/cli.js CHANGED
@@ -18,7 +18,7 @@ function checkNodeVersion() {
18
18
  }
19
19
  }
20
20
  checkNodeVersion();
21
- program.name('openbot').description('OpenBot CLI').version('0.5.10');
21
+ program.name('openbot').description('OpenBot CLI').version('0.5.11');
22
22
  program
23
23
  .command('start')
24
24
  .description('Start the OpenBot harness')
@@ -447,7 +447,7 @@ export async function startServer(options = {}) {
447
447
  }
448
448
  });
449
449
  const WEBHOOK_TIMEOUT_MS = Number(process.env.OPENBOT_WEBHOOK_TIMEOUT_MS ?? 30000);
450
- app.post('/api/webhooks/:provider', async (req, res) => {
450
+ const handleInboundWebhook = async (req, res) => {
451
451
  const provider = req.params.provider?.trim();
452
452
  if (!provider || !/^[a-z0-9][a-z0-9_-]*$/i.test(provider)) {
453
453
  res.status(400).json({ error: 'Invalid webhook provider' });
@@ -471,6 +471,7 @@ export async function startServer(options = {}) {
471
471
  type: 'action:webhook',
472
472
  data: {
473
473
  provider,
474
+ method: req.method,
474
475
  rawBody: rawBody.toString('base64'),
475
476
  headers: pickWebhookHeaders(req),
476
477
  query: req.query,
@@ -478,14 +479,6 @@ export async function startServer(options = {}) {
478
479
  };
479
480
  try {
480
481
  ensureEventId(event);
481
- console.log('runAgent', {
482
- runId,
483
- agentId,
484
- event,
485
- persistEvents: true,
486
- publicBaseUrl: resolvePublicBaseUrl(),
487
- onEvent,
488
- });
489
482
  const runPromise = runAgent({
490
483
  runId,
491
484
  agentId,
@@ -511,6 +504,7 @@ export async function startServer(options = {}) {
511
504
  const isTimeout = error instanceof Error && error.message === 'webhook_timeout';
512
505
  console.error('[webhook] Failed to process inbound webhook', {
513
506
  provider,
507
+ method: req.method,
514
508
  agentId,
515
509
  error,
516
510
  });
@@ -520,7 +514,9 @@ export async function startServer(options = {}) {
520
514
  }
521
515
  respondAgentDispatchError(res, error, 'Failed to process webhook');
522
516
  }
523
- });
517
+ };
518
+ app.get('/api/webhooks/:provider', handleInboundWebhook);
519
+ app.post('/api/webhooks/:provider', handleInboundWebhook);
524
520
  app.get('/api/state', async (req, res) => {
525
521
  let event;
526
522
  try {
@@ -14,7 +14,7 @@ export function respondAgentDispatchError(res, error, fallbackMessage) {
14
14
  res.status(500).json({ error: fallbackMessage });
15
15
  }
16
16
  /**
17
- * Routes `POST /api/webhooks/:provider` to agent `<provider>` when that agent exists,
17
+ * Routes `GET`/`POST /api/webhooks/:provider` to agent `<provider>` when that agent exists,
18
18
  * otherwise falls back to {@link WEBHOOK_AGENT_FALLBACK_ID}.
19
19
  */
20
20
  export async function resolveWebhookAgentId(provider) {
package/docs/plugins.md CHANGED
@@ -62,16 +62,28 @@ model as the tool result (`history.ts`). Structured fields (e.g. `list`,
62
62
 
63
63
  ## Inbound webhooks
64
64
 
65
- `POST /api/webhooks/:provider` forwards third-party HTTP payloads onto the bus as
66
- `action:webhook`. The URL segment is used as the target agent id when
65
+ `GET` and `POST /api/webhooks/:provider` forward third-party HTTP requests onto the
66
+ bus as `action:webhook`. The URL segment is used as the target agent id when
67
67
  `~/.openbot/agents/<provider>/AGENT.md` exists; otherwise the request falls back
68
68
  to the `system` agent. Attach a plugin to the routed agent and handle
69
69
  verification, channel/thread routing, transforms, and HTTP responses there.
70
70
 
71
+ GET requests have an empty `rawBody`; use `event.data.method` and `event.data.query`
72
+ for URL verification challenges (for example Meta `hub.challenge`).
73
+
71
74
  ```ts
72
75
  builder.on('action:webhook', async function* (event) {
73
76
  if (event.data?.provider !== 'slack') return;
74
77
 
78
+ if (event.data.method === 'GET') {
79
+ const challenge = event.data.query?.['hub.challenge'];
80
+ yield {
81
+ type: 'action:webhook:http-response',
82
+ data: { status: 200, body: String(challenge) },
83
+ };
84
+ return;
85
+ }
86
+
75
87
  const rawBody = Buffer.from(event.data.rawBody, 'base64');
76
88
 
77
89
  // Optional: control the HTTP response (URL challenges, 401s, custom acks)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openbot",
3
- "version": "0.5.10",
3
+ "version": "0.5.11",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "engines": {
@@ -11,7 +11,7 @@
11
11
  "build": "tsc && mkdir -p dist/assets && cp src/assets/icon.svg dist/assets/icon.svg",
12
12
  "start": "node dist/app/cli.js start",
13
13
  "format": "prettier --write .",
14
- "push": "fly deploy --build-only --push --config deploy/fly.toml -a openbot-runtime --image-label v0.5.10"
14
+ "push": "fly deploy --build-only --push --config deploy/fly.toml -a openbot-runtime --image-label v0.5.11"
15
15
  },
16
16
  "bin": {
17
17
  "openbot": "./dist/app/cli.js"
package/src/app/cli.ts CHANGED
@@ -27,7 +27,7 @@ function checkNodeVersion() {
27
27
 
28
28
  checkNodeVersion();
29
29
 
30
- program.name('openbot').description('OpenBot CLI').version('0.5.10');
30
+ program.name('openbot').description('OpenBot CLI').version('0.5.11');
31
31
 
32
32
  program
33
33
  .command('start')
package/src/app/server.ts CHANGED
@@ -127,7 +127,7 @@ export async function startServer(options: ServerOptions = {}) {
127
127
  const threadId = parts[1]; // undefined if no ":"
128
128
  storageService
129
129
  .setLastRead({ channelId, threadId, lastReadEventId: chunk.id })
130
- .catch(() => { });
130
+ .catch(() => {});
131
131
  }
132
132
 
133
133
  threadClients.forEach((client) => {
@@ -266,7 +266,7 @@ export async function startServer(options: ServerOptions = {}) {
266
266
  return storageService.setLastRead({ channelId, threadId, lastReadEventId: latestId });
267
267
  }
268
268
  })
269
- .catch(() => { });
269
+ .catch(() => {});
270
270
  }
271
271
 
272
272
  if (channelId === GLOBAL_CHANNEL_ID) {
@@ -539,7 +539,7 @@ export async function startServer(options: ServerOptions = {}) {
539
539
 
540
540
  const WEBHOOK_TIMEOUT_MS = Number(process.env.OPENBOT_WEBHOOK_TIMEOUT_MS ?? 30_000);
541
541
 
542
- app.post('/api/webhooks/:provider', async (req, res) => {
542
+ const handleInboundWebhook = async (req: express.Request, res: express.Response) => {
543
543
  const provider = req.params.provider?.trim();
544
544
  if (!provider || !/^[a-z0-9][a-z0-9_-]*$/i.test(provider)) {
545
545
  res.status(400).json({ error: 'Invalid webhook provider' });
@@ -567,6 +567,7 @@ export async function startServer(options: ServerOptions = {}) {
567
567
  type: 'action:webhook',
568
568
  data: {
569
569
  provider,
570
+ method: req.method,
570
571
  rawBody: rawBody.toString('base64'),
571
572
  headers: pickWebhookHeaders(req),
572
573
  query: req.query as Record<string, unknown>,
@@ -576,15 +577,6 @@ export async function startServer(options: ServerOptions = {}) {
576
577
  try {
577
578
  ensureEventId(event);
578
579
 
579
- console.log('runAgent', {
580
- runId,
581
- agentId,
582
- event,
583
- persistEvents: true,
584
- publicBaseUrl: resolvePublicBaseUrl(),
585
- onEvent,
586
- });
587
-
588
580
  const runPromise = runAgent({
589
581
  runId,
590
582
  agentId,
@@ -610,6 +602,7 @@ export async function startServer(options: ServerOptions = {}) {
610
602
  const isTimeout = error instanceof Error && error.message === 'webhook_timeout';
611
603
  console.error('[webhook] Failed to process inbound webhook', {
612
604
  provider,
605
+ method: req.method,
613
606
  agentId,
614
607
  error,
615
608
  });
@@ -621,7 +614,10 @@ export async function startServer(options: ServerOptions = {}) {
621
614
 
622
615
  respondAgentDispatchError(res, error, 'Failed to process webhook');
623
616
  }
624
- });
617
+ };
618
+
619
+ app.get('/api/webhooks/:provider', handleInboundWebhook);
620
+ app.post('/api/webhooks/:provider', handleInboundWebhook);
625
621
 
626
622
  app.get('/api/state', async (req, res) => {
627
623
  let event: OpenBotEvent;
package/src/app/types.ts CHANGED
@@ -148,11 +148,12 @@ export type GetActiveRunsEvent = BaseEvent & {
148
148
  type: 'action:storage:get-active-runs';
149
149
  };
150
150
 
151
- /** Inbound third-party webhook forwarded from `POST /api/webhooks/:provider`. */
151
+ /** Inbound third-party webhook forwarded from `GET`/`POST /api/webhooks/:provider`. */
152
152
  export type WebhookEvent = BaseEvent & {
153
153
  type: 'action:webhook';
154
154
  data: {
155
155
  provider: string;
156
+ method: string;
156
157
  /** Request body encoded as base64 so plugins can verify HMACs on the raw bytes. */
157
158
  rawBody: string;
158
159
  headers: Record<string, string | string[] | undefined>;
@@ -24,7 +24,7 @@ export function respondAgentDispatchError(
24
24
  }
25
25
 
26
26
  /**
27
- * Routes `POST /api/webhooks/:provider` to agent `<provider>` when that agent exists,
27
+ * Routes `GET`/`POST /api/webhooks/:provider` to agent `<provider>` when that agent exists,
28
28
  * otherwise falls back to {@link WEBHOOK_AGENT_FALLBACK_ID}.
29
29
  */
30
30
  export async function resolveWebhookAgentId(provider: string): Promise<string> {