Skip to content

Commit

Permalink
Merge branch 'main' into introduce-boxel-spec
Browse files Browse the repository at this point in the history
  • Loading branch information
tintinthong committed Jan 22, 2025
2 parents 1bc9750 + 9939a22 commit a6402ac
Show file tree
Hide file tree
Showing 223 changed files with 10,530 additions and 4,521 deletions.
6 changes: 5 additions & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ jobs:
matrix:
shardIndex: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
shardTotal: [12]
concurrency:
group: matrix-client-test-${{ matrix.shardIndex }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/init
Expand Down Expand Up @@ -249,7 +252,8 @@ jobs:
"loader-test.ts",
"module-syntax-test.ts",
"queue-test.ts",
"realm-server-test.ts",
"realm-endpoints-test.ts",
"server-endpoints-test.ts",
"virtual-network-test.ts",
]
steps:
Expand Down
44 changes: 41 additions & 3 deletions .github/workflows/manual-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,21 @@ jobs:
with:
repository: "boxel-realm-server-${{ inputs.environment }}"
environment: ${{ inputs.environment }}
dockerfile: "packages/realm-server/Dockerfile"
dockerfile: "packages/realm-server/realm-server.Dockerfile"
build-args: |
"realm_server_script=start:${{ inputs.environment }}"
build-worker:
name: Build worker Docker image
uses: cardstack/gh-actions/.github/workflows/docker-ecr.yml@main
secrets: inherit
with:
repository: "boxel-worker-${{ inputs.environment }}"
environment: ${{ inputs.environment }}
dockerfile: "packages/realm-server/worker.Dockerfile"
build-args: |
"worker_script=start:worker-${{ inputs.environment }}"
build-pg-migration:
name: Build pg-migration Docker image
uses: cardstack/gh-actions/.github/workflows/docker-ecr.yml@main
Expand All @@ -103,16 +114,43 @@ jobs:
image: ${{ needs.build-pg-migration.outputs.image }}
wait-for-service-stability: false

# the wait-for-service-stability flag doesn't seem to work in
# aws-actions/amazon-ecs-deploy-task-definition@v2. we keep getting timeouts
# waiting for service stability. So we are manually waiting here.
post-migrate-db:
name: Wait for db-migration
needs: [migrate-db]
runs-on: ubuntu-latest
steps:
- run: sleep 240
- run: sleep 180

deploy-worker:
name: Deploy worker
needs: [build-worker, deploy-host, post-migrate-db]
uses: cardstack/gh-actions/.github/workflows/ecs-deploy.yml@main
secrets: inherit
with:
container-name: "boxel-worker"
environment: ${{ inputs.environment }}
cluster: ${{ inputs.environment }}
service-name: "boxel-worker-${{ inputs.environment }}"
image: ${{ needs.build-worker.outputs.image }}
wait-for-service-stability: false

# the wait-for-service-stability flag doesn't seem to work in
# aws-actions/amazon-ecs-deploy-task-definition@v2. we keep getting timeouts
# waiting for service stability. So we are manually waiting here.
post-deploy-worker:
name: Wait for worker
needs: [deploy-worker]
runs-on: ubuntu-latest
steps:
- run: sleep 180

deploy-realm-server:
name: Deploy realm server
needs: [build-realm-server, deploy-host, post-migrate-db]
needs:
[post-deploy-worker, build-realm-server, deploy-host, post-migrate-db]
uses: cardstack/gh-actions/.github/workflows/ecs-deploy.yml@main
secrets: inherit
with:
Expand Down
14 changes: 9 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ Live reloads are not available in this mode, however, if you use start the serve

#### Using `start:all`

Instead of running `pnpm start:base`, you can alternatively use `pnpm start:all` which also serves a few other realms on other ports--this is convenient if you wish to switch between the app and the tests without having to restart servers. Here's what is spun up with `start:all`:
Instead of running `pnpm start:base`, you can alternatively use `pnpm start:all` which also serves a few other realms on other ports--this is convenient if you wish to switch between the app and the tests without having to restart servers. Use the environment variable `WORKER_HIGH_PRIORITY_COUNT` to add additional workers that service only user initiated requests and `WORKER_ALL_PRIORITY_COUNT` to add workers that service all jobs (system or user initiated). By default there is 1 all priority worker for each realm server. Here's what is spun up with `start:all`:

