Agent-surface async fetch — prop city and action fetchForecast carry expose/describe so MCP agents can read and invoke them.
propprop.exposeprop.describestateactionaction.exposeaction.describegroupifelseifelseon:clickinterpolationThe real, compiled agent-weather.aihu component, hydrated as an island right here — fully interactive.
// agent-weather — agent-surface pattern: prop city + action fetchForecast with expose/describe
@state {
let city = prop({
default: 'London',
describe: 'City name to retrieve weather forecast for',
expose: 'read',
})
let forecast = state('')
let loading = state(false)
let errorMsg = state('')
const fetchForecast = action(
{ describe: 'Fetch the latest weather forecast for the current city',
expose: 'read write' },
async () => {
loading = true
errorMsg = ''
try {
const res = await fetch(`/api/weather?city=${encodeURIComponent(city)}`)
if (!res.ok) throw new Error(`HTTP ${res.status}`)
forecast = await res.text()
} catch (e) {
errorMsg = (e as Error).message
} finally {
loading = false
}
})
}
@template {
<div class="weather-agent">
<h2 class="title">Weather — {city}</h2>
<group if={loading}>
<p class="loading">Fetching forecast…</p>
</group><group elseif={errorMsg}>
<p class="error">{errorMsg}</p>
</group><group elseif={forecast}>
<p class="forecast">{forecast}</p>
</group><group else>
<p class="prompt">Press Refresh to load forecast.</p>
</group>
<button on:click={fetchForecast} class="refresh-btn" disabled={loading}>
Refresh
</button>
</div>
}
@style {
.weather-agent { padding: 1.5rem; max-width: 22rem; border: 1px solid var(--border, #ccc); border-radius: 6px; }
.title { margin: 0 0 1rem; font-size: 1.2rem; }
.loading { color: var(--info, #036); }
.error { color: var(--error, #c00); }
.forecast { font-size: 1rem; line-height: 1.5; }
.prompt { color: var(--muted, #888); font-style: italic; }
.refresh-btn { margin-top: 0.75rem; padding: 0.4rem 1rem; cursor: pointer; border: 1px solid var(--border, #ccc); border-radius: 4px; }
.refresh-btn:disabled { opacity: 0.5; cursor: not-allowed; }
}stateeventsgovernance