From bf89f7255ae388ef3222ab083618fd5a29ffbfd3 Mon Sep 17 00:00:00 2001 From: daniel Date: Sat, 9 May 2026 14:14:38 -0500 Subject: [PATCH] Fix: always load flat secret as primary regardless of labeled secrets --- .../agent_claw_main/tools/google_workspace.py | 4 +- ...173310dace910d7081be6f3a642f7e81dabc06.zip | Bin 0 -> 4022 bytes ...55ee18b849e39c418e8e9cd25dea8c4bf85fc4.zip | Bin 0 -> 3246 bytes ...c8bb3cf79f1ca97c4286cc8e741e774b2ac1ae.zip | Bin 0 -> 3234 bytes cdk/cdk.out/AgentClawStack.assets.json | 22 +- cdk/cdk.out/AgentClawStack.metadata.json | 62 ++-- cdk/cdk.out/AgentClawStack.template.json | 14 +- .../handler.py | 272 ++++++++++++++++++ .../requirements.txt | 1 + .../handler.py | 244 ++++++++++++++++ .../requirements.txt | 1 + .../handler.py | 238 +++++++++++++++ .../requirements.txt | 1 + cdk/cdk.out/manifest.json | 2 +- cdk/cdk.out/tree.json | 2 +- cdk/lib/agent-claw-stack.ts | 5 + 16 files changed, 818 insertions(+), 50 deletions(-) create mode 100644 cdk/cdk.out/.cache/647684a0ff5a7a3df590aa5532173310dace910d7081be6f3a642f7e81dabc06.zip create mode 100644 cdk/cdk.out/.cache/99aabce70089266e2352cb313d55ee18b849e39c418e8e9cd25dea8c4bf85fc4.zip create mode 100644 cdk/cdk.out/.cache/e2e48659a729723ff586b8a7cec8bb3cf79f1ca97c4286cc8e741e774b2ac1ae.zip create mode 100644 cdk/cdk.out/asset.647684a0ff5a7a3df590aa5532173310dace910d7081be6f3a642f7e81dabc06/handler.py create mode 100644 cdk/cdk.out/asset.647684a0ff5a7a3df590aa5532173310dace910d7081be6f3a642f7e81dabc06/requirements.txt create mode 100644 cdk/cdk.out/asset.99aabce70089266e2352cb313d55ee18b849e39c418e8e9cd25dea8c4bf85fc4/handler.py create mode 100644 cdk/cdk.out/asset.99aabce70089266e2352cb313d55ee18b849e39c418e8e9cd25dea8c4bf85fc4/requirements.txt create mode 100644 cdk/cdk.out/asset.e2e48659a729723ff586b8a7cec8bb3cf79f1ca97c4286cc8e741e774b2ac1ae/handler.py create mode 100644 cdk/cdk.out/asset.e2e48659a729723ff586b8a7cec8bb3cf79f1ca97c4286cc8e741e774b2ac1ae/requirements.txt diff --git a/agentclaw/app/agent_claw_main/tools/google_workspace.py b/agentclaw/app/agent_claw_main/tools/google_workspace.py index 00e9a1b..847be1e 100644 --- a/agentclaw/app/agent_claw_main/tools/google_workspace.py +++ b/agentclaw/app/agent_claw_main/tools/google_workspace.py @@ -98,8 +98,8 @@ def _load_all_creds(actor_id: str) -> dict[str, Credentials]: except Exception as e: print(f'[google] list_secrets failed: {e}') - # Backward compat: flat secret path - if not result: + # Always include flat secret as 'primary' if not already in result + if 'primary' not in result: flat = f'agent-claw/google-credentials/{safe}' try: result['primary'] = _load_creds_from_secret(flat) diff --git a/cdk/cdk.out/.cache/647684a0ff5a7a3df590aa5532173310dace910d7081be6f3a642f7e81dabc06.zip b/cdk/cdk.out/.cache/647684a0ff5a7a3df590aa5532173310dace910d7081be6f3a642f7e81dabc06.zip new file mode 100644 index 0000000000000000000000000000000000000000..f1146bda185b8697d5bf2f08053314d4e33c62f4 GIT binary patch literal 4022 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 a{$|bp{z^}akm&CO{!RGayaJSeyZ-=LGN>8= literal 0 HcmV?d00001 diff --git a/cdk/cdk.out/.cache/99aabce70089266e2352cb313d55ee18b849e39c418e8e9cd25dea8c4bf85fc4.zip b/cdk/cdk.out/.cache/99aabce70089266e2352cb313d55ee18b849e39c418e8e9cd25dea8c4bf85fc4.zip new file mode 100644 index 0000000000000000000000000000000000000000..6b1255e08c55b011f35d4413d45e10b208455186 GIT binary patch literal 3246 zcmZ`+c{CLK_ok60l1a$EleN&0>`{y%>tO8L*vV3i8oay=BaAg>Vyt1r5N2d+o2)aD zU3MkXi$r7{Kb`L%@ArJq`Q3Z&x%YFG0H#X}tf$GqAbwi^#<|nc&m+V; z2p+B+8r=n(4xf1mj47`FX7cQ;tVoy?to?#bCE5GY=Lh3Y$Q5DMf_bS);&1tD!3oUz zE~+3*AIp-aTZ>zEfHNYe*^X?@)0qM|lYXasaFsnOGV;!kM2D{&0~UduD3H=fA$U*! zG2E0g^zGItj_`?fVHU|~V-VPhmp6Y#$ICeO7F1>VXgYx%X`C3>*qjk*YPplR9^mL; zFfQI(E?;q|YP$Ob9dbA-NQ%H_?D z=Pia2WGwCF#yIBY@|(HtxnUwt33XH_jy6=J#zd{f9hVuc7AI|4;P_~I6RLyzs(1eYoy8vj%t-- z5fc>>1a>PIpg`D*#$x{Lb5GGlGq(F63Dt*UeYw&Aae z?zj=@)qBaGr;a%;dPQ}ptQG%7d|v1xrv&8Pnws+R^<8;aBRJWrVj;UAQfJkj3ATFk zjKqa(mN^I1_A{4#p9zOpxeN_GmY=(Y8QX2I<+<^ zh2aJ7azds2W((RbV?A*XwG3ikTmCVU(jShzy*3C@if)yd&{3O&+gE6wZ^gfH|45gb z7;wf{dnz3f5$o}y#igAx?gdnBNe6{KcKIJ@mAc_!oXt?00aGme3M|j2qly1vzb=1^ zq>aY#18mwy9)+FQ?2&0g*HNqltl#v5Ke19U_jOT7n!MBJUl^TaW)dwu;SM2Jb}Hbj zP`F{HV&Kl5iZt57*SAAVy||%V@NJ(4aZ#gNAU+F|Y75U$tQnk~cv6cCXp)|O1%!_cb1RKCYSPl_IyN!pnVC}fQfBog#DO52xp1Jh z-dj@k@I0^}ikF-{M>pERr5W^Y+!%OI4Mo&cS0sJEdTgy0eeZZ(7Wv`&6peK%$XKN7 z$`x;TO-QRNONHQh^vF5j7a}D<^r<`lq!w<%IQIjry2eRLo0`6;p!3V$F)43E`UU1ML~(pjyOI?0W=sF=}o36Gv_YK_}mz}l+O*nS1d%g4k*lD#aqS)SZVa0~4Aj#mT*!QF*0IF#;QYG$? z?n(Cn#CNs?L`Pxa*#N>OKlyuH2 z-q$yhzHQ}SA)jBXI|<0KNiYM00$V~gCLTK}p%2+NH8TKn43ikoL4>Pl)b6+QtuVed z3l%S6XH~f*A^pCzR?X$_2xgx(woxBuGTECo%$_xXk`6NbLA_37wt zKBgt$y~~%BJ3z5>3snZ?V1JstnicghvOTp@F58@`r{RL8f>L6414~c(G>)XxF(uUP z*~V_j0%~G#Wk9nY0cS*%xa!nObhK@5c^`KNh2O4*6o#hCw%f5m8l#KXLgm{b4$nM7 z=wVjmo|&YH>-$Iu{2cmbkM$yvNRs5-sy*Xs$#51{*X zLm!dbyQ`EhH;b!UJeFgk4I?&!Ha`{#JQ48jJvqEQT<0myJ)GAtZvO(egZ~YED2-z9 zA&Z1?jDRts(#|Jy@cs`%hwbpjl`K^l*zr5cJZm9wDNdu+Cy1@zk1VVK?7w5v_ey`s zFy;Ak3cHh=-o-*QEbcNpj@pFkwGs5BBc73q-IcQ#l zaAsy&J!dc$-GeYOi-oOK>=JbPDa@On(ptA)F}By=lw%;i)9ZUBqyvZ#iF_)fJKWT`P&n67ST@i> zGh)ec)n_*d(omN&@X5@YNHdl37=cFr6Tfn{dAvKT-u*{4;ML#ENaH%`&e8Gy3s#6F zkG(yYvXsRb&IYs%YVVhN0!_afV*w~~LAY#dC*6&Elk3IxvYT;Ou{$FnAdsgJ{UG@1 zBW`MXlSpOTuJo5DB4}@{cR(;B_~7xukGAKE$l!swT;QNrfM^op00CQ=j{})vokbrB z+4mdSB#jlA9|`-Wsho$F%5}T!ZyeTpBWG0-y1vsgad6@Qb=;yMX*l$0(F@Q-cN6}_ zCzmd18}?4qII!N&)^bAyMEy6CQLlZPJU-(lpa{T9YX z+GnW86P)k%brjzui7f~b)((RbT`UcL5*25XAR`cC%8pjNKFQn!7SP7KT(E0ucGx^} z;ZY4`85cNiZeBdoawfe&q?90GCRL7Wb#)0vDNPN;a#xiEPZ*)z2P*~BrZD+6tV%aq zuRsxt4{Nuzh|LeBeC=*Kj9Ki+oCFG^N;G&kBn2Y$Y`BaB-S~p)NRkt0o3lVu%^N83 z8LRhIbUqCKB{Sk>*LDU7_lx>(r6qYJb(dw@yz}$~>DTURcx)K|)w^zS1wFo1qANuO z@%UNgXYeUoRi)D1kc*wv+R*(b|Ey&8TwrtdL0U++;i0(fGL9!kv7}e@Q%tk?oMX{4 znmQDkaniJlorh-2b=~IAqV9i=hf6HLoX-iXec{V+7o?iIcc+@pV^|s}=8i*Ej*wTi zphNb^W@xi`Bu}Jk3t)_X;>#Holdc)@3H|f@y%yOFl;!)JPhIBaHE@&HbOoQc7+se$ zF~i!gB^wXw`S;7p4`y;C-##6^q`*v-oVY7&%9G?4C%Cvx^OA0mXM*jOci0%)#|nYCU-LN zuV@@1Q)o}kA#Qiz zlr7Q#i!a5AN}TJ7^_64bf6Vx!p+!fE0VaNIVC74I&gF9<(b!Zc{Y=dmlArs0mWs$R zizS4Gb@2jVxsaWK0eC9nE&pFl&vmNl!{K2M{KMhF@R0iv%J&iXA^lhTG{{Y$Q8o1; zwS_aMXcpFVYvsB>yPT(G31K{=1o+n@{P$0PJi>oMjG-d_&-AZj_+Q+A-~4m?Kk)}Q addmBMSy@8PGXL2)bDEK-U4rA!>;C|iZU-0u literal 0 HcmV?d00001 diff --git a/cdk/cdk.out/.cache/e2e48659a729723ff586b8a7cec8bb3cf79f1ca97c4286cc8e741e774b2ac1ae.zip b/cdk/cdk.out/.cache/e2e48659a729723ff586b8a7cec8bb3cf79f1ca97c4286cc8e741e774b2ac1ae.zip new file mode 100644 index 0000000000000000000000000000000000000000..b430e87cc653fce5f6a575fcc38e96a7ed8cab66 GIT binary patch literal 3234 zcmZ`+X*3&J*AAuTHjSakrJ|;)Dbzft=6Na!YG_bH8uP4NQ>m$>F+>bCR?S7su2K}0 zqOGI^mvU9z_w2LRdCpq<*=MhF{_JgKdVzrpz_ah9?DzL);@TCQ-pT7=^sry(+<^D3W0MHHhn2{)C({(sz z8^h3;LHf!w?8>7PeZ|{K*~eoF)vH*A!Wc z>&a^L+Ff*Y$%bZ|2*}s|ScdXtPIO^5On3}348}zeKZeaP`qJW2LrC3*Qn<0GZ8-)C z#ta?!w+Jn)WZw-gc|0_F*PkKf{9>SQrcZOc)NUfI4rAuSKDv#ejUIx7)E_OD zpBSTyyEUxz9S>}$w{Q1r=|9XI5Xz4nag!FEd=VpLKrk__v(UG_2#FZiX_2q+ZoLsT z4&hV0$=UHf42PW(z4^nvXqq}Sa_laJ7-S{-REvRE`-@Q-5>B62pJ+U~bQ8x%mubcF zgpfO~y81{6Zoipn#ETnzTk#Z{&0WFrG|kNYwpMC^uMDevvWXW3nw@MUILgI5`>WMn zZSqm)cH2FKMf_EMn2M@e6lpfEHvAZD?cIBFT&8!J>h&`!VJ#<5BBJf;h-U?)2bnB* zJLAXCxp-Y;Dl1HG7xl@c`xLjy%@?2jHFW;*NWh+*jdAdd=!p&V(Cy^w{TSk{%?Y_V z6q8n3j`gcFy@oCq4r6sNNSxasLm?$sOMWcK`!b(tomOk)`*s%?&bp4&OpN|J1-M;Rzkd>BI<1imTUUb%vheb`UT?C0bN^bG zO)s1j?P`9`J=mWc8eXr9AM!V9FI={m*&U4xkT8j{>Y+#(YE?ecGA!d zkY9QYhA&C(mcyXm%rJ8%(wf_`D{aW``k>mcvDKX+JF&l?7Va?88{d^E3$REs?;CDz zl7>}l9ex`k-8v9FOEpw&W5SV=ub;-W+2+DE4dx&$i!*nwWPyR)Y!?*TPd5Xf1x{dV zH}ng=dLxF)vBI*7u-u#W*NWqZZ|GK57AhL5ybayAzwmhx@YhISJeh5~_~m_#CU7`y zQ?V0qbsG)!Yv}Z_VVz|YZT&*y{jkS1F~@0*FKi~5CoV97zsFHn?zTNjq`TgeeG!zQ zXBn`w6fZ8%An?v$^kIbGac@?s8o#+QvSz|S`dZJ=<{TkJKLpJ0KG{m_(o;3lj1{O5tjD}xCr5~KS3 z_zu$Ew*VLC%tciExvZF}-Somth$qsR%B7d5lI>{A*l$0sY!E8_F?H6OujGdmfhu!g zNVtP9YslpPvejYfD!36-yjY3*IV?cz{4jtFueGjqfSjEL8}+0o+ZmAu9bJdfr07M5 zAs!CY*oy;+^cB1`9KUmbQ!lNO%nF?qqW1=}{ISSb98W$et|mpDp~%|WTxDqxA# zn1}IG&w*qICWrR^#hfBDkoJc1+v+2Kh{BgoQ&Rk*O8J3R0iBQ&6KtO6$b$zOUE0n~ z+3vU*7cY#g*jquN?v-fg4;vye5(MwOg+6- zd^z8L3xm2A>!#+STUEgDVT@w&J}WX~c<+vfYqAb%VQN~?QrNE+qqRhYglsndx#mil z;Hr^di87*>?^bPpAm*|Hm5Xc{4g3m=F0w}R|7q{{OT>zb(1aaagsSHgQa(9#-Y_h# zJZeYHmsOg~P6Z%ZmuFF%5yIzHt0MtVwOK&y?&KLFX z=p4_~{4R*%Xnk>5)|$2JmZYM>b0+P%z}b)HfZVT>g@#z@gi@_i%vZs~%#jgGanJ zUqKfP3h2db#_kos-mPNFW*OlHsWFC^Rizu+H-wRkK}2WrAm#bi>`dq_?YI+np1VbH zMTDS>QDL`D(kpj7_;tR*L49mrQ3fjmfB2+uq*%LYll7cid$;zC4mhKkm4~(}6@>$H zd3W~W?Acn6Y~-stC163Ccm(sB#@go*x^9r;xEm7+;9!~=Od+;E&lJ-rYp5o?FEAahrdRMO(dU!N?v zZepI8-RRzaGMAnIm9h!eyo9ZeIPN>;_&%`fklFa0c2ez6+8)MZ_ME_Gt}K;WBV?#G zGtri8H<)F$X(sO5(R`OzE%6Axvjo09@oS_Mb)8f#G08s}Nl@`qpR61EJfQ+?1oKip zzjyiOYg3~54vTU4XI8d6p@0W?9|oPe+2}@0*Q=*XoEWRq7obTCRt&_^S(!31bCzEe z%Vq-rOoaddtN*u;2cGxwL7su3K0%%jJkcS+G9eKmrsJ|>%I&R+9~G3Q6_)7F)lAHp zHZl#rV=tY%l_?#)^o4)tg8#nh_gwHF2mvbNf3tt5g#Xq3ch29r|AXJU(et|hw<;@B S#*4or=+7 (/Users/daniel/agent-claw/cdk/bin/agent-claw.ts:8:1)", "...node internals, ts-node, ts-node, ts-node..." ] @@ -46,7 +46,7 @@ { "type": "aws:cdk:creationStack", "data": [ - "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:377:5)", + "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:382:5)", " (/Users/daniel/agent-claw/cdk/bin/agent-claw.ts:8:1)", "...node internals, ts-node, ts-node, ts-node..." ] @@ -60,7 +60,7 @@ { "type": "aws:cdk:creationStack", "data": [ - "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:381:5)", + "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:386:5)", " (/Users/daniel/agent-claw/cdk/bin/agent-claw.ts:8:1)", "...node internals, ts-node, ts-node, ts-node..." ] @@ -74,7 +74,7 @@ { "type": "aws:cdk:creationStack", "data": [ - "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:386:5)", + "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:391:5)", " (/Users/daniel/agent-claw/cdk/bin/agent-claw.ts:8:1)", "...node internals, ts-node, ts-node, ts-node..." ] @@ -88,7 +88,7 @@ { "type": "aws:cdk:creationStack", "data": [ - "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:391:5)", + "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:396:5)", " (/Users/daniel/agent-claw/cdk/bin/agent-claw.ts:8:1)", "...node internals, ts-node, ts-node, ts-node..." ] @@ -102,7 +102,7 @@ { "type": "aws:cdk:creationStack", "data": [ - "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:396:5)", + "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:401:5)", " (/Users/daniel/agent-claw/cdk/bin/agent-claw.ts:8:1)", "...node internals, ts-node, ts-node, ts-node..." ] @@ -116,7 +116,7 @@ { "type": "aws:cdk:creationStack", "data": [ - "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:401:5)", + "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:406:5)", " (/Users/daniel/agent-claw/cdk/bin/agent-claw.ts:8:1)", "...node internals, ts-node, ts-node, ts-node..." ] @@ -130,7 +130,7 @@ { "type": "aws:cdk:creationStack", "data": [ - "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:406:5)", + "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:411:5)", " (/Users/daniel/agent-claw/cdk/bin/agent-claw.ts:8:1)", "...node internals, ts-node, ts-node, ts-node..." ] @@ -144,7 +144,7 @@ { "type": "aws:cdk:creationStack", "data": [ - "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:411:5)", + "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:416:5)", " (/Users/daniel/agent-claw/cdk/bin/agent-claw.ts:8:1)", "...node internals, ts-node, ts-node, ts-node..." ] @@ -158,7 +158,7 @@ { "type": "aws:cdk:creationStack", "data": [ - "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:416:5)", + "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:421:5)", " (/Users/daniel/agent-claw/cdk/bin/agent-claw.ts:8:1)", "...node internals, ts-node, ts-node, ts-node..." ] @@ -304,7 +304,7 @@ "type": "aws:cdk:creationStack", "data": [ "...new Function2 in aws-cdk-lib...", - "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:238:28)", + "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:243:28)", " (/Users/daniel/agent-claw/cdk/bin/agent-claw.ts:8:1)", "...node internals, ts-node, ts-node, ts-node..." ] @@ -319,7 +319,7 @@ "type": "aws:cdk:creationStack", "data": [ "...new Function2 in aws-cdk-lib...", - "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:309:31)", + "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:314:31)", " (/Users/daniel/agent-claw/cdk/bin/agent-claw.ts:8:1)", "...node internals, ts-node, ts-node, ts-node..." ] @@ -334,7 +334,7 @@ "type": "aws:cdk:creationStack", "data": [ "...new Rule2 in aws-cdk-lib...", - "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:325:27)", + "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:330:27)", " (/Users/daniel/agent-claw/cdk/bin/agent-claw.ts:8:1)", "...node internals, ts-node, ts-node, ts-node..." ] @@ -349,7 +349,7 @@ "type": "aws:cdk:creationStack", "data": [ "...WrappedClass. in aws-cdk-lib...", - "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:329:19)", + "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:334:19)", " (/Users/daniel/agent-claw/cdk/bin/agent-claw.ts:8:1)", "...node internals, ts-node, ts-node, ts-node..." ] @@ -364,7 +364,7 @@ "type": "aws:cdk:creationStack", "data": [ "...new Function2 in aws-cdk-lib...", - "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:332:25)", + "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:337:25)", " (/Users/daniel/agent-claw/cdk/bin/agent-claw.ts:8:1)", "...node internals, ts-node, ts-node, ts-node..." ] @@ -379,7 +379,7 @@ "type": "aws:cdk:creationStack", "data": [ "...WrappedClass.addPermission in aws-cdk-lib...", - "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:345:17)", + "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:350:17)", " (/Users/daniel/agent-claw/cdk/bin/agent-claw.ts:8:1)", "...node internals, ts-node, ts-node, ts-node..." ] @@ -503,7 +503,7 @@ ".../Users/daniel/agent-claw/cdk/node_modules/aws-cdk-lib/aws-apigatewayv2/lib/http/api.js:1:96 in aws-cdk-lib...", "Array.map (:)", "...WrappedClass. in aws-cdk-lib...", - "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:274:13)", + "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:279:13)", " (/Users/daniel/agent-claw/cdk/bin/agent-claw.ts:8:1)", "...node internals, ts-node, ts-node, ts-node..." ] @@ -520,7 +520,7 @@ ".../Users/daniel/agent-claw/cdk/node_modules/aws-cdk-lib/aws-apigatewayv2/lib/http/api.js:1:96 in aws-cdk-lib...", "Array.map (:)", "...WrappedClass. in aws-cdk-lib...", - "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:274:13)", + "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:279:13)", " (/Users/daniel/agent-claw/cdk/bin/agent-claw.ts:8:1)", "...node internals, ts-node, ts-node, ts-node..." ] @@ -537,7 +537,7 @@ ".../Users/daniel/agent-claw/cdk/node_modules/aws-cdk-lib/aws-apigatewayv2/lib/http/api.js:1:96 in aws-cdk-lib...", "Array.map (:)", "...WrappedClass. in aws-cdk-lib...", - "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:281:13)", + "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:286:13)", " (/Users/daniel/agent-claw/cdk/bin/agent-claw.ts:8:1)", "...node internals, ts-node, ts-node, ts-node..." ] @@ -554,7 +554,7 @@ ".../Users/daniel/agent-claw/cdk/node_modules/aws-cdk-lib/aws-apigatewayv2/lib/http/api.js:1:96 in aws-cdk-lib...", "Array.map (:)", "...WrappedClass. in aws-cdk-lib...", - "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:281:13)", + "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:286:13)", " (/Users/daniel/agent-claw/cdk/bin/agent-claw.ts:8:1)", "...node internals, ts-node, ts-node, ts-node..." ] @@ -571,7 +571,7 @@ ".../Users/daniel/agent-claw/cdk/node_modules/aws-cdk-lib/aws-apigatewayv2/lib/http/api.js:1:96 in aws-cdk-lib...", "Array.map (:)", "...WrappedClass. in aws-cdk-lib...", - "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:290:13)", + "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:295:13)", " (/Users/daniel/agent-claw/cdk/bin/agent-claw.ts:8:1)", "...node internals, ts-node, ts-node, ts-node..." ] @@ -588,7 +588,7 @@ ".../Users/daniel/agent-claw/cdk/node_modules/aws-cdk-lib/aws-apigatewayv2/lib/http/api.js:1:96 in aws-cdk-lib...", "Array.map (:)", "...WrappedClass. in aws-cdk-lib...", - "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:290:13)", + "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:295:13)", " (/Users/daniel/agent-claw/cdk/bin/agent-claw.ts:8:1)", "...node internals, ts-node, ts-node, ts-node..." ] @@ -633,7 +633,7 @@ "type": "aws:cdk:creationStack", "data": [ "...new Function2 in aws-cdk-lib...", - "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:238:28)", + "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:243:28)", " (/Users/daniel/agent-claw/cdk/bin/agent-claw.ts:8:1)", "...node internals, ts-node, ts-node, ts-node..." ] @@ -648,7 +648,7 @@ "type": "aws:cdk:creationStack", "data": [ "...new Function2 in aws-cdk-lib...", - "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:309:31)", + "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:314:31)", " (/Users/daniel/agent-claw/cdk/bin/agent-claw.ts:8:1)", "...node internals, ts-node, ts-node, ts-node..." ] @@ -663,7 +663,7 @@ "type": "aws:cdk:creationStack", "data": [ "...new Function2 in aws-cdk-lib...", - "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:332:25)", + "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:337:25)", " (/Users/daniel/agent-claw/cdk/bin/agent-claw.ts:8:1)", "...node internals, ts-node, ts-node, ts-node..." ] @@ -727,7 +727,7 @@ ".../Users/daniel/agent-claw/cdk/node_modules/aws-cdk-lib/aws-apigatewayv2/lib/http/api.js:1:96 in aws-cdk-lib...", "Array.map (:)", "...WrappedClass. in aws-cdk-lib...", - "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:274:13)", + "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:279:13)", " (/Users/daniel/agent-claw/cdk/bin/agent-claw.ts:8:1)", "...node internals, ts-node, ts-node, ts-node..." ] @@ -744,7 +744,7 @@ ".../Users/daniel/agent-claw/cdk/node_modules/aws-cdk-lib/aws-apigatewayv2/lib/http/api.js:1:96 in aws-cdk-lib...", "Array.map (:)", "...WrappedClass. in aws-cdk-lib...", - "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:281:13)", + "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:286:13)", " (/Users/daniel/agent-claw/cdk/bin/agent-claw.ts:8:1)", "...node internals, ts-node, ts-node, ts-node..." ] @@ -761,7 +761,7 @@ ".../Users/daniel/agent-claw/cdk/node_modules/aws-cdk-lib/aws-apigatewayv2/lib/http/api.js:1:96 in aws-cdk-lib...", "Array.map (:)", "...WrappedClass. in aws-cdk-lib...", - "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:290:13)", + "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:295:13)", " (/Users/daniel/agent-claw/cdk/bin/agent-claw.ts:8:1)", "...node internals, ts-node, ts-node, ts-node..." ] @@ -776,7 +776,7 @@ "type": "aws:cdk:creationStack", "data": [ "...environmentFromArn.grantRead in aws-cdk-lib...", - "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:253:29)", + "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:258:29)", " (/Users/daniel/agent-claw/cdk/bin/agent-claw.ts:8:1)", "...node internals, ts-node, ts-node, ts-node..." ] @@ -791,7 +791,7 @@ "type": "aws:cdk:creationStack", "data": [ "...WrappedClass.grantSendMessages in aws-cdk-lib...", - "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:321:18)", + "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:326:18)", " (/Users/daniel/agent-claw/cdk/bin/agent-claw.ts:8:1)", "...node internals, ts-node, ts-node, ts-node..." ] @@ -806,7 +806,7 @@ "type": "aws:cdk:creationStack", "data": [ "...environmentFromArn.grantRead in aws-cdk-lib...", - "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:343:20)", + "new AgentClawStack (/Users/daniel/agent-claw/cdk/lib/agent-claw-stack.ts:348:20)", " (/Users/daniel/agent-claw/cdk/bin/agent-claw.ts:8:1)", "...node internals, ts-node, ts-node, ts-node..." ] diff --git a/cdk/cdk.out/AgentClawStack.template.json b/cdk/cdk.out/AgentClawStack.template.json index 4321c4f..3e958c1 100644 --- a/cdk/cdk.out/AgentClawStack.template.json +++ b/cdk/cdk.out/AgentClawStack.template.json @@ -387,7 +387,7 @@ "Properties": { "Code": { "S3Bucket": "cdk-hnb659fds-assets-495395224548-us-east-1", - "S3Key": "4f645198a38249aec43db7c3d289ab4896fad437f79e8cfe1ff77fc2e788167c.zip" + "S3Key": "647684a0ff5a7a3df590aa5532173310dace910d7081be6f3a642f7e81dabc06.zip" }, "Environment": { "Variables": { @@ -423,7 +423,7 @@ ], "Metadata": { "aws:cdk:path": "AgentClawStack/AgentRunner/Resource", - "aws:asset:path": "asset.4f645198a38249aec43db7c3d289ab4896fad437f79e8cfe1ff77fc2e788167c", + "aws:asset:path": "asset.647684a0ff5a7a3df590aa5532173310dace910d7081be6f3a642f7e81dabc06", "aws:asset:is-bundled": false, "aws:asset:property": "Code" } @@ -949,6 +949,12 @@ "Resource": "arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/google-credentials/*", "Sid": "PerUserGoogleCredentialsReadRuntime" }, + { + "Action": "secretsmanager:ListSecrets", + "Effect": "Allow", + "Resource": "*", + "Sid": "GoogleCredentialsListRuntime" + }, { "Action": [ "events:PutRule", @@ -1149,7 +1155,7 @@ "Properties": { "Code": { "S3Bucket": "cdk-hnb659fds-assets-495395224548-us-east-1", - "S3Key": "b45b92872bd4af9d3688817f862e6574ff6b4903e68b140bcee6fe0b2678c645.zip" + "S3Key": "99aabce70089266e2352cb313d55ee18b849e39c418e8e9cd25dea8c4bf85fc4.zip" }, "Environment": { "Variables": { @@ -1194,7 +1200,7 @@ ], "Metadata": { "aws:cdk:path": "AgentClawStack/OAuthHandler/Resource", - "aws:asset:path": "asset.b45b92872bd4af9d3688817f862e6574ff6b4903e68b140bcee6fe0b2678c645", + "aws:asset:path": "asset.99aabce70089266e2352cb313d55ee18b849e39c418e8e9cd25dea8c4bf85fc4", "aws:asset:is-bundled": false, "aws:asset:property": "Code" } diff --git a/cdk/cdk.out/asset.647684a0ff5a7a3df590aa5532173310dace910d7081be6f3a642f7e81dabc06/handler.py b/cdk/cdk.out/asset.647684a0ff5a7a3df590aa5532173310dace910d7081be6f3a642f7e81dabc06/handler.py new file mode 100644 index 0000000..7ba13fc --- /dev/null +++ b/cdk/cdk.out/asset.647684a0ff5a7a3df590aa5532173310dace910d7081be6f3a642f7e81dabc06/handler.py @@ -0,0 +1,272 @@ +import json +import os +import time +import uuid +import boto3 +import urllib.request +from typing import Any + +# AWS clients +_ddb = None +_agentcore = None + + +def get_ddb(): + global _ddb + if _ddb is None: + _ddb = boto3.resource('dynamodb') + return _ddb + + +def get_agentcore(): + global _agentcore + if _agentcore is None: + from botocore.config import Config + _agentcore = boto3.client( + 'bedrock-agentcore', + region_name='us-east-1', + config=Config(read_timeout=600, connect_timeout=10) + ) + return _agentcore + + +def get_or_create_user(actor_id: str, from_info: dict) -> dict: + """Look up user in registry, auto-registering on first contact.""" + table_name = os.environ.get('USERS_TABLE_NAME', '') + if not table_name: + return {'actor_id': actor_id, 'display_name': from_info.get('from_name', actor_id)} + table = get_ddb().Table(table_name) + response = table.get_item(Key={'actor_id': actor_id}) + item = response.get('Item') + if item: + return item + now = int(time.time()) + item = { + 'actor_id': actor_id, + 'display_name': from_info.get('from_name') or actor_id, + 'telegram_username': from_info.get('from_username', ''), + 'created_at': str(now), + 'status': 'pending', + 'services': {}, + } + table.put_item(Item=item) + print(f'[agent-runner] Registered new user (pending): {actor_id}') + return item + + +def update_user_status(actor_id: str, name: str, status: str) -> None: + table_name = os.environ.get('USERS_TABLE_NAME', '') + if not table_name: + return + table = get_ddb().Table(table_name) + table.update_item( + Key={'actor_id': actor_id}, + UpdateExpression='SET display_name = :n, #s = :s', + ExpressionAttributeNames={'#s': 'status'}, + ExpressionAttributeValues={':n': name, ':s': status}, + ) + + +# Per-invocation dedup: track sent message hashes to prevent AgentCore retry duplicates +_sent_hashes: set = set() + + +def send_telegram_direct(chat_id: str, token: str, text: str) -> None: + import hashlib + h = hashlib.md5(f'{chat_id}:{text}'.encode()).hexdigest()[:12] + if h in _sent_hashes: + print(f'[agent-runner] dedup: skipping duplicate message (hash={h})') + return + _sent_hashes.add(h) + url = f'https://api.telegram.org/bot{token}/sendMessage' + data = json.dumps({'chat_id': chat_id, 'text': text}).encode() + req = urllib.request.Request(url, data=data, headers={'Content-Type': 'application/json'}) + try: + resp = urllib.request.urlopen(req, timeout=10) + resp_body = resp.read() + import re + msg_id = re.search(r'"message_id":(\d+)', resp_body.decode('utf-8', errors='replace')) + print(f'[agent-runner] Telegram sendMessage -> msg_id={msg_id.group(1) if msg_id else "?"} hash={h}') + except Exception as e: + print(f'[agent-runner] Telegram sendMessage FAILED: {type(e).__name__}: {e} hash={h}') + raise + + +def get_or_create_session(actor_id: str) -> str: + """Look up active session for actor, or create a new one.""" + table = get_ddb().Table(os.environ['SESSION_TABLE_NAME']) + + response = table.get_item(Key={'actor_id': actor_id}) + item = response.get('Item') + + now = int(time.time()) + ttl_8hr = now + (8 * 3600) + + if item and item.get('ttl', 0) > now: + # Active session exists — extend TTL + table.update_item( + Key={'actor_id': actor_id}, + UpdateExpression='SET #ttl = :ttl', + ExpressionAttributeNames={'#ttl': 'ttl'}, + ExpressionAttributeValues={':ttl': ttl_8hr}, + ) + return item['session_id'] + + # Create new session + session_id = str(uuid.uuid4()) + table.put_item(Item={ + 'actor_id': actor_id, + 'session_id': session_id, + 'created_at': str(now), + 'ttl': ttl_8hr, + }) + return session_id + + +def handler(event, context): + # ── Parse SQS records (FIFO — all from same actor) ─────────────────── + records = [] + for record in event.get('Records', []): + try: + records.append(json.loads(record['body'])) + except (json.JSONDecodeError, KeyError): + continue + + if not records: + return + + first = records[0] + channel = first.get('channel', 'telegram') + chat_id = first.get('chat_id', '') + actor_id = f"{channel}:{chat_id}" + + # ── User registry ───────────────────────────────────────────────────── + from_info = first.get('messages', [{}])[0] + user_profile = get_or_create_user(actor_id, from_info) + + # ── Onboarding gate ───────────────────────────────────────────────────── + table_name = os.environ.get('USERS_TABLE_NAME', '') + if table_name and user_profile.get('status', 'active') == 'pending': + raw_prompt = records[0]['messages'][0]['text'] if records else '' + is_name_msg = bool(raw_prompt and len(raw_prompt.strip()) < 50 and '?' not in raw_prompt) + if is_name_msg: + name = raw_prompt.strip() + update_user_status(actor_id, name=name, status='active') + user_profile['display_name'] = name + user_profile['status'] = 'active' + prompt = f"[System: User just registered with name '{name}'. Welcome them warmly and ask how you can help.]" + else: + bot_token_secret_arn = os.environ.get('TELEGRAM_BOT_TOKEN_SECRET_ARN', '') + bot_token = '' + if bot_token_secret_arn: + sm = boto3.client('secretsmanager', region_name='us-east-1') + bot_token = sm.get_secret_value(SecretId=bot_token_secret_arn)['SecretString'] + send_telegram_direct(chat_id, bot_token, "Hi! I don't recognize you yet. What's your name?") + return + # ── Get or create AgentCore session ────────────────────────────────── + session_id = get_or_create_session(actor_id) + print(f"[agent-runner] actor={actor_id} session={session_id} user={user_profile.get('display_name', '')}") + + # ── Bundle messages ─────────────────────────────────────────────────── + if len(records) == 1: + prompt = records[0]['messages'][0]['text'] + else: + lines = [ + f"[{i+1}] {r['messages'][0]['text']}" + for i, r in enumerate(records) + ] + prompt = f"You have {len(records)} queued messages:\n" + "\n".join(lines) + + # ── Build payload for AgentCore Runtime 1 ──────────────────────────── + payload: dict[str, Any] = { + 'prompt': prompt, + 'actor_id': actor_id, + 'session_id': session_id, + 'user_profile': { + 'display_name': user_profile.get('display_name', actor_id), + 'telegram_username': user_profile.get('telegram_username', ''), + 'google_accounts': user_profile.get('google_accounts', {'primary': user_profile['google_email']} if user_profile.get('google_email') else {}), + 'allowed': user_profile.get('allowed', True), + 'services': user_profile.get('enrolled_services', user_profile.get('services', {})), + }, + 'channel_adapter': { + 'type': channel, + 'target_id': str(chat_id), + 'bot_token_secret_arn': os.environ.get('TELEGRAM_BOT_TOKEN_SECRET_ARN', ''), + }, + } + + # ── Invoke AgentCore Runtime 1 ──────────────────────────────────────── + runtime_arn = os.environ.get('RUNTIME_1_ARN', '') + if not runtime_arn or runtime_arn == 'PLACEHOLDER_SET_AFTER_RUNTIME_DEPLOY': + print(f"[agent-runner] RUNTIME_1_ARN not set — skipping AgentCore invoke") + print(f"[agent-runner] Would have sent: {json.dumps(payload)[:200]}") + return + + client = get_agentcore() + response = client.invoke_agent_runtime( + agentRuntimeArn=runtime_arn, + runtimeSessionId=session_id, + payload=json.dumps(payload).encode(), + ) + + # Process streaming response: buffer text chunks and send to Telegram as paragraphs arrive + bot_token = '' + bot_token_secret_arn = os.environ.get('TELEGRAM_BOT_TOKEN_SECRET_ARN', '') + if bot_token_secret_arn: + sm = boto3.client('secretsmanager', region_name='us-east-1') + try: + bot_token = sm.get_secret_value(SecretId=bot_token_secret_arn)['SecretString'] + except Exception as e: + print(f'[agent-runner] Failed to get bot token: {e}') + + body = response.get('response') + text_buffer = '' + leftover = '' + if body is not None: + for raw_chunk in body.iter_chunks(): + if not raw_chunk: + continue + # AgentCore streams SSE format: "data: {...}\n\n" + text = leftover + raw_chunk.decode('utf-8', errors='replace') + parts = text.split('\n\n') + leftover = parts[-1] + for part in parts[:-1]: + for line in part.splitlines(): + if not line.startswith('data: '): + continue + data = line[6:].strip() + if not data or data == '[DONE]': + continue + try: + event = json.loads(data) + except (json.JSONDecodeError, ValueError): + continue + if not isinstance(event, dict): + continue + # Extract text delta from contentBlockDelta ONLY + # Do NOT use event.get('data') — that's the full formatted summary, + # causing duplicate delivery alongside the token stream. + delta = event.get('event', {}).get('contentBlockDelta', {}).get('delta', {}) + if not isinstance(delta, dict): + continue + token = delta.get('text', '') + if token: + text_buffer += token + # Only flush if buffer is very large — prevents splitting multi-turn responses + if len(text_buffer) > 1200: + print(f'[agent-runner] send chunk {len(text_buffer)}c to {chat_id}') + send_telegram_direct(str(chat_id), bot_token, text_buffer.strip()) + text_buffer = '' + + # Flush any remaining text + print(f'[agent-runner] stream done buffer={len(text_buffer)} bot_token_set={bool(bot_token)}') + if text_buffer.strip() and bot_token: + # Suppress heartbeat OK responses + if text_buffer.strip().upper().startswith('HEARTBEAT_OK'): + print(f'[agent-runner] heartbeat suppressed for {actor_id}') + return + print(f'[agent-runner] flushing {len(text_buffer)}c to {chat_id}') + send_telegram_direct(str(chat_id), bot_token, text_buffer.strip()) + + print(f"[agent-runner] Completed session={session_id} actor={actor_id}") diff --git a/cdk/cdk.out/asset.647684a0ff5a7a3df590aa5532173310dace910d7081be6f3a642f7e81dabc06/requirements.txt b/cdk/cdk.out/asset.647684a0ff5a7a3df590aa5532173310dace910d7081be6f3a642f7e81dabc06/requirements.txt new file mode 100644 index 0000000..011ba23 --- /dev/null +++ b/cdk/cdk.out/asset.647684a0ff5a7a3df590aa5532173310dace910d7081be6f3a642f7e81dabc06/requirements.txt @@ -0,0 +1 @@ +boto3>=1.34.0 diff --git a/cdk/cdk.out/asset.99aabce70089266e2352cb313d55ee18b849e39c418e8e9cd25dea8c4bf85fc4/handler.py b/cdk/cdk.out/asset.99aabce70089266e2352cb313d55ee18b849e39c418e8e9cd25dea8c4bf85fc4/handler.py new file mode 100644 index 0000000..84daee8 --- /dev/null +++ b/cdk/cdk.out/asset.99aabce70089266e2352cb313d55ee18b849e39c418e8e9cd25dea8c4bf85fc4/handler.py @@ -0,0 +1,244 @@ +""" +Google OAuth handler Lambda. + +Routes: + GET /oauth/start?actor_id=telegram:123&label=work → redirect to Google OAuth consent + GET /oauth/callback?code=...&state=... → exchange code, store tokens, update DynamoDB +""" +import base64 +import json +import os +import time +import urllib.parse +import urllib.request + +import boto3 + +_sm = None +_ddb = None + +SCOPES = ' '.join([ + 'https://www.googleapis.com/auth/gmail.modify', + 'https://www.googleapis.com/auth/calendar', + 'https://www.googleapis.com/auth/drive', + 'https://www.googleapis.com/auth/spreadsheets', + 'https://www.googleapis.com/auth/documents', + 'openid', + 'email', + 'profile', +]) + + +def get_sm(): + global _sm + if _sm is None: + _sm = boto3.client('secretsmanager', region_name=os.environ.get('AWS_REGION', 'us-east-1')) + return _sm + + +def get_ddb(): + global _ddb + if _ddb is None: + _ddb = boto3.resource('dynamodb') + return _ddb + + +def get_oauth_client() -> tuple[str, str]: + """Return (client_id, client_secret) from Secrets Manager.""" + arn = os.environ['GOOGLE_OAUTH_CLIENT_SECRET_ARN'] + secret = json.loads(get_sm().get_secret_value(SecretId=arn)['SecretString']) + return secret['client_id'], secret['client_secret'] + + +def actor_id_to_secret_name(actor_id: str, label: str = 'primary') -> str: + safe = actor_id.replace(':', '-').replace('/', '-') + return f'agent-claw/google-credentials/{safe}/{label}' + + +def _redirect(url: str) -> dict: + return {'statusCode': 302, 'headers': {'Location': url}, 'body': ''} + + +def _html(body: str, status: int = 200) -> dict: + return {'statusCode': status, 'headers': {'Content-Type': 'text/html'}, 'body': body} + + +def handler(event, context): + path = event.get('rawPath') or event.get('path', '') + params = event.get('queryStringParameters') or {} + + if path.endswith('/oauth/start'): + return handle_start(params) + elif path.endswith('/oauth/callback'): + return handle_callback(params) + else: + return {'statusCode': 404, 'body': 'Not found'} + + +def handle_start(params: dict) -> dict: + actor_id = params.get('actor_id', '') + if not actor_id: + return _html('

