CopilotKit × Strands Agents on Bedrock AgentCore構成を試してみた

CopilotKit × Strands Agents on Bedrock AgentCore構成を試してみた

2025.12.06

はじめに

Strands AgentsがAG-UIに対応しました。これによりCopilotKitからStrandsを呼び出すことが可能です。

https://x.com/CopilotKit/status/1996252183176613896

CopilotKitとAWS Strandsを使ったQuickStartがあったので、こちらをベースに少しカスタマイズしつつ、サーバー側だけホスティングしてみたいと思います。

https://docs.copilotkit.ai/aws-strands/quickstart

構成

構成は以下の通りです。

architecture.drawio

CopilotKitはNext.jsを使っており、App Router の Route Handler(API Route)を使っているため静的ホストできないため、今回はローカルとし対象外とします。サクッとデプロイするならCopilot CloudやVercelなどのホスティングサービスを利用すると良いと思います。

Amazon API Gatewayは先月(25年11月末)に発表されたAPI Gatewayのストリーミング時間が15分に拡張されたため、LLMの長いストリーミングに対応できるようになりました。

https://aws.amazon.com/jp/blogs/compute/building-responsive-apis-with-amazon-api-gateway-response-streaming/

また、API Gatewayの認証、認可の幅広い機能やWAFなどをAgentCoreの前段に設定することが可能です。

CopilotKitのQuickStartから始まりますが、途中で大きく構成を変更するため、以下のリポジトリを参照するのが良いと思います。

https://github.com/shuntaka9576/copilotkit-strands-agentcore

構築

CopilotkitのStrands(Python)のQuickStart

CopilotKitのStrandsのQuick Startを利用します。適宜読み替えていますので、最終的にはリポジトリのソースを確認するのが良いと思います。

https://docs.copilotkit.ai/aws-strands/quickstart

まずテンプレートを初期化します。

$ pnpm dlx copilotkit@latest create -f aws-strands-py

⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠙⣿⡛⠻⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠋⠀⠀⠈⢿⡄⠀⠀⠀⠈⠉⠙⣻⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠁⠀⠀⠀⠀⠈⢿⡄⠀⢀⣠⣴⠾⠋⢸⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡟⠁⢀⣀⣀⣀⣀⣤⣤⡾⢿⡟⠛⠉⠀⠀⠀⠀⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡛⠛⠛⠛⠉⠉⠉⠁⠀⢠⡿⣿⡀⠀⠀⠀⠀⠀⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⣰⡟⠀⠸⣧⠀⠀⠀⠀⢠⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⢀⣼⠏⠀⠀⠀⣿⡀⠀⠀⠀⢸⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠂⣠⡿⠁⠀⠀⠀⠀⢸⡇⠀⠀⠀⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⣡⣾⣿⣄⠀⠀⠀⠀⠀⢸⡇⠀⠀⢰⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣿⡟⠛⡿⠋⣡⣾⣿⣿⣿⣿⣦⡀⠀⠀⠀⢸⡇⠀⠀⣿⣿⣿⣿
⣿⣿⣿⣿⡿⠿⣿⠷⠂⡀⠘⣿⣿⣿⣿⣿⣿⣿⣷⡀⠀⠀⢸⡇⠀⣼⣿⣿⣿⣿
⣿⣿⠻⢿⡷⠀⠁⠴⣿⣷⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⣾⠇⣴⣿⣿⣿⣿⣿
⡿⠛⠀⠀⢴⣾⣷⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣤⣿⣾⣿⣿⣿⣿⣿⣿
⣷⣾⣿⣤⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿

~ Welcome to CopilotKit! ~

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
? What is your project named? copilotkit-strands-agentcore

依存関係をインストールします。

pnpm install

動作確認するためOpenAIのAPIキーを利用します。この後Bedrockに書き換えるので、APIキーがない場合はこちらの手順はスキップで問題ありません。

export OPENAI_API_KEY='your_openai_api_key'
perl -i -pe "s/your_openai_api_key/${OPENAI_API_KEY}/" agent/.env

以下のコマンドで、Webアプリが http://localhost:3000に Webサーバー(Strands)が http://localhost:8000 に立ち上がります。

pnpm run dev

http://localhost:3000 に Webアプリが起動していることを確認します。赤枠のGenerative UIを押下します。

CleanShot 2025-12-06 at 08.36.56@2-2

UIがBotから返却されれば、正しく動作していることがわかります。

CleanShot 2025-12-06 at 08.37.09@2x

ここからテンプレートを変更して冒頭の構成になるようにコードを書き換えます。最終的な差分はこちらを参考にしてください

https://github.com/shuntaka9576/copilotkit-strands-agentcore/compare/d914406fa9922ec04d6271c99c27bacd3d0eca94...main#diff-38cef5159b85e71367322015a5142d88ed9d964baaab26e60ef195cc10d0fe7f

主な変更点は以下の通りです

  • テンプレートだとnpmで取り回しが難しい部分があるので、pnpm workspaceとturboでプロジェクト構成へ変更
  • 自動生成されたテンプレートのpyproject.tomlに利用していないライブラリも含まれており、削除
  • APIGatewayから呼ばれるLambdaの実装を追加
  • AgentCoreの要件に合うようにAgentのソースを修正
  • インフラ(iacコード)定義の追加

Amazon API Gatewayから呼び出されるLambda実装

https://github.com/shuntaka9576/copilotkit-strands-agentcore/blob/4046577112d106e051f3d3971f2d2e26c6c8199a/server/src/index.ts#L1-L49

LambdaはそのままAgentCoreにリクエストをプロキシします。

https://github.com/shuntaka9576/copilotkit-strands-agentcore/blob/4046577112d106e051f3d3971f2d2e26c6c8199a/server/src/index.ts#L17-L37

Amazon API Gatewayから呼び出されストリーミングをする際に、awslambda.streamifyResponseを使うパターンもありますが、Honoの場合streamHandleを使えば、Lambda特有のコードを書かずにすみます。

https://github.com/shuntaka9576/copilotkit-strands-agentcore/blob/4046577112d106e051f3d3971f2d2e26c6c8199a/server/src/index.ts#L6
https://github.com/shuntaka9576/copilotkit-strands-agentcore/blob/4046577112d106e051f3d3971f2d2e26c6c8199a/server/src/index.ts#L49

AgentCoreのアプリケーション実装

先ほどのテンプレートからAgentCoreにデプロイできるように変更をしていきます。

AgentCoreへのデプロイ要件への対応

https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/getting-started-custom.html#bedrock-agentcore-runtime-requirements

及び、OpenAIモデルからBedrockモデルへ変更します。該当箇所を示します。

/invocations パスの実装。ag_ui_strands の パスを置き換えて対応します。

https://github.com/shuntaka9576/copilotkit-strands-agentcore/blob/4046577112d106e051f3d3971f2d2e26c6c8199a/agent/main.py#L148-L149

関連してこちらのag-ui-strandsのAgent定義が、AG-UIの処理をラップしたStrandsのAgent実装と理解しています。(違っていた場合、フィードバックお願いします🙇)
https://github.com/shuntaka9576/copilotkit-strands-agentcore/blob/4046577112d106e051f3d3971f2d2e26c6c8199a/agent/main.py#L13-L18

Webアプリ側も同様に変更が必要です。
https://github.com/shuntaka9576/copilotkit-strands-agentcore/blob/4046577112d106e051f3d3971f2d2e26c6c8199a/web/src/app/api/copilotkit/route.ts#L16-L21

/ping パスの実装

https://github.com/shuntaka9576/copilotkit-strands-agentcore/blob/4046577112d106e051f3d3971f2d2e26c6c8199a/agent/main.py#L152-L155

8080ポートでLISTENする

https://github.com/shuntaka9576/copilotkit-strands-agentcore/blob/4046577112d106e051f3d3971f2d2e26c6c8199a/agent/main.py#L158-L161

Bedrockの実装に差し替えます。

https://github.com/shuntaka9576/copilotkit-strands-agentcore/blob/4046577112d106e051f3d3971f2d2e26c6c8199a/agent/main.py#L123-L126

Dockerfileを定義します。

https://github.com/shuntaka9576/copilotkit-strands-agentcore/blob/4046577112d106e051f3d3971f2d2e26c6c8199a/Dockerfile#L1-L20

インフラ実装

AgentCoreを実装します。Dockerfileを指定してCDK側でビルド、デプロイしています。

https://github.com/shuntaka9576/copilotkit-strands-agentcore/blob/4046577112d106e051f3d3971f2d2e26c6c8199a/iac/lib/main-stack.ts#L20-L37

.dockerignore/agent 以外のソースをdocker contextに送らないように注意してください。(データサイズが大きいとCDKがクラッシュします)

https://github.com/shuntaka9576/copilotkit-strands-agentcore/blob/4046577112d106e051f3d3971f2d2e26c6c8199a/.dockerignore#L1-L2

Lambdaの設定とAPIGatewayのストリーミングの設定を行います。これによりSSEで29秒のタイムアウトの壁を超えることができます。
https://github.com/shuntaka9576/copilotkit-strands-agentcore/blob/4046577112d106e051f3d3971f2d2e26c6c8199a/iac/lib/main-stack.ts#L39-L94

CDKをデプロイします

$ cd iac
$ pnpm run deploy

> iac@0.1.0 deploy /Users/shuntaka/repos/github.com/shuntaka9576/copilotkit-strands-agentcore/iac
> cdk deploy

(中略)

Outputs:
CopilotKitStrandsStack.RestApiEndpoint0551178A = https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/v1/
CopilotKitStrandsStack.RestApiUrl = https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/v1/
Stack ARN:
arn:aws:cloudformation:ap-northeast-1:622455551446:stack/CopilotKitStrandsStack/181cdbd0-d24b-11f0-a0ad-0ec93f2d35bd

✨  Total time: 3.9s

(中略)

出力RestApiUrlのURLを控えておきます。

実行してみる

現在ソースコードは、pnpm dev をするとWebアプリ(CopilotKit)のNext.js App Router の Route Handler(API Route)から http://localhost:8080/invocations を実行しています。これはLambdaを通さずに直接ローカルのStrandsのuvicornのサーバーを叩いています。このURLをAPIGatewayのものに置換し、応答が変えることを確認します。

$ export API_GATEWAY_ENDPOINT="https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com"
$ perl -pi -e "s|http://localhost:8080/invocations|${API_GATEWAY_ENDPOINT}/v1/api|" web/src/app/api/copilotkit/route.ts

# AWS資格情報取得(bedrockリクエストのため)
$ pnpm dev

動作することが確認できました。

CleanShot 2025-12-06 at 22.05.10

CleanShot 2025-12-06 at 22.09.34@2x

AgentCoreのCloudWatchのログも確認できました

timestamp,message,logStreamName
1765026312512,WARNING:  Invalid HTTP request received.,2025/12/06/[runtime-logs]2e89abcd-a991-487f-af11-9361d04c17f3
1765026312536,"INFO:     127.0.0.1:43550 - ""POST /invocations HTTP/1.1"" 200 OK",2025/12/06/[runtime-logs]2e89abcd-a991-487f-af11-9361d04c17f3
1765026314069,Tool #1: get_weather,2025/12/06/[runtime-logs]2e89abcd-a991-487f-af11-9361d04c17f3
1765026314069,"The weather inINFO:     127.0.0.1:43564 - ""GET /ping HTTP/1.1"" 200 OK",2025/12/06/[runtime-logs]2e89abcd-a991-487f-af11-9361d04c17f3
1765026316070," San Francisco is currently **70 degrees**. It's a pleasant, mild day! 🌤️INFO:     127.0.0.1:43564 - ""GET /ping HTTP/1.1"" 200 OK",2025/12/06/[runtime-logs]2e89abcd-a991-487f-af11-9361d04c17f3
1765026318071,"INFO:     127.0.0.1:43564 - ""GET /ping HTTP/1.1"" 200 OK",2025/12/06/[runtime-logs]2e89abcd-a991-487f-af11-9361d04c17f3
1765026319523,INFO:     Started server process [1],2025/12/06/[runtime-logs]841a6e7f-ca7a-4e56-b356-d7248f6fc9e3
1765026319523,INFO:     Waiting for application startup.,2025/12/06/[runtime-logs]841a6e7f-ca7a-4e56-b356-d7248f6fc9e3
1765026319523,INFO:     Application startup complete.,2025/12/06/[runtime-logs]841a6e7f-ca7a-4e56-b356-d7248f6fc9e3

動作的に逐次で文章生成をしている感じがしなかったのでcurlでも叩いてみます。(ヘッダー省略)

$ curl 'http://localhost:3000/api/copilotkit' \
  --data-raw $'{"operationName":"generateCopilotResponse","query":"mutation generateCopilotResponse($data: GenerateCopilotResponseInput\u0021, $properties: JSONObject) {\\n  generateCopilotResponse(data: $data, properties: $properties) {\\n    threadId\\n    runId\\n    extensions {\\n      openaiAssistantAPI {\\n        runId\\n        threadId\\n        __typename\\n      }\\n      __typename\\n    }\\n    ... on CopilotResponse @defer {\\n      status {\\n        ... on BaseResponseStatus {\\n          code\\n          __typename\\n        }\\n        ... on FailedResponseStatus {\\n          reason\\n          details\\n          __typename\\n        }\\n        __typename\\n      }\\n      __typename\\n    }\\n    messages @stream {\\n      __typename\\n      ... on BaseMessageOutput {\\n        id\\n        createdAt\\n        __typename\\n      }\\n      ... on BaseMessageOutput @defer {\\n        status {\\n          ... on SuccessMessageStatus {\\n            code\\n            __typename\\n          }\\n          ... on FailedMessageStatus {\\n            code\\n            reason\\n            __typename\\n          }\\n          ... on PendingMessageStatus {\\n            code\\n            __typename\\n          }\\n          __typename\\n        }\\n        __typename\\n      }\\n      ... on TextMessageOutput {\\n        content @stream\\n        role\\n        parentMessageId\\n        __typename\\n      }\\n      ... on ImageMessageOutput {\\n        format\\n        bytes\\n        role\\n        parentMessageId\\n        __typename\\n      }\\n      ... on ActionExecutionMessageOutput {\\n        name\\n        arguments @stream\\n        parentMessageId\\n        __typename\\n      }\\n      ... on ResultMessageOutput {\\n        result\\n        actionExecutionId\\n        actionName\\n        __typename\\n      }\\n      ... on AgentStateMessageOutput {\\n        threadId\\n        state\\n        running\\n        agentName\\n        nodeName\\n        runId\\n        active\\n        role\\n        __typename\\n      }\\n    }\\n    metaEvents @stream {\\n      ... on LangGraphInterruptEvent {\\n        type\\n        name\\n        value\\n        __typename\\n      }\\n      ... on CopilotKitLangGraphInterruptEvent {\\n        type\\n        name\\n        data {\\n          messages {\\n            __typename\\n            ... on BaseMessageOutput {\\n              id\\n              createdAt\\n              __typename\\n            }\\n            ... on BaseMessageOutput @defer {\\n              status {\\n                ... on SuccessMessageStatus {\\n                  code\\n                  __typename\\n                }\\n                ... on FailedMessageStatus {\\n                  code\\n                  reason\\n                  __typename\\n                }\\n                ... on PendingMessageStatus {\\n                  code\\n                  __typename\\n                }\\n                __typename\\n              }\\n              __typename\\n            }\\n            ... on TextMessageOutput {\\n              content\\n              role\\n              parentMessageId\\n              __typename\\n            }\\n            ... on ActionExecutionMessageOutput {\\n              name\\n              arguments\\n              parentMessageId\\n              __typename\\n            }\\n            ... on ResultMessageOutput {\\n              result\\n              actionExecutionId\\n              actionName\\n              __typename\\n            }\\n          }\\n          value\\n          __typename\\n        }\\n        __typename\\n      }\\n      __typename\\n    }\\n    __typename\\n  }\\n}","variables":{"data":{"agentSession":{"agentName":"strands_agent"},"agentStates":[{"agentName":"strands_agent","config":"{}","state":"{\\"proverbs\\":[\\"CopilotKit may be new, but its the best thing since sliced bread.\\"]}"}],"context":[],"extensions":{},"forwardedParameters":{},"frontend":{"actions":[{"available":"enabled","description":"","jsonSchema":"{\\"type\\":\\"object\\",\\"properties\\":{\\"theme_color\\":{\\"type\\":\\"string\\",\\"description\\":\\"The theme color to set. Make sure to pick nice colors.\\"}},\\"required\\":[\\"theme_color\\"]}","name":"set_theme_color"}],"url":"http://localhost:3000/"},"messages":[{"createdAt":"2025-12-06T13:11:06.705Z","id":"ck-95e26812-4372-4511-8b94-d874ae3b8b96","textMessage":{"content":"\\nPlease act as an efficient, competent, conscientious, and industrious professional assistant.\\n\\nHelp the user achieve their goals, and you do so in a way that is as efficient as possible, without unnecessary fluff, but also without sacrificing professionalism.\\nAlways be polite and respectful, and prefer brevity over verbosity.\\n\\nThe user has provided you with the following context:\\n```\\n\\n\\n\\n```\\n\\nThey have also provided you with functions you can call to initiate actions on their behalf, or functions you can call to receive more information.\\n\\nPlease assist them as best you can.\\n\\nYou can ask them for clarifying questions if needed, but don\'t be annoying about it. If you can reasonably \'fill in the blanks\' yourself, do so.\\n\\nIf you would like to call a function, call it without saying anything else.\\nIn case of a function error:\\n- If this error stems from incorrect function parameters or syntax, you may retry with corrected arguments.\\n- If the error\'s source is unclear or seems unrelated to your input, do not attempt further retries.\\n","role":"system"}},{"createdAt":"2025-12-06T13:11:06.704Z","id":"ck-85b8308c-44e7-471c-a09a-03301b904288","textMessage":{"content":"Add a proverb about AI.","role":"user"}}],"metaEvents":[],"metadata":{"requestType":"Chat"},"runId":null,"threadId":"ff930531-f0cf-4423-bd51-f443904bc063"},"properties":{}}}'

---
Content-Type: application/json; charset=utf-8
Content-Length: 195

{"data":{"generateCopilotResponse":{"threadId":"ff930531-f0cf-4423-bd51-f443904bc063","runId":null,"extensions":null,"__typename":"CopilotResponse","messages":[],"metaEvents":[]}},"hasNext":true}
---
Content-Type: application/json; charset=utf-8
Content-Length: 503

{"incremental":[{"items":[{"__typename":"AgentStateMessageOutput","id":"ck-1a4f8dd8-3341-4993-84d7-88476ec24120","createdAt":"2025-12-06T13:13:04.630Z","threadId":"ff930531-f0cf-4423-bd51-f443904bc063","state":"{\"proverbs\":[\"CopilotKit may be new, but its the best thing since sliced bread.\"]}","running":true,"agentName":"strands_agent","nodeName":"","runId":"db8440e0-b87c-4625-8614-4da3cd661e2e","active":true,"role":"assistant"}],"path":["generateCopilotResponse","messages",0]}],"hasNext":true}
---
Content-Type: application/json; charset=utf-8
Content-Length: 2305

{"incremental":[{"items":[{"__typename":"AgentStateMessageOutput","id":"ck-ed5b9c44-46c0-4fc4-b3d7-4d9205317250","createdAt":"2025-12-06T13:13:04.630Z","threadId":"ff930531-f0cf-4423-bd51-f443904bc063","state":"{\"proverbs\":[\"CopilotKit may be new, but its the best thing since sliced bread.\",\"Artificial intelligence is a tool; wisdom is knowing how to use it.\"]}","running":true,"agentName":"strands_agent","nodeName":"","runId":"db8440e0-b87c-4625-8614-4da3cd661e2e","active":true,"role":"assistant"}],"path":["generateCopilotResponse","messages",1]},{"data":{"status":{"code":"Success","__typename":"SuccessMessageStatus"},"__typename":"AgentStateMessageOutput"},"path":["generateCopilotResponse","messages",0]},{"items":[{"__typename":"ActionExecutionMessageOutput","id":"tooluse_pnrf2viIRqKFqlh2NzI1qA","createdAt":"2025-12-06T13:13:04.631Z","name":"update_proverbs","parentMessageId":"9a5a9c91-0c5d-4381-9ba8-e5ef972902a7","arguments":[]}],"path":["generateCopilotResponse","messages",2]},{"data":{"status":{"code":"Success","__typename":"SuccessMessageStatus"},"__typename":"AgentStateMessageOutput"},"path":["generateCopilotResponse","messages",1]},{"items":[{"__typename":"ResultMessageOutput","id":"result-tooluse_pnrf2viIRqKFqlh2NzI1qA","createdAt":"2025-12-06T13:13:04.631Z","result":"\"Proverbs updated successfully\"","actionExecutionId":"tooluse_pnrf2viIRqKFqlh2NzI1qA","actionName":"update_proverbs"}],"path":["generateCopilotResponse","messages",3]},{"items":["{\"proverbs_list\": {\"proverbs\": [\"CopilotKit may be new, but its the best thing since sliced bread.\", \"Artificial intelligence is a tool; wisdom is knowing how to use it.\"]}}"],"path":["generateCopilotResponse","messages",2,"arguments",0]},{"data":{"__typename":"ActionExecutionMessageOutput","status":{"code":"Success","__typename":"SuccessMessageStatus"}},"path":["generateCopilotResponse","messages",2]},{"items":[{"__typename":"TextMessageOutput","id":"9a5a9c91-0c5d-4381-9ba8-e5ef972902a7","createdAt":"2025-12-06T13:13:04.631Z","role":"assistant","parentMessageId":null,"content":[]}],"path":["generateCopilotResponse","messages",4]},{"data":{"status":{"code":"Success","__typename":"SuccessMessageStatus"},"__typename":"ResultMessageOutput"},"path":["generateCopilotResponse","messages",3]}],"hasNext":true}
---
Content-Type: application/json; charset=utf-8
Content-Length: 1721

{"incremental":[{"items":[{"__typename":"AgentStateMessageOutput","id":"ck-342c2e14-16b6-4785-9472-8ce467b690f5","createdAt":"2025-12-06T13:13:04.631Z","threadId":"ff930531-f0cf-4423-bd51-f443904bc063","state":"{\"proverbs\":[\"CopilotKit may be new, but its the best thing since sliced bread.\",\"Artificial intelligence is a tool; wisdom is knowing how to use it.\"]}","running":true,"agentName":"strands_agent","nodeName":"","runId":"db8440e0-b87c-4625-8614-4da3cd661e2e","active":false,"role":"assistant"}],"path":["generateCopilotResponse","messages",5]},{"items":["Perfect"],"path":["generateCopilotResponse","messages",4,"content",0]},{"data":{"__typename":"TextMessageOutput","status":{"code":"Success","__typename":"SuccessMessageStatus"}},"path":["generateCopilotResponse","messages",4]},{"items":["! I've added a new proverb about AI to your"],"path":["generateCopilotResponse","messages",4,"content",1]},{"data":{"status":{"code":"Success","__typename":"SuccessMessageStatus"},"__typename":"AgentStateMessageOutput"},"path":["generateCopilotResponse","messages",5]},{"items":[" collection:\n\n**\"Artificial intelligence is a tool;"],"path":["generateCopilotResponse","messages",4,"content",2]},{"items":[" wisdom is knowing how to use it.\"**\n\nYour"],"path":["generateCopilotResponse","messages",4,"content",3]},{"items":[" proverbs list now contains:\n1. \""],"path":["generateCopilotResponse","messages",4,"content",4]},{"items":["CopilotKit may be new, but its the best thing since sl"],"path":["generateCopilotResponse","messages",4,"content",5]},{"items":["iced bread.\"\n2. \"Artificial intelligence is a tool; wisdom is"],"path":["generateCopilotResponse","messages",4,"content",6]}],"hasNext":true}
---
Content-Type: application/json; charset=utf-8
Content-Length: 132

{"incremental":[{"items":[" knowing how to use it.\""],"path":["generateCopilotResponse","messages",4,"content",7]}],"hasNext":true}
---
Content-Type: application/json; charset=utf-8
Content-Length: 174

{"incremental":[{"data":{"__typename":"CopilotResponse","status":{"code":"Success","__typename":"SuccessResponseStatus"}},"path":["generateCopilotResponse"]}],"hasNext":true}
---
Content-Type: application/json; charset=utf-8
Content-Length: 17

{"hasNext":false}
-----

SSEと思っていましたが、リクエストのGraphQLクエリに@streamが付与されていることから、CopilotKitは、GraphQL Incremental Deliveryを使ったMultipart HTTP Responseっぽいです。逐次ストリーミング出来ないか別機会に調べてみようと思います。

さいごに

CopilotKitとStrandsの連携について書きました。初めてCopilotKiを触りましたが、AIエージェントの表現の幅を広げることができ、今までのWebアプリやLLMチャットアプリとは違う体験を提供出来る点非常に面白いと思いました。Strandsは最近TypeScript版もリリースされたので、同じようなAG-UIサポートが待ち遠しいですね!

まだまだCopilotKit自体の理解が浅いので、色々触って発信したいと思います🙇

余談ですが、CopilotKitのQuickStartのドキュメントにミスがあったため修正しました!

https://github.com/CopilotKit/CopilotKit/pull/2801

参考資料

https://docs.copilotkit.ai/aws-strands

https://strandsagents.com/latest/documentation/docs/community/integrations/ag-ui/

https://dev.classmethod.jp/articles/amazon-bedrock-agentcore-runtime-api-gateway-lambda-streaming-response/

https://dev.classmethod.jp/articles/shuntaka-cdk-hono-lambda-web-adapter-apigateway-15/

この記事をシェアする

FacebookHatena blogX