Skip to content

miniapp tool is not exposed in web personal DMs (surfaceName only set with surfaceTools) #899

Description

@lookfree

Summary

The miniapp tool is never offered to the agent in a web personal DM, even though the web UI can render playground artifacts in DMs. Asking for a miniapp in a personal web conversation makes the agent reply that it has no miniapp tool (it only sees execute, read, write, publish, memory, history, background, finish_silently, goals), so it falls back to writing a file or attempting a publish instead.

Repro

  1. Run core + web-ui (org acme, runtime pi).
  2. In the web UI, open your personal DM (web:<user>:default, scope personal:<user>).
  3. Send: "做一个 miniapp 演示" / "make a miniapp demo".
  4. Agent reads skills/miniapp/SKILL.md, then states the miniapp tool is missing from its function list and never emits it.

Observed agent toolset in a web DM turn: execute, read, write, publish, memory, history, background, finish_silently, create_goal, get_goal, update_goal — no miniapp.

In a web channel/group conversation the tool does appear (the same ask works).

Root cause

The tool gating in src/harness/pi-tools.ts is correct:

...(opts?.surfaceName === "web" ? [miniapp] : []),

But surfaceName is only ever set when the turn is routed with surface tools, in src/core/orchestrator.ts (turn assembly):

...(input.surfaceTools && surfaceToolDeps
  ? { surfaceTools: true, surfaceName: /* "web" for web surfaces */ }
  : {}),

And input.surfaceTools only becomes true via spine routing, src/api/app-ambient.ts:

function shouldRouteToSpine(input: OrchestratorInput): boolean {
  const { conversation } = input;
  return conversation.kind !== "dm" && (input.origin.kind === "human" || input.origin.kind === "ambient");
}

src/api/app-turn.ts only sets surfaceTools: true when req.surfaceTools is set or spineRouted.

So for a web conversation with conversation.kind === "dm", surfaceTools is always false → surfaceName is never set → miniapp is never exposed, even though the surface is "web" and the web UI (plugins/web-ui playground.ts + /api/playgrounds/:id with sandbox CSP) renders playgrounds in any session, DM included. Channel/group web chats work only because they go through the spine path.

Suggested fix

Decouple surfaceName from surfaceTools in orchestrator turn assembly so web surfaces always carry surfaceName: "web":

-            ...(input.surfaceTools && surfaceToolDeps
+            ...(input.surfaceTools && surfaceToolDeps ? { surfaceTools: true } : {}),
+            ...(input.surface === "web" || (input.surfaceTools && surfaceToolDeps)
               ? {
-                  surfaceTools: true,
                   surfaceName:
                     input.origin.kind === "automation" && input.origin.destination
                       ? "slack"
                       : (input.surface ?? "slack"),
                 }
               : {}),

surfaceTools still gates the surface post tools as before; only the web surfaceName (which additionally enables miniapp) is now available in web DMs. Non-web turns without surface tools are unaffected (their behavior already defaults to surfaceName ?? "slack" inside pi-tools).

Verified locally with this change: a web DM turn exposes miniapp, the tool call succeeds, and GET /api/playgrounds/:artifactId serves the artifact with the sandbox CSP.

Environment

  • Repo: yc-software/qm @ b384c65
  • Surface: web-ui DM, org runtime pi + OpenAI-compatible provider

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions