Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement pieces of planned Commands API in support of AI App Generator card #1746

Merged
merged 48 commits into from
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
610e3af
Implement pieces of planned Commands API in support of AI App Generat…
lukemelia Oct 31, 2024
8733ab4
Merge branch 'main' into cs-7389-introduce-command-types
lukemelia Nov 4, 2024
04ced18
WIP commands implementation
lukemelia Nov 4, 2024
1703c75
Getting up to returning a patchcardcommand function call
IanCal Nov 5, 2024
f8e5e71
Track registered commands
IanCal Nov 5, 2024
e728066
WIP Add tests for sending commands to AI Assistant and having them be…
lukemelia Nov 5, 2024
c8e6064
Added notes from convo with Ed
lukemelia Nov 6, 2024
bf5f1d4
Merge branch 'main' into cs-7389-introduce-command-types
lukemelia Nov 6, 2024
558980d
Add basic auto-execution of commands
lukemelia Nov 7, 2024
71009f8
Add test coverage for command with autoexecute false
lukemelia Nov 7, 2024
ffcf86e
WIP trying to get PatchCard command working
lukemelia Nov 7, 2024
c345165
Get auto patching working with a json field type & patch working outs…
IanCal Nov 9, 2024
cbbd9df
Add show card
IanCal Nov 11, 2024
3717887
Testing around showing updates in a new stack
IanCal Nov 11, 2024
405e873
Add ReloadCard command, and reload after patch completes
lukemelia Nov 11, 2024
4a91807
Clean up lint errors and AttributesSchema/RelationshipsSchema
lukemelia Nov 11, 2024
3661971
More lint fixes
lukemelia Nov 11, 2024
7d98d27
Merge branch 'cs-7389-introduce-command-types' of github.com:cardstac…
IanCal Nov 12, 2024
f961bed
Smaller test setup for commands, add basic create module command
IanCal Nov 12, 2024
9006a8f
Lint fixes
lukemelia Nov 12, 2024
f0d59cb
Merge branch 'main' into cs-7389-introduce-command-types
lukemelia Nov 12, 2024
d7b69f9
Test fixes and improve command payload consistency
lukemelia Nov 12, 2024
fe8a51f
Minor fixes
lukemelia Nov 13, 2024
fe5c2b4
Update tests for newer command/tool schema
lukemelia Nov 13, 2024
00cb956
Fix two host tests
lukemelia Nov 13, 2024
6ca260e
Defer attempt to access defaultWritableRealm until needed
lukemelia Nov 14, 2024
fad7859
Avoid duplicated events in room.events and RoomResource#_messageCache
lukemelia Nov 14, 2024
aea6434
Extra fallback option for body description supporting old and new for…
IanCal Nov 14, 2024
6c9dec8
Test fixes, check test for old & newer formats
IanCal Nov 14, 2024
7fe1a5e
add type layer in properties
IanCal Nov 14, 2024
d8ba247
Update to patch structure
IanCal Nov 14, 2024
9f0e8f0
Fix lint and patchCard issues
lukemelia Nov 14, 2024
6bfefb8
Lint fix
lukemelia Nov 14, 2024
cf5dff0
Test fixes
lukemelia Nov 14, 2024
0f308db
Remove extraneous logging
lukemelia Nov 14, 2024
af94bc0
Merge branch 'main' into cs-7389-introduce-command-types
lukemelia Nov 14, 2024
6c55d98
Use short UUID instead of incrementing integer for unique command too…
lukemelia Nov 14, 2024
2aaed2c
Rollback changes to how events are updated
lukemelia Nov 14, 2024
fe70d4e
Merge branch 'cs-7389-introduce-command-types' of github.com:cardstac…
IanCal Nov 15, 2024
16f81a0
Restore path in the code that skips incorrectly serialised events
IanCal Nov 18, 2024
d4bcc15
Wip commands error duplicate event data (#1810)
IanCal Nov 18, 2024
3e2b639
Remove unneeded code
lukemelia Nov 18, 2024
37ccc7b
Merge branch 'main' into cs-7389-introduce-command-types
lukemelia Nov 18, 2024
0f78aa8
command payload fix
lukemelia Nov 18, 2024
7c7ce8c
Fix aibot tests
lukemelia Nov 18, 2024
5e7d654
Address code review feedback
lukemelia Nov 19, 2024
22efc8c
Merge branch 'main' into cs-7389-introduce-command-types
lukemelia Nov 19, 2024
5cf45e7
Fix test to work with page title change
lukemelia Nov 19, 2024
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
2 changes: 1 addition & 1 deletion packages/ai-bot/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ It will be able to see any cards shared in the chat and can respond using GPT4 i
You can deliberately trigger a specific patch by sending a message that starts `debug:patch:` and has the JSON patch you want returned. For example:

```
debug:patch:{"card_id":"http://localhost:4200/experiments/Author/1", "description": "message", "attributes": {"firstName": "David"}}
debug:patch:{"attributes": {"cardId":"http://localhost:4200/experiments/Author/1", "patch": { "attributes": {"firstName": "David"}}}}
```

This will return a patch with the ID of the last card you uploaded. This does not hit GPT4 and is useful for testing the integration of the two components without waiting for streaming responses.
Expand Down
2 changes: 1 addition & 1 deletion packages/ai-bot/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ export function getTools(
history: DiscreteMatrixEvent[],
aiBotUserId: string,
): Tool[] {
// TODO: there should be no default tools defined in the ai-bot, tools must be determined by the host
let searchTool = getSearchTool();
let tools = [searchTool];
// Just get the users messages
Expand Down Expand Up @@ -426,7 +427,6 @@ export function getModifyPrompt(
mostRecentlyAttachedCard,
attachedCards,
);

if (skillCards.length) {
systemMessage += SKILL_INSTRUCTIONS_MESSAGE;
systemMessage += skillCardsToMessage(skillCards);
Expand Down
29 changes: 22 additions & 7 deletions packages/ai-bot/lib/debug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,21 @@ export async function handleDebugCommands(
let patchMessage = eventBody.split('debug:patch:')[1];
// If there's a card attached, we need to split it off to parse the json
patchMessage = patchMessage.split('(Card')[0];
let command: {
card_id?: string;
let toolArguments: {
attributes?: {
cardId?: string;
patch?: any;
};
description?: string;
attributes?: any;
} = {};
try {
command = JSON.parse(patchMessage);
if (!command.card_id || !command.description || !command.attributes) {
toolArguments = JSON.parse(patchMessage);
if (
!toolArguments.attributes?.cardId ||
!toolArguments.attributes?.patch
) {
throw new Error(
'Invalid debug patch: card_id, description, or attributes is missing.',
'Invalid debug patch: attributes.cardId, or attributes.patch is missing.',
);
}
} catch (error) {
Expand All @@ -54,7 +59,17 @@ export async function handleDebugCommands(
undefined,
);
}
return await sendOption(client, roomId, command, undefined);
return await sendOption(
client,
roomId,
{
id: 'patchCard-debug',
name: 'patchCard',
type: 'function',
arguments: toolArguments,
},
undefined,
);
}
return;
}
7 changes: 4 additions & 3 deletions packages/ai-bot/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,17 @@ class Assistant {
getResponse(history: DiscreteMatrixEvent[]) {
let tools = getTools(history, this.id);
let messages = getModifyPrompt(history, this.id, tools);

if (tools.length === 0) {
return this.openai.beta.chat.completions.stream({
model: 'openai/gpt-4o',
messages: messages,
messages,
});
} else {
return this.openai.beta.chat.completions.stream({
model: 'openai/gpt-4o',
messages: messages,
tools: tools,
messages,
tools,
tool_choice: 'auto',
});
}
Expand Down
16 changes: 12 additions & 4 deletions packages/ai-bot/tests/chat-titling-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -378,9 +378,13 @@ module('shouldSetRoomTitle', () => {
toolCall: {
name: 'patchCard',
arguments: {
card_id: 'http://localhost:4201/experiments/Friend/1',
attributes: {
firstName: 'Dave',
cardId: 'http://localhost:4201/experiments/Friend/1',
patch: {
attributes: {
firstName: 'Dave',
},
},
},
},
},
Expand Down Expand Up @@ -443,9 +447,13 @@ module('shouldSetRoomTitle', () => {
toolCall: {
name: 'patchCard',
arguments: {
card_id: 'http://localhost:4201/drafts/Friend/1',
attributes: {
firstName: 'Dave',
cardId: 'http://localhost:4201/drafts/Friend/1',
patch: {
attributes: {
firstName: 'Dave',
},
},
},
},
},
Expand Down
100 changes: 73 additions & 27 deletions packages/ai-bot/tests/prompt-construction-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import type {
Tool,
CardMessageContent,
} from 'https://cardstack.com/base/matrix-event';
import { EventStatus } from 'matrix-js-sdk';
import { EventStatus, IRoomEvent } from 'matrix-js-sdk';
import type { SingleCardDocument } from '@cardstack/runtime-common';
import { CardDef } from 'https://cardstack.com/base/card-api';

Expand Down Expand Up @@ -769,7 +769,9 @@ module('getModifyPrompt', () => {
openCardIds: ['http://localhost:4201/experiments/Friend/1'],
tools: [
getPatchTool('http://localhost:4201/experiments/Friend/1', {
firstName: { type: 'string' },
attributes: {
firstName: { type: 'string' },
},
}),
],
submode: 'interact',
Expand Down Expand Up @@ -891,13 +893,13 @@ module('getModifyPrompt', () => {
parameters: {
type: 'object',
properties: {
description: {
type: 'string',
},
card_id: {
type: 'string',
const: 'http://localhost:4201/experiments/Friend/1',
},
description: {
type: 'string',
},
attributes: {
type: 'object',
properties: {
Expand Down Expand Up @@ -928,7 +930,12 @@ module('getModifyPrompt', () => {
openCardIds: ['http://localhost:4201/experiments/Friend/1'],
tools: [
getPatchTool('http://localhost:4201/experiments/Friend/1', {
firstName: { type: 'string' },
attributes: {
type: 'object',
properties: {
firstName: { type: 'string' },
},
},
}),
],
submode: 'interact',
Expand Down Expand Up @@ -960,15 +967,30 @@ module('getModifyPrompt', () => {
description: {
type: 'string',
},
card_id: {
type: 'string',
const: 'http://localhost:4201/experiments/Friend/1',
},
firstName: {
type: 'string',
attributes: {
type: 'object',
properties: {
cardId: {
type: 'string',
const: 'http://localhost:4201/experiments/Friend/1',
},
patch: {
type: 'object',
properties: {
attributes: {
type: 'object',
properties: {
firstName: {
type: 'string',
},
},
},
},
},
},
},
},
required: ['card_id', 'attributes', 'description'],
required: ['attributes', 'description'],
},
},
});
Expand All @@ -989,7 +1011,9 @@ module('getModifyPrompt', () => {
openCardIds: ['http://localhost:4201/experiments/Friend/1'],
tools: [
getPatchTool('http://localhost:4201/experiments/Friend/1', {
firstName: { type: 'string' },
attributes: {
firstName: { type: 'string' },
},
}),
],
submode: 'interact',
Expand Down Expand Up @@ -1018,7 +1042,12 @@ module('getModifyPrompt', () => {
openCardIds: ['http://localhost:4201/experiments/Meeting/2'],
tools: [
getPatchTool('http://localhost:4201/experiments/Meeting/2', {
location: { type: 'string' },
attributes: {
type: 'object',
properties: {
location: { type: 'string' },
},
},
}),
],
submode: 'interact',
Expand Down Expand Up @@ -1048,18 +1077,33 @@ module('getModifyPrompt', () => {
parameters: {
type: 'object',
properties: {
card_id: {
type: 'string',
const: 'http://localhost:4201/experiments/Meeting/2',
},
description: {
type: 'string',
},
location: {
type: 'string',
attributes: {
type: 'object',
properties: {
cardId: {
type: 'string',
const: 'http://localhost:4201/experiments/Meeting/2',
},
patch: {
type: 'object',
properties: {
attributes: {
type: 'object',
properties: {
location: {
type: 'string',
},
},
},
},
},
},
},
},
required: ['card_id', 'attributes', 'description'],
required: ['attributes', 'description'],
},
},
});
Expand Down Expand Up @@ -1867,11 +1911,13 @@ module('getModifyPrompt', () => {
id: 'tool-call-id-1',
name: 'searchCard',
arguments: {
description: "Search for card instances of type 'Author'",
filter: {
type: {
module: 'http://localhost:4201/drafts/author',
name: 'Author',
attributes: {
description: "Search for card instances of type 'Author'",
filter: {
type: {
module: 'http://localhost:4201/drafts/author',
name: 'Author',
},
},
},
},
Expand Down
36 changes: 28 additions & 8 deletions packages/ai-bot/tests/responding-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,9 +184,15 @@ module('Responding', (hooks) => {

test('Sends tool call event and replaces thinking message when tool call happens with no content', async () => {
const patchArgs = {
card_id: 'card/1',
description: 'A new thing',
attributes: { some: 'thing' },
attributes: {
cardId: 'card/1',
patch: {
attributes: {
some: 'thing',
},
},
},
};

await responder.initialize();
Expand Down Expand Up @@ -225,10 +231,14 @@ module('Responding', (hooks) => {
id: 'some-tool-call-id',
name: 'patchCard',
arguments: {
card_id: 'card/1',
description: 'A new thing',
attributes: {
some: 'thing',
cardId: 'card/1',
patch: {
attributes: {
some: 'thing',
},
},
},
},
},
Expand All @@ -252,9 +262,15 @@ module('Responding', (hooks) => {

test('Sends tool call event separately when content is sent before tool call', async () => {
const patchArgs = {
card_id: 'card/1',
description: 'A new thing',
attributes: { some: 'thing' },
attributes: {
cardId: 'card/1',
patch: {
attributes: {
some: 'thing',
},
},
},
};
await responder.initialize();

Expand Down Expand Up @@ -293,10 +309,14 @@ module('Responding', (hooks) => {
id: 'some-tool-call-id',
name: 'patchCard',
arguments: {
card_id: 'card/1',
description: 'A new thing',
attributes: {
some: 'thing',
cardId: 'card/1',
patch: {
attributes: {
some: 'thing',
},
},
},
},
},
Expand Down
2 changes: 2 additions & 0 deletions packages/base/card-api.gts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import {
type Actions,
type RealmInfo,
CodeRef,
CommandContext,
} from '@cardstack/runtime-common';
import type { ComponentLike } from '@glint/template';
import { initSharedState } from './shared-state';
Expand Down Expand Up @@ -130,6 +131,7 @@ interface NotLoadedValue {

export interface CardContext {
actions?: Actions;
commandContext?: CommandContext;
cardComponentModifier?: typeof Modifier<{
Args: {
Named: {
Expand Down
Loading