# Agent and AI APIs

Developer reference for conversation components, Agent sessions and orchestration, AI calls, and host file access.

Source: https://appjuice.app/guide/api-reference/
Updated: 2026-09-14
Guide baseline: AppJuice 0.350.4

This page is for developers editing app code. For the ordinary Builder workflow, read [Add AI features to your app](https://appjuice.app/guide/apis/). Examples assume a running AppJuice app and configured services for the capabilities used.

## Runtime and imports

AppJuice runs the Agent loop, persists sessions, streams progress, and handles managed tool approvals and artifacts. App code supplies the interface, domain tools, and workflow decisions. These are App-facing interfaces, not an unrestricted public cloud API.

Backend imports under `@appjuice/app-runtime` are supplied by AppJuice. Browser code loads shared components and clients through app-relative `./runtime/` URLs. Keep provider credentials and platform tokens out of browser code.

## Declare an Agent profile

In `agent/agents.json`, declare the Agent identifier used by the client. This minimal profile leaves provider and model selection to AppJuice.

```json
{
  "schemaVersion": 2,
  "defaultAgentId": "assistant",
  "permissions": { "mode": "relaxed" },
  "agents": {
    "assistant": {
      "systemPrompt": "Help the user work with this app.",
      "tools": [],
      "skills": []
    }
  }
}
```

An empty tools list does not disable the automatic built-in tools. It selects no additional app or platform extension tools. Runtime permissions still apply. Add selected Skill folder identifiers from `agent/skills/` and custom tools from `agent/tools/` as the app requires.

## Embed the shared conversation

```html
<script type="module"
  src="./runtime/agent-conversation/agent-conversation.js"></script>

<appjuice-agent-conversation
  agent-id="assistant"
  heading="Assistant"
  intro="Ask for help with this app."
  font-family="inherit"
></appjuice-agent-conversation>
```

`agent-id` is required. For an expandable assistant, use `appjuice-agent-chat-widget` from the same component module. Customize the public attributes rather than the component's internal DOM.

## Invoke an Agent from app backend code

This example belongs in an app's Hono server. It starts an invocation and waits for its canonical result. The client uses the app runtime's Agent routes, derived from the current request.

```typescript
import { Hono } from "hono";
import { createAgentClient } from "@appjuice/app-runtime/agent-session";

const app = new Hono();
app.post("/api/review", async (c) => {
  const body = await c.req.json().catch(() => null);
  if (typeof body?.text !== "string" || !body.text.trim()) {
    return c.json({ error: "Enter text to review." }, 400);
  }
  const client = createAgentClient({
    agentId: "assistant",
    baseUrl: new URL("/agent", c.req.url).toString()
  });
  try {
    const handle = await client.invoke({
      prompt: `Review this text and list its main issues:\n${body.text}`,
      source: "backend",
      executionTimeoutMs: 120000
    });
    const result = await handle.completed;
    if (result.status !== "completed") {
      return c.json({ sessionId: result.sessionId,
        error: "The review did not complete." }, 502);
    }
    return c.json({ sessionId: result.sessionId,
      invocationId: result.invocationId,
      finalMessage: result.finalMessage, artifacts: result.artifacts });
  } catch {
    return c.json({ error: "The review could not be completed." }, 502);
  }
});
export default app;
```

For custom browser UI, import `createAgentClient` from `./runtime/agent-session-client.js`. Do not use the backend package import in browser code. Return a session identifier for longer work and reconnect from the UI rather than holding an HTTP request indefinitely.

## Sessions, events, and results

| Interface | Purpose |
| --- | --- |
| `client.createSession()`, `client.openSession(id)` | Create a conversation or obtain a client for an existing one. |
| `session.invoke({ prompt, ... })` | Start work in a specific session. |
| `handle.on("tool-end", listener)` | Observe events filtered to this invocation. |
| `handle.completed` | Receive status, final message, session identity, and artifacts. |
| `handle.cancel()` | Request cancellation of this invocation. |
| `session.steer(...)`, `session.followUp(...)` | Provide active guidance or queued follow-up work. |
| `session.approve({ toolCallId, approved })` | Resolve a pending tool approval from an authorized UI. |
| `session.uploadAttachment(file, name?)` | Upload a file for use with the message's attachment identifiers. |
Use the shared conversation component for normal approvals and artifact interactions. Do not approve tools silently to keep a backend request moving. Uploaded attachments and host file references are message-scoped; app-owned structured Session Context is a separate feature.

## Coordinate Agent tasks

App code can compose invocations in sequence, in parallel, or in bounded review loops. For a sequential workflow, wait for one invocation's result and pass the relevant output to the next. For parallel work, keep each invocation's identity and handle failures separately before combining results.

The app owns workflow persistence, retries, and partial-failure policy. A persisted Agent session does not make browser orchestration durable across page reloads. Use explicit completion checks and cancellation handling; do not treat starting an invocation as proof that its task succeeded.

## Call Direct AI helpers

Use shared helpers from backend code when the operation is defined. Omitting provider and model uses AppJuice's configured capability selection.

```typescript
import { generateText, searchWeb, extractWeb }
  from "@appjuice/app-runtime/ai";

const summary = await generateText({
  prompt: "Summarize this note in two sentences: The meeting is on Friday.",
  maxTokens: 120
});
console.log(summary.text);

const search = await searchWeb({
  query: "public library opening hours",
  includeImages: false
});
if (search.providerSearchCompleted) {
  console.log(search.citedSources);
}

const page = await extractWeb({ url: "https://example.com/" });
console.log(page.text);
```

Wrap calls in the app's own error handling and present useful errors to the user. Text generation returns natural-language text, not a guaranteed JSON schema. Search completion and warnings are explicit result fields; a returned object alone does not prove a successful search. Web Extract rejects ineligible URLs and reports structured errors.

Other exports include `analyzeImage`, `generateImage`, `transcribeAudio`, `synthesizeSpeech`, `generateMusic`, and `generateVideo`. Inputs and outputs vary by capability. Generated files or asynchronous job results need app-specific presentation and error handling.

The installed Direct AI Capability Integration Building Skill includes per-capability signatures and result guidance. Use those references when implementing media operations; do not guess arguments from a model name.

## Provider and credential access

Prefer shared AI helpers for covered capabilities. Lower-level server-side provider access includes `requestCredential`, `requestCapabilityModelSelections`, and `requestDelegatedProviderAccess`. Use the current installed integration references for their exact contracts.

Do not expose credentials through API responses or generated frontend bundles. App-specific tools can call the same backend helper as the app's normal routes.

## Use host capabilities

Check capability availability before showing a host-dependent action. This browser-side example asks the host to save generated text to a user-selected location.

```javascript
const system = window.AppJuice?.system;
const capabilities = await system?.getCapabilities?.();
if (capabilities?.saveFile) {
  const result = await system.saveFile({
    title: "Save report",
    defaultName: "report.txt",
    source: { kind: "text", text: "Report contents" }
  });
  if (!result.canceled) {
    console.log(result.name);
  }
}
```

Check the returned cancellation and error state in the actual app. In Remote or browser flows, host path operations target the computer or server running AppJuice. Use a normal browser upload for files from the client device. Native clipboard, sharing, opening, and reveal actions depend on host support.
