diff --git a/docs/README.md b/docs/README.md index 6a0cc26529..c474aaee02 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,4 +1,3 @@ - # Documentation about Boxel ## Prerequisites @@ -9,13 +8,13 @@ It also has a feature to save an .svg image, which be opened in Chrome for a dec ## Concepts -The following are important concepts: +The following are important concepts: -- [Card and Field Definition Relationships](card-def-field-def-relationships.md): There is a subtle distinction between card and fields to consider when creating cards. -- [Inheritance](card-inheritance.md): Cards can be extended based upon user's custom needs -- no reinventing the wheel. -- [Rendering](card-rendering.md): Cards can be rendered easily in the browser. Each card renders differently based upon how it is related and what context it exists in. +- [Card and Field Definition Relationships](card-def-field-def-relationships.md): There is a subtle distinction between card and fields to consider when creating cards. +- [Inheritance](card-inheritance.md): Cards can be extended based upon user's custom needs -- no reinventing the wheel. +- [Rendering](card-rendering.md): Cards can be rendered easily in the browser. Each card renders differently based upon how it is related and what context it exists in. - [Serialization and Deserialization](card-serialization-deserialization.md): Cards have to be adapted to a consistent JSON format before being sent over-the-wire to other consumers. -- [Computed Fields](computed-fields.md): Computed fields work too! We can compute on the data that is already contained in a card to build more complex logic. -- [Indexing](indexing.md): Indexing powers the re-rendering of cards when it's dependencies get updated. +- [Computed Fields](computed-fields.md): Computed fields work too! We can compute on the data that is already contained in a card to build more complex logic. +- [Indexing](indexing.md): Indexing powers the re-rendering of cards when it's dependencies get updated. - [Realm](realm.md): Realms are storage for cards that have their own underlying permissions and indexer. -- [Search](search.md): Every Card is searchable within and across realms. \ No newline at end of file +- [Search](search.md): Every Card is searchable within and across realms. diff --git a/docs/queue.md b/docs/queue.md index f8c98a1393..0b6cc3326d 100644 --- a/docs/queue.md +++ b/docs/queue.md @@ -1,29 +1,33 @@ Our queue system is postgres based job queue system (resurrected from hub v2). This leverages postgres pub/sub capabilities to create a job queue system that implements our `Queue` interface (we previously created a mock queue that implements this same interface for browser testing). -The queue is controlled by the `jobs` table. We can monitor and control our queue using this table. The following is an example query of this table after running our tests. +The queue is controlled by the `jobs` table. We can monitor and control our queue using this table. The following is an example query of this table after running our tests. ``` > SELECT * FROM JOBS; - - id | category | args | status | created_at | finished_at | queue | result + + id | category | args | status | created_at | finished_at | queue | result ----+-----------+------+----------+----------------------------+----------------------------+-----------------+-------- 1 | increment | 17 | resolved | 2024-04-19 16:57:43.305961 | 2024-04-19 16:57:43.311274 | increment-queue | 18 ``` On system start up we can register job handlers whose responsibility it is to run queued jobs (these handlers can horizontally scale if we so choose). A handler registration looks like this: + ```ts queue.register('increment', async (a: number) => a + 1); ``` -This is a real simple example that just adds 1 to the job's input arguments. A handler ran return an async result as JSONB value which is stored in the `jobs.result` column of the `jobs` table. This handler defines a "category" called `increment` for this function that it has registered. A handler processes the queue by looking for the oldest job that isn't running and handles that first. + +This is a real simple example that just adds 1 to the job's input arguments. A handler ran return an async result as JSONB value which is stored in the `jobs.result` column of the `jobs` table. This handler defines a "category" called `increment` for this function that it has registered. A handler processes the queue by looking for the oldest job that isn't running and handles that first. Clients of the queue that wish to run jobs can do so by specifying the category of job that they wish to run, the queue that they wish to use, and input arguments for the job (the input arguments can be a JSONB value which is stored in the `jobs.args` column of the `jobs` table). + ```ts let job = await queue.publish('increment', 17, { queueName: 'increment-queue', }); ``` + The caller is handed a `job` object. This object has an `id` property and a `done` property that returns a promise for the job's return value (which is a parameterized type) when the job is completed. Note that the `queueName` is optional. If no name is supplied then the queue name `"default"` is used. The `queueName` is used to control job concurrency. Jobs are processed in each `queueName` serially. -When a job is first published to a queue it is assigned a status of `unfulfilled`. When a job has completed successfully it is assigned a status of `resolved`. If a job throws an error it is assigned a status of `rejected` and the error is serialized in the `jobs.result` column. +When a job is first published to a queue it is assigned a status of `unfulfilled`. When a job has completed successfully it is assigned a status of `resolved`. If a job throws an error it is assigned a status of `rejected` and the error is serialized in the `jobs.result` column. -Using SQL you can monitor the progress of the jobs in the queue, as well as, you can manipulate the results of the queue processing by setting `jobs.status`, `jobs.result`, and `jobs.queueName` using SQL. \ No newline at end of file +Using SQL you can monitor the progress of the jobs in the queue, as well as, you can manipulate the results of the queue processing by setting `jobs.status`, `jobs.result`, and `jobs.queueName` using SQL. diff --git a/package.json b/package.json index c8598c1a57..1940f0f5d0 100644 --- a/package.json +++ b/package.json @@ -27,13 +27,11 @@ "@embroider/util": "1.13.1", "@glimmer/tracking>@glimmer/validator": "0.84.3", "jsesc": "^3.0.0", - "ember-modifier": "^4.1.0", - "prettier": "github:cardstack/prettier#glimmer-style-tag-in-template-support" + "ember-modifier": "^4.1.0" }, "peerDependencyRules": { "allowedVersions": { "mustache": "3", - "prettier@github:cardstack/prettier#glimmer-style-tag-in-template-support": "3.1.0-dev", "ember-qunit@5.1.2>ember-source": "*" } }, @@ -70,7 +68,7 @@ "eslint-plugin-prefer-let": "^3.0.1", "eslint-plugin-prettier": "^5.0.0", "hcl2-parser": "^1.0.3", - "prettier": "^2.7.1", + "prettier": "^3.5.1", "prettier-plugin-ember-template-tag": "^1.1.0", "typescript": "~5.1.6" }, diff --git a/packages/ai-bot/tests/resources/chats/connect-tool-calls-to-results.json b/packages/ai-bot/tests/resources/chats/connect-tool-calls-to-results.json index 5ee89e8e60..60de9dcbc6 100644 --- a/packages/ai-bot/tests/resources/chats/connect-tool-calls-to-results.json +++ b/packages/ai-bot/tests/resources/chats/connect-tool-calls-to-results.json @@ -819,4 +819,4 @@ "user_id": "@aibot:localhost", "age": 48448 } -] \ No newline at end of file +] diff --git a/packages/ai-bot/tests/resources/chats/set-active-llm.json b/packages/ai-bot/tests/resources/chats/set-active-llm.json index 68d6d48ab3..718ae1d0a7 100644 --- a/packages/ai-bot/tests/resources/chats/set-active-llm.json +++ b/packages/ai-bot/tests/resources/chats/set-active-llm.json @@ -1,232 +1,202 @@ [ - { - "type": "m.room.create", - "room_id": "!ycnlQsqkSRyIlCeddx:localhost", - "sender": "@user:localhost", - "content": { - "room_version": "10", - "creator": "@user:localhost" - }, - "state_key": "", - "origin_server_ts": 1733266515853, - "unsigned": { - "age": 118196 - }, - "event_id": "$8lJX2OE_akNbPnqCKdYshidkXPOGUf4E6l-bepTt8hk", - "user_id": "@user:localhost", + { + "type": "m.room.create", + "room_id": "!ycnlQsqkSRyIlCeddx:localhost", + "sender": "@user:localhost", + "content": { + "room_version": "10", + "creator": "@user:localhost" + }, + "state_key": "", + "origin_server_ts": 1733266515853, + "unsigned": { "age": 118196 }, - { - "type": "m.room.member", - "room_id": "!ycnlQsqkSRyIlCeddx:localhost", - "sender": "@user:localhost", - "content": { - "membership": "join", - "displayname": "user" - }, - "state_key": "@user:localhost", - "origin_server_ts": 1733266516149, - "unsigned": { - "age": 117900 - }, - "event_id": "$5EXBBhQszWK21oqzn_uuNACK9mh5CU7Pb4Rb4nMkR7c", - "user_id": "@user:localhost", + "event_id": "$8lJX2OE_akNbPnqCKdYshidkXPOGUf4E6l-bepTt8hk", + "user_id": "@user:localhost", + "age": 118196 + }, + { + "type": "m.room.member", + "room_id": "!ycnlQsqkSRyIlCeddx:localhost", + "sender": "@user:localhost", + "content": { + "membership": "join", + "displayname": "user" + }, + "state_key": "@user:localhost", + "origin_server_ts": 1733266516149, + "unsigned": { "age": 117900 }, - { - "type": "m.room.power_levels", - "room_id": "!ycnlQsqkSRyIlCeddx:localhost", - "sender": "@user:localhost", - "content": { - "users": { - "@user:localhost": 100 - }, - "users_default": 0, - "events": { - "m.room.name": 50, - "m.room.power_levels": 100, - "m.room.history_visibility": 100, - "m.room.canonical_alias": 50, - "m.room.avatar": 50, - "m.room.tombstone": 100, - "m.room.server_acl": 100, - "m.room.encryption": 100 - }, - "events_default": 0, - "state_default": 50, - "ban": 50, - "kick": 50, - "redact": 50, - "invite": 0, - "historical": 100 - }, - "state_key": "", - "origin_server_ts": 1733266516406, - "unsigned": { - "age": 117643 - }, - "event_id": "$uXNeSgAl8qClK7ojcrS_zJv8_w3MeLormozbCpWgqlI", - "user_id": "@user:localhost", + "event_id": "$5EXBBhQszWK21oqzn_uuNACK9mh5CU7Pb4Rb4nMkR7c", + "user_id": "@user:localhost", + "age": 117900 + }, + { + "type": "m.room.power_levels", + "room_id": "!ycnlQsqkSRyIlCeddx:localhost", + "sender": "@user:localhost", + "content": { + "users": { + "@user:localhost": 100 + }, + "users_default": 0, + "events": { + "m.room.name": 50, + "m.room.power_levels": 100, + "m.room.history_visibility": 100, + "m.room.canonical_alias": 50, + "m.room.avatar": 50, + "m.room.tombstone": 100, + "m.room.server_acl": 100, + "m.room.encryption": 100 + }, + "events_default": 0, + "state_default": 50, + "ban": 50, + "kick": 50, + "redact": 50, + "invite": 0, + "historical": 100 + }, + "state_key": "", + "origin_server_ts": 1733266516406, + "unsigned": { "age": 117643 }, - { - "type": "m.room.canonical_alias", - "room_id": "!ycnlQsqkSRyIlCeddx:localhost", - "sender": "@user:localhost", - "content": { - "alias": "#New%20AI%20Assistant%20Chat%20-%202024-12-03T17%3A55%3A15.752-05%3A00%20-%20%40user%3Alocalhost:localhost" - }, - "state_key": "", - "origin_server_ts": 1733266516412, - "unsigned": { - "age": 117637 - }, - "event_id": "$BPL4mUBOnt25eBgHR5s8zF0HA-vRdcwiiAJISWUR_9U", - "user_id": "@user:localhost", + "event_id": "$uXNeSgAl8qClK7ojcrS_zJv8_w3MeLormozbCpWgqlI", + "user_id": "@user:localhost", + "age": 117643 + }, + { + "type": "m.room.canonical_alias", + "room_id": "!ycnlQsqkSRyIlCeddx:localhost", + "sender": "@user:localhost", + "content": { + "alias": "#New%20AI%20Assistant%20Chat%20-%202024-12-03T17%3A55%3A15.752-05%3A00%20-%20%40user%3Alocalhost:localhost" + }, + "state_key": "", + "origin_server_ts": 1733266516412, + "unsigned": { "age": 117637 }, - { - "type": "m.room.join_rules", - "room_id": "!ycnlQsqkSRyIlCeddx:localhost", - "sender": "@user:localhost", - "content": { - "join_rule": "invite" - }, - "state_key": "", - "origin_server_ts": 1733266516413, - "unsigned": { - "age": 117636 - }, - "event_id": "$kuR8bA7VNU_2qKXyT4gRDK4DOwlywpQJLIz6wTScnvg", - "user_id": "@user:localhost", + "event_id": "$BPL4mUBOnt25eBgHR5s8zF0HA-vRdcwiiAJISWUR_9U", + "user_id": "@user:localhost", + "age": 117637 + }, + { + "type": "m.room.join_rules", + "room_id": "!ycnlQsqkSRyIlCeddx:localhost", + "sender": "@user:localhost", + "content": { + "join_rule": "invite" + }, + "state_key": "", + "origin_server_ts": 1733266516413, + "unsigned": { "age": 117636 }, - { - "type": "m.room.history_visibility", - "room_id": "!ycnlQsqkSRyIlCeddx:localhost", - "sender": "@user:localhost", - "content": { - "history_visibility": "shared" - }, - "state_key": "", - "origin_server_ts": 1733266516413, - "unsigned": { - "age": 117636 - }, - "event_id": "$-INaWcDkl6WB_2lawtsaW57KWrpYVaJGi9LzutkwY3s", - "user_id": "@user:localhost", + "event_id": "$kuR8bA7VNU_2qKXyT4gRDK4DOwlywpQJLIz6wTScnvg", + "user_id": "@user:localhost", + "age": 117636 + }, + { + "type": "m.room.history_visibility", + "room_id": "!ycnlQsqkSRyIlCeddx:localhost", + "sender": "@user:localhost", + "content": { + "history_visibility": "shared" + }, + "state_key": "", + "origin_server_ts": 1733266516413, + "unsigned": { "age": 117636 }, - { - "type": "m.room.guest_access", - "room_id": "!ycnlQsqkSRyIlCeddx:localhost", - "sender": "@user:localhost", - "content": { - "guest_access": "can_join" - }, - "state_key": "", - "origin_server_ts": 1733266516414, - "unsigned": { - "age": 117635 - }, - "event_id": "$fa11iun8CJBeKLUPc1WHXjNjM-jnoX5pt53KR92PX14", - "user_id": "@user:localhost", + "event_id": "$-INaWcDkl6WB_2lawtsaW57KWrpYVaJGi9LzutkwY3s", + "user_id": "@user:localhost", + "age": 117636 + }, + { + "type": "m.room.guest_access", + "room_id": "!ycnlQsqkSRyIlCeddx:localhost", + "sender": "@user:localhost", + "content": { + "guest_access": "can_join" + }, + "state_key": "", + "origin_server_ts": 1733266516414, + "unsigned": { "age": 117635 }, - { - "type": "m.room.name", - "room_id": "!ycnlQsqkSRyIlCeddx:localhost", - "sender": "@user:localhost", - "content": { - "name": "New AI Assistant Chat" - }, - "state_key": "", - "origin_server_ts": 1733266516414, - "unsigned": { - "age": 117635 - }, - "event_id": "$YZnZNhUi7xkBDNvlPKGEJvGvoyBASAW-ngPeBS0Mo0M", - "user_id": "@user:localhost", + "event_id": "$fa11iun8CJBeKLUPc1WHXjNjM-jnoX5pt53KR92PX14", + "user_id": "@user:localhost", + "age": 117635 + }, + { + "type": "m.room.name", + "room_id": "!ycnlQsqkSRyIlCeddx:localhost", + "sender": "@user:localhost", + "content": { + "name": "New AI Assistant Chat" + }, + "state_key": "", + "origin_server_ts": 1733266516414, + "unsigned": { "age": 117635 }, - { - "type": "m.room.member", - "room_id": "!ycnlQsqkSRyIlCeddx:localhost", - "sender": "@user:localhost", - "content": { - "membership": "invite", - "displayname": "aibot" - }, - "state_key": "@aibot:localhost", - "origin_server_ts": 1733266516880, - "unsigned": { - "age": 117169 - }, - "event_id": "$4CG8ZfV6yyNTH8qukH0d7ODp0zSXS_Mp0zX_UkgLnNY", - "user_id": "@user:localhost", + "event_id": "$YZnZNhUi7xkBDNvlPKGEJvGvoyBASAW-ngPeBS0Mo0M", + "user_id": "@user:localhost", + "age": 117635 + }, + { + "type": "m.room.member", + "room_id": "!ycnlQsqkSRyIlCeddx:localhost", + "sender": "@user:localhost", + "content": { + "membership": "invite", + "displayname": "aibot" + }, + "state_key": "@aibot:localhost", + "origin_server_ts": 1733266516880, + "unsigned": { "age": 117169 }, - { - "type": "m.room.power_levels", - "room_id": "!ycnlQsqkSRyIlCeddx:localhost", - "sender": "@user:localhost", - "content": { - "users": { - "@user:localhost": 100, - "@aibot:localhost": 50 - }, - "users_default": 0, - "events": { - "m.room.name": 50, - "m.room.power_levels": 100, - "m.room.history_visibility": 100, - "m.room.canonical_alias": 50, - "m.room.avatar": 50, - "m.room.tombstone": 100, - "m.room.server_acl": 100, - "m.room.encryption": 100 - }, - "events_default": 0, - "state_default": 50, - "ban": 50, - "kick": 50, - "redact": 50, - "invite": 0, - "historical": 100 - }, - "state_key": "", - "origin_server_ts": 1733266517258, - "unsigned": { - "replaces_state": "$uXNeSgAl8qClK7ojcrS_zJv8_w3MeLormozbCpWgqlI", - "prev_content": { - "users": { - "@user:localhost": 100 - }, - "users_default": 0, - "events": { - "m.room.name": 50, - "m.room.power_levels": 100, - "m.room.history_visibility": 100, - "m.room.canonical_alias": 50, - "m.room.avatar": 50, - "m.room.tombstone": 100, - "m.room.server_acl": 100, - "m.room.encryption": 100 - }, - "events_default": 0, - "state_default": 50, - "ban": 50, - "kick": 50, - "redact": 50, - "invite": 0, - "historical": 100 - }, - "prev_sender": "@user:localhost", - "age": 116791 - }, - "event_id": "$fGy-zCIKjDDYskyLeY0qziNJINy5OP4JEibBd-SFnw4", - "user_id": "@user:localhost", - "age": 116791, + "event_id": "$4CG8ZfV6yyNTH8qukH0d7ODp0zSXS_Mp0zX_UkgLnNY", + "user_id": "@user:localhost", + "age": 117169 + }, + { + "type": "m.room.power_levels", + "room_id": "!ycnlQsqkSRyIlCeddx:localhost", + "sender": "@user:localhost", + "content": { + "users": { + "@user:localhost": 100, + "@aibot:localhost": 50 + }, + "users_default": 0, + "events": { + "m.room.name": 50, + "m.room.power_levels": 100, + "m.room.history_visibility": 100, + "m.room.canonical_alias": 50, + "m.room.avatar": 50, + "m.room.tombstone": 100, + "m.room.server_acl": 100, + "m.room.encryption": 100 + }, + "events_default": 0, + "state_default": 50, + "ban": 50, + "kick": 50, + "redact": 50, + "invite": 0, + "historical": 100 + }, + "state_key": "", + "origin_server_ts": 1733266517258, + "unsigned": { "replaces_state": "$uXNeSgAl8qClK7ojcrS_zJv8_w3MeLormozbCpWgqlI", "prev_content": { "users": { @@ -250,141 +220,170 @@ "redact": 50, "invite": 0, "historical": 100 - } - }, - { - "type": "m.room.member", - "room_id": "!ycnlQsqkSRyIlCeddx:localhost", - "sender": "@aibot:localhost", - "content": { - "membership": "join", - "displayname": "aibot" - }, - "state_key": "@aibot:localhost", - "origin_server_ts": 1733266517883, - "unsigned": { - "replaces_state": "$4CG8ZfV6yyNTH8qukH0d7ODp0zSXS_Mp0zX_UkgLnNY", - "prev_content": { - "membership": "invite", - "displayname": "aibot" - }, - "prev_sender": "@user:localhost", - "age": 116166 }, - "event_id": "$gQDUwu8GbsptlqcYPp9K8BpC7SaWHxQdvwQZOU0EYVQ", - "user_id": "@aibot:localhost", - "age": 116166, + "prev_sender": "@user:localhost", + "age": 116791 + }, + "event_id": "$fGy-zCIKjDDYskyLeY0qziNJINy5OP4JEibBd-SFnw4", + "user_id": "@user:localhost", + "age": 116791, + "replaces_state": "$uXNeSgAl8qClK7ojcrS_zJv8_w3MeLormozbCpWgqlI", + "prev_content": { + "users": { + "@user:localhost": 100 + }, + "users_default": 0, + "events": { + "m.room.name": 50, + "m.room.power_levels": 100, + "m.room.history_visibility": 100, + "m.room.canonical_alias": 50, + "m.room.avatar": 50, + "m.room.tombstone": 100, + "m.room.server_acl": 100, + "m.room.encryption": 100 + }, + "events_default": 0, + "state_default": 50, + "ban": 50, + "kick": 50, + "redact": 50, + "invite": 0, + "historical": 100 + } + }, + { + "type": "m.room.member", + "room_id": "!ycnlQsqkSRyIlCeddx:localhost", + "sender": "@aibot:localhost", + "content": { + "membership": "join", + "displayname": "aibot" + }, + "state_key": "@aibot:localhost", + "origin_server_ts": 1733266517883, + "unsigned": { "replaces_state": "$4CG8ZfV6yyNTH8qukH0d7ODp0zSXS_Mp0zX_UkgLnNY", "prev_content": { "membership": "invite", "displayname": "aibot" - } - }, - { - "type": "app.boxel.active-llm", - "room_id": "!ycnlQsqkSRyIlCeddx:localhost", - "sender": "@user:localhost", - "content": { - "model": "openai/gpt-4o" - }, - "state_key": "", - "origin_server_ts": 1733266518032, - "unsigned": { - "age": 116017 }, - "event_id": "$1pZDTUqrUOHjIxwYuywpDs-5jiY-kyu0d2LshvMIrqU", - "user_id": "@user:localhost", + "prev_sender": "@user:localhost", + "age": 116166 + }, + "event_id": "$gQDUwu8GbsptlqcYPp9K8BpC7SaWHxQdvwQZOU0EYVQ", + "user_id": "@aibot:localhost", + "age": 116166, + "replaces_state": "$4CG8ZfV6yyNTH8qukH0d7ODp0zSXS_Mp0zX_UkgLnNY", + "prev_content": { + "membership": "invite", + "displayname": "aibot" + } + }, + { + "type": "app.boxel.active-llm", + "room_id": "!ycnlQsqkSRyIlCeddx:localhost", + "sender": "@user:localhost", + "content": { + "model": "openai/gpt-4o" + }, + "state_key": "", + "origin_server_ts": 1733266518032, + "unsigned": { "age": 116017 }, - { - "type": "app.boxel.active-llm", - "room_id": "!ycnlQsqkSRyIlCeddx:localhost", - "sender": "@user:localhost", - "content": { - "model": "google/gemini-pro-1.5" - }, - "state_key": "", - "origin_server_ts": 1733266540113, - "unsigned": { - "replaces_state": "$1pZDTUqrUOHjIxwYuywpDs-5jiY-kyu0d2LshvMIrqU", - "prev_content": { - "enabledEventIds": ["$McWbvIHD4AA5QeaBJthLoINc1XqE-5a5XpthRFvP0eE"], - "disabledEventIds": [] - }, - "prev_sender": "@user:localhost", - "age": 93936 - }, - "event_id": "$pcL3-132rbsFZHHFDfhkSw2S4lmPbEMOIt3SuEM5YQg", - "user_id": "@user:localhost", - "age": 93936, + "event_id": "$1pZDTUqrUOHjIxwYuywpDs-5jiY-kyu0d2LshvMIrqU", + "user_id": "@user:localhost", + "age": 116017 + }, + { + "type": "app.boxel.active-llm", + "room_id": "!ycnlQsqkSRyIlCeddx:localhost", + "sender": "@user:localhost", + "content": { + "model": "google/gemini-pro-1.5" + }, + "state_key": "", + "origin_server_ts": 1733266540113, + "unsigned": { "replaces_state": "$1pZDTUqrUOHjIxwYuywpDs-5jiY-kyu0d2LshvMIrqU", "prev_content": { "enabledEventIds": ["$McWbvIHD4AA5QeaBJthLoINc1XqE-5a5XpthRFvP0eE"], "disabledEventIds": [] - } - }, - { - "type": "m.room.message", - "room_id": "!ycnlQsqkSRyIlCeddx:localhost", - "sender": "@user:localhost", - "content": { - "msgtype": "app.boxel.cardFragment", - "format": "app.boxel.card", - "body": "card fragment 1 of 1", - "formatted_body": "card fragment 1 of 1", - "data": "{\"cardFragment\":\"{\\\"data\\\":{\\\"type\\\":\\\"card\\\",\\\"id\\\":\\\"http://localhost:4201/user/lukes-workspace/ProductRequirementDocument/9f816882-17e0-473f-81f2-a37381874322\\\",\\\"attributes\\\":{\\\"appTitle\\\":\\\"Radio Episode Tracker for Nerds\\\",\\\"shortDescription\\\":\\\"An app to track and manage listened and unlistened radio episodes.\\\",\\\"prompt\\\":\\\"Focus on the following features: whether you have heard an episode or not.\\\",\\\"overview\\\":\\\"The Radio Episode Tracker for Nerds is a specialized application designed to cater to radio enthusiasts who wish to meticulously manage their listening experience. This app enables users to keep track of radio episodes they have listened to and identify those they haven't. It also offers features that allow users to organize episodes based on various criteria like genre, podcast series, and personal ratings, ensuring a streamlined and personalized listening journey.\\\",\\\"schema\\\":\\\"1. User Profile: Stores user information, preferences, and listening history.\\\\n2. Episode Database: Maintains records of all available radio episodes.\\\\n3. Listening Status Tracker: Keeps track of episodes as 'heard' or 'unheard'.\\\\n4. Episode Organizer: Allows categorization and prioritization of episodes based on user-defined criteria.\\\",\\\"layoutAndNavigation\\\":\\\"The app features a user-friendly dashboard that displays all the episodes categorized by their status (heard/unheard). Navigation is intuitive with tabs for different functionalities such as search, organize, and history. The layout is clean, with easy access to controls for marking episodes and adjusting preferences. \\\",\\\"moduleURL\\\":null,\\\"thumbnailURL\\\":null},\\\"relationships\\\":{\\\"appInstances\\\":{\\\"links\\\":{\\\"self\\\":null}}},\\\"meta\\\":{\\\"adoptsFrom\\\":{\\\"module\\\":\\\"http://localhost:4201/catalog/product-requirement-document\\\",\\\"name\\\":\\\"ProductRequirementDocument\\\"}}}}\",\"index\":0,\"totalParts\":1}" }, - "origin_server_ts": 1733266550044, - "unsigned": { - "age": 84005 - }, - "event_id": "$VpJ0-QkjZZo5C2yVrgY2m9BtMSXyMJaRrfeSftTX5vU", - "user_id": "@user:localhost", + "prev_sender": "@user:localhost", + "age": 93936 + }, + "event_id": "$pcL3-132rbsFZHHFDfhkSw2S4lmPbEMOIt3SuEM5YQg", + "user_id": "@user:localhost", + "age": 93936, + "replaces_state": "$1pZDTUqrUOHjIxwYuywpDs-5jiY-kyu0d2LshvMIrqU", + "prev_content": { + "enabledEventIds": ["$McWbvIHD4AA5QeaBJthLoINc1XqE-5a5XpthRFvP0eE"], + "disabledEventIds": [] + } + }, + { + "type": "m.room.message", + "room_id": "!ycnlQsqkSRyIlCeddx:localhost", + "sender": "@user:localhost", + "content": { + "msgtype": "app.boxel.cardFragment", + "format": "app.boxel.card", + "body": "card fragment 1 of 1", + "formatted_body": "card fragment 1 of 1", + "data": "{\"cardFragment\":\"{\\\"data\\\":{\\\"type\\\":\\\"card\\\",\\\"id\\\":\\\"http://localhost:4201/user/lukes-workspace/ProductRequirementDocument/9f816882-17e0-473f-81f2-a37381874322\\\",\\\"attributes\\\":{\\\"appTitle\\\":\\\"Radio Episode Tracker for Nerds\\\",\\\"shortDescription\\\":\\\"An app to track and manage listened and unlistened radio episodes.\\\",\\\"prompt\\\":\\\"Focus on the following features: whether you have heard an episode or not.\\\",\\\"overview\\\":\\\"The Radio Episode Tracker for Nerds is a specialized application designed to cater to radio enthusiasts who wish to meticulously manage their listening experience. This app enables users to keep track of radio episodes they have listened to and identify those they haven't. It also offers features that allow users to organize episodes based on various criteria like genre, podcast series, and personal ratings, ensuring a streamlined and personalized listening journey.\\\",\\\"schema\\\":\\\"1. User Profile: Stores user information, preferences, and listening history.\\\\n2. Episode Database: Maintains records of all available radio episodes.\\\\n3. Listening Status Tracker: Keeps track of episodes as 'heard' or 'unheard'.\\\\n4. Episode Organizer: Allows categorization and prioritization of episodes based on user-defined criteria.\\\",\\\"layoutAndNavigation\\\":\\\"The app features a user-friendly dashboard that displays all the episodes categorized by their status (heard/unheard). Navigation is intuitive with tabs for different functionalities such as search, organize, and history. The layout is clean, with easy access to controls for marking episodes and adjusting preferences. \\\",\\\"moduleURL\\\":null,\\\"thumbnailURL\\\":null},\\\"relationships\\\":{\\\"appInstances\\\":{\\\"links\\\":{\\\"self\\\":null}}},\\\"meta\\\":{\\\"adoptsFrom\\\":{\\\"module\\\":\\\"http://localhost:4201/catalog/product-requirement-document\\\",\\\"name\\\":\\\"ProductRequirementDocument\\\"}}}}\",\"index\":0,\"totalParts\":1}" + }, + "origin_server_ts": 1733266550044, + "unsigned": { "age": 84005 }, - { - "type": "m.room.message", - "room_id": "!ycnlQsqkSRyIlCeddx:localhost", - "sender": "@user:localhost", - "content": { - "msgtype": "app.boxel.message", - "body": "Summarize this card", - "format": "org.matrix.custom.html", - "formatted_body": "

