Skip to content

Commit 2ad413f

Browse files
committed
wip
1 parent 38b18cb commit 2ad413f

10 files changed

Lines changed: 192 additions & 5 deletions

File tree

packages/bot-runner/README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Bot Runner
2+
3+
Minimal Matrix event listener that will enqueue bot jobs in the future.
4+
5+
## Environment
6+
7+
- `MATRIX_URL` (default: `http://localhost:8008`)
8+
- `BOT_RUNNER_USERNAME` (default: `bot-runner`)
9+
- `BOT_RUNNER_PASSWORD` (default: `password`)
10+
- `LOG_LEVELS` (optional, default: `*=info`)
11+
12+
## Running
13+
14+
- `pnpm start`
15+
- `pnpm start:development`

packages/bot-runner/main.ts

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import './setup-logger'; // This should be first
2+
import { RoomMemberEvent, RoomEvent, createClient } from 'matrix-js-sdk';
3+
import { PgAdapter, PgQueuePublisher } from '@cardstack/postgres';
4+
import { logger } from '@cardstack/runtime-common';
5+
6+
const log = logger('bot-runner');
7+
const startTime = Date.now();
8+
9+
const matrixUrl = process.env.MATRIX_URL || 'http://localhost:8008';
10+
const botUsername = process.env.BOT_RUNNER_USERNAME || 'bot-runner';
11+
const botPassword = process.env.BOT_RUNNER_PASSWORD || 'password';
12+
13+
(async () => {
14+
let client = createClient({
15+
baseUrl: matrixUrl,
16+
});
17+
18+
let auth = await client.loginWithPassword(botUsername, botPassword).catch(
19+
(error) => {
20+
log.error(error);
21+
log.error(
22+
`Bot runner could not login to Matrix at ${matrixUrl}. Check credentials and server availability.`,
23+
);
24+
process.exit(1);
25+
},
26+
);
27+
28+
log.info(`logged in as ${auth.user_id}`);
29+
30+
let dbAdapter = new PgAdapter();
31+
let queuePublisher = new PgQueuePublisher(dbAdapter);
32+
33+
const shutdown = async () => {
34+
log.info('shutting down bot runner...');
35+
try {
36+
await queuePublisher.destroy();
37+
await dbAdapter.close();
38+
} catch (error) {
39+
log.error('error during shutdown', error);
40+
process.exit(1);
41+
}
42+
process.exit(0);
43+
};
44+
45+
process.on('SIGINT', shutdown);
46+
process.on('SIGTERM', shutdown);
47+
48+
client.on(RoomMemberEvent.Membership, function (event, member) {
49+
if (event.event.origin_server_ts! < startTime) {
50+
return;
51+
}
52+
if (member.membership === 'invite' && member.userId === auth.user_id) {
53+
client
54+
.joinRoom(member.roomId)
55+
.then(function () {
56+
log.info('%s auto-joined %s', member.name, member.roomId);
57+
})
58+
.catch(function (err) {
59+
log.info(
60+
'Error joining room after invite (user may have left before join)',
61+
err,
62+
);
63+
});
64+
}
65+
});
66+
67+
client.on(RoomEvent.Timeline, async (event, room, toStartOfTimeline) => {
68+
if (!room || toStartOfTimeline) {
69+
return;
70+
}
71+
72+
let senderMatrixUserId = event.getSender();
73+
if (!senderMatrixUserId || senderMatrixUserId === auth.user_id) {
74+
return;
75+
}
76+
77+
let eventBody = event.getContent()?.body || '';
78+
log.info(
79+
'received event in room %s (%s): %s',
80+
room.name,
81+
room.roomId,
82+
eventBody,
83+
);
84+
85+
// TODO: enqueue bot command job via queuePublisher.publish(...)
86+
});
87+
88+
client.startClient();
89+
log.info('bot runner listening for Matrix events');
90+
})().catch((error) => {
91+
log.error('bot runner failed to start', error);
92+
process.exit(1);
93+
});

packages/bot-runner/package.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"name": "@cardstack/bot-runner",
3+
"dependencies": {
4+
"@cardstack/postgres": "workspace:*",
5+
"@cardstack/runtime-common": "workspace:*",
6+
"matrix-js-sdk": "catalog:",
7+
"ts-node": "^10.9.2",
8+
"typescript": "catalog:"
9+
},
10+
"devDependencies": {
11+
"@cardstack/local-types": "workspace:*",
12+
"@types/node": "catalog:"
13+
},
14+
"scripts": {
15+
"start": "NODE_NO_WARNINGS=1 ts-node --transpileOnly main",
16+
"start:development": "NODE_NO_WARNINGS=1 PGDATABASE=boxel PGPORT=5435 ts-node --transpileOnly main"
17+
},
18+
"volta": {
19+
"extends": "../../package.json"
20+
}
21+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { makeLogDefinitions } from '@cardstack/runtime-common';
2+
3+
(globalThis as any)._logDefinitions = makeLogDefinitions(
4+
process.env.LOG_LEVELS || '*=info',
5+
);

packages/bot-runner/tsconfig.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"compilerOptions": {
3+
"target": "es2023",
4+
"lib": ["es2023", "dom"],
5+
"module": "nodenext",
6+
"moduleResolution": "nodenext",
7+
"allowSyntheticDefaultImports": true,
8+
"noEmit": true,
9+
"inlineSourceMap": true,
10+
"inlineSources": true,
11+
"esModuleInterop": true,
12+
"experimentalDecorators": true,
13+
"skipLibCheck": true,
14+
"strict": true,
15+
"types": ["@cardstack/local-types"]
16+
},
17+
"include": ["./**/*"]
18+
}

packages/host/app/commands/create-ai-assistant-room.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ export default class CreateAiAssistantRoomCommand extends HostBaseCommand<
5454
let { matrixService } = this;
5555
let userId = matrixService.userId;
5656
let aiBotFullId = matrixService.aiBotUserId;
57+
let botRunnerFullId = matrixService.botRunnerUserId;
5758

5859
if (!userId) {
5960
throw new Error(
@@ -88,7 +89,8 @@ export default class CreateAiAssistantRoomCommand extends HostBaseCommand<
8889
const [roomResult, commandModule] = await Promise.all([
8990
await matrixService.createRoom({
9091
preset: matrixService.privateChatPreset,
91-
invite: [aiBotFullId],
92+
//TODO: botRunner is here for testing purposes. Remove once finished
93+
invite: [aiBotFullId, botRunnerFullId],
9294
name: input.name,
9395
room_alias_name: encodeURIComponent(
9496
`${input.name} - ${format(

packages/host/app/services/matrix-service.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import type {
2828
} from '@cardstack/runtime-common';
2929
import {
3030
aiBotUsername,
31+
botRunnerUsername,
3132
logger,
3233
isCardInstance,
3334
Deferred,
@@ -400,6 +401,11 @@ export default class MatrixService extends Service {
400401
return `@${aiBotUsername}:${server}`;
401402
}
402403

404+
get botRunnerUserId() {
405+
let server = this.userId!.split(':')[1];
406+
return `@${botRunnerUsername}:${server}`;
407+
}
408+
403409
get userName() {
404410
return this.userId ? getMatrixUsername(this.userId) : null;
405411
}

packages/matrix/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,14 @@
3131
"start:admin": "ts-node --transpileOnly ./scripts/admin-console",
3232
"stop:admin": "docker stop synapse-admin && docker rm synapse-admin",
3333
"register-bot-user": "MATRIX_USERNAME=aibot MATRIX_PASSWORD=pass ts-node --transpileOnly ./scripts/register-test-user.ts",
34+
"register-bot-runner": "MATRIX_IS_ADMIN=TRUE MATRIX_USERNAME=bot-runner MATRIX_PASSWORD=password ts-node --transpileOnly ./scripts/register-test-user.ts",
3435
"register-test-user": "MATRIX_USERNAME=user MATRIX_PASSWORD=password ts-node --transpileOnly ./scripts/register-test-user.ts",
3536
"register-skills-writer": "MATRIX_USERNAME=skills_writer MATRIX_PASSWORD=password ts-node --transpileOnly ./scripts/register-test-user.ts",
3637
"register-homepage-writer": "MATRIX_USERNAME=homepage_writer MATRIX_PASSWORD=password ts-node --transpileOnly ./scripts/register-test-user.ts",
3738
"register-realm-users": "./scripts/register-realm-users.sh",
3839
"register-test-admin": "MATRIX_IS_ADMIN=TRUE MATRIX_USERNAME=admin MATRIX_PASSWORD=password ts-node --transpileOnly ./scripts/register-test-user.ts",
3940
"register-test-admin-and-token": "pnpm register-test-admin && ts-node --transpileOnly ./scripts/register-test-token.ts",
40-
"register-all": "pnpm register-test-admin-and-token && pnpm register-realm-users && pnpm register-bot-user && pnpm register-test-user && pnpm register-skills-writer && pnpm register-homepage-writer",
41+
"register-all": "pnpm register-test-admin-and-token && pnpm register-realm-users && pnpm register-bot-user && pnpm register-bot-runner && pnpm register-test-user && pnpm register-skills-writer && pnpm register-homepage-writer",
4142
"test": "./scripts/test.sh",
4243
"test:group": "./scripts/test.sh",
4344
"wait": "sleep 10000000",

packages/runtime-common/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ export const realmURL = Symbol.for('cardstack-realm-url');
4242
export const relativeTo = Symbol.for('cardstack-relative-to');
4343

4444
export const aiBotUsername = 'aibot';
45+
export const botRunnerUsername = 'bot-runner';
4546

4647
export const CardContextName = 'card-context';
4748
export const CardCrudFunctionsContextName = 'card-crud-functions-context';

pnpm-lock.yaml

Lines changed: 28 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)