mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-02-08 22:05:08 -05:00
Merge branch 'master' into bently/secrt-881-find-local-businesses-using-google-maps-list-building
This commit is contained in:
@@ -74,6 +74,11 @@ SMTP_PASSWORD=
|
||||
MEDIUM_API_KEY=
|
||||
MEDIUM_AUTHOR_ID=
|
||||
|
||||
# Google Maps
|
||||
GOOGLE_MAPS_API_KEY=
|
||||
|
||||
# Replicate
|
||||
REPLICATE_API_KEY=
|
||||
|
||||
# Logging Configuration
|
||||
LOG_LEVEL=INFO
|
||||
|
||||
127
autogpt_platform/backend/backend/blocks/google_maps.py
Normal file
127
autogpt_platform/backend/backend/blocks/google_maps.py
Normal file
@@ -0,0 +1,127 @@
|
||||
import googlemaps
|
||||
from pydantic import BaseModel
|
||||
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import BlockSecret, SchemaField, SecretField
|
||||
|
||||
|
||||
class Place(BaseModel):
|
||||
name: str
|
||||
address: str
|
||||
phone: str
|
||||
rating: float
|
||||
reviews: int
|
||||
website: str
|
||||
|
||||
|
||||
class GoogleMapsSearchBlock(Block):
|
||||
class Input(BlockSchema):
|
||||
api_key: BlockSecret = SecretField(
|
||||
key="google_maps_api_key",
|
||||
description="Google Maps API Key",
|
||||
)
|
||||
query: str = SchemaField(
|
||||
description="Search query for local businesses",
|
||||
placeholder="e.g., 'restaurants in New York'",
|
||||
)
|
||||
radius: int = SchemaField(
|
||||
description="Search radius in meters (max 50000)",
|
||||
default=5000,
|
||||
ge=1,
|
||||
le=50000,
|
||||
)
|
||||
max_results: int = SchemaField(
|
||||
description="Maximum number of results to return (max 60)",
|
||||
default=20,
|
||||
ge=1,
|
||||
le=60,
|
||||
)
|
||||
|
||||
class Output(BlockSchema):
|
||||
place: Place = SchemaField(description="Place found")
|
||||
error: str = SchemaField(description="Error message if the search failed")
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(
|
||||
id="f47ac10b-58cc-4372-a567-0e02b2c3d479",
|
||||
description="This block searches for local businesses using Google Maps API.",
|
||||
categories={BlockCategory.SEARCH},
|
||||
input_schema=GoogleMapsSearchBlock.Input,
|
||||
output_schema=GoogleMapsSearchBlock.Output,
|
||||
test_input={
|
||||
"api_key": "your_test_api_key",
|
||||
"query": "restaurants in new york",
|
||||
"radius": 5000,
|
||||
"max_results": 5,
|
||||
},
|
||||
test_output=[
|
||||
(
|
||||
"place",
|
||||
{
|
||||
"name": "Test Restaurant",
|
||||
"address": "123 Test St, New York, NY 10001",
|
||||
"phone": "+1 (555) 123-4567",
|
||||
"rating": 4.5,
|
||||
"reviews": 100,
|
||||
"website": "https://testrestaurant.com",
|
||||
},
|
||||
),
|
||||
],
|
||||
test_mock={
|
||||
"search_places": lambda *args, **kwargs: [
|
||||
{
|
||||
"name": "Test Restaurant",
|
||||
"address": "123 Test St, New York, NY 10001",
|
||||
"phone": "+1 (555) 123-4567",
|
||||
"rating": 4.5,
|
||||
"reviews": 100,
|
||||
"website": "https://testrestaurant.com",
|
||||
}
|
||||
]
|
||||
},
|
||||
)
|
||||
|
||||
def run(self, input_data: Input, **kwargs) -> BlockOutput:
|
||||
try:
|
||||
places = self.search_places(
|
||||
input_data.api_key.get_secret_value(),
|
||||
input_data.query,
|
||||
input_data.radius,
|
||||
input_data.max_results,
|
||||
)
|
||||
for place in places:
|
||||
yield "place", place
|
||||
except Exception as e:
|
||||
yield "error", str(e)
|
||||
|
||||
def search_places(self, api_key, query, radius, max_results):
|
||||
client = googlemaps.Client(key=api_key)
|
||||
return self._search_places(client, query, radius, max_results)
|
||||
|
||||
def _search_places(self, client, query, radius, max_results):
|
||||
results = []
|
||||
next_page_token = None
|
||||
while len(results) < max_results:
|
||||
response = client.places(
|
||||
query=query,
|
||||
radius=radius,
|
||||
page_token=next_page_token,
|
||||
)
|
||||
for place in response["results"]:
|
||||
if len(results) >= max_results:
|
||||
break
|
||||
place_details = client.place(place["place_id"])["result"]
|
||||
results.append(
|
||||
Place(
|
||||
name=place_details.get("name", ""),
|
||||
address=place_details.get("formatted_address", ""),
|
||||
phone=place_details.get("formatted_phone_number", ""),
|
||||
rating=place_details.get("rating", 0),
|
||||
reviews=place_details.get("user_ratings_total", 0),
|
||||
website=place_details.get("website", ""),
|
||||
)
|
||||
)
|
||||
next_page_token = response.get("next_page_token")
|
||||
if not next_page_token:
|
||||
break
|
||||
return results
|
||||
@@ -0,0 +1,202 @@
|
||||
import os
|
||||
from enum import Enum
|
||||
|
||||
import replicate
|
||||
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import BlockSecret, SchemaField, SecretField
|
||||
|
||||
|
||||
# Model name enum
|
||||
class ReplicateFluxModelName(str, Enum):
|
||||
FLUX_SCHNELL = ("Flux Schnell",)
|
||||
FLUX_PRO = ("Flux Pro",)
|
||||
|
||||
@property
|
||||
def api_name(self):
|
||||
api_names = {
|
||||
ReplicateFluxModelName.FLUX_SCHNELL: "black-forest-labs/flux-schnell",
|
||||
ReplicateFluxModelName.FLUX_PRO: "black-forest-labs/flux-pro",
|
||||
}
|
||||
return api_names[self]
|
||||
|
||||
|
||||
# Image type Enum
|
||||
class ImageType(str, Enum):
|
||||
WEBP = "webp"
|
||||
JPG = "jpg"
|
||||
PNG = "png"
|
||||
|
||||
|
||||
class ReplicateFluxAdvancedModelBlock(Block):
|
||||
class Input(BlockSchema):
|
||||
api_key: BlockSecret = SecretField(
|
||||
key="replicate_api_key",
|
||||
description="Replicate API Key",
|
||||
)
|
||||
prompt: str = SchemaField(
|
||||
description="Text prompt for image generation",
|
||||
placeholder="e.g., 'A futuristic cityscape at sunset'",
|
||||
title="Prompt",
|
||||
)
|
||||
replicate_model_name: ReplicateFluxModelName = SchemaField(
|
||||
description="The name of the Image Generation Model, i.e Flux Schnell",
|
||||
default=ReplicateFluxModelName.FLUX_SCHNELL,
|
||||
title="Image Generation Model",
|
||||
advanced=False,
|
||||
)
|
||||
seed: int | None = SchemaField(
|
||||
description="Random seed. Set for reproducible generation",
|
||||
default=None,
|
||||
title="Seed",
|
||||
)
|
||||
steps: int = SchemaField(
|
||||
description="Number of diffusion steps",
|
||||
default=25,
|
||||
title="Steps",
|
||||
)
|
||||
guidance: float = SchemaField(
|
||||
description=(
|
||||
"Controls the balance between adherence to the text prompt and image quality/diversity. "
|
||||
"Higher values make the output more closely match the prompt but may reduce overall image quality."
|
||||
),
|
||||
default=3,
|
||||
title="Guidance",
|
||||
)
|
||||
interval: float = SchemaField(
|
||||
description=(
|
||||
"Interval is a setting that increases the variance in possible outputs. "
|
||||
"Setting this value low will ensure strong prompt following with more consistent outputs."
|
||||
),
|
||||
default=2,
|
||||
title="Interval",
|
||||
)
|
||||
aspect_ratio: str = SchemaField(
|
||||
description="Aspect ratio for the generated image",
|
||||
default="1:1",
|
||||
title="Aspect Ratio",
|
||||
placeholder="Choose from: 1:1, 16:9, 2:3, 3:2, 4:5, 5:4, 9:16",
|
||||
)
|
||||
output_format: ImageType = SchemaField(
|
||||
description="File format of the output image",
|
||||
default=ImageType.WEBP,
|
||||
title="Output Format",
|
||||
)
|
||||
output_quality: int = SchemaField(
|
||||
description=(
|
||||
"Quality when saving the output images, from 0 to 100. "
|
||||
"Not relevant for .png outputs"
|
||||
),
|
||||
default=80,
|
||||
title="Output Quality",
|
||||
)
|
||||
safety_tolerance: int = SchemaField(
|
||||
description="Safety tolerance, 1 is most strict and 5 is most permissive",
|
||||
default=2,
|
||||
title="Safety Tolerance",
|
||||
)
|
||||
|
||||
class Output(BlockSchema):
|
||||
result: str = SchemaField(description="Generated output")
|
||||
error: str = SchemaField(description="Error message if the model run failed")
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(
|
||||
id="90f8c45e-e983-4644-aa0b-b4ebe2f531bc",
|
||||
description="This block runs Flux models on Replicate with advanced settings.",
|
||||
categories={BlockCategory.AI},
|
||||
input_schema=ReplicateFluxAdvancedModelBlock.Input,
|
||||
output_schema=ReplicateFluxAdvancedModelBlock.Output,
|
||||
test_input={
|
||||
"api_key": "test_api_key",
|
||||
"replicate_model_name": ReplicateFluxModelName.FLUX_SCHNELL,
|
||||
"prompt": "A beautiful landscape painting of a serene lake at sunrise",
|
||||
"seed": None,
|
||||
"steps": 25,
|
||||
"guidance": 3.0,
|
||||
"interval": 2.0,
|
||||
"aspect_ratio": "1:1",
|
||||
"output_format": ImageType.PNG,
|
||||
"output_quality": 80,
|
||||
"safety_tolerance": 2,
|
||||
},
|
||||
test_output=[
|
||||
(
|
||||
"result",
|
||||
"https://replicate.com/output/generated-image-url.jpg",
|
||||
),
|
||||
],
|
||||
test_mock={
|
||||
"run_model": lambda api_key, model_name, prompt, seed, steps, guidance, interval, aspect_ratio, output_format, output_quality, safety_tolerance: "https://replicate.com/output/generated-image-url.jpg",
|
||||
},
|
||||
)
|
||||
|
||||
def run(self, input_data: Input, **kwargs) -> BlockOutput:
|
||||
# If the seed is not provided, generate a random seed
|
||||
seed = input_data.seed
|
||||
if seed is None:
|
||||
seed = int.from_bytes(os.urandom(4), "big")
|
||||
|
||||
try:
|
||||
# Run the model using the provided inputs
|
||||
result = self.run_model(
|
||||
api_key=input_data.api_key.get_secret_value(),
|
||||
model_name=input_data.replicate_model_name.api_name,
|
||||
prompt=input_data.prompt,
|
||||
seed=seed,
|
||||
steps=input_data.steps,
|
||||
guidance=input_data.guidance,
|
||||
interval=input_data.interval,
|
||||
aspect_ratio=input_data.aspect_ratio,
|
||||
output_format=input_data.output_format,
|
||||
output_quality=input_data.output_quality,
|
||||
safety_tolerance=input_data.safety_tolerance,
|
||||
)
|
||||
yield "result", result
|
||||
except Exception as e:
|
||||
yield "error", str(e)
|
||||
|
||||
def run_model(
|
||||
self,
|
||||
api_key,
|
||||
model_name,
|
||||
prompt,
|
||||
seed,
|
||||
steps,
|
||||
guidance,
|
||||
interval,
|
||||
aspect_ratio,
|
||||
output_format,
|
||||
output_quality,
|
||||
safety_tolerance,
|
||||
):
|
||||
# Initialize Replicate client with the API key
|
||||
client = replicate.Client(api_token=api_key)
|
||||
|
||||
# Run the model with additional parameters
|
||||
output = client.run(
|
||||
f"{model_name}",
|
||||
input={
|
||||
"prompt": prompt,
|
||||
"seed": seed,
|
||||
"steps": steps,
|
||||
"guidance": guidance,
|
||||
"interval": interval,
|
||||
"aspect_ratio": aspect_ratio,
|
||||
"output_format": output_format,
|
||||
"output_quality": output_quality,
|
||||
"safety_tolerance": safety_tolerance,
|
||||
},
|
||||
)
|
||||
|
||||
# Check if output is a list or a string and extract accordingly; otherwise, assign a default message
|
||||
if isinstance(output, list) and len(output) > 0:
|
||||
result_url = output[0] # If output is a list, get the first element
|
||||
elif isinstance(output, str):
|
||||
result_url = output # If output is a string, use it directly
|
||||
else:
|
||||
result_url = (
|
||||
"No output received" # Fallback message if output is not as expected
|
||||
)
|
||||
|
||||
return result_url
|
||||
@@ -216,6 +216,9 @@ class Secrets(UpdateTrackingModel["Secrets"], BaseSettings):
|
||||
|
||||
sentry_dsn: str = Field(default="", description="Sentry DSN")
|
||||
|
||||
google_maps_api_key: str = Field(default="", description="Google Maps API Key")
|
||||
|
||||
replicate_api_key: str = Field(default="", description="Replicate API Key")
|
||||
# Add more secret fields as needed
|
||||
|
||||
model_config = SettingsConfigDict(
|
||||
|
||||
922
autogpt_platform/backend/poetry.lock
generated
922
autogpt_platform/backend/poetry.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -44,6 +44,8 @@ tenacity = "^8.3.0"
|
||||
uvicorn = { extras = ["standard"], version = "^0.30.1" }
|
||||
websockets = "^12.0"
|
||||
youtube-transcript-api = "^0.6.2"
|
||||
googlemaps = "^4.10.0"
|
||||
replicate = "^0.34.1"
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
poethepoet = "^0.26.1"
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
"dotenv": "^16.4.5",
|
||||
"lucide-react": "^0.407.0",
|
||||
"moment": "^2.30.1",
|
||||
"next": "14.2.4",
|
||||
"next": "^14.2.13",
|
||||
"next-themes": "^0.3.0",
|
||||
"react": "^18",
|
||||
"react-day-picker": "^8.10.1",
|
||||
|
||||
@@ -6,7 +6,7 @@ export async function GET(request: Request) {
|
||||
const { searchParams, origin } = new URL(request.url);
|
||||
const code = searchParams.get("code");
|
||||
// if "next" is in param, use it as the redirect URL
|
||||
const next = searchParams.get("next") ?? "/profile";
|
||||
const next = searchParams.get("next") ?? "/";
|
||||
|
||||
if (code) {
|
||||
const supabase = createServerClient();
|
||||
|
||||
@@ -8,7 +8,7 @@ export default function Home() {
|
||||
|
||||
return (
|
||||
<FlowEditor
|
||||
className="flow-container w-full min-h-[86vh] border border-gray-300 dark:border-gray-700 rounded-lg"
|
||||
className="flow-container"
|
||||
flowID={query.get("flowID") ?? query.get("templateID") ?? undefined}
|
||||
template={!!query.get("templateID")}
|
||||
/>
|
||||
|
||||
@@ -34,7 +34,7 @@ export default function RootLayout({
|
||||
>
|
||||
<div className="flex min-h-screen flex-col">
|
||||
<NavBar />
|
||||
<main className="flex-1 overflow-hidden p-4">{children}</main>
|
||||
<main className="flex-1 p-4">{children}</main>
|
||||
<TallyPopupSimple />
|
||||
</div>
|
||||
<Toaster />
|
||||
|
||||
@@ -30,7 +30,7 @@ export async function login(values: z.infer<typeof loginFormSchema>) {
|
||||
}
|
||||
|
||||
revalidatePath("/", "layout");
|
||||
redirect("/profile");
|
||||
redirect("/");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ export async function signup(values: z.infer<typeof loginFormSchema>) {
|
||||
}
|
||||
|
||||
revalidatePath("/", "layout");
|
||||
redirect("/profile");
|
||||
redirect("/");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -48,8 +48,8 @@ export default function LoginPage() {
|
||||
});
|
||||
|
||||
if (user) {
|
||||
console.log("User exists, redirecting to profile");
|
||||
router.push("/profile");
|
||||
console.log("User exists, redirecting to home");
|
||||
router.push("/");
|
||||
}
|
||||
|
||||
if (isUserLoading || isSupabaseLoading || user) {
|
||||
|
||||
@@ -585,7 +585,7 @@ export function CustomNode({ data, id, width, height }: NodeProps<CustomNode>) {
|
||||
{blockCost && (
|
||||
<div className="p-3 font-semibold">
|
||||
<span className="ml-auto flex items-center">
|
||||
<IconCoin /> {blockCost.cost_amount} per {blockCost.cost_type}
|
||||
<IconCoin /> {blockCost.cost_amount} credits/{blockCost.cost_type}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -579,21 +579,27 @@ const FlowEditor: React.FC<{
|
||||
>
|
||||
<Controls />
|
||||
<Background />
|
||||
<ControlPanel className="absolute z-10" controls={editorControls}>
|
||||
<BlocksControl
|
||||
pinBlocksPopover={pinBlocksPopover} // Pass the state to BlocksControl
|
||||
blocks={availableNodes}
|
||||
addBlock={addNode}
|
||||
/>
|
||||
<SaveControl
|
||||
agentMeta={savedAgent}
|
||||
onSave={(isTemplate) => requestSave(isTemplate ?? false)}
|
||||
agentDescription={agentDescription}
|
||||
onDescriptionChange={setAgentDescription}
|
||||
agentName={agentName}
|
||||
onNameChange={setAgentName}
|
||||
/>
|
||||
</ControlPanel>
|
||||
<ControlPanel
|
||||
className="absolute z-10"
|
||||
controls={editorControls}
|
||||
topChildren={
|
||||
<BlocksControl
|
||||
pinBlocksPopover={pinBlocksPopover} // Pass the state to BlocksControl
|
||||
blocks={availableNodes}
|
||||
addBlock={addNode}
|
||||
/>
|
||||
}
|
||||
botChildren={
|
||||
<SaveControl
|
||||
agentMeta={savedAgent}
|
||||
onSave={(isTemplate) => requestSave(isTemplate ?? false)}
|
||||
agentDescription={agentDescription}
|
||||
onDescriptionChange={setAgentDescription}
|
||||
agentName={agentName}
|
||||
onNameChange={setAgentName}
|
||||
/>
|
||||
}
|
||||
></ControlPanel>
|
||||
<PrimaryActionBar
|
||||
onClickAgentOutputs={() => runnerUIRef.current?.openRunnerOutput()}
|
||||
onClickRunAgent={() => {
|
||||
|
||||
@@ -5,19 +5,9 @@ import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet";
|
||||
import Image from "next/image";
|
||||
import getServerUser from "@/hooks/getServerUser";
|
||||
import ProfileDropdown from "./ProfileDropdown";
|
||||
import {
|
||||
IconCircleUser,
|
||||
IconMenu,
|
||||
IconPackage2,
|
||||
IconRefresh,
|
||||
IconSquareActivity,
|
||||
IconWorkFlow,
|
||||
} from "@/components/ui/icons";
|
||||
import AutoGPTServerAPI from "@/lib/autogpt-server-api";
|
||||
import { IconCircleUser, IconMenu } from "@/components/ui/icons";
|
||||
import CreditButton from "@/components/CreditButton";
|
||||
import { BsBoxes } from "react-icons/bs";
|
||||
import { LuLaptop } from "react-icons/lu";
|
||||
import { LuShoppingCart } from "react-icons/lu";
|
||||
import { NavBarButtons } from "./NavBarButtons";
|
||||
|
||||
export async function NavBar() {
|
||||
const isAvailable = Boolean(
|
||||
@@ -27,7 +17,7 @@ export async function NavBar() {
|
||||
const { user } = await getServerUser();
|
||||
|
||||
return (
|
||||
<header className="sticky top-0 z-50 flex h-16 items-center gap-4 border-b bg-background px-4 md:rounded-b-3xl md:px-6 md:shadow-md">
|
||||
<header className="sticky top-0 z-50 mx-4 flex h-16 items-center gap-4 border-b bg-background p-3 md:rounded-b-2xl md:px-6 md:shadow">
|
||||
<div className="flex flex-1 items-center gap-4">
|
||||
<Sheet>
|
||||
<SheetTrigger asChild>
|
||||
@@ -42,28 +32,11 @@ export async function NavBar() {
|
||||
</SheetTrigger>
|
||||
<SheetContent side="left">
|
||||
<nav className="grid gap-6 text-lg font-medium">
|
||||
<Link
|
||||
href="/marketplace"
|
||||
className="mt-4 flex flex-row items-center gap-2 text-muted-foreground hover:text-foreground"
|
||||
>
|
||||
<LuShoppingCart /> Marketplace
|
||||
</Link>
|
||||
<Link
|
||||
href="/"
|
||||
className="flex flex-row items-center gap-2 text-muted-foreground hover:text-foreground"
|
||||
>
|
||||
<LuLaptop /> Monitor
|
||||
</Link>
|
||||
<Link
|
||||
href="/build"
|
||||
className="flex flex-row items-center gap-2 text-muted-foreground hover:text-foreground"
|
||||
>
|
||||
<BsBoxes /> Build
|
||||
</Link>
|
||||
<NavBarButtons className="flex flex-row items-center gap-2" />
|
||||
</nav>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
<nav className="hidden md:flex md:flex-row md:items-center md:gap-7 lg:gap-8">
|
||||
<nav className="hidden md:flex md:flex-row md:items-center md:gap-5 lg:gap-8">
|
||||
<div className="flex h-10 w-20 flex-1 flex-row items-center justify-center gap-2">
|
||||
<a href="https://agpt.co/">
|
||||
<Image
|
||||
@@ -75,24 +48,7 @@ export async function NavBar() {
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
<Link
|
||||
href="/marketplace"
|
||||
className="text-basehover:text-foreground flex flex-row items-center gap-2 font-semibold text-foreground"
|
||||
>
|
||||
<LuShoppingCart /> Marketplace
|
||||
</Link>
|
||||
<Link
|
||||
href="/"
|
||||
className="text-basehover:text-foreground flex flex-row items-center gap-2 font-semibold text-foreground"
|
||||
>
|
||||
<LuLaptop className="mr-1" /> Monitor
|
||||
</Link>
|
||||
<Link
|
||||
href="/build"
|
||||
className="flex flex-row items-center gap-2 text-base font-semibold text-foreground hover:text-foreground"
|
||||
>
|
||||
<BsBoxes className="mr-1" /> Build
|
||||
</Link>
|
||||
<NavBarButtons className="flex flex-row items-center gap-1 border border-white font-semibold hover:border-gray-900" />
|
||||
</nav>
|
||||
</div>
|
||||
<div className="flex flex-1 items-center justify-end gap-4">
|
||||
|
||||
49
autogpt_platform/frontend/src/components/NavBarButtons.tsx
Normal file
49
autogpt_platform/frontend/src/components/NavBarButtons.tsx
Normal file
@@ -0,0 +1,49 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import { BsBoxes } from "react-icons/bs";
|
||||
import { LuLaptop } from "react-icons/lu";
|
||||
import { LuShoppingCart } from "react-icons/lu";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { usePathname } from "next/navigation";
|
||||
|
||||
export function NavBarButtons({ className }: { className?: string }) {
|
||||
"use client";
|
||||
|
||||
const pathname = usePathname();
|
||||
const buttons = [
|
||||
{
|
||||
href: "/marketplace",
|
||||
text: "Marketplace",
|
||||
icon: <LuShoppingCart />,
|
||||
},
|
||||
{
|
||||
href: "/",
|
||||
text: "Monitor",
|
||||
icon: <LuLaptop />,
|
||||
},
|
||||
{
|
||||
href: "/build",
|
||||
text: "Build",
|
||||
icon: <BsBoxes />,
|
||||
},
|
||||
];
|
||||
|
||||
const activeButton = buttons.find((button) => button.href === pathname);
|
||||
|
||||
console.log(">>>> ", activeButton);
|
||||
|
||||
return buttons.map((button) => (
|
||||
<Link
|
||||
key={button.href}
|
||||
href={button.href}
|
||||
className={cn(
|
||||
className,
|
||||
"rounded-xl p-3",
|
||||
activeButton === button ? "button bg-gray-950 text-white" : "",
|
||||
)}
|
||||
>
|
||||
{button.icon} {button.text}
|
||||
</Link>
|
||||
));
|
||||
}
|
||||
@@ -32,7 +32,7 @@ const PrimaryActionBar: React.FC<PrimaryActionBarProps> = ({
|
||||
const runButtonOnClick = !isRunning ? onClickRunAgent : requestStopRun;
|
||||
|
||||
return (
|
||||
<div className="absolute bottom-0 left-0 right-0 z-50 flex items-center justify-center p-4">
|
||||
<div className="absolute bottom-0 left-1/2 z-50 flex w-fit -translate-x-1/2 transform items-center justify-center p-4">
|
||||
<div className={`flex gap-4`}>
|
||||
<Tooltip key="ViewOutputs" delayDuration={500}>
|
||||
<TooltipTrigger asChild>
|
||||
@@ -42,8 +42,10 @@ const PrimaryActionBar: React.FC<PrimaryActionBarProps> = ({
|
||||
size="primary"
|
||||
variant="outline"
|
||||
>
|
||||
<LogOut className="h-5 w-5" />
|
||||
<span className="text-lg font-medium">Agent Outputs </span>
|
||||
<LogOut className="hidden h-5 w-5 md:flex" />
|
||||
<span className="text-sm font-medium md:text-lg">
|
||||
Agent Outputs{" "}
|
||||
</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
@@ -62,7 +64,9 @@ const PrimaryActionBar: React.FC<PrimaryActionBarProps> = ({
|
||||
}}
|
||||
>
|
||||
{runButtonIcon}
|
||||
<span className="text-lg font-medium">{runButtonLabel}</span>
|
||||
<span className="text-sm font-medium md:text-lg">
|
||||
{runButtonLabel}
|
||||
</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
|
||||
@@ -47,7 +47,7 @@ const TallyPopupSimple = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="fixed bottom-6 right-6 z-50 flex items-center gap-4 p-3 transition-all duration-300 ease-in-out">
|
||||
<div className="fixed bottom-6 right-6 z-50 hidden items-center gap-4 p-3 transition-all duration-300 ease-in-out md:flex">
|
||||
<Button variant="default" onClick={resetTutorial} className="mb-0">
|
||||
Tutorial
|
||||
</Button>
|
||||
|
||||
@@ -138,7 +138,7 @@ export const BlocksControl: React.FC<BlocksControlProps> = ({
|
||||
))}
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="p-1">
|
||||
<CardContent className="border-t px-1 py-0">
|
||||
<ScrollArea
|
||||
className="h-[60vh]"
|
||||
data-id="blocks-control-scroll-area"
|
||||
|
||||
@@ -25,7 +25,8 @@ export type Control = {
|
||||
|
||||
interface ControlPanelProps {
|
||||
controls: Control[];
|
||||
children?: React.ReactNode;
|
||||
topChildren?: React.ReactNode;
|
||||
botChildren?: React.ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
@@ -39,14 +40,15 @@ interface ControlPanelProps {
|
||||
*/
|
||||
export const ControlPanel = ({
|
||||
controls,
|
||||
children,
|
||||
topChildren,
|
||||
botChildren,
|
||||
className,
|
||||
}: ControlPanelProps) => {
|
||||
return (
|
||||
<Card className={cn("w-14", className)}>
|
||||
<Card className={cn("m-4 mt-24 w-14", className)}>
|
||||
<CardContent className="p-0">
|
||||
<div className="rounded-radius flex flex-col items-center gap-8 px-2 sm:py-5">
|
||||
{children}
|
||||
<div className="flex flex-col items-center gap-3 rounded-xl border py-3">
|
||||
{topChildren}
|
||||
<Separator />
|
||||
{controls.map((control, index) => (
|
||||
<Tooltip key={index} delayDuration={500}>
|
||||
@@ -67,6 +69,8 @@ export const ControlPanel = ({
|
||||
<TooltipContent side="right">{control.label}</TooltipContent>
|
||||
</Tooltip>
|
||||
))}
|
||||
<Separator />
|
||||
{botChildren}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
@@ -111,6 +111,9 @@ textarea::placeholder {
|
||||
}
|
||||
|
||||
.flow-container {
|
||||
width: 100%;
|
||||
height: 600px; /* Adjust this height as needed */
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
@@ -182,7 +182,7 @@ export const startTutorial = (
|
||||
tour.addStep({
|
||||
id: "scroll-block-menu",
|
||||
title: "Scroll Down or Search",
|
||||
text: 'Scroll down or search in the blocks menu for the "Calculator Block" and press the "+" to add the block.',
|
||||
text: 'Scroll down or search in the blocks menu for the "Calculator Block" and press the block to add it.',
|
||||
attachTo: {
|
||||
element: '[data-id="blocks-control-popover-content"]',
|
||||
on: "right",
|
||||
@@ -191,12 +191,11 @@ export const startTutorial = (
|
||||
beforeShowPromise: () =>
|
||||
waitForElement('[data-id="blocks-control-popover-content"]').then(() => {
|
||||
disableOtherBlocks(
|
||||
'[data-id="add-block-button-b1ab9b19-67a6-406d-abf5-2dba76d00c79"]',
|
||||
'[data-id="block-card-b1ab9b19-67a6-406d-abf5-2dba76d00c79"]',
|
||||
);
|
||||
}),
|
||||
advanceOn: {
|
||||
selector:
|
||||
'[data-id="add-block-button-b1ab9b19-67a6-406d-abf5-2dba76d00c79"]',
|
||||
selector: '[data-id="block-card-b1ab9b19-67a6-406d-abf5-2dba76d00c79"]',
|
||||
event: "click",
|
||||
},
|
||||
when: {
|
||||
|
||||
@@ -25,7 +25,7 @@ const buttonVariants = cva(
|
||||
default: "h-9 px-4 py-2",
|
||||
sm: "h-8 rounded-md px-3 text-xs",
|
||||
lg: "h-10 rounded-md px-8",
|
||||
primary: "h-14 w-44 rounded-2xl",
|
||||
primary: "md:h-14 md:w-44 rounded-2xl h-10 w-28",
|
||||
icon: "h-9 w-9",
|
||||
},
|
||||
},
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
apiVersion: cloud.google.com/v1
|
||||
kind: BackendConfig
|
||||
metadata:
|
||||
name: {{ include "autogpt-market.fullname" . }}
|
||||
name: {{ include "autogpt-market.fullname" . }}-backend-config
|
||||
spec:
|
||||
customRequestHeaders:
|
||||
headers:
|
||||
|
||||
@@ -41,7 +41,7 @@ spec:
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: {{ .Values.service.port }}
|
||||
containerPort: {{ .Values.service.targetPort }}
|
||||
protocol: TCP
|
||||
livenessProbe:
|
||||
{{- toYaml .Values.livenessProbe | nindent 12 }}
|
||||
@@ -53,15 +53,6 @@ spec:
|
||||
volumeMounts:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
- name: cloud-sql-proxy
|
||||
image: "{{ .Values.cloudSqlProxy.image.repository }}:{{ .Values.cloudSqlProxy.image.tag }}"
|
||||
args:
|
||||
- "--structured-logs"
|
||||
{{- if .Values.cloudSqlProxy.usePrivateIp }}
|
||||
- "--private-ip"
|
||||
{{- end }}
|
||||
- "--port={{ .Values.cloudSqlProxy.port }}"
|
||||
- "{{ .Values.cloudSqlProxy.instanceConnectionName }}"
|
||||
{{- with .Values.volumes }}
|
||||
volumes:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
|
||||
@@ -4,11 +4,15 @@ metadata:
|
||||
name: {{ include "autogpt-market.fullname" . }}
|
||||
labels:
|
||||
{{- include "autogpt-market.labels" . | nindent 4 }}
|
||||
{{- with .Values.service.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
type: {{ .Values.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.service.port }}
|
||||
targetPort: http
|
||||
targetPort: {{ .Values.service.targetPort }}
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
|
||||
@@ -12,11 +12,11 @@ serviceAccount:
|
||||
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 8000
|
||||
targetPort: 8005
|
||||
port: 8015
|
||||
targetPort: 8015
|
||||
annotations:
|
||||
cloud.google.com/neg: '{"ingress": true}'
|
||||
beta.cloud.google.com/backend-config: '{"default": "autogpt-market"}'
|
||||
beta.cloud.google.com/backend-config: '{"default": "autogpt-market-backend-config"}'
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
@@ -25,7 +25,7 @@ ingress:
|
||||
kubernetes.io/ingress.class: gce
|
||||
kubernetes.io/ingress.global-static-ip-name: "agpt-dev-agpt-market-ip"
|
||||
networking.gke.io/managed-certificates: "autogpt-market-cert"
|
||||
kubernetes.io/ingress.allow-http: "false"
|
||||
networking.gke.io/v1beta1.FrontendConfig: "autogpt-market-frontend-config"
|
||||
hosts:
|
||||
- host: dev-market.agpt.co
|
||||
paths:
|
||||
@@ -34,12 +34,12 @@ ingress:
|
||||
backend:
|
||||
service:
|
||||
name: autogpt-market
|
||||
port: 8000
|
||||
port: 8015
|
||||
defaultBackend:
|
||||
service:
|
||||
name: autogpt-market
|
||||
port:
|
||||
number: 8000
|
||||
number: 8015
|
||||
|
||||
resources:
|
||||
requests:
|
||||
@@ -52,7 +52,7 @@ resources:
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 8000
|
||||
port: 8015
|
||||
initialDelaySeconds: 60
|
||||
periodSeconds: 20
|
||||
timeoutSeconds: 10
|
||||
@@ -60,7 +60,7 @@ livenessProbe:
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 8000
|
||||
port: 8015
|
||||
initialDelaySeconds: 60
|
||||
periodSeconds: 20
|
||||
timeoutSeconds: 10
|
||||
@@ -95,9 +95,14 @@ cors:
|
||||
|
||||
env:
|
||||
APP_ENV: "dev"
|
||||
PYRO_HOST: "0.0.0.0"
|
||||
ENABLE_AUTH: "true"
|
||||
SUPABASE_JWT_SECRET: ""
|
||||
SUPABASE_ANON_KEY: ""
|
||||
SUPABASE_URL: ""
|
||||
DATABASE_URL: ""
|
||||
SENTRY_DSN: ""
|
||||
SUPABASE_SERVICE_ROLE_KEY: ""
|
||||
GITHUB_CLIENT_ID: ""
|
||||
GITHUB_CLIENT_SECRET: ""
|
||||
FRONTEND_BASE_URL: "https://dev-builder.agpt.co/"
|
||||
SUPABASE_URL: "https://adfjtextkuilwuhzdjpf.supabase.co"
|
||||
BACKEND_CORS_ALLOW_ORIGINS: "https://dev-builder.agpt.co"
|
||||
109
autogpt_platform/infra/helm/autogpt-market/values.prod.yaml
Normal file
109
autogpt_platform/infra/helm/autogpt-market/values.prod.yaml
Normal file
@@ -0,0 +1,109 @@
|
||||
# prod values, overwrite base values as needed.
|
||||
|
||||
image:
|
||||
repository: us-east1-docker.pkg.dev/agpt-prod/agpt-market-prod/agpt-market-prod
|
||||
pullPolicy: Always
|
||||
tag: "latest"
|
||||
|
||||
serviceAccount:
|
||||
annotations:
|
||||
iam.gke.io/gcp-service-account: "prod-agpt-market-sa@agpt-prod.iam.gserviceaccount.com"
|
||||
name: "prod-agpt-market-sa"
|
||||
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 8015
|
||||
targetPort: 8015
|
||||
annotations:
|
||||
cloud.google.com/neg: '{"ingress": true}'
|
||||
beta.cloud.google.com/backend-config: '{"default": "autogpt-market-backend-config"}'
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
className: "gce"
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: gce
|
||||
kubernetes.io/ingress.global-static-ip-name: "agpt-prod-agpt-market-ip"
|
||||
networking.gke.io/managed-certificates: "autogpt-market-cert"
|
||||
networking.gke.io/v1beta1.FrontendConfig: "autogpt-market-frontend-config"
|
||||
hosts:
|
||||
- host: market.agpt.co
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: autogpt-market
|
||||
port: 8015
|
||||
defaultBackend:
|
||||
service:
|
||||
name: autogpt-market
|
||||
port:
|
||||
number: 8015
|
||||
|
||||
resources:
|
||||
requests:
|
||||
cpu: 200m
|
||||
memory: 1Gi
|
||||
limits:
|
||||
cpu: 2
|
||||
memory: 2Gi
|
||||
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 8015
|
||||
initialDelaySeconds: 60
|
||||
periodSeconds: 20
|
||||
timeoutSeconds: 10
|
||||
failureThreshold: 12
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 8015
|
||||
initialDelaySeconds: 60
|
||||
periodSeconds: 20
|
||||
timeoutSeconds: 10
|
||||
failureThreshold: 12
|
||||
|
||||
domain: "market.agpt.co"
|
||||
|
||||
cloudSqlProxy:
|
||||
image:
|
||||
repository: gcr.io/cloud-sql-connectors/cloud-sql-proxy
|
||||
tag: 2.11.4
|
||||
instanceConnectionName: "agpt-prod:us-central1:agpt-server-prod"
|
||||
port: 5432
|
||||
resources:
|
||||
requests:
|
||||
memory: "2Gi"
|
||||
cpu: "1"
|
||||
|
||||
cors:
|
||||
allowOrigin: "https://platform.agpt.co"
|
||||
allowMethods:
|
||||
- "GET"
|
||||
- "POST"
|
||||
- "PUT"
|
||||
- "DELETE"
|
||||
- "OPTIONS"
|
||||
allowHeaders:
|
||||
- "Content-Type"
|
||||
- "Authorization"
|
||||
maxAge: 3600
|
||||
allowCredentials: true
|
||||
|
||||
env:
|
||||
APP_ENV: "prod"
|
||||
PYRO_HOST: "0.0.0.0"
|
||||
ENABLE_AUTH: "true"
|
||||
SUPABASE_JWT_SECRET: ""
|
||||
DATABASE_URL: ""
|
||||
SENTRY_DSN: ""
|
||||
SUPABASE_SERVICE_ROLE_KEY: ""
|
||||
GITHUB_CLIENT_ID: ""
|
||||
GITHUB_CLIENT_SECRET: ""
|
||||
FRONTEND_BASE_URL: "https://platform.agpt.co/"
|
||||
SUPABASE_URL: "https://bgwpwdsxblryihinutbx.supabase.co"
|
||||
BACKEND_CORS_ALLOW_ORIGINS: "https://platform.agpt.co"
|
||||
|
||||
@@ -71,15 +71,6 @@ resources: {}
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: http
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: http
|
||||
|
||||
autoscaling:
|
||||
enabled: false
|
||||
minReplicas: 1
|
||||
|
||||
15
autogpt_platform/infra/helm/redis-values.prod.yaml
Normal file
15
autogpt_platform/infra/helm/redis-values.prod.yaml
Normal file
@@ -0,0 +1,15 @@
|
||||
architecture: standalone
|
||||
auth:
|
||||
enabled: true
|
||||
password: "" #empty on purpose
|
||||
master:
|
||||
persistence:
|
||||
enabled: true
|
||||
size: 3Gi
|
||||
configmap:
|
||||
redis.conf: |
|
||||
bind 127.0.0.1
|
||||
protected-mode yes
|
||||
requirepass password
|
||||
replica:
|
||||
replicaCount: 0
|
||||
100
autogpt_platform/infra/terraform/environments/prod.tfvars
Normal file
100
autogpt_platform/infra/terraform/environments/prod.tfvars
Normal file
@@ -0,0 +1,100 @@
|
||||
project_id = "agpt-prod"
|
||||
region = "us-central1"
|
||||
zone = "us-central1-a"
|
||||
network_name = "prod-gke-network"
|
||||
subnet_name = "prod-gke-subnet"
|
||||
subnet_cidr = "10.0.0.0/24"
|
||||
cluster_name = "prod-gke-cluster"
|
||||
node_count = 4
|
||||
node_pool_name = "prod-main-pool"
|
||||
machine_type = "e2-highmem-4"
|
||||
disk_size_gb = 100
|
||||
static_ip_names = ["agpt-backend-ip", "agpt-frontend-ip", "agpt-ws-backend-ip", "agpt-market-ip"]
|
||||
|
||||
|
||||
service_accounts = {
|
||||
"prod-agpt-backend-sa" = {
|
||||
display_name = "AutoGPT prod backend Account"
|
||||
description = "Service account for agpt prod backend"
|
||||
},
|
||||
"prod-agpt-frontend-sa" = {
|
||||
display_name = "AutoGPT prod frontend Account"
|
||||
description = "Service account for agpt prod frontend"
|
||||
},
|
||||
"prod-agpt-ws-backend-sa" = {
|
||||
display_name = "AutoGPT prod WebSocket backend Account"
|
||||
description = "Service account for agpt prod websocket backend"
|
||||
},
|
||||
"prod-agpt-market-sa" = {
|
||||
display_name = "AutoGPT prod Market backend Account"
|
||||
description = "Service account for agpt prod market backend"
|
||||
}
|
||||
}
|
||||
|
||||
workload_identity_bindings = {
|
||||
"prod-agpt-backend-workload-identity" = {
|
||||
service_account_name = "prod-agpt-backend-sa"
|
||||
namespace = "prod-agpt"
|
||||
ksa_name = "prod-agpt-backend-sa"
|
||||
},
|
||||
"prod-agpt-frontend-workload-identity" = {
|
||||
service_account_name = "prod-agpt-frontend-sa"
|
||||
namespace = "prod-agpt"
|
||||
ksa_name = "prod-agpt-frontend-sa"
|
||||
},
|
||||
"prod-agpt-ws-backend-workload-identity" = {
|
||||
service_account_name = "prod-agpt-ws-backend-sa"
|
||||
namespace = "prod-agpt"
|
||||
ksa_name = "prod-agpt-ws-backend-sa"
|
||||
},
|
||||
"prod-agpt-market-workload-identity" = {
|
||||
service_account_name = "prod-agpt-market-sa"
|
||||
namespace = "prod-agpt"
|
||||
ksa_name = "prod-agpt-market-sa"
|
||||
}
|
||||
}
|
||||
|
||||
role_bindings = {
|
||||
"roles/container.developer" = [
|
||||
"serviceAccount:prod-agpt-backend-sa@agpt-prod.iam.gserviceaccount.com",
|
||||
"serviceAccount:prod-agpt-frontend-sa@agpt-prod.iam.gserviceaccount.com",
|
||||
"serviceAccount:prod-agpt-ws-backend-sa@agpt-prod.iam.gserviceaccount.com",
|
||||
"serviceAccount:prod-agpt-market-sa@agpt-prod.iam.gserviceaccount.com"
|
||||
],
|
||||
"roles/cloudsql.client" = [
|
||||
"serviceAccount:prod-agpt-backend-sa@agpt-prod.iam.gserviceaccount.com",
|
||||
"serviceAccount:prod-agpt-frontend-sa@agpt-prod.iam.gserviceaccount.com",
|
||||
"serviceAccount:prod-agpt-market-sa@agpt-prod.iam.gserviceaccount.com"
|
||||
],
|
||||
"roles/cloudsql.editor" = [
|
||||
"serviceAccount:prod-agpt-backend-sa@agpt-prod.iam.gserviceaccount.com",
|
||||
"serviceAccount:prod-agpt-frontend-sa@agpt-prod.iam.gserviceaccount.com",
|
||||
"serviceAccount:prod-agpt-market-sa@agpt-prod.iam.gserviceaccount.com"
|
||||
],
|
||||
"roles/cloudsql.instanceUser" = [
|
||||
"serviceAccount:prod-agpt-backend-sa@agpt-prod.iam.gserviceaccount.com",
|
||||
"serviceAccount:prod-agpt-frontend-sa@agpt-prod.iam.gserviceaccount.com",
|
||||
"serviceAccount:prod-agpt-market-sa@agpt-prod.iam.gserviceaccount.com"
|
||||
],
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
"serviceAccount:prod-agpt-backend-sa@agpt-prod.iam.gserviceaccount.com",
|
||||
"serviceAccount:prod-agpt-frontend-sa@agpt-prod.iam.gserviceaccount.com",
|
||||
"serviceAccount:prod-agpt-ws-backend-sa@agpt-prod.iam.gserviceaccount.com",
|
||||
"serviceAccount:prod-agpt-market-sa@agpt-prod.iam.gserviceaccount.com"
|
||||
]
|
||||
"roles/compute.networkUser" = [
|
||||
"serviceAccount:prod-agpt-backend-sa@agpt-prod.iam.gserviceaccount.com",
|
||||
"serviceAccount:prod-agpt-frontend-sa@agpt-prod.iam.gserviceaccount.com",
|
||||
"serviceAccount:prod-agpt-ws-backend-sa@agpt-prod.iam.gserviceaccount.com",
|
||||
"serviceAccount:prod-agpt-market-sa@agpt-prod.iam.gserviceaccount.com"
|
||||
],
|
||||
"roles/container.hostServiceAgentUser" = [
|
||||
"serviceAccount:prod-agpt-backend-sa@agpt-prod.iam.gserviceaccount.com",
|
||||
"serviceAccount:prod-agpt-frontend-sa@agpt-prod.iam.gserviceaccount.com",
|
||||
"serviceAccount:prod-agpt-ws-backend-sa@agpt-prod.iam.gserviceaccount.com",
|
||||
"serviceAccount:prod-agpt-market-sa@agpt-prod.iam.gserviceaccount.com"
|
||||
]
|
||||
}
|
||||
|
||||
pods_ip_cidr_range = "10.1.0.0/16"
|
||||
services_ip_cidr_range = "10.2.0.0/20"
|
||||
Reference in New Issue
Block a user