Summarize this card

\n", - "clientGeneratedId": "b329fa44-e944-46c2-9e65-34d157509326", - "data": "{\"attachedCardsEventIds\":[\"$VpJ0-QkjZZo5C2yVrgY2m9BtMSXyMJaRrfeSftTX5vU\"],\"context\":{\"openCardIds\":[\"http://localhost:4201/user/lukes-workspace/ProductRequirementDocument/9f816882-17e0-473f-81f2-a37381874322\"],\"tools\":[{\"type\":\"function\",\"function\":{\"name\":\"patchCard\",\"description\":\"Propose a patch to an existing card to change its contents. Any attributes specified will be fully replaced, return the minimum required to make the change. If a relationship field value is removed, set the self property of the specific item to null. When editing a relationship array, display the full array in the patch code. Ensure the description explains what change you are making.\",\"parameters\":{\"type\":\"object\",\"properties\":{\"description\":{\"type\":\"string\"},\"attributes\":{\"type\":\"object\",\"properties\":{\"cardId\":{\"type\":\"string\",\"const\":\"http://localhost:4201/user/lukes-workspace/ProductRequirementDocument/9f816882-17e0-473f-81f2-a37381874322\"},\"patch\":{\"type\":\"object\",\"properties\":{\"attributes\":{\"type\":\"object\",\"properties\":{\"appTitle\":{\"type\":\"string\"},\"shortDescription\":{\"type\":\"string\"},\"thumbnail\":{\"type\":\"object\",\"properties\":{\"altText\":{\"type\":\"string\"},\"height\":{\"type\":\"number\"},\"width\":{\"type\":\"number\"},\"base64\":{\"type\":\"string\"}}},\"prompt\":{\"type\":\"string\"},\"overview\":{\"type\":\"string\"},\"schema\":{\"type\":\"string\"},\"layoutAndNavigation\":{\"type\":\"string\"},\"moduleURL\":{\"type\":\"string\"},\"thumbnailURL\":{\"type\":\"string\"}}},\"relationships\":{\"type\":\"object\",\"properties\":{\"appInstances\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"properties\":{\"links\":{\"type\":\"object\",\"properties\":{\"self\":{\"type\":\"string\"}},\"required\":[\"self\"]}},\"required\":[\"links\"]}}},\"required\":[\"appInstances\"]}}}}}},\"required\":[\"attributes\",\"description\"]}}},{\"type\":\"function\",\"function\":{\"name\":\"searchCard\",\"description\":\"Propose a query to search for a card instance filtered by type. If a card was shared with you, always prioritise search based upon the card that was last shared. If you do not have information on card module and name, do the search using the `_cardType` attribute.\",\"parameters\":{\"type\":\"object\",\"properties\":{\"description\":{\"type\":\"string\"},\"attributes\":{\"type\":\"object\",\"properties\":{\"filter\":{\"type\":\"object\",\"properties\":{\"contains\":{\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"description\":\"title of the card\"}},\"required\":[\"title\"]},\"eq\":{\"type\":\"object\",\"properties\":{\"_cardType\":{\"type\":\"string\",\"description\":\"name of the card type\"}},\"required\":[\"_cardType\"]}}}}}},\"required\":[\"attributes\",\"description\"]}}},{\"type\":\"function\",\"function\":{\"name\":\"generateAppModule\",\"description\":\"Propose a post request to generate a new app module. Insert the module code in the 'moduleCode' property of the payload and the title for the module in the 'appTitle' property. Ensure the description explains what change you are making.\",\"parameters\":{\"type\":\"object\",\"properties\":{\"attached_card_id\":{\"type\":\"string\",\"const\":\"http://localhost:4201/user/lukes-workspace/ProductRequirementDocument/9f816882-17e0-473f-81f2-a37381874322\"},\"description\":{\"type\":\"string\"},\"appTitle\":{\"type\":\"string\"},\"moduleCode\":{\"type\":\"string\"}},\"required\":[\"attached_card_id\",\"description\",\"appTitle\",\"moduleCode\"]}}}],\"submode\":\"interact\"}}" - }, - "origin_server_ts": 1733266550275, - "unsigned": { - "age": 83774 - }, - "event_id": "$4dcowWPnX_0flglzfIXKU8uFwIm_fgLVglZf_X_nLyY", - "user_id": "@user:localhost", + "event_id": "$VpJ0-QkjZZo5C2yVrgY2m9BtMSXyMJaRrfeSftTX5vU", + "user_id": "@user:localhost", + "age": 84005 + }, + { + "type": "m.room.message", + "room_id": "!ycnlQsqkSRyIlCeddx:localhost", + "sender": "@user:localhost", + "content": { + "msgtype": "app.boxel.message", + "body": "Summarize this card", + "format": "org.matrix.custom.html", + "formatted_body": "

Summarize this card

\n", + "clientGeneratedId": "b329fa44-e944-46c2-9e65-34d157509326", + "data": "{\"attachedCardsEventIds\":[\"$VpJ0-QkjZZo5C2yVrgY2m9BtMSXyMJaRrfeSftTX5vU\"],\"context\":{\"openCardIds\":[\"http://localhost:4201/user/lukes-workspace/ProductRequirementDocument/9f816882-17e0-473f-81f2-a37381874322\"],\"tools\":[{\"type\":\"function\",\"function\":{\"name\":\"patchCard\",\"description\":\"Propose a patch to an existing card to change its contents. Any attributes specified will be fully replaced, return the minimum required to make the change. If a relationship field value is removed, set the self property of the specific item to null. When editing a relationship array, display the full array in the patch code. Ensure the description explains what change you are making.\",\"parameters\":{\"type\":\"object\",\"properties\":{\"description\":{\"type\":\"string\"},\"attributes\":{\"type\":\"object\",\"properties\":{\"cardId\":{\"type\":\"string\",\"const\":\"http://localhost:4201/user/lukes-workspace/ProductRequirementDocument/9f816882-17e0-473f-81f2-a37381874322\"},\"patch\":{\"type\":\"object\",\"properties\":{\"attributes\":{\"type\":\"object\",\"properties\":{\"appTitle\":{\"type\":\"string\"},\"shortDescription\":{\"type\":\"string\"},\"thumbnail\":{\"type\":\"object\",\"properties\":{\"altText\":{\"type\":\"string\"},\"height\":{\"type\":\"number\"},\"width\":{\"type\":\"number\"},\"base64\":{\"type\":\"string\"}}},\"prompt\":{\"type\":\"string\"},\"overview\":{\"type\":\"string\"},\"schema\":{\"type\":\"string\"},\"layoutAndNavigation\":{\"type\":\"string\"},\"moduleURL\":{\"type\":\"string\"},\"thumbnailURL\":{\"type\":\"string\"}}},\"relationships\":{\"type\":\"object\",\"properties\":{\"appInstances\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"properties\":{\"links\":{\"type\":\"object\",\"properties\":{\"self\":{\"type\":\"string\"}},\"required\":[\"self\"]}},\"required\":[\"links\"]}}},\"required\":[\"appInstances\"]}}}}}},\"required\":[\"attributes\",\"description\"]}}},{\"type\":\"function\",\"function\":{\"name\":\"searchCard\",\"description\":\"Propose a query to search for a card instance filtered by type. If a card was shared with you, always prioritise search based upon the card that was last shared. If you do not have information on card module and name, do the search using the `_cardType` attribute.\",\"parameters\":{\"type\":\"object\",\"properties\":{\"description\":{\"type\":\"string\"},\"attributes\":{\"type\":\"object\",\"properties\":{\"filter\":{\"type\":\"object\",\"properties\":{\"contains\":{\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"description\":\"title of the card\"}},\"required\":[\"title\"]},\"eq\":{\"type\":\"object\",\"properties\":{\"_cardType\":{\"type\":\"string\",\"description\":\"name of the card type\"}},\"required\":[\"_cardType\"]}}}}}},\"required\":[\"attributes\",\"description\"]}}},{\"type\":\"function\",\"function\":{\"name\":\"generateAppModule\",\"description\":\"Propose a post request to generate a new app module. Insert the module code in the 'moduleCode' property of the payload and the title for the module in the 'appTitle' property. Ensure the description explains what change you are making.\",\"parameters\":{\"type\":\"object\",\"properties\":{\"attached_card_id\":{\"type\":\"string\",\"const\":\"http://localhost:4201/user/lukes-workspace/ProductRequirementDocument/9f816882-17e0-473f-81f2-a37381874322\"},\"description\":{\"type\":\"string\"},\"appTitle\":{\"type\":\"string\"},\"moduleCode\":{\"type\":\"string\"}},\"required\":[\"attached_card_id\",\"description\",\"appTitle\",\"moduleCode\"]}}}],\"submode\":\"interact\"}}" + }, + "origin_server_ts": 1733266550275, + "unsigned": { "age": 83774 }, - { - "type": "m.room.message", - "room_id": "!ycnlQsqkSRyIlCeddx:localhost", - "sender": "@aibot:localhost", - "content": { + "event_id": "$4dcowWPnX_0flglzfIXKU8uFwIm_fgLVglZf_X_nLyY", + "user_id": "@user:localhost", + "age": 83774 + }, + { + "type": "m.room.message", + "room_id": "!ycnlQsqkSRyIlCeddx:localhost", + "sender": "@aibot:localhost", + "content": { + "body": "Thinking...", + "msgtype": "m.text", + "formatted_body": "Thinking...", + "format": "org.matrix.custom.html", + "m.new_content": { "body": "Thinking...", "msgtype": "m.text", "formatted_body": "Thinking...", - "format": "org.matrix.custom.html", - "m.new_content": { - "body": "Thinking...", - "msgtype": "m.text", - "formatted_body": "Thinking...", - "format": "org.matrix.custom.html" - } - }, - "origin_server_ts": 1733266551309, - "unsigned": { - "age": 82740 - }, - "event_id": "$EJV9fqpgRZ1hWnWLLpOtmaRiyC8Yume66qf-19lJ2A0", - "user_id": "@aibot:localhost", + "format": "org.matrix.custom.html" + } + }, + "origin_server_ts": 1733266551309, + "unsigned": { "age": 82740 - } - ] - \ No newline at end of file + }, + "event_id": "$EJV9fqpgRZ1hWnWLLpOtmaRiyC8Yume66qf-19lJ2A0", + "user_id": "@aibot:localhost", + "age": 82740 + } +] diff --git a/packages/base/base64-image.gts b/packages/base/base64-image.gts index 8f9df3dff7..78d83c1ea3 100644 --- a/packages/base/base64-image.gts +++ b/packages/base/base64-image.gts @@ -168,11 +168,8 @@ class Edit extends Component { -12px 0, 0 0, 0 12px; - background-image: linear-gradient( - 45deg, - var(--boxel-300) 25%, - transparent 25% - ), + background-image: + linear-gradient(45deg, var(--boxel-300) 25%, transparent 25%), linear-gradient(-45deg, var(--boxel-300) 25%, transparent 25%), linear-gradient(45deg, transparent 75%, var(--boxel-300) 75%), linear-gradient(-45deg, transparent 75%, var(--boxel-300) 75%); diff --git a/packages/base/watched-array.ts b/packages/base/watched-array.ts index 13a5a9e47c..25268bc7f0 100644 --- a/packages/base/watched-array.ts +++ b/packages/base/watched-array.ts @@ -1,5 +1,8 @@ class WatchedArray { - constructor(subscriber: (oldArr: Array, arr: Array) => void, arr: T[] = []) { + constructor( + subscriber: (oldArr: Array, arr: Array) => void, + arr: T[] = [], + ) { this.#subscriber = subscriber; let clone = arr.slice(); let self = this; @@ -12,7 +15,10 @@ class WatchedArray { // The first call is to add the item, and the second call is to update the length value. // When adding items, we need to notify the subscriber with the first call. // When removing items, we need the second call. - if (prop !== 'length' || (prop === 'length' && value !== prevValues.length)) { + if ( + prop !== 'length' || + (prop === 'length' && value !== prevValues.length) + ) { let done: () => void; let notifyPromise = (self.#notifyPromise = new Promise( (res) => (done = res), @@ -24,7 +30,7 @@ class WatchedArray { } })().then(done!); } - + return true; }, getPrototypeOf() { diff --git a/packages/boxel-icons/package.json b/packages/boxel-icons/package.json index fb07dc6a36..da616d196c 100644 --- a/packages/boxel-icons/package.json +++ b/packages/boxel-icons/package.json @@ -66,7 +66,7 @@ "eslint-plugin-prettier": "^5.0.0", "http-server": "^14.1.1", "lucide-static": "^0.447.0", - "prettier": "^2.8.7", + "prettier": "^3.5.1", "prettier-plugin-ember-template-tag": "^1.1.0", "rollup": "^4.18.1", "rollup-plugin-copy": "^3.5.0", diff --git a/packages/boxel-motion/addon/package.json b/packages/boxel-motion/addon/package.json index 45aeefb68e..c1ad5df21f 100644 --- a/packages/boxel-motion/addon/package.json +++ b/packages/boxel-motion/addon/package.json @@ -82,7 +82,7 @@ "eslint-plugin-simple-import-sort": "^8.0.0", "eslint-plugin-typescript-sort-keys": "^3.2.0", "npm-run-all": "^4.1.5", - "prettier": "^2.8.7", + "prettier": "^3.5.1", "prettier-plugin-ember-template-tag": "^1.1.0", "rollup": "^4.18.1", "rollup-plugin-copy": "^3.5.0" diff --git a/packages/boxel-motion/test-app/app/components/accordion/panel/index.hbs b/packages/boxel-motion/test-app/app/components/accordion/panel/index.hbs index 69dc8f6c50..c9ba4a7e2b 100644 --- a/packages/boxel-motion/test-app/app/components/accordion/panel/index.hbs +++ b/packages/boxel-motion/test-app/app/components/accordion/panel/index.hbs @@ -72,14 +72,25 @@ .accordion-panel-animation-context:nth-of-type(1), .accordion-panel-animation-context:nth-of-type(1) .accordion-panel-container, - .accordion-panel-animation-context:nth-of-type(1) .accordion-panel-container .accordion-panel-header, - .accordion-panel-animation-context:nth-of-type(1) .accordion-panel-container .accordion-panel-header .Accordion-trigger { + .accordion-panel-animation-context:nth-of-type(1) + .accordion-panel-container + .accordion-panel-header, + .accordion-panel-animation-context:nth-of-type(1) + .accordion-panel-container + .accordion-panel-header + .Accordion-trigger { border-radius: 7px 7px 0 0; } .accordion-panel-animation-context:nth-last-of-type(1), - .accordion-panel-animation-context:nth-last-of-type(1) .accordion-panel-container, - .accordion-panel-animation-context:nth-last-of-type(1) .accordion-panel-container .accordion-panel-header, - .accordion-panel-animation-context:nth-last-of-type(1) .accordion-panel-container .accordion-panel-header .Accordion-trigger { + .accordion-panel-animation-context:nth-last-of-type(1) + .accordion-panel-container, + .accordion-panel-animation-context:nth-last-of-type(1) + .accordion-panel-container + .accordion-panel-header, + .accordion-panel-animation-context:nth-last-of-type(1) + .accordion-panel-container + .accordion-panel-header + .Accordion-trigger { border-radius: 0 0 7px 7px; } @@ -90,7 +101,9 @@ padding: 0; } - .accordion-panel-animation-context:nth-of-type(1) .accordion-panel-container .accordion-panel-header { + .accordion-panel-animation-context:nth-of-type(1) + .accordion-panel-container + .accordion-panel-header { border-top: 0; } diff --git a/packages/boxel-motion/test-app/app/styles/app.css b/packages/boxel-motion/test-app/app/styles/app.css index 1a2d7e92f3..9f11e83042 100644 --- a/packages/boxel-motion/test-app/app/styles/app.css +++ b/packages/boxel-motion/test-app/app/styles/app.css @@ -1,9 +1,9 @@ /* Ember supports plain CSS out of the box. More info: https://cli.emberjs.com/release/advanced-use/stylesheets/ */ -@import 'application.css'; -@import 'interruption.css'; -@import 'list.css'; -@import 'nested-contexts.css'; -@import 'nested-sprites.css'; -@import 'prune-and-graft.css'; -@import 'motion-study/details.css'; -@import 'motion-study/index.css'; +@import "application.css"; +@import "interruption.css"; +@import "list.css"; +@import "nested-contexts.css"; +@import "nested-sprites.css"; +@import "prune-and-graft.css"; +@import "motion-study/details.css"; +@import "motion-study/index.css"; diff --git a/packages/boxel-motion/test-app/app/templates/application.hbs b/packages/boxel-motion/test-app/app/templates/application.hbs index 16038b43d8..47950c232d 100644 --- a/packages/boxel-motion/test-app/app/templates/application.hbs +++ b/packages/boxel-motion/test-app/app/templates/application.hbs @@ -39,7 +39,7 @@
  • Removed Sprite Interruption - +
  • diff --git a/packages/boxel-motion/test-app/app/templates/nested-contexts.hbs b/packages/boxel-motion/test-app/app/templates/nested-contexts.hbs index 6c34cde87c..fa65d0c75f 100644 --- a/packages/boxel-motion/test-app/app/templates/nested-contexts.hbs +++ b/packages/boxel-motion/test-app/app/templates/nested-contexts.hbs @@ -28,10 +28,8 @@ @use={{this.level3Transition}} class="level-3-context" > -
    Level 3 Sprite
    +
    Level 3 + Sprite
    {{/if}} diff --git a/packages/boxel-motion/test-app/app/templates/nested-sprites.hbs b/packages/boxel-motion/test-app/app/templates/nested-sprites.hbs index fdee349fe4..08e303594d 100644 --- a/packages/boxel-motion/test-app/app/templates/nested-sprites.hbs +++ b/packages/boxel-motion/test-app/app/templates/nested-sprites.hbs @@ -9,10 +9,7 @@ >Move Inner -
    +
    Outer Sprite
    .split-view-toggle-button { - position: absolute; - bottom: 1.25rem; - right: 1.25rem; - margin-right: 0; - } + position: absolute; + bottom: 1.25rem; + right: 1.25rem; + margin-right: 0; + }

    Hello

    -