@aws/agentcore 0.14.2 → 0.16.0
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/README.md +24 -7
- package/dist/assets/__tests__/__snapshots__/assets.snapshot.test.ts.snap +65 -5
- package/dist/assets/cdk/bin/cdk.ts +37 -0
- package/dist/assets/cdk/lib/cdk-stack.ts +24 -5
- package/dist/assets/cdk/test/cdk.test.ts +1 -0
- package/dist/assets/datasets/predefined-v1.jsonl +3 -0
- package/dist/assets/datasets/simulated-v1.jsonl +3 -0
- package/dist/assets/harness/invoke.py.template +74 -0
- package/dist/cli/index.mjs +637 -572
- package/dist/lib/constants.d.ts +1 -0
- package/dist/lib/constants.d.ts.map +1 -1
- package/dist/lib/constants.js +3 -1
- package/dist/lib/constants.js.map +1 -1
- package/dist/lib/schemas/io/config-io.d.ts +9 -1
- package/dist/lib/schemas/io/config-io.d.ts.map +1 -1
- package/dist/lib/schemas/io/config-io.js +14 -0
- package/dist/lib/schemas/io/config-io.js.map +1 -1
- package/dist/lib/schemas/io/path-resolver.d.ts +12 -0
- package/dist/lib/schemas/io/path-resolver.d.ts.map +1 -1
- package/dist/lib/schemas/io/path-resolver.js +18 -0
- package/dist/lib/schemas/io/path-resolver.js.map +1 -1
- package/dist/schema/schemas/agentcore-project.d.ts +74 -0
- package/dist/schema/schemas/agentcore-project.d.ts.map +1 -1
- package/dist/schema/schemas/agentcore-project.js +82 -2
- package/dist/schema/schemas/agentcore-project.js.map +1 -1
- package/dist/schema/schemas/deployed-state.d.ts +76 -0
- package/dist/schema/schemas/deployed-state.d.ts.map +1 -1
- package/dist/schema/schemas/deployed-state.js +24 -1
- package/dist/schema/schemas/deployed-state.js.map +1 -1
- package/dist/schema/schemas/primitives/dataset.d.ts +48 -0
- package/dist/schema/schemas/primitives/dataset.d.ts.map +1 -0
- package/dist/schema/schemas/primitives/dataset.js +58 -0
- package/dist/schema/schemas/primitives/dataset.js.map +1 -0
- package/dist/schema/schemas/primitives/harness.d.ts +363 -0
- package/dist/schema/schemas/primitives/harness.d.ts.map +1 -0
- package/dist/schema/schemas/primitives/harness.js +261 -0
- package/dist/schema/schemas/primitives/harness.js.map +1 -0
- package/dist/schema/schemas/primitives/index.d.ts +4 -0
- package/dist/schema/schemas/primitives/index.d.ts.map +1 -1
- package/dist/schema/schemas/primitives/index.js +21 -1
- package/dist/schema/schemas/primitives/index.js.map +1 -1
- package/npm-shrinkwrap.json +184 -217
- package/package.json +11 -9
- package/scripts/bundle.mjs +86 -9
package/README.md
CHANGED
|
@@ -135,12 +135,13 @@ agentcore invoke
|
|
|
135
135
|
|
|
136
136
|
### Utilities
|
|
137
137
|
|
|
138
|
-
| Command | Description
|
|
139
|
-
| -------------- |
|
|
140
|
-
| `validate` | Validate configuration files
|
|
141
|
-
| `package` | Package agent artifacts without deploying
|
|
142
|
-
| `fetch access` | Fetch access info for deployed resources
|
|
143
|
-
| `
|
|
138
|
+
| Command | Description |
|
|
139
|
+
| -------------- | ----------------------------------------------------- |
|
|
140
|
+
| `validate` | Validate configuration files |
|
|
141
|
+
| `package` | Package agent artifacts without deploying |
|
|
142
|
+
| `fetch access` | Fetch access info for deployed resources |
|
|
143
|
+
| `feedback` | Send feedback to the AgentCore team (with screenshot) |
|
|
144
|
+
| `update` | Check for and install CLI updates |
|
|
144
145
|
|
|
145
146
|
## Project Structure
|
|
146
147
|
|
|
@@ -191,10 +192,26 @@ Projects use JSON schema files in the `agentcore/` directory:
|
|
|
191
192
|
- [Gateway](docs/gateway.md) - Gateway setup, targets, and authentication
|
|
192
193
|
- [Memory](docs/memory.md) - Memory strategies and sharing
|
|
193
194
|
- [Local Development](docs/local-development.md) - Dev server and debugging
|
|
195
|
+
- [Feedback](docs/feedback.md) - Submit feedback from your terminal
|
|
196
|
+
|
|
197
|
+
## Examples
|
|
198
|
+
|
|
199
|
+
See the [AgentCore Samples](https://github.com/awslabs/agentcore-samples) repository for end-to-end examples using the
|
|
200
|
+
CLI, including multi-agent workflows, MCP gateway targets, and framework integrations.
|
|
194
201
|
|
|
195
202
|
## Feedback & Issues
|
|
196
203
|
|
|
197
|
-
|
|
204
|
+
Have a quick comment or suggestion? Send it from your terminal:
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
agentcore feedback "your message" --screenshot path/to/screenshot.png
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
The CLI will display the AWS Customer Agreement and prompt for consent before submitting. See
|
|
211
|
+
[docs/feedback.md](docs/feedback.md) for usage details.
|
|
212
|
+
|
|
213
|
+
For bugs, regressions, or feature requests that need discussion,
|
|
214
|
+
[open an issue](https://github.com/aws/agentcore-cli/issues/new) on GitHub instead.
|
|
198
215
|
|
|
199
216
|
## Security
|
|
200
217
|
|
|
@@ -99,6 +99,42 @@ async function main() {
|
|
|
99
99
|
throw new Error('No deployment targets configured. Please define targets in agentcore/aws-targets.json');
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
+
// Read harness configs for role creation.
|
|
103
|
+
const projectRoot = path.resolve(configRoot, '..');
|
|
104
|
+
const harnessConfigs: {
|
|
105
|
+
name: string;
|
|
106
|
+
executionRoleArn?: string;
|
|
107
|
+
memoryName?: string;
|
|
108
|
+
containerUri?: string;
|
|
109
|
+
hasDockerfile?: boolean;
|
|
110
|
+
dockerfile?: string;
|
|
111
|
+
codeLocation?: string;
|
|
112
|
+
tools?: { type: string; name: string }[];
|
|
113
|
+
apiKeyArn?: string;
|
|
114
|
+
}[] = [];
|
|
115
|
+
for (const entry of specAny.harnesses ?? []) {
|
|
116
|
+
const harnessDir = path.resolve(projectRoot, entry.path);
|
|
117
|
+
const harnessPath = path.resolve(harnessDir, 'harness.json');
|
|
118
|
+
try {
|
|
119
|
+
const harnessSpec = JSON.parse(fs.readFileSync(harnessPath, 'utf-8'));
|
|
120
|
+
harnessConfigs.push({
|
|
121
|
+
name: entry.name,
|
|
122
|
+
executionRoleArn: harnessSpec.executionRoleArn,
|
|
123
|
+
memoryName: harnessSpec.memory?.name,
|
|
124
|
+
containerUri: harnessSpec.containerUri,
|
|
125
|
+
hasDockerfile: !!harnessSpec.dockerfile,
|
|
126
|
+
dockerfile: harnessSpec.dockerfile,
|
|
127
|
+
codeLocation: harnessSpec.dockerfile ? harnessDir : undefined,
|
|
128
|
+
tools: harnessSpec.tools,
|
|
129
|
+
apiKeyArn: harnessSpec.model?.apiKeyArn,
|
|
130
|
+
});
|
|
131
|
+
} catch (err) {
|
|
132
|
+
throw new Error(
|
|
133
|
+
\`Could not read harness.json for "\${entry.name}" at \${harnessPath}: \${err instanceof Error ? err.message : err}\`
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
102
138
|
const app = new App();
|
|
103
139
|
|
|
104
140
|
for (const target of targets) {
|
|
@@ -118,6 +154,7 @@ async function main() {
|
|
|
118
154
|
spec,
|
|
119
155
|
mcpSpec,
|
|
120
156
|
credentials,
|
|
157
|
+
harnesses: harnessConfigs.length > 0 ? harnessConfigs : undefined,
|
|
121
158
|
env,
|
|
122
159
|
description: \`AgentCore stack for \${spec.name} deployed to \${target.name} (\${target.region})\`,
|
|
123
160
|
tags: {
|
|
@@ -265,6 +302,18 @@ exports[`Assets Directory Snapshots > CDK assets > cdk/cdk/lib/cdk-stack.ts shou
|
|
|
265
302
|
import { CfnOutput, Stack, type StackProps } from 'aws-cdk-lib';
|
|
266
303
|
import { Construct } from 'constructs';
|
|
267
304
|
|
|
305
|
+
export interface HarnessConfig {
|
|
306
|
+
name: string;
|
|
307
|
+
executionRoleArn?: string;
|
|
308
|
+
memoryName?: string;
|
|
309
|
+
containerUri?: string;
|
|
310
|
+
hasDockerfile?: boolean;
|
|
311
|
+
dockerfile?: string;
|
|
312
|
+
codeLocation?: string;
|
|
313
|
+
tools?: { type: string; name: string }[];
|
|
314
|
+
apiKeyArn?: string;
|
|
315
|
+
}
|
|
316
|
+
|
|
268
317
|
export interface AgentCoreStackProps extends StackProps {
|
|
269
318
|
/**
|
|
270
319
|
* The AgentCore project specification containing agents, memories, and credentials.
|
|
@@ -278,6 +327,10 @@ export interface AgentCoreStackProps extends StackProps {
|
|
|
278
327
|
* Credential provider ARNs from deployed state, keyed by credential name.
|
|
279
328
|
*/
|
|
280
329
|
credentials?: Record<string, { credentialProviderArn: string; clientSecretArn?: string }>;
|
|
330
|
+
/**
|
|
331
|
+
* Harness role configurations.
|
|
332
|
+
*/
|
|
333
|
+
harnesses?: HarnessConfig[];
|
|
281
334
|
}
|
|
282
335
|
|
|
283
336
|
/**
|
|
@@ -293,12 +346,15 @@ export class AgentCoreStack extends Stack {
|
|
|
293
346
|
constructor(scope: Construct, id: string, props: AgentCoreStackProps) {
|
|
294
347
|
super(scope, id, props);
|
|
295
348
|
|
|
296
|
-
const { spec, mcpSpec, credentials } = props;
|
|
349
|
+
const { spec, mcpSpec, credentials, harnesses } = props;
|
|
297
350
|
|
|
298
|
-
// Create AgentCoreApplication with all agents
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
351
|
+
// Create AgentCoreApplication with all agents and harness roles
|
|
352
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
353
|
+
const appProps: Record<string, unknown> = { spec };
|
|
354
|
+
if (harnesses?.length) {
|
|
355
|
+
appProps.harnesses = harnesses;
|
|
356
|
+
}
|
|
357
|
+
this.application = new AgentCoreApplication(this, 'Application', appProps as any);
|
|
302
358
|
|
|
303
359
|
// Create AgentCoreMcp if there are gateways configured
|
|
304
360
|
if (mcpSpec?.agentCoreGateways && mcpSpec.agentCoreGateways.length > 0) {
|
|
@@ -386,6 +442,7 @@ test('AgentCoreStack synthesizes with empty spec', () => {
|
|
|
386
442
|
agentCoreGateways: [],
|
|
387
443
|
mcpRuntimeTools: [],
|
|
388
444
|
unassignedTargets: [],
|
|
445
|
+
datasets: [],
|
|
389
446
|
},
|
|
390
447
|
});
|
|
391
448
|
const template = Template.fromStack(stack);
|
|
@@ -448,9 +505,12 @@ exports[`Assets Directory Snapshots > File listing > should match the expected f
|
|
|
448
505
|
"container/python/dockerignore.template",
|
|
449
506
|
"container/typescript/Dockerfile",
|
|
450
507
|
"container/typescript/dockerignore.template",
|
|
508
|
+
"datasets/predefined-v1.jsonl",
|
|
509
|
+
"datasets/simulated-v1.jsonl",
|
|
451
510
|
"evaluators/python-lambda/execution-role-policy.json",
|
|
452
511
|
"evaluators/python-lambda/lambda_function.py",
|
|
453
512
|
"evaluators/python-lambda/pyproject.toml",
|
|
513
|
+
"harness/invoke.py.template",
|
|
454
514
|
"mcp/python-lambda/README.md",
|
|
455
515
|
"mcp/python-lambda/handler.py",
|
|
456
516
|
"mcp/python-lambda/pyproject.toml",
|
|
@@ -54,6 +54,42 @@ async function main() {
|
|
|
54
54
|
throw new Error('No deployment targets configured. Please define targets in agentcore/aws-targets.json');
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
// Read harness configs for role creation.
|
|
58
|
+
const projectRoot = path.resolve(configRoot, '..');
|
|
59
|
+
const harnessConfigs: {
|
|
60
|
+
name: string;
|
|
61
|
+
executionRoleArn?: string;
|
|
62
|
+
memoryName?: string;
|
|
63
|
+
containerUri?: string;
|
|
64
|
+
hasDockerfile?: boolean;
|
|
65
|
+
dockerfile?: string;
|
|
66
|
+
codeLocation?: string;
|
|
67
|
+
tools?: { type: string; name: string }[];
|
|
68
|
+
apiKeyArn?: string;
|
|
69
|
+
}[] = [];
|
|
70
|
+
for (const entry of specAny.harnesses ?? []) {
|
|
71
|
+
const harnessDir = path.resolve(projectRoot, entry.path);
|
|
72
|
+
const harnessPath = path.resolve(harnessDir, 'harness.json');
|
|
73
|
+
try {
|
|
74
|
+
const harnessSpec = JSON.parse(fs.readFileSync(harnessPath, 'utf-8'));
|
|
75
|
+
harnessConfigs.push({
|
|
76
|
+
name: entry.name,
|
|
77
|
+
executionRoleArn: harnessSpec.executionRoleArn,
|
|
78
|
+
memoryName: harnessSpec.memory?.name,
|
|
79
|
+
containerUri: harnessSpec.containerUri,
|
|
80
|
+
hasDockerfile: !!harnessSpec.dockerfile,
|
|
81
|
+
dockerfile: harnessSpec.dockerfile,
|
|
82
|
+
codeLocation: harnessSpec.dockerfile ? harnessDir : undefined,
|
|
83
|
+
tools: harnessSpec.tools,
|
|
84
|
+
apiKeyArn: harnessSpec.model?.apiKeyArn,
|
|
85
|
+
});
|
|
86
|
+
} catch (err) {
|
|
87
|
+
throw new Error(
|
|
88
|
+
`Could not read harness.json for "${entry.name}" at ${harnessPath}: ${err instanceof Error ? err.message : err}`
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
57
93
|
const app = new App();
|
|
58
94
|
|
|
59
95
|
for (const target of targets) {
|
|
@@ -73,6 +109,7 @@ async function main() {
|
|
|
73
109
|
spec,
|
|
74
110
|
mcpSpec,
|
|
75
111
|
credentials,
|
|
112
|
+
harnesses: harnessConfigs.length > 0 ? harnessConfigs : undefined,
|
|
76
113
|
env,
|
|
77
114
|
description: `AgentCore stack for ${spec.name} deployed to ${target.name} (${target.region})`,
|
|
78
115
|
tags: {
|
|
@@ -7,6 +7,18 @@ import {
|
|
|
7
7
|
import { CfnOutput, Stack, type StackProps } from 'aws-cdk-lib';
|
|
8
8
|
import { Construct } from 'constructs';
|
|
9
9
|
|
|
10
|
+
export interface HarnessConfig {
|
|
11
|
+
name: string;
|
|
12
|
+
executionRoleArn?: string;
|
|
13
|
+
memoryName?: string;
|
|
14
|
+
containerUri?: string;
|
|
15
|
+
hasDockerfile?: boolean;
|
|
16
|
+
dockerfile?: string;
|
|
17
|
+
codeLocation?: string;
|
|
18
|
+
tools?: { type: string; name: string }[];
|
|
19
|
+
apiKeyArn?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
10
22
|
export interface AgentCoreStackProps extends StackProps {
|
|
11
23
|
/**
|
|
12
24
|
* The AgentCore project specification containing agents, memories, and credentials.
|
|
@@ -20,6 +32,10 @@ export interface AgentCoreStackProps extends StackProps {
|
|
|
20
32
|
* Credential provider ARNs from deployed state, keyed by credential name.
|
|
21
33
|
*/
|
|
22
34
|
credentials?: Record<string, { credentialProviderArn: string; clientSecretArn?: string }>;
|
|
35
|
+
/**
|
|
36
|
+
* Harness role configurations.
|
|
37
|
+
*/
|
|
38
|
+
harnesses?: HarnessConfig[];
|
|
23
39
|
}
|
|
24
40
|
|
|
25
41
|
/**
|
|
@@ -35,12 +51,15 @@ export class AgentCoreStack extends Stack {
|
|
|
35
51
|
constructor(scope: Construct, id: string, props: AgentCoreStackProps) {
|
|
36
52
|
super(scope, id, props);
|
|
37
53
|
|
|
38
|
-
const { spec, mcpSpec, credentials } = props;
|
|
54
|
+
const { spec, mcpSpec, credentials, harnesses } = props;
|
|
39
55
|
|
|
40
|
-
// Create AgentCoreApplication with all agents
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
56
|
+
// Create AgentCoreApplication with all agents and harness roles
|
|
57
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
58
|
+
const appProps: Record<string, unknown> = { spec };
|
|
59
|
+
if (harnesses?.length) {
|
|
60
|
+
appProps.harnesses = harnesses;
|
|
61
|
+
}
|
|
62
|
+
this.application = new AgentCoreApplication(this, 'Application', appProps as any);
|
|
44
63
|
|
|
45
64
|
// Create AgentCoreMcp if there are gateways configured
|
|
46
65
|
if (mcpSpec?.agentCoreGateways && mcpSpec.agentCoreGateways.length > 0) {
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
{"scenario_id": "refund-policy", "turns": [{"input": "What is your refund policy?", "expectedResponse": "We offer full refunds within 30 days of purchase. After 30 days, we can provide store credit."}, {"input": "What if I lost my receipt?", "expectedResponse": "No problem! We can look up your purchase using your email address or payment method."}], "assertions": ["Agent should clearly state the 30-day refund window", "Agent should offer alternatives for lost receipts"], "expected_trajectory": ["lookup_policy", "check_eligibility"]}
|
|
2
|
+
{"scenario_id": "order-tracking", "turns": [{"input": "Where is my order #12345?", "expectedResponse": "Let me look up order #12345 for you. I can see it shipped on Monday and is expected to arrive by Thursday."}], "assertions": ["Agent should reference the specific order number", "Agent should provide estimated delivery date"], "expected_trajectory": ["lookup_order", "get_shipping_status"]}
|
|
3
|
+
{"scenario_id": "account-locked", "turns": [{"input": "I can't log into my account", "expectedResponse": "I'm sorry you're having trouble logging in. Let me help you regain access. Can you provide the email address associated with your account?"}, {"input": "It's john@example.com", "expectedResponse": "I've sent a password reset link to john@example.com. Please check your inbox and spam folder. The link expires in 24 hours."}], "assertions": ["Agent should ask for identifying information", "Agent should explain the reset process clearly"], "expected_trajectory": ["verify_identity", "send_reset_link"]}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
{"scenario_id": "frustrated-refund-customer", "input": "I want a refund for my cancelled flight BK-98765", "actor_profile": {"traits": {"personality": "impatient and frustrated", "communication_style": "direct and demanding"}, "context": "Has been waiting 3 days for a refund with no response. Previously had a bad experience with customer service.", "goal": "Get a full cash refund for cancelled flight BK-98765, not a voucher or credit"}, "max_turns": 10, "assertions": ["Agent should acknowledge the frustration", "Agent should not offer only vouchers when cash refund is requested", "Agent should provide a timeline for the refund"]}
|
|
2
|
+
{"scenario_id": "confused-new-user", "input": "How do I set up my new account?", "actor_profile": {"traits": {"personality": "polite but confused", "communication_style": "asks many follow-up questions", "technical_level": "beginner"}, "context": "First time using the service. Not familiar with technical terminology. English is a second language.", "goal": "Successfully create and configure a new account with basic settings"}, "max_turns": 15, "assertions": ["Agent should use simple non-technical language", "Agent should break instructions into small steps", "Agent should confirm understanding at each step"]}
|
|
3
|
+
{"scenario_id": "edge-case-multi-issue", "input": "I need to change my flight AND get a refund for the hotel that was bundled with it", "actor_profile": {"traits": {"personality": "methodical and detail-oriented", "communication_style": "provides lots of context upfront"}, "context": "Has a bundled flight+hotel booking. Flight was changed by the airline, making the hotel dates wrong. Wants partial refund for hotel and rebooking for flight.", "goal": "Get the flight rebooked to new dates AND get a refund for the hotel nights that no longer align"}, "max_turns": 12, "assertions": ["Agent should handle both issues without losing track", "Agent should clarify which parts are refundable", "Agent should not close the conversation until both issues are resolved"]}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Standalone invoke script for AgentCore Harness.
|
|
3
|
+
Generated by: agentcore create --with-invoke-script
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
pip install boto3
|
|
7
|
+
export HARNESS_ARN="arn:aws:bedrock-agentcore:<region>:<account>:harness/<harness-id>"
|
|
8
|
+
python invoke.py "Hello, what can you do?"
|
|
9
|
+
python invoke.py --raw-events "Hello"
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import argparse
|
|
13
|
+
import json
|
|
14
|
+
import os
|
|
15
|
+
import sys
|
|
16
|
+
import uuid
|
|
17
|
+
|
|
18
|
+
import boto3
|
|
19
|
+
|
|
20
|
+
# --- Configuration ---
|
|
21
|
+
HARNESS_ARN = os.environ.get("HARNESS_ARN", "{{HARNESS_ARN}}")
|
|
22
|
+
REGION = os.environ.get("AWS_REGION", "{{REGION}}")
|
|
23
|
+
SESSION_ID = os.environ.get("SESSION_ID", str(uuid.uuid4()))
|
|
24
|
+
|
|
25
|
+
parser = argparse.ArgumentParser(description="Invoke an AgentCore Harness")
|
|
26
|
+
parser.add_argument("prompt", nargs="?", default="Hello!", help="Prompt to send to the agent")
|
|
27
|
+
parser.add_argument("--raw-events", action="store_true", help="Print raw streaming events as JSON")
|
|
28
|
+
parser.add_argument("--session-id", default=SESSION_ID, help="Session ID for conversation continuity")
|
|
29
|
+
args = parser.parse_args()
|
|
30
|
+
|
|
31
|
+
client = boto3.client("bedrock-agentcore", region_name=REGION)
|
|
32
|
+
|
|
33
|
+
response = client.invoke_harness(
|
|
34
|
+
harnessArn=HARNESS_ARN,
|
|
35
|
+
runtimeSessionId=args.session_id,
|
|
36
|
+
messages=[
|
|
37
|
+
{
|
|
38
|
+
"role": "user",
|
|
39
|
+
"content": [{"text": args.prompt}],
|
|
40
|
+
}
|
|
41
|
+
],
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
for event in response["stream"]:
|
|
45
|
+
if args.raw_events:
|
|
46
|
+
print(json.dumps(event, default=str))
|
|
47
|
+
else:
|
|
48
|
+
if "contentBlockStart" in event:
|
|
49
|
+
start = event["contentBlockStart"].get("start", {})
|
|
50
|
+
if "toolUse" in start:
|
|
51
|
+
tool = start["toolUse"]
|
|
52
|
+
print(f"\n🔧 Tool: {tool.get('name', 'unknown')}", flush=True)
|
|
53
|
+
elif "contentBlockDelta" in event:
|
|
54
|
+
delta = event["contentBlockDelta"].get("delta", {})
|
|
55
|
+
if "text" in delta:
|
|
56
|
+
print(delta["text"], end="", flush=True)
|
|
57
|
+
elif "messageStop" in event:
|
|
58
|
+
stop_reason = event["messageStop"].get("stopReason", "")
|
|
59
|
+
if stop_reason == "end_turn":
|
|
60
|
+
print()
|
|
61
|
+
elif "metadata" in event:
|
|
62
|
+
usage = event["metadata"].get("usage", {})
|
|
63
|
+
metrics = event["metadata"].get("metrics", {})
|
|
64
|
+
latency = metrics.get("latencyMs", 0) / 1000
|
|
65
|
+
print(
|
|
66
|
+
f"\n⚡ {usage.get('inputTokens', 0)} in · "
|
|
67
|
+
f"{usage.get('outputTokens', 0)} out · "
|
|
68
|
+
f"{latency:.1f}s",
|
|
69
|
+
file=sys.stderr,
|
|
70
|
+
)
|
|
71
|
+
elif "internalServerException" in event:
|
|
72
|
+
print(f"\nError: {event['internalServerException']}", file=sys.stderr)
|
|
73
|
+
|
|
74
|
+
print(f"\n🔗 Session: {args.session_id}", file=sys.stderr)
|