TypeScript Strands エージェント
TypeScript Strands Agent を生成し、ツールを使用したAIエージェントを構築します。オプションで Amazon Bedrock AgentCore Runtime にデプロイできます。このジェネレーターは、WebSocket 上の tRPC を使用して、AgentCore の双方向ストリーミングサポートを活用し、リアルタイムで型安全な通信を実現します。
Strands とは?
Section titled “Strands とは?”Strands は、AIエージェントを構築するための軽量なフレームワークです。主な機能は次のとおりです:
- 軽量でカスタマイズ可能: シンプルなエージェントループで邪魔にならない
- 本番環境対応: 完全な可観測性、トレーシング、スケールのためのデプロイオプション
- モデルとプロバイダーに依存しない: さまざまなプロバイダーの多くの異なるモデルをサポート
- コミュニティ主導のツール: コミュニティが提供する強力なツールセット
- マルチエージェントサポート: エージェントチームや自律エージェントなどの高度な技術
- 柔軟な対話モード: 会話、ストリーミング、非ストリーミングサポート
Strands Agent の生成
Section titled “Strands Agent の生成”TypeScript Strands Agent は2つの方法で生成できます:
- インストール Nx Console VSCode Plugin まだインストールしていない場合
- VSCodeでNxコンソールを開く
- クリック
Generate (UI)"Common Nx Commands"セクションで - 検索
@aws/nx-plugin - ts#strands-agent - 必須パラメータを入力
- クリック
Generate
pnpm nx g @aws/nx-plugin:ts#strands-agentyarn nx g @aws/nx-plugin:ts#strands-agentnpx nx g @aws/nx-plugin:ts#strands-agentbunx nx g @aws/nx-plugin:ts#strands-agent変更されるファイルを確認するためにドライランを実行することもできます
pnpm nx g @aws/nx-plugin:ts#strands-agent --dry-runyarn nx g @aws/nx-plugin:ts#strands-agent --dry-runnpx nx g @aws/nx-plugin:ts#strands-agent --dry-runbunx nx g @aws/nx-plugin:ts#strands-agent --dry-run| パラメータ | 型 | デフォルト | 説明 |
|---|---|---|---|
| project 必須 | string | - | The project to add the Strands Agent to |
| computeType | string | BedrockAgentCoreRuntime | The type of compute to host your Strands Agent. |
| name | string | - | The name of your Strands Agent (default: agent) |
| iacProvider | string | Inherit | The preferred IaC provider. By default this is inherited from your initial selection. |
ジェネレーター出力
Section titled “ジェネレーター出力”ジェネレーターは、既存の TypeScript プロジェクトに次のファイルを追加します:
Directoryyour-project/
Directorysrc/
Directoryagent/ (指定した場合はカスタム名)
- index.ts Bedrock AgentCore Runtime のエントリーポイント
- init.ts tRPC の初期化
- router.ts エージェントプロシージャを含む tRPC ルーター
- agent.ts サンプルツールを含むメインエージェント定義
- client.ts エージェントを呼び出すための提供されたクライアント
- agent-core-trpc-client.ts AgentCore Runtime 上のエージェントに接続するためのクライアントファクトリー
- agent-core-mcp-client.ts AgentCore Runtime 上の MCP サーバーに接続するためのクライアントファクトリー
- Dockerfile エージェントをホストするためのエントリーポイント (
computeTypeがNoneに設定されている場合は除外)
- package.json Strands 依存関係で更新
- project.json エージェント serve ターゲットで更新
インフラストラクチャ
Section titled “インフラストラクチャ”このジェネレータは選択した iacProvider に基づいてInfrastructure as Codeを生成するため、packages/common に関連するCDKコンストラクトまたはTerraformモジュールを含むプロジェクトを作成します。
共通のInfrastructure as Codeプロジェクトは以下の構造を持ちます:
Directorypackages/common/constructs
Directorysrc
Directoryapp/ プロジェクト/ジェネレータ固有のインフラストラクチャ用コンストラクト
- …
Directorycore/
app内のコンストラクトで再利用される汎用コンストラクト- …
- index.ts
appからコンストラクトをエクスポートするエントリーポイント
- project.json プロジェクトのビルドターゲットと設定
Directorypackages/common/terraform
Directorysrc
Directoryapp/ プロジェクト/ジェネレータ固有のインフラストラクチャ用Terraformモジュール
- …
Directorycore/
app内のモジュールで再利用される汎用モジュール- …
- project.json プロジェクトのビルドターゲットと設定
Strands Agent をデプロイするために、次のファイルが生成されます:
Directorypackages/common/constructs/src
Directoryapp
Directoryagents
Directory<project-name>
- <project-name>.ts エージェントをデプロイするための CDK コンストラクト
- Dockerfile CDK コンストラクトで使用されるパススルー docker ファイル
Directorypackages/common/terraform/src
Directoryapp
Directoryagents
Directory<project-name>
- <project-name>.tf エージェントをデプロイするためのモジュール
Directorycore
Directoryagent-core
- runtime.tf Bedrock AgentCore Runtime にデプロイするための汎用モジュール
Strands Agent の操作
Section titled “Strands Agent の操作”WebSocket 上の tRPC
Section titled “WebSocket 上の tRPC”TypeScript Strands Agent は、WebSocket 上の tRPC を使用し、AgentCore の双方向ストリーミングサポートを活用して、クライアントとエージェント間のリアルタイムで型安全な通信を実現します。
tRPC は WebSocket 上で Query、Mutation、Subscription プロシージャをサポートしているため、任意の数のプロシージャを定義できます。デフォルトでは、router.ts に invoke という名前の単一のサブスクリプションプロシージャが定義されています。
ツールの追加
Section titled “ツールの追加”ツールは、AIエージェントがアクションを実行するために呼び出すことができる関数です。agent.ts ファイルに新しいツールを追加できます:
import { Agent, tool } from '@strands-agents/sdk';import z from 'zod';
const letterCounter = tool({ name: 'letter_counter', description: 'Count occurrences of a specific letter in a word', inputSchema: z.object({ word: z.string().describe('The input word to search in'), letter: z.string().length(1).describe('The specific letter to count'), }), callback: (input) => { const { word, letter } = input; const count = word.toLowerCase().split(letter.toLowerCase()).length - 1; return `The letter '${letter}' appears ${count} time(s) in '${word}'`; },});
// エージェントにツールを追加export const agent = new Agent({ systemPrompt: 'You are a helpful assistant with access to various tools.', tools: [letterCounter],});Strands フレームワークは次を自動的に処理します:
- Zod スキーマを使用した入力検証
- ツール呼び出しのための JSON スキーマ生成
- エラー処理とレスポンスのフォーマット
デフォルトでは、Strands エージェントは Claude 4 Sonnet を使用しますが、モデルプロバイダー間を簡単に切り替えることができます:
import { Agent } from '@strands-agents/sdk';import { BedrockModel } from '@strands-agents/sdk/models/bedrock';import { OpenAIModel } from '@strands-agents/sdk/models/openai';
// Bedrock を使用const bedrockModel = new BedrockModel({ modelId: 'anthropic.claude-sonnet-4-20250514-v1:0',});let agent = new Agent({ model: bedrockModel });let response = await agent.invoke('What can you help me with?');
// または、モデルプロバイダーを切り替えるだけで OpenAI を使用const openaiModel = new OpenAIModel({ apiKey: process.env.OPENAI_API_KEY, modelId: 'gpt-4o',});agent = new Agent({ model: openaiModel });response = await agent.invoke('What can you help me with?');詳細な設定オプションについては、モデルプロバイダーに関する Strands ドキュメントを参照してください。
MCP サーバーの使用
Section titled “MCP サーバーの使用”Strands エージェントに MCP サーバーからツールを追加できます。
py#mcp-server または ts#mcp-server ジェネレーターを使用して作成した MCP サーバー (または Bedrock AgentCore Runtime でホストされている他のサーバー) を使用する場合、agent-core-mcp-client.ts にクライアントファクトリーが生成されます。
agent.ts でエージェントの初期化を更新して、MCP クライアントを作成してツールを追加できます。次の例は、IAM (SigV4) 認証でこれを実行する方法を示しています:
import { Agent } from '@strands-agents/sdk';import { AgentCoreMcpClient } from './agent-core-mcp-client.js';
const mcpClient = AgentCoreMcpClient.withIamAuth({ agentRuntimeArn: process.env.MCP_AGENTCORE_RUNTIME_ARN!, region: process.env.AWS_REGION || 'us-west-2', sessionId: 'my-session-id',});
export const agent = new Agent({ systemPrompt: '...', tools: [mcpClient],});上記の IAM 認証の例では、インフラストラクチャで2つのことを設定する必要があります。まず、MCP サーバーの AgentCore Runtime ARN に対してエージェントが使用している環境変数を追加する必要があり、次にエージェントに MCP サーバーを呼び出す権限を付与する必要があります。これは次のように実現できます:
import { MyProjectAgent, MyProjectMcpServer } from ':my-scope/common-constructs';
export class ExampleStack extends Stack { constructor(scope: Construct, id: string) { const mcpServer = new MyProjectMcpServer(this, 'MyProjectMcpServer');
const agent = new MyProjectAgent(this, 'MyProjectAgent', { environmentVariables: { MCP_AGENTCORE_RUNTIME_ARN: mcpServer.agentCoreRuntime.agentRuntimeArn, }, });
mcpServer.agentCoreRuntime.grantInvoke(agent.agentCoreRuntime); }}# MCP Servermodule "my_project_mcp_server" { source = "../../common/terraform/src/app/mcp-servers/my-project-mcp-server"}
# Agentmodule "my_project_agent" { source = "../../common/terraform/src/app/agents/my-project-agent"
env = { MCP_AGENTCORE_RUNTIME_ARN = module.my_project_mcp_server.agent_core_runtime_arn }
additional_iam_policy_statements = [ { Effect = "Allow" Action = [ "bedrock-agentcore:InvokeAgentRuntime" ] Resource = [ module.my_project_mcp_server.agent_core_runtime_arn, "${module.my_project_mcp_server.agent_core_runtime_arn}/*" ] } ]}Strands エージェントの作成に関する詳細なガイドについては、Strands ドキュメントを参照してください。
Strands Agent の実行
Section titled “Strands Agent の実行”ローカル開発
Section titled “ローカル開発”ジェネレーターは <your-agent-name>-serve という名前のターゲットを設定し、開発とテストのために Strands Agent をローカルで起動します。
pnpm nx run your-project:agent-serveyarn nx run your-project:agent-servenpx nx run your-project:agent-servebunx nx run your-project:agent-serveこのコマンドは tsx --watch を使用して、ファイルが変更されたときにサーバーを自動的に再起動します。エージェントは http://localhost:8081 (または複数のエージェントがある場合は割り当てられたポート) で利用可能になります。
Strands Agent を Bedrock AgentCore Runtime にデプロイ
Section titled “Strands Agent を Bedrock AgentCore Runtime にデプロイ”Infrastructure as Code
Section titled “Infrastructure as Code”computeTypeにBedrockAgentCoreRuntimeを選択した場合、関連するCDKまたはTerraformインフラストラクチャが生成され、Strands AgentをAmazon Bedrock AgentCore Runtimeにデプロイするために使用できます。
エージェント用のCDKコンストラクトが生成されます。名前はジェネレーター実行時に選択したnameに基づくか、デフォルトでは<ProjectName>Agentになります。
このCDKコンストラクトをCDKアプリケーションで使用できます:
import { MyProjectAgent } from ':my-scope/common-constructs';
export class ExampleStack extends Stack { constructor(scope: Construct, id: string) { // Add the agent to your stack const agent = new MyProjectAgent(this, 'MyProjectAgent');
// Grant permissions to invoke the relevant models in bedrock agent.agentCoreRuntime.addToRolePolicy( new PolicyStatement({ actions: [ 'bedrock:InvokeModel', 'bedrock:InvokeModelWithResponseStream', ], // You can scope the below down to the specific models you use resources: [ 'arn:aws:bedrock:*:*:foundation-model/*', 'arn:aws:bedrock:*:*:inference-profile/*', ], }), ); }}Terraformモジュールが生成されます。名前はジェネレーター実行時に選択したnameに基づくか、デフォルトでは<ProjectName>-agentになります。
このTerraformモジュールをTerraformプロジェクトで使用できます:
# Agentmodule "my_project_agent" { # Relative path to the generated module in the common/terraform project source = "../../common/terraform/src/app/agents/my-project-agent"
# Grant permissions to invoke the relevant models in bedrock additional_iam_policy_statements = [ { Effect = "Allow" Action = [ "bedrock:InvokeModel", "bedrock:InvokeModelWithResponseStream" ] # You can scope the below down to the specific models you use Resource = [ "arn:aws:bedrock:*:*:foundation-model/*", "arn:aws:bedrock:*:*:inference-profile/*" ] } ]}デフォルトでは、Strands AgentはIAM認証を使用して保護されます。引数なしで単純にデプロイしてください:
import { MyProjectAgent } from ':my-scope/common-constructs';
export class ExampleStack extends Stack { constructor(scope: Construct, id: string) { new MyProjectAgent(this, 'MyProjectAgent'); }}grantInvokeメソッドを使用して、Bedrock AgentCore Runtime上でエージェントを呼び出すアクセス権を付与できます。例:
import { MyProjectAgent } from ':my-scope/common-constructs';
export class ExampleStack extends Stack { constructor(scope: Construct, id: string) { const agent = new MyProjectAgent(this, 'MyProjectAgent'); const lambdaFunction = new Function(this, ...);
agent.agentCoreRuntime.grantInvoke(lambdaFunction); }}# Agentmodule "my_project_agent" { # Relative path to the generated module in the common/terraform project source = "../../common/terraform/src/app/agents/my-project-agent"}エージェントを呼び出すアクセス権を付与するには、module.my_project_agent.agent_core_runtime_arn出力を参照して、次のようなポリシーを追加する必要があります:
{ Effect = "Allow" Action = [ "bedrock-agentcore:InvokeAgentRuntime" ] Resource = [ module.my_project_agent.agent_core_runtime_arn, "${module.my_project_agent.agent_core_runtime_arn}/*" ]}Cognito JWT認証
Section titled “Cognito JWT認証”以下は、エージェントのCognito認証を設定する方法を示しています。
Cognitoを使用してJWT認証を設定するには、RuntimeAuthorizerConfiguration.usingCognito()ファクトリメソッドを使用します:
import { MyProjectAgent } from ':my-scope/common-constructs';import { RuntimeAuthorizerConfiguration } from '@aws-cdk/aws-bedrock-agentcore-alpha';
export class ExampleStack extends Stack { constructor(scope: Construct, id: string) { const userPool = new UserPool(this, 'UserPool'); const client = userPool.addClient('Client', { authFlows: { userPassword: true, }, });
new MyProjectAgent(this, 'MyProjectAgent', { authorizerConfiguration: RuntimeAuthorizerConfiguration.usingCognito( userPool, [client], ), }); }}または、独自のOIDCプロバイダーを使用したカスタムJWT認証の場合は、RuntimeAuthorizerConfiguration.usingJWT()を使用します:
import { MyProjectAgent } from ':my-scope/common-constructs';import { RuntimeAuthorizerConfiguration } from '@aws-cdk/aws-bedrock-agentcore-alpha';
export class ExampleStack extends Stack { constructor(scope: Construct, id: string) { new MyProjectAgent(this, 'MyProjectAgent', { authorizerConfiguration: RuntimeAuthorizerConfiguration.usingJWT( 'https://example.com/.well-known/openid-configuration', ['client1', 'client2'], // Allowed Client IDs (optional) ['audience1'], // Allowed Audiences (optional) ), }); }}JWT認証を設定するには、エージェントモジュールを編集して、次のようにauthorizer_configuration変数を設定します:
data "aws_region" "current" {}
locals { aws_region = data.aws_region.current.id
# Replace with your user pool and client ids or expose as variables user_pool_id = "xxx" user_pool_client_ids = ["yyy"]}
module "agent_core_runtime" { source = "../../../core/agent-core" agent_runtime_name = "MyProjectAgent" docker_image_tag = "my-scope-my-project-agent:latest" server_protocol = "HTTP" authorizer_configuration = { custom_jwt_authorizer = { discovery_url = "https://cognito-idp.${local.aws_region}.amazonaws.com/${local.user_pool_id}/.well-known/openid-configuration" allowed_clients = local.user_pool_client_ids } } env = var.env additional_iam_policy_statements = var.additional_iam_policy_statements tags = var.tags}Bundle ターゲット
Section titled “Bundle ターゲット”ジェネレーターは自動的に Rolldown を使用する bundle ターゲットを設定します。このターゲットはデプロイメントパッケージの作成に使用されます:
pnpm nx run <project-name>:bundleyarn nx run <project-name>:bundlenpx nx run <project-name>:bundlebunx nx run <project-name>:bundleRolldownの設定はrolldown.config.tsに記述され、生成するバンドルごとにエントリを定義します。Rolldownは定義された複数のバンドルを並行して作成する処理を管理します。
bundle ターゲットは、Bedrock AgentCore Runtime でホストする WebSocket サーバーのエントリーポイントとして index.ts を使用します。
Docker ターゲット
Section titled “Docker ターゲット”ジェネレーターは <your-agent-name>-docker ターゲットを設定し、AgentCore ランタイムコントラクトに従ってポート 8080 でバンドルされた WebSocket サーバーを実行します。
複数のエージェントが定義されている場合、すべてのエージェントに対して docker ビルドを実行する docker ターゲットも生成されます。
エージェントは、Dockerfile で自動計装を設定することにより、AWS Distro for Open Telemetry (ADOT) を使用した可観測性で自動的に構成されます。
CloudWatch AWS コンソールでトレースを見つけるには、メニューで “GenAI Observability” を選択します。トレースを入力するには、Transaction Search を有効にする必要があることに注意してください。
詳細については、可観測性に関する AgentCore ドキュメントを参照してください。
Strands Agent の呼び出し
Section titled “Strands Agent の呼び出し”エージェント通信は、WebSocket 上の tRPC を介して送信されます。そのため、client.ts で生成された型安全なクライアントファクトリーを使用することをお勧めします。
ローカルサーバーの呼び出し
Section titled “ローカルサーバーの呼び出し”クライアントファクトリーの .local ファクトリーメソッドを使用して、ローカルで実行されているエージェントを呼び出すことができます。
たとえば、ワークスペースに scripts/test.ts という名前のファイルを作成し、クライアントをインポートできます:
import { AgentClient } from '../packages/<project>/src/agent/client.js';
const client = AgentClient.local({ url: 'http://localhost:8081/ws' });
client.invoke.subscribe({ message: 'what is 1 plus 1?' }, { onData: console.log });デプロイされたエージェントの呼び出し
Section titled “デプロイされたエージェントの呼び出し”Bedrock AgentCore Runtimeにデプロイされたエージェントを呼び出すには、URLエンコードされたランタイムARNを使用して、Bedrock AgentCore RuntimeデータプレーンエンドポイントにPOSTリクエストを送信します。
ランタイムARNは、以下のようにインフラストラクチャから取得できます:
import { CfnOutput } from 'aws-cdk-lib';import { MyProjectAgent } from ':my-scope/common-constructs';
export class ExampleStack extends Stack { constructor(scope: Construct, id: string) { const agent = new MyProjectAgent(this, 'MyProjectAgent');
new CfnOutput(this, 'AgentArn', { value: agent.agentCoreRuntime.agentRuntimeArn, }); }}# Agentmodule "my_project_agent" { # Relative path to the generated module in the common/terraform project source = "../../common/terraform/src/app/agents/my-project-agent"}
output "agent_arn" { value = module.my_project_agent.agent_core_runtime_arn}ARNは次の形式になります: arn:aws:bedrock-agentcore:<region>:<account>:runtime/<agent-runtime-id>
次に、:を%3Aに、/を%2Fに置き換えることで、ARNをURLエンコードできます。
エージェントを呼び出すためのBedrock AgentCore RuntimeデータプレーンURLは次のとおりです:
https://bedrock-agentcore.<region>.amazonaws.com/runtimes/<url-encoded-arn>/invocationsこのURLを呼び出す正確な方法は、使用する認証方法によって異なります。
NodeJS
Section titled “NodeJS”生成された client.ts ファイルには、デプロイされたエージェントを呼び出すために使用できる型安全なクライアントファクトリーが含まれています。
IAM 認証
Section titled “IAM 認証”withIamAuth ファクトリーメソッドに ARN を渡すことで、デプロイされたエージェントを呼び出すことができます:
import { AgentClient } from './agent/client.js';
const client = AgentClient.withIamAuth({ agentRuntimeArn: 'arn:aws:bedrock-agentcore:us-west-2:123456789012:runtime/my-agent',});
client.invoke.subscribe({ message: 'what is 1 plus 1?' }, { onData: (message) => console.log(message), onError: (error) => console.error(error), onComplete: () => console.log('Done'),});JWT / Cognito 認証
Section titled “JWT / Cognito 認証”JWT / Cognito アクセストークンで認証するには、withJwtAuth ファクトリーメソッドを使用します。
const client = AgentClient.withJwtAuth({ agentRuntimeArn: 'arn:aws:bedrock-agentcore:us-west-2:123456789012:runtime/my-agent', accessTokenProvider: async () => `<access-token>`,});
client.invoke.subscribe({ message: 'what is 1 plus 1?' }, { onData: console.log,});accessTokenProvider は、リクエストの認証に使用されるトークンを返す必要があります。たとえば、tRPC が WebSocket 接続を再起動するときに新しい認証情報が再利用されるように、このメソッド内でトークンを取得できます。以下は、AWS SDK を使用して Cognito からトークンを取得する方法を示しています:
import { CognitoIdentityProvider } from "@aws-sdk/client-cognito-identity-provider";
const cognito = new CognitoIdentityProvider();
const jwtClient = AgentClient.withJwtAuth({ agentRuntimeArn: 'arn:aws:bedrock-agentcore:us-west-2:123456789012:runtime/my-agent', accessTokenProvider: async () => { const response = await cognito.adminInitiateAuth({ UserPoolId: '<user-pool-id>', ClientId: '<user-pool-client-id>', AuthFlow: 'ADMIN_NO_SRP_AUTH', AuthParameters: { USERNAME: '<username>', PASSWORD: '<password>', }, }); return response.AuthenticationResult!.AccessToken!; },});Browser
Section titled “Browser”ブラウザの WebSocket は (Sec-WebSocket-Protocol 以外の) ヘッダーの指定をサポートしていないため、client.ts で生成されたクライアントファクトリーはブラウザでは使用できません (実際には、NodeJS のように WebSocket コンストラクターがヘッダーを受け入れないため、コンパイルエラーが発生します)。
JWT / Cognito 認証
Section titled “JWT / Cognito 認証”IAM 認証
Section titled “IAM 認証”ブラウザからエージェントを呼び出すには、AWS SigV4 を使用して事前署名された WebSocket URL を作成する必要があります。
以下の例は、認証情報の取得、事前署名された URL の作成、エージェントの呼び出しのエンドツーエンドフローを示しています:
import { createTRPCClient, createWSClient, wsLink } from '@trpc/client';import { AwsClient } from 'aws4fetch';import { CognitoIdentityClient } from '@aws-sdk/client-cognito-identity';import { fromCognitoIdentityPool } from '@aws-sdk/credential-provider-cognito-identity';import type { AppRouter } from './your-agent/router';
// 事前署名された WebSocket URL を構築async function buildSignedUrl( agentRuntimeArn: string, idToken: string, region: string = 'us-west-2'): Promise<string> { // Cognito Identity Pool (または他のソース) から認証情報を取得 const credentials = fromCognitoIdentityPool({ client: new CognitoIdentityClient({ region }), identityPoolId: 'us-west-2:xxxxx', logins: { [`cognito-idp.${region}.amazonaws.com/us-west-2_xxxxx`]: idToken, }, });
const cognitoIdentity = new CognitoIdentityClient({ credentials }); const credential = await cognitoIdentity.config.credentials();
// AWS SigV4 クライアントを作成 const awsClient = new AwsClient({ ...credential, service: 'bedrock-agentcore', });
// ARN から WebSocket URL を構築 const wsUrl = `wss://bedrock-agentcore.${region}.amazonaws.com/runtimes/${agentRuntimeArn.replace(/:/g, '%3A').replace(/\//g, '%2F')}/ws`;
// 事前署名された URL を作成 const signedRequest = await awsClient.sign(wsUrl, { method: 'GET', aws: { signQuery: true }, });
return signedRequest.url;}
// 事前署名された WebSocket URL で tRPC クライアントを作成const agentRuntimeArn = 'arn:aws:bedrock-agentcore:us-west-2:123456789012:runtime/my-agent';const idToken = '<your-id-token>';
const wsClient = createWSClient({ url: async () => buildSignedUrl(agentRuntimeArn, idToken),});
const trpcClient = createTRPCClient<AppRouter>({ links: [wsLink({ client: wsClient })],});
// エージェントを呼び出すtrpcClient.invoke.subscribe({ message: 'what is 1 plus 1?' }, { onData: (message) => console.log(message),});