Missing actor_id

', 400) + + label = params.get('label', 'primary') + + client_id, _ = get_oauth_client() + redirect_uri = os.environ['OAUTH_REDIRECT_URI'] + + # Encode actor_id + label in state (JSON → base64) + state_data = json.dumps({'a': actor_id, 'l': label}) + state = base64.urlsafe_b64encode(state_data.encode()).decode().rstrip('=') + + auth_url = ( + 'https://accounts.google.com/o/oauth2/v2/auth?' + + urllib.parse.urlencode({ + 'client_id': client_id, + 'redirect_uri': redirect_uri, + 'response_type': 'code', + 'scope': SCOPES, + 'access_type': 'offline', + 'prompt': 'consent', + 'state': state, + }) + ) + return _redirect(auth_url) + + +def handle_callback(params: dict) -> dict: + code = params.get('code', '') + state = params.get('state', '') + error = params.get('error', '') + + if error: + return _html(f'

OAuth error: {error}

', 400) + if not code or not state: + return _html('

Missing code or state

', 400) + + # Decode actor_id + label from state + try: + padding = 4 - len(state) % 4 + state_data = json.loads(base64.urlsafe_b64decode(state + '=' * padding).decode()) + actor_id = state_data['a'] + label = state_data.get('l', 'primary') + except Exception: + # Backward compat: old state was just base64(actor_id) + try: + padding = 4 - len(state) % 4 + actor_id = base64.urlsafe_b64decode(state + '=' * padding).decode() + label = 'primary' + except Exception: + return _html('

