@aws/nx-plugin-mcp 1.0.0-rc.4 → 1.0.0-rc.41
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/bin/aws-nx-mcp.js +2240 -1030
- package/docs/get_started/building-with-ai.mdx +116 -0
- package/docs/get_started/concepts.mdx +52 -0
- package/docs/get_started/existing-project.mdx +176 -0
- package/docs/get_started/quick-start.mdx +266 -0
- package/docs/get_started/tutorials/contribute-generator.mdx +405 -0
- package/docs/get_started/tutorials/dungeon-game/1.mdx +1205 -0
- package/docs/get_started/tutorials/dungeon-game/2.mdx +237 -0
- package/docs/get_started/tutorials/dungeon-game/3.mdx +76 -0
- package/docs/get_started/tutorials/dungeon-game/4.mdx +162 -0
- package/docs/get_started/tutorials/dungeon-game/overview.mdx +144 -0
- package/docs/get_started/tutorials/dungeon-game/wrap-up.mdx +41 -0
- package/docs/get_started/tutorials/existing-project.mdx +4 -0
- package/docs/guides/agentcore-gateway.mdx +376 -0
- package/docs/guides/connection/agentcore-gateway-gateway.mdx +154 -0
- package/docs/guides/connection/agentcore-gateway-mcp.mdx +134 -0
- package/docs/guides/connection/py-agent-a2a.mdx +47 -15
- package/docs/guides/connection/py-agent-dynamodb.mdx +116 -0
- package/docs/guides/connection/py-agent-gateway.mdx +176 -0
- package/docs/guides/connection/py-agent-mcp.mdx +42 -13
- package/docs/guides/connection/py-agent-rdb.mdx +178 -0
- package/docs/guides/connection/py-fast-api-dynamodb.mdx +56 -0
- package/docs/guides/connection/py-fast-api-rdb.mdx +184 -0
- package/docs/guides/connection/py-mcp-server-dynamodb.mdx +116 -0
- package/docs/guides/connection/py-mcp-server-rdb.mdx +187 -0
- package/docs/guides/connection/react-agui.mdx +4 -4
- package/docs/guides/connection/react-fastapi.mdx +38 -2
- package/docs/guides/connection/react-py-agent.mdx +7 -13
- package/docs/guides/connection/react-smithy.mdx +3 -3
- package/docs/guides/connection/react-trpc.mdx +1 -1
- package/docs/guides/connection/react-ts-agent.mdx +8 -8
- package/docs/guides/connection/smithy-dynamodb.mdx +4 -4
- package/docs/guides/connection/smithy-rdb.mdx +5 -5
- package/docs/guides/connection/trpc-dynamodb.mdx +4 -4
- package/docs/guides/connection/trpc-rdb.mdx +5 -5
- package/docs/guides/connection/ts-agent-a2a.mdx +12 -9
- package/docs/guides/connection/ts-agent-dynamodb.mdx +3 -3
- package/docs/guides/connection/ts-agent-gateway.mdx +141 -0
- package/docs/guides/connection/ts-agent-mcp.mdx +11 -8
- package/docs/guides/connection/ts-agent-rdb.mdx +66 -21
- package/docs/guides/connection/ts-mcp-server-dynamodb.mdx +3 -3
- package/docs/guides/connection/ts-mcp-server-rdb.mdx +66 -16
- package/docs/guides/connection.mdx +104 -5
- package/docs/guides/docker-bundling.mdx +68 -8
- package/docs/guides/fastapi.mdx +244 -4
- package/docs/guides/license.mdx +264 -109
- package/docs/guides/local-development.mdx +87 -0
- package/docs/guides/nx-generator.mdx +7 -2
- package/docs/guides/py-agent.mdx +257 -49
- package/docs/guides/py-dynamodb.mdx +476 -0
- package/docs/guides/py-mcp-server.mdx +61 -2
- package/docs/guides/py-rdb.mdx +254 -0
- package/docs/guides/react-website-auth.mdx +58 -1
- package/docs/guides/react-website.mdx +130 -19
- package/docs/guides/security.mdx +75 -0
- package/docs/guides/terraform-project.mdx +1 -1
- package/docs/guides/trpc.mdx +45 -9
- package/docs/guides/ts-agent.mdx +149 -9
- package/docs/guides/ts-dynamodb.mdx +62 -239
- package/docs/guides/ts-mcp-server.mdx +66 -3
- package/docs/guides/ts-nx-plugin.mdx +1 -1
- package/docs/guides/ts-rdb.mdx +117 -470
- package/docs/guides/ts-smithy-api.mdx +183 -4
- package/docs/guides/typescript-infrastructure.mdx +9 -1
- package/docs/guides/typescript-project.mdx +5 -10
- package/docs/guides/workspace.mdx +2 -2
- package/docs/snippets/agent/architecture.mdx +1 -1
- package/docs/snippets/agent/bedrock-deployment.mdx +4 -0
- package/docs/snippets/agent/runtime-arn.mdx +21 -0
- package/docs/snippets/agent/securing-your-agent.mdx +39 -0
- package/docs/snippets/api/access-logging.mdx +33 -0
- package/docs/snippets/api/type-safe-api-integrations.mdx +31 -0
- package/docs/snippets/api/waf-configuration.mdx +1 -1
- package/docs/snippets/connection/dynamodb-local-development.mdx +2 -2
- package/docs/snippets/connection/py-dynamodb-local-development.mdx +7 -0
- package/docs/snippets/connection/py-lambda-rdb-ssl-requirements.mdx +7 -0
- package/docs/snippets/connection/rdb-api-infrastructure.mdx +50 -18
- package/docs/snippets/dynamodb/deploying-table.mdx +166 -0
- package/docs/snippets/dynamodb/gsi-config.mdx +38 -0
- package/docs/snippets/dynamodb/infrastructure.mdx +33 -0
- package/docs/snippets/dynamodb/local-dev-start.mdx +13 -0
- package/docs/snippets/dynamodb/local-dev-windows.mdx +15 -0
- package/docs/snippets/mcp/architecture.mdx +1 -1
- package/docs/snippets/mcp/bedrock-deployment.mdx +4 -0
- package/docs/snippets/mcp/config.mdx +3 -2
- package/docs/snippets/rdb/architecture.mdx +38 -0
- package/docs/snippets/rdb/cluster-instances.mdx +31 -0
- package/docs/snippets/rdb/deletion-protection.mdx +34 -0
- package/docs/snippets/rdb/deploying.mdx +187 -0
- package/docs/snippets/rdb/encryption-key-rotation.mdx +30 -0
- package/docs/snippets/rdb/engine-version.mdx +63 -0
- package/docs/snippets/rdb/infrastructure.mdx +35 -0
- package/docs/snippets/rdb/logging.mdx +32 -0
- package/docs/snippets/rdb/rds-proxy.mdx +50 -0
- package/docs/snippets/rdb/removal-policy.mdx +57 -0
- package/docs/snippets/rdb/serverless-capacity.mdx +32 -0
- package/docs/snippets/required-prerequisites.mdx +1 -1
- package/docs/snippets/trivy-image-scan.mdx +27 -0
- package/generators.json +101 -2
- package/package.json +1 -1
- package/src/agentcore-gateway/gateway-connection/schema.json +31 -0
- package/src/agentcore-gateway/mcp-connection/schema.json +31 -0
- package/src/agentcore-gateway/schema.json +70 -0
- package/src/connection/schema.json +5 -0
- package/src/infra/app/schema.json +5 -0
- package/src/init/schema.json +35 -0
- package/src/license/schema.json +11 -0
- package/src/preset/schema.json +11 -5
- package/src/py/agent/a2a-connection/schema.json +5 -0
- package/src/py/agent/gateway-connection/schema.json +31 -0
- package/src/py/agent/mcp-connection/schema.json +5 -0
- package/src/py/agent/react-connection/schema.json +5 -0
- package/src/py/agent/schema.json +6 -1
- package/src/py/api/schema.json +5 -0
- package/src/py/dynamodb/agent-connection/schema.json +27 -0
- package/src/py/dynamodb/fast-api-connection/schema.json +23 -0
- package/src/py/dynamodb/mcp-server-connection/schema.json +27 -0
- package/src/py/dynamodb/schema.json +75 -0
- package/src/py/fast-api/react/schema.json +5 -0
- package/src/py/fast-api/schema.json +5 -0
- package/src/py/lambda-function/schema.json +5 -0
- package/src/py/mcp-server/schema.json +5 -0
- package/src/py/project/schema.json +5 -0
- package/src/py/rdb/agent-connection/schema.json +27 -0
- package/src/py/rdb/fast-api-connection/schema.json +23 -0
- package/src/py/rdb/mcp-server-connection/schema.json +27 -0
- package/src/py/rdb/schema.json +77 -0
- package/src/smithy/project/schema.json +5 -0
- package/src/smithy/react-connection/schema.json +5 -0
- package/src/smithy/ts/api/schema.json +5 -0
- package/src/terraform/project/schema.json +5 -0
- package/src/trpc/backend/schema.json +5 -0
- package/src/trpc/react/schema.json +5 -0
- package/src/ts/agent/a2a-connection/schema.json +5 -0
- package/src/ts/agent/gateway-connection/schema.json +31 -0
- package/src/ts/agent/mcp-connection/schema.json +5 -0
- package/src/ts/agent/react-connection/schema.json +5 -0
- package/src/ts/agent/schema.json +5 -0
- package/src/ts/api/schema.json +5 -0
- package/src/ts/astro-docs/schema.json +3 -3
- package/src/ts/docs/schema.json +3 -3
- package/src/ts/dynamodb/agent-connection/schema.json +5 -0
- package/src/ts/dynamodb/mcp-server-connection/schema.json +5 -0
- package/src/ts/dynamodb/schema.json +25 -2
- package/src/ts/dynamodb/smithy-connection/schema.json +5 -0
- package/src/ts/dynamodb/trpc-connection/schema.json +5 -0
- package/src/ts/lambda-function/schema.json +5 -0
- package/src/ts/lib/schema.json +5 -0
- package/src/ts/mcp-server/schema.json +5 -0
- package/src/ts/nx-generator/schema.json +5 -0
- package/src/ts/nx-plugin/schema.json +5 -0
- package/src/ts/rdb/agent-connection/schema.json +5 -0
- package/src/ts/rdb/mcp-server-connection/schema.json +5 -0
- package/src/ts/rdb/schema.json +6 -1
- package/src/ts/rdb/smithy-connection/schema.json +5 -0
- package/src/ts/rdb/trpc-connection/schema.json +5 -0
- package/src/ts/react-website/app/schema.json +11 -6
- package/src/ts/react-website/cognito-auth/schema.json +5 -0
- package/src/ts/react-website/runtime-config/schema.json +5 -0
- package/src/ts/website/app/schema.json +11 -6
- package/src/ts/website/auth/schema.json +5 -0
- /package/docs/snippets/connection/{lambda-rdb-ssl-requirements.mdx → ts-lambda-rdb-ssl-requirements.mdx} +0 -0
- /package/docs/snippets/connection/{mcp-server-rdb-ssl-requirements.mdx → ts-mcp-server-rdb-ssl-requirements.mdx} +0 -0
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Implement the Game API and Inventory MCP server
|
|
3
|
+
description: A walkthrough of how to build an agentic AI-powered dungeon adventure game using the @aws/nx-plugin.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
import { Aside, Code, FileTree, Steps, Tabs, TabItem } from '@astrojs/starlight/components';
|
|
7
|
+
import { Image } from 'astro:assets';
|
|
8
|
+
import Link from '@components/link.astro';
|
|
9
|
+
import Drawer from '@components/drawer.astro';
|
|
10
|
+
import RunGenerator from '@components/run-generator.astro';
|
|
11
|
+
import NxCommands from '@components/nx-commands.astro';
|
|
12
|
+
import PackageManagerShortCommand from '@components/package-manager-short-command.astro';
|
|
13
|
+
import InstallCommand from '@components/install-command.astro';
|
|
14
|
+
import E2EDiff from '@components/e2e-diff.astro';
|
|
15
|
+
import E2ECode from '@components/e2e-code.astro';
|
|
16
|
+
import Snippet from '@components/snippet.astro';
|
|
17
|
+
|
|
18
|
+
import dungeonAdventureArchitecturePng from '@assets/dungeon-game-architecture.png'
|
|
19
|
+
import baselineWebsitePng from '@assets/baseline-website.png'
|
|
20
|
+
import baselineGamePng from '@assets/baseline-game.png'
|
|
21
|
+
import nxGraphPng from '@assets/nx-graph.png'
|
|
22
|
+
import gameSelectPng from '@assets/game-select.png'
|
|
23
|
+
import gameConversationPng from '@assets/game-conversation.png'
|
|
24
|
+
|
|
25
|
+
import { getDungeonAdventureElectroDbDependencies } from '../../../../../../../../e2e/src/utils';
|
|
26
|
+
|
|
27
|
+
## Task 1: Implement the Game API
|
|
28
|
+
|
|
29
|
+
We will implement the following APIs in this section:
|
|
30
|
+
|
|
31
|
+
1. `saveGame` - create or update a game.
|
|
32
|
+
2. `queryGames` - return a paginated list of previously saved games.
|
|
33
|
+
3. `queryInventory` - return a paginated list of items in a player's inventory.
|
|
34
|
+
4. `queryActions` - return the conversation history for a given game.
|
|
35
|
+
|
|
36
|
+
:::note[Where each piece of state lives]
|
|
37
|
+
- `games` and `inventory` are in **DynamoDB** (via ElectroDB) — the Game API lambdas and the Inventory MCP server read/write them.
|
|
38
|
+
- `actions` (chat transcript) is in **S3** — the Story Agent's `S3SessionManager` writes one JSON blob per turn, and `queryActions` in the Game API reads them back so the UI can replay history on page reload. There's no `saveAction` procedure; the agent is the only writer.
|
|
39
|
+
:::
|
|
40
|
+
|
|
41
|
+
### API schema
|
|
42
|
+
|
|
43
|
+
To define our API inputs and outputs, let's create our schema using [Zod](https://zod.dev/) within the `packages/game-api/src/schema/index.ts` file as follows:
|
|
44
|
+
|
|
45
|
+
<E2EDiff lang="typescript" before="dungeon-adventure/2/schema/index.ts.old.template" after="dungeon-adventure/2/schema/index.ts.template" />
|
|
46
|
+
|
|
47
|
+
Delete the `packages/game-api/src/schema/echo.ts` file as we will not be using it in this project.
|
|
48
|
+
|
|
49
|
+
<Aside type="tip" title="Automatic Type Inference">
|
|
50
|
+
For each of the schemas we define in Zod, we also export an interface using the `z.TypeOf` syntax. This converts our Zod definition into a Typescript interface without having to duplicate effort.
|
|
51
|
+
</Aside>
|
|
52
|
+
|
|
53
|
+
### Entity modelling
|
|
54
|
+
|
|
55
|
+
This is the ER diagram for our application.
|
|
56
|
+
|
|
57
|
+
```d2
|
|
58
|
+
direction: right
|
|
59
|
+
|
|
60
|
+
game: Game {
|
|
61
|
+
shape: sql_table
|
|
62
|
+
playerName: "string PK"
|
|
63
|
+
genre: string
|
|
64
|
+
lastUpdated: string
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
item: Item {
|
|
68
|
+
shape: sql_table
|
|
69
|
+
playerName: "string PK"
|
|
70
|
+
itemName: "string SK"
|
|
71
|
+
emoji: "string (optional)"
|
|
72
|
+
lastUpdated: string
|
|
73
|
+
quantity: number
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
game -> item: 1..*
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
The `ts#dynamodb` generator set up [ElectroDB](https://electrodb.dev/en/core-concepts/introduction/), which we will use to model our data. We will persist conversation history in S3, so we add a dependency on the S3 client:
|
|
80
|
+
|
|
81
|
+
<InstallCommand pkg={getDungeonAdventureElectroDbDependencies()} />
|
|
82
|
+
|
|
83
|
+
<Aside title="Root Dependencies">
|
|
84
|
+
All dependencies are added to the root `package.json` as the `@aws/nx-plugin` follows the [single version policy](https://nx.dev/concepts/decisions/dependency-management#single-version-policy) principle. For more information, refer to the <Link path="guides/typescript-project#dependencies">ts#project guide</Link>.
|
|
85
|
+
</Aside>
|
|
86
|
+
|
|
87
|
+
Replace the generated example entity in `packages/dungeon-db/src/entities/index.ts` with our `Game` and `Inventory` entities, and delete `packages/dungeon-db/src/entities/example.ts`:
|
|
88
|
+
|
|
89
|
+
<E2ECode lang="typescript" path="dungeon-adventure/2/dungeon-db/entities/index.ts.template" />
|
|
90
|
+
|
|
91
|
+
ElectroDB allows us to not only define our types, but can also provide defaults for certain values like timestamps. In addition, ElectroDB follows [single-table design](https://electrodb.dev/en/core-concepts/single-table-relationships/) which is the best practice when using DynamoDB.
|
|
92
|
+
|
|
93
|
+
<Aside title="ElectroDB Collections">
|
|
94
|
+
Whilst ElectroDB does support [collections](https://electrodb.dev/en/modeling/collections/), we have chosen not to use them in this tutorial for simplicity.
|
|
95
|
+
</Aside>
|
|
96
|
+
|
|
97
|
+
### Defining our procedures
|
|
98
|
+
|
|
99
|
+
To implement the API methods, make the following changes within `packages/game-api/src/procedures`:
|
|
100
|
+
|
|
101
|
+
<Tabs>
|
|
102
|
+
<TabItem label="games.ts">
|
|
103
|
+
<E2ECode lang="typescript" path="dungeon-adventure/2/procedures/games.ts.template" />
|
|
104
|
+
</TabItem>
|
|
105
|
+
<TabItem label="inventory.ts">
|
|
106
|
+
<E2ECode lang="typescript" path="dungeon-adventure/2/procedures/inventory.ts.template" />
|
|
107
|
+
</TabItem>
|
|
108
|
+
<TabItem label="actions.ts">
|
|
109
|
+
<E2ECode lang="typescript" path="dungeon-adventure/2/procedures/actions.ts.template" />
|
|
110
|
+
</TabItem>
|
|
111
|
+
</Tabs>
|
|
112
|
+
|
|
113
|
+
Delete the `echo.ts` file (from `packages/game-api/src/procedures`) as we will not be using it in this project.
|
|
114
|
+
|
|
115
|
+
### Router setup
|
|
116
|
+
|
|
117
|
+
After we define our procedures, to wire them into our API, update the following file:
|
|
118
|
+
|
|
119
|
+
<Tabs>
|
|
120
|
+
<TabItem label="packages/game-api/src/router.ts">
|
|
121
|
+
<E2EDiff lang="typescript" before="dungeon-adventure/2/router.ts.old.template" after="dungeon-adventure/2/router.ts.template" />
|
|
122
|
+
</TabItem>
|
|
123
|
+
</Tabs>
|
|
124
|
+
|
|
125
|
+
## Task 2: Create an Inventory MCP server
|
|
126
|
+
|
|
127
|
+
Let us create an MCP server which will allow our agent to manage items in a player's inventory.
|
|
128
|
+
|
|
129
|
+
We'll define the following tools for our agent:
|
|
130
|
+
|
|
131
|
+
- `list-inventory-items` for retrieving the player's current inventory items
|
|
132
|
+
- `add-to-inventory` for adding items to the player's inventory
|
|
133
|
+
- `remove-from-inventory` for removing items from the player's inventory
|
|
134
|
+
|
|
135
|
+
To save time, we will define all the tools inline:
|
|
136
|
+
|
|
137
|
+
<Tabs>
|
|
138
|
+
<TabItem label="packages/inventory/src/mcp-server/server.ts">
|
|
139
|
+
<E2EDiff lang="typescript" before="dungeon-adventure/2/mcp/server.ts.old.template" after="dungeon-adventure/2/mcp/server.ts.template" />
|
|
140
|
+
</TabItem>
|
|
141
|
+
</Tabs>
|
|
142
|
+
|
|
143
|
+
As the number of tools grow, you can refactor them out into separate files if you like.
|
|
144
|
+
|
|
145
|
+
Delete the `tools` and `resources` directories in `packages/inventory/src/mcp-server` as these will not be used.
|
|
146
|
+
|
|
147
|
+
## Task 3: Update the infrastructure
|
|
148
|
+
|
|
149
|
+
The `DungeonDb` construct generated by `ts#dynamodb` already provisions our table, so we just need to instantiate it in our stack and grant the Game API and Inventory MCP server the permissions they need. Update `packages/infra/src/stacks/application-stack.ts` as follows:
|
|
150
|
+
|
|
151
|
+
<E2EDiff lang="typescript" before="dungeon-adventure/1/application-stack.ts.template" after="dungeon-adventure/2/stacks/application-stack.ts.template" />
|
|
152
|
+
|
|
153
|
+
:::note[Isolated Procedures]
|
|
154
|
+
Notice here that since each procedure is served by an individual lambda function, we can follow the principle of least privilege and assign only the required read/write permissions based on the procedure's implementation.
|
|
155
|
+
:::
|
|
156
|
+
|
|
157
|
+
:::tip[Runtime Configuration]
|
|
158
|
+
The `DungeonDb` construct registers the deployed table name in <Link path="guides/runtime-config">Runtime Configuration</Link> under the `dynamodb` namespace, stored in AWS AppConfig. The Game API and Inventory MCP server retrieve it at runtime using Lambda Powertools, rather than needing it passed as an environment variable. A benefit of this approach is that as the number of tables or other infrastructure identifiers grows, you only need a single `RUNTIME_CONFIG_APP_ID` environment variable when running against deployed infrastructure.
|
|
159
|
+
:::
|
|
160
|
+
|
|
161
|
+
## Task 4: Test the Game API locally
|
|
162
|
+
|
|
163
|
+
There's no need to deploy to AWS to try out our API — the `dev` target runs the Game API against [DynamoDB Local](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.html). Because we connected the Game API to the `DungeonDb` project in Module 1, this target also starts DynamoDB Local automatically.
|
|
164
|
+
|
|
165
|
+
First, fix any lint issues:
|
|
166
|
+
|
|
167
|
+
<PackageManagerShortCommand commands={["lint"]} />
|
|
168
|
+
|
|
169
|
+
Then build the codebase:
|
|
170
|
+
|
|
171
|
+
<PackageManagerShortCommand commands={["build"]} />
|
|
172
|
+
|
|
173
|
+
### Start the local server
|
|
174
|
+
|
|
175
|
+
Start the Game API locally with the `dev` target, which also boots DynamoDB Local:
|
|
176
|
+
|
|
177
|
+
<NxCommands commands={["dev game-api"]} />
|
|
178
|
+
|
|
179
|
+
<Aside type="tip" title="First run">
|
|
180
|
+
The first run pulls the DynamoDB Local container image, which may take a moment. Leave the server running in this terminal and open a second terminal for the `curl` commands below.
|
|
181
|
+
</Aside>
|
|
182
|
+
|
|
183
|
+
### Test the API
|
|
184
|
+
|
|
185
|
+
Once your server is up and running, query the (empty) list of games:
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
curl -X GET 'http://localhost:2022/games.query?input=%7B%7D'
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
:::note[URL Encoding]
|
|
192
|
+
The `%7B%7D` we pass to test the API is a URI encoded empty JSON object (`{}`).
|
|
193
|
+
:::
|
|
194
|
+
|
|
195
|
+
You will see an empty list:
|
|
196
|
+
|
|
197
|
+
```json
|
|
198
|
+
{"result":{"data":{"items":[],"cursor":null}}}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Now save a game:
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
curl -X POST 'http://localhost:2022/games.save' \
|
|
205
|
+
-H 'Content-Type: application/json' \
|
|
206
|
+
-d '{"playerName":"Alice","genre":"zombie"}'
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
The save returns the persisted game (with the `lastUpdated` timestamp the entity sets for you):
|
|
210
|
+
|
|
211
|
+
```json
|
|
212
|
+
{"result":{"data":{"playerName":"Alice","genre":"zombie","lastUpdated":"..."}}}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Query again to confirm it's persisted in DynamoDB Local:
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
curl -X GET 'http://localhost:2022/games.query?input=%7B%7D'
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
This response now includes the saved game:
|
|
222
|
+
|
|
223
|
+
```json
|
|
224
|
+
{"result":{"data":{"items":[{"playerName":"Alice","genre":"zombie","lastUpdated":"..."}],"cursor":null}}}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
You can stop the local server (`Ctrl+C`) once you're done.
|
|
228
|
+
|
|
229
|
+
## Task 5: Test the Inventory MCP server locally
|
|
230
|
+
|
|
231
|
+
We can try out the MCP server's tools with the [MCP Inspector](https://github.com/modelcontextprotocol/inspector) using the generated `mcp-server-inspect` target:
|
|
232
|
+
|
|
233
|
+
<NxCommands commands={["mcp-server-inspect inventory"]} />
|
|
234
|
+
|
|
235
|
+
This serves the MCP server locally (booting DynamoDB Local too) and launches the MCP Inspector at `http://localhost:6274` pre-configured to connect to it. Click **Connect**, switch to the **Tools** tab, click **List Tools**, and try `add-to-inventory` (e.g. `playerName: Alice`, `itemName: Rusty Sword`, `emoji: ⚔️`) followed by `list-inventory-items` to see it persisted to DynamoDB Local. Stop the server (`Ctrl+C`) when you're done.
|
|
236
|
+
|
|
237
|
+
Congratulations, you have built and tested your first tRPC API and MCP server against a local DynamoDB table! 🎉🎉🎉
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Implement and configure the Story agent
|
|
3
|
+
description: A walkthrough of how to build an agentic AI-powered dungeon adventure game using the @aws/nx-plugin.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
import { Aside, Code, FileTree, Steps, Tabs, TabItem } from '@astrojs/starlight/components';
|
|
7
|
+
import { Image } from 'astro:assets';
|
|
8
|
+
import Drawer from '@components/drawer.astro';
|
|
9
|
+
import Link from '@components/link.astro';
|
|
10
|
+
import RunGenerator from '@components/run-generator.astro';
|
|
11
|
+
import NxCommands from '@components/nx-commands.astro';
|
|
12
|
+
import PackageManagerShortCommand from '@components/package-manager-short-command.astro';
|
|
13
|
+
import InstallCommand from '@components/install-command.astro';
|
|
14
|
+
import E2ECode from '@components/e2e-code.astro';
|
|
15
|
+
import E2EDiff from '@components/e2e-diff.astro';
|
|
16
|
+
|
|
17
|
+
import dungeonAdventureArchitecturePng from '@assets/dungeon-game-architecture.png'
|
|
18
|
+
import baselineWebsitePng from '@assets/baseline-website.png'
|
|
19
|
+
import baselineGamePng from '@assets/baseline-game.png'
|
|
20
|
+
import nxGraphPng from '@assets/nx-graph.png'
|
|
21
|
+
import gameSelectPng from '@assets/game-select.png'
|
|
22
|
+
import gameConversationPng from '@assets/game-conversation.png'
|
|
23
|
+
|
|
24
|
+
## Task 1: Implement the Story Agent
|
|
25
|
+
|
|
26
|
+
The Story Agent is a [Strands](https://strandsagents.com/) agent generated with `--protocol=AG-UI` in <Link path="get_started/tutorials/dungeon-game/1">Module 1</Link>, so the UI can stream from it over the [Agent-User Interaction protocol](https://docs.copilotkit.ai/aws-strands/protocol) via CopilotKit. It uses the Inventory MCP Server to manage the player's items, and Strands' built-in [`S3SessionManager`](https://strandsagents.com/latest/documentation/docs/user-guide/concepts/agents/sessions/) to persist conversation history into the sessions bucket we provisioned in Module 2.
|
|
27
|
+
|
|
28
|
+
### Agent implementation
|
|
29
|
+
|
|
30
|
+
Update the following files in `packages/story/dungeon_adventure_story/agent`:
|
|
31
|
+
|
|
32
|
+
<Tabs>
|
|
33
|
+
<TabItem label="main.py">
|
|
34
|
+
<E2EDiff lang="python" before="dungeon-adventure/3/main.py.old.template" after="dungeon-adventure/3/main.py.template" />
|
|
35
|
+
</TabItem>
|
|
36
|
+
<TabItem label="agent.py">
|
|
37
|
+
<E2EDiff lang="python" before="dungeon-adventure/3/agent.py.old.template" after="dungeon-adventure/3/agent.py.template" />
|
|
38
|
+
</TabItem>
|
|
39
|
+
</Tabs>
|
|
40
|
+
|
|
41
|
+
The changes are:
|
|
42
|
+
|
|
43
|
+
- `main.py` adds a `session_manager_provider` that creates an `S3SessionManager` per `thread_id` when deployed, and falls back to an on-disk `FileSessionManager` under `/tmp/strands-sessions` when running under `agent-dev` (`LOCAL_DEV=true`). Deployed, the S3 bucket is the same one the Game API's `queryActions` reads from, so the browser can rebuild transcripts on revisit; locally the agent persists sessions to disk and talks to the local MCP server, without a deployment.
|
|
44
|
+
- `agent.py` drops the sample `subtract` tool and swaps the system prompt for a dungeon-master one that invites the first user message to state the player's name and genre, and uses the Inventory MCP Server's tools.
|
|
45
|
+
|
|
46
|
+
## Task 2: Test your Agent locally
|
|
47
|
+
|
|
48
|
+
### Build the code
|
|
49
|
+
|
|
50
|
+
To build the code:
|
|
51
|
+
|
|
52
|
+
<PackageManagerShortCommand commands={["build"]} />
|
|
53
|
+
|
|
54
|
+
<Aside type="tip" title="Fixing Lint Errors">
|
|
55
|
+
If you encounter any lint errors, run the following command to automatically fix them.
|
|
56
|
+
|
|
57
|
+
<PackageManagerShortCommand commands={["lint"]} />
|
|
58
|
+
</Aside>
|
|
59
|
+
|
|
60
|
+
### Chat with your Agent
|
|
61
|
+
|
|
62
|
+
The generated `agent-chat` target opens an interactive REPL against your agent. It runs standalone and connects to your locally-running agent, so first start the agent's local server in one terminal:
|
|
63
|
+
|
|
64
|
+
<NxCommands commands={["agent-dev story"]} />
|
|
65
|
+
|
|
66
|
+
Then, in a second terminal, start the chat:
|
|
67
|
+
|
|
68
|
+
<NxCommands commands={["agent-chat story"]} />
|
|
69
|
+
|
|
70
|
+
Your first message should tell the agent your hero's name and the genre (for example: `My name is Alice. Start my zombie adventure.`) and the story will stream back.
|
|
71
|
+
|
|
72
|
+
<Aside type="caution" title="AWS credentials required">
|
|
73
|
+
Although the agent runs locally, it invokes [Amazon Bedrock](https://aws.amazon.com/bedrock/) for the LLM. You'll need AWS credentials in your environment with access to the [Strands default model](https://strandsagents.com/latest/documentation/docs/user-guide/concepts/model-providers/amazon-bedrock/). See the [Strands model provider documentation](https://strandsagents.com/latest/documentation/docs/user-guide/concepts/model-providers/amazon-bedrock/) for details.
|
|
74
|
+
</Aside>
|
|
75
|
+
|
|
76
|
+
Congratulations. You have built and tested your first Strands Agent locally! 🎉🎉🎉
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Build the UI
|
|
3
|
+
description: A walkthrough of how to build an agentic AI-powered dungeon adventure game using the @aws/nx-plugin.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
import { Aside, Code, FileTree, Steps, Tabs, TabItem } from '@astrojs/starlight/components';
|
|
7
|
+
import { Image } from 'astro:assets';
|
|
8
|
+
import Link from '@components/link.astro';
|
|
9
|
+
import Drawer from '@components/drawer.astro';
|
|
10
|
+
import RunGenerator from '@components/run-generator.astro';
|
|
11
|
+
import NxCommands from '@components/nx-commands.astro';
|
|
12
|
+
import PackageManagerShortCommand from '@components/package-manager-short-command.astro';
|
|
13
|
+
import InstallCommand from '@components/install-command.astro';
|
|
14
|
+
import E2ECode from '@components/e2e-code.astro';
|
|
15
|
+
import E2EDiff from '@components/e2e-diff.astro';
|
|
16
|
+
|
|
17
|
+
import dungeonAdventureArchitecturePng from '@assets/dungeon-game-architecture.png'
|
|
18
|
+
import baselineWebsitePng from '@assets/baseline-website.png'
|
|
19
|
+
import baselineGamePng from '@assets/baseline-game.png'
|
|
20
|
+
import nxGraphPng from '@assets/nx-graph.png'
|
|
21
|
+
import gameSelectPng from '@assets/game-select.png'
|
|
22
|
+
import gameConversationPng from '@assets/game-conversation.png'
|
|
23
|
+
|
|
24
|
+
## Task 1: Run everything locally
|
|
25
|
+
|
|
26
|
+
Start the full local stack — the game-ui dev server together with a local Game API and a local AG-UI Story Agent (which in turn boots the Inventory MCP server) — with one command:
|
|
27
|
+
|
|
28
|
+
<NxCommands commands={["dev game-ui"]} />
|
|
29
|
+
|
|
30
|
+
The `dev` target on `game-ui` has `dependsOn` on `game-api:dev` and `dungeon_adventure.story:agent-dev`, so Nx spins up every project's local server in parallel. Through the connections we set up in Module 1, those in turn boot the Inventory MCP server and DynamoDB Local. Make sure your container engine is running, then open the dev server in a browser.
|
|
31
|
+
|
|
32
|
+
<Aside type="tip" title="No login locally">
|
|
33
|
+
In `local-dev` mode the `CognitoAuth` component skips the Cognito login flow (there's no user pool running locally), so you'll land straight on the game without signing in. You'll create a real account when we deploy to AWS at the end of this module.
|
|
34
|
+
</Aside>
|
|
35
|
+
|
|
36
|
+
<Aside type="caution" title="Keep Dev Server Running">
|
|
37
|
+
Leave the dev server running for the rest of this module — it hot-reloads every change below.
|
|
38
|
+
</Aside>
|
|
39
|
+
|
|
40
|
+
## Task 2: Where CopilotKit is already wired up
|
|
41
|
+
|
|
42
|
+
When you ran the `connection` generator for `game-ui → story` in <Link path="get_started/tutorials/dungeon-game/1">Module 1</Link>, the Shadcn website's AG-UI integration was generated for you. It's worth a quick look:
|
|
43
|
+
|
|
44
|
+
<FileTree>
|
|
45
|
+
- packages/game-ui/src/
|
|
46
|
+
- components/
|
|
47
|
+
- AguiProvider.tsx Single `CopilotKitProvider` registered with every AG-UI agent.
|
|
48
|
+
- copilot/
|
|
49
|
+
- index.tsx Re-exports themed `CopilotChat` / `CopilotSidebar` / `CopilotPopup`.
|
|
50
|
+
- ShadcnAssistantMessage.tsx, ShadcnUserMessage.tsx, ShadcnChatInput.tsx, ShadcnCursor.tsx, copilot.css
|
|
51
|
+
- hooks/
|
|
52
|
+
- useAguiStoryAgent.tsx Instantiates an `@ag-ui/client` `HttpAgent` pointing at the deployed Story Agent and pads `threadId` to AgentCore's 33-character minimum session id.
|
|
53
|
+
- main.tsx Wraps `<App />` in `<AguiProvider>`
|
|
54
|
+
</FileTree>
|
|
55
|
+
|
|
56
|
+
All we need to do is drop a `<CopilotChat agentId="agent" threadId={...} />` into a route. For more detail on how the integration is put together, see the <Link path="guides/connection/react-agui">React → AG-UI connection guide</Link>.
|
|
57
|
+
|
|
58
|
+
## Task 3: Restyle for the dungeon
|
|
59
|
+
|
|
60
|
+
Replace `packages/game-ui/src/styles.css` — this is the *only* file we change for styling. It imports the shared Shadcn globals, overrides the palette to a torch-lit dungeon theme, and makes CopilotKit inherit those colours:
|
|
61
|
+
|
|
62
|
+
<E2ECode lang="css" path="dungeon-adventure/4/styles.css.template" />
|
|
63
|
+
|
|
64
|
+
## Task 4: Create the game routes
|
|
65
|
+
|
|
66
|
+
We need two routes — one to pick a hero, one to play. Both use shadcn components and the CopilotKit chat; there is no hand-rolled chat UI.
|
|
67
|
+
|
|
68
|
+
<Tabs>
|
|
69
|
+
<TabItem label="routes/index.tsx">
|
|
70
|
+
<E2EDiff before="dungeon-adventure/4/routes/index.tsx.old.template" after="dungeon-adventure/4/routes/index.tsx.template" lang="tsx" />
|
|
71
|
+
|
|
72
|
+
This is the game picker: new-game form (shadcn `Input` + `Button` + `Card`) plus a "Continue" list fed by `useGameApi().games.query` with `useInfiniteQuery` — a bottom sentinel `<div>` watched by an `IntersectionObserver` auto-calls `fetchNextPage()` when scrolled into view, and spinners next to the heading and below the list surface the loading state. Starting a game `saveGame`s the `(playerName, genre)` pair (so it shows up next time) and navigates to the play route.
|
|
73
|
+
</TabItem>
|
|
74
|
+
<TabItem label="routes/game/$playerName.tsx">
|
|
75
|
+
<E2ECode path="dungeon-adventure/4/routes/game/$playerName.tsx.template" lang="tsx" />
|
|
76
|
+
|
|
77
|
+
This is the play route. It builds the deterministic `threadId` (``{player}-{genre}`` padded to 33 chars — the AG-UI hook will send it verbatim as the AgentCore session id), renders `<CopilotChat agentId="agent" threadId={threadId} />`, and overlays the inventory from `useGameApi().inventory.query` on top. On mount, `useGameApi().actions.query({ sessionId: threadId })` reads the conversation history the agent has stored in S3 and — if there is any — calls `agent.setMessages(...)` to rehydrate the chat; otherwise it sends one priming user message to kick the story off. `agent.messages` is subscribed via `useAgent({ updates: [OnMessagesChanged] })` so every new turn also refetches the inventory query (the MCP tool calls mutate DynamoDB directly).
|
|
78
|
+
|
|
79
|
+
<Aside type="tip" title="Wait for `isFetching`, not `isLoading`">
|
|
80
|
+
React Query's default cache retains the first result for 5 minutes, so a return visit initially sees the stale empty list from the very first load. We set `staleTime: 0` + `refetchOnMount: 'always'` and guard the hydration `useEffect` on `!isFetching && isSuccess` so the re-prime path only fires on a genuinely empty thread.
|
|
81
|
+
</Aside>
|
|
82
|
+
|
|
83
|
+
<Aside type="tip" title="Deterministic threadIds make /game/$playerName?genre=... sharable">
|
|
84
|
+
Revisiting the same URL — whether after a reload, a redeploy, or on another device — resolves to the same `threadId`, so the agent keeps telling the same story.
|
|
85
|
+
</Aside>
|
|
86
|
+
|
|
87
|
+
<Aside type="tip" title="Path Parameters">
|
|
88
|
+
The `$playerName` syntax tells `@tanstack/react-router` to treat `playerName` as a [path param](https://tanstack.com/router/v1/docs/framework/react/guide/path-params). `validateSearch` makes `genre` strongly typed against our enum.
|
|
89
|
+
</Aside>
|
|
90
|
+
</TabItem>
|
|
91
|
+
</Tabs>
|
|
92
|
+
|
|
93
|
+
Once saved, the dev server at `http://localhost:4200/` should now let you start an adventure and chat with the Story Agent.
|
|
94
|
+
|
|
95
|
+
<Image src={gameSelectPng} alt="game-select.png" width="600" height="309" />
|
|
96
|
+
<div style="margin-top: -100px; margin-left: 100px;">
|
|
97
|
+
<Image src={gameConversationPng} alt="game-conversation.png" width="600" height="310" />
|
|
98
|
+
</div>
|
|
99
|
+
|
|
100
|
+
## Task 5: Deploy to AWS
|
|
101
|
+
|
|
102
|
+
Your game is complete and you've tested every piece locally. Now let's deploy it to AWS so you can play it from anywhere.
|
|
103
|
+
|
|
104
|
+
### Build your code
|
|
105
|
+
|
|
106
|
+
<PackageManagerShortCommand commands={["build"]} />
|
|
107
|
+
|
|
108
|
+
### Deploy your application
|
|
109
|
+
|
|
110
|
+
<NxCommands commands={['deploy infra "dungeon-adventure-infra-sandbox/*"']} />
|
|
111
|
+
|
|
112
|
+
:::caution[Bootstrap Required]
|
|
113
|
+
If this is the first CDK deployment in your AWS account/region, bootstrap it first:
|
|
114
|
+
|
|
115
|
+
<NxCommands commands={['bootstrap infra']} />
|
|
116
|
+
:::
|
|
117
|
+
|
|
118
|
+
Your first deployment will take around 6 minutes to complete as it waits for all resources to fully stabilize. Subsequent deployments are faster. To speed up iteration during development you can opt into [CloudFormation express mode](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cloudformation-express-mode.html) by passing the `--express` flag, which completes each resource operation as soon as its configuration is applied rather than waiting for full stabilization.
|
|
119
|
+
|
|
120
|
+
Once the deployment completes, you will see outputs similar to the following:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
dungeon-adventure-infra-sandbox-Application
|
|
124
|
+
dungeon-adventure-infra-sandbox-Application: deploying... [2/2]
|
|
125
|
+
|
|
126
|
+
✅ dungeon-adventure-infra-sandbox-Application
|
|
127
|
+
|
|
128
|
+
✨ Deployment time: 354s
|
|
129
|
+
|
|
130
|
+
Outputs:
|
|
131
|
+
dungeon-adventure-infra-sandbox-Application.GameApiEndpointXXX = https://xxx.execute-api.region.amazonaws.com/prod/
|
|
132
|
+
dungeon-adventure-infra-sandbox-Application.GameUIDistributionDomainNameXXX = xxx.cloudfront.net
|
|
133
|
+
dungeon-adventure-infra-sandbox-Application.InventoryMcpArn = arn:aws:bedrock-agentcore:region:xxxxxxx:runtime/dungeonadventureventoryMcpServerXXXX-YYYY
|
|
134
|
+
dungeon-adventure-infra-sandbox-Application.RuntimeConfigApplicationId = xxxx
|
|
135
|
+
dungeon-adventure-infra-sandbox-Application.StoryAgentArn = arn:aws:bedrock-agentcore:region:xxxxxxx:runtime/dungeonadventurecationStoryAgentXXXX-YYYY
|
|
136
|
+
dungeon-adventure-infra-sandbox-Application.UserIdentityUserIdentityIdentityPoolIdXXX = region:xxx
|
|
137
|
+
dungeon-adventure-infra-sandbox-Application.UserIdentityUserIdentityUserPoolClientIdXXX = xxxxxxxxxx
|
|
138
|
+
dungeon-adventure-infra-sandbox-Application.UserIdentityUserIdentityUserPoolIdXXX = region_xxx
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Navigate to your CloudFront URL (`GameUIDistributionDomainName` from the CDK outputs), sign up for a new account, and play your game running entirely on AWS!
|
|
142
|
+
|
|
143
|
+
## Task 6: Mixing local and deployed components
|
|
144
|
+
|
|
145
|
+
You've seen two ends of the spectrum: everything local (`dev`) and everything deployed. During day-to-day development it's often useful to mix the two — for example, iterate on website code against the *real* deployed API and agent, or run the API locally against the *real* DynamoDB table.
|
|
146
|
+
|
|
147
|
+
The key is the `RUNTIME_CONFIG_APP_ID` environment variable. When a project runs **without** `LOCAL_DEV=true`, the runtime config lookups fetch their configuration from AWS AppConfig using this application id — the `RuntimeConfigApplicationId` value from your CDK outputs.
|
|
148
|
+
|
|
149
|
+
Each website has a `load:runtime-config` target that downloads the deployed `runtime-config.json` (Cognito pool, API endpoints, agent ARN) into the local dev server. Some useful combinations:
|
|
150
|
+
|
|
151
|
+
- **Local website → deployed backend.** Pull the deployed config once, then run the plain `serve` target so the UI talks to the deployed API and agent:
|
|
152
|
+
|
|
153
|
+
<NxCommands commands={["run game-ui:load:runtime-config"]} />
|
|
154
|
+
<NxCommands commands={["serve game-ui"]} />
|
|
155
|
+
|
|
156
|
+
- **Local API → real DynamoDB table.** Run the plain `serve` target with `RUNTIME_CONFIG_APP_ID` set to the deployed application id:
|
|
157
|
+
|
|
158
|
+
<NxCommands env={{RUNTIME_CONFIG_APP_ID:"<RuntimeConfigApplicationId from CDK outputs>"}} commands={["serve game-api"]} />
|
|
159
|
+
|
|
160
|
+
This flexibility lets you test exactly the slice you're working on, against whichever components — local or deployed — make sense.
|
|
161
|
+
|
|
162
|
+
Congratulations. You have built, tested, and deployed your Agentic Dungeon Adventure Game! 🎉🎉🎉
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Agentic AI Dungeon Game
|
|
3
|
+
description: A walkthrough of how to build an agentic AI-powered dungeon adventure game using the @aws/nx-plugin.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
import { Aside, Code, FileTree, Steps, Tabs, TabItem } from '@astrojs/starlight/components';
|
|
7
|
+
import Snippet from '@components/snippet.astro';
|
|
8
|
+
import { Image } from 'astro:assets';
|
|
9
|
+
import Drawer from '@components/drawer.astro';
|
|
10
|
+
import RunGenerator from '@components/run-generator.astro';
|
|
11
|
+
import NxCommands from '@components/nx-commands.astro';
|
|
12
|
+
import InstallCommand from '@components/install-command.astro';
|
|
13
|
+
import Link from '@components/link.astro';
|
|
14
|
+
|
|
15
|
+
import baselineWebsitePng from '@assets/baseline-website.png'
|
|
16
|
+
import baselineGamePng from '@assets/baseline-game.png'
|
|
17
|
+
import nxGraphPng from '@assets/nx-graph.png'
|
|
18
|
+
import gameSelectPng from '@assets/game-select.png'
|
|
19
|
+
import gameConversationPng from '@assets/game-conversation.png'
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
Using this tutorial, you will build an Agentic AI-powered dungeon adventure game with `@aws/nx-plugin`. This tutorial does not assume any existing knowledge of the `@aws/nx-plugin` or related technologies.
|
|
23
|
+
The techniques you'll learn in this tutorial will help:
|
|
24
|
+
- Build any `@aws/nx-plugin` based application,
|
|
25
|
+
- Provide a deep understanding of the `@aws/nx-plugin`, and
|
|
26
|
+
- Get a basic understanding of how to use the [NX](https://nx.dev/) framework.
|
|
27
|
+
|
|
28
|
+
<Aside title="Hands-on Learning">This tutorial is designed for people who prefer to learn by doing and want to quickly try making something tangible. If you prefer learning each concept step by step, refer to the individual component guides using the left navigation.</Aside>
|
|
29
|
+
|
|
30
|
+
At the end of the tutorial, you will walk away with the knowledge to:
|
|
31
|
+
|
|
32
|
+
- use the `@aws/nx-plugin` to create new applications,
|
|
33
|
+
- use NX to manage/build their codebase,
|
|
34
|
+
- build APIs using tRPC,
|
|
35
|
+
- build Agents using Strands,
|
|
36
|
+
- build MCP servers in TypeScript,
|
|
37
|
+
- use Tanstack router to create new pages,
|
|
38
|
+
- use Tanstack query to call backend APIs,
|
|
39
|
+
- model data in DynamoDB and develop locally against DynamoDB Local, and
|
|
40
|
+
- create and deploy CDK infrastructure.
|
|
41
|
+
|
|
42
|
+
## What are you building?
|
|
43
|
+
|
|
44
|
+
In this tutorial, you'll build an Agentic AI-powered dungeon adventure game with `@aws/nx-plugin`.
|
|
45
|
+
|
|
46
|
+
The game interface will resemble something like this diagram:
|
|
47
|
+
|
|
48
|
+
<Image src={gameSelectPng} alt="game-select.png" width="600" height="309" />
|
|
49
|
+
<div style="margin-top: -100px; margin-left: 100px;">
|
|
50
|
+
<Image src={gameConversationPng} alt="game-conversation.png" width="600" height="310" />
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
### Application architecture
|
|
54
|
+
|
|
55
|
+
The Agentic AI-powered dungeon adventure game is built using the following architecture:
|
|
56
|
+
|
|
57
|
+
```d2 inline=true
|
|
58
|
+
direction: down
|
|
59
|
+
|
|
60
|
+
browser: Web Browser {
|
|
61
|
+
shape: image
|
|
62
|
+
icon: /nx-plugin-for-aws/icons/aws/client.svg
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
cognito: Cognito / IAM {
|
|
66
|
+
shape: image
|
|
67
|
+
icon: /nx-plugin-for-aws/icons/aws/cognito.svg
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
cloudfront: CloudFront {
|
|
71
|
+
shape: image
|
|
72
|
+
icon: /nx-plugin-for-aws/icons/aws/cloudfront.svg
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
s3: Static Assets\n(S3) {
|
|
76
|
+
shape: image
|
|
77
|
+
icon: /nx-plugin-for-aws/icons/aws/s3.svg
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
apigw: API Gateway\n(Game API) {
|
|
81
|
+
shape: image
|
|
82
|
+
icon: /nx-plugin-for-aws/icons/aws/api-gateway.svg
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
lambda: tRPC API\n(Lambda) {
|
|
86
|
+
shape: image
|
|
87
|
+
icon: /nx-plugin-for-aws/icons/aws/lambda.svg
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
story: Story Agent\n(AgentCore) {
|
|
91
|
+
shape: image
|
|
92
|
+
icon: /nx-plugin-for-aws/icons/aws/bedrock-agentcore-runtime.svg
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
mcp: Inventory MCP\n(AgentCore) {
|
|
96
|
+
shape: image
|
|
97
|
+
icon: /nx-plugin-for-aws/icons/aws/bedrock-agentcore-runtime.svg
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
ddb: Game State\n(DynamoDB) {
|
|
101
|
+
shape: image
|
|
102
|
+
icon: /nx-plugin-for-aws/icons/aws/dynamodb.svg
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
sessions: Story Sessions\n(S3) {
|
|
106
|
+
shape: image
|
|
107
|
+
icon: /nx-plugin-for-aws/icons/aws/s3.svg
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
browser -> cognito: Sign in
|
|
111
|
+
browser -> cloudfront
|
|
112
|
+
cloudfront -> s3
|
|
113
|
+
browser -> apigw
|
|
114
|
+
apigw -> lambda
|
|
115
|
+
lambda -> ddb
|
|
116
|
+
lambda -> sessions: Read transcripts
|
|
117
|
+
browser -> story: AG-UI stream
|
|
118
|
+
story -> sessions: Persist turns
|
|
119
|
+
story -> mcp: Tool calls
|
|
120
|
+
mcp -> ddb
|
|
121
|
+
ddb -> sessions: {
|
|
122
|
+
style.opacity: 0
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
- React/Vite frontend website utilising:
|
|
127
|
+
- Amazon Cognito/Identity Pools for secure API calls.
|
|
128
|
+
- [Tanstack router](https://tanstack.com/router/latest) which supports type-safe file based routing.
|
|
129
|
+
- Generated SDKs for calling the Game API.
|
|
130
|
+
- [tRPC](https://trpc.io/) API which uses [ElectroDB](https://electrodb.dev/)/[DynamoDB](https://aws.amazon.com/dynamodb/) for managing the game state.
|
|
131
|
+
- [Strands](https://strandsagents.com/) Agent hosted on [Amazon Bedrock AgentCore](https://aws.amazon.com/bedrock/agentcore/) for running the game.
|
|
132
|
+
- TypeScript MCP Server hosted on [Amazon Bedrock AgentCore](https://aws.amazon.com/bedrock/agentcore/) for the agent to manage the player's inventory.
|
|
133
|
+
- [CDK](https://docs.aws.amazon.com/cdk/v2/guide/home.html) infrastructure to deploy the application.
|
|
134
|
+
|
|
135
|
+
## Prerequisites
|
|
136
|
+
|
|
137
|
+
Before you proceed, you will need the following global dependencies:
|
|
138
|
+
|
|
139
|
+
<Snippet name="required-prerequisites" />
|
|
140
|
+
- [Docker](https://www.docker.com/) (or [Finch](https://github.com/runfinch/finch)) is required for local DynamoDB development and for building the AgentCore components
|
|
141
|
+
|
|
142
|
+
:::tip[AI Assistant Setup]
|
|
143
|
+
If you use an AI Assistant such as Kiro, Kiro CLI, Cursor, Claude Code or Cline, refer to the <Link path="/get_started/building-with-ai">install the Nx Plugin for AWS MCP server</Link> page.
|
|
144
|
+
:::
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Agentic AI Dungeon Game
|
|
3
|
+
description: A walkthrough of how to build an agentic AI-powered dungeon adventure game using the @aws/nx-plugin.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
import { Aside, Code, FileTree, Steps, Tabs, TabItem } from '@astrojs/starlight/components';
|
|
7
|
+
import { Image } from 'astro:assets';
|
|
8
|
+
import Drawer from '@components/drawer.astro';
|
|
9
|
+
import Link from '@components/link.astro';
|
|
10
|
+
import RunGenerator from '@components/run-generator.astro';
|
|
11
|
+
import NxCommands from '@components/nx-commands.astro';
|
|
12
|
+
import InstallCommand from '@components/install-command.astro';
|
|
13
|
+
import dungeonAdventureArchitecturePng from '@assets/dungeon-game-architecture.png'
|
|
14
|
+
import baselineWebsitePng from '@assets/baseline-website.png'
|
|
15
|
+
import baselineGamePng from '@assets/baseline-game.png'
|
|
16
|
+
import nxGraphPng from '@assets/nx-graph.png'
|
|
17
|
+
import gameSelectPng from '@assets/game-select.png'
|
|
18
|
+
import gameConversationPng from '@assets/game-conversation.png'
|
|
19
|
+
|
|
20
|
+
## Wrap up
|
|
21
|
+
|
|
22
|
+
Congratulations! You’ve created an Agentic AI Dungeon adventure game that uses many of the available generators found within the `@aws/nx-plugin`. 🎉🎉🎉
|
|
23
|
+
|
|
24
|
+
## What next?
|
|
25
|
+
|
|
26
|
+
We recommend you try your hand at extending the codebase with the following capabilities on your own:
|
|
27
|
+
|
|
28
|
+
1. Add the <Link path="guides/license">license generator</Link> to your project which will automatically manage LICENSE files and source code headers in your workspace.
|
|
29
|
+
2. <Link path="get_started/tutorials/contribute-generator">Contribute your own generator</Link> to simplify the addition on new tRPC APIs.
|
|
30
|
+
3. Add a new `resetToAction` api (using your above generator) in GameAPI which allows you to go back in time and delete all actions from a given point. Update the UI to add a button on a conversation bubble to reset to this point (and call the newly created API).
|
|
31
|
+
4. Explore the various component guides using the left navigation.
|
|
32
|
+
|
|
33
|
+
## Destroying resources
|
|
34
|
+
|
|
35
|
+
1. To destroy the AWS resources that were created, run the following command:
|
|
36
|
+
|
|
37
|
+
<NxCommands commands={['destroy infra "dungeon-adventure-infra-sandbox/*"']} />
|
|
38
|
+
|
|
39
|
+
This will prompt you for a list of stacks to delete which should comprise of the `dungeon-adventure-infra-sandbox/Application/GameUI/waf` and `dungeon-adventure-infra-sandbox/Application`.
|
|
40
|
+
|
|
41
|
+
2. Enter `Y` to continue. CloudFormation will destroy your stacks.
|