fix(amethyst): supply app_metadata so AppFunctions discovery actually works

After fixing the missing aggregated XML, Pixel 8 logcat still showed:
  D AppFunctions: Unable to resolve AppFunctionMetadata.

Comparing against Google's FilipFan/AppFunctionsPilot sample turned up
a separate metadata pointer the system requires:

  <property
      android:name="android.app.appfunctions.app_metadata"
      android:resource="@xml/app_metadata" />

This goes on the <application> element (not the service) and points to
an XML resource — distinct from the asset-side `app_functions.xml`
that the library auto-merges onto the service. The asset metadata
declares "here are my function ids and schemas"; the resource
metadata gives the agent a user-facing summary like "Search Nostr and
read your follows" to show users before they grant access.

Without the resource, the system can find our service and our
function list but can't resolve the descriptive metadata it shows
the user — so Gemini's tool picker stays empty.

Two new files:
  * amethyst/src/play/res/xml/app_metadata.xml — short description +
    displayDescription. Update when the @AppFunction surface grows.
  * play AndroidManifest <property> pointing at the resource.

Also dropped our explicit <service> declaration for
PlatformAppFunctionService — confirmed via the appfunctions-service
AAR that the library auto-merges that exact entry, complete with
permission + intent-filter, so our copy was redundant.
This commit is contained in:
Claude
2026-05-25 22:03:46 +00:00
parent 82188b719a
commit 0619788644
2 changed files with 29 additions and 14 deletions
+13 -14
View File
@@ -40,21 +40,20 @@
<!-- Gemini / system-agent bridge via androidx.appfunctions
(pre-stable as of May 2026). The androidx-provided
PlatformAppFunctionService dispatches to plain Kotlin
PlatformAppFunctionService (registered automatically via
manifest merging by the library) dispatches to plain Kotlin
classes annotated with @AppFunction (see
com.vitorpamplona.amethyst.appfunctions.AmethystAppFunctions);
instances are constructed by PlayAmethyst's
AppFunctionConfiguration. Play flavor only — the F-Droid
channel ships without the alpha Google AI dependency. -->
<service
android:name="androidx.appfunctions.service.PlatformAppFunctionService"
android:exported="true"
android:permission="android.permission.BIND_APP_FUNCTION_SERVICE"
tools:ignore="ExportedService">
<intent-filter>
<action android:name="android.app.AppFunctionService" />
</intent-filter>
</service>
com.vitorpamplona.amethyst.appfunctions.AmethystAppFunctions).
Play flavor only — the F-Droid channel ships without the
alpha Google AI dependency.
The `app_metadata` property below gives the system agent a
user-facing summary of what this app exposes. Without it,
system logcat logs "Unable to resolve AppFunctionMetadata"
and our functions never make it into Gemini's tool picker. -->
<property
android:name="android.app.appfunctions.app_metadata"
android:resource="@xml/app_metadata" />
</application>
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Natural-language description of the app for the AppFunctions agent
(Gemini and other system assistants). Resolved by the system via the
application-level `<property android:name="android.app.appfunctions.app_metadata">`
pointer in play/AndroidManifest.xml. Without this resource, system
logcat shows "Unable to resolve AppFunctionMetadata" and the agent
can't render a user-facing summary of what our functions do.
Keep descriptions short and Nostr-grounded so a user reading "What
can Amethyst do?" in the agent gets a useful answer. Update when
the @AppFunction surface grows.
-->
<AppFunctionAppMetadata xmlns:appfn="http://schemas.android.com/apk/res-auto"
appfn:description="Amethyst is a Nostr social client. The agent can search Nostr profiles and short text notes through Amethyst's configured search relays, and read the list of accounts the signed-in user follows."
appfn:displayDescription="Search Nostr and read your follows" />