Invalid state

', 400) + + client_id, client_secret = get_oauth_client() + redirect_uri = os.environ['OAUTH_REDIRECT_URI'] + + # Exchange code for tokens + token_data = urllib.parse.urlencode({ + 'code': code, + 'client_id': client_id, + 'client_secret': client_secret, + 'redirect_uri': redirect_uri, + 'grant_type': 'authorization_code', + }).encode() + + req = urllib.request.Request( + 'https://oauth2.googleapis.com/token', + data=token_data, + headers={'Content-Type': 'application/x-www-form-urlencoded'}, + ) + try: + with urllib.request.urlopen(req, timeout=15) as resp: + tokens = json.loads(resp.read()) + except Exception as e: + print(f'[oauth] Token exchange failed: {e}') + return _html(f'

Token exchange failed: {e}

', 500) + + # Fetch user email from Google + user_email = '' + try: + id_token_payload = tokens.get('id_token', '').split('.')[1] + padding = 4 - len(id_token_payload) % 4 + claims = json.loads(base64.urlsafe_b64decode(id_token_payload + '=' * padding)) + user_email = claims.get('email', '') + except Exception: + pass + + if not user_email: + try: + access_token = tokens.get('access_token', '') + req2 = urllib.request.Request( + 'https://www.googleapis.com/oauth2/v3/userinfo', + headers={'Authorization': f'Bearer {access_token}'}, + ) + with urllib.request.urlopen(req2, timeout=10) as resp2: + user_email = json.loads(resp2.read()).get('email', '') + except Exception as e: + print(f'[oauth] userinfo fetch failed: {e}') + + # Build credentials dict (google-auth format) + creds = { + 'token': tokens.get('access_token'), + 'refresh_token': tokens.get('refresh_token'), + 'token_uri': 'https://oauth2.googleapis.com/token', + 'client_id': client_id, + 'client_secret': client_secret, + 'scopes': [s for s in SCOPES.split() if s.startswith('https://')], + 'email': user_email, + 'user_email': user_email, + } + if tokens.get('expires_in'): + creds['expiry'] = time.strftime( + '%Y-%m-%dT%H:%M:%SZ', + time.gmtime(time.time() + int(tokens['expires_in'])) + ) + + # Store in Secrets Manager at labeled path + secret_name = actor_id_to_secret_name(actor_id, label) + sm = get_sm() + try: + sm.create_secret(Name=secret_name, SecretString=json.dumps(creds)) + except sm.exceptions.ResourceExistsException: + sm.put_secret_value(SecretId=secret_name, SecretString=json.dumps(creds)) + print(f'[oauth] Stored credentials for actor={actor_id} label={label} email={user_email}') + + # Update DynamoDB: merge into google_accounts map + table_name = os.environ.get('USERS_TABLE_NAME', '') + if table_name and actor_id: + try: + table = get_ddb().Table(table_name) + table.update_item( + Key={'actor_id': actor_id}, + UpdateExpression='SET google_accounts = if_not_exists(google_accounts, :empty)', + ExpressionAttributeValues={':empty': {}}, + ) + table.update_item( + Key={'actor_id': actor_id}, + UpdateExpression='SET google_accounts.#label = :email', + ExpressionAttributeNames={'#label': label}, + ExpressionAttributeValues={':email': user_email}, + ) + except Exception as e: + print(f'[oauth] DynamoDB update failed: {e}') + + # Best-effort Telegram confirmation + try: + bot_token_arn = os.environ.get('TELEGRAM_BOT_TOKEN_SECRET_ARN', '') + if bot_token_arn and actor_id.startswith('telegram:'): + chat_id = actor_id.split(':', 1)[1] + bot_token = get_sm().get_secret_value(SecretId=bot_token_arn)['SecretString'] + tg_text = f'✅ Connected {user_email} as "{label}"' + tg_payload = json.dumps({'chat_id': chat_id, 'text': tg_text}).encode() + tg_req = urllib.request.Request( + f'https://api.telegram.org/bot{bot_token}/sendMessage', + data=tg_payload, + headers={'Content-Type': 'application/json'}, + ) + urllib.request.urlopen(tg_req, timeout=5) + except Exception as e: + print(f'[oauth] Telegram notification failed: {e}') + + return _html( + f'

✅ Google account connected!

' + f'

Connected {user_email} as "{label}".

' + f'

You can close this window and return to Telegram.

' + ) diff --git a/cdk/cdk.out/asset.99aabce70089266e2352cb313d55ee18b849e39c418e8e9cd25dea8c4bf85fc4/requirements.txt b/cdk/cdk.out/asset.99aabce70089266e2352cb313d55ee18b849e39c418e8e9cd25dea8c4bf85fc4/requirements.txt new file mode 100644 index 0000000..011ba23 --- /dev/null +++ b/cdk/cdk.out/asset.99aabce70089266e2352cb313d55ee18b849e39c418e8e9cd25dea8c4bf85fc4/requirements.txt @@ -0,0 +1 @@ +boto3>=1.34.0 diff --git a/cdk/cdk.out/asset.e2e48659a729723ff586b8a7cec8bb3cf79f1ca97c4286cc8e741e774b2ac1ae/handler.py b/cdk/cdk.out/asset.e2e48659a729723ff586b8a7cec8bb3cf79f1ca97c4286cc8e741e774b2ac1ae/handler.py new file mode 100644 index 0000000..3012b68 --- /dev/null +++ b/cdk/cdk.out/asset.e2e48659a729723ff586b8a7cec8bb3cf79f1ca97c4286cc8e741e774b2ac1ae/handler.py @@ -0,0 +1,238 @@ +""" +Google OAuth handler Lambda. + +Routes: + GET /oauth/start?actor_id=telegram:123&label=work → redirect to Google OAuth consent + GET /oauth/callback?code=...&state=... → exchange code, store tokens, update DynamoDB +""" +import base64 +import json +import os +import time +import urllib.parse +import urllib.request + +import boto3 + +_sm = None +_ddb = None + +SCOPES = ' '.join([ + 'https://www.googleapis.com/auth/gmail.modify', + 'https://www.googleapis.com/auth/calendar', + 'https://www.googleapis.com/auth/drive', + 'https://www.googleapis.com/auth/spreadsheets', + 'https://www.googleapis.com/auth/documents', + 'openid', + 'email', + 'profile', +]) + + +def get_sm(): + global _sm + if _sm is None: + _sm = boto3.client('secretsmanager', region_name=os.environ.get('AWS_REGION', 'us-east-1')) + return _sm + + +def get_ddb(): + global _ddb + if _ddb is None: + _ddb = boto3.resource('dynamodb') + return _ddb + + +def get_oauth_client() -> tuple[str, str]: + """Return (client_id, client_secret) from Secrets Manager.""" + arn = os.environ['GOOGLE_OAUTH_CLIENT_SECRET_ARN'] + secret = json.loads(get_sm().get_secret_value(SecretId=arn)['SecretString']) + return secret['client_id'], secret['client_secret'] + + +def actor_id_to_secret_name(actor_id: str, label: str = 'primary') -> str: + safe = actor_id.replace(':', '-').replace('/', '-') + return f'agent-claw/google-credentials/{safe}/{label}' + + +def _redirect(url: str) -> dict: + return {'statusCode': 302, 'headers': {'Location': url}, 'body': ''} + + +def _html(body: str, status: int = 200) -> dict: + return {'statusCode': status, 'headers': {'Content-Type': 'text/html'}, 'body': body} + + +def handler(event, context): + path = event.get('rawPath') or event.get('path', '') + params = event.get('queryStringParameters') or {} + + if path.endswith('/oauth/start'): + return handle_start(params) + elif path.endswith('/oauth/callback'): + return handle_callback(params) + else: + return {'statusCode': 404, 'body': 'Not found'} + + +def handle_start(params: dict) -> dict: + actor_id = params.get('actor_id', '') + if not actor_id: + return _html('

Missing actor_id

', 400) + + label = params.get('label', 'primary') + + client_id, _ = get_oauth_client() + redirect_uri = os.environ['OAUTH_REDIRECT_URI'] + + # Encode actor_id + label in state (JSON → base64) + state_data = json.dumps({'a': actor_id, 'l': label}) + state = base64.urlsafe_b64encode(state_data.encode()).decode().rstrip('=') + + auth_url = ( + 'https://accounts.google.com/o/oauth2/v2/auth?' + + urllib.parse.urlencode({ + 'client_id': client_id, + 'redirect_uri': redirect_uri, + 'response_type': 'code', + 'scope': SCOPES, + 'access_type': 'offline', + 'prompt': 'consent', + 'state': state, + }) + ) + return _redirect(auth_url) + + +def handle_callback(params: dict) -> dict: + code = params.get('code', '') + state = params.get('state', '') + error = params.get('error', '') + + if error: + return _html(f'

OAuth error: {error}

', 400) + if not code or not state: + return _html('

Missing code or state

', 400) + + # Decode actor_id + label from state + try: + padding = 4 - len(state) % 4 + state_data = json.loads(base64.urlsafe_b64decode(state + '=' * padding).decode()) + actor_id = state_data['a'] + label = state_data.get('l', 'primary') + except Exception: + # Backward compat: old state was just base64(actor_id) + try: + padding = 4 - len(state) % 4 + actor_id = base64.urlsafe_b64decode(state + '=' * padding).decode() + label = 'primary' + except Exception: + return _html('

Invalid state

