@aws/nx-plugin 1.0.0-rc.21 → 1.0.0-rc.23
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/package.json +1 -1
- package/src/license/generator.js +22 -8
- package/src/license/generator.js.map +1 -1
- package/src/license/known-exceptions.d.ts +1 -0
- package/src/license/known-exceptions.js +13 -1
- package/src/license/known-exceptions.js.map +1 -1
- package/src/py/agent/__snapshots__/generator.spec.ts.snap +167 -3
- package/src/py/agent/a2a-connection/files/langchain/agent-connection/app/__targetAgentSnakeCase___client_langchain.py.template +28 -0
- package/src/py/agent/a2a-connection/generator.js +59 -31
- package/src/py/agent/a2a-connection/generator.js.map +1 -1
- package/src/py/agent/files/a2a-langchain/main.py.template +89 -0
- package/src/py/agent/files/ag-ui-langchain/main.py.template +83 -0
- package/src/py/agent/files/common-langchain/agent.py.template +30 -0
- package/src/py/agent/files/http-langchain/main.py.template +84 -0
- package/src/py/agent/gateway-connection/files/langchain/agent-connection/app/__gatewaySnakeCase___client_langchain.py.template +34 -0
- package/src/py/agent/gateway-connection/generator.js +15 -9
- package/src/py/agent/gateway-connection/generator.js.map +1 -1
- package/src/py/agent/generator.js +69 -14
- package/src/py/agent/generator.js.map +1 -1
- package/src/py/agent/mcp-connection/files/langchain/agent-connection/app/__mcpServerSnakeCase___client_langchain.py.template +30 -0
- package/src/py/agent/mcp-connection/generator.js +15 -11
- package/src/py/agent/mcp-connection/generator.js.map +1 -1
- package/src/py/agent/react-connection/serve-local.js +9 -1
- package/src/py/agent/react-connection/serve-local.js.map +1 -1
- package/src/py/agent/schema.d.ts +1 -1
- package/src/py/agent/schema.json +1 -1
- package/src/py/dynamodb/agent-connection/generator.js +1 -1
- package/src/py/dynamodb/agent-connection/generator.js.map +1 -1
- package/src/py/dynamodb/fast-api-connection/generator.js +1 -1
- package/src/py/dynamodb/fast-api-connection/generator.js.map +1 -1
- package/src/py/dynamodb/mcp-server-connection/generator.js +1 -1
- package/src/py/dynamodb/mcp-server-connection/generator.js.map +1 -1
- package/src/py/mcp-server/__snapshots__/generator.spec.ts.snap +1 -1
- package/src/py/project/generator.d.ts +14 -1
- package/src/py/project/generator.js +12 -2
- package/src/py/project/generator.js.map +1 -1
- package/src/ts/agent/__snapshots__/generator.spec.ts.snap +1 -1
- package/src/ts/mcp-server/__snapshots__/generator.spec.ts.snap +1 -1
- package/src/ts/rdb/__snapshots__/generator.spec.ts.snap +4 -0
- package/src/ts/rdb/files/src/utils.ts.template +2 -0
- package/src/ts/react-website/app/__snapshots__/generator.spec.ts.snap +25 -72
- package/src/ts/react-website/cognito-auth/__snapshots__/generator.terraform.spec.ts.snap +17 -4
- package/src/utils/agent-connection/agent-connection.d.ts +58 -9
- package/src/utils/agent-connection/agent-connection.js +146 -13
- package/src/utils/agent-connection/agent-connection.js.map +1 -1
- package/src/utils/agent-connection/files/py-core-langchain/a2a/agentcore_a2a_client_langchain.py.template +99 -0
- package/src/utils/agent-connection/files/py-core-langchain/gateway/agentcore_gateway_mcp_client_langchain.py.template +57 -0
- package/src/utils/agent-connection/files/py-core-langchain/mcp/agentcore_mcp_client_langchain.py.template +64 -0
- package/src/utils/agent-core-constructs/files/terraform/core/agent-core/runtime.tf.template +1 -1
- package/src/utils/identity-constructs/files/terraform/core/user-identity/add-callback-url/add-callback-url.tf.template +17 -4
- package/src/utils/names.d.ts +16 -0
- package/src/utils/names.js +18 -1
- package/src/utils/names.js.map +1 -1
- package/src/utils/py.d.ts +14 -1
- package/src/utils/py.js +34 -7
- package/src/utils/py.js.map +1 -1
- package/src/utils/versions.d.ts +6 -0
- package/src/utils/versions.js +6 -0
- package/src/utils/versions.js.map +1 -1
package/package.json
CHANGED
package/src/license/generator.js
CHANGED
|
@@ -7,15 +7,16 @@ exports.licenseGenerator = licenseGenerator;
|
|
|
7
7
|
* SPDX-License-Identifier: Apache-2.0
|
|
8
8
|
*/
|
|
9
9
|
const devkit_1 = require("@nx/devkit");
|
|
10
|
-
const generator_1 = require("../py/
|
|
11
|
-
const generator_2 = require("../
|
|
10
|
+
const generator_1 = require("../py/agent/generator");
|
|
11
|
+
const generator_2 = require("../py/mcp-server/generator");
|
|
12
|
+
const generator_3 = require("../ts/mcp-server/generator");
|
|
12
13
|
const utils_1 = require("../utils/config/utils");
|
|
13
14
|
const format_1 = require("../utils/format");
|
|
14
15
|
const metrics_1 = require("../utils/metrics");
|
|
15
16
|
const nx_1 = require("../utils/nx");
|
|
16
17
|
const config_1 = require("./config");
|
|
17
18
|
const known_exceptions_1 = require("./known-exceptions");
|
|
18
|
-
const
|
|
19
|
+
const generator_4 = require("./sync/generator");
|
|
19
20
|
exports.LICENSE_GENERATOR_INFO = (0, nx_1.getGeneratorInfo)(__filename);
|
|
20
21
|
async function licenseGenerator(tree, options) {
|
|
21
22
|
const { license, copyrightHolder } = options;
|
|
@@ -44,8 +45,8 @@ async function licenseGenerator(tree, options) {
|
|
|
44
45
|
const lintTargetDefault = {
|
|
45
46
|
...nxJson.targetDefaults?.lint,
|
|
46
47
|
syncGenerators: [
|
|
47
|
-
...(nxJson.targetDefaults?.lint?.syncGenerators ?? []).filter((g) => g !==
|
|
48
|
-
|
|
48
|
+
...(nxJson.targetDefaults?.lint?.syncGenerators ?? []).filter((g) => g !== generator_4.SYNC_GENERATOR_NAME),
|
|
49
|
+
generator_4.SYNC_GENERATOR_NAME,
|
|
49
50
|
],
|
|
50
51
|
};
|
|
51
52
|
const updatedNxJson = {
|
|
@@ -95,9 +96,15 @@ const writeLicenseCheckTarget = async (tree) => {
|
|
|
95
96
|
const addExceptionsForExistingProjects = async (tree) => {
|
|
96
97
|
const projects = (0, devkit_1.getProjects)(tree);
|
|
97
98
|
let needsMcp = false;
|
|
99
|
+
// A LangChain AG-UI agent pulls jsonpatch/jsonpointer (BSD-3-Clause but with
|
|
100
|
+
// only free-text metadata) via langchain-core. The py#agent generator adds
|
|
101
|
+
// these exceptions itself, but if the license generator runs afterwards (or
|
|
102
|
+
// the agent predates the dependency-check block) they may be missing, so
|
|
103
|
+
// re-assert them here when such an agent exists.
|
|
104
|
+
let needsLangchain = false;
|
|
98
105
|
const mcpIds = [
|
|
99
|
-
|
|
100
|
-
|
|
106
|
+
generator_3.TS_MCP_SERVER_GENERATOR_INFO.id,
|
|
107
|
+
generator_2.PY_MCP_SERVER_GENERATOR_INFO.id,
|
|
101
108
|
];
|
|
102
109
|
for (const [, config] of projects) {
|
|
103
110
|
const components = config.metadata?.components ??
|
|
@@ -108,9 +115,16 @@ const addExceptionsForExistingProjects = async (tree) => {
|
|
|
108
115
|
if (typeof gen === 'string' && mcpIds.includes(gen)) {
|
|
109
116
|
needsMcp = true;
|
|
110
117
|
}
|
|
118
|
+
if (gen === generator_1.PY_AGENT_GENERATOR_INFO.id &&
|
|
119
|
+
comp.framework === 'langchain') {
|
|
120
|
+
needsLangchain = true;
|
|
121
|
+
}
|
|
111
122
|
}
|
|
112
123
|
}
|
|
113
|
-
const exceptions = [
|
|
124
|
+
const exceptions = [
|
|
125
|
+
...(needsMcp ? known_exceptions_1.MCP_INSPECTOR_EXCEPTIONS : []),
|
|
126
|
+
...(needsLangchain ? known_exceptions_1.AG_UI_LANGGRAPH_EXCEPTIONS : []),
|
|
127
|
+
];
|
|
114
128
|
if (exceptions.length > 0) {
|
|
115
129
|
await (0, config_1.ensureLicenseExceptions)(tree, exceptions);
|
|
116
130
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../../../packages/nx-plugin/src/license/generator.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../../../packages/nx-plugin/src/license/generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.MCP_INSPECTOR_EXCEPTIONS = void 0;
|
|
3
|
+
exports.AG_UI_LANGGRAPH_EXCEPTIONS = exports.MCP_INSPECTOR_EXCEPTIONS = void 0;
|
|
4
4
|
exports.MCP_INSPECTOR_EXCEPTIONS = [
|
|
5
5
|
{
|
|
6
6
|
package: '@modelcontextprotocol/inspector',
|
|
@@ -23,4 +23,16 @@ exports.MCP_INSPECTOR_EXCEPTIONS = [
|
|
|
23
23
|
spdx: 'Apache-2.0',
|
|
24
24
|
},
|
|
25
25
|
];
|
|
26
|
+
exports.AG_UI_LANGGRAPH_EXCEPTIONS = [
|
|
27
|
+
{
|
|
28
|
+
package: 'jsonpatch',
|
|
29
|
+
reason: 'Unconditional dependency of langchain-core. Genuinely BSD-3-Clause (LICENSE matches the SPDX BSD-3-Clause template), but the wheel only carries the free-text "Modified BSD License" metadata, not an SPDX expression.',
|
|
30
|
+
spdx: 'BSD-3-Clause',
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
package: 'jsonpointer',
|
|
34
|
+
reason: 'Transitive dependency of jsonpatch (via langchain-core). Genuinely BSD-3-Clause (LICENSE matches the SPDX BSD-3-Clause template), but the wheel only carries the free-text "Modified BSD License" metadata, not an SPDX expression.',
|
|
35
|
+
spdx: 'BSD-3-Clause',
|
|
36
|
+
},
|
|
37
|
+
];
|
|
26
38
|
//# sourceMappingURL=known-exceptions.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"known-exceptions.js","sourceRoot":"","sources":["../../../../../packages/nx-plugin/src/license/known-exceptions.ts"],"names":[],"mappings":";;;AAMa,QAAA,wBAAwB,GAA+B;IAClE;QACE,OAAO,EAAE,iCAAiC;QAC1C,MAAM,EACJ,2EAA2E;QAC7E,IAAI,EAAE,YAAY;KACnB;IACD;QACE,OAAO,EAAE,qCAAqC;QAC9C,MAAM,EACJ,2EAA2E;QAC7E,IAAI,EAAE,YAAY;KACnB;IACD;QACE,OAAO,EAAE,wCAAwC;QACjD,MAAM,EACJ,2EAA2E;QAC7E,IAAI,EAAE,YAAY;KACnB;IACD;QACE,OAAO,EAAE,wCAAwC;QACjD,MAAM,EACJ,2EAA2E;QAC7E,IAAI,EAAE,YAAY;KACnB;CACF,CAAC"}
|
|
1
|
+
{"version":3,"file":"known-exceptions.js","sourceRoot":"","sources":["../../../../../packages/nx-plugin/src/license/known-exceptions.ts"],"names":[],"mappings":";;;AAMa,QAAA,wBAAwB,GAA+B;IAClE;QACE,OAAO,EAAE,iCAAiC;QAC1C,MAAM,EACJ,2EAA2E;QAC7E,IAAI,EAAE,YAAY;KACnB;IACD;QACE,OAAO,EAAE,qCAAqC;QAC9C,MAAM,EACJ,2EAA2E;QAC7E,IAAI,EAAE,YAAY;KACnB;IACD;QACE,OAAO,EAAE,wCAAwC;QACjD,MAAM,EACJ,2EAA2E;QAC7E,IAAI,EAAE,YAAY;KACnB;IACD;QACE,OAAO,EAAE,wCAAwC;QACjD,MAAM,EACJ,2EAA2E;QAC7E,IAAI,EAAE,YAAY;KACnB;CACF,CAAC;AAEW,QAAA,0BAA0B,GAA+B;IACpE;QACE,OAAO,EAAE,WAAW;QACpB,MAAM,EACJ,wNAAwN;QAC1N,IAAI,EAAE,cAAc;KACrB;IACD;QACE,OAAO,EAAE,aAAa;QACtB,MAAM,EACJ,qOAAqO;QACvO,IAAI,EAAE,cAAc;KACrB;CACF,CAAC"}
|
|
@@ -569,6 +569,170 @@ await chatLoop(new TestProjectAgentAdapter(), process.env.URL ?? '');
|
|
|
569
569
|
"
|
|
570
570
|
`;
|
|
571
571
|
|
|
572
|
+
exports[`py#agent generator > langchain framework > should match snapshot for langchain generated files > langchain-__init__.py 1`] = `""`;
|
|
573
|
+
|
|
574
|
+
exports[`py#agent generator > langchain framework > should match snapshot for langchain generated files > langchain-agent.py 1`] = `
|
|
575
|
+
"import os
|
|
576
|
+
|
|
577
|
+
from langchain.agents import create_agent
|
|
578
|
+
from langchain_aws import ChatBedrockConverse
|
|
579
|
+
from langchain_core.tools import tool
|
|
580
|
+
from langgraph.checkpoint.memory import InMemorySaver
|
|
581
|
+
|
|
582
|
+
REGION = os.environ.get("AWS_REGION", "us-east-1")
|
|
583
|
+
MODEL_ID = os.environ.get("MODEL_ID", "global.anthropic.claude-haiku-4-5-20251001-v1:0")
|
|
584
|
+
|
|
585
|
+
|
|
586
|
+
@tool
|
|
587
|
+
def subtract(a: int, b: int) -> int:
|
|
588
|
+
"""Subtract b from a."""
|
|
589
|
+
return a - b
|
|
590
|
+
|
|
591
|
+
|
|
592
|
+
def get_agent():
|
|
593
|
+
model = ChatBedrockConverse(model=MODEL_ID, region_name=REGION)
|
|
594
|
+
# Swap InMemorySaver for a durable checkpointer in a multi-replica deployment.
|
|
595
|
+
return create_agent(
|
|
596
|
+
model=model,
|
|
597
|
+
tools=[subtract],
|
|
598
|
+
system_prompt="""
|
|
599
|
+
You are a mathematical wizard.
|
|
600
|
+
Use your tools for mathematical tasks.
|
|
601
|
+
Refer to tools as your 'spellbook'.
|
|
602
|
+
""",
|
|
603
|
+
checkpointer=InMemorySaver(),
|
|
604
|
+
)
|
|
605
|
+
"
|
|
606
|
+
`;
|
|
607
|
+
|
|
608
|
+
exports[`py#agent generator > langchain framework > should match snapshot for langchain generated files > langchain-main.py 1`] = `
|
|
609
|
+
"import logging
|
|
610
|
+
import time
|
|
611
|
+
import uuid
|
|
612
|
+
|
|
613
|
+
from ag_ui.core import EventType, RunAgentInput, RunErrorEvent
|
|
614
|
+
from ag_ui.encoder import EventEncoder
|
|
615
|
+
from ag_ui_langgraph import LangGraphAgent
|
|
616
|
+
from fastapi import FastAPI, Request
|
|
617
|
+
from fastapi.middleware.cors import CORSMiddleware
|
|
618
|
+
from fastapi.responses import JSONResponse, StreamingResponse
|
|
619
|
+
from proj_agent_connection import get_current_session_id, session_id_context
|
|
620
|
+
from starlette.middleware.base import BaseHTTPMiddleware
|
|
621
|
+
|
|
622
|
+
from .agent import get_agent
|
|
623
|
+
|
|
624
|
+
logging.basicConfig(level=logging.INFO)
|
|
625
|
+
|
|
626
|
+
SESSION_ID_HEADER = "x-amzn-bedrock-agentcore-runtime-session-id"
|
|
627
|
+
|
|
628
|
+
_graph = get_agent()
|
|
629
|
+
|
|
630
|
+
agui_agent = LangGraphAgent(
|
|
631
|
+
name="SnapshotAgent",
|
|
632
|
+
graph=_graph,
|
|
633
|
+
description="A LangChain/LangGraph Agent exposed via the AG-UI protocol.",
|
|
634
|
+
)
|
|
635
|
+
|
|
636
|
+
|
|
637
|
+
class _SessionIdMiddleware(BaseHTTPMiddleware):
|
|
638
|
+
"""Bind the session ID for this request so downstream MCP / A2A clients forward it on outbound calls."""
|
|
639
|
+
|
|
640
|
+
async def dispatch(self, request: Request, call_next):
|
|
641
|
+
session_id = request.headers.get(SESSION_ID_HEADER) or str(uuid.uuid4())
|
|
642
|
+
with session_id_context(session_id):
|
|
643
|
+
return await call_next(request)
|
|
644
|
+
|
|
645
|
+
|
|
646
|
+
app = FastAPI(title="SnapshotAgent")
|
|
647
|
+
# Allow browser-based AG-UI clients (e.g. a connected React website) to call
|
|
648
|
+
# this agent cross-origin, including the CORS preflight.
|
|
649
|
+
app.add_middleware(
|
|
650
|
+
CORSMiddleware,
|
|
651
|
+
allow_origins=["*"],
|
|
652
|
+
allow_credentials=True,
|
|
653
|
+
allow_methods=["*"],
|
|
654
|
+
allow_headers=["*"],
|
|
655
|
+
)
|
|
656
|
+
app.add_middleware(_SessionIdMiddleware)
|
|
657
|
+
|
|
658
|
+
|
|
659
|
+
@app.post("/invocations")
|
|
660
|
+
async def invocations(request: Request):
|
|
661
|
+
# Validate the body manually since AgentCore may omit Content-Type.
|
|
662
|
+
accept = request.headers.get("accept") or ""
|
|
663
|
+
encoder = EventEncoder(accept=accept)
|
|
664
|
+
raw = await request.body()
|
|
665
|
+
try:
|
|
666
|
+
input_data = RunAgentInput.model_validate_json(raw)
|
|
667
|
+
except Exception as exc:
|
|
668
|
+
message = f"Invalid RunAgentInput: {str(exc)[:200]}"
|
|
669
|
+
|
|
670
|
+
async def _bad():
|
|
671
|
+
yield encoder.encode(
|
|
672
|
+
RunErrorEvent(
|
|
673
|
+
type=EventType.RUN_ERROR, message=message, code="BAD_REQUEST"
|
|
674
|
+
)
|
|
675
|
+
)
|
|
676
|
+
|
|
677
|
+
return StreamingResponse(_bad(), media_type=encoder.get_content_type())
|
|
678
|
+
|
|
679
|
+
session_id = request.headers.get(SESSION_ID_HEADER) or get_current_session_id()
|
|
680
|
+
|
|
681
|
+
async def event_generator():
|
|
682
|
+
# Re-bind the session: the streaming body runs outside the middleware.
|
|
683
|
+
with session_id_context(session_id or str(uuid.uuid4())):
|
|
684
|
+
try:
|
|
685
|
+
async for event in agui_agent.run(input_data):
|
|
686
|
+
yield encoder.encode(event)
|
|
687
|
+
except Exception as e:
|
|
688
|
+
yield encoder.encode(
|
|
689
|
+
RunErrorEvent(
|
|
690
|
+
type=EventType.RUN_ERROR,
|
|
691
|
+
message=str(e)[:300],
|
|
692
|
+
code="AGENT_ERROR",
|
|
693
|
+
)
|
|
694
|
+
)
|
|
695
|
+
|
|
696
|
+
return StreamingResponse(event_generator(), media_type=encoder.get_content_type())
|
|
697
|
+
|
|
698
|
+
|
|
699
|
+
@app.get("/ping")
|
|
700
|
+
async def ping():
|
|
701
|
+
return JSONResponse({"status": "Healthy", "time_of_last_update": int(time.time())})
|
|
702
|
+
"
|
|
703
|
+
`;
|
|
704
|
+
|
|
705
|
+
exports[`py#agent generator > langchain framework > should match snapshot for langchain generated files > langchain-pyproject.toml 1`] = `
|
|
706
|
+
"[project]
|
|
707
|
+
name = "proj.test_project"
|
|
708
|
+
version = "0.1.0"
|
|
709
|
+
dependencies = [
|
|
710
|
+
"proj-agent-connection",
|
|
711
|
+
"aws-lambda-powertools==3.29.0",
|
|
712
|
+
"aws-opentelemetry-distro==0.17.1",
|
|
713
|
+
"bedrock-agentcore==1.14.1",
|
|
714
|
+
"boto3==1.43.29",
|
|
715
|
+
"fastapi==0.137.1",
|
|
716
|
+
"mcp==1.27.2",
|
|
717
|
+
"langchain==1.3.9",
|
|
718
|
+
"langchain-aws==1.5.1",
|
|
719
|
+
"langgraph==1.2.5",
|
|
720
|
+
"ag-ui-protocol==0.1.19",
|
|
721
|
+
"ag-ui-langgraph==0.0.42",
|
|
722
|
+
"uvicorn==0.49.0"
|
|
723
|
+
]
|
|
724
|
+
|
|
725
|
+
[dependency-groups]
|
|
726
|
+
dev = [ "fastapi[standard]==0.137.1" ]
|
|
727
|
+
|
|
728
|
+
[tool.uv]
|
|
729
|
+
dev-dependencies = [ ]
|
|
730
|
+
|
|
731
|
+
[tool.uv.sources.proj-agent-connection]
|
|
732
|
+
workspace = true
|
|
733
|
+
"
|
|
734
|
+
`;
|
|
735
|
+
|
|
572
736
|
exports[`py#agent generator > should match snapshot for BedrockAgentCoreRuntime generated constructs files > agent-Dockerfile 1`] = `
|
|
573
737
|
"FROM public.ecr.aws/docker/library/python:3.14-slim
|
|
574
738
|
|
|
@@ -1205,7 +1369,7 @@ initialize_request = json.dumps({
|
|
|
1205
1369
|
},
|
|
1206
1370
|
})
|
|
1207
1371
|
|
|
1208
|
-
deadline = time.time() +
|
|
1372
|
+
deadline = time.time() + 5 * 60
|
|
1209
1373
|
while True:
|
|
1210
1374
|
try:
|
|
1211
1375
|
client.invoke_agent_runtime(
|
|
@@ -1383,7 +1547,7 @@ exports[`py#agent generator > should match snapshot for generated files > update
|
|
|
1383
1547
|
name = "proj.test_project"
|
|
1384
1548
|
version = "0.1.0"
|
|
1385
1549
|
dependencies = [
|
|
1386
|
-
"proj
|
|
1550
|
+
"proj-agent-connection",
|
|
1387
1551
|
"aws-lambda-powertools==3.29.0",
|
|
1388
1552
|
"aws-opentelemetry-distro==0.17.1",
|
|
1389
1553
|
"bedrock-agentcore==1.14.1",
|
|
@@ -1401,7 +1565,7 @@ dev = [ "fastapi[standard]==0.137.1" ]
|
|
|
1401
1565
|
[tool.uv]
|
|
1402
1566
|
dev-dependencies = [ ]
|
|
1403
1567
|
|
|
1404
|
-
[tool.uv.sources.
|
|
1568
|
+
[tool.uv.sources.proj-agent-connection]
|
|
1405
1569
|
workspace = true
|
|
1406
1570
|
"
|
|
1407
1571
|
`;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
from <%- agentConnectionModuleName %>.core.agentcore_a2a_client_langchain import (
|
|
4
|
+
AgentCoreA2aClientLangChain,
|
|
5
|
+
)
|
|
6
|
+
from <%- agentConnectionModuleName %>.core.runtime_config import (
|
|
7
|
+
get_agentcore_runtime_config,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class <%- targetAgentClassName %>ClientLangChain:
|
|
12
|
+
"""LangChain client for the <%- targetAgentClassName %> A2A agent."""
|
|
13
|
+
|
|
14
|
+
@staticmethod
|
|
15
|
+
def create():
|
|
16
|
+
if os.environ.get("SERVE_LOCAL") == "true":
|
|
17
|
+
return AgentCoreA2aClientLangChain.without_auth(
|
|
18
|
+
"http://localhost:<%- targetAgentPort %>/"
|
|
19
|
+
)
|
|
20
|
+
config = get_agentcore_runtime_config()
|
|
21
|
+
agent_runtime_arn = config.get("agentRuntimes", {}).get(
|
|
22
|
+
"<%- targetAgentClassName %>"
|
|
23
|
+
)
|
|
24
|
+
if not agent_runtime_arn:
|
|
25
|
+
raise RuntimeError(
|
|
26
|
+
"No connected agent runtime named '<%- targetAgentClassName %>' found in runtime configuration."
|
|
27
|
+
)
|
|
28
|
+
return AgentCoreA2aClientLangChain.with_iam_auth(agent_runtime_arn)
|
|
@@ -15,6 +15,25 @@ const nx_1 = require("../../../utils/nx");
|
|
|
15
15
|
const py_1 = require("../../../utils/py");
|
|
16
16
|
/** Prefix a GritQL pattern with `language python` */
|
|
17
17
|
const py = (pattern) => `language python\n${pattern}`;
|
|
18
|
+
/** The module each framework imports the `tool` decorator from. */
|
|
19
|
+
const TOOL_IMPORT_MODULE = {
|
|
20
|
+
strands: 'strands',
|
|
21
|
+
langchain: 'langchain_core.tools',
|
|
22
|
+
};
|
|
23
|
+
/** The GritQL pattern matching each framework's agent constructor. */
|
|
24
|
+
const AGENT_CONSTRUCTOR = {
|
|
25
|
+
strands: 'yield Agent($_)',
|
|
26
|
+
langchain: 'create_agent($_)',
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* The A2A transport dependency each framework's Layer-2 client needs. Strands
|
|
30
|
+
* wraps strands' `A2AAgent` (strands-agents[a2a]); LangChain drives the a2a SDK
|
|
31
|
+
* directly (a2a-sdk) and must not pull Strands in.
|
|
32
|
+
*/
|
|
33
|
+
const A2A_TRANSPORT_DEP = {
|
|
34
|
+
strands: 'strands-agents[a2a]',
|
|
35
|
+
langchain: 'a2a-sdk',
|
|
36
|
+
};
|
|
18
37
|
exports.PY_AGENT_A2A_CONNECTION_GENERATOR_INFO = (0, nx_1.getGeneratorInfo)(__filename);
|
|
19
38
|
const pyAgentA2aConnectionGenerator = async (tree, options) => {
|
|
20
39
|
const sourceProject = (0, nx_1.readProjectConfigurationUnqualified)(tree, options.sourceProject);
|
|
@@ -35,24 +54,31 @@ const pyAgentA2aConnectionGenerator = async (tree, options) => {
|
|
|
35
54
|
const targetAgentClassName = targetAgentComponent.rc;
|
|
36
55
|
const targetAgentSnakeCase = (0, names_1.snakeCase)(targetAgentClassName);
|
|
37
56
|
const targetAgentPort = targetAgentComponent.port ?? 9000;
|
|
57
|
+
// The source agent's framework drives everything that varies: the client
|
|
58
|
+
// naming + app template (shared with the mcp/gateway generators via
|
|
59
|
+
// PY_CLIENT_NAMING), the A2A transport dep (see A2A_TRANSPORT_DEP), and the
|
|
60
|
+
// agent.py transform below. Each framework wraps its own A2A Layer-2 client
|
|
61
|
+
// (Strands' A2AAgent vs an a2a-sdk-only client) over the shared,
|
|
62
|
+
// framework-agnostic A2A client config. Keyed on the framework, not a
|
|
63
|
+
// boolean, so a third framework stays additive.
|
|
64
|
+
const framework = (0, agent_connection_1.resolveAgentFramework)(agentComponent.framework);
|
|
65
|
+
const naming = agent_connection_1.PY_CLIENT_NAMING[framework];
|
|
38
66
|
// 1. Ensure the shared Python agent-connection project exists + has the
|
|
39
|
-
// A2A core client and its shared SigV4 auth helper.
|
|
67
|
+
// A2A core client (framework Layer-2) and its shared SigV4 auth helper.
|
|
40
68
|
await (0, agent_connection_1.ensurePythonAgentConnectionProject)(tree);
|
|
41
|
-
await (0, agent_connection_1.addPythonCoreClient)(tree, 'a2a');
|
|
69
|
+
await (0, agent_connection_1.addPythonCoreClient)(tree, 'a2a', framework);
|
|
42
70
|
const agentConnectionProjectDir = (0, agent_connection_1.getPythonAgentConnectionProjectDir)(tree);
|
|
43
71
|
const agentConnectionModuleName = (0, agent_connection_1.getPythonAgentConnectionModuleName)(tree);
|
|
44
|
-
|
|
45
|
-
//
|
|
46
|
-
// Strands A2A extra the framework's A2A client needs (the base strands-agents
|
|
47
|
-
// dependency is added by addPythonCoreClient).
|
|
72
|
+
// A2A client config + shared auth helper deps, plus the framework's A2A
|
|
73
|
+
// transport dep (see A2A_TRANSPORT_DEP).
|
|
48
74
|
(0, py_1.addDependenciesToPyProjectToml)(tree, agentConnectionProjectDir, [
|
|
49
75
|
'boto3',
|
|
50
76
|
'httpx',
|
|
51
|
-
|
|
77
|
+
A2A_TRANSPORT_DEP[framework],
|
|
52
78
|
]);
|
|
53
79
|
// 2. Generate the per-connection client into the shared agent-connection project
|
|
54
80
|
const appDir = (0, devkit_1.joinPathFragments)(agentConnectionProjectDir, agentConnectionModuleName, 'app');
|
|
55
|
-
(0, devkit_1.generateFiles)(tree, (0, devkit_1.joinPathFragments)(__dirname, 'files',
|
|
81
|
+
(0, devkit_1.generateFiles)(tree, (0, devkit_1.joinPathFragments)(__dirname, 'files', naming.appTemplateSubdir), appDir, {
|
|
56
82
|
targetAgentSnakeCase,
|
|
57
83
|
targetAgentClassName,
|
|
58
84
|
targetAgentPort,
|
|
@@ -65,20 +91,20 @@ const pyAgentA2aConnectionGenerator = async (tree, options) => {
|
|
|
65
91
|
}
|
|
66
92
|
// Add re-export to module __init__.py
|
|
67
93
|
const moduleInitPath = (0, devkit_1.joinPathFragments)(agentConnectionProjectDir, agentConnectionModuleName, '__init__.py');
|
|
68
|
-
await (0, agent_connection_1.addPythonReExport)(tree, moduleInitPath, `.app.${targetAgentSnakeCase}
|
|
94
|
+
await (0, agent_connection_1.addPythonReExport)(tree, moduleInitPath, `.app.${targetAgentSnakeCase}_client_${naming.clientModuleSuffix}`, `${targetAgentClassName}Client${naming.clientClassSuffix}`);
|
|
69
95
|
// 3. Transform agent.py to add the A2A client import + wrap it as a tool
|
|
70
96
|
const agentSourceDir = (0, devkit_1.joinPathFragments)(sourceProject.root, agentComponent.path ?? 'src');
|
|
71
97
|
const agentFilePath = (0, devkit_1.joinPathFragments)(agentSourceDir, 'agent.py');
|
|
72
98
|
if (tree.exists(agentFilePath)) {
|
|
73
|
-
const clientClassName = `${targetAgentClassName}
|
|
99
|
+
const clientClassName = `${targetAgentClassName}Client${naming.clientClassSuffix}`;
|
|
74
100
|
const clientVarName = targetAgentSnakeCase;
|
|
75
101
|
const toolName = `ask_${targetAgentSnakeCase}`;
|
|
76
|
-
await addImportToAgentFile(tree, agentFilePath, agentConnectionModuleName, clientClassName);
|
|
77
|
-
await addToolToAgent(tree, agentFilePath, toolName);
|
|
78
|
-
await addClientToolToGetAgent(tree, agentFilePath, clientClassName, clientVarName, toolName, targetAgentClassName);
|
|
102
|
+
await addImportToAgentFile(tree, agentFilePath, agentConnectionModuleName, clientClassName, framework);
|
|
103
|
+
await addToolToAgent(tree, agentFilePath, toolName, framework);
|
|
104
|
+
await addClientToolToGetAgent(tree, agentFilePath, clientClassName, clientVarName, toolName, targetAgentClassName, framework);
|
|
79
105
|
}
|
|
80
106
|
// 4. Add workspace dependency from agent project to agent-connection project
|
|
81
|
-
(0, py_1.addWorkspaceDependencyToPyProject)(tree, sourceProject
|
|
107
|
+
(0, py_1.addWorkspaceDependencyToPyProject)(tree, sourceProject, (0, agent_connection_1.getPythonAgentConnectionProject)(tree));
|
|
82
108
|
// 5. Set up serve-local target dependencies — chain onto the target agent
|
|
83
109
|
const agentName = agentComponent.name ?? 'agent';
|
|
84
110
|
const serveLocalTargetName = `${agentName}-serve-local`;
|
|
@@ -101,22 +127,23 @@ const pyAgentA2aConnectionGenerator = async (tree, options) => {
|
|
|
101
127
|
exports.pyAgentA2aConnectionGenerator = pyAgentA2aConnectionGenerator;
|
|
102
128
|
/**
|
|
103
129
|
* Add imports to agent.py:
|
|
104
|
-
* - `tool` from `strands`
|
|
130
|
+
* - `tool` (from `strands`, or `langchain_core.tools` for LangChain agents)
|
|
105
131
|
* - the per-connection client class from the shared agent-connection module
|
|
106
132
|
*/
|
|
107
|
-
const addImportToAgentFile = async (tree, filePath, agentConnectionModuleName, clientClassName) => {
|
|
108
|
-
await (0, ast_1.addPythonDestructuredImport)(tree, filePath, ['tool'],
|
|
133
|
+
const addImportToAgentFile = async (tree, filePath, agentConnectionModuleName, clientClassName, framework) => {
|
|
134
|
+
await (0, ast_1.addPythonDestructuredImport)(tree, filePath, ['tool'], TOOL_IMPORT_MODULE[framework]);
|
|
109
135
|
await (0, ast_1.addPythonDestructuredImport)(tree, filePath, [clientClassName], agentConnectionModuleName);
|
|
110
136
|
};
|
|
111
137
|
/**
|
|
112
138
|
* Add the A2A tool to the Agent's tools array using GritQL.
|
|
113
139
|
*
|
|
114
|
-
* Scoped
|
|
115
|
-
*
|
|
140
|
+
* Scoped to the framework's agent constructor so unrelated `tools=` keyword
|
|
141
|
+
* arguments elsewhere in the file are not touched.
|
|
116
142
|
*/
|
|
117
|
-
const addToolToAgent = async (tree, filePath, toolName) => {
|
|
143
|
+
const addToolToAgent = async (tree, filePath, toolName, framework) => {
|
|
144
|
+
const scope = AGENT_CONSTRUCTOR[framework];
|
|
118
145
|
await (0, ast_1.applyGritQL)(tree, filePath, py(`\`tools=$old\` where {
|
|
119
|
-
$old <: within
|
|
146
|
+
$old <: within \`${scope}\`,
|
|
120
147
|
$old <: not contains \`${toolName}\`,
|
|
121
148
|
if ($old <: \`[]\`) {
|
|
122
149
|
$old => \`[${toolName}]\`
|
|
@@ -127,19 +154,19 @@ const addToolToAgent = async (tree, filePath, toolName) => {
|
|
|
127
154
|
};
|
|
128
155
|
/**
|
|
129
156
|
* Wrap the get_agent body so the remote A2A client is created and exposed
|
|
130
|
-
* as a `@tool`-decorated closure before
|
|
157
|
+
* as a `@tool`-decorated closure before constructing the Agent.
|
|
131
158
|
*
|
|
132
159
|
* Unlike MCP clients, A2A clients aren't context managers — we don't need
|
|
133
160
|
* a `with` block around them. Creation + tool definition happen at the
|
|
134
|
-
* top of the function body.
|
|
161
|
+
* top of the function body, anchored on the framework's agent constructor.
|
|
135
162
|
*/
|
|
136
|
-
const addClientToolToGetAgent = async (tree, filePath, clientClassName, clientVarName, toolName, targetAgentClassName) => {
|
|
163
|
+
const addClientToolToGetAgent = async (tree, filePath, clientClassName, clientVarName, toolName, targetAgentClassName, framework) => {
|
|
137
164
|
if (await (0, ast_1.matchGritQL)(tree, filePath, py(`\`${clientClassName}.create\``))) {
|
|
138
165
|
return;
|
|
139
166
|
}
|
|
140
|
-
//
|
|
141
|
-
//
|
|
142
|
-
//
|
|
167
|
+
// Both frameworks' tools are @tool-decorated callables (the decorator's
|
|
168
|
+
// import differs, handled in addImportToAgentFile), defined inline in
|
|
169
|
+
// get_agent. The client is directly callable, returning the remote's reply.
|
|
143
170
|
const toolBlock = `${clientVarName} = ${clientClassName}.create()
|
|
144
171
|
|
|
145
172
|
@tool
|
|
@@ -147,12 +174,13 @@ const addClientToolToGetAgent = async (tree, filePath, clientClassName, clientVa
|
|
|
147
174
|
"""Delegate a question to the remote ${targetAgentClassName} A2A agent and return its reply."""
|
|
148
175
|
return str(${clientVarName}(prompt))
|
|
149
176
|
`;
|
|
150
|
-
// Prepend client creation + tool definition to the function body
|
|
151
|
-
// This works whether or not a prior MCP
|
|
152
|
-
// insert before any existing statements.
|
|
177
|
+
// Prepend client creation + tool definition to the function body, anchored on
|
|
178
|
+
// the framework's agent constructor. This works whether or not a prior MCP
|
|
179
|
+
// block is present since we insert before any existing statements.
|
|
180
|
+
const anchor = AGENT_CONSTRUCTOR[framework];
|
|
153
181
|
await (0, ast_1.applyGritQL)(tree, filePath, py(`\`def get_agent($params):
|
|
154
182
|
$body\` where {
|
|
155
|
-
$body <: contains
|
|
183
|
+
$body <: contains \`${anchor}\`,
|
|
156
184
|
$body <: not contains \`${clientClassName}.create\`
|
|
157
185
|
} => \`def get_agent($params):
|
|
158
186
|
${toolBlock}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../../../../../packages/nx-plugin/src/py/agent/a2a-connection/generator.ts"],"names":[],"mappings":";;;AAAA;;;GAGG;AACH,uCAQoB;AACpB,
|
|
1
|
+
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../../../../../packages/nx-plugin/src/py/agent/a2a-connection/generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
3
|
+
import uuid
|
|
4
|
+
|
|
5
|
+
from a2a.server.agent_execution import AgentExecutor, RequestContext
|
|
6
|
+
from a2a.server.apps import A2AStarletteApplication
|
|
7
|
+
from a2a.server.events import EventQueue
|
|
8
|
+
from a2a.server.request_handlers import DefaultRequestHandler
|
|
9
|
+
from a2a.server.tasks import InMemoryTaskStore, TaskUpdater
|
|
10
|
+
from a2a.types import AgentCapabilities, AgentCard, Part, TextPart
|
|
11
|
+
from a2a.utils import new_task
|
|
12
|
+
from fastapi import FastAPI, Request
|
|
13
|
+
from starlette.middleware.base import BaseHTTPMiddleware
|
|
14
|
+
|
|
15
|
+
from <%- agentConnectionModuleName %> import get_current_session_id, session_id_context
|
|
16
|
+
|
|
17
|
+
from .agent import get_agent
|
|
18
|
+
|
|
19
|
+
logging.basicConfig(level=logging.INFO)
|
|
20
|
+
|
|
21
|
+
PORT = int(os.environ.get("PORT", "9000"))
|
|
22
|
+
RUNTIME_URL = os.environ.get("AGENTCORE_RUNTIME_URL", f"http://localhost:{PORT}/")
|
|
23
|
+
SESSION_ID_HEADER = "x-amzn-bedrock-agentcore-runtime-session-id"
|
|
24
|
+
DEFAULT_MODES = ["text/plain"]
|
|
25
|
+
|
|
26
|
+
_graph = get_agent()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class _GraphAgentExecutor(AgentExecutor):
|
|
30
|
+
async def execute(self, context: RequestContext, event_queue: EventQueue) -> None:
|
|
31
|
+
if context.message is None:
|
|
32
|
+
raise ValueError("A2A request is missing a message")
|
|
33
|
+
task = context.current_task or new_task(context.message)
|
|
34
|
+
await event_queue.enqueue_event(task)
|
|
35
|
+
updater = TaskUpdater(event_queue, task.id, task.context_id)
|
|
36
|
+
await updater.start_work()
|
|
37
|
+
# The session bound by the middleware drives the LangGraph thread, keeping
|
|
38
|
+
# checkpointed conversation state separate per caller session.
|
|
39
|
+
session_id = get_current_session_id() or task.context_id
|
|
40
|
+
result = await _graph.ainvoke(
|
|
41
|
+
{"messages": [{"role": "user", "content": context.get_user_input()}]},
|
|
42
|
+
{"configurable": {"thread_id": session_id}},
|
|
43
|
+
)
|
|
44
|
+
reply = result["messages"][-1].content
|
|
45
|
+
await updater.add_artifact([Part(TextPart(kind="text", text=reply))])
|
|
46
|
+
await updater.complete()
|
|
47
|
+
|
|
48
|
+
async def cancel(self, context: RequestContext, event_queue: EventQueue) -> None:
|
|
49
|
+
raise NotImplementedError("Cancellation is not supported.")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
_handler = DefaultRequestHandler(
|
|
53
|
+
agent_executor=_GraphAgentExecutor(),
|
|
54
|
+
task_store=InMemoryTaskStore(),
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
_agent_card = AgentCard(
|
|
58
|
+
name="<%= agentNameClassName %>",
|
|
59
|
+
description="A LangChain/LangGraph Agent exposed via the Agent-to-Agent (A2A) protocol.",
|
|
60
|
+
url=RUNTIME_URL,
|
|
61
|
+
version="1.0.0",
|
|
62
|
+
default_input_modes=DEFAULT_MODES,
|
|
63
|
+
default_output_modes=DEFAULT_MODES,
|
|
64
|
+
capabilities=AgentCapabilities(streaming=True),
|
|
65
|
+
skills=[],
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
a2a_app = A2AStarletteApplication(agent_card=_agent_card, http_handler=_handler).build()
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class _SessionIdMiddleware(BaseHTTPMiddleware):
|
|
72
|
+
"""Bind the inbound session (or a fresh UUID) to async context."""
|
|
73
|
+
|
|
74
|
+
async def dispatch(self, request: Request, call_next):
|
|
75
|
+
session_id = request.headers.get(SESSION_ID_HEADER) or str(uuid.uuid4())
|
|
76
|
+
with session_id_context(session_id):
|
|
77
|
+
return await call_next(request)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
app = FastAPI(title="<%= agentNameClassName %>")
|
|
81
|
+
app.add_middleware(_SessionIdMiddleware)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
@app.get("/ping")
|
|
85
|
+
def ping() -> dict[str, str]:
|
|
86
|
+
return {"status": "Healthy"}
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
app.mount("/", a2a_app)
|