From 07ce17f3513233574cec2d3dc263cb55e5871e09 Mon Sep 17 00:00:00 2001 From: Brian Love Date: Wed, 24 Jun 2026 21:56:10 -0700 Subject: [PATCH 1/4] feat(ag-ui): plumb GOOGLE_MAPS_MAP_ID through the env mechanism --- examples/ag-ui/angular/scripts/inject-env.mjs | 4 +++- .../ag-ui/angular/src/environments/environment.development.ts | 1 + examples/ag-ui/angular/src/environments/environment.ts | 1 + examples/ag-ui/angular/src/environments/generated-keys.ts | 1 + 4 files changed, 6 insertions(+), 1 deletion(-) diff --git a/examples/ag-ui/angular/scripts/inject-env.mjs b/examples/ag-ui/angular/scripts/inject-env.mjs index 47aa0bebf..93500c617 100644 --- a/examples/ag-ui/angular/scripts/inject-env.mjs +++ b/examples/ag-ui/angular/scripts/inject-env.mjs @@ -20,13 +20,15 @@ function readDotEnv() { const env = { ...readDotEnv(), ...process.env }; const key = env.GOOGLE_MAPS_API_KEY ?? ''; +const mapId = env.GOOGLE_MAPS_MAP_ID ?? ''; const targetPath = resolve(__dirname, '../src/environments/generated-keys.local.ts'); const contents = `// SPDX-License-Identifier: MIT // AUTO-GENERATED by scripts/inject-env.mjs. Do not edit by hand. export const GENERATED_KEYS = { googleMaps: ${JSON.stringify(key)}, + googleMapsMapId: ${JSON.stringify(mapId)}, } as const; `; writeFileSync(targetPath, contents); -console.log(`[inject-env] wrote generated-keys.local.ts (key length: ${key.length})`); +console.log(`[inject-env] wrote generated-keys.local.ts (key length: ${key.length}, mapId: ${mapId ? 'set' : 'unset'})`); diff --git a/examples/ag-ui/angular/src/environments/environment.development.ts b/examples/ag-ui/angular/src/environments/environment.development.ts index 034218f64..4deaa83b6 100644 --- a/examples/ag-ui/angular/src/environments/environment.development.ts +++ b/examples/ag-ui/angular/src/environments/environment.development.ts @@ -7,4 +7,5 @@ export const environment = { telemetry: { enabled: false, sampleRate: 1 }, license: undefined as string | undefined, googleMapsApiKey: GENERATED_KEYS.googleMaps, + googleMapsMapId: GENERATED_KEYS.googleMapsMapId, }; diff --git a/examples/ag-ui/angular/src/environments/environment.ts b/examples/ag-ui/angular/src/environments/environment.ts index b6dc8f395..12a99d0c5 100644 --- a/examples/ag-ui/angular/src/environments/environment.ts +++ b/examples/ag-ui/angular/src/environments/environment.ts @@ -7,4 +7,5 @@ export const environment = { telemetry: { enabled: false, sampleRate: 1 }, license: undefined as string | undefined, googleMapsApiKey: GENERATED_KEYS.googleMaps, + googleMapsMapId: GENERATED_KEYS.googleMapsMapId, }; diff --git a/examples/ag-ui/angular/src/environments/generated-keys.ts b/examples/ag-ui/angular/src/environments/generated-keys.ts index 86059ef48..7da7b6554 100644 --- a/examples/ag-ui/angular/src/environments/generated-keys.ts +++ b/examples/ag-ui/angular/src/environments/generated-keys.ts @@ -4,4 +4,5 @@ // Ships empty (CI has no key); local/preview builds get the real value. export const GENERATED_KEYS = { googleMaps: '', + googleMapsMapId: '', } as const; From 8e5229992b1264bc4a04cbbb15cdb0fd5ff3ea60 Mon Sep 17 00:00:00 2001 From: Brian Love Date: Wed, 24 Jun 2026 21:58:52 -0700 Subject: [PATCH 2/4] feat(ag-ui): load Maps marker library for advanced markers --- examples/ag-ui/angular/src/app/google-maps-loader.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/ag-ui/angular/src/app/google-maps-loader.ts b/examples/ag-ui/angular/src/app/google-maps-loader.ts index 2cfc4b787..297899eef 100644 --- a/examples/ag-ui/angular/src/app/google-maps-loader.ts +++ b/examples/ag-ui/angular/src/app/google-maps-loader.ts @@ -50,7 +50,7 @@ export class GoogleMapsLoader { } const script = doc.createElement('script'); - script.src = `https://maps.googleapis.com/maps/api/js?key=${encodeURIComponent(key)}&libraries=geocoding`; + script.src = `https://maps.googleapis.com/maps/api/js?key=${encodeURIComponent(key)}&libraries=geocoding,marker`; script.async = true; script.setAttribute('data-google-maps', ''); script.addEventListener('load', () => this.loaded.set(true)); From 508b037de1b5e5cf92cb06d2f99551a38420c343 Mon Sep 17 00:00:00 2001 From: Brian Love Date: Wed, 24 Jun 2026 22:01:34 -0700 Subject: [PATCH 3/4] feat(ag-ui): migrate to AdvancedMarkerElement + cloud dark map style --- .../angular/src/app/map-canvas.component.ts | 71 +++++++++---------- 1 file changed, 33 insertions(+), 38 deletions(-) diff --git a/examples/ag-ui/angular/src/app/map-canvas.component.ts b/examples/ag-ui/angular/src/app/map-canvas.component.ts index dfcff47ff..383b27dea 100644 --- a/examples/ag-ui/angular/src/app/map-canvas.component.ts +++ b/examples/ag-ui/angular/src/app/map-canvas.component.ts @@ -10,24 +10,10 @@ import { viewChild, viewChildren, } from '@angular/core'; -import { GoogleMap, MapInfoWindow, MapMarker, MapPolyline } from '@angular/google-maps'; +import { GoogleMap, MapInfoWindow, MapAdvancedMarker, MapPolyline } from '@angular/google-maps'; import { ItineraryStop, ItineraryStore } from './itinerary-store'; import { GoogleMapsLoader } from './google-maps-loader'; - -const DARK_STYLE: google.maps.MapTypeStyle[] = [ - { elementType: 'geometry', stylers: [{ color: '#1d2c4d' }] }, - { elementType: 'labels.text.fill', stylers: [{ color: '#8ec3b9' }] }, - { elementType: 'labels.text.stroke', stylers: [{ color: '#1a3646' }] }, - { featureType: 'administrative.country', elementType: 'geometry.stroke', stylers: [{ color: '#4b6878' }] }, - { featureType: 'landscape.man_made', elementType: 'geometry.stroke', stylers: [{ color: '#334e87' }] }, - { featureType: 'landscape.natural', elementType: 'geometry', stylers: [{ color: '#023e58' }] }, - { featureType: 'poi', elementType: 'geometry', stylers: [{ color: '#283d6a' }] }, - { featureType: 'road', elementType: 'geometry', stylers: [{ color: '#304a7d' }] }, - { featureType: 'road', elementType: 'labels.text.fill', stylers: [{ color: '#98a5be' }] }, - { featureType: 'transit', elementType: 'geometry', stylers: [{ color: '#283d6a' }] }, - { featureType: 'water', elementType: 'geometry', stylers: [{ color: '#0e1626' }] }, - { featureType: 'water', elementType: 'labels.text.fill', stylers: [{ color: '#4e6d70' }] }, -]; +import { environment } from '../environments/environment'; const DAY_COLORS = ['#ef4444', '#3b82f6', '#10b981', '#f59e0b', '#8b5cf6', '#ec4899', '#06b6d4', '#84cc16']; const PARIS_CENTER: google.maps.LatLngLiteral = { lat: 48.8566, lng: 2.3522 }; @@ -35,7 +21,7 @@ const PARIS_CENTER: google.maps.LatLngLiteral = { lat: 48.8566, lng: 2.3522 }; @Component({ selector: 'app-map-canvas', standalone: true, - imports: [GoogleMap, MapInfoWindow, MapMarker, MapPolyline], + imports: [GoogleMap, MapInfoWindow, MapAdvancedMarker, MapPolyline], changeDetection: ChangeDetectionStrategy.OnPush, template: ` +# AG-UI Itinerary example (Angular) + +A trip-planner demo where the agent edits a live itinerary UI over the +[AG-UI](https://github.com/cacheplane/angular-agent-framework) transport. It has a +chat/panel layout and an **App mode** that swaps the panel for a full-bleed +Google Map cockpit. + +## Google Maps (App mode) + +App mode renders a Google Map, which needs a Maps JavaScript API key. The key is +read from the repo-root `.env` at build time (via `scripts/inject-env.mjs`, which +writes a gitignored `src/environments/generated-keys.local.ts`). Add to the root +`.env`: + +``` +GOOGLE_MAPS_API_KEY=your_api_key_here +``` + +Without a key, App mode's map stays disabled (the rest of the demo still works). + +### Dark map theme (optional) + +App-mode markers use Google's **Advanced Markers**, which require the map to have +a **Map ID** — and a map with a Map ID takes its styling from a **cloud-based map +style** (the inline JSON dark theme no longer applies). To get the dark theme: + +1. In the [Google Cloud Console](https://console.cloud.google.com/google/maps-apis/studio/maps), + create a **vector Map ID** and a **dark map style**, and associate them. +2. Add the id to the root `.env`: + + ``` + GOOGLE_MAPS_MAP_ID=your_map_id_here + ``` + +Without `GOOGLE_MAPS_MAP_ID`, the demo falls back to Google's `DEMO_MAP_ID` and +renders a **light** map — markers and routes still work, only the dark styling is +absent.