', 400) + + client_id, client_secret = get_oauth_client() + redirect_uri = os.environ['OAUTH_REDIRECT_URI'] + + # Exchange code for tokens + token_data = urllib.parse.urlencode({ + 'code': code, + 'client_id': client_id, + 'client_secret': client_secret, + 'redirect_uri': redirect_uri, + 'grant_type': 'authorization_code', + }).encode() + + req = urllib.request.Request( + 'https://oauth2.googleapis.com/token', + data=token_data, + headers={'Content-Type': 'application/x-www-form-urlencoded'}, + ) + try: + with urllib.request.urlopen(req, timeout=15) as resp: + tokens = json.loads(resp.read()) + except Exception as e: + print(f'[oauth] Token exchange failed: {e}') + return _html(f'

Token exchange failed: {e}

', 500) + + # Fetch user email from Google + user_email = '' + try: + id_token_payload = tokens.get('id_token', '').split('.')[1] + padding = 4 - len(id_token_payload) % 4 + claims = json.loads(base64.urlsafe_b64decode(id_token_payload + '=' * padding)) + user_email = claims.get('email', '') + except Exception: + pass + + if not user_email: + try: + access_token = tokens.get('access_token', '') + req2 = urllib.request.Request( + 'https://www.googleapis.com/oauth2/v3/userinfo', + headers={'Authorization': f'Bearer {access_token}'}, + ) + with urllib.request.urlopen(req2, timeout=10) as resp2: + user_email = json.loads(resp2.read()).get('email', '') + except Exception as e: + print(f'[oauth] userinfo fetch failed: {e}') + + # Build credentials dict (google-auth format) + creds = { + 'token': tokens.get('access_token'), + 'refresh_token': tokens.get('refresh_token'), + 'token_uri': 'https://oauth2.googleapis.com/token', + 'client_id': client_id, + 'client_secret': client_secret, + 'scopes': [s for s in SCOPES.split() if s.startswith('https://')], + 'email': user_email, + 'user_email': user_email, + } + if tokens.get('expires_in'): + creds['expiry'] = time.strftime( + '%Y-%m-%dT%H:%M:%SZ', + time.gmtime(time.time() + int(tokens['expires_in'])) + ) + + # Store in Secrets Manager at labeled path + secret_name = actor_id_to_secret_name(actor_id, label) + sm = get_sm() + try: + sm.create_secret(Name=secret_name, SecretString=json.dumps(creds)) + except sm.exceptions.ResourceExistsException: + sm.put_secret_value(SecretId=secret_name, SecretString=json.dumps(creds)) + print(f'[oauth] Stored credentials for actor={actor_id} label={label} email={user_email}') + + # Update DynamoDB: merge into google_accounts map + table_name = os.environ.get('USERS_TABLE_NAME', '') + if table_name and actor_id: + try: + get_ddb().Table(table_name).update_item( + Key={'actor_id': actor_id}, + UpdateExpression='SET google_accounts = if_not_exists(google_accounts, :empty), google_accounts.#label = :email', + ExpressionAttributeNames={'#label': label}, + ExpressionAttributeValues={':email': user_email, ':empty': {}}, + ) + except Exception as e: + print(f'[oauth] DynamoDB update failed: {e}') + + # Best-effort Telegram confirmation + try: + bot_token_arn = os.environ.get('TELEGRAM_BOT_TOKEN_SECRET_ARN', '') + if bot_token_arn and actor_id.startswith('telegram:'): + chat_id = actor_id.split(':', 1)[1] + bot_token = get_sm().get_secret_value(SecretId=bot_token_arn)['SecretString'] + tg_text = f'✅ Connected {user_email} as "{label}"' + tg_payload = json.dumps({'chat_id': chat_id, 'text': tg_text}).encode() + tg_req = urllib.request.Request( + f'https://api.telegram.org/bot{bot_token}/sendMessage', + data=tg_payload, + headers={'Content-Type': 'application/json'}, + ) + urllib.request.urlopen(tg_req, timeout=5) + except Exception as e: + print(f'[oauth] Telegram notification failed: {e}') + + return _html( + f'

✅ Google account connected!

' + f'

Connected {user_email} as "{label}".

' + f'

You can close this window and return to Telegram.

