mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
feat(block): Add cloudwatch publish operation (#4027)
* feat(block): Add cloudwatch publish operation * fix(integrations): validate and fix cloudwatch, cloudformation, athena conventions - Update tool version strings from '1.0' to '1.0.0' across all three integrations - Add missing `export * from './types'` barrel re-exports (cloudwatch, cloudformation) - Add docsLink, wandConfig timestamps, mode: 'advanced' on optional fields (cloudwatch) - Add dropdown defaults, ZodError handling, docs intro section (cloudwatch) - Add mode: 'advanced' on limit field (cloudformation) - Alphabetize registry entries (cloudwatch, cloudformation) - Fix athena docs maxResults range (1-999) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(cloudwatch): complete put_metric_data unit dropdown, add missing outputs, fix JSON error handling - Add all 27 valid CloudWatch StandardUnit values to metricUnit dropdown (was 13) - Add missing block outputs for put_metric_data: success, namespace, metricName, value, unit - Add try-catch around dimensions JSON.parse in put-metric-data route for proper 400 errors Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(cloudwatch): fix DescribeAlarms returning only MetricAlarm when "All Types" selected Per AWS docs, omitting AlarmTypes returns only MetricAlarm. Now explicitly sends both MetricAlarm and CompositeAlarm when no filter is selected. Also fix dimensions JSON parse errors returning 500 instead of 400 in get-metric-statistics route. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(cloudwatch): validate dimensions JSON at Zod schema level Move dimensions validation from runtime try-catch to Zod refinement, catching malformed JSON and arrays at schema validation time (400) instead of runtime (500). Also rejects JSON arrays that would produce meaningless numeric dimension names. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(cloudwatch): reject non-numeric metricValue instead of silently publishing 0 Add NaN guard in block config and .finite() refinement in Zod schema so "abc" → NaN is caught at both layers instead of coercing to 0. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(cloudwatch): use Number.isFinite to also reject Infinity in block config Aligns block-level validation with route's Zod .finite() refinement so Infinity/-Infinity are caught at the block config layer, not just the API. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Theodore Li <teddy@zenobiapay.com> Co-authored-by: Waleed Latif <walif6@gmail.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
Theodore Li
Waleed Latif
parent
a8468a6056
commit
139213ef45
@@ -113,7 +113,7 @@ Retrieve the results of a completed Athena query execution
|
||||
| `awsAccessKeyId` | string | Yes | AWS access key ID |
|
||||
| `awsSecretAccessKey` | string | Yes | AWS secret access key |
|
||||
| `queryExecutionId` | string | Yes | Query execution ID to get results for |
|
||||
| `maxResults` | number | No | Maximum number of rows to return \(1-1000\) |
|
||||
| `maxResults` | number | No | Maximum number of rows to return \(1-999\) |
|
||||
| `nextToken` | string | No | Pagination token from a previous request |
|
||||
|
||||
#### Output
|
||||
|
||||
@@ -10,6 +10,24 @@ import { BlockInfoCard } from "@/components/ui/block-info-card"
|
||||
color="linear-gradient(45deg, #B0084D 0%, #FF4F8B 100%)"
|
||||
/>
|
||||
|
||||
{/* MANUAL-CONTENT-START:intro */}
|
||||
[AWS CloudWatch](https://aws.amazon.com/cloudwatch/) is a monitoring and observability service that provides data and actionable insights for AWS resources, applications, and services. CloudWatch collects monitoring and operational data in the form of logs, metrics, and events, giving you a unified view of your AWS environment.
|
||||
|
||||
With the CloudWatch integration, you can:
|
||||
|
||||
- **Query Logs (Insights)**: Run CloudWatch Log Insights queries against one or more log groups to analyze log data with a powerful query language
|
||||
- **Describe Log Groups**: List available CloudWatch log groups in your account, optionally filtered by name prefix
|
||||
- **Get Log Events**: Retrieve log events from a specific log stream within a log group
|
||||
- **Describe Log Streams**: List log streams within a log group, ordered by last event time or filtered by name prefix
|
||||
- **List Metrics**: Browse available CloudWatch metrics, optionally filtered by namespace, metric name, or recent activity
|
||||
- **Get Metric Statistics**: Retrieve statistical data for a metric over a specified time range with configurable granularity
|
||||
- **Publish Metric**: Publish custom metric data points to CloudWatch for your own application monitoring
|
||||
- **Describe Alarms**: List and filter CloudWatch alarms by name prefix, state, or alarm type
|
||||
|
||||
In Sim, the CloudWatch integration enables your agents to monitor AWS infrastructure, analyze application logs, track custom metrics, and respond to alarm states as part of automated DevOps and SRE workflows. This is especially powerful when combined with other AWS integrations like CloudFormation and SNS for end-to-end infrastructure management.
|
||||
{/* MANUAL-CONTENT-END */}
|
||||
|
||||
|
||||
## Usage Instructions
|
||||
|
||||
Integrate AWS CloudWatch into workflows. Run Log Insights queries, list log groups, retrieve log events, list and get metrics, and monitor alarms. Requires AWS access key and secret access key.
|
||||
@@ -155,6 +173,34 @@ Get statistics for a CloudWatch metric over a time range
|
||||
| `label` | string | Metric label |
|
||||
| `datapoints` | array | Datapoints with timestamp and statistics values |
|
||||
|
||||
### `cloudwatch_put_metric_data`
|
||||
|
||||
Publish a custom metric data point to CloudWatch
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `awsRegion` | string | Yes | AWS region \(e.g., us-east-1\) |
|
||||
| `awsAccessKeyId` | string | Yes | AWS access key ID |
|
||||
| `awsSecretAccessKey` | string | Yes | AWS secret access key |
|
||||
| `namespace` | string | Yes | Metric namespace \(e.g., Custom/MyApp\) |
|
||||
| `metricName` | string | Yes | Name of the metric |
|
||||
| `value` | number | Yes | Metric value to publish |
|
||||
| `unit` | string | No | Unit of the metric \(e.g., Count, Seconds, Bytes\) |
|
||||
| `dimensions` | string | No | JSON string of dimension name/value pairs |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `success` | boolean | Whether the metric was published successfully |
|
||||
| `namespace` | string | Metric namespace |
|
||||
| `metricName` | string | Metric name |
|
||||
| `value` | number | Published metric value |
|
||||
| `unit` | string | Metric unit |
|
||||
| `timestamp` | string | Timestamp when the metric was published |
|
||||
|
||||
### `cloudwatch_describe_alarms`
|
||||
|
||||
List and filter CloudWatch alarms
|
||||
|
||||
@@ -2044,12 +2044,16 @@
|
||||
"name": "Get Metric Statistics",
|
||||
"description": "Get statistics for a CloudWatch metric over a time range"
|
||||
},
|
||||
{
|
||||
"name": "Publish Metric",
|
||||
"description": "Publish a custom metric data point to CloudWatch"
|
||||
},
|
||||
{
|
||||
"name": "Describe Alarms",
|
||||
"description": "List and filter CloudWatch alarms"
|
||||
}
|
||||
],
|
||||
"operationCount": 7,
|
||||
"operationCount": 8,
|
||||
"triggers": [],
|
||||
"triggerCount": 0,
|
||||
"authType": "none",
|
||||
|
||||
@@ -51,7 +51,9 @@ export async function POST(request: NextRequest) {
|
||||
const command = new DescribeAlarmsCommand({
|
||||
...(validatedData.alarmNamePrefix && { AlarmNamePrefix: validatedData.alarmNamePrefix }),
|
||||
...(validatedData.stateValue && { StateValue: validatedData.stateValue as StateValue }),
|
||||
...(validatedData.alarmType && { AlarmTypes: [validatedData.alarmType as AlarmType] }),
|
||||
AlarmTypes: validatedData.alarmType
|
||||
? [validatedData.alarmType as AlarmType]
|
||||
: (['MetricAlarm', 'CompositeAlarm'] as AlarmType[]),
|
||||
...(validatedData.limit !== undefined && { MaxRecords: validatedData.limit }),
|
||||
})
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ export async function POST(request: NextRequest) {
|
||||
}))
|
||||
}
|
||||
} catch {
|
||||
throw new Error('Invalid dimensions JSON')
|
||||
return NextResponse.json({ error: 'Invalid dimensions JSON format' }, { status: 400 })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
import {
|
||||
CloudWatchClient,
|
||||
PutMetricDataCommand,
|
||||
type StandardUnit,
|
||||
} from '@aws-sdk/client-cloudwatch'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
import { checkInternalAuth } from '@/lib/auth/hybrid'
|
||||
|
||||
const logger = createLogger('CloudWatchPutMetricData')
|
||||
|
||||
const VALID_UNITS = [
|
||||
'Seconds',
|
||||
'Microseconds',
|
||||
'Milliseconds',
|
||||
'Bytes',
|
||||
'Kilobytes',
|
||||
'Megabytes',
|
||||
'Gigabytes',
|
||||
'Terabytes',
|
||||
'Bits',
|
||||
'Kilobits',
|
||||
'Megabits',
|
||||
'Gigabits',
|
||||
'Terabits',
|
||||
'Percent',
|
||||
'Count',
|
||||
'Bytes/Second',
|
||||
'Kilobytes/Second',
|
||||
'Megabytes/Second',
|
||||
'Gigabytes/Second',
|
||||
'Terabytes/Second',
|
||||
'Bits/Second',
|
||||
'Kilobits/Second',
|
||||
'Megabits/Second',
|
||||
'Gigabits/Second',
|
||||
'Terabits/Second',
|
||||
'Count/Second',
|
||||
'None',
|
||||
] as const
|
||||
|
||||
const PutMetricDataSchema = z.object({
|
||||
region: z.string().min(1, 'AWS region is required'),
|
||||
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
|
||||
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
|
||||
namespace: z.string().min(1, 'Namespace is required'),
|
||||
metricName: z.string().min(1, 'Metric name is required'),
|
||||
value: z.number({ coerce: true }).refine((v) => Number.isFinite(v), {
|
||||
message: 'Metric value must be a finite number',
|
||||
}),
|
||||
unit: z.enum(VALID_UNITS).optional(),
|
||||
dimensions: z
|
||||
.string()
|
||||
.optional()
|
||||
.refine(
|
||||
(val) => {
|
||||
if (!val) return true
|
||||
try {
|
||||
const parsed = JSON.parse(val)
|
||||
return typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
},
|
||||
{ message: 'dimensions must be a valid JSON object string' }
|
||||
),
|
||||
})
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const auth = await checkInternalAuth(request)
|
||||
if (!auth.success || !auth.userId) {
|
||||
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
|
||||
}
|
||||
|
||||
const body = await request.json()
|
||||
const validatedData = PutMetricDataSchema.parse(body)
|
||||
|
||||
const client = new CloudWatchClient({
|
||||
region: validatedData.region,
|
||||
credentials: {
|
||||
accessKeyId: validatedData.accessKeyId,
|
||||
secretAccessKey: validatedData.secretAccessKey,
|
||||
},
|
||||
})
|
||||
|
||||
const timestamp = new Date()
|
||||
|
||||
const dimensions: { Name: string; Value: string }[] = []
|
||||
if (validatedData.dimensions) {
|
||||
const parsed = JSON.parse(validatedData.dimensions)
|
||||
for (const [name, value] of Object.entries(parsed)) {
|
||||
dimensions.push({ Name: name, Value: String(value) })
|
||||
}
|
||||
}
|
||||
|
||||
const command = new PutMetricDataCommand({
|
||||
Namespace: validatedData.namespace,
|
||||
MetricData: [
|
||||
{
|
||||
MetricName: validatedData.metricName,
|
||||
Value: validatedData.value,
|
||||
Timestamp: timestamp,
|
||||
...(validatedData.unit && { Unit: validatedData.unit as StandardUnit }),
|
||||
...(dimensions.length > 0 && { Dimensions: dimensions }),
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
await client.send(command)
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
output: {
|
||||
success: true,
|
||||
namespace: validatedData.namespace,
|
||||
metricName: validatedData.metricName,
|
||||
value: validatedData.value,
|
||||
unit: validatedData.unit ?? 'None',
|
||||
timestamp: timestamp.toISOString(),
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
if (error instanceof z.ZodError) {
|
||||
return NextResponse.json(
|
||||
{ error: error.errors[0]?.message ?? 'Invalid request' },
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : 'Failed to publish CloudWatch metric'
|
||||
logger.error('PutMetricData failed', { error: errorMessage })
|
||||
return NextResponse.json({ error: errorMessage }, { status: 500 })
|
||||
}
|
||||
}
|
||||
@@ -117,6 +117,7 @@ export const CloudFormationBlock: BlockConfig<
|
||||
type: 'short-input',
|
||||
placeholder: '50',
|
||||
condition: { field: 'operation', value: 'describe_stack_events' },
|
||||
mode: 'advanced',
|
||||
},
|
||||
],
|
||||
tools: {
|
||||
|
||||
@@ -8,6 +8,7 @@ import type {
|
||||
CloudWatchGetLogEventsResponse,
|
||||
CloudWatchGetMetricStatisticsResponse,
|
||||
CloudWatchListMetricsResponse,
|
||||
CloudWatchPutMetricDataResponse,
|
||||
CloudWatchQueryLogsResponse,
|
||||
} from '@/tools/cloudwatch/types'
|
||||
|
||||
@@ -19,6 +20,7 @@ export const CloudWatchBlock: BlockConfig<
|
||||
| CloudWatchDescribeAlarmsResponse
|
||||
| CloudWatchListMetricsResponse
|
||||
| CloudWatchGetMetricStatisticsResponse
|
||||
| CloudWatchPutMetricDataResponse
|
||||
> = {
|
||||
type: 'cloudwatch',
|
||||
name: 'CloudWatch',
|
||||
@@ -27,6 +29,7 @@ export const CloudWatchBlock: BlockConfig<
|
||||
'Integrate AWS CloudWatch into workflows. Run Log Insights queries, list log groups, retrieve log events, list and get metrics, and monitor alarms. Requires AWS access key and secret access key.',
|
||||
category: 'tools',
|
||||
integrationType: IntegrationType.Analytics,
|
||||
docsLink: 'https://docs.sim.ai/tools/cloudwatch',
|
||||
tags: ['cloud', 'monitoring'],
|
||||
bgColor: 'linear-gradient(45deg, #B0084D 0%, #FF4F8B 100%)',
|
||||
icon: CloudWatchIcon,
|
||||
@@ -42,6 +45,7 @@ export const CloudWatchBlock: BlockConfig<
|
||||
{ label: 'Describe Log Streams', id: 'describe_log_streams' },
|
||||
{ label: 'List Metrics', id: 'list_metrics' },
|
||||
{ label: 'Get Metric Statistics', id: 'get_metric_statistics' },
|
||||
{ label: 'Publish Metric', id: 'put_metric_data' },
|
||||
{ label: 'Describe Alarms', id: 'describe_alarms' },
|
||||
],
|
||||
value: () => 'query_logs',
|
||||
@@ -69,7 +73,6 @@ export const CloudWatchBlock: BlockConfig<
|
||||
password: true,
|
||||
required: true,
|
||||
},
|
||||
// Query Logs fields
|
||||
{
|
||||
id: 'logGroupSelector',
|
||||
title: 'Log Group',
|
||||
@@ -124,6 +127,14 @@ Return ONLY the query — no explanations, no markdown code blocks.`,
|
||||
value: ['query_logs', 'get_log_events', 'get_metric_statistics'],
|
||||
},
|
||||
required: { field: 'operation', value: ['query_logs', 'get_metric_statistics'] },
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate a Unix epoch timestamp (in seconds) based on the user's description of a point in time.
|
||||
|
||||
Return ONLY the numeric timestamp - no explanations, no quotes, no extra text.`,
|
||||
placeholder: 'Describe the start time (e.g., "1 hour ago", "beginning of today")...',
|
||||
generationType: 'timestamp',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'endTime',
|
||||
@@ -135,8 +146,15 @@ Return ONLY the query — no explanations, no markdown code blocks.`,
|
||||
value: ['query_logs', 'get_log_events', 'get_metric_statistics'],
|
||||
},
|
||||
required: { field: 'operation', value: ['query_logs', 'get_metric_statistics'] },
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate a Unix epoch timestamp (in seconds) based on the user's description of a point in time.
|
||||
|
||||
Return ONLY the numeric timestamp - no explanations, no quotes, no extra text.`,
|
||||
placeholder: 'Describe the end time (e.g., "now", "end of yesterday")...',
|
||||
generationType: 'timestamp',
|
||||
},
|
||||
},
|
||||
// Describe Log Groups fields
|
||||
{
|
||||
id: 'prefix',
|
||||
title: 'Log Group Name Prefix',
|
||||
@@ -144,7 +162,6 @@ Return ONLY the query — no explanations, no markdown code blocks.`,
|
||||
placeholder: '/aws/lambda/',
|
||||
condition: { field: 'operation', value: 'describe_log_groups' },
|
||||
},
|
||||
// Get Log Events / Describe Log Streams — shared log group selector
|
||||
{
|
||||
id: 'logGroupNameSelector',
|
||||
title: 'Log Group',
|
||||
@@ -167,7 +184,6 @@ Return ONLY the query — no explanations, no markdown code blocks.`,
|
||||
required: { field: 'operation', value: ['get_log_events', 'describe_log_streams'] },
|
||||
mode: 'advanced',
|
||||
},
|
||||
// Describe Log Streams — stream prefix filter
|
||||
{
|
||||
id: 'streamPrefix',
|
||||
title: 'Stream Name Prefix',
|
||||
@@ -175,7 +191,6 @@ Return ONLY the query — no explanations, no markdown code blocks.`,
|
||||
placeholder: '2024/03/31/',
|
||||
condition: { field: 'operation', value: 'describe_log_streams' },
|
||||
},
|
||||
// Get Log Events — log stream selector (cascading: depends on log group)
|
||||
{
|
||||
id: 'logStreamNameSelector',
|
||||
title: 'Log Stream',
|
||||
@@ -198,30 +213,92 @@ Return ONLY the query — no explanations, no markdown code blocks.`,
|
||||
required: { field: 'operation', value: 'get_log_events' },
|
||||
mode: 'advanced',
|
||||
},
|
||||
// List Metrics fields
|
||||
{
|
||||
id: 'metricNamespace',
|
||||
title: 'Namespace',
|
||||
type: 'short-input',
|
||||
placeholder: 'e.g., AWS/EC2, AWS/Lambda, AWS/RDS',
|
||||
condition: { field: 'operation', value: ['list_metrics', 'get_metric_statistics'] },
|
||||
required: { field: 'operation', value: 'get_metric_statistics' },
|
||||
placeholder: 'e.g., AWS/EC2, AWS/Lambda, Custom/MyApp',
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: ['list_metrics', 'get_metric_statistics', 'put_metric_data'],
|
||||
},
|
||||
required: {
|
||||
field: 'operation',
|
||||
value: ['get_metric_statistics', 'put_metric_data'],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'metricName',
|
||||
title: 'Metric Name',
|
||||
type: 'short-input',
|
||||
placeholder: 'e.g., CPUUtilization, Invocations',
|
||||
condition: { field: 'operation', value: ['list_metrics', 'get_metric_statistics'] },
|
||||
required: { field: 'operation', value: 'get_metric_statistics' },
|
||||
placeholder: 'e.g., CPUUtilization, Invocations, ErrorCount',
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: ['list_metrics', 'get_metric_statistics', 'put_metric_data'],
|
||||
},
|
||||
required: {
|
||||
field: 'operation',
|
||||
value: ['get_metric_statistics', 'put_metric_data'],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'recentlyActive',
|
||||
title: 'Recently Active Only',
|
||||
type: 'switch',
|
||||
condition: { field: 'operation', value: 'list_metrics' },
|
||||
mode: 'advanced',
|
||||
},
|
||||
{
|
||||
id: 'metricValue',
|
||||
title: 'Value',
|
||||
type: 'short-input',
|
||||
placeholder: 'e.g., 1, 42.5',
|
||||
condition: { field: 'operation', value: 'put_metric_data' },
|
||||
required: { field: 'operation', value: 'put_metric_data' },
|
||||
},
|
||||
{
|
||||
id: 'metricUnit',
|
||||
title: 'Unit',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'None', id: 'None' },
|
||||
{ label: 'Count', id: 'Count' },
|
||||
{ label: 'Percent', id: 'Percent' },
|
||||
{ label: 'Seconds', id: 'Seconds' },
|
||||
{ label: 'Milliseconds', id: 'Milliseconds' },
|
||||
{ label: 'Microseconds', id: 'Microseconds' },
|
||||
{ label: 'Bytes', id: 'Bytes' },
|
||||
{ label: 'Kilobytes', id: 'Kilobytes' },
|
||||
{ label: 'Megabytes', id: 'Megabytes' },
|
||||
{ label: 'Gigabytes', id: 'Gigabytes' },
|
||||
{ label: 'Terabytes', id: 'Terabytes' },
|
||||
{ label: 'Bits', id: 'Bits' },
|
||||
{ label: 'Kilobits', id: 'Kilobits' },
|
||||
{ label: 'Megabits', id: 'Megabits' },
|
||||
{ label: 'Gigabits', id: 'Gigabits' },
|
||||
{ label: 'Terabits', id: 'Terabits' },
|
||||
{ label: 'Bytes/Second', id: 'Bytes/Second' },
|
||||
{ label: 'Kilobytes/Second', id: 'Kilobytes/Second' },
|
||||
{ label: 'Megabytes/Second', id: 'Megabytes/Second' },
|
||||
{ label: 'Gigabytes/Second', id: 'Gigabytes/Second' },
|
||||
{ label: 'Terabytes/Second', id: 'Terabytes/Second' },
|
||||
{ label: 'Bits/Second', id: 'Bits/Second' },
|
||||
{ label: 'Kilobits/Second', id: 'Kilobits/Second' },
|
||||
{ label: 'Megabits/Second', id: 'Megabits/Second' },
|
||||
{ label: 'Gigabits/Second', id: 'Gigabits/Second' },
|
||||
{ label: 'Terabits/Second', id: 'Terabits/Second' },
|
||||
{ label: 'Count/Second', id: 'Count/Second' },
|
||||
],
|
||||
value: () => 'None',
|
||||
condition: { field: 'operation', value: 'put_metric_data' },
|
||||
},
|
||||
{
|
||||
id: 'publishDimensions',
|
||||
title: 'Dimensions',
|
||||
type: 'table',
|
||||
columns: ['name', 'value'],
|
||||
condition: { field: 'operation', value: 'put_metric_data' },
|
||||
},
|
||||
// Get Metric Statistics fields
|
||||
{
|
||||
id: 'metricPeriod',
|
||||
title: 'Period (seconds)',
|
||||
@@ -251,7 +328,6 @@ Return ONLY the query — no explanations, no markdown code blocks.`,
|
||||
columns: ['name', 'value'],
|
||||
condition: { field: 'operation', value: 'get_metric_statistics' },
|
||||
},
|
||||
// Describe Alarms fields
|
||||
{
|
||||
id: 'alarmNamePrefix',
|
||||
title: 'Alarm Name Prefix',
|
||||
@@ -269,6 +345,7 @@ Return ONLY the query — no explanations, no markdown code blocks.`,
|
||||
{ label: 'ALARM', id: 'ALARM' },
|
||||
{ label: 'INSUFFICIENT_DATA', id: 'INSUFFICIENT_DATA' },
|
||||
],
|
||||
value: () => '',
|
||||
condition: { field: 'operation', value: 'describe_alarms' },
|
||||
},
|
||||
{
|
||||
@@ -280,9 +357,9 @@ Return ONLY the query — no explanations, no markdown code blocks.`,
|
||||
{ label: 'Metric Alarm', id: 'MetricAlarm' },
|
||||
{ label: 'Composite Alarm', id: 'CompositeAlarm' },
|
||||
],
|
||||
value: () => '',
|
||||
condition: { field: 'operation', value: 'describe_alarms' },
|
||||
},
|
||||
// Shared limit field
|
||||
{
|
||||
id: 'limit',
|
||||
title: 'Limit',
|
||||
@@ -299,6 +376,7 @@ Return ONLY the query — no explanations, no markdown code blocks.`,
|
||||
'describe_alarms',
|
||||
],
|
||||
},
|
||||
mode: 'advanced',
|
||||
},
|
||||
],
|
||||
tools: {
|
||||
@@ -309,6 +387,7 @@ Return ONLY the query — no explanations, no markdown code blocks.`,
|
||||
'cloudwatch_describe_log_streams',
|
||||
'cloudwatch_list_metrics',
|
||||
'cloudwatch_get_metric_statistics',
|
||||
'cloudwatch_put_metric_data',
|
||||
'cloudwatch_describe_alarms',
|
||||
],
|
||||
config: {
|
||||
@@ -326,6 +405,8 @@ Return ONLY the query — no explanations, no markdown code blocks.`,
|
||||
return 'cloudwatch_list_metrics'
|
||||
case 'get_metric_statistics':
|
||||
return 'cloudwatch_get_metric_statistics'
|
||||
case 'put_metric_data':
|
||||
return 'cloudwatch_put_metric_data'
|
||||
case 'describe_alarms':
|
||||
return 'cloudwatch_describe_alarms'
|
||||
default:
|
||||
@@ -479,6 +560,48 @@ Return ONLY the query — no explanations, no markdown code blocks.`,
|
||||
}
|
||||
}
|
||||
|
||||
case 'put_metric_data': {
|
||||
if (!rest.metricNamespace) {
|
||||
throw new Error('Namespace is required')
|
||||
}
|
||||
if (!rest.metricName) {
|
||||
throw new Error('Metric name is required')
|
||||
}
|
||||
if (rest.metricValue === undefined || rest.metricValue === '') {
|
||||
throw new Error('Metric value is required')
|
||||
}
|
||||
const numericValue = Number(rest.metricValue)
|
||||
if (!Number.isFinite(numericValue)) {
|
||||
throw new Error('Metric value must be a finite number')
|
||||
}
|
||||
|
||||
return {
|
||||
awsRegion,
|
||||
awsAccessKeyId,
|
||||
awsSecretAccessKey,
|
||||
namespace: rest.metricNamespace,
|
||||
metricName: rest.metricName,
|
||||
value: numericValue,
|
||||
...(rest.metricUnit && rest.metricUnit !== 'None' && { unit: rest.metricUnit }),
|
||||
...(rest.publishDimensions && {
|
||||
dimensions: (() => {
|
||||
const dims = rest.publishDimensions
|
||||
if (typeof dims === 'string') return dims
|
||||
if (Array.isArray(dims)) {
|
||||
const obj: Record<string, string> = {}
|
||||
for (const row of dims) {
|
||||
const name = row.cells?.name
|
||||
const value = row.cells?.value
|
||||
if (name && value !== undefined) obj[name] = String(value)
|
||||
}
|
||||
return JSON.stringify(obj)
|
||||
}
|
||||
return JSON.stringify(dims)
|
||||
})(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
case 'describe_alarms':
|
||||
return {
|
||||
awsRegion,
|
||||
@@ -518,6 +641,12 @@ Return ONLY the query — no explanations, no markdown code blocks.`,
|
||||
metricPeriod: { type: 'number', description: 'Granularity in seconds' },
|
||||
metricStatistics: { type: 'string', description: 'Statistic type (Average, Sum, etc.)' },
|
||||
metricDimensions: { type: 'json', description: 'Metric dimensions (Name/Value pairs)' },
|
||||
metricValue: { type: 'number', description: 'Metric value to publish' },
|
||||
metricUnit: { type: 'string', description: 'Metric unit (Count, Seconds, Bytes, etc.)' },
|
||||
publishDimensions: {
|
||||
type: 'json',
|
||||
description: 'Dimensions for published metric (Name/Value pairs)',
|
||||
},
|
||||
alarmNamePrefix: { type: 'string', description: 'Alarm name prefix filter' },
|
||||
stateValue: {
|
||||
type: 'string',
|
||||
@@ -567,5 +696,29 @@ Return ONLY the query — no explanations, no markdown code blocks.`,
|
||||
type: 'array',
|
||||
description: 'CloudWatch alarms with state and configuration',
|
||||
},
|
||||
success: {
|
||||
type: 'boolean',
|
||||
description: 'Whether the published metric was successful',
|
||||
},
|
||||
namespace: {
|
||||
type: 'string',
|
||||
description: 'Metric namespace',
|
||||
},
|
||||
metricName: {
|
||||
type: 'string',
|
||||
description: 'Metric name',
|
||||
},
|
||||
value: {
|
||||
type: 'number',
|
||||
description: 'Published metric value',
|
||||
},
|
||||
unit: {
|
||||
type: 'string',
|
||||
description: 'Metric unit',
|
||||
},
|
||||
timestamp: {
|
||||
type: 'string',
|
||||
description: 'Timestamp when metric was published',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ export const createNamedQueryTool: ToolConfig<
|
||||
id: 'athena_create_named_query',
|
||||
name: 'Athena Create Named Query',
|
||||
description: 'Create a saved/named query in AWS Athena',
|
||||
version: '1.0',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
awsRegion: {
|
||||
|
||||
@@ -6,7 +6,7 @@ export const getNamedQueryTool: ToolConfig<AthenaGetNamedQueryParams, AthenaGetN
|
||||
id: 'athena_get_named_query',
|
||||
name: 'Athena Get Named Query',
|
||||
description: 'Get details of a saved/named query in AWS Athena',
|
||||
version: '1.0',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
awsRegion: {
|
||||
|
||||
@@ -11,7 +11,7 @@ export const getQueryExecutionTool: ToolConfig<
|
||||
id: 'athena_get_query_execution',
|
||||
name: 'Athena Get Query Execution',
|
||||
description: 'Get the status and details of an Athena query execution',
|
||||
version: '1.0',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
awsRegion: {
|
||||
|
||||
@@ -11,7 +11,7 @@ export const getQueryResultsTool: ToolConfig<
|
||||
id: 'athena_get_query_results',
|
||||
name: 'Athena Get Query Results',
|
||||
description: 'Retrieve the results of a completed Athena query execution',
|
||||
version: '1.0',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
awsRegion: {
|
||||
|
||||
@@ -11,7 +11,7 @@ export const listNamedQueriesTool: ToolConfig<
|
||||
id: 'athena_list_named_queries',
|
||||
name: 'Athena List Named Queries',
|
||||
description: 'List saved/named query IDs in AWS Athena',
|
||||
version: '1.0',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
awsRegion: {
|
||||
|
||||
@@ -11,7 +11,7 @@ export const listQueryExecutionsTool: ToolConfig<
|
||||
id: 'athena_list_query_executions',
|
||||
name: 'Athena List Query Executions',
|
||||
description: 'List recent Athena query execution IDs',
|
||||
version: '1.0',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
awsRegion: {
|
||||
|
||||
@@ -5,7 +5,7 @@ export const startQueryTool: ToolConfig<AthenaStartQueryParams, AthenaStartQuery
|
||||
id: 'athena_start_query',
|
||||
name: 'Athena Start Query',
|
||||
description: 'Start an SQL query execution in AWS Athena',
|
||||
version: '1.0',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
awsRegion: {
|
||||
|
||||
@@ -5,7 +5,7 @@ export const stopQueryTool: ToolConfig<AthenaStopQueryParams, AthenaStopQueryRes
|
||||
id: 'athena_stop_query',
|
||||
name: 'Athena Stop Query',
|
||||
description: 'Stop a running Athena query execution',
|
||||
version: '1.0',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
awsRegion: {
|
||||
|
||||
@@ -11,7 +11,7 @@ export const describeStackDriftDetectionStatusTool: ToolConfig<
|
||||
id: 'cloudformation_describe_stack_drift_detection_status',
|
||||
name: 'CloudFormation Describe Stack Drift Detection Status',
|
||||
description: 'Check the status of a stack drift detection operation',
|
||||
version: '1.0',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
awsRegion: {
|
||||
|
||||
@@ -11,7 +11,7 @@ export const describeStackEventsTool: ToolConfig<
|
||||
id: 'cloudformation_describe_stack_events',
|
||||
name: 'CloudFormation Describe Stack Events',
|
||||
description: 'Get the event history for a CloudFormation stack',
|
||||
version: '1.0',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
awsRegion: {
|
||||
|
||||
@@ -11,7 +11,7 @@ export const describeStacksTool: ToolConfig<
|
||||
id: 'cloudformation_describe_stacks',
|
||||
name: 'CloudFormation Describe Stacks',
|
||||
description: 'List and describe CloudFormation stacks',
|
||||
version: '1.0',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
awsRegion: {
|
||||
|
||||
@@ -11,7 +11,7 @@ export const detectStackDriftTool: ToolConfig<
|
||||
id: 'cloudformation_detect_stack_drift',
|
||||
name: 'CloudFormation Detect Stack Drift',
|
||||
description: 'Initiate drift detection on a CloudFormation stack',
|
||||
version: '1.0',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
awsRegion: {
|
||||
|
||||
@@ -11,7 +11,7 @@ export const getTemplateTool: ToolConfig<
|
||||
id: 'cloudformation_get_template',
|
||||
name: 'CloudFormation Get Template',
|
||||
description: 'Retrieve the template body for a CloudFormation stack',
|
||||
version: '1.0',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
awsRegion: {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
export * from './types'
|
||||
|
||||
import { describeStackDriftDetectionStatusTool } from '@/tools/cloudformation/describe_stack_drift_detection_status'
|
||||
import { describeStackEventsTool } from '@/tools/cloudformation/describe_stack_events'
|
||||
import { describeStacksTool } from '@/tools/cloudformation/describe_stacks'
|
||||
|
||||
@@ -11,7 +11,7 @@ export const listStackResourcesTool: ToolConfig<
|
||||
id: 'cloudformation_list_stack_resources',
|
||||
name: 'CloudFormation List Stack Resources',
|
||||
description: 'List all resources in a CloudFormation stack',
|
||||
version: '1.0',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
awsRegion: {
|
||||
|
||||
@@ -11,7 +11,7 @@ export const validateTemplateTool: ToolConfig<
|
||||
id: 'cloudformation_validate_template',
|
||||
name: 'CloudFormation Validate Template',
|
||||
description: 'Validate a CloudFormation template for syntax and structural correctness',
|
||||
version: '1.0',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
awsRegion: {
|
||||
|
||||
@@ -11,7 +11,7 @@ export const describeAlarmsTool: ToolConfig<
|
||||
id: 'cloudwatch_describe_alarms',
|
||||
name: 'CloudWatch Describe Alarms',
|
||||
description: 'List and filter CloudWatch alarms',
|
||||
version: '1.0',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
awsRegion: {
|
||||
|
||||
@@ -11,7 +11,7 @@ export const describeLogGroupsTool: ToolConfig<
|
||||
id: 'cloudwatch_describe_log_groups',
|
||||
name: 'CloudWatch Describe Log Groups',
|
||||
description: 'List available CloudWatch log groups',
|
||||
version: '1.0',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
awsRegion: {
|
||||
|
||||
@@ -11,7 +11,7 @@ export const describeLogStreamsTool: ToolConfig<
|
||||
id: 'cloudwatch_describe_log_streams',
|
||||
name: 'CloudWatch Describe Log Streams',
|
||||
description: 'List log streams within a CloudWatch log group',
|
||||
version: '1.0',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
awsRegion: {
|
||||
|
||||
@@ -11,7 +11,7 @@ export const getLogEventsTool: ToolConfig<
|
||||
id: 'cloudwatch_get_log_events',
|
||||
name: 'CloudWatch Get Log Events',
|
||||
description: 'Retrieve log events from a specific CloudWatch log stream',
|
||||
version: '1.0',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
awsRegion: {
|
||||
|
||||
@@ -11,7 +11,7 @@ export const getMetricStatisticsTool: ToolConfig<
|
||||
id: 'cloudwatch_get_metric_statistics',
|
||||
name: 'CloudWatch Get Metric Statistics',
|
||||
description: 'Get statistics for a CloudWatch metric over a time range',
|
||||
version: '1.0',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
awsRegion: {
|
||||
|
||||
@@ -4,12 +4,16 @@ import { describeLogStreamsTool } from '@/tools/cloudwatch/describe_log_streams'
|
||||
import { getLogEventsTool } from '@/tools/cloudwatch/get_log_events'
|
||||
import { getMetricStatisticsTool } from '@/tools/cloudwatch/get_metric_statistics'
|
||||
import { listMetricsTool } from '@/tools/cloudwatch/list_metrics'
|
||||
import { putMetricDataTool } from '@/tools/cloudwatch/put_metric_data'
|
||||
import { queryLogsTool } from '@/tools/cloudwatch/query_logs'
|
||||
|
||||
export * from './types'
|
||||
|
||||
export const cloudwatchDescribeAlarmsTool = describeAlarmsTool
|
||||
export const cloudwatchDescribeLogGroupsTool = describeLogGroupsTool
|
||||
export const cloudwatchDescribeLogStreamsTool = describeLogStreamsTool
|
||||
export const cloudwatchGetLogEventsTool = getLogEventsTool
|
||||
export const cloudwatchGetMetricStatisticsTool = getMetricStatisticsTool
|
||||
export const cloudwatchListMetricsTool = listMetricsTool
|
||||
export const cloudwatchPutMetricDataTool = putMetricDataTool
|
||||
export const cloudwatchQueryLogsTool = queryLogsTool
|
||||
|
||||
@@ -11,7 +11,7 @@ export const listMetricsTool: ToolConfig<
|
||||
id: 'cloudwatch_list_metrics',
|
||||
name: 'CloudWatch List Metrics',
|
||||
description: 'List available CloudWatch metrics',
|
||||
version: '1.0',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
awsRegion: {
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
import type {
|
||||
CloudWatchPutMetricDataParams,
|
||||
CloudWatchPutMetricDataResponse,
|
||||
} from '@/tools/cloudwatch/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const putMetricDataTool: ToolConfig<
|
||||
CloudWatchPutMetricDataParams,
|
||||
CloudWatchPutMetricDataResponse
|
||||
> = {
|
||||
id: 'cloudwatch_put_metric_data',
|
||||
name: 'CloudWatch Publish Metric',
|
||||
description: 'Publish a custom metric data point to CloudWatch',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
awsRegion: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'AWS region (e.g., us-east-1)',
|
||||
},
|
||||
awsAccessKeyId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'AWS access key ID',
|
||||
},
|
||||
awsSecretAccessKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'AWS secret access key',
|
||||
},
|
||||
namespace: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Metric namespace (e.g., Custom/MyApp)',
|
||||
},
|
||||
metricName: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Name of the metric',
|
||||
},
|
||||
value: {
|
||||
type: 'number',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Metric value to publish',
|
||||
},
|
||||
unit: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Unit of the metric (e.g., Count, Seconds, Bytes)',
|
||||
},
|
||||
dimensions: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'JSON string of dimension name/value pairs',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/cloudwatch/put-metric-data',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
region: params.awsRegion,
|
||||
accessKeyId: params.awsAccessKeyId,
|
||||
secretAccessKey: params.awsSecretAccessKey,
|
||||
namespace: params.namespace,
|
||||
metricName: params.metricName,
|
||||
value: params.value,
|
||||
...(params.unit && { unit: params.unit }),
|
||||
...(params.dimensions && { dimensions: params.dimensions }),
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(data.error || 'Failed to publish CloudWatch metric')
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: data.output,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
success: { type: 'boolean', description: 'Whether the metric was published successfully' },
|
||||
namespace: { type: 'string', description: 'Metric namespace' },
|
||||
metricName: { type: 'string', description: 'Metric name' },
|
||||
value: { type: 'number', description: 'Published metric value' },
|
||||
unit: { type: 'string', description: 'Metric unit' },
|
||||
timestamp: { type: 'string', description: 'Timestamp when the metric was published' },
|
||||
},
|
||||
}
|
||||
@@ -8,7 +8,7 @@ export const queryLogsTool: ToolConfig<CloudWatchQueryLogsParams, CloudWatchQuer
|
||||
id: 'cloudwatch_query_logs',
|
||||
name: 'CloudWatch Query Logs',
|
||||
description: 'Run a CloudWatch Log Insights query against one or more log groups',
|
||||
version: '1.0',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
awsRegion: {
|
||||
|
||||
@@ -144,3 +144,22 @@ export interface CloudWatchDescribeAlarmsResponse extends ToolResponse {
|
||||
}[]
|
||||
}
|
||||
}
|
||||
|
||||
export interface CloudWatchPutMetricDataParams extends CloudWatchConnectionConfig {
|
||||
namespace: string
|
||||
metricName: string
|
||||
value: number
|
||||
unit?: string
|
||||
dimensions?: string
|
||||
}
|
||||
|
||||
export interface CloudWatchPutMetricDataResponse extends ToolResponse {
|
||||
output: {
|
||||
success: boolean
|
||||
namespace: string
|
||||
metricName: string
|
||||
value: number
|
||||
unit: string
|
||||
timestamp: string
|
||||
}
|
||||
}
|
||||
|
||||
@@ -301,6 +301,7 @@ import {
|
||||
cloudwatchGetLogEventsTool,
|
||||
cloudwatchGetMetricStatisticsTool,
|
||||
cloudwatchListMetricsTool,
|
||||
cloudwatchPutMetricDataTool,
|
||||
cloudwatchQueryLogsTool,
|
||||
} from '@/tools/cloudwatch'
|
||||
import {
|
||||
@@ -3442,21 +3443,22 @@ export const tools: Record<string, ToolConfig> = {
|
||||
rds_delete: rdsDeleteTool,
|
||||
rds_execute: rdsExecuteTool,
|
||||
rds_introspect: rdsIntrospectTool,
|
||||
cloudformation_describe_stacks: cloudformationDescribeStacksTool,
|
||||
cloudformation_list_stack_resources: cloudformationListStackResourcesTool,
|
||||
cloudformation_detect_stack_drift: cloudformationDetectStackDriftTool,
|
||||
cloudformation_describe_stack_drift_detection_status:
|
||||
cloudformationDescribeStackDriftDetectionStatusTool,
|
||||
cloudformation_describe_stack_events: cloudformationDescribeStackEventsTool,
|
||||
cloudformation_describe_stacks: cloudformationDescribeStacksTool,
|
||||
cloudformation_detect_stack_drift: cloudformationDetectStackDriftTool,
|
||||
cloudformation_get_template: cloudformationGetTemplateTool,
|
||||
cloudformation_list_stack_resources: cloudformationListStackResourcesTool,
|
||||
cloudformation_validate_template: cloudformationValidateTemplateTool,
|
||||
cloudwatch_query_logs: cloudwatchQueryLogsTool,
|
||||
cloudwatch_describe_log_groups: cloudwatchDescribeLogGroupsTool,
|
||||
cloudwatch_describe_alarms: cloudwatchDescribeAlarmsTool,
|
||||
cloudwatch_describe_log_groups: cloudwatchDescribeLogGroupsTool,
|
||||
cloudwatch_describe_log_streams: cloudwatchDescribeLogStreamsTool,
|
||||
cloudwatch_get_log_events: cloudwatchGetLogEventsTool,
|
||||
cloudwatch_list_metrics: cloudwatchListMetricsTool,
|
||||
cloudwatch_get_metric_statistics: cloudwatchGetMetricStatisticsTool,
|
||||
cloudwatch_list_metrics: cloudwatchListMetricsTool,
|
||||
cloudwatch_put_metric_data: cloudwatchPutMetricDataTool,
|
||||
cloudwatch_query_logs: cloudwatchQueryLogsTool,
|
||||
dynamodb_get: dynamodbGetTool,
|
||||
dynamodb_put: dynamodbPutTool,
|
||||
dynamodb_query: dynamodbQueryTool,
|
||||
|
||||
Reference in New Issue
Block a user