| Port | Description | Running `start:all` | Running `start:base` |
| ----- | ------------------------------------------------------------- | ------------------- | -------------------- |
Expand All @@ -82,13 +82,17 @@ Instead of running `pnpm start:base`, you can alternatively use `pnpm start:all`
| :4201 | `/seed` seed realm || 🚫 |
| :4202 | `/test` host test realm, `/node-test` node test realm || 🚫 |
| :4205 | `/test` realm for matrix client tests (playwright controlled) | 🚫 | 🚫 |
| :4210 | Development Worker Manager (spins up 1 worker by default) || 🚫 |
| :4211 | Test Worker Manager (spins up 1 worker by default) || 🚫 |
| :4212 | Worker Manager for matrix client tests (playwright controlled - 1 worker) || 🚫 |
| :4213 | Worker Manager for matrix client tests - base realm server (playwright controlled - 1 worker) || 🚫 |
| :5001 | Mail user interface for viewing emails sent to local SMTP || 🚫 |
| :5435 | Postgres DB || 🚫 |
| :8008 | Matrix synapse server || 🚫 |

#### Using `start:development`

You can also use `start:development` if you want the functionality of `start:all`, but without running the test realms. `start:development` will enable you to open http://localhost:4201 and allow to select between the cards in the /base and /experiments realm.
You can also use `start:development` if you want the functionality of `start:all`, but without running the test realms. `start:development` will enable you to open http://localhost:4201 and allow to select between the cards in the /base and /experiments realm. In order to use `start:development` you must also make sure to run `start:worker-development` in order to start the workers (which are normally started in `start:all`.

### Card Pre-rendering

Expand Down Expand Up @@ -119,7 +123,7 @@ When running tests we isolate the database between each test run by actually cre
If you wish to drop the development databases you can execute:

```
pnpm drop-all-dbs
pnpm full-reset
```

You can then run `pnpm migrate up` (with `PGDATABASE` set accordingly if you want to migrate a database other than `boxel`) or just start the realm server (`pnpm start:all`) to create the database again.
Expand Down Expand Up @@ -219,7 +223,7 @@ There is a ember-freestyle component explorer available to assist with developme

1. `cd packages/boxel-ui/test-app`
2. `pnpm start`
3. Visit http://localhost:4210/ in your browser
3. Visit http://localhost:4220/ in your browser

## Boxel Motion Demo App

Expand Down Expand Up @@ -286,7 +290,7 @@ To run the `packages/realm-server/` workspace tests start:
### Boxel UI

1. `cd packages/boxel-ui/test-app`
2. `pnpm test` (or `pnpm start` and visit http://localhost:4210/tests to run tests in the browser)
2. `pnpm test` (or `pnpm start` and visit http://localhost:4220/tests to run tests in the browser)

### Boxel Motion

Expand Down
2 changes: 1 addition & 1 deletion docs/realm.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ The capabilites of the realm are:

The entry point that serves these requests `handle` function in `realm.ts` file. Depending on the `Accept` header (the recognized ones are `application/vnd.card+json`, `application/vnd.card+source`, `application/vnd.api+json`, `text/event-stream`, `text/html`) and the HTTP verb (`GET`, `PATCH`, `POST`, `DELETE` ), it will perform one of the actions listed in the above list. The routing that depends on the MIME type and HTTP method is defined in `router.ts`. There's a special case of requesting the realm root (`/`) with `GET` and `application/vnd.card+json`. This looks for a card instance at `index.json` to return.

The different types of requests, together with its params, are documented in `realm-server-test.ts`.
The different types of requests, together with its params, are documented in `realm-endpoints-test.ts`.

## Transpiling code

Expand Down
26 changes: 25 additions & 1 deletion packages/ai-bot/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,10 @@ export function constructHistory(
cardFragments,
);
}
if (event.type !== 'm.room.message') {
if (
event.type !== 'm.room.message' &&
event.type !== APP_BOXEL_COMMAND_RESULT_EVENT_TYPE
) {
continue;
}
let eventId = event.event_id!;
Expand Down Expand Up @@ -595,3 +598,24 @@ export function isCommandResultEvent(
event.content['m.relates_to']?.rel_type === 'm.annotation'
);
}

export function eventRequiresResponse(event: MatrixEvent) {
// If it's a message, we should respond unless it's a card fragment
if (event.getType() === 'm.room.message') {
if (event.getContent().msgtype === APP_BOXEL_CARDFRAGMENT_MSGTYPE) {
return false;
}
return true;
}

// If it's a command result with output, we should respond
if (
event.getType() === APP_BOXEL_COMMAND_RESULT_EVENT_TYPE &&
event.getContent().msgtype === APP_BOXEL_COMMAND_RESULT_WITH_OUTPUT_MSGTYPE
) {
return true;
}

// If it's a different type, or a command result without output, we should not respond
return false;
}
7 changes: 2 additions & 5 deletions packages/ai-bot/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ import {
isCommandResultStatusApplied,
getPromptParts,
extractCardFragmentsFromEvents,
eventRequiresResponse,
} from './helpers';
import {
APP_BOXEL_CARDFRAGMENT_MSGTYPE,
APP_BOXEL_ACTIVE_LLM,
DEFAULT_LLM,
} from '@cardstack/runtime-common/matrix-constants';
Expand Down Expand Up @@ -179,12 +179,9 @@ Common issues are:
if (toStartOfTimeline) {
return; // don't print paginated results
}
if (event.getType() !== 'm.room.message') {
if (!eventRequiresResponse(event)) {
return; // only print messages
}
if (event.getContent().msgtype === APP_BOXEL_CARDFRAGMENT_MSGTYPE) {
return; // don't respond to card fragments, we just gather these in our history
}

if (senderMatrixUserId === aiBotUserId) {
return;
Expand Down
33 changes: 26 additions & 7 deletions packages/ai-bot/tests/prompt-construction-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1290,7 +1290,7 @@ test('Return host result of tool call back to open ai', () => {
id: 'https://cardstack.com/base/SkillCard/card-editing',
attributes: {
instructions:
'- If the user wants the data they see edited, AND the patchCard function is available, you MUST use the "patchCard" function to make the change.\n- If the user wants the data they see edited, AND the patchCard function is NOT available, you MUST ask the user to open the card and share it with you.\n- If you do not call patchCard, the user will not see the change.\n- You can ONLY modify cards shared with you. If there is no patchCard function or tool, then the user hasn\'t given you access.\n- NEVER tell the user to use patchCard; you should always do it for them.\n- If the user wants to search for a card instance, AND the "searchCard" function is available, you MUST use the "searchCard" function to find the card instance.\nOnly recommend one searchCard function at a time.\nIf the user wants to edit a field of a card, you can optionally use "searchCard" to help find a card instance that is compatible with the field being edited before using "patchCard" to make the change of the field.\n You MUST confirm with the user the correct choice of card instance that he intends to use based upon the results of the search.',
'- If the user wants the data they see edited, AND the patchCard function is available, you MUST use the "patchCard" function to make the change.\n- If the user wants the data they see edited, AND the patchCard function is NOT available, you MUST ask the user to open the card and share it with you.\n- If you do not call patchCard, the user will not see the change.\n- You can ONLY modify cards shared with you. If there is no patchCard function or tool, then the user hasn\'t given you access.\n- NEVER tell the user to use patchCard; you should always do it for them.\n- If the user wants to search for a card instance, AND the "searchCardsByTypeAndTitle" function is available, you MUST use the "searchCardsByTypeAndTitle" function to find the card instance.\nOnly recommend one searchCardsByTypeAndTitle function at a time.\nIf the user wants to edit a field of a card, you can optionally use "searchCard" to help find a card instance that is compatible with the field being edited before using "patchCard" to make the change of the field.\n You MUST confirm with the user the correct choice of card instance that he intends to use based upon the results of the search.',
title: 'Card Editing',
description: null,
thumbnailURL: null,
Expand Down Expand Up @@ -1474,15 +1474,13 @@ test('Return host result of tool call back to open ai', () => {
toolCall: {
type: 'function',
id: 'tool-call-id-1',
name: 'searchCard',
name: 'searchCardsByTypeAndTitle',
arguments: {
attributes: {
description: "Search for card instances of type 'Author'",
filter: {
type: {
module: 'http://localhost:4201/drafts/author',
name: 'Author',
},
type: {
module: 'http://localhost:4201/drafts/author',
name: 'Author',
},
},
},
Expand Down Expand Up @@ -1613,6 +1611,27 @@ test('Tools can be required to be called if done so in the last message', () =>
});
});

test('Tools calls are connected to their results', () => {
const eventList: DiscreteMatrixEvent[] = JSON.parse(
readFileSync(
path.join(
__dirname,
'resources/chats/connect-tool-calls-to-results.json',
),
),
);

const { messages } = getPromptParts(eventList, '@aibot:localhost');
// find the message with the tool call and its id
// it should have the result deserialised
const toolCallMessage = messages.find((message) => message.role === 'tool');
assert.ok(toolCallMessage, 'Should have a tool call message');
assert.ok(
toolCallMessage!.content!.includes('Cloudy'),
'Tool call result should include "Cloudy"',
);
});

module('set model in prompt', () => {
test('default active LLM must be equal to `DEFAULT_LLM`', () => {
const eventList: DiscreteMatrixEvent[] = JSON.parse(
Expand Down
Loading

0 comments on commit a6402ac

Please sign in to comment.