' + ) diff --git a/cdk/cdk.out/asset.e2e48659a729723ff586b8a7cec8bb3cf79f1ca97c4286cc8e741e774b2ac1ae/requirements.txt b/cdk/cdk.out/asset.e2e48659a729723ff586b8a7cec8bb3cf79f1ca97c4286cc8e741e774b2ac1ae/requirements.txt new file mode 100644 index 0000000..011ba23 --- /dev/null +++ b/cdk/cdk.out/asset.e2e48659a729723ff586b8a7cec8bb3cf79f1ca97c4286cc8e741e774b2ac1ae/requirements.txt @@ -0,0 +1 @@ +boto3>=1.34.0 diff --git a/cdk/cdk.out/manifest.json b/cdk/cdk.out/manifest.json index f026d40..949d4ea 100644 --- a/cdk/cdk.out/manifest.json +++ b/cdk/cdk.out/manifest.json @@ -18,7 +18,7 @@ "validateOnSynth": false, "assumeRoleArn": "arn:${AWS::Partition}:iam::495395224548:role/cdk-hnb659fds-deploy-role-495395224548-us-east-1", "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::495395224548:role/cdk-hnb659fds-cfn-exec-role-495395224548-us-east-1", - "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-495395224548-us-east-1/f5e50400defa8e717f9f7ae32453df078f55bafc76973f390e22e14616b1eea0.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-495395224548-us-east-1/bf77d8fb57b225c495e242bd05bd7658713d3e0e810a6701955397f14f68d7e5.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ diff --git a/cdk/cdk.out/tree.json b/cdk/cdk.out/tree.json index 4f61c56..f6877dd 100644 --- a/cdk/cdk.out/tree.json +++ b/cdk/cdk.out/tree.json @@ -1 +1 @@ -{"version":"tree-0.1","tree":{"id":"App","path":"","constructInfo":{"fqn":"aws-cdk-lib.App","version":"2.252.0"},"children":{"AgentClawStack":{"id":"AgentClawStack","path":"AgentClawStack","constructInfo":{"fqn":"aws-cdk-lib.Stack","version":"2.252.0"},"children":{"TelegramBotToken":{"id":"TelegramBotToken","path":"AgentClawStack/TelegramBotToken","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"2.252.0"}},"BraveApiKey":{"id":"BraveApiKey","path":"AgentClawStack/BraveApiKey","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"2.252.0"}},"WorkspaceBucket":{"id":"WorkspaceBucket","path":"AgentClawStack/WorkspaceBucket","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.BucketBase","version":"2.252.0"}},"SessionStore":{"id":"SessionStore","path":"AgentClawStack/SessionStore","constructInfo":{"fqn":"aws-cdk-lib.aws_dynamodb.Table","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/SessionStore/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_dynamodb.CfnTable","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::DynamoDB::Table","aws:cdk:cloudformation:logicalId":"SessionStore8C86EEFE","aws:cdk:cloudformation:props":{"attributeDefinitions":[{"attributeName":"actor_id","attributeType":"S"}],"billingMode":"PAY_PER_REQUEST","keySchema":[{"attributeName":"actor_id","keyType":"HASH"}],"tableName":"agent-claw-sessions","timeToLiveSpecification":{"attributeName":"ttl","enabled":true}}}},"ScalingRole":{"id":"ScalingRole","path":"AgentClawStack/SessionStore/ScalingRole","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"2.252.0"}}}},"UsersTable":{"id":"UsersTable","path":"AgentClawStack/UsersTable","constructInfo":{"fqn":"aws-cdk-lib.aws_dynamodb.Table","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/UsersTable/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_dynamodb.CfnTable","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::DynamoDB::Table","aws:cdk:cloudformation:logicalId":"UsersTable9725E9C8","aws:cdk:cloudformation:props":{"attributeDefinitions":[{"attributeName":"actor_id","attributeType":"S"}],"billingMode":"PAY_PER_REQUEST","keySchema":[{"attributeName":"actor_id","keyType":"HASH"}],"tableName":"agent-claw-users"}}},"ScalingRole":{"id":"ScalingRole","path":"AgentClawStack/UsersTable/ScalingRole","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"2.252.0"}}}},"MessageQueue":{"id":"MessageQueue","path":"AgentClawStack/MessageQueue","constructInfo":{"fqn":"aws-cdk-lib.aws_sqs.Queue","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/MessageQueue/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_sqs.CfnQueue","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::SQS::Queue","aws:cdk:cloudformation:logicalId":"MessageQueue7A3BF959","aws:cdk:cloudformation:props":{"contentBasedDeduplication":false,"fifoQueue":true,"queueName":"agent-claw-messages.fifo","receiveMessageWaitTimeSeconds":20,"visibilityTimeout":900}}}}},"TgIngest":{"id":"TgIngest","path":"AgentClawStack/TgIngest","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.Function","version":"2.252.0"},"children":{"ServiceRole":{"id":"ServiceRole","path":"AgentClawStack/TgIngest/ServiceRole","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Role","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/TgIngest/ServiceRole/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnRole","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:logicalId":"TgIngestServiceRoleB96980B6","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"}}],"Version":"2012-10-17"},"managedPolicyArns":[{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]]}]}}},"DefaultPolicy":{"id":"DefaultPolicy","path":"AgentClawStack/TgIngest/ServiceRole/DefaultPolicy","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Policy","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/TgIngest/ServiceRole/DefaultPolicy/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnPolicy","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Policy","aws:cdk:cloudformation:logicalId":"TgIngestServiceRoleDefaultPolicyCC51E135","aws:cdk:cloudformation:props":{"policyDocument":{"Statement":[{"Action":["sqs:SendMessage","sqs:GetQueueAttributes","sqs:GetQueueUrl"],"Effect":"Allow","Resource":{"Fn::GetAtt":["MessageQueue7A3BF959","Arn"]}},{"Action":["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],"Effect":"Allow","Resource":"arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/telegram-bot-token-Oq3in3"}],"Version":"2012-10-17"},"policyName":"TgIngestServiceRoleDefaultPolicyCC51E135","roles":[{"Ref":"TgIngestServiceRoleB96980B6"}]}}}}}}},"Code":{"id":"Code","path":"AgentClawStack/TgIngest/Code","constructInfo":{"fqn":"aws-cdk-lib.aws_s3_assets.Asset","version":"2.252.0"},"children":{"Stage":{"id":"Stage","path":"AgentClawStack/TgIngest/Code/Stage","constructInfo":{"fqn":"aws-cdk-lib.AssetStaging","version":"2.252.0"}},"AssetBucket":{"id":"AssetBucket","path":"AgentClawStack/TgIngest/Code/AssetBucket","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.BucketBase","version":"2.252.0"}}}},"Resource":{"id":"Resource","path":"AgentClawStack/TgIngest/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnFunction","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Function","aws:cdk:cloudformation:logicalId":"TgIngest4CB35C2F","aws:cdk:cloudformation:props":{"code":{"s3Bucket":"cdk-hnb659fds-assets-495395224548-us-east-1","s3Key":"8da48fd743d1e2cb70d8d1935cee795b6f8cf02609db05e2b8f28449be9ef875.zip"},"environment":{"variables":{"MESSAGE_QUEUE_URL":{"Ref":"MessageQueue7A3BF959"},"TELEGRAM_BOT_TOKEN_SECRET_ARN":"arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/telegram-bot-token-Oq3in3","TELEGRAM_WEBHOOK_SECRET":""}},"functionName":"agent-claw-tg-ingest","handler":"handler.handler","memorySize":128,"role":{"Fn::GetAtt":["TgIngestServiceRoleB96980B6","Arn"]},"runtime":"python3.12","timeout":10}}}}},"AgentRunner":{"id":"AgentRunner","path":"AgentClawStack/AgentRunner","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.Function","version":"2.252.0"},"children":{"ServiceRole":{"id":"ServiceRole","path":"AgentClawStack/AgentRunner/ServiceRole","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Role","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/AgentRunner/ServiceRole/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnRole","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:logicalId":"AgentRunnerServiceRole40CA0A00","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"}}],"Version":"2012-10-17"},"managedPolicyArns":[{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]]}]}}},"DefaultPolicy":{"id":"DefaultPolicy","path":"AgentClawStack/AgentRunner/ServiceRole/DefaultPolicy","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Policy","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/AgentRunner/ServiceRole/DefaultPolicy/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnPolicy","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Policy","aws:cdk:cloudformation:logicalId":"AgentRunnerServiceRoleDefaultPolicyA584A5CF","aws:cdk:cloudformation:props":{"policyDocument":{"Statement":[{"Action":["dynamodb:BatchGetItem","dynamodb:Query","dynamodb:GetItem","dynamodb:Scan","dynamodb:ConditionCheckItem","dynamodb:BatchWriteItem","dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:DeleteItem","dynamodb:DescribeTable"],"Effect":"Allow","Resource":[{"Fn::GetAtt":["SessionStore8C86EEFE","Arn"]}]},{"Action":["dynamodb:GetRecords","dynamodb:GetShardIterator"],"Effect":"Allow","Resource":[{"Fn::GetAtt":["SessionStore8C86EEFE","Arn"]}]},{"Action":["dynamodb:BatchGetItem","dynamodb:Query","dynamodb:GetItem","dynamodb:Scan","dynamodb:ConditionCheckItem","dynamodb:BatchWriteItem","dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:DeleteItem","dynamodb:DescribeTable"],"Effect":"Allow","Resource":[{"Fn::GetAtt":["UsersTable9725E9C8","Arn"]}]},{"Action":["dynamodb:GetRecords","dynamodb:GetShardIterator"],"Effect":"Allow","Resource":[{"Fn::GetAtt":["UsersTable9725E9C8","Arn"]}]},{"Action":["s3:GetObject*","s3:GetBucket*","s3:List*"],"Effect":"Allow","Resource":[{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":s3:::agent-claw-workspace-495395224548"]]},{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":s3:::agent-claw-workspace-495395224548/*"]]}]},{"Action":["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],"Effect":"Allow","Resource":"arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/telegram-bot-token-Oq3in3"},{"Action":["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],"Effect":"Allow","Resource":"arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/brave-api-key-uUSgzi"},{"Action":["sqs:ReceiveMessage","sqs:ChangeMessageVisibility","sqs:GetQueueUrl","sqs:DeleteMessage","sqs:GetQueueAttributes"],"Effect":"Allow","Resource":{"Fn::GetAtt":["MessageQueue7A3BF959","Arn"]}},{"Action":"bedrock-agentcore:InvokeAgentRuntime","Effect":"Allow","Resource":"*"}],"Version":"2012-10-17"},"policyName":"AgentRunnerServiceRoleDefaultPolicyA584A5CF","roles":[{"Ref":"AgentRunnerServiceRole40CA0A00"}]}}}}}}},"Code":{"id":"Code","path":"AgentClawStack/AgentRunner/Code","constructInfo":{"fqn":"aws-cdk-lib.aws_s3_assets.Asset","version":"2.252.0"},"children":{"Stage":{"id":"Stage","path":"AgentClawStack/AgentRunner/Code/Stage","constructInfo":{"fqn":"aws-cdk-lib.AssetStaging","version":"2.252.0"}},"AssetBucket":{"id":"AssetBucket","path":"AgentClawStack/AgentRunner/Code/AssetBucket","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.BucketBase","version":"2.252.0"}}}},"Resource":{"id":"Resource","path":"AgentClawStack/AgentRunner/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnFunction","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Function","aws:cdk:cloudformation:logicalId":"AgentRunnerBDE3FA56","aws:cdk:cloudformation:props":{"code":{"s3Bucket":"cdk-hnb659fds-assets-495395224548-us-east-1","s3Key":"4f645198a38249aec43db7c3d289ab4896fad437f79e8cfe1ff77fc2e788167c.zip"},"environment":{"variables":{"SESSION_TABLE_NAME":{"Ref":"SessionStore8C86EEFE"},"WORKSPACE_BUCKET_NAME":"agent-claw-workspace-495395224548","TELEGRAM_BOT_TOKEN_SECRET_ARN":"arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/telegram-bot-token-Oq3in3","BRAVE_API_KEY_SECRET_ARN":"arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/brave-api-key-uUSgzi","RUNTIME_1_ARN":"arn:aws:bedrock-agentcore:us-east-1:495395224548:runtime/agentclaw_agent_claw_main-vTRGIEG6ON","AWS_REGION_NAME":"us-east-1","USERS_TABLE_NAME":{"Ref":"UsersTable9725E9C8"},"WORKSPACE_MCP_URL":"https://25hugrzw4uwtueeg77jsmft6lq0wunmd.lambda-url.us-east-1.on.aws/mcp"}},"functionName":"agent-claw-agent-runner","handler":"handler.handler","memorySize":256,"role":{"Fn::GetAtt":["AgentRunnerServiceRole40CA0A00","Arn"]},"runtime":"python3.12","timeout":900}}},"SqsEventSource:AgentClawStackMessageQueue9AF4DF23":{"id":"SqsEventSource:AgentClawStackMessageQueue9AF4DF23","path":"AgentClawStack/AgentRunner/SqsEventSource:AgentClawStackMessageQueue9AF4DF23","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.EventSourceMapping","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/AgentRunner/SqsEventSource:AgentClawStackMessageQueue9AF4DF23/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnEventSourceMapping","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::EventSourceMapping","aws:cdk:cloudformation:logicalId":"AgentRunnerSqsEventSourceAgentClawStackMessageQueue9AF4DF234671B32B","aws:cdk:cloudformation:props":{"batchSize":10,"enabled":true,"eventSourceArn":{"Fn::GetAtt":["MessageQueue7A3BF959","Arn"]},"functionName":{"Ref":"AgentRunnerBDE3FA56"}}}}}}}},"WebhookApi":{"id":"WebhookApi","path":"AgentClawStack/WebhookApi","constructInfo":{"fqn":"aws-cdk-lib.aws_apigatewayv2.HttpApi","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/WebhookApi/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_apigatewayv2.CfnApi","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::ApiGatewayV2::Api","aws:cdk:cloudformation:logicalId":"WebhookApi28122C53","aws:cdk:cloudformation:props":{"name":"agent-claw-webhook","protocolType":"HTTP"}}},"DefaultStage":{"id":"DefaultStage","path":"AgentClawStack/WebhookApi/DefaultStage","constructInfo":{"fqn":"aws-cdk-lib.aws_apigatewayv2.HttpStage","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/WebhookApi/DefaultStage/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_apigatewayv2.CfnStage","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::ApiGatewayV2::Stage","aws:cdk:cloudformation:logicalId":"WebhookApiDefaultStageC0BC9CA5","aws:cdk:cloudformation:props":{"apiId":{"Ref":"WebhookApi28122C53"},"autoDeploy":true,"stageName":"$default"}}}}},"POST--telegram":{"id":"POST--telegram","path":"AgentClawStack/WebhookApi/POST--telegram","constructInfo":{"fqn":"aws-cdk-lib.aws_apigatewayv2.HttpRoute","version":"2.252.0"},"children":{"TgIngestIntegration":{"id":"TgIngestIntegration","path":"AgentClawStack/WebhookApi/POST--telegram/TgIngestIntegration","constructInfo":{"fqn":"aws-cdk-lib.aws_apigatewayv2.HttpIntegration","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/WebhookApi/POST--telegram/TgIngestIntegration/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_apigatewayv2.CfnIntegration","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::ApiGatewayV2::Integration","aws:cdk:cloudformation:logicalId":"WebhookApiPOSTtelegramTgIngestIntegration9EE5BB85","aws:cdk:cloudformation:props":{"apiId":{"Ref":"WebhookApi28122C53"},"integrationType":"AWS_PROXY","integrationUri":{"Fn::GetAtt":["TgIngest4CB35C2F","Arn"]},"payloadFormatVersion":"2.0"}}}}},"TgIngestIntegration-Permission":{"id":"TgIngestIntegration-Permission","path":"AgentClawStack/WebhookApi/POST--telegram/TgIngestIntegration-Permission","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnPermission","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Permission","aws:cdk:cloudformation:logicalId":"WebhookApiPOSTtelegramTgIngestIntegrationPermissionFEBC2E3B","aws:cdk:cloudformation:props":{"action":"lambda:InvokeFunction","functionName":{"Fn::GetAtt":["TgIngest4CB35C2F","Arn"]},"principal":"apigateway.amazonaws.com","sourceArn":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":execute-api:us-east-1:495395224548:",{"Ref":"WebhookApi28122C53"},"/*/*/telegram"]]}}}},"Resource":{"id":"Resource","path":"AgentClawStack/WebhookApi/POST--telegram/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_apigatewayv2.CfnRoute","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::ApiGatewayV2::Route","aws:cdk:cloudformation:logicalId":"WebhookApiPOSTtelegramF7127CFF","aws:cdk:cloudformation:props":{"apiId":{"Ref":"WebhookApi28122C53"},"authorizationType":"NONE","routeKey":"POST /telegram","target":{"Fn::Join":["",["integrations/",{"Ref":"WebhookApiPOSTtelegramTgIngestIntegration9EE5BB85"}]]}}}}}},"GET--oauth--start":{"id":"GET--oauth--start","path":"AgentClawStack/WebhookApi/GET--oauth--start","constructInfo":{"fqn":"aws-cdk-lib.aws_apigatewayv2.HttpRoute","version":"2.252.0"},"children":{"OAuthStartIntegration":{"id":"OAuthStartIntegration","path":"AgentClawStack/WebhookApi/GET--oauth--start/OAuthStartIntegration","constructInfo":{"fqn":"aws-cdk-lib.aws_apigatewayv2.HttpIntegration","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/WebhookApi/GET--oauth--start/OAuthStartIntegration/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_apigatewayv2.CfnIntegration","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::ApiGatewayV2::Integration","aws:cdk:cloudformation:logicalId":"WebhookApiGEToauthstartOAuthStartIntegrationA546443F","aws:cdk:cloudformation:props":{"apiId":{"Ref":"WebhookApi28122C53"},"integrationType":"AWS_PROXY","integrationUri":{"Fn::GetAtt":["OAuthHandlerC97C2476","Arn"]},"payloadFormatVersion":"2.0"}}}}},"OAuthStartIntegration-Permission":{"id":"OAuthStartIntegration-Permission","path":"AgentClawStack/WebhookApi/GET--oauth--start/OAuthStartIntegration-Permission","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnPermission","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Permission","aws:cdk:cloudformation:logicalId":"WebhookApiGEToauthstartOAuthStartIntegrationPermission38BAEF6D","aws:cdk:cloudformation:props":{"action":"lambda:InvokeFunction","functionName":{"Fn::GetAtt":["OAuthHandlerC97C2476","Arn"]},"principal":"apigateway.amazonaws.com","sourceArn":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":execute-api:us-east-1:495395224548:",{"Ref":"WebhookApi28122C53"},"/*/*/oauth/start"]]}}}},"Resource":{"id":"Resource","path":"AgentClawStack/WebhookApi/GET--oauth--start/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_apigatewayv2.CfnRoute","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::ApiGatewayV2::Route","aws:cdk:cloudformation:logicalId":"WebhookApiGEToauthstart6DCA713A","aws:cdk:cloudformation:props":{"apiId":{"Ref":"WebhookApi28122C53"},"authorizationType":"NONE","routeKey":"GET /oauth/start","target":{"Fn::Join":["",["integrations/",{"Ref":"WebhookApiGEToauthstartOAuthStartIntegrationA546443F"}]]}}}}}},"GET--oauth--callback":{"id":"GET--oauth--callback","path":"AgentClawStack/WebhookApi/GET--oauth--callback","constructInfo":{"fqn":"aws-cdk-lib.aws_apigatewayv2.HttpRoute","version":"2.252.0"},"children":{"OAuthCallbackIntegration":{"id":"OAuthCallbackIntegration","path":"AgentClawStack/WebhookApi/GET--oauth--callback/OAuthCallbackIntegration","constructInfo":{"fqn":"aws-cdk-lib.aws_apigatewayv2.HttpIntegration","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/WebhookApi/GET--oauth--callback/OAuthCallbackIntegration/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_apigatewayv2.CfnIntegration","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::ApiGatewayV2::Integration","aws:cdk:cloudformation:logicalId":"WebhookApiGEToauthcallbackOAuthCallbackIntegrationCFBBEB09","aws:cdk:cloudformation:props":{"apiId":{"Ref":"WebhookApi28122C53"},"integrationType":"AWS_PROXY","integrationUri":{"Fn::GetAtt":["OAuthHandlerC97C2476","Arn"]},"payloadFormatVersion":"2.0"}}}}},"OAuthCallbackIntegration-Permission":{"id":"OAuthCallbackIntegration-Permission","path":"AgentClawStack/WebhookApi/GET--oauth--callback/OAuthCallbackIntegration-Permission","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnPermission","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Permission","aws:cdk:cloudformation:logicalId":"WebhookApiGEToauthcallbackOAuthCallbackIntegrationPermission6BA3A5AD","aws:cdk:cloudformation:props":{"action":"lambda:InvokeFunction","functionName":{"Fn::GetAtt":["OAuthHandlerC97C2476","Arn"]},"principal":"apigateway.amazonaws.com","sourceArn":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":execute-api:us-east-1:495395224548:",{"Ref":"WebhookApi28122C53"},"/*/*/oauth/callback"]]}}}},"Resource":{"id":"Resource","path":"AgentClawStack/WebhookApi/GET--oauth--callback/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_apigatewayv2.CfnRoute","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::ApiGatewayV2::Route","aws:cdk:cloudformation:logicalId":"WebhookApiGEToauthcallbackFC1F6BCD","aws:cdk:cloudformation:props":{"apiId":{"Ref":"WebhookApi28122C53"},"authorizationType":"NONE","routeKey":"GET /oauth/callback","target":{"Fn::Join":["",["integrations/",{"Ref":"WebhookApiGEToauthcallbackOAuthCallbackIntegrationCFBBEB09"}]]}}}}}},"ANY--workspace--{proxy+}":{"id":"ANY--workspace--{proxy+}","path":"AgentClawStack/WebhookApi/ANY--workspace--{proxy+}","constructInfo":{"fqn":"aws-cdk-lib.aws_apigatewayv2.HttpRoute","version":"2.252.0"},"children":{"WorkspaceMcpIntegration":{"id":"WorkspaceMcpIntegration","path":"AgentClawStack/WebhookApi/ANY--workspace--{proxy+}/WorkspaceMcpIntegration","constructInfo":{"fqn":"aws-cdk-lib.aws_apigatewayv2.HttpIntegration","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/WebhookApi/ANY--workspace--{proxy+}/WorkspaceMcpIntegration/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_apigatewayv2.CfnIntegration","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::ApiGatewayV2::Integration","aws:cdk:cloudformation:logicalId":"WebhookApiANYworkspaceproxyWorkspaceMcpIntegration7377EE13","aws:cdk:cloudformation:props":{"apiId":{"Ref":"WebhookApi28122C53"},"integrationType":"AWS_PROXY","integrationUri":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":lambda:us-east-1:495395224548:function:agent-claw-workspace-mcp"]]},"payloadFormatVersion":"2.0"}}}}},"WorkspaceMcpIntegration-Permission":{"id":"WorkspaceMcpIntegration-Permission","path":"AgentClawStack/WebhookApi/ANY--workspace--{proxy+}/WorkspaceMcpIntegration-Permission","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnPermission","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Permission","aws:cdk:cloudformation:logicalId":"WebhookApiANYworkspaceproxyWorkspaceMcpIntegrationPermission97613ADF","aws:cdk:cloudformation:props":{"action":"lambda:InvokeFunction","functionName":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":lambda:us-east-1:495395224548:function:agent-claw-workspace-mcp"]]},"principal":"apigateway.amazonaws.com","sourceArn":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":execute-api:us-east-1:495395224548:",{"Ref":"WebhookApi28122C53"},"/*/*/workspace/{proxy+}"]]}}}},"Resource":{"id":"Resource","path":"AgentClawStack/WebhookApi/ANY--workspace--{proxy+}/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_apigatewayv2.CfnRoute","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::ApiGatewayV2::Route","aws:cdk:cloudformation:logicalId":"WebhookApiANYworkspaceproxy4455BE19","aws:cdk:cloudformation:props":{"apiId":{"Ref":"WebhookApi28122C53"},"authorizationType":"NONE","routeKey":"ANY /workspace/{proxy+}","target":{"Fn::Join":["",["integrations/",{"Ref":"WebhookApiANYworkspaceproxyWorkspaceMcpIntegration7377EE13"}]]}}}}}}}},"Runtime1Role":{"id":"Runtime1Role","path":"AgentClawStack/Runtime1Role","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Role","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/Runtime1Role/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnRole","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:logicalId":"Runtime1RoleA7A82078","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"bedrock-agentcore.amazonaws.com"}}],"Version":"2012-10-17"},"description":"Execution role for agent-claw Runtime 1 (main assistant)"}}},"DefaultPolicy":{"id":"DefaultPolicy","path":"AgentClawStack/Runtime1Role/DefaultPolicy","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Policy","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/Runtime1Role/DefaultPolicy/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnPolicy","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Policy","aws:cdk:cloudformation:logicalId":"Runtime1RoleDefaultPolicy1A3D5ACF","aws:cdk:cloudformation:props":{"policyDocument":{"Statement":[{"Action":["bedrock:InvokeModel","bedrock:InvokeModelWithResponseStream"],"Effect":"Allow","Resource":"*"},{"Action":["s3:GetObject*","s3:GetBucket*","s3:List*"],"Effect":"Allow","Resource":[{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":s3:::agent-claw-workspace-495395224548"]]},{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":s3:::agent-claw-workspace-495395224548/*"]]}]},{"Action":["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],"Effect":"Allow","Resource":"arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/telegram-bot-token-Oq3in3"},{"Action":["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],"Effect":"Allow","Resource":"arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/brave-api-key-uUSgzi"},{"Action":["dynamodb:BatchGetItem","dynamodb:Query","dynamodb:GetItem","dynamodb:Scan","dynamodb:ConditionCheckItem","dynamodb:BatchWriteItem","dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:DeleteItem","dynamodb:DescribeTable"],"Effect":"Allow","Resource":[{"Fn::GetAtt":["UsersTable9725E9C8","Arn"]}]},{"Action":["dynamodb:GetRecords","dynamodb:GetShardIterator"],"Effect":"Allow","Resource":[{"Fn::GetAtt":["UsersTable9725E9C8","Arn"]}]},{"Action":["bedrock-agentcore:CreateEvent","bedrock-agentcore:ListEvents","bedrock-agentcore:RetrieveMemoryRecords"],"Effect":"Allow","Resource":"*"},{"Action":"lambda:InvokeFunctionUrl","Condition":{"StringEquals":{"lambda:FunctionUrlAuthType":"AWS_IAM"}},"Effect":"Allow","Resource":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":lambda:us-east-1:495395224548:function:agent-claw-workspace-mcp"]]},"Sid":"WorkspaceMcpInvoke"},{"Action":["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],"Effect":"Allow","Resource":"arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/google-oauth-client-subXHl"},{"Action":"secretsmanager:GetSecretValue","Effect":"Allow","Resource":"arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/google-credentials/*","Sid":"PerUserGoogleCredentialsReadRuntime"},{"Action":["events:PutRule","events:PutTargets","events:ListRules","events:ListTargetsByRule","events:RemoveTargets","events:DeleteRule"],"Effect":"Allow","Resource":"arn:aws:events:us-east-1:*:rule/agent-claw-reminder-*","Sid":"EventBridgeScheduler"},{"Action":["lambda:AddPermission","lambda:RemovePermission"],"Effect":"Allow","Resource":{"Fn::GetAtt":["SchedulerCFE73206","Arn"]},"Sid":"SchedulerLambdaPermission"}],"Version":"2012-10-17"},"policyName":"Runtime1RoleDefaultPolicy1A3D5ACF","roles":[{"Ref":"Runtime1RoleA7A82078"}]}}}}}}},"GoogleOAuthClient":{"id":"GoogleOAuthClient","path":"AgentClawStack/GoogleOAuthClient","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"2.252.0"}},"WorkspaceMcpRole":{"id":"WorkspaceMcpRole","path":"AgentClawStack/WorkspaceMcpRole","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"2.252.0"},"children":{"Policy":{"id":"Policy","path":"AgentClawStack/WorkspaceMcpRole/Policy","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Policy","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/WorkspaceMcpRole/Policy/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnPolicy","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Policy","aws:cdk:cloudformation:logicalId":"WorkspaceMcpRolePolicy5B8B0072","aws:cdk:cloudformation:props":{"policyDocument":{"Statement":[{"Action":["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],"Effect":"Allow","Resource":"arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/google-oauth-client-subXHl"},{"Action":"secretsmanager:GetSecretValue","Effect":"Allow","Resource":"arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/google-credentials/*","Sid":"PerUserGoogleCredentialsRead"}],"Version":"2012-10-17"},"policyName":"WorkspaceMcpRolePolicy5B8B0072","roles":["agent-claw-workspace-mcp-role"]}}}}}}},"WorkspaceMcp":{"id":"WorkspaceMcp","path":"AgentClawStack/WorkspaceMcp","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.FunctionBase","version":"2.252.0"}},"OAuthHandler":{"id":"OAuthHandler","path":"AgentClawStack/OAuthHandler","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.Function","version":"2.252.0"},"children":{"ServiceRole":{"id":"ServiceRole","path":"AgentClawStack/OAuthHandler/ServiceRole","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Role","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/OAuthHandler/ServiceRole/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnRole","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:logicalId":"OAuthHandlerServiceRole9CDCCF9E","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"}}],"Version":"2012-10-17"},"managedPolicyArns":[{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]]}]}}},"DefaultPolicy":{"id":"DefaultPolicy","path":"AgentClawStack/OAuthHandler/ServiceRole/DefaultPolicy","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Policy","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/OAuthHandler/ServiceRole/DefaultPolicy/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnPolicy","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Policy","aws:cdk:cloudformation:logicalId":"OAuthHandlerServiceRoleDefaultPolicy69D90416","aws:cdk:cloudformation:props":{"policyDocument":{"Statement":[{"Action":["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],"Effect":"Allow","Resource":"arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/google-oauth-client-subXHl"},{"Action":["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],"Effect":"Allow","Resource":"arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/telegram-bot-token-Oq3in3"},{"Action":["dynamodb:BatchGetItem","dynamodb:Query","dynamodb:GetItem","dynamodb:Scan","dynamodb:ConditionCheckItem","dynamodb:BatchWriteItem","dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:DeleteItem","dynamodb:DescribeTable"],"Effect":"Allow","Resource":[{"Fn::GetAtt":["UsersTable9725E9C8","Arn"]}]},{"Action":["dynamodb:GetRecords","dynamodb:GetShardIterator"],"Effect":"Allow","Resource":[{"Fn::GetAtt":["UsersTable9725E9C8","Arn"]}]},{"Action":"secretsmanager:GetSecretValue","Effect":"Allow","Resource":"arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/google-oauth-client-subXHl","Sid":"GoogleOAuthClientSecretExact"},{"Action":["secretsmanager:CreateSecret","secretsmanager:PutSecretValue","secretsmanager:GetSecretValue"],"Effect":"Allow","Resource":"arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/google-credentials/*","Sid":"PerUserGoogleCredentialsWrite"}],"Version":"2012-10-17"},"policyName":"OAuthHandlerServiceRoleDefaultPolicy69D90416","roles":[{"Ref":"OAuthHandlerServiceRole9CDCCF9E"}]}}}}}}},"Code":{"id":"Code","path":"AgentClawStack/OAuthHandler/Code","constructInfo":{"fqn":"aws-cdk-lib.aws_s3_assets.Asset","version":"2.252.0"},"children":{"Stage":{"id":"Stage","path":"AgentClawStack/OAuthHandler/Code/Stage","constructInfo":{"fqn":"aws-cdk-lib.AssetStaging","version":"2.252.0"}},"AssetBucket":{"id":"AssetBucket","path":"AgentClawStack/OAuthHandler/Code/AssetBucket","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.BucketBase","version":"2.252.0"}}}},"Resource":{"id":"Resource","path":"AgentClawStack/OAuthHandler/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnFunction","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Function","aws:cdk:cloudformation:logicalId":"OAuthHandlerC97C2476","aws:cdk:cloudformation:props":{"code":{"s3Bucket":"cdk-hnb659fds-assets-495395224548-us-east-1","s3Key":"b45b92872bd4af9d3688817f862e6574ff6b4903e68b140bcee6fe0b2678c645.zip"},"environment":{"variables":{"GOOGLE_OAUTH_CLIENT_SECRET_ARN":"arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/google-oauth-client-subXHl","USERS_TABLE_NAME":{"Ref":"UsersTable9725E9C8"},"TELEGRAM_BOT_TOKEN_SECRET_ARN":"arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/telegram-bot-token-Oq3in3","OAUTH_REDIRECT_URI":{"Fn::Join":["",["https://",{"Ref":"WebhookApi28122C53"},".execute-api.us-east-1.",{"Ref":"AWS::URLSuffix"},"/oauth/callback"]]}}},"functionName":"agent-claw-oauth-handler","handler":"handler.handler","memorySize":128,"role":{"Fn::GetAtt":["OAuthHandlerServiceRole9CDCCF9E","Arn"]},"runtime":"python3.12","timeout":30}}}}},"HeartbeatRunner":{"id":"HeartbeatRunner","path":"AgentClawStack/HeartbeatRunner","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.Function","version":"2.252.0"},"children":{"ServiceRole":{"id":"ServiceRole","path":"AgentClawStack/HeartbeatRunner/ServiceRole","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Role","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/HeartbeatRunner/ServiceRole/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnRole","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:logicalId":"HeartbeatRunnerServiceRole07B33F7E","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"}}],"Version":"2012-10-17"},"managedPolicyArns":[{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]]}]}}},"DefaultPolicy":{"id":"DefaultPolicy","path":"AgentClawStack/HeartbeatRunner/ServiceRole/DefaultPolicy","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Policy","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/HeartbeatRunner/ServiceRole/DefaultPolicy/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnPolicy","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Policy","aws:cdk:cloudformation:logicalId":"HeartbeatRunnerServiceRoleDefaultPolicy08E364EE","aws:cdk:cloudformation:props":{"policyDocument":{"Statement":[{"Action":["sqs:SendMessage","sqs:GetQueueAttributes","sqs:GetQueueUrl"],"Effect":"Allow","Resource":{"Fn::GetAtt":["MessageQueue7A3BF959","Arn"]}},{"Action":["dynamodb:BatchGetItem","dynamodb:Query","dynamodb:GetItem","dynamodb:Scan","dynamodb:ConditionCheckItem","dynamodb:DescribeTable"],"Effect":"Allow","Resource":[{"Fn::GetAtt":["UsersTable9725E9C8","Arn"]}]},{"Action":["dynamodb:GetRecords","dynamodb:GetShardIterator"],"Effect":"Allow","Resource":[{"Fn::GetAtt":["UsersTable9725E9C8","Arn"]}]}],"Version":"2012-10-17"},"policyName":"HeartbeatRunnerServiceRoleDefaultPolicy08E364EE","roles":[{"Ref":"HeartbeatRunnerServiceRole07B33F7E"}]}}}}}}},"Code":{"id":"Code","path":"AgentClawStack/HeartbeatRunner/Code","constructInfo":{"fqn":"aws-cdk-lib.aws_s3_assets.Asset","version":"2.252.0"},"children":{"Stage":{"id":"Stage","path":"AgentClawStack/HeartbeatRunner/Code/Stage","constructInfo":{"fqn":"aws-cdk-lib.AssetStaging","version":"2.252.0"}},"AssetBucket":{"id":"AssetBucket","path":"AgentClawStack/HeartbeatRunner/Code/AssetBucket","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.BucketBase","version":"2.252.0"}}}},"Resource":{"id":"Resource","path":"AgentClawStack/HeartbeatRunner/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnFunction","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Function","aws:cdk:cloudformation:logicalId":"HeartbeatRunnerEA31B930","aws:cdk:cloudformation:props":{"code":{"s3Bucket":"cdk-hnb659fds-assets-495395224548-us-east-1","s3Key":"724b3c95c6cd487c828621ad670d23696cd81da614d7df21b846c2d97ef058bf.zip"},"environment":{"variables":{"MESSAGE_QUEUE_URL":{"Ref":"MessageQueue7A3BF959"},"USERS_TABLE_NAME":{"Ref":"UsersTable9725E9C8"}}},"functionName":"agent-claw-heartbeat-runner","handler":"handler.handler","memorySize":128,"role":{"Fn::GetAtt":["HeartbeatRunnerServiceRole07B33F7E","Arn"]},"runtime":"python3.12","timeout":60}}}}},"HeartbeatRule":{"id":"HeartbeatRule","path":"AgentClawStack/HeartbeatRule","constructInfo":{"fqn":"aws-cdk-lib.aws_events.Rule","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/HeartbeatRule/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_events.CfnRule","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Events::Rule","aws:cdk:cloudformation:logicalId":"HeartbeatRuleDCC8D7FB","aws:cdk:cloudformation:props":{"name":"agent-claw-heartbeat","scheduleExpression":"rate(30 minutes)","state":"ENABLED","targets":[{"id":"Target0","arn":{"Fn::GetAtt":["HeartbeatRunnerEA31B930","Arn"]}}]}}},"AllowEventRuleAgentClawStackHeartbeatRunner11988F5B":{"id":"AllowEventRuleAgentClawStackHeartbeatRunner11988F5B","path":"AgentClawStack/HeartbeatRule/AllowEventRuleAgentClawStackHeartbeatRunner11988F5B","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnPermission","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Permission","aws:cdk:cloudformation:logicalId":"HeartbeatRuleAllowEventRuleAgentClawStackHeartbeatRunner11988F5BB95BE86F","aws:cdk:cloudformation:props":{"action":"lambda:InvokeFunction","functionName":{"Fn::GetAtt":["HeartbeatRunnerEA31B930","Arn"]},"principal":"events.amazonaws.com","sourceArn":{"Fn::GetAtt":["HeartbeatRuleDCC8D7FB","Arn"]}}}}}},"Scheduler":{"id":"Scheduler","path":"AgentClawStack/Scheduler","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.Function","version":"2.252.0"},"children":{"ServiceRole":{"id":"ServiceRole","path":"AgentClawStack/Scheduler/ServiceRole","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Role","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/Scheduler/ServiceRole/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnRole","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:logicalId":"SchedulerServiceRole62CDA70C","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"}}],"Version":"2012-10-17"},"managedPolicyArns":[{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]]}]}}},"DefaultPolicy":{"id":"DefaultPolicy","path":"AgentClawStack/Scheduler/ServiceRole/DefaultPolicy","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Policy","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/Scheduler/ServiceRole/DefaultPolicy/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnPolicy","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Policy","aws:cdk:cloudformation:logicalId":"SchedulerServiceRoleDefaultPolicyFA0D8235","aws:cdk:cloudformation:props":{"policyDocument":{"Statement":[{"Action":["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],"Effect":"Allow","Resource":"arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/telegram-bot-token-Oq3in3"},{"Action":["events:RemoveTargets","events:DeleteRule"],"Effect":"Allow","Resource":"arn:aws:events:us-east-1:495395224548:rule/agent-claw-reminder-*"}],"Version":"2012-10-17"},"policyName":"SchedulerServiceRoleDefaultPolicyFA0D8235","roles":[{"Ref":"SchedulerServiceRole62CDA70C"}]}}}}}}},"Code":{"id":"Code","path":"AgentClawStack/Scheduler/Code","constructInfo":{"fqn":"aws-cdk-lib.aws_s3_assets.Asset","version":"2.252.0"},"children":{"Stage":{"id":"Stage","path":"AgentClawStack/Scheduler/Code/Stage","constructInfo":{"fqn":"aws-cdk-lib.AssetStaging","version":"2.252.0"}},"AssetBucket":{"id":"AssetBucket","path":"AgentClawStack/Scheduler/Code/AssetBucket","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.BucketBase","version":"2.252.0"}}}},"Resource":{"id":"Resource","path":"AgentClawStack/Scheduler/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnFunction","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Function","aws:cdk:cloudformation:logicalId":"SchedulerCFE73206","aws:cdk:cloudformation:props":{"code":{"s3Bucket":"cdk-hnb659fds-assets-495395224548-us-east-1","s3Key":"8e7324457a5952eb51f04a34fbc5ba853252e7157d8d8958ac5fda92e72edb1f.zip"},"environment":{"variables":{"TELEGRAM_BOT_TOKEN_SECRET_ARN":"arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/telegram-bot-token-Oq3in3"}},"functionName":"agent-claw-scheduler","handler":"handler.handler","memorySize":128,"role":{"Fn::GetAtt":["SchedulerServiceRole62CDA70C","Arn"]},"runtime":"python3.12","timeout":30}}},"EventBridgeInvoke":{"id":"EventBridgeInvoke","path":"AgentClawStack/Scheduler/EventBridgeInvoke","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnPermission","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Permission","aws:cdk:cloudformation:logicalId":"SchedulerEventBridgeInvoke72A0529A","aws:cdk:cloudformation:props":{"action":"lambda:InvokeFunction","functionName":{"Fn::GetAtt":["SchedulerCFE73206","Arn"]},"principal":"events.amazonaws.com","sourceArn":"arn:aws:events:us-east-1:495395224548:rule/agent-claw-reminder-*"}}}}},"WorkspaceMcpFunctionUrl":{"id":"WorkspaceMcpFunctionUrl","path":"AgentClawStack/WorkspaceMcpFunctionUrl","constructInfo":{"fqn":"aws-cdk-lib.CfnOutput","version":"2.252.0"}},"OAuthStartUrl":{"id":"OAuthStartUrl","path":"AgentClawStack/OAuthStartUrl","constructInfo":{"fqn":"aws-cdk-lib.CfnOutput","version":"2.252.0"}},"OAuthRedirectUri":{"id":"OAuthRedirectUri","path":"AgentClawStack/OAuthRedirectUri","constructInfo":{"fqn":"aws-cdk-lib.CfnOutput","version":"2.252.0"}},"WebhookUrl":{"id":"WebhookUrl","path":"AgentClawStack/WebhookUrl","constructInfo":{"fqn":"aws-cdk-lib.CfnOutput","version":"2.252.0"}},"WorkspaceBucketName":{"id":"WorkspaceBucketName","path":"AgentClawStack/WorkspaceBucketName","constructInfo":{"fqn":"aws-cdk-lib.CfnOutput","version":"2.252.0"}},"SessionTableName":{"id":"SessionTableName","path":"AgentClawStack/SessionTableName","constructInfo":{"fqn":"aws-cdk-lib.CfnOutput","version":"2.252.0"}},"UsersTableName":{"id":"UsersTableName","path":"AgentClawStack/UsersTableName","constructInfo":{"fqn":"aws-cdk-lib.CfnOutput","version":"2.252.0"}},"MessageQueueUrl":{"id":"MessageQueueUrl","path":"AgentClawStack/MessageQueueUrl","constructInfo":{"fqn":"aws-cdk-lib.CfnOutput","version":"2.252.0"}},"Runtime1RoleArn":{"id":"Runtime1RoleArn","path":"AgentClawStack/Runtime1RoleArn","constructInfo":{"fqn":"aws-cdk-lib.CfnOutput","version":"2.252.0"}},"SchedulerLambdaArn":{"id":"SchedulerLambdaArn","path":"AgentClawStack/SchedulerLambdaArn","constructInfo":{"fqn":"aws-cdk-lib.CfnOutput","version":"2.252.0"}},"CDKMetadata":{"id":"CDKMetadata","path":"AgentClawStack/CDKMetadata","constructInfo":{"fqn":"constructs.Construct","version":"10.6.0"},"children":{"Default":{"id":"Default","path":"AgentClawStack/CDKMetadata/Default","constructInfo":{"fqn":"aws-cdk-lib.CfnResource","version":"2.252.0"}}}},"BootstrapVersion":{"id":"BootstrapVersion","path":"AgentClawStack/BootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnParameter","version":"2.252.0"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"AgentClawStack/CheckBootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnRule","version":"2.252.0"}}}},"Tree":{"id":"Tree","path":"Tree","constructInfo":{"fqn":"constructs.Construct","version":"10.6.0"}}}}} \ No newline at end of file +{"version":"tree-0.1","tree":{"id":"App","path":"","constructInfo":{"fqn":"aws-cdk-lib.App","version":"2.252.0"},"children":{"AgentClawStack":{"id":"AgentClawStack","path":"AgentClawStack","constructInfo":{"fqn":"aws-cdk-lib.Stack","version":"2.252.0"},"children":{"TelegramBotToken":{"id":"TelegramBotToken","path":"AgentClawStack/TelegramBotToken","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"2.252.0"}},"BraveApiKey":{"id":"BraveApiKey","path":"AgentClawStack/BraveApiKey","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"2.252.0"}},"WorkspaceBucket":{"id":"WorkspaceBucket","path":"AgentClawStack/WorkspaceBucket","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.BucketBase","version":"2.252.0"}},"SessionStore":{"id":"SessionStore","path":"AgentClawStack/SessionStore","constructInfo":{"fqn":"aws-cdk-lib.aws_dynamodb.Table","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/SessionStore/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_dynamodb.CfnTable","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::DynamoDB::Table","aws:cdk:cloudformation:logicalId":"SessionStore8C86EEFE","aws:cdk:cloudformation:props":{"attributeDefinitions":[{"attributeName":"actor_id","attributeType":"S"}],"billingMode":"PAY_PER_REQUEST","keySchema":[{"attributeName":"actor_id","keyType":"HASH"}],"tableName":"agent-claw-sessions","timeToLiveSpecification":{"attributeName":"ttl","enabled":true}}}},"ScalingRole":{"id":"ScalingRole","path":"AgentClawStack/SessionStore/ScalingRole","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"2.252.0"}}}},"UsersTable":{"id":"UsersTable","path":"AgentClawStack/UsersTable","constructInfo":{"fqn":"aws-cdk-lib.aws_dynamodb.Table","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/UsersTable/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_dynamodb.CfnTable","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::DynamoDB::Table","aws:cdk:cloudformation:logicalId":"UsersTable9725E9C8","aws:cdk:cloudformation:props":{"attributeDefinitions":[{"attributeName":"actor_id","attributeType":"S"}],"billingMode":"PAY_PER_REQUEST","keySchema":[{"attributeName":"actor_id","keyType":"HASH"}],"tableName":"agent-claw-users"}}},"ScalingRole":{"id":"ScalingRole","path":"AgentClawStack/UsersTable/ScalingRole","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"2.252.0"}}}},"MessageQueue":{"id":"MessageQueue","path":"AgentClawStack/MessageQueue","constructInfo":{"fqn":"aws-cdk-lib.aws_sqs.Queue","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/MessageQueue/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_sqs.CfnQueue","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::SQS::Queue","aws:cdk:cloudformation:logicalId":"MessageQueue7A3BF959","aws:cdk:cloudformation:props":{"contentBasedDeduplication":false,"fifoQueue":true,"queueName":"agent-claw-messages.fifo","receiveMessageWaitTimeSeconds":20,"visibilityTimeout":900}}}}},"TgIngest":{"id":"TgIngest","path":"AgentClawStack/TgIngest","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.Function","version":"2.252.0"},"children":{"ServiceRole":{"id":"ServiceRole","path":"AgentClawStack/TgIngest/ServiceRole","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Role","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/TgIngest/ServiceRole/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnRole","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:logicalId":"TgIngestServiceRoleB96980B6","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"}}],"Version":"2012-10-17"},"managedPolicyArns":[{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]]}]}}},"DefaultPolicy":{"id":"DefaultPolicy","path":"AgentClawStack/TgIngest/ServiceRole/DefaultPolicy","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Policy","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/TgIngest/ServiceRole/DefaultPolicy/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnPolicy","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Policy","aws:cdk:cloudformation:logicalId":"TgIngestServiceRoleDefaultPolicyCC51E135","aws:cdk:cloudformation:props":{"policyDocument":{"Statement":[{"Action":["sqs:SendMessage","sqs:GetQueueAttributes","sqs:GetQueueUrl"],"Effect":"Allow","Resource":{"Fn::GetAtt":["MessageQueue7A3BF959","Arn"]}},{"Action":["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],"Effect":"Allow","Resource":"arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/telegram-bot-token-Oq3in3"}],"Version":"2012-10-17"},"policyName":"TgIngestServiceRoleDefaultPolicyCC51E135","roles":[{"Ref":"TgIngestServiceRoleB96980B6"}]}}}}}}},"Code":{"id":"Code","path":"AgentClawStack/TgIngest/Code","constructInfo":{"fqn":"aws-cdk-lib.aws_s3_assets.Asset","version":"2.252.0"},"children":{"Stage":{"id":"Stage","path":"AgentClawStack/TgIngest/Code/Stage","constructInfo":{"fqn":"aws-cdk-lib.AssetStaging","version":"2.252.0"}},"AssetBucket":{"id":"AssetBucket","path":"AgentClawStack/TgIngest/Code/AssetBucket","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.BucketBase","version":"2.252.0"}}}},"Resource":{"id":"Resource","path":"AgentClawStack/TgIngest/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnFunction","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Function","aws:cdk:cloudformation:logicalId":"TgIngest4CB35C2F","aws:cdk:cloudformation:props":{"code":{"s3Bucket":"cdk-hnb659fds-assets-495395224548-us-east-1","s3Key":"8da48fd743d1e2cb70d8d1935cee795b6f8cf02609db05e2b8f28449be9ef875.zip"},"environment":{"variables":{"MESSAGE_QUEUE_URL":{"Ref":"MessageQueue7A3BF959"},"TELEGRAM_BOT_TOKEN_SECRET_ARN":"arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/telegram-bot-token-Oq3in3","TELEGRAM_WEBHOOK_SECRET":""}},"functionName":"agent-claw-tg-ingest","handler":"handler.handler","memorySize":128,"role":{"Fn::GetAtt":["TgIngestServiceRoleB96980B6","Arn"]},"runtime":"python3.12","timeout":10}}}}},"AgentRunner":{"id":"AgentRunner","path":"AgentClawStack/AgentRunner","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.Function","version":"2.252.0"},"children":{"ServiceRole":{"id":"ServiceRole","path":"AgentClawStack/AgentRunner/ServiceRole","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Role","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/AgentRunner/ServiceRole/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnRole","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:logicalId":"AgentRunnerServiceRole40CA0A00","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"}}],"Version":"2012-10-17"},"managedPolicyArns":[{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]]}]}}},"DefaultPolicy":{"id":"DefaultPolicy","path":"AgentClawStack/AgentRunner/ServiceRole/DefaultPolicy","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Policy","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/AgentRunner/ServiceRole/DefaultPolicy/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnPolicy","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Policy","aws:cdk:cloudformation:logicalId":"AgentRunnerServiceRoleDefaultPolicyA584A5CF","aws:cdk:cloudformation:props":{"policyDocument":{"Statement":[{"Action":["dynamodb:BatchGetItem","dynamodb:Query","dynamodb:GetItem","dynamodb:Scan","dynamodb:ConditionCheckItem","dynamodb:BatchWriteItem","dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:DeleteItem","dynamodb:DescribeTable"],"Effect":"Allow","Resource":[{"Fn::GetAtt":["SessionStore8C86EEFE","Arn"]}]},{"Action":["dynamodb:GetRecords","dynamodb:GetShardIterator"],"Effect":"Allow","Resource":[{"Fn::GetAtt":["SessionStore8C86EEFE","Arn"]}]},{"Action":["dynamodb:BatchGetItem","dynamodb:Query","dynamodb:GetItem","dynamodb:Scan","dynamodb:ConditionCheckItem","dynamodb:BatchWriteItem","dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:DeleteItem","dynamodb:DescribeTable"],"Effect":"Allow","Resource":[{"Fn::GetAtt":["UsersTable9725E9C8","Arn"]}]},{"Action":["dynamodb:GetRecords","dynamodb:GetShardIterator"],"Effect":"Allow","Resource":[{"Fn::GetAtt":["UsersTable9725E9C8","Arn"]}]},{"Action":["s3:GetObject*","s3:GetBucket*","s3:List*"],"Effect":"Allow","Resource":[{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":s3:::agent-claw-workspace-495395224548"]]},{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":s3:::agent-claw-workspace-495395224548/*"]]}]},{"Action":["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],"Effect":"Allow","Resource":"arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/telegram-bot-token-Oq3in3"},{"Action":["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],"Effect":"Allow","Resource":"arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/brave-api-key-uUSgzi"},{"Action":["sqs:ReceiveMessage","sqs:ChangeMessageVisibility","sqs:GetQueueUrl","sqs:DeleteMessage","sqs:GetQueueAttributes"],"Effect":"Allow","Resource":{"Fn::GetAtt":["MessageQueue7A3BF959","Arn"]}},{"Action":"bedrock-agentcore:InvokeAgentRuntime","Effect":"Allow","Resource":"*"}],"Version":"2012-10-17"},"policyName":"AgentRunnerServiceRoleDefaultPolicyA584A5CF","roles":[{"Ref":"AgentRunnerServiceRole40CA0A00"}]}}}}}}},"Code":{"id":"Code","path":"AgentClawStack/AgentRunner/Code","constructInfo":{"fqn":"aws-cdk-lib.aws_s3_assets.Asset","version":"2.252.0"},"children":{"Stage":{"id":"Stage","path":"AgentClawStack/AgentRunner/Code/Stage","constructInfo":{"fqn":"aws-cdk-lib.AssetStaging","version":"2.252.0"}},"AssetBucket":{"id":"AssetBucket","path":"AgentClawStack/AgentRunner/Code/AssetBucket","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.BucketBase","version":"2.252.0"}}}},"Resource":{"id":"Resource","path":"AgentClawStack/AgentRunner/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnFunction","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Function","aws:cdk:cloudformation:logicalId":"AgentRunnerBDE3FA56","aws:cdk:cloudformation:props":{"code":{"s3Bucket":"cdk-hnb659fds-assets-495395224548-us-east-1","s3Key":"647684a0ff5a7a3df590aa5532173310dace910d7081be6f3a642f7e81dabc06.zip"},"environment":{"variables":{"SESSION_TABLE_NAME":{"Ref":"SessionStore8C86EEFE"},"WORKSPACE_BUCKET_NAME":"agent-claw-workspace-495395224548","TELEGRAM_BOT_TOKEN_SECRET_ARN":"arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/telegram-bot-token-Oq3in3","BRAVE_API_KEY_SECRET_ARN":"arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/brave-api-key-uUSgzi","RUNTIME_1_ARN":"arn:aws:bedrock-agentcore:us-east-1:495395224548:runtime/agentclaw_agent_claw_main-vTRGIEG6ON","AWS_REGION_NAME":"us-east-1","USERS_TABLE_NAME":{"Ref":"UsersTable9725E9C8"},"WORKSPACE_MCP_URL":"https://25hugrzw4uwtueeg77jsmft6lq0wunmd.lambda-url.us-east-1.on.aws/mcp"}},"functionName":"agent-claw-agent-runner","handler":"handler.handler","memorySize":256,"role":{"Fn::GetAtt":["AgentRunnerServiceRole40CA0A00","Arn"]},"runtime":"python3.12","timeout":900}}},"SqsEventSource:AgentClawStackMessageQueue9AF4DF23":{"id":"SqsEventSource:AgentClawStackMessageQueue9AF4DF23","path":"AgentClawStack/AgentRunner/SqsEventSource:AgentClawStackMessageQueue9AF4DF23","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.EventSourceMapping","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/AgentRunner/SqsEventSource:AgentClawStackMessageQueue9AF4DF23/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnEventSourceMapping","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::EventSourceMapping","aws:cdk:cloudformation:logicalId":"AgentRunnerSqsEventSourceAgentClawStackMessageQueue9AF4DF234671B32B","aws:cdk:cloudformation:props":{"batchSize":10,"enabled":true,"eventSourceArn":{"Fn::GetAtt":["MessageQueue7A3BF959","Arn"]},"functionName":{"Ref":"AgentRunnerBDE3FA56"}}}}}}}},"WebhookApi":{"id":"WebhookApi","path":"AgentClawStack/WebhookApi","constructInfo":{"fqn":"aws-cdk-lib.aws_apigatewayv2.HttpApi","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/WebhookApi/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_apigatewayv2.CfnApi","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::ApiGatewayV2::Api","aws:cdk:cloudformation:logicalId":"WebhookApi28122C53","aws:cdk:cloudformation:props":{"name":"agent-claw-webhook","protocolType":"HTTP"}}},"DefaultStage":{"id":"DefaultStage","path":"AgentClawStack/WebhookApi/DefaultStage","constructInfo":{"fqn":"aws-cdk-lib.aws_apigatewayv2.HttpStage","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/WebhookApi/DefaultStage/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_apigatewayv2.CfnStage","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::ApiGatewayV2::Stage","aws:cdk:cloudformation:logicalId":"WebhookApiDefaultStageC0BC9CA5","aws:cdk:cloudformation:props":{"apiId":{"Ref":"WebhookApi28122C53"},"autoDeploy":true,"stageName":"$default"}}}}},"POST--telegram":{"id":"POST--telegram","path":"AgentClawStack/WebhookApi/POST--telegram","constructInfo":{"fqn":"aws-cdk-lib.aws_apigatewayv2.HttpRoute","version":"2.252.0"},"children":{"TgIngestIntegration":{"id":"TgIngestIntegration","path":"AgentClawStack/WebhookApi/POST--telegram/TgIngestIntegration","constructInfo":{"fqn":"aws-cdk-lib.aws_apigatewayv2.HttpIntegration","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/WebhookApi/POST--telegram/TgIngestIntegration/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_apigatewayv2.CfnIntegration","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::ApiGatewayV2::Integration","aws:cdk:cloudformation:logicalId":"WebhookApiPOSTtelegramTgIngestIntegration9EE5BB85","aws:cdk:cloudformation:props":{"apiId":{"Ref":"WebhookApi28122C53"},"integrationType":"AWS_PROXY","integrationUri":{"Fn::GetAtt":["TgIngest4CB35C2F","Arn"]},"payloadFormatVersion":"2.0"}}}}},"TgIngestIntegration-Permission":{"id":"TgIngestIntegration-Permission","path":"AgentClawStack/WebhookApi/POST--telegram/TgIngestIntegration-Permission","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnPermission","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Permission","aws:cdk:cloudformation:logicalId":"WebhookApiPOSTtelegramTgIngestIntegrationPermissionFEBC2E3B","aws:cdk:cloudformation:props":{"action":"lambda:InvokeFunction","functionName":{"Fn::GetAtt":["TgIngest4CB35C2F","Arn"]},"principal":"apigateway.amazonaws.com","sourceArn":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":execute-api:us-east-1:495395224548:",{"Ref":"WebhookApi28122C53"},"/*/*/telegram"]]}}}},"Resource":{"id":"Resource","path":"AgentClawStack/WebhookApi/POST--telegram/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_apigatewayv2.CfnRoute","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::ApiGatewayV2::Route","aws:cdk:cloudformation:logicalId":"WebhookApiPOSTtelegramF7127CFF","aws:cdk:cloudformation:props":{"apiId":{"Ref":"WebhookApi28122C53"},"authorizationType":"NONE","routeKey":"POST /telegram","target":{"Fn::Join":["",["integrations/",{"Ref":"WebhookApiPOSTtelegramTgIngestIntegration9EE5BB85"}]]}}}}}},"GET--oauth--start":{"id":"GET--oauth--start","path":"AgentClawStack/WebhookApi/GET--oauth--start","constructInfo":{"fqn":"aws-cdk-lib.aws_apigatewayv2.HttpRoute","version":"2.252.0"},"children":{"OAuthStartIntegration":{"id":"OAuthStartIntegration","path":"AgentClawStack/WebhookApi/GET--oauth--start/OAuthStartIntegration","constructInfo":{"fqn":"aws-cdk-lib.aws_apigatewayv2.HttpIntegration","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/WebhookApi/GET--oauth--start/OAuthStartIntegration/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_apigatewayv2.CfnIntegration","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::ApiGatewayV2::Integration","aws:cdk:cloudformation:logicalId":"WebhookApiGEToauthstartOAuthStartIntegrationA546443F","aws:cdk:cloudformation:props":{"apiId":{"Ref":"WebhookApi28122C53"},"integrationType":"AWS_PROXY","integrationUri":{"Fn::GetAtt":["OAuthHandlerC97C2476","Arn"]},"payloadFormatVersion":"2.0"}}}}},"OAuthStartIntegration-Permission":{"id":"OAuthStartIntegration-Permission","path":"AgentClawStack/WebhookApi/GET--oauth--start/OAuthStartIntegration-Permission","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnPermission","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Permission","aws:cdk:cloudformation:logicalId":"WebhookApiGEToauthstartOAuthStartIntegrationPermission38BAEF6D","aws:cdk:cloudformation:props":{"action":"lambda:InvokeFunction","functionName":{"Fn::GetAtt":["OAuthHandlerC97C2476","Arn"]},"principal":"apigateway.amazonaws.com","sourceArn":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":execute-api:us-east-1:495395224548:",{"Ref":"WebhookApi28122C53"},"/*/*/oauth/start"]]}}}},"Resource":{"id":"Resource","path":"AgentClawStack/WebhookApi/GET--oauth--start/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_apigatewayv2.CfnRoute","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::ApiGatewayV2::Route","aws:cdk:cloudformation:logicalId":"WebhookApiGEToauthstart6DCA713A","aws:cdk:cloudformation:props":{"apiId":{"Ref":"WebhookApi28122C53"},"authorizationType":"NONE","routeKey":"GET /oauth/start","target":{"Fn::Join":["",["integrations/",{"Ref":"WebhookApiGEToauthstartOAuthStartIntegrationA546443F"}]]}}}}}},"GET--oauth--callback":{"id":"GET--oauth--callback","path":"AgentClawStack/WebhookApi/GET--oauth--callback","constructInfo":{"fqn":"aws-cdk-lib.aws_apigatewayv2.HttpRoute","version":"2.252.0"},"children":{"OAuthCallbackIntegration":{"id":"OAuthCallbackIntegration","path":"AgentClawStack/WebhookApi/GET--oauth--callback/OAuthCallbackIntegration","constructInfo":{"fqn":"aws-cdk-lib.aws_apigatewayv2.HttpIntegration","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/WebhookApi/GET--oauth--callback/OAuthCallbackIntegration/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_apigatewayv2.CfnIntegration","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::ApiGatewayV2::Integration","aws:cdk:cloudformation:logicalId":"WebhookApiGEToauthcallbackOAuthCallbackIntegrationCFBBEB09","aws:cdk:cloudformation:props":{"apiId":{"Ref":"WebhookApi28122C53"},"integrationType":"AWS_PROXY","integrationUri":{"Fn::GetAtt":["OAuthHandlerC97C2476","Arn"]},"payloadFormatVersion":"2.0"}}}}},"OAuthCallbackIntegration-Permission":{"id":"OAuthCallbackIntegration-Permission","path":"AgentClawStack/WebhookApi/GET--oauth--callback/OAuthCallbackIntegration-Permission","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnPermission","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Permission","aws:cdk:cloudformation:logicalId":"WebhookApiGEToauthcallbackOAuthCallbackIntegrationPermission6BA3A5AD","aws:cdk:cloudformation:props":{"action":"lambda:InvokeFunction","functionName":{"Fn::GetAtt":["OAuthHandlerC97C2476","Arn"]},"principal":"apigateway.amazonaws.com","sourceArn":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":execute-api:us-east-1:495395224548:",{"Ref":"WebhookApi28122C53"},"/*/*/oauth/callback"]]}}}},"Resource":{"id":"Resource","path":"AgentClawStack/WebhookApi/GET--oauth--callback/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_apigatewayv2.CfnRoute","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::ApiGatewayV2::Route","aws:cdk:cloudformation:logicalId":"WebhookApiGEToauthcallbackFC1F6BCD","aws:cdk:cloudformation:props":{"apiId":{"Ref":"WebhookApi28122C53"},"authorizationType":"NONE","routeKey":"GET /oauth/callback","target":{"Fn::Join":["",["integrations/",{"Ref":"WebhookApiGEToauthcallbackOAuthCallbackIntegrationCFBBEB09"}]]}}}}}},"ANY--workspace--{proxy+}":{"id":"ANY--workspace--{proxy+}","path":"AgentClawStack/WebhookApi/ANY--workspace--{proxy+}","constructInfo":{"fqn":"aws-cdk-lib.aws_apigatewayv2.HttpRoute","version":"2.252.0"},"children":{"WorkspaceMcpIntegration":{"id":"WorkspaceMcpIntegration","path":"AgentClawStack/WebhookApi/ANY--workspace--{proxy+}/WorkspaceMcpIntegration","constructInfo":{"fqn":"aws-cdk-lib.aws_apigatewayv2.HttpIntegration","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/WebhookApi/ANY--workspace--{proxy+}/WorkspaceMcpIntegration/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_apigatewayv2.CfnIntegration","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::ApiGatewayV2::Integration","aws:cdk:cloudformation:logicalId":"WebhookApiANYworkspaceproxyWorkspaceMcpIntegration7377EE13","aws:cdk:cloudformation:props":{"apiId":{"Ref":"WebhookApi28122C53"},"integrationType":"AWS_PROXY","integrationUri":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":lambda:us-east-1:495395224548:function:agent-claw-workspace-mcp"]]},"payloadFormatVersion":"2.0"}}}}},"WorkspaceMcpIntegration-Permission":{"id":"WorkspaceMcpIntegration-Permission","path":"AgentClawStack/WebhookApi/ANY--workspace--{proxy+}/WorkspaceMcpIntegration-Permission","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnPermission","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Permission","aws:cdk:cloudformation:logicalId":"WebhookApiANYworkspaceproxyWorkspaceMcpIntegrationPermission97613ADF","aws:cdk:cloudformation:props":{"action":"lambda:InvokeFunction","functionName":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":lambda:us-east-1:495395224548:function:agent-claw-workspace-mcp"]]},"principal":"apigateway.amazonaws.com","sourceArn":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":execute-api:us-east-1:495395224548:",{"Ref":"WebhookApi28122C53"},"/*/*/workspace/{proxy+}"]]}}}},"Resource":{"id":"Resource","path":"AgentClawStack/WebhookApi/ANY--workspace--{proxy+}/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_apigatewayv2.CfnRoute","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::ApiGatewayV2::Route","aws:cdk:cloudformation:logicalId":"WebhookApiANYworkspaceproxy4455BE19","aws:cdk:cloudformation:props":{"apiId":{"Ref":"WebhookApi28122C53"},"authorizationType":"NONE","routeKey":"ANY /workspace/{proxy+}","target":{"Fn::Join":["",["integrations/",{"Ref":"WebhookApiANYworkspaceproxyWorkspaceMcpIntegration7377EE13"}]]}}}}}}}},"Runtime1Role":{"id":"Runtime1Role","path":"AgentClawStack/Runtime1Role","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Role","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/Runtime1Role/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnRole","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:logicalId":"Runtime1RoleA7A82078","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"bedrock-agentcore.amazonaws.com"}}],"Version":"2012-10-17"},"description":"Execution role for agent-claw Runtime 1 (main assistant)"}}},"DefaultPolicy":{"id":"DefaultPolicy","path":"AgentClawStack/Runtime1Role/DefaultPolicy","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Policy","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/Runtime1Role/DefaultPolicy/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnPolicy","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Policy","aws:cdk:cloudformation:logicalId":"Runtime1RoleDefaultPolicy1A3D5ACF","aws:cdk:cloudformation:props":{"policyDocument":{"Statement":[{"Action":["bedrock:InvokeModel","bedrock:InvokeModelWithResponseStream"],"Effect":"Allow","Resource":"*"},{"Action":["s3:GetObject*","s3:GetBucket*","s3:List*"],"Effect":"Allow","Resource":[{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":s3:::agent-claw-workspace-495395224548"]]},{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":s3:::agent-claw-workspace-495395224548/*"]]}]},{"Action":["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],"Effect":"Allow","Resource":"arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/telegram-bot-token-Oq3in3"},{"Action":["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],"Effect":"Allow","Resource":"arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/brave-api-key-uUSgzi"},{"Action":["dynamodb:BatchGetItem","dynamodb:Query","dynamodb:GetItem","dynamodb:Scan","dynamodb:ConditionCheckItem","dynamodb:BatchWriteItem","dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:DeleteItem","dynamodb:DescribeTable"],"Effect":"Allow","Resource":[{"Fn::GetAtt":["UsersTable9725E9C8","Arn"]}]},{"Action":["dynamodb:GetRecords","dynamodb:GetShardIterator"],"Effect":"Allow","Resource":[{"Fn::GetAtt":["UsersTable9725E9C8","Arn"]}]},{"Action":["bedrock-agentcore:CreateEvent","bedrock-agentcore:ListEvents","bedrock-agentcore:RetrieveMemoryRecords"],"Effect":"Allow","Resource":"*"},{"Action":"lambda:InvokeFunctionUrl","Condition":{"StringEquals":{"lambda:FunctionUrlAuthType":"AWS_IAM"}},"Effect":"Allow","Resource":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":lambda:us-east-1:495395224548:function:agent-claw-workspace-mcp"]]},"Sid":"WorkspaceMcpInvoke"},{"Action":["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],"Effect":"Allow","Resource":"arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/google-oauth-client-subXHl"},{"Action":"secretsmanager:GetSecretValue","Effect":"Allow","Resource":"arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/google-credentials/*","Sid":"PerUserGoogleCredentialsReadRuntime"},{"Action":"secretsmanager:ListSecrets","Effect":"Allow","Resource":"*","Sid":"GoogleCredentialsListRuntime"},{"Action":["events:PutRule","events:PutTargets","events:ListRules","events:ListTargetsByRule","events:RemoveTargets","events:DeleteRule"],"Effect":"Allow","Resource":"arn:aws:events:us-east-1:*:rule/agent-claw-reminder-*","Sid":"EventBridgeScheduler"},{"Action":["lambda:AddPermission","lambda:RemovePermission"],"Effect":"Allow","Resource":{"Fn::GetAtt":["SchedulerCFE73206","Arn"]},"Sid":"SchedulerLambdaPermission"}],"Version":"2012-10-17"},"policyName":"Runtime1RoleDefaultPolicy1A3D5ACF","roles":[{"Ref":"Runtime1RoleA7A82078"}]}}}}}}},"GoogleOAuthClient":{"id":"GoogleOAuthClient","path":"AgentClawStack/GoogleOAuthClient","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"2.252.0"}},"WorkspaceMcpRole":{"id":"WorkspaceMcpRole","path":"AgentClawStack/WorkspaceMcpRole","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"2.252.0"},"children":{"Policy":{"id":"Policy","path":"AgentClawStack/WorkspaceMcpRole/Policy","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Policy","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/WorkspaceMcpRole/Policy/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnPolicy","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Policy","aws:cdk:cloudformation:logicalId":"WorkspaceMcpRolePolicy5B8B0072","aws:cdk:cloudformation:props":{"policyDocument":{"Statement":[{"Action":["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],"Effect":"Allow","Resource":"arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/google-oauth-client-subXHl"},{"Action":"secretsmanager:GetSecretValue","Effect":"Allow","Resource":"arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/google-credentials/*","Sid":"PerUserGoogleCredentialsRead"}],"Version":"2012-10-17"},"policyName":"WorkspaceMcpRolePolicy5B8B0072","roles":["agent-claw-workspace-mcp-role"]}}}}}}},"WorkspaceMcp":{"id":"WorkspaceMcp","path":"AgentClawStack/WorkspaceMcp","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.FunctionBase","version":"2.252.0"}},"OAuthHandler":{"id":"OAuthHandler","path":"AgentClawStack/OAuthHandler","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.Function","version":"2.252.0"},"children":{"ServiceRole":{"id":"ServiceRole","path":"AgentClawStack/OAuthHandler/ServiceRole","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Role","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/OAuthHandler/ServiceRole/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnRole","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:logicalId":"OAuthHandlerServiceRole9CDCCF9E","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"}}],"Version":"2012-10-17"},"managedPolicyArns":[{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]]}]}}},"DefaultPolicy":{"id":"DefaultPolicy","path":"AgentClawStack/OAuthHandler/ServiceRole/DefaultPolicy","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Policy","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/OAuthHandler/ServiceRole/DefaultPolicy/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnPolicy","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Policy","aws:cdk:cloudformation:logicalId":"OAuthHandlerServiceRoleDefaultPolicy69D90416","aws:cdk:cloudformation:props":{"policyDocument":{"Statement":[{"Action":["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],"Effect":"Allow","Resource":"arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/google-oauth-client-subXHl"},{"Action":["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],"Effect":"Allow","Resource":"arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/telegram-bot-token-Oq3in3"},{"Action":["dynamodb:BatchGetItem","dynamodb:Query","dynamodb:GetItem","dynamodb:Scan","dynamodb:ConditionCheckItem","dynamodb:BatchWriteItem","dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:DeleteItem","dynamodb:DescribeTable"],"Effect":"Allow","Resource":[{"Fn::GetAtt":["UsersTable9725E9C8","Arn"]}]},{"Action":["dynamodb:GetRecords","dynamodb:GetShardIterator"],"Effect":"Allow","Resource":[{"Fn::GetAtt":["UsersTable9725E9C8","Arn"]}]},{"Action":"secretsmanager:GetSecretValue","Effect":"Allow","Resource":"arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/google-oauth-client-subXHl","Sid":"GoogleOAuthClientSecretExact"},{"Action":["secretsmanager:CreateSecret","secretsmanager:PutSecretValue","secretsmanager:GetSecretValue"],"Effect":"Allow","Resource":"arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/google-credentials/*","Sid":"PerUserGoogleCredentialsWrite"}],"Version":"2012-10-17"},"policyName":"OAuthHandlerServiceRoleDefaultPolicy69D90416","roles":[{"Ref":"OAuthHandlerServiceRole9CDCCF9E"}]}}}}}}},"Code":{"id":"Code","path":"AgentClawStack/OAuthHandler/Code","constructInfo":{"fqn":"aws-cdk-lib.aws_s3_assets.Asset","version":"2.252.0"},"children":{"Stage":{"id":"Stage","path":"AgentClawStack/OAuthHandler/Code/Stage","constructInfo":{"fqn":"aws-cdk-lib.AssetStaging","version":"2.252.0"}},"AssetBucket":{"id":"AssetBucket","path":"AgentClawStack/OAuthHandler/Code/AssetBucket","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.BucketBase","version":"2.252.0"}}}},"Resource":{"id":"Resource","path":"AgentClawStack/OAuthHandler/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnFunction","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Function","aws:cdk:cloudformation:logicalId":"OAuthHandlerC97C2476","aws:cdk:cloudformation:props":{"code":{"s3Bucket":"cdk-hnb659fds-assets-495395224548-us-east-1","s3Key":"99aabce70089266e2352cb313d55ee18b849e39c418e8e9cd25dea8c4bf85fc4.zip"},"environment":{"variables":{"GOOGLE_OAUTH_CLIENT_SECRET_ARN":"arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/google-oauth-client-subXHl","USERS_TABLE_NAME":{"Ref":"UsersTable9725E9C8"},"TELEGRAM_BOT_TOKEN_SECRET_ARN":"arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/telegram-bot-token-Oq3in3","OAUTH_REDIRECT_URI":{"Fn::Join":["",["https://",{"Ref":"WebhookApi28122C53"},".execute-api.us-east-1.",{"Ref":"AWS::URLSuffix"},"/oauth/callback"]]}}},"functionName":"agent-claw-oauth-handler","handler":"handler.handler","memorySize":128,"role":{"Fn::GetAtt":["OAuthHandlerServiceRole9CDCCF9E","Arn"]},"runtime":"python3.12","timeout":30}}}}},"HeartbeatRunner":{"id":"HeartbeatRunner","path":"AgentClawStack/HeartbeatRunner","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.Function","version":"2.252.0"},"children":{"ServiceRole":{"id":"ServiceRole","path":"AgentClawStack/HeartbeatRunner/ServiceRole","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Role","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/HeartbeatRunner/ServiceRole/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnRole","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:logicalId":"HeartbeatRunnerServiceRole07B33F7E","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"}}],"Version":"2012-10-17"},"managedPolicyArns":[{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]]}]}}},"DefaultPolicy":{"id":"DefaultPolicy","path":"AgentClawStack/HeartbeatRunner/ServiceRole/DefaultPolicy","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Policy","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/HeartbeatRunner/ServiceRole/DefaultPolicy/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnPolicy","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Policy","aws:cdk:cloudformation:logicalId":"HeartbeatRunnerServiceRoleDefaultPolicy08E364EE","aws:cdk:cloudformation:props":{"policyDocument":{"Statement":[{"Action":["sqs:SendMessage","sqs:GetQueueAttributes","sqs:GetQueueUrl"],"Effect":"Allow","Resource":{"Fn::GetAtt":["MessageQueue7A3BF959","Arn"]}},{"Action":["dynamodb:BatchGetItem","dynamodb:Query","dynamodb:GetItem","dynamodb:Scan","dynamodb:ConditionCheckItem","dynamodb:DescribeTable"],"Effect":"Allow","Resource":[{"Fn::GetAtt":["UsersTable9725E9C8","Arn"]}]},{"Action":["dynamodb:GetRecords","dynamodb:GetShardIterator"],"Effect":"Allow","Resource":[{"Fn::GetAtt":["UsersTable9725E9C8","Arn"]}]}],"Version":"2012-10-17"},"policyName":"HeartbeatRunnerServiceRoleDefaultPolicy08E364EE","roles":[{"Ref":"HeartbeatRunnerServiceRole07B33F7E"}]}}}}}}},"Code":{"id":"Code","path":"AgentClawStack/HeartbeatRunner/Code","constructInfo":{"fqn":"aws-cdk-lib.aws_s3_assets.Asset","version":"2.252.0"},"children":{"Stage":{"id":"Stage","path":"AgentClawStack/HeartbeatRunner/Code/Stage","constructInfo":{"fqn":"aws-cdk-lib.AssetStaging","version":"2.252.0"}},"AssetBucket":{"id":"AssetBucket","path":"AgentClawStack/HeartbeatRunner/Code/AssetBucket","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.BucketBase","version":"2.252.0"}}}},"Resource":{"id":"Resource","path":"AgentClawStack/HeartbeatRunner/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnFunction","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Function","aws:cdk:cloudformation:logicalId":"HeartbeatRunnerEA31B930","aws:cdk:cloudformation:props":{"code":{"s3Bucket":"cdk-hnb659fds-assets-495395224548-us-east-1","s3Key":"724b3c95c6cd487c828621ad670d23696cd81da614d7df21b846c2d97ef058bf.zip"},"environment":{"variables":{"MESSAGE_QUEUE_URL":{"Ref":"MessageQueue7A3BF959"},"USERS_TABLE_NAME":{"Ref":"UsersTable9725E9C8"}}},"functionName":"agent-claw-heartbeat-runner","handler":"handler.handler","memorySize":128,"role":{"Fn::GetAtt":["HeartbeatRunnerServiceRole07B33F7E","Arn"]},"runtime":"python3.12","timeout":60}}}}},"HeartbeatRule":{"id":"HeartbeatRule","path":"AgentClawStack/HeartbeatRule","constructInfo":{"fqn":"aws-cdk-lib.aws_events.Rule","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/HeartbeatRule/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_events.CfnRule","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Events::Rule","aws:cdk:cloudformation:logicalId":"HeartbeatRuleDCC8D7FB","aws:cdk:cloudformation:props":{"name":"agent-claw-heartbeat","scheduleExpression":"rate(30 minutes)","state":"ENABLED","targets":[{"id":"Target0","arn":{"Fn::GetAtt":["HeartbeatRunnerEA31B930","Arn"]}}]}}},"AllowEventRuleAgentClawStackHeartbeatRunner11988F5B":{"id":"AllowEventRuleAgentClawStackHeartbeatRunner11988F5B","path":"AgentClawStack/HeartbeatRule/AllowEventRuleAgentClawStackHeartbeatRunner11988F5B","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnPermission","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Permission","aws:cdk:cloudformation:logicalId":"HeartbeatRuleAllowEventRuleAgentClawStackHeartbeatRunner11988F5BB95BE86F","aws:cdk:cloudformation:props":{"action":"lambda:InvokeFunction","functionName":{"Fn::GetAtt":["HeartbeatRunnerEA31B930","Arn"]},"principal":"events.amazonaws.com","sourceArn":{"Fn::GetAtt":["HeartbeatRuleDCC8D7FB","Arn"]}}}}}},"Scheduler":{"id":"Scheduler","path":"AgentClawStack/Scheduler","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.Function","version":"2.252.0"},"children":{"ServiceRole":{"id":"ServiceRole","path":"AgentClawStack/Scheduler/ServiceRole","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Role","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/Scheduler/ServiceRole/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnRole","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:logicalId":"SchedulerServiceRole62CDA70C","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"}}],"Version":"2012-10-17"},"managedPolicyArns":[{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]]}]}}},"DefaultPolicy":{"id":"DefaultPolicy","path":"AgentClawStack/Scheduler/ServiceRole/DefaultPolicy","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Policy","version":"2.252.0"},"children":{"Resource":{"id":"Resource","path":"AgentClawStack/Scheduler/ServiceRole/DefaultPolicy/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnPolicy","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Policy","aws:cdk:cloudformation:logicalId":"SchedulerServiceRoleDefaultPolicyFA0D8235","aws:cdk:cloudformation:props":{"policyDocument":{"Statement":[{"Action":["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],"Effect":"Allow","Resource":"arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/telegram-bot-token-Oq3in3"},{"Action":["events:RemoveTargets","events:DeleteRule"],"Effect":"Allow","Resource":"arn:aws:events:us-east-1:495395224548:rule/agent-claw-reminder-*"}],"Version":"2012-10-17"},"policyName":"SchedulerServiceRoleDefaultPolicyFA0D8235","roles":[{"Ref":"SchedulerServiceRole62CDA70C"}]}}}}}}},"Code":{"id":"Code","path":"AgentClawStack/Scheduler/Code","constructInfo":{"fqn":"aws-cdk-lib.aws_s3_assets.Asset","version":"2.252.0"},"children":{"Stage":{"id":"Stage","path":"AgentClawStack/Scheduler/Code/Stage","constructInfo":{"fqn":"aws-cdk-lib.AssetStaging","version":"2.252.0"}},"AssetBucket":{"id":"AssetBucket","path":"AgentClawStack/Scheduler/Code/AssetBucket","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.BucketBase","version":"2.252.0"}}}},"Resource":{"id":"Resource","path":"AgentClawStack/Scheduler/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnFunction","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Function","aws:cdk:cloudformation:logicalId":"SchedulerCFE73206","aws:cdk:cloudformation:props":{"code":{"s3Bucket":"cdk-hnb659fds-assets-495395224548-us-east-1","s3Key":"8e7324457a5952eb51f04a34fbc5ba853252e7157d8d8958ac5fda92e72edb1f.zip"},"environment":{"variables":{"TELEGRAM_BOT_TOKEN_SECRET_ARN":"arn:aws:secretsmanager:us-east-1:495395224548:secret:agent-claw/telegram-bot-token-Oq3in3"}},"functionName":"agent-claw-scheduler","handler":"handler.handler","memorySize":128,"role":{"Fn::GetAtt":["SchedulerServiceRole62CDA70C","Arn"]},"runtime":"python3.12","timeout":30}}},"EventBridgeInvoke":{"id":"EventBridgeInvoke","path":"AgentClawStack/Scheduler/EventBridgeInvoke","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnPermission","version":"2.252.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Permission","aws:cdk:cloudformation:logicalId":"SchedulerEventBridgeInvoke72A0529A","aws:cdk:cloudformation:props":{"action":"lambda:InvokeFunction","functionName":{"Fn::GetAtt":["SchedulerCFE73206","Arn"]},"principal":"events.amazonaws.com","sourceArn":"arn:aws:events:us-east-1:495395224548:rule/agent-claw-reminder-*"}}}}},"WorkspaceMcpFunctionUrl":{"id":"WorkspaceMcpFunctionUrl","path":"AgentClawStack/WorkspaceMcpFunctionUrl","constructInfo":{"fqn":"aws-cdk-lib.CfnOutput","version":"2.252.0"}},"OAuthStartUrl":{"id":"OAuthStartUrl","path":"AgentClawStack/OAuthStartUrl","constructInfo":{"fqn":"aws-cdk-lib.CfnOutput","version":"2.252.0"}},"OAuthRedirectUri":{"id":"OAuthRedirectUri","path":"AgentClawStack/OAuthRedirectUri","constructInfo":{"fqn":"aws-cdk-lib.CfnOutput","version":"2.252.0"}},"WebhookUrl":{"id":"WebhookUrl","path":"AgentClawStack/WebhookUrl","constructInfo":{"fqn":"aws-cdk-lib.CfnOutput","version":"2.252.0"}},"WorkspaceBucketName":{"id":"WorkspaceBucketName","path":"AgentClawStack/WorkspaceBucketName","constructInfo":{"fqn":"aws-cdk-lib.CfnOutput","version":"2.252.0"}},"SessionTableName":{"id":"SessionTableName","path":"AgentClawStack/SessionTableName","constructInfo":{"fqn":"aws-cdk-lib.CfnOutput","version":"2.252.0"}},"UsersTableName":{"id":"UsersTableName","path":"AgentClawStack/UsersTableName","constructInfo":{"fqn":"aws-cdk-lib.CfnOutput","version":"2.252.0"}},"MessageQueueUrl":{"id":"MessageQueueUrl","path":"AgentClawStack/MessageQueueUrl","constructInfo":{"fqn":"aws-cdk-lib.CfnOutput","version":"2.252.0"}},"Runtime1RoleArn":{"id":"Runtime1RoleArn","path":"AgentClawStack/Runtime1RoleArn","constructInfo":{"fqn":"aws-cdk-lib.CfnOutput","version":"2.252.0"}},"SchedulerLambdaArn":{"id":"SchedulerLambdaArn","path":"AgentClawStack/SchedulerLambdaArn","constructInfo":{"fqn":"aws-cdk-lib.CfnOutput","version":"2.252.0"}},"CDKMetadata":{"id":"CDKMetadata","path":"AgentClawStack/CDKMetadata","constructInfo":{"fqn":"constructs.Construct","version":"10.6.0"},"children":{"Default":{"id":"Default","path":"AgentClawStack/CDKMetadata/Default","constructInfo":{"fqn":"aws-cdk-lib.CfnResource","version":"2.252.0"}}}},"BootstrapVersion":{"id":"BootstrapVersion","path":"AgentClawStack/BootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnParameter","version":"2.252.0"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"AgentClawStack/CheckBootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnRule","version":"2.252.0"}}}},"Tree":{"id":"Tree","path":"Tree","constructInfo":{"fqn":"constructs.Construct","version":"10.6.0"}}}}} \ No newline at end of file diff --git a/cdk/lib/agent-claw-stack.ts b/cdk/lib/agent-claw-stack.ts index 84311bb..88978c1 100644 --- a/cdk/lib/agent-claw-stack.ts +++ b/cdk/lib/agent-claw-stack.ts @@ -230,6 +230,11 @@ export class AgentClawStack extends cdk.Stack { actions: ['secretsmanager:GetSecretValue'], resources: [`arn:aws:secretsmanager:${this.region}:${this.account}:secret:agent-claw/google-credentials/*`], })); + runtime1Role.addToPolicy(new iam.PolicyStatement({ + sid: 'GoogleCredentialsListRuntime', + actions: ['secretsmanager:ListSecrets'], + resources: ['*'], + })); // Pass workspace_mcp MCP URL to agent-runner (informational) agentRunnerFn.addEnvironment('WORKSPACE_MCP_URL', workspaceMcpMcpUrl);