@ag-ui/omnara 0.0.0-stage → 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +138 -2
- package/dist/index.d.mts +154 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.d.ts +154 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +6 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +67 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,139 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @ag-ui/omnara
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Connect an [AG-UI](https://ag-ui.com) frontend, such as [CopilotKit](https://copilotkit.ai), to [Omnara](https://omnara.com), the open-source control plane for durable, hosted agents. Each chat thread gets its own Omnara agent, per user, launched from a [profile or an inline definition](https://docs.omnara.com/agents/configuration).
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @ag-ui/omnara
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Requires Node 22.12+ (the CommonJS build loads the ESM-only `@omnara/sdk`).
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { OmnaraAgent } from "@ag-ui/omnara";
|
|
17
|
+
|
|
18
|
+
const agent = new OmnaraAgent({
|
|
19
|
+
apiKey: process.env.OMNARA_API_KEY, // org API key, developer role on the project
|
|
20
|
+
orgId: "org_...",
|
|
21
|
+
projectId: "proj_...",
|
|
22
|
+
profile: "support-agent", // or `definition: { source }`
|
|
23
|
+
user: { id: session.userId, name: session.userName }, // from your auth, per request
|
|
24
|
+
});
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
With CopilotKit, build the agent in the runtime's `agents` factory, which receives the request, so `user` comes from your own auth:
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
new CopilotRuntime({
|
|
31
|
+
agents: async ({ request }) => {
|
|
32
|
+
const session = await auth(request);
|
|
33
|
+
return { support: new OmnaraAgent({ ...omnaraConfig, user: { id: session.userId } }) };
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## What it does
|
|
39
|
+
|
|
40
|
+
| Omnara | AG-UI |
|
|
41
|
+
| --- | --- |
|
|
42
|
+
| Text and reasoning previews, completed by `model_output` | `TEXT_MESSAGE_*`, `REASONING_*` (streamed live) |
|
|
43
|
+
| Tool calls and results | `TOOL_CALL_*`, `TOOL_CALL_RESULT` (files as `[file]`) |
|
|
44
|
+
| A custom call to one of the page's tools | `TOOL_CALL_*`, then `RUN_FINISHED` with `pendingToolCallIds`; the page's result goes back as the call's result |
|
|
45
|
+
| A `permission` or `question` interaction | `RUN_FINISHED` with an interrupt (`omnara:permission`, `omnara:question`); the resume answers it |
|
|
46
|
+
| [Subagent](https://docs.omnara.com/tools/built-in#subagents) reports; messages from other people (Omnara's dashboard, the API, Slack) | Assistant messages for reports, user messages for everyone else; both carry the sender's `name` |
|
|
47
|
+
| The log | `MESSAGES_SNAPSHOT` at the end of every run |
|
|
48
|
+
| The thread's agent is created | `CUSTOM` `omnara.agent` with `{ agentId, threadId }` |
|
|
49
|
+
|
|
50
|
+
### Context and attachments
|
|
51
|
+
|
|
52
|
+
`RunAgentInput.context` reaches the model as a hidden block; inline images and documents are sent as files, and other parts become a note to the model.
|
|
53
|
+
|
|
54
|
+
### Browser tools
|
|
55
|
+
|
|
56
|
+
Tools in `RunAgentInput.tools` are added to the thread's Omnara agent as [custom tools](https://docs.omnara.com/tools/custom) (profiles are never changed); a tool the agent's definition already declares keeps the definition's version. A browser tool call the page never answers (a new message arrives without its result) is cancelled with Omnara's cancel before the message is delivered.
|
|
57
|
+
|
|
58
|
+
### Backend tools
|
|
59
|
+
|
|
60
|
+
Tools your server runs go in `backendTools`:
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
new OmnaraAgent({
|
|
64
|
+
...config,
|
|
65
|
+
backendTools: [
|
|
66
|
+
{
|
|
67
|
+
name: "get_weather",
|
|
68
|
+
description: "Get the weather for a location.",
|
|
69
|
+
parameters: { type: "object", properties: { location: { type: "string" } } },
|
|
70
|
+
handler: async (input, { toolCallId }) => ({ temperature: 21 }),
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
});
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
A handler runs while a request is following the agent, and must be safe to run twice for the same `toolCallId`: two servers following one agent can both pick up a call before Omnara records the first result. A handler's error is returned to the agent as a failed result.
|
|
77
|
+
|
|
78
|
+
### Approvals and questions
|
|
79
|
+
|
|
80
|
+
An interrupt carries Omnara's [approval or question form](https://docs.omnara.com/events/interactions) in `metadata.omnara` (`kind`, `form`, `agentId`, `agentName`, `toolName`) and a `responseSchema`. Resume with:
|
|
81
|
+
|
|
82
|
+
- permission: `{ approved: boolean, reason?: string }`
|
|
83
|
+
- question: `{ answers: [{ optionIndices: number[], text?: string }] }`, one entry per question
|
|
84
|
+
|
|
85
|
+
A `cancelled` resume entry lets the agent continue: a permission is denied, a question gets its "Other" option with a note. Subagent approvals and questions arrive the same way.
|
|
86
|
+
|
|
87
|
+
### Stop and disconnect
|
|
88
|
+
|
|
89
|
+
`abortRun()` (CopilotKit's Stop button) cancels the agent and its running subagents with Omnara's cancel, and ends the run as cancelled. A closed tab or dropped connection cancels nothing: the agent keeps working, and the next run catches the chat up from the log.
|
|
90
|
+
|
|
91
|
+
## Options
|
|
92
|
+
|
|
93
|
+
| Option | Default | |
|
|
94
|
+
| --- | --- | --- |
|
|
95
|
+
| `apiKey` | `OMNARA_API_KEY` | [Org API key](https://docs.omnara.com/api/authentication#org-api-keys-for-services) with the developer role on the project. |
|
|
96
|
+
| `orgId`, `projectId` | required | |
|
|
97
|
+
| `baseUrl` | `https://api.omnara.com/v1` | A [self-hosted](https://docs.omnara.com/self-hosting/deployment) Omnara serves its API at `https://<your-host>/api/v1`. |
|
|
98
|
+
| `profile` | | Profile id (`aprf_...`) or name. A thread keeps the agent it started with, so changing the profile (or editing it) applies to new threads. |
|
|
99
|
+
| `definition` | | Inline `{ source, format? }`; `source` is a YAML or JSON string or an object. Changes apply to new threads, as with a profile. |
|
|
100
|
+
| `user` | required | `{ id, tenant?, name? }` from your auth, or `"anonymous"` for demos; the Omnara actor on everything the adapter sends. |
|
|
101
|
+
| `backendTools` | `[]` | Tools your server runs. |
|
|
102
|
+
| `onError` | `console.error` | Receives absorbed failures and the full upstream error text. |
|
|
103
|
+
|
|
104
|
+
Give exactly one of `profile` and `definition`.
|
|
105
|
+
|
|
106
|
+
## Errors
|
|
107
|
+
|
|
108
|
+
`RUN_ERROR` carries a stable `code` and a generic message; upstream text goes to `onError`, never to the client.
|
|
109
|
+
|
|
110
|
+
| Code | When |
|
|
111
|
+
| --- | --- |
|
|
112
|
+
| `thread_ended` | The thread's Omnara agent was archived. Start a new thread. |
|
|
113
|
+
| `invalid_tools` | Omnara rejected the tools (the page's or `backendTools`). |
|
|
114
|
+
| `message_too_large` | A message plus the page's context is over Omnara's 1 MiB limit. The thread can't continue past it; start a new one. |
|
|
115
|
+
| `model_error` | The model call failed for good. |
|
|
116
|
+
| `run_failed` | Anything else, such as Omnara being unreachable. Retrying is safe. |
|
|
117
|
+
|
|
118
|
+
## Limits
|
|
119
|
+
|
|
120
|
+
- **Check thread ownership.** The adapter keys each thread's agent by user, but CopilotKit's in-memory runner replays and stops runs by thread id alone. Check that the caller owns the thread in `beforeRequestMiddleware`.
|
|
121
|
+
- **A thread belongs to one user.** To continue a chat as someone else (a guest who signs in, say), start a new thread: that user's agent would receive the whole chat.
|
|
122
|
+
- **Tool results over 1 MiB** reach the agent as a failed result saying so.
|
|
123
|
+
- **The adapter owns the custom tools it adds to a thread's agent.** A custom tool added to that agent another way (in Omnara's dashboard, say) is removed with the next request; put tools in the profile or definition instead.
|
|
124
|
+
- **Don't make the Omnara agent CopilotKit's suggestions provider.** Each suggestion with `instructions` would launch a new Omnara agent.
|
|
125
|
+
- **No updates while the chat is idle.** AG-UI has no channel for them; what happened meanwhile appears with the next request.
|
|
126
|
+
- **With nested subagents ([`max_depth`](https://docs.omnara.com/agents/configuration) above 1), a run can end before their work does.** What they report appears with the next request.
|
|
127
|
+
- **After a CopilotKit server restart the chat shows only new messages.** The runner keeps history in memory; Omnara still has it all.
|
|
128
|
+
- **Files the agent creates aren't shown.** Omnara files ([artifacts](https://docs.omnara.com/events/artifacts)) can only be downloaded with the API key, so the browser can't load them. Tool results and messages show `[file]` where one was.
|
|
129
|
+
|
|
130
|
+
## Running the dojo
|
|
131
|
+
|
|
132
|
+
The dojo runs the Omnara agents in-process (`apps/dojo/src/agents.ts`), so there is no separate server:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
cd apps/dojo
|
|
136
|
+
OMNARA_API_KEY=... OMNARA_ORG_ID=org_... OMNARA_PROJECT_ID=proj_... pnpm dev
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Visit http://localhost:3000 and select **Omnara**. `OMNARA_MODEL_PROVIDER` and `OMNARA_MODEL` pick the model; the defaults exist only in the hosted dojo's project, so set them to a [model provider](https://docs.omnara.com/organization/model-providers) and model in yours.
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { AbstractAgent, AgentConfig } from "@ag-ui/client";
|
|
2
|
+
import { Observable } from "rxjs";
|
|
3
|
+
import { Actor, Agent, AgentConfig as AgentConfig$1, AgentEvent, AgentEventStreamFrame, AgentInteraction, CreateAgentInputContentBlock, ExternalActorParams, InteractionAnswer, SubmitToolResultContentBlock, ToolCall } from "@omnara/sdk";
|
|
4
|
+
import { BaseEvent, RunAgentInput } from "@ag-ui/core";
|
|
5
|
+
|
|
6
|
+
//#region src/api.d.ts
|
|
7
|
+
/**
|
|
8
|
+
* The Omnara calls the adapter makes. A narrow seam over `@omnara/sdk` so the
|
|
9
|
+
* run logic can be tested against a fake.
|
|
10
|
+
*/
|
|
11
|
+
interface OmnaraApi {
|
|
12
|
+
createConfig(source: string, format: "yaml" | "json"): Promise<{
|
|
13
|
+
id: string;
|
|
14
|
+
}>;
|
|
15
|
+
getConfig(configId: string): Promise<AgentConfig$1>;
|
|
16
|
+
getProfile(idOrName: string): Promise<{
|
|
17
|
+
id: string;
|
|
18
|
+
current_config_id: string;
|
|
19
|
+
}>;
|
|
20
|
+
/** `created` is false when the idempotency key replayed an existing agent. */
|
|
21
|
+
launch(body: {
|
|
22
|
+
config: string;
|
|
23
|
+
profile?: string;
|
|
24
|
+
name: string;
|
|
25
|
+
}, idempotencyKey: string): Promise<{
|
|
26
|
+
agent: Agent;
|
|
27
|
+
created: boolean;
|
|
28
|
+
}>;
|
|
29
|
+
getAgent(agentId: string): Promise<Agent>;
|
|
30
|
+
/** All of the agent's unarchived subagents. */
|
|
31
|
+
listChildren(agentId: string): Promise<Agent[]>;
|
|
32
|
+
setConfig(agentId: string, source: string, format: "yaml" | "json", expectedCurrentConfigId: string): Promise<void>;
|
|
33
|
+
/** The whole log, oldest first. */
|
|
34
|
+
listEvents(agentId: string): Promise<AgentEvent[]>;
|
|
35
|
+
/** Whether the log has events after `sequence`. */
|
|
36
|
+
hasEventsAfter(agentId: string, sequence: number): Promise<boolean>;
|
|
37
|
+
/** All inputs stored but not yet started (queued messages, undelivered subagent reports). */
|
|
38
|
+
listBacklog(agentId: string): Promise<Array<{
|
|
39
|
+
id: string;
|
|
40
|
+
input_idempotency_key?: string;
|
|
41
|
+
}>>;
|
|
42
|
+
/** Cancel an input still in the backlog (a 409 once it has started). */
|
|
43
|
+
cancelQueuedInput(agentId: string, inputId: string): Promise<void>;
|
|
44
|
+
postInput(agentId: string, body: {
|
|
45
|
+
content_blocks: CreateAgentInputContentBlock[];
|
|
46
|
+
actor?: ExternalActorParams;
|
|
47
|
+
}, idempotencyKey: string): Promise<void>;
|
|
48
|
+
stream(agentId: string, afterSequence: number, signal: AbortSignal, onConnected: () => void): AsyncIterable<AgentEventStreamFrame>;
|
|
49
|
+
/** Ready custom calls on the agent and its subagents. */
|
|
50
|
+
readyCustomCalls(agentId: string): Promise<ToolCall[]>;
|
|
51
|
+
/** Open interactions on the agent and its subagents. */
|
|
52
|
+
openInteractions(agentId: string): Promise<AgentInteraction[]>;
|
|
53
|
+
submitResult(agentId: string, toolCallId: string, outcome: "succeeded" | "failed", content: SubmitToolResultContentBlock[]): Promise<void>;
|
|
54
|
+
resolveInteraction(agentId: string, interactionId: string, answers: InteractionAnswer[], actor?: ExternalActorParams): Promise<void>;
|
|
55
|
+
cancel(agentId: string, actor?: ExternalActorParams): Promise<void>;
|
|
56
|
+
getActor(actorId: string): Promise<Actor>;
|
|
57
|
+
}
|
|
58
|
+
//#endregion
|
|
59
|
+
//#region src/types.d.ts
|
|
60
|
+
/**
|
|
61
|
+
* The end user a request acts for. Set it on the server from your own auth,
|
|
62
|
+
* never from the request body: it picks the user's Omnara agent for a thread,
|
|
63
|
+
* and becomes the Omnara actor on every message, answer and cancel.
|
|
64
|
+
*/
|
|
65
|
+
interface OmnaraUser {
|
|
66
|
+
id: string;
|
|
67
|
+
/** Namespace for `id` when user ids are only unique per tenant. */
|
|
68
|
+
tenant?: string;
|
|
69
|
+
/** Shown in Omnara as the actor's name. */
|
|
70
|
+
name?: string;
|
|
71
|
+
}
|
|
72
|
+
/** A tool the agent may call that this server runs. */
|
|
73
|
+
interface BackendTool {
|
|
74
|
+
name: string;
|
|
75
|
+
description: string;
|
|
76
|
+
/** JSON Schema for the tool input. */
|
|
77
|
+
parameters?: Record<string, unknown>;
|
|
78
|
+
/**
|
|
79
|
+
* Runs the call. Must be safe to run twice for the same `toolCallId`: two
|
|
80
|
+
* servers following one agent can both pick up a call before either
|
|
81
|
+
* result is recorded (Omnara keeps the first result).
|
|
82
|
+
*/
|
|
83
|
+
handler: (input: unknown, context: {
|
|
84
|
+
toolCallId: string;
|
|
85
|
+
}) => unknown | Promise<unknown>;
|
|
86
|
+
}
|
|
87
|
+
/** An agent definition passed inline instead of a profile. */
|
|
88
|
+
interface OmnaraAgentDefinition {
|
|
89
|
+
/** Omnara agent config source: a YAML or JSON string, or an object. */
|
|
90
|
+
source: string | Record<string, unknown>;
|
|
91
|
+
/** Defaults to `json` for an object and `yaml` for a string. */
|
|
92
|
+
format?: "yaml" | "json";
|
|
93
|
+
}
|
|
94
|
+
type OmnaraErrorContext = {
|
|
95
|
+
/** Stable identifier for what failed, e.g. `"run_failed"`. */operation: string;
|
|
96
|
+
threadId?: string;
|
|
97
|
+
agentId?: string;
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Receives failures that are absorbed or reported to the client only as a
|
|
101
|
+
* stable code, with the full upstream detail. Nothing it does can fail a run.
|
|
102
|
+
*/
|
|
103
|
+
type OmnaraErrorHandler = (error: unknown, context: OmnaraErrorContext) => void | Promise<void>;
|
|
104
|
+
interface OmnaraAgentConfig extends AgentConfig {
|
|
105
|
+
/** Org API key with the developer role on the project. Defaults to `OMNARA_API_KEY`. */
|
|
106
|
+
apiKey?: string;
|
|
107
|
+
orgId: string;
|
|
108
|
+
projectId: string;
|
|
109
|
+
/** Defaults to hosted Omnara (`https://api.omnara.com/v1`). */
|
|
110
|
+
baseUrl?: string;
|
|
111
|
+
/** Profile id (`aprf_...`) or name. Give exactly one of `profile` and `definition`. */
|
|
112
|
+
profile?: string;
|
|
113
|
+
/** Inline agent definition. Give exactly one of `profile` and `definition`. */
|
|
114
|
+
definition?: OmnaraAgentDefinition;
|
|
115
|
+
/** The end user, or `"anonymous"` to opt out of per-user threads (demos only). */
|
|
116
|
+
user: OmnaraUser | "anonymous";
|
|
117
|
+
backendTools?: BackendTool[];
|
|
118
|
+
onError?: OmnaraErrorHandler;
|
|
119
|
+
}
|
|
120
|
+
//#endregion
|
|
121
|
+
//#region src/agent.d.ts
|
|
122
|
+
/**
|
|
123
|
+
* An AG-UI agent backed by an Omnara agent. Each AG-UI thread gets its own
|
|
124
|
+
* Omnara agent (per user), launched from a profile or an inline definition.
|
|
125
|
+
* Omnara's log is the truth; each run restates the chat from it.
|
|
126
|
+
*/
|
|
127
|
+
declare class OmnaraAgent extends AbstractAgent {
|
|
128
|
+
private config;
|
|
129
|
+
private api;
|
|
130
|
+
private backendTools;
|
|
131
|
+
private currentRun;
|
|
132
|
+
/** `api` replaces the Omnara client (tests). */
|
|
133
|
+
constructor(config: OmnaraAgentConfig, api?: OmnaraApi);
|
|
134
|
+
/** `super.clone()` keeps the AbstractAgent state; the Omnara client is shared. */
|
|
135
|
+
clone(): OmnaraAgent;
|
|
136
|
+
/** Stop: cancels the agent's current work and its running subagents, and ends the run as cancelled. */
|
|
137
|
+
abortRun(): void;
|
|
138
|
+
run(input: RunAgentInput): Observable<BaseEvent>;
|
|
139
|
+
private report;
|
|
140
|
+
}
|
|
141
|
+
//#endregion
|
|
142
|
+
//#region src/run.d.ts
|
|
143
|
+
/** Stable `RUN_ERROR` codes. Upstream error text never reaches the client; it goes to `onError`. */
|
|
144
|
+
declare const ERROR_MESSAGES: {
|
|
145
|
+
readonly thread_ended: "This chat's Omnara agent was archived. Start a new chat to continue.";
|
|
146
|
+
readonly invalid_tools: "Omnara rejected this chat's tools.";
|
|
147
|
+
readonly message_too_large: "This message is too large for Omnara. Start a new chat to continue.";
|
|
148
|
+
readonly run_failed: "The Omnara agent could not complete this request.";
|
|
149
|
+
readonly model_error: "The model failed to respond.";
|
|
150
|
+
};
|
|
151
|
+
type OmnaraErrorCode = keyof typeof ERROR_MESSAGES;
|
|
152
|
+
//#endregion
|
|
153
|
+
export { type BackendTool, ERROR_MESSAGES, OmnaraAgent, type OmnaraAgentConfig, type OmnaraAgentDefinition, type OmnaraErrorCode, type OmnaraErrorContext, type OmnaraErrorHandler, type OmnaraUser };
|
|
154
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/api.ts","../src/types.ts","../src/agent.ts","../src/run.ts"],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { AbstractAgent, AgentConfig } from "@ag-ui/client";
|
|
2
|
+
import { BaseEvent, RunAgentInput } from "@ag-ui/core";
|
|
3
|
+
import { Observable } from "rxjs";
|
|
4
|
+
import { Actor, Agent, AgentConfig as AgentConfig$1, AgentEvent, AgentEventStreamFrame, AgentInteraction, CreateAgentInputContentBlock, ExternalActorParams, InteractionAnswer, SubmitToolResultContentBlock, ToolCall } from "@omnara/sdk";
|
|
5
|
+
|
|
6
|
+
//#region src/api.d.ts
|
|
7
|
+
/**
|
|
8
|
+
* The Omnara calls the adapter makes. A narrow seam over `@omnara/sdk` so the
|
|
9
|
+
* run logic can be tested against a fake.
|
|
10
|
+
*/
|
|
11
|
+
interface OmnaraApi {
|
|
12
|
+
createConfig(source: string, format: "yaml" | "json"): Promise<{
|
|
13
|
+
id: string;
|
|
14
|
+
}>;
|
|
15
|
+
getConfig(configId: string): Promise<AgentConfig$1>;
|
|
16
|
+
getProfile(idOrName: string): Promise<{
|
|
17
|
+
id: string;
|
|
18
|
+
current_config_id: string;
|
|
19
|
+
}>;
|
|
20
|
+
/** `created` is false when the idempotency key replayed an existing agent. */
|
|
21
|
+
launch(body: {
|
|
22
|
+
config: string;
|
|
23
|
+
profile?: string;
|
|
24
|
+
name: string;
|
|
25
|
+
}, idempotencyKey: string): Promise<{
|
|
26
|
+
agent: Agent;
|
|
27
|
+
created: boolean;
|
|
28
|
+
}>;
|
|
29
|
+
getAgent(agentId: string): Promise<Agent>;
|
|
30
|
+
/** All of the agent's unarchived subagents. */
|
|
31
|
+
listChildren(agentId: string): Promise<Agent[]>;
|
|
32
|
+
setConfig(agentId: string, source: string, format: "yaml" | "json", expectedCurrentConfigId: string): Promise<void>;
|
|
33
|
+
/** The whole log, oldest first. */
|
|
34
|
+
listEvents(agentId: string): Promise<AgentEvent[]>;
|
|
35
|
+
/** Whether the log has events after `sequence`. */
|
|
36
|
+
hasEventsAfter(agentId: string, sequence: number): Promise<boolean>;
|
|
37
|
+
/** All inputs stored but not yet started (queued messages, undelivered subagent reports). */
|
|
38
|
+
listBacklog(agentId: string): Promise<Array<{
|
|
39
|
+
id: string;
|
|
40
|
+
input_idempotency_key?: string;
|
|
41
|
+
}>>;
|
|
42
|
+
/** Cancel an input still in the backlog (a 409 once it has started). */
|
|
43
|
+
cancelQueuedInput(agentId: string, inputId: string): Promise<void>;
|
|
44
|
+
postInput(agentId: string, body: {
|
|
45
|
+
content_blocks: CreateAgentInputContentBlock[];
|
|
46
|
+
actor?: ExternalActorParams;
|
|
47
|
+
}, idempotencyKey: string): Promise<void>;
|
|
48
|
+
stream(agentId: string, afterSequence: number, signal: AbortSignal, onConnected: () => void): AsyncIterable<AgentEventStreamFrame>;
|
|
49
|
+
/** Ready custom calls on the agent and its subagents. */
|
|
50
|
+
readyCustomCalls(agentId: string): Promise<ToolCall[]>;
|
|
51
|
+
/** Open interactions on the agent and its subagents. */
|
|
52
|
+
openInteractions(agentId: string): Promise<AgentInteraction[]>;
|
|
53
|
+
submitResult(agentId: string, toolCallId: string, outcome: "succeeded" | "failed", content: SubmitToolResultContentBlock[]): Promise<void>;
|
|
54
|
+
resolveInteraction(agentId: string, interactionId: string, answers: InteractionAnswer[], actor?: ExternalActorParams): Promise<void>;
|
|
55
|
+
cancel(agentId: string, actor?: ExternalActorParams): Promise<void>;
|
|
56
|
+
getActor(actorId: string): Promise<Actor>;
|
|
57
|
+
}
|
|
58
|
+
//#endregion
|
|
59
|
+
//#region src/types.d.ts
|
|
60
|
+
/**
|
|
61
|
+
* The end user a request acts for. Set it on the server from your own auth,
|
|
62
|
+
* never from the request body: it picks the user's Omnara agent for a thread,
|
|
63
|
+
* and becomes the Omnara actor on every message, answer and cancel.
|
|
64
|
+
*/
|
|
65
|
+
interface OmnaraUser {
|
|
66
|
+
id: string;
|
|
67
|
+
/** Namespace for `id` when user ids are only unique per tenant. */
|
|
68
|
+
tenant?: string;
|
|
69
|
+
/** Shown in Omnara as the actor's name. */
|
|
70
|
+
name?: string;
|
|
71
|
+
}
|
|
72
|
+
/** A tool the agent may call that this server runs. */
|
|
73
|
+
interface BackendTool {
|
|
74
|
+
name: string;
|
|
75
|
+
description: string;
|
|
76
|
+
/** JSON Schema for the tool input. */
|
|
77
|
+
parameters?: Record<string, unknown>;
|
|
78
|
+
/**
|
|
79
|
+
* Runs the call. Must be safe to run twice for the same `toolCallId`: two
|
|
80
|
+
* servers following one agent can both pick up a call before either
|
|
81
|
+
* result is recorded (Omnara keeps the first result).
|
|
82
|
+
*/
|
|
83
|
+
handler: (input: unknown, context: {
|
|
84
|
+
toolCallId: string;
|
|
85
|
+
}) => unknown | Promise<unknown>;
|
|
86
|
+
}
|
|
87
|
+
/** An agent definition passed inline instead of a profile. */
|
|
88
|
+
interface OmnaraAgentDefinition {
|
|
89
|
+
/** Omnara agent config source: a YAML or JSON string, or an object. */
|
|
90
|
+
source: string | Record<string, unknown>;
|
|
91
|
+
/** Defaults to `json` for an object and `yaml` for a string. */
|
|
92
|
+
format?: "yaml" | "json";
|
|
93
|
+
}
|
|
94
|
+
type OmnaraErrorContext = {
|
|
95
|
+
/** Stable identifier for what failed, e.g. `"run_failed"`. */operation: string;
|
|
96
|
+
threadId?: string;
|
|
97
|
+
agentId?: string;
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Receives failures that are absorbed or reported to the client only as a
|
|
101
|
+
* stable code, with the full upstream detail. Nothing it does can fail a run.
|
|
102
|
+
*/
|
|
103
|
+
type OmnaraErrorHandler = (error: unknown, context: OmnaraErrorContext) => void | Promise<void>;
|
|
104
|
+
interface OmnaraAgentConfig extends AgentConfig {
|
|
105
|
+
/** Org API key with the developer role on the project. Defaults to `OMNARA_API_KEY`. */
|
|
106
|
+
apiKey?: string;
|
|
107
|
+
orgId: string;
|
|
108
|
+
projectId: string;
|
|
109
|
+
/** Defaults to hosted Omnara (`https://api.omnara.com/v1`). */
|
|
110
|
+
baseUrl?: string;
|
|
111
|
+
/** Profile id (`aprf_...`) or name. Give exactly one of `profile` and `definition`. */
|
|
112
|
+
profile?: string;
|
|
113
|
+
/** Inline agent definition. Give exactly one of `profile` and `definition`. */
|
|
114
|
+
definition?: OmnaraAgentDefinition;
|
|
115
|
+
/** The end user, or `"anonymous"` to opt out of per-user threads (demos only). */
|
|
116
|
+
user: OmnaraUser | "anonymous";
|
|
117
|
+
backendTools?: BackendTool[];
|
|
118
|
+
onError?: OmnaraErrorHandler;
|
|
119
|
+
}
|
|
120
|
+
//#endregion
|
|
121
|
+
//#region src/agent.d.ts
|
|
122
|
+
/**
|
|
123
|
+
* An AG-UI agent backed by an Omnara agent. Each AG-UI thread gets its own
|
|
124
|
+
* Omnara agent (per user), launched from a profile or an inline definition.
|
|
125
|
+
* Omnara's log is the truth; each run restates the chat from it.
|
|
126
|
+
*/
|
|
127
|
+
declare class OmnaraAgent extends AbstractAgent {
|
|
128
|
+
private config;
|
|
129
|
+
private api;
|
|
130
|
+
private backendTools;
|
|
131
|
+
private currentRun;
|
|
132
|
+
/** `api` replaces the Omnara client (tests). */
|
|
133
|
+
constructor(config: OmnaraAgentConfig, api?: OmnaraApi);
|
|
134
|
+
/** `super.clone()` keeps the AbstractAgent state; the Omnara client is shared. */
|
|
135
|
+
clone(): OmnaraAgent;
|
|
136
|
+
/** Stop: cancels the agent's current work and its running subagents, and ends the run as cancelled. */
|
|
137
|
+
abortRun(): void;
|
|
138
|
+
run(input: RunAgentInput): Observable<BaseEvent>;
|
|
139
|
+
private report;
|
|
140
|
+
}
|
|
141
|
+
//#endregion
|
|
142
|
+
//#region src/run.d.ts
|
|
143
|
+
/** Stable `RUN_ERROR` codes. Upstream error text never reaches the client; it goes to `onError`. */
|
|
144
|
+
declare const ERROR_MESSAGES: {
|
|
145
|
+
readonly thread_ended: "This chat's Omnara agent was archived. Start a new chat to continue.";
|
|
146
|
+
readonly invalid_tools: "Omnara rejected this chat's tools.";
|
|
147
|
+
readonly message_too_large: "This message is too large for Omnara. Start a new chat to continue.";
|
|
148
|
+
readonly run_failed: "The Omnara agent could not complete this request.";
|
|
149
|
+
readonly model_error: "The model failed to respond.";
|
|
150
|
+
};
|
|
151
|
+
type OmnaraErrorCode = keyof typeof ERROR_MESSAGES;
|
|
152
|
+
//#endregion
|
|
153
|
+
export { type BackendTool, ERROR_MESSAGES, OmnaraAgent, type OmnaraAgentConfig, type OmnaraAgentDefinition, type OmnaraErrorCode, type OmnaraErrorContext, type OmnaraErrorHandler, type OmnaraUser };
|
|
154
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/api.ts","../src/types.ts","../src/agent.ts","../src/run.ts"],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
let e=require(`@ag-ui/client`),t=require(`rxjs`),n=require(`@omnara/sdk`),r=require(`@ag-ui/core`),i=require(`node:crypto`),a=require(`yaml`);function o(e){if(e instanceof n.ApiError)return e.status;let t=e?.status;return typeof t==`number`?t:void 0}function s(e){if(e instanceof n.ApiError)return e.code;let t=e?.code;return typeof t==`string`?t:void 0}function c(e){let t=(0,n.createOmnaraClient)({baseUrl:e.baseUrl,auth:(0,n.bearerToken)(e.apiKey),fetch:(e,t)=>{if((e instanceof Request?e.url:String(e)).includes(`/events/stream`))return fetch(e,t);let n=AbortSignal.timeout(3e4),r=t?.signal?AbortSignal.any([t.signal,n]):n;return fetch(e,{...t,signal:r})}}),r={orgID:e.orgId,projectID:e.projectId},i=e=>({...r,agentID:e});return{async createConfig(e,i){let{data:a}=await n.sdk.createAgentConfig({client:t,path:r,body:{source:e,source_format:i}});return{id:a.id}},async getConfig(e){let{data:i}=await n.sdk.getAgentConfig({client:t,path:{...r,agentConfigID:e}});return i},async getProfile(e){if(e.startsWith(`aprf_`)){let{data:i}=await n.sdk.getAgentProfile({client:t,path:{...r,agentProfileID:e}});return i}let{data:i}=await n.sdk.listAgentProfiles({client:t,path:r,query:{name:e.replace(/[\\*?]/g,`\\$&`),limit:100}}),a=i.data.find(t=>t.name===e);if(!a)throw Error(`Omnara profile "${e}" not found`);return a},async launch(e,i){let{data:a,response:o}=await n.sdk.createAgent({client:t,path:r,body:e,headers:{"Idempotency-Key":i}});return{agent:a.agent,created:o.status===201}},async getAgent(e){let{data:r}=await n.sdk.getAgent({client:t,path:i(e)});return r.agent},async listChildren(e){let i=[],a;for(;;){let{data:o}=await n.sdk.listAgents({client:t,path:r,query:{parent_agent_id:e,limit:100,cursor:a}});if(i.push(...o.data),!o.next_cursor||o.data.length===0)return i;a=o.next_cursor}},async setConfig(e,r,a,o){await n.sdk.updateAgentConfig({client:t,path:i(e),body:{source:r,source_format:a,expected_current_config_id:o}})},async listEvents(e){let r=[],a=0;for(;;){let{data:o}=await n.sdk.listEvents({client:t,path:i(e),query:{after_sequence:a,limit:100}});if(r.push(...o.data),!o.has_more||o.data.length===0)return r;a=o.next_after_sequence}},async hasEventsAfter(e,r){let{data:a}=await n.sdk.listEvents({client:t,path:i(e),query:{after_sequence:r,limit:1}});return a.data.length>0},async listBacklog(e){let r=[],a;for(;;){let{data:o}=await n.sdk.listQueuedBacklogInputs({client:t,path:i(e),query:{limit:100,cursor:a}});if(r.push(...o.data),!o.next_cursor||o.data.length===0)return r;a=o.next_cursor}},async cancelQueuedInput(e,r){await n.sdk.cancelQueuedBacklogInput({client:t,path:{...i(e),inputID:r}})},async postInput(e,r,a){await n.sdk.createAgentInput({client:t,path:i(e),body:{...r,delivery_mode:`queued`},headers:{"Idempotency-Key":a}})},stream(e,r,a,o){return(0,n.openAgentEventStream)({client:t,path:i(e),query:{after_sequence:r,stream_deltas:!0},signal:a,onConnectionStateChange:e=>{e.state===`connected`&&o()}})},async readyCustomCalls(e){let{data:r}=await n.sdk.listToolCalls({client:t,path:i(e),query:{state:`ready`,type:`custom`,include_subagents:!0,limit:100}});return r.data},async openInteractions(e){let{data:r}=await n.sdk.listAgentInteractions({client:t,path:i(e),query:{state:`open`,include_subagents:!0,limit:100}});return r.data},async submitResult(e,r,a,o){await n.sdk.submitToolCallResult({client:t,path:{...i(e),toolCallID:r},body:{outcome:a,content_blocks:o}})},async resolveInteraction(e,r,a,o){await n.sdk.resolveAgentInteraction({client:t,path:{...i(e),interactionID:r},body:{answers:a,actor:o}})},async cancel(e,r){await n.sdk.cancelAgent({client:t,path:i(e),body:{actor:r}})},async getActor(e){let{data:i}=await n.sdk.getActor({client:t,path:{...r,actorID:e}});return i}}}function l(e){let t=e.source?(0,a.parse)(e.source):{};return t&&typeof t==`object`?t:{}}function u(e){let t=e.tools??{};return Object.entries(t).filter(([,e])=>e?.type===`custom`).map(([e])=>e)}function d(e,t,n){return{type:`custom`,description:t?.trim()||e,input_schema:n??{type:`object`,properties:{}}}}function f(e){return Object.fromEntries(Object.entries(e).map(([e,t])=>{let n=t;return[e,{type:`custom`,description:n.description,input_schema:n.input_schema}]}))}function p(e){return JSON.stringify(e,(e,t)=>t&&typeof t==`object`&&!Array.isArray(t)?Object.fromEntries(Object.entries(t).sort(([e],[t])=>e.localeCompare(t))):t)}function m(e){return typeof e==`string`?e:e.map(e=>e.type===`text`?e.text??``:``).join(``)}const h=e=>e.replaceAll(`\0`,``);function g(e){if(e?.length)return{type:`text`,text:h(`Context from the app:\n${e.map(e=>`- ${e.description}: ${e.value}`).join(`
|
|
2
|
+
`)}`),metadata:{omnara_hidden:`true`}}}const _=e=>({type:`text`,text:e,metadata:{omnara_hidden:`true`}});function v(e,t){let n=[],r=!1,i=typeof e.content==`string`?[{type:`text`,text:e.content}]:e.content;for(let e of i)if(e.type===`text`){let t=h(e.text);t&&n.push({type:`text`,text:t})}else (e.type===`image`||e.type===`document`)&&e.source.type===`data`?(r=!0,n.push({type:`media`,media_type:e.source.mimeType,data:e.source.value})):n.push(_(`(The user attached a file (${e.type}) that could not be forwarded.)`));return t&&n.push(t),{blocks:n,media:r}}const y=1024*1024;function b(e){return e.reduce((e,t)=>e+(t.type===`media`?0:Buffer.byteLength(JSON.stringify(t).replace(/[<>&\u2028\u2029]/g,`\\u0000`))),0)}function x(e){return e.map(e=>e.type===`media`?_(`(The user attached a file that Omnara could not accept.)`):e)}const S={type:`object`,properties:{approved:{type:`boolean`},reason:{type:`string`}},required:[`approved`]},C={type:`object`,properties:{answers:{type:`array`,description:`One entry per question, in order.`,items:{type:`object`,properties:{optionIndices:{type:`array`,items:{type:`integer`}},text:{type:`string`}},required:[`optionIndices`]}}},required:[`answers`]},w=`The user dismissed this without answering.`;function T(e){let t=e.interaction_kind===`permission`;return{id:e.id,reason:t?`omnara:permission`:`omnara:question`,message:e.request.title,toolCallId:e.tool_call_id,responseSchema:t?S:C,metadata:{omnara:{kind:e.interaction_kind,agentId:e.agent_id,agentName:e.agent_name,toolName:e.tool_name,form:e.request}}}}function E(e,t){let n=t.payload??{};if(e.interaction_kind===`permission`){if(t.status===`resolved`&&n.approved===!0)return[{option_indices:[0]}];let e=t.status===`cancelled`?w:n.reason;return[{option_indices:[1],...e?{text:e}:{}}]}return e.request.questions.map((e,r)=>{if(t.status===`resolved`){let e=n.answers?.[r];return{option_indices:e?.optionIndices??[],...e?.text?{text:e.text}:{}}}let i=e.options.findIndex(e=>e.allows_text);return{option_indices:[i>=0?i:e.options.length-1],text:w}})}const D=`agui:`;function O(e){let t=`${D}${e}`;return t.length<=255&&/^[ -~]*$/.test(e)&&!e.endsWith(` `)?t:`${D}${(0,i.createHash)(`sha256`).update(e).digest(`hex`)}`}const k=(e,t)=>`${e}:block:${t}`,A=e=>e.metadata?.omnara_hidden===`true`;function j(e){return e.filter(e=>e.type===`text`&&!A(e)).map(e=>e.text??``).join(``)}const M=`[file]`;function N(e){return e.flatMap(e=>e.type===`text`?A(e)?[]:[e.text??``]:e.type===`media_ref`?[M]:[]).join(`
|
|
3
|
+
`)}function P(e){return e.map(e=>e.type===`text`?e.text??``:e.type===`structured_data`?JSON.stringify(e.value):e.type===`media_ref`?M:``).join(`
|
|
4
|
+
`)}function F(e,t){if(e.event_kind!==`agent_input`)return;let n=e.input_idempotency_key;if(n?.startsWith(D))return t?.get(n)??n.slice(5)}function I(e,t){let n=new Map(t.clientMessages.map(e=>[e.id,e])),r=new Map(t.clientMessages.map(e=>[O(e.id),e.id])),i=new Map(t.clientMessages.filter(e=>e.role===`tool`).map(e=>[e.toolCallId,e])),a=new Map,o=new Set;for(let t of e)if(t.event_kind===`model_output`)for(let e of t.content_blocks)e.type===`tool_call`&&a.set(e.tool_call_id,{name:e.name,type:e.tool_type});let s=e=>{let n=a.get(e);return n!==void 0&&t.isBrowserCall(n.name,n.type)};for(let t of e)t.event_kind===`tool_result`&&t.outcome===`canceled`&&s(t.tool_call_id)&&!i.has(t.tool_call_id)&&o.add(t.tool_call_id);let c=[];for(let a of e)if(a.event_kind===`agent_input`){if(a.input_kind!==`content`)continue;let e=F(a,r);if(e!==void 0){c.push(n.get(e)??{id:e,role:`user`,content:N(a.content_blocks)});continue}let i=N(a.content_blocks);if(!i)continue;let o=a.actor_id&&t.authors.get(a.actor_id)||{role:`user`};c.push({id:a.agent_input_id,role:o.role,content:i,...o.name?{name:o.name}:{}})}else if(a.event_kind===`model_output`){a.content_blocks.forEach((e,t)=>{e.type===`reasoning`&&e.text&&c.push({id:k(a.model_call_context_id,t),role:`reasoning`,content:e.text})});let e=j(a.content_blocks),t=a.content_blocks.flatMap(e=>e.type===`tool_call`&&!o.has(e.tool_call_id)?[{id:e.tool_call_id,type:`function`,function:{name:e.name,arguments:JSON.stringify(e.input??{})}}]:[]);if(!e&&t.length===0)continue;c.push({id:a.model_call_context_id,role:`assistant`,...e?{content:e}:{},...t.length?{toolCalls:t}:{}})}else if(a.event_kind===`tool_result`){let e=s(a.tool_call_id)?i.get(a.tool_call_id):void 0;e?c.push(e):o.has(a.tool_call_id)||c.push({id:a.id,role:`tool`,toolCallId:a.tool_call_id,content:P(a.content_blocks)})}let l=c.findIndex(e=>n.has(e.id)),u=l>=0?c.slice(l):n.size?[]:c,d=new Set(u.map(e=>e.id));for(let e of t.clientMessages)d.has(e.id)||(e.role===`user`||e.role===`tool`&&s(e.toolCallId))&&u.push(e);return u}const L={thread_ended:`This chat's Omnara agent was archived. Start a new chat to continue.`,invalid_tools:`Omnara rejected this chat's tools.`,message_too_large:`This message is too large for Omnara. Start a new chat to continue.`,run_failed:`The Omnara agent could not complete this request.`,model_error:`The model failed to respond.`};var R=class extends Error{constructor(e,t){super(L[e]),this.code=e,this.detail=t}},z=class{constructor(e,t,n){this.deps=e,this.input=t,this.emitEvent=n,this.stopped=!1,this.detached=!1,this.following=new AbortController,this.launchCustomTools=new Set,this.toolNames=new Map,this.selfKeys=new Set,this.copies=new Map,this.pendingKeys=new Set,this.submitted=!1,this.turnEnded=!0,this.cancelled=!1,this.lastSequence=0,this.handledCalls=new Set,this.checking=!1,this.checkAgain=!1,this.previews=new Map,this.authors=new Map}stop(){this.stopped=!0,this.following.abort()}detach(){this.detached=!0,this.following.abort()}async execute(){let{threadId:e,runId:t}=this.input;this.emit({type:r.EventType.RUN_STARTED,threadId:e,runId:t,protocolVersion:r.PROTOCOL_VERSION});let n;try{n=await this.drive()}catch(e){if(this.detached&&!this.stopped){await this.report(`run_after_disconnect`,e);return}let t=e instanceof R?e.code:`run_failed`;await this.report(t,e instanceof R?e.detail:e),n=this.stopped?await this.endStopped():{error:t}}this.detached||(this.closeOpen(),await this.sendSnapshot(),`error`in n?this.emit({type:r.EventType.RUN_ERROR,message:L[n.error],code:n.error}):n.outcome.type===`success`&&this.modelError!==void 0?(await this.report(`model_error`,Error(this.modelError)),this.emit({type:r.EventType.RUN_ERROR,message:L.model_error,code:`model_error`})):this.emit({type:r.EventType.RUN_FINISHED,threadId:e,runId:t,outcome:n.outcome}))}async drive(){let e=await this.findOrCreateAgent();if(this.stopped)return this.endStopped();let t=await this.deps.api.listEvents(e.id);await this.syncTools(e,t);for(let e of t)this.noteToolCalls(e),this.noteTurn(e);let n=this.newWork(t);await this.restoreOrder(t,n.messages);for(let e of n.messages)this.pendingKeys.add(O(e.id));let r=t.at(-1);this.lastSequence=r?.sequence??0;let i=this.follow(e.id,r?.sequence??0);try{if(await i.connected,this.stopped)return this.endStopped();await this.submit(e.id,n),this.submitted=!0,this.check(),await i.done}finally{this.following.abort(),await i.done.catch(()=>void 0)}if(this.stopped)return this.endStopped();if(this.failure)throw this.failure;if(this.detached)return{outcome:{type:`success`}};if(!this.settled)throw Error(`event stream ended before the agent settled`);return{outcome:this.settled}}async findOrCreateAgent(){let{api:e,config:t}=this.deps;if(!this.input.threadId.trim())throw Error(`threadId is required`);let n,a=`AG-UI ${this.input.threadId.replace(/[^\w.:-]/g,``)}`.slice(0,64).trimEnd();if(t.profile){let r=await e.getProfile(t.profile);n={config:r.current_config_id,profile:r.id,name:a}}else{let r=t.definition,i=typeof r.source==`string`,o=i?r.source:JSON.stringify(r.source);n={config:(await e.createConfig(o,r.format??(i?`yaml`:`json`))).id,name:a}}let o=t.user===`anonymous`?{id:`anonymous`}:t.user,s=(0,i.createHash)(`sha256`).update(JSON.stringify([o.tenant??``,o.id,this.deps.aguiAgentId,this.input.threadId])).digest(`hex`),{agent:c,created:l}=await e.launch(n,`agui-thread:${s}`);if(this.agentId=c.id,c.state===`archived`)throw new R(`thread_ended`,Error(`agent ${c.id} is archived`));return l&&this.emit({type:r.EventType.CUSTOM,name:`omnara.agent`,value:{agentId:c.id,threadId:this.input.threadId}}),c}actor(){let{user:e}=this.deps.config;if(e!==`anonymous`)return{provider_user_id:e.id,...e.tenant?{provider_tenant_id:e.tenant}:{},...e.name?{display_name:e.name}:{}}}async syncTools(e,t){let{api:n,backendTools:r}=this.deps,i=t.find(e=>e.event_kind===`agent_input`&&e.input_kind===`config_change`),a=e.current_config_id;if(!a)return;let s=l(await n.getConfig(a)),c=i?.agent_config_id&&i.agent_config_id!==a?l(await n.getConfig(i.agent_config_id)):s;this.launchCustomTools=new Set(u(c));let m=s.subagents??{};this.selfKeys=new Set(Object.keys(m).filter(e=>m[e]?.type===`self`));let h=new Set(Object.keys(c.tools??{})),g={};for(let e of[...this.input.tools??[],...r.values()])h.has(e.name)||(g[e.name]=d(e.name,e.description,e.parameters));let _={...s.tools??{}},v={};for(let e of u(s))this.launchCustomTools.has(e)||(v[e]=_[e],delete _[e]);if(p(f(v))===p(g))return;let y=JSON.stringify({...s,tools:{..._,...g}});try{await n.setConfig(e.id,y,`json`,a)}catch(e){let t=o(e);throw t===400||t===413?new R(`invalid_tools`,e):e}}isBrowserCall(e,t){return t===`custom`&&!this.launchCustomTools.has(e)&&!this.deps.backendTools.has(e)}noteToolCalls(e){if(e.event_kind===`model_output`)for(let t of e.content_blocks)t.type===`tool_call`&&this.toolNames.set(t.tool_call_id,{name:t.name,type:t.tool_type})}newWork(e){let t=new Set,n=new Set,r=new Set;for(let i of e)i.event_kind===`agent_input`?(t.add(i.agent_input_id),i.input_idempotency_key&&n.add(i.input_idempotency_key)):i.event_kind===`tool_result`&&r.add(i.tool_call_id);let i=this.input.messages,a=g(this.input.context);return{messages:i.filter(e=>e.role===`user`&&!t.has(e.id)&&!n.has(O(e.id))&&v(e,a).blocks.length>0),results:i.filter(e=>{if(e.role!==`tool`||r.has(e.toolCallId))return!1;let t=this.toolNames.get(e.toolCallId);return t!==void 0&&this.isBrowserCall(t.name,t.type)}),resume:this.input.resume??[]}}async submit(e,t){let{api:n}=this.deps,r=this.actor();for(let n of t.results)await this.postResult(e,n.toolCallId,n.error?`failed`:`succeeded`,m(n.content)||n.error||``);let i=t.resume.length?await n.openInteractions(e).then(e=>new Map(e.map(e=>[e.id,e])),async e=>{await this.report(`resolve`,e)}):void 0;if(i)for(let e of t.resume){let t=i.get(e.interruptId);if(!t){await this.report(`unknown_interrupt`,Error(`no open interaction ${e.interruptId}`));continue}await H(()=>n.resolveInteraction(t.agent_id,t.id,E(t,e),r)).catch(e=>this.report(`resolve`,e))}if(!t.messages.length)return;let a=new Set(t.results.map(e=>e.toolCallId));(await n.readyCustomCalls(e)).filter(t=>t.agent_id===e&&this.isBrowserCall(t.name,t.type)&&!a.has(t.id)).length&&await n.cancel(e,r);let c=g(this.input.context),l=(t,i)=>H(()=>n.postInput(e,{content_blocks:t,actor:r},i).catch(e=>{throw s(e)===`state_transition_conflict`?new R(`thread_ended`,e):e}));for(let e of t.messages){let t=O(e.id),{blocks:n,media:r}=v(e,c);if(b(n)>y)throw new R(`message_too_large`,Error(`message ${e.id} with its context is over 1 MiB`));try{await l(n,t)}catch(e){let i=o(e);if(!r||e instanceof R||i===void 0||i<400||i>=500)throw e;await this.report(`attachment_rejected`,e),await l(x(n),t)}}}follow(e,t){let n,r=new Promise(e=>n=e),i=this.deps.api.stream(e,t,this.following.signal,n),a=(async()=>{let e=setInterval(()=>void this.check(),5e3);try{for await(let e of B(i,this.following.signal))await this.onFrame(e)}finally{clearInterval(e)}})(),o=new Promise((e,t)=>setTimeout(()=>t(Error(`event stream did not connect`)),3e4).unref?.());return{connected:Promise.race([r,a,o]).then(()=>void 0),done:a}}async onFrame(e){if(`event_kind`in e)return this.onEvent(e);if(`model_call_context_id`in e&&`event`in e)return this.onDelta(e);`tool_call_id`in e&&`state`in e&&(e.state===`ready`||e.state===`awaiting_permission`)&&this.check()}async onEvent(e){if(this.noteToolCalls(e),this.noteTurn(e),this.lastSequence=Math.max(this.lastSequence,e.sequence),e.event_kind===`agent_input`)if(e.input_kind===`content`){let t=e.input_idempotency_key;t&&this.pendingKeys.delete(t)&&this.pendingKeys.size===0&&this.check(),F(e)===void 0&&await this.emitOtherInput(e)}else e.input_kind===`control`&&this.check();else if(e.event_kind===`model_output`)this.emitModelOutput(e),this.turnEnded&&this.check();else if(e.event_kind===`tool_result`){let t=this.toolNames.get(e.tool_call_id);(!t||!this.isBrowserCall(t.name,t.type))&&(this.closeOpen(),this.emit({type:r.EventType.TOOL_CALL_RESULT,messageId:e.id,toolCallId:e.tool_call_id,content:P(e.content_blocks),role:`tool`}))}}noteTurn(e){this.turnEnded=V(e,this.turnEnded),e.event_kind===`agent_input`?e.input_kind===`content`?(this.cancelled=!1,this.modelError=void 0):e.input_kind===`control`&&(this.cancelled=!0):e.event_kind===`model_output`&&(this.modelError=e.stop_reason===`error`?e.content_blocks.map(e=>e.type===`error`?e.text:``).join(`
|
|
5
|
+
`):void 0,this.cancelled=!1)}async check(){if(this.settled||!this.submitted||this.following.signal.aborted)return;if(this.checking){this.checkAgain=!0;return}this.checking=!0;let e=this.lastSequence;try{let t=this.agentId,n=await this.waitingOutcome(t);if(n===null)return;let r=n;if(!r&&this.pendingKeys.size&&this.turnEnded&&await this.dropCancelledInputs(t),!r&&this.pendingKeys.size===0&&this.turnEnded&&!await this.subagentsBusy(t)&&(r={type:this.cancelled?`cancelled`:`success`}),r&&!this.following.signal.aborted){if(this.lastSequence!==e){this.checkAgain=!0;return}this.settled=r,this.following.abort()}}catch(e){await this.report(`check`,e)}finally{this.checking=!1,this.checkAgain&&(this.checkAgain=!1,this.check())}}async waitingOutcome(e){let{api:t,backendTools:n}=this.deps,r=await t.openInteractions(e);if(r.length)return{type:`interrupt`,interrupts:r.map(T)};let i=await t.readyCustomCalls(e),a=new Set((this.input.tools??[]).map(e=>e.name)),o=[],s=[];for(let t of i){if(this.handledCalls.has(t.id))continue;let r=n.has(t.name),i=t.agent_id!==e&&a.has(t.name)&&this.isBrowserCall(t.name,t.type);!(r||i)||!await this.hasOurTools(t.agent_id)||(r?o:s).push(t)}if(o.length||s.length)return this.following.signal.aborted||await Promise.all([...o.map(e=>this.runBackendTool(e)),...s.map(e=>this.deliver(e,`failed`,`This tool runs in the user's browser; subagents can't use it.`))]),null;let c=i.filter(t=>t.agent_id===e&&this.isBrowserCall(t.name,t.type));if(c.length)return{type:`success`,pendingToolCallIds:c.map(e=>e.id)}}async hasOurTools(e){let t=[],n=e,r;try{for(;n!==this.agentId&&(r=this.copies.get(n))===void 0;){let e=await this.deps.api.getAgent(n);t.push(n);let i=e.subagent_key;if(!i||!this.selfKeys.has(i)||!e.parent_agent_id){r=!1;break}n=e.parent_agent_id}}catch(e){return await this.report(`get_agent`,e),!1}r??=!0;for(let e of t)this.copies.set(e,r);return r}async subagentsBusy(e){if(![...this.toolNames.values()].some(e=>e.name===`spawn_agent`))return!1;let{api:t}=this.deps;return(await t.listChildren(e)).some(e=>e.state!==`archived`&&(e.activity?.state===`running`||e.activity?.state===`waiting_on_interaction`))||(await t.listBacklog(e)).length?!0:t.hasEventsAfter(e,this.lastSequence)}async dropCancelledInputs(e){let{api:t}=this.deps,n=new Set((await t.listBacklog(e)).map(e=>e.input_idempotency_key));if(!await t.hasEventsAfter(e,this.lastSequence))for(let e of this.pendingKeys)n.has(e)||this.pendingKeys.delete(e)}async runBackendTool(e){this.handledCalls.add(e.id);let t=this.deps.backendTools.get(e.name),n=`succeeded`,r;try{let n=await t.handler(e.input,{toolCallId:e.id});r=typeof n==`string`?n:JSON.stringify(n??null)}catch(e){n=`failed`,r=e instanceof Error?e.message:String(e)}await this.deliver(e,n,r)}async deliver(e,t,n){this.handledCalls.add(e.id);try{await this.postResult(e.agent_id,e.id,t,n)}catch(e){this.failure=e,this.following.abort()}}async postResult(e,t,n,r){let i={type:`text`,text:h(r)};b([i])>y&&(await this.report(`result_too_large`,Error(`result for ${t} is over 1 MiB`)),n=`failed`,i={type:`text`,text:`The result was too large to deliver (over Omnara's 1 MiB limit).`}),await H(()=>this.deps.api.submitResult(e,t,n,[i]))}async endStopped(){return this.agentId&&(await this.cancelQueuedInputs(this.agentId),await this.cancelWork(this.agentId)),{outcome:{type:`cancelled`}}}async cancelQueuedInputs(e){if(!this.pendingKeys.size)return;let{api:t}=this.deps,n=await t.listBacklog(e).catch(async e=>(await this.report(`cancel_input`,e),[]));for(let r of n)this.pendingKeys.has(r.input_idempotency_key??``)&&await H(()=>t.cancelQueuedInput(e,r.id)).catch(e=>this.report(`cancel_input`,e))}async cancelWork(e){await this.cancelSubagents(e),await this.deps.api.cancel(e,this.actor()).catch(e=>this.report(`cancel`,e))}async cancelSubagents(e){let{api:t}=this.deps,n=await t.listChildren(e).catch(async e=>(await this.report(`cancel_subagent`,e),[]));for(let e of n)e.state!==`archived`&&(await this.cancelSubagents(e.id),e.activity?.state!==`idle`&&await t.cancel(e.id,this.actor()).catch(e=>this.report(`cancel_subagent`,e)))}emit(e){this.detached||this.emitEvent(e)}closeOpen(){this.openText&&=(this.emit({type:r.EventType.TEXT_MESSAGE_END,messageId:this.openText}),void 0),this.openReasoning&&=(this.emit({type:r.EventType.REASONING_MESSAGE_END,messageId:this.openReasoning}),this.emit({type:r.EventType.REASONING_END,messageId:this.openReasoning}),void 0)}openTextMessage(e){this.openText!==e&&(this.closeOpen(),this.emit({type:r.EventType.TEXT_MESSAGE_START,messageId:e,role:`assistant`}),this.openText=e)}openReasoningMessage(e){this.openReasoning!==e&&(this.closeOpen(),this.emit({type:r.EventType.REASONING_START,messageId:e}),this.emit({type:r.EventType.REASONING_MESSAGE_START,messageId:e,role:`reasoning`}),this.openReasoning=e,this.shownReasoning??=e)}onDelta(e){let t=e.model_call_context_id,n=this.previews.get(t);if(n||(n={text:``,reasoning:new Set,next:1,broken:e.seq!==1},this.previews.set(t,n)),n.broken)return;if(e.seq!==n.next){n.broken=!0,this.closeOpen();return}n.next=e.seq+1;let i=e.event;switch(i.kind){case`block_start`:i.block.kind===`text`&&this.openTextMessage(t);break;case`text_delta`:this.openText===t&&i.delta&&(n.text+=i.delta,this.emit({type:r.EventType.TEXT_MESSAGE_CONTENT,messageId:t,delta:i.delta}));break;case`thinking_delta`:{if(!i.delta)break;let e=k(t,i.block_index);n.reasoning.has(i.block_index)||(n.reasoning.add(i.block_index),this.openReasoningMessage(e)),this.openReasoning===e&&this.emit({type:r.EventType.REASONING_MESSAGE_CONTENT,messageId:e,delta:i.delta});break}case`block_stop`:(this.openText===t||this.openReasoning===k(t,i.block_index))&&this.closeOpen();break;case`error`:n.broken=!0,this.closeOpen();break}}emitModelOutput(e){let t=e.model_call_context_id,n=this.previews.get(t);this.closeOpen(),e.content_blocks.forEach((e,i)=>{if(e.type!==`reasoning`||!e.text||n?.reasoning.has(i))return;let a=k(t,i);this.openReasoningMessage(a),this.emit({type:r.EventType.REASONING_MESSAGE_CONTENT,messageId:a,delta:e.text}),this.closeOpen()});let i=j(e.content_blocks),a=n?.text??``;i.length>a.length&&i.startsWith(a)&&(this.openTextMessage(t),this.emit({type:r.EventType.TEXT_MESSAGE_CONTENT,messageId:t,delta:i.slice(a.length)}),this.closeOpen());for(let n of e.content_blocks)n.type===`tool_call`&&(this.emit({type:r.EventType.TOOL_CALL_START,toolCallId:n.tool_call_id,toolCallName:n.name,parentMessageId:t}),this.emit({type:r.EventType.TOOL_CALL_ARGS,toolCallId:n.tool_call_id,delta:JSON.stringify(n.input??{})}),this.emit({type:r.EventType.TOOL_CALL_END,toolCallId:n.tool_call_id}))}async emitOtherInput(e){let t=N(e.content_blocks);if(!t)return;let n=e.actor_id?await this.author(e.actor_id):{role:`user`};this.closeOpen(),this.emit({type:r.EventType.TEXT_MESSAGE_START,messageId:e.agent_input_id,role:n.role,...n.name?{name:n.name}:{}}),this.emit({type:r.EventType.TEXT_MESSAGE_CONTENT,messageId:e.agent_input_id,delta:t}),this.emit({type:r.EventType.TEXT_MESSAGE_END,messageId:e.agent_input_id})}author(e){let t=this.authors.get(e);return t||(t=this.deps.api.getActor(e).then(e=>e.provider===`omnara`&&e.provider_user_id.startsWith(`agt_`)?{role:`assistant`,name:e.display_name||`Subagent`}:{role:`user`,...e.display_name?{name:e.display_name}:{}},async e=>(await this.report(`actor`,e),{role:`user`})),this.authors.set(e,t)),t}async history(e,t){let n=new Map;for(let t of e)t.event_kind===`agent_input`&&t.input_kind===`content`&&t.actor_id&&F(t)===void 0&&n.set(t.actor_id,await this.author(t.actor_id));return I(e,{clientMessages:t,isBrowserCall:(e,t)=>this.isBrowserCall(e,t),authors:n})}async restoreOrder(e,t){let n=new Set(this.input.messages.map(e=>e.id)),i=new Set(t.map(e=>e.id)),a=await this.history(e,this.input.messages.filter(e=>!i.has(e.id)));!a[0]||!n.has(a[0].id)||a.every(e=>e.role===`reasoning`||n.has(e.id))||(this.emit({type:r.EventType.MESSAGES_SNAPSHOT,messages:a}),t.length&&this.emit({type:r.EventType.MESSAGES_SNAPSHOT,messages:[...a,...t]}))}async sendSnapshot(){if(this.agentId)try{let e=await this.deps.api.listEvents(this.agentId);for(let t of e)this.noteToolCalls(t);let t=await this.history(e,this.input.messages);if(!t.some(e=>e.role===`reasoning`)){let e=this.input.messages.find(e=>e.role===`reasoning`)?.id??this.shownReasoning;e!==void 0&&t.push({id:e,role:`reasoning`,content:``})}this.emit({type:r.EventType.MESSAGES_SNAPSHOT,messages:t})}catch(e){await this.report(`snapshot`,e)}}report(e,t){return this.deps.report(t,{operation:e,threadId:this.input.threadId,agentId:this.agentId})}};async function*B(e,t){let n=e[Symbol.asyncIterator](),r=new Promise(e=>{t.aborted&&e({done:!0,value:void 0}),t.addEventListener(`abort`,()=>e({done:!0,value:void 0}),{once:!0})});try{for(;;){let e=await Promise.race([n.next(),r]);if(e.done)return;yield e.value}}finally{n.return?.()?.catch(()=>void 0)}}function V(e,t){switch(e.event_kind){case`agent_input`:return e.input_kind===`content`?!1:e.input_kind===`control`?!0:t;case`model_output`:return e.stop_reason!==`max_tokens`&&!e.content_blocks.some(e=>e.type===`tool_call`);case`tool_result`:return e.outcome===`canceled`?t:!1;default:return t}}async function H(e){try{await e()}catch(e){if(o(e)!==409)throw e}}var U=class extends e.AbstractAgent{constructor(e,t){if(super(e),this.currentRun=null,this.agentId??=`omnara`,!!e.profile==!!e.definition)throw Error("OmnaraAgent: give exactly one of `profile` and `definition`");if(!e.user||e.user!==`anonymous`&&!e.user.id)throw Error('OmnaraAgent: `user` is required (an `{ id }` from your auth, or "anonymous")');if(this.config=e,this.backendTools=new Map((e.backendTools??[]).map(e=>[e.name,e])),t)this.api=t;else{let t=e.apiKey??process.env.OMNARA_API_KEY;if(!t)throw Error("OmnaraAgent: set `apiKey` or OMNARA_API_KEY");this.api=c({apiKey:t,orgId:e.orgId,projectId:e.projectId,baseUrl:e.baseUrl})}}clone(){let e=super.clone();return e.config=this.config,e.api=this.api,e.backendTools=this.backendTools,e.currentRun=null,e}abortRun(){this.currentRun?.stop()}run(e){return new t.Observable(t=>{let n=new z({api:this.api,config:this.config,aguiAgentId:this.agentId,backendTools:this.backendTools,report:(e,t)=>this.report(e,t)},e,e=>t.next(e));return this.currentRun=n,n.execute().catch(t=>this.report(t,{operation:`run`,threadId:e.threadId})).finally(()=>{this.currentRun===n&&(this.currentRun=null),t.complete()}),()=>n.detach()})}async report(e,t){try{this.config.onError?await this.config.onError(e,t):console.error(`[@ag-ui/omnara] ${t.operation}`,e)}catch{}}};exports.ERROR_MESSAGES=L,exports.OmnaraAgent=U;
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["ApiError","sdk","EventType","PROTOCOL_VERSION","AbstractAgent","Observable"],"sources":["../src/api.ts","../src/inputs.ts","../src/interrupts.ts","../src/messages.ts","../src/run.ts","../src/agent.ts"],"sourcesContent":["import {\n ApiError,\n bearerToken,\n createOmnaraClient,\n openAgentEventStream,\n sdk,\n type Actor,\n type Agent,\n type AgentConfig,\n type AgentEvent,\n type AgentEventStreamFrame,\n type AgentInput,\n type AgentInteraction,\n type CreateAgentInputContentBlock,\n type ExternalActorParams,\n type InteractionAnswer,\n type SubmitToolResultContentBlock,\n type ToolCall,\n} from \"@omnara/sdk\";\n\nexport type {\n Actor,\n Agent,\n AgentEvent,\n AgentEventStreamFrame,\n AgentInteraction,\n CreateAgentInputContentBlock,\n ExternalActorParams,\n InteractionAnswer,\n SubmitToolResultContentBlock,\n ToolCall,\n};\n\n/**\n * The Omnara calls the adapter makes. A narrow seam over `@omnara/sdk` so the\n * run logic can be tested against a fake.\n */\nexport interface OmnaraApi {\n createConfig(\n source: string,\n format: \"yaml\" | \"json\",\n ): Promise<{ id: string }>;\n getConfig(configId: string): Promise<AgentConfig>;\n getProfile(\n idOrName: string,\n ): Promise<{ id: string; current_config_id: string }>;\n /** `created` is false when the idempotency key replayed an existing agent. */\n launch(\n body: { config: string; profile?: string; name: string },\n idempotencyKey: string,\n ): Promise<{ agent: Agent; created: boolean }>;\n getAgent(agentId: string): Promise<Agent>;\n /** All of the agent's unarchived subagents. */\n listChildren(agentId: string): Promise<Agent[]>;\n setConfig(\n agentId: string,\n source: string,\n format: \"yaml\" | \"json\",\n expectedCurrentConfigId: string,\n ): Promise<void>;\n /** The whole log, oldest first. */\n listEvents(agentId: string): Promise<AgentEvent[]>;\n /** Whether the log has events after `sequence`. */\n hasEventsAfter(agentId: string, sequence: number): Promise<boolean>;\n /** All inputs stored but not yet started (queued messages, undelivered subagent reports). */\n listBacklog(\n agentId: string,\n ): Promise<Array<{ id: string; input_idempotency_key?: string }>>;\n /** Cancel an input still in the backlog (a 409 once it has started). */\n cancelQueuedInput(agentId: string, inputId: string): Promise<void>;\n postInput(\n agentId: string,\n body: {\n content_blocks: CreateAgentInputContentBlock[];\n actor?: ExternalActorParams;\n },\n idempotencyKey: string,\n ): Promise<void>;\n stream(\n agentId: string,\n afterSequence: number,\n signal: AbortSignal,\n onConnected: () => void,\n ): AsyncIterable<AgentEventStreamFrame>;\n /** Ready custom calls on the agent and its subagents. */\n readyCustomCalls(agentId: string): Promise<ToolCall[]>;\n /** Open interactions on the agent and its subagents. */\n openInteractions(agentId: string): Promise<AgentInteraction[]>;\n submitResult(\n agentId: string,\n toolCallId: string,\n outcome: \"succeeded\" | \"failed\",\n content: SubmitToolResultContentBlock[],\n ): Promise<void>;\n resolveInteraction(\n agentId: string,\n interactionId: string,\n answers: InteractionAnswer[],\n actor?: ExternalActorParams,\n ): Promise<void>;\n cancel(agentId: string, actor?: ExternalActorParams): Promise<void>;\n getActor(actorId: string): Promise<Actor>;\n}\n\n/** HTTP status of an Omnara API failure, if it was one. */\nexport function statusOf(error: unknown): number | undefined {\n if (error instanceof ApiError) return error.status;\n const status = (error as { status?: unknown } | null)?.status;\n return typeof status === \"number\" ? status : undefined;\n}\n\n/** Omnara's error code (e.g. `state_transition_conflict`), if it was an API failure. */\nexport function codeOf(error: unknown): string | undefined {\n if (error instanceof ApiError) return error.code;\n const code = (error as { code?: unknown } | null)?.code;\n return typeof code === \"string\" ? code : undefined;\n}\n\nconst CALL_TIMEOUT_MS = 30_000;\nconst PAGE_LIMIT = 100;\n\nexport function createOmnaraApi(options: {\n apiKey: string;\n orgId: string;\n projectId: string;\n baseUrl?: string;\n}): OmnaraApi {\n const client = createOmnaraClient({\n baseUrl: options.baseUrl,\n auth: bearerToken(options.apiKey),\n // Every call is bounded, except the event stream, which is meant to stay open.\n fetch: (input, init) => {\n const url = input instanceof Request ? input.url : String(input);\n if (url.includes(\"/events/stream\")) return fetch(input, init);\n const timeout = AbortSignal.timeout(CALL_TIMEOUT_MS);\n const signal = init?.signal\n ? AbortSignal.any([init.signal, timeout])\n : timeout;\n return fetch(input, { ...init, signal });\n },\n });\n const project = { orgID: options.orgId, projectID: options.projectId };\n const agent = (agentID: string) => ({ ...project, agentID });\n\n return {\n async createConfig(source, format) {\n const { data } = await sdk.createAgentConfig({\n client,\n path: project,\n body: { source, source_format: format },\n });\n return { id: data.id };\n },\n async getConfig(configId) {\n const { data } = await sdk.getAgentConfig({\n client,\n path: { ...project, agentConfigID: configId },\n });\n return data;\n },\n async getProfile(idOrName) {\n if (idOrName.startsWith(\"aprf_\")) {\n const { data } = await sdk.getAgentProfile({\n client,\n path: { ...project, agentProfileID: idOrName },\n });\n return data;\n }\n // The filter is a case-insensitive glob, but names are unique only as\n // written: escape the wildcards and pick the exact name.\n const { data } = await sdk.listAgentProfiles({\n client,\n path: project,\n query: { name: idOrName.replace(/[\\\\*?]/g, \"\\\\$&\"), limit: PAGE_LIMIT },\n });\n const found = data.data.find((p) => p.name === idOrName);\n if (!found) throw new Error(`Omnara profile \"${idOrName}\" not found`);\n return found;\n },\n async launch(body, idempotencyKey) {\n const { data, response } = await sdk.createAgent({\n client,\n path: project,\n body,\n headers: { \"Idempotency-Key\": idempotencyKey },\n });\n return { agent: data.agent, created: response.status === 201 };\n },\n async getAgent(agentId) {\n const { data } = await sdk.getAgent({ client, path: agent(agentId) });\n return data.agent;\n },\n async listChildren(agentId) {\n const children: Agent[] = [];\n let cursor: string | undefined;\n for (;;) {\n const { data } = await sdk.listAgents({\n client,\n path: project,\n query: { parent_agent_id: agentId, limit: PAGE_LIMIT, cursor },\n });\n children.push(...data.data);\n if (!data.next_cursor || data.data.length === 0) return children;\n cursor = data.next_cursor;\n }\n },\n async setConfig(agentId, source, format, expectedCurrentConfigId) {\n await sdk.updateAgentConfig({\n client,\n path: agent(agentId),\n body: {\n source,\n source_format: format,\n expected_current_config_id: expectedCurrentConfigId,\n },\n });\n },\n async listEvents(agentId) {\n const events: AgentEvent[] = [];\n let after = 0;\n for (;;) {\n const { data } = await sdk.listEvents({\n client,\n path: agent(agentId),\n query: { after_sequence: after, limit: PAGE_LIMIT },\n });\n events.push(...data.data);\n if (!data.has_more || data.data.length === 0) return events;\n after = data.next_after_sequence;\n }\n },\n async hasEventsAfter(agentId, sequence) {\n const { data } = await sdk.listEvents({\n client,\n path: agent(agentId),\n query: { after_sequence: sequence, limit: 1 },\n });\n return data.data.length > 0;\n },\n async listBacklog(agentId) {\n const inputs: AgentInput[] = [];\n let cursor: string | undefined;\n for (;;) {\n const { data } = await sdk.listQueuedBacklogInputs({\n client,\n path: agent(agentId),\n query: { limit: PAGE_LIMIT, cursor },\n });\n inputs.push(...data.data);\n if (!data.next_cursor || data.data.length === 0) return inputs;\n cursor = data.next_cursor;\n }\n },\n async cancelQueuedInput(agentId, inputId) {\n await sdk.cancelQueuedBacklogInput({\n client,\n path: { ...agent(agentId), inputID: inputId },\n });\n },\n async postInput(agentId, body, idempotencyKey) {\n await sdk.createAgentInput({\n client,\n path: agent(agentId),\n body: { ...body, delivery_mode: \"queued\" },\n headers: { \"Idempotency-Key\": idempotencyKey },\n });\n },\n stream(agentId, afterSequence, signal, onConnected) {\n return openAgentEventStream({\n client,\n path: agent(agentId),\n query: { after_sequence: afterSequence, stream_deltas: true },\n signal,\n onConnectionStateChange: (state) => {\n if (state.state === \"connected\") onConnected();\n },\n });\n },\n async readyCustomCalls(agentId) {\n const { data } = await sdk.listToolCalls({\n client,\n path: agent(agentId),\n query: {\n state: \"ready\",\n type: \"custom\",\n include_subagents: true,\n limit: PAGE_LIMIT,\n },\n });\n return data.data;\n },\n async openInteractions(agentId) {\n const { data } = await sdk.listAgentInteractions({\n client,\n path: agent(agentId),\n query: { state: \"open\", include_subagents: true, limit: PAGE_LIMIT },\n });\n return data.data;\n },\n async submitResult(agentId, toolCallId, outcome, content) {\n await sdk.submitToolCallResult({\n client,\n path: { ...agent(agentId), toolCallID: toolCallId },\n body: { outcome, content_blocks: content },\n });\n },\n async resolveInteraction(agentId, interactionId, answers, actor) {\n await sdk.resolveAgentInteraction({\n client,\n path: { ...agent(agentId), interactionID: interactionId },\n body: { answers, actor },\n });\n },\n async cancel(agentId, actor) {\n await sdk.cancelAgent({ client, path: agent(agentId), body: { actor } });\n },\n async getActor(actorId) {\n const { data } = await sdk.getActor({\n client,\n path: { ...project, actorID: actorId },\n });\n return data;\n },\n };\n}\n","import type { RunAgentInput, UserMessage } from \"@ag-ui/core\";\nimport { parse as parseYaml } from \"yaml\";\nimport type { CreateAgentInputContentBlock } from \"./api\";\n\n// What the adapter sends to Omnara besides API calls: the tool definitions in a\n// derived agent config, and a user message as Omnara content blocks.\n\nexport function parseSource(config: {\n source?: string;\n}): Record<string, unknown> {\n const parsed = config.source ? parseYaml(config.source) : {};\n return parsed && typeof parsed === \"object\"\n ? (parsed as Record<string, unknown>)\n : {};\n}\n\nexport function customToolNames(definition: Record<string, unknown>): string[] {\n const tools =\n (definition.tools as Record<string, { type?: string } | null>) ?? {};\n return Object.entries(tools)\n .filter(([, t]) => t?.type === \"custom\")\n .map(([name]) => name);\n}\n\nexport function customTool(\n name: string,\n description: string | undefined,\n parameters: unknown,\n) {\n return {\n type: \"custom\",\n // Omnara requires a description; a tool without one is described by its name.\n description: description?.trim() || name,\n input_schema: parameters ?? { type: \"object\", properties: {} },\n };\n}\n\nexport function pickToolShape(\n tools: Record<string, unknown>,\n): Record<string, unknown> {\n return Object.fromEntries(\n Object.entries(tools).map(([name, t]) => {\n const tool = t as { description?: string; input_schema?: unknown };\n return [\n name,\n {\n type: \"custom\",\n description: tool.description,\n input_schema: tool.input_schema,\n },\n ];\n }),\n );\n}\n\n/** JSON with sorted keys, for comparing tool definitions. */\nexport function canonical(value: unknown): string {\n return JSON.stringify(value, (_, v) =>\n v && typeof v === \"object\" && !Array.isArray(v)\n ? Object.fromEntries(\n Object.entries(v).sort(([a], [b]) => a.localeCompare(b)),\n )\n : v,\n );\n}\n\nexport function messageText(\n content: string | ReadonlyArray<{ type: string; text?: string }>,\n): string {\n return typeof content === \"string\"\n ? content\n : content.map((p) => (p.type === \"text\" ? (p.text ?? \"\") : \"\")).join(\"\");\n}\n\n/** Omnara stores no U+0000 in text. */\nexport const storable = (text: string): string => text.replaceAll(\"\\0\", \"\");\n\nexport function contextBlock(\n context: RunAgentInput[\"context\"],\n): CreateAgentInputContentBlock | undefined {\n if (!context?.length) return undefined;\n return {\n type: \"text\",\n text: storable(\n `Context from the app:\\n${context.map((c) => `- ${c.description}: ${c.value}`).join(\"\\n\")}`,\n ),\n metadata: { omnara_hidden: \"true\" },\n };\n}\n\nconst note = (text: string): CreateAgentInputContentBlock => ({\n type: \"text\",\n text,\n metadata: { omnara_hidden: \"true\" },\n});\n\n/** The message as Omnara content blocks; inline images and documents become media. */\nexport function userBlocks(\n message: UserMessage,\n context: CreateAgentInputContentBlock | undefined,\n): { blocks: CreateAgentInputContentBlock[]; media: boolean } {\n const blocks: CreateAgentInputContentBlock[] = [];\n let media = false;\n const parts =\n typeof message.content === \"string\"\n ? [{ type: \"text\" as const, text: message.content }]\n : message.content;\n for (const part of parts) {\n if (part.type === \"text\") {\n const text = storable(part.text);\n if (text) blocks.push({ type: \"text\", text });\n } else if (\n (part.type === \"image\" || part.type === \"document\") &&\n part.source.type === \"data\"\n ) {\n media = true;\n blocks.push({\n type: \"media\",\n media_type: part.source.mimeType as Extract<\n CreateAgentInputContentBlock,\n { type: \"media\" }\n >[\"media_type\"],\n data: part.source.value,\n });\n } else {\n blocks.push(\n note(\n `(The user attached a file (${part.type}) that could not be forwarded.)`,\n ),\n );\n }\n }\n if (context) blocks.push(context);\n return { blocks, media };\n}\n\n/** Omnara's limit on the content of one submission, inline media aside. */\nexport const MAX_CONTENT_BYTES = 1024 * 1024;\n\n/**\n * The size Omnara counts against `MAX_CONTENT_BYTES`: the blocks as Go's JSON\n * encodes them, which escapes `<`, `>`, `&`, U+2028 and U+2029 as `\\uXXXX`.\n */\nexport function contentBytes(blocks: ReadonlyArray<{ type: string }>): number {\n return blocks.reduce(\n (n, b) =>\n n +\n (b.type === \"media\"\n ? 0\n : Buffer.byteLength(\n JSON.stringify(b).replace(/[<>&\\u2028\\u2029]/g, \"\\\\u0000\"),\n )),\n 0,\n );\n}\n\nexport function withoutMedia(\n blocks: CreateAgentInputContentBlock[],\n): CreateAgentInputContentBlock[] {\n return blocks.map((b) =>\n b.type === \"media\"\n ? note(\"(The user attached a file that Omnara could not accept.)\")\n : b,\n );\n}\n","import type { Interrupt, ResumeEntry } from \"@ag-ui/core\";\nimport type { AgentInteraction, InteractionAnswer } from \"./api\";\n\n// Omnara's approvals and questions as AG-UI interrupts, and the resume payload\n// back to Omnara's answers.\n\nconst PERMISSION_SCHEMA = {\n type: \"object\",\n properties: { approved: { type: \"boolean\" }, reason: { type: \"string\" } },\n required: [\"approved\"],\n};\nconst QUESTION_SCHEMA = {\n type: \"object\",\n properties: {\n answers: {\n type: \"array\",\n description: \"One entry per question, in order.\",\n items: {\n type: \"object\",\n properties: {\n optionIndices: { type: \"array\", items: { type: \"integer\" } },\n text: { type: \"string\" },\n },\n required: [\"optionIndices\"],\n },\n },\n },\n required: [\"answers\"],\n};\nconst DISMISSED = \"The user dismissed this without answering.\";\n\nexport function toInterrupt(interaction: AgentInteraction): Interrupt {\n const permission = interaction.interaction_kind === \"permission\";\n return {\n id: interaction.id,\n reason: permission ? \"omnara:permission\" : \"omnara:question\",\n message: interaction.request.title,\n toolCallId: interaction.tool_call_id,\n responseSchema: permission ? PERMISSION_SCHEMA : QUESTION_SCHEMA,\n metadata: {\n omnara: {\n kind: interaction.interaction_kind,\n agentId: interaction.agent_id,\n agentName: interaction.agent_name,\n toolName: interaction.tool_name,\n form: interaction.request,\n },\n },\n };\n}\n\n/**\n * Resume payload to Omnara answers. A dismissed card still lets the agent\n * continue: a permission is denied, a question gets its \"Other\" option.\n */\nexport function answersFor(\n interaction: AgentInteraction,\n entry: ResumeEntry,\n): InteractionAnswer[] {\n const payload = (entry.payload ?? {}) as {\n approved?: boolean;\n reason?: string;\n answers?: Array<{ optionIndices?: number[]; text?: string }>;\n };\n if (interaction.interaction_kind === \"permission\") {\n if (entry.status === \"resolved\" && payload.approved === true)\n return [{ option_indices: [0] }];\n const reason = entry.status === \"cancelled\" ? DISMISSED : payload.reason;\n return [{ option_indices: [1], ...(reason ? { text: reason } : {}) }];\n }\n return interaction.request.questions.map((question, i) => {\n if (entry.status === \"resolved\") {\n const answer = payload.answers?.[i];\n return {\n option_indices: answer?.optionIndices ?? [],\n ...(answer?.text ? { text: answer.text } : {}),\n };\n }\n const other = question.options.findIndex((o) => o.allows_text);\n return {\n option_indices: [other >= 0 ? other : question.options.length - 1],\n text: DISMISSED,\n };\n });\n}\n","import type { Message, ToolMessage } from \"@ag-ui/core\";\nimport { createHash } from \"node:crypto\";\nimport type { AgentEvent } from \"./api\";\n\n/**\n * One mapping from Omnara's log to AG-UI messages, shared by live streaming and\n * the end-of-request snapshot, so the ids always match and the snapshot\n * replaces what was streamed instead of duplicating it.\n *\n * - assistant message: the model call id (`mcc_...`)\n * - reasoning message: `<model call id>:block:<index>`\n * - tool call: Omnara's tool-call id\n * - tool message: the tool result's event id\n * - user message: the client's id (behind its `agui:` input key), or\n * Omnara's input id for messages from anyone else (see `Author`)\n */\n\nexport const INPUT_KEY_PREFIX = \"agui:\";\n\n/**\n * A client message's Omnara idempotency key. An id a header can't carry as is\n * (non-ASCII, a trailing space, too long) is hashed; `clientIdOf` maps it back\n * through the client's messages.\n */\nexport function inputKey(messageId: string): string {\n const key = `${INPUT_KEY_PREFIX}${messageId}`;\n return key.length <= 255 &&\n /^[ -~]*$/.test(messageId) &&\n !messageId.endsWith(\" \")\n ? key\n : `${INPUT_KEY_PREFIX}${createHash(\"sha256\").update(messageId).digest(\"hex\")}`;\n}\n\nexport const reasoningId = (modelCallId: string, index: number) =>\n `${modelCallId}:block:${index}`;\n\ntype Blocks = ReadonlyArray<{\n type: string;\n text?: string;\n metadata?: Record<string, unknown>;\n}>;\n\nconst hidden = (block: { metadata?: Record<string, unknown> }) =>\n block.metadata?.omnara_hidden === \"true\";\n\n/** The visible text of a set of content blocks. */\nexport function visibleText(blocks: Blocks): string {\n return blocks\n .filter((b) => b.type === \"text\" && !hidden(b))\n .map((b) => b.text ?? \"\")\n .join(\"\");\n}\n\n/**\n * Where a file was. Omnara files (artifacts) can only be downloaded with the\n * API key, so the chat can't show them; it gets a marker in their place.\n */\nconst FILE_MARKER = \"[file]\";\n\n/** A message's visible text, with a marker for each attached file. */\nexport function inputText(\n blocks: ReadonlyArray<{\n type: string;\n text?: string;\n metadata?: Record<string, unknown>;\n }>,\n): string {\n return blocks\n .flatMap((b) => {\n if (b.type === \"text\") return hidden(b) ? [] : [b.text ?? \"\"];\n return b.type === \"media_ref\" ? [FILE_MARKER] : [];\n })\n .join(\"\\n\");\n}\n\n/** A tool result as text: text as is, structured data as JSON, a marker for each file. */\nexport function toolResultText(\n blocks: ReadonlyArray<{\n type: string;\n text?: string;\n value?: unknown;\n artifact_id?: string;\n }>,\n): string {\n return blocks\n .map((b) => {\n if (b.type === \"text\") return b.text ?? \"\";\n if (b.type === \"structured_data\") return JSON.stringify(b.value);\n if (b.type === \"media_ref\") return FILE_MARKER;\n return \"\";\n })\n .join(\"\\n\");\n}\n\n/**\n * The client message id behind an input key, if the input came from this\n * adapter. `byKey` maps the keys of the client's messages to their ids.\n */\nexport function clientIdOf(\n event: AgentEvent,\n byKey?: ReadonlyMap<string, string>,\n): string | undefined {\n if (event.event_kind !== \"agent_input\") return undefined;\n const key = event.input_idempotency_key;\n if (!key?.startsWith(INPUT_KEY_PREFIX)) return undefined;\n return byKey?.get(key) ?? key.slice(INPUT_KEY_PREFIX.length);\n}\n\n/**\n * Who wrote an input that did not come from this adapter, in AG-UI's terms: a\n * subagent's report is the agent's side (as LangGraph and ADK show subagent\n * output by default), anyone else is a user. `name` is AG-UI's sender name.\n */\nexport type Author = { role: \"user\" | \"assistant\"; name?: string };\n\ninterface SnapshotContext {\n /** The client's messages to keep (usually what it sent this request). */\n clientMessages: Message[];\n /** Browser-tool calls: their results come only from the client. */\n isBrowserCall: (name: string, type: string) => boolean;\n /** Author of each other-writer input, by actor id. */\n authors: ReadonlyMap<string, Author>;\n}\n\n/**\n * The messages to restate at the end of a request: Omnara's log from the\n * oldest message the chat holds onward. The user's own messages and\n * browser-tool results are the client's copies; the agent's messages come\n * from the log, which drops partial replies left by failed previews.\n */\nexport function snapshotMessages(\n events: AgentEvent[],\n ctx: SnapshotContext,\n): Message[] {\n const held = new Map(ctx.clientMessages.map((m) => [m.id, m]));\n const byKey = new Map(ctx.clientMessages.map((m) => [inputKey(m.id), m.id]));\n const clientResults = new Map(\n ctx.clientMessages\n .filter((m): m is ToolMessage => m.role === \"tool\")\n .map((m) => [m.toolCallId, m]),\n );\n\n const calls = new Map<string, { name: string; type: string }>();\n const cancelledBrowserCalls = new Set<string>();\n for (const e of events) {\n if (e.event_kind === \"model_output\") {\n for (const b of e.content_blocks) {\n if (b.type === \"tool_call\")\n calls.set(b.tool_call_id, { name: b.name, type: b.tool_type });\n }\n }\n }\n const isBrowserCall = (id: string) => {\n const call = calls.get(id);\n return call !== undefined && ctx.isBrowserCall(call.name, call.type);\n };\n for (const e of events) {\n if (\n e.event_kind === \"tool_result\" &&\n e.outcome === \"canceled\" &&\n isBrowserCall(e.tool_call_id) &&\n !clientResults.has(e.tool_call_id)\n ) {\n cancelledBrowserCalls.add(e.tool_call_id);\n }\n }\n\n const out: Message[] = [];\n for (const e of events) {\n if (e.event_kind === \"agent_input\") {\n if (e.input_kind !== \"content\") continue;\n const clientId = clientIdOf(e, byKey);\n if (clientId !== undefined) {\n out.push(\n held.get(clientId) ?? {\n id: clientId,\n role: \"user\",\n content: inputText(e.content_blocks),\n },\n );\n continue;\n }\n const text = inputText(e.content_blocks);\n if (!text) continue;\n const author = (e.actor_id && ctx.authors.get(e.actor_id)) || {\n role: \"user\" as const,\n };\n out.push({\n id: e.agent_input_id,\n role: author.role,\n content: text,\n ...(author.name ? { name: author.name } : {}),\n });\n } else if (e.event_kind === \"model_output\") {\n e.content_blocks.forEach((b, i) => {\n if (b.type === \"reasoning\" && b.text) {\n out.push({\n id: reasoningId(e.model_call_context_id, i),\n role: \"reasoning\",\n content: b.text,\n });\n }\n });\n const text = visibleText(e.content_blocks);\n const toolCalls = e.content_blocks.flatMap((b) =>\n b.type === \"tool_call\" && !cancelledBrowserCalls.has(b.tool_call_id)\n ? [\n {\n id: b.tool_call_id,\n type: \"function\" as const,\n function: {\n name: b.name,\n arguments: JSON.stringify(b.input ?? {}),\n },\n },\n ]\n : [],\n );\n if (!text && toolCalls.length === 0) continue;\n out.push({\n id: e.model_call_context_id,\n role: \"assistant\",\n ...(text ? { content: text } : {}),\n ...(toolCalls.length ? { toolCalls } : {}),\n });\n } else if (e.event_kind === \"tool_result\") {\n // The page's copy of its own (browser) results; the log's for the rest.\n const own = isBrowserCall(e.tool_call_id)\n ? clientResults.get(e.tool_call_id)\n : undefined;\n if (own) out.push(own);\n else if (!cancelledBrowserCalls.has(e.tool_call_id)) {\n out.push({\n id: e.id,\n role: \"tool\",\n toolCallId: e.tool_call_id,\n content: toolResultText(e.content_blocks),\n });\n }\n }\n }\n\n // Start at the oldest message the chat holds: history it lacks (after a\n // server restart, say) would land below the new message, so it stays out.\n // An empty chat gets all of it.\n const anchor = out.findIndex((m) => held.has(m.id));\n const kept = anchor >= 0 ? out.slice(anchor) : held.size ? [] : out;\n\n // The page's own messages the log doesn't have yet stay where they are: a\n // message not delivered yet, a browser tool's result. Anything else the log\n // doesn't have (a preview from a failed model call, say) goes.\n const ids = new Set(kept.map((m) => m.id));\n for (const m of ctx.clientMessages) {\n if (ids.has(m.id)) continue;\n if (m.role === \"user\" || (m.role === \"tool\" && isBrowserCall(m.toolCallId)))\n kept.push(m);\n }\n return kept;\n}\n","import {\n EventType,\n PROTOCOL_VERSION,\n type AGUIEvent,\n type BaseEvent,\n type Message,\n type ResumeEntry,\n type RunAgentInput,\n type RunFinishedOutcome,\n type ToolMessage,\n type UserMessage,\n} from \"@ag-ui/core\";\nimport { createHash } from \"node:crypto\";\nimport {\n codeOf,\n statusOf,\n type Agent,\n type AgentEvent,\n type AgentEventStreamFrame,\n type CreateAgentInputContentBlock,\n type ExternalActorParams,\n type OmnaraApi,\n type ToolCall,\n} from \"./api\";\nimport {\n MAX_CONTENT_BYTES,\n canonical,\n contentBytes,\n contextBlock,\n customTool,\n customToolNames,\n messageText,\n parseSource,\n pickToolShape,\n storable,\n userBlocks,\n withoutMedia,\n} from \"./inputs\";\nimport { answersFor, toInterrupt } from \"./interrupts\";\nimport {\n clientIdOf,\n inputKey,\n inputText,\n reasoningId,\n snapshotMessages,\n toolResultText,\n visibleText,\n type Author,\n} from \"./messages\";\nimport type {\n BackendTool,\n OmnaraAgentConfig,\n OmnaraErrorContext,\n} from \"./types\";\n\n/** Stable `RUN_ERROR` codes. Upstream error text never reaches the client; it goes to `onError`. */\nexport const ERROR_MESSAGES = {\n thread_ended:\n \"This chat's Omnara agent was archived. Start a new chat to continue.\",\n invalid_tools: \"Omnara rejected this chat's tools.\",\n message_too_large:\n \"This message is too large for Omnara. Start a new chat to continue.\",\n run_failed: \"The Omnara agent could not complete this request.\",\n model_error: \"The model failed to respond.\",\n} as const;\nexport type OmnaraErrorCode = keyof typeof ERROR_MESSAGES;\n\nclass RunError extends Error {\n constructor(\n readonly code: OmnaraErrorCode,\n readonly detail: unknown,\n ) {\n super(ERROR_MESSAGES[code]);\n }\n}\n\nconst CONNECT_TIMEOUT_MS = 30_000;\nconst CHECK_INTERVAL_MS = 5_000;\n\nconst SUBAGENT_BROWSER_TOOL =\n \"This tool runs in the user's browser; subagents can't use it.\";\nconst RESULT_TOO_LARGE =\n \"The result was too large to deliver (over Omnara's 1 MiB limit).\";\n\ninterface RunDeps {\n api: OmnaraApi;\n config: OmnaraAgentConfig;\n /** The AG-UI agent's id (CopilotKit's registered name). */\n aguiAgentId: string;\n backendTools: ReadonlyMap<string, BackendTool>;\n report: (error: unknown, context: OmnaraErrorContext) => Promise<void>;\n}\n\ntype Ending = { outcome: RunFinishedOutcome } | { error: OmnaraErrorCode };\ntype Preview = {\n text: string;\n reasoning: Set<number>;\n next: number;\n broken: boolean;\n};\ntype Work = {\n messages: UserMessage[];\n results: ToolMessage[];\n resume: ResumeEntry[];\n};\n\n/** One AG-UI request against one Omnara agent. */\nexport class OmnaraRun {\n private agentId?: string;\n private stopped = false;\n private detached = false;\n private readonly following = new AbortController();\n\n // What the tools look like: which custom tools are the page's (browser) tools.\n private launchCustomTools = new Set<string>();\n private readonly toolNames = new Map<\n string,\n { name: string; type: string }\n >();\n /** The agent's `type: self` subagent keys; its `self` copies share them. */\n private selfKeys = new Set<string>();\n /** Whether each subagent asked about has the agent's tools. */\n private readonly copies = new Map<string, boolean>();\n\n // Following.\n private readonly pendingKeys = new Set<string>();\n private submitted = false;\n /** A new agent has no turn under way. */\n private turnEnded = true;\n /** The agent's latest turn was cancelled (someone pressed Stop elsewhere). */\n private cancelled = false;\n private lastSequence = 0;\n private modelError?: string;\n private readonly handledCalls = new Set<string>();\n private settled?: RunFinishedOutcome;\n /** A result Omnara didn't accept while following: ends the run with an error. */\n private failure?: unknown;\n private checking = false;\n private checkAgain = false;\n\n // Streaming.\n private openText?: string;\n private openReasoning?: string;\n private readonly previews = new Map<string, Preview>();\n /** The first reasoning message this run showed. */\n private shownReasoning?: string;\n private readonly authors = new Map<string, Promise<Author>>();\n\n constructor(\n private readonly deps: RunDeps,\n private readonly input: RunAgentInput,\n private readonly emitEvent: (event: BaseEvent) => void,\n ) {}\n\n /** Stop button: cancel the agent's current work and its running subagents, then end as cancelled. */\n stop(): void {\n this.stopped = true;\n this.following.abort();\n }\n\n /** The client went away: stop emitting, leave the agent running. */\n detach(): void {\n this.detached = true;\n this.following.abort();\n }\n\n async execute(): Promise<void> {\n const { threadId, runId } = this.input;\n this.emit({\n type: EventType.RUN_STARTED,\n threadId,\n runId,\n protocolVersion: PROTOCOL_VERSION,\n });\n let ending: Ending;\n try {\n ending = await this.drive();\n } catch (error) {\n if (this.detached && !this.stopped) {\n await this.report(\"run_after_disconnect\", error);\n return;\n }\n const code = error instanceof RunError ? error.code : \"run_failed\";\n await this.report(code, error instanceof RunError ? error.detail : error);\n // Stop still cancels what was sent, however the request failed.\n ending = this.stopped ? await this.endStopped() : { error: code };\n }\n if (this.detached) return;\n this.closeOpen();\n await this.sendSnapshot();\n if (\"error\" in ending) {\n this.emit({\n type: EventType.RUN_ERROR,\n message: ERROR_MESSAGES[ending.error],\n code: ending.error,\n });\n } else if (\n ending.outcome.type === \"success\" &&\n this.modelError !== undefined\n ) {\n await this.report(\"model_error\", new Error(this.modelError));\n this.emit({\n type: EventType.RUN_ERROR,\n message: ERROR_MESSAGES.model_error,\n code: \"model_error\",\n });\n } else {\n this.emit({\n type: EventType.RUN_FINISHED,\n threadId,\n runId,\n outcome: ending.outcome,\n });\n }\n }\n\n private async drive(): Promise<Ending> {\n const agent = await this.findOrCreateAgent();\n if (this.stopped) return this.endStopped();\n const log = await this.deps.api.listEvents(agent.id);\n await this.syncTools(agent, log);\n // By the same rules as while following.\n for (const e of log) {\n this.noteToolCalls(e);\n this.noteTurn(e);\n }\n // With nothing new to send (a reconnect), the run still follows the\n // agent's current work to its end.\n const work = this.newWork(log);\n\n await this.restoreOrder(log, work.messages);\n\n // Registered before the stream opens: a message already queued in Omnara\n // can start while earlier answers are submitted.\n for (const m of work.messages) this.pendingKeys.add(inputKey(m.id));\n const last = log.at(-1);\n this.lastSequence = last?.sequence ?? 0;\n const followed = this.follow(agent.id, last?.sequence ?? 0);\n try {\n await followed.connected;\n if (this.stopped) return this.endStopped();\n await this.submit(agent.id, work);\n this.submitted = true;\n void this.check();\n await followed.done;\n } finally {\n // However the run ends, nothing streams after it.\n this.following.abort();\n await followed.done.catch(() => undefined);\n }\n\n if (this.stopped) return this.endStopped();\n if (this.failure) throw this.failure;\n // The client left: nothing more is sent, and the agent carries on in Omnara.\n if (this.detached) return { outcome: { type: \"success\" } };\n if (!this.settled)\n throw new Error(\"event stream ended before the agent settled\");\n return { outcome: this.settled };\n }\n\n // ---------------------------------------------------------------- agent\n\n private async findOrCreateAgent(): Promise<Agent> {\n const { api, config } = this.deps;\n if (!this.input.threadId.trim()) throw new Error(\"threadId is required\");\n let launch: { config: string; profile?: string; name: string };\n // Omnara agent names: at most 64 characters, no edge or invisible spaces.\n const name = `AG-UI ${this.input.threadId.replace(/[^\\w.:-]/g, \"\")}`\n .slice(0, 64)\n .trimEnd();\n if (config.profile) {\n const profile = await api.getProfile(config.profile);\n launch = { config: profile.current_config_id, profile: profile.id, name };\n } else {\n const def = config.definition!;\n const isText = typeof def.source === \"string\";\n const source = isText\n ? (def.source as string)\n : JSON.stringify(def.source);\n const created = await api.createConfig(\n source,\n def.format ?? (isText ? \"yaml\" : \"json\"),\n );\n launch = { config: created.id, name };\n }\n // A thread has one Omnara agent per AG-UI agent and user: the launch key\n // replays the agent the thread started with, so a changed profile or\n // definition only reaches new threads.\n const user =\n config.user === \"anonymous\" ? { id: \"anonymous\" } : config.user;\n const key = createHash(\"sha256\")\n .update(\n JSON.stringify([\n user.tenant ?? \"\",\n user.id,\n this.deps.aguiAgentId,\n this.input.threadId,\n ]),\n )\n .digest(\"hex\");\n const { agent, created } = await api.launch(launch, `agui-thread:${key}`);\n this.agentId = agent.id;\n if (agent.state === \"archived\")\n throw new RunError(\n \"thread_ended\",\n new Error(`agent ${agent.id} is archived`),\n );\n if (created) {\n this.emit({\n type: EventType.CUSTOM,\n name: \"omnara.agent\",\n value: { agentId: agent.id, threadId: this.input.threadId },\n });\n }\n return agent;\n }\n\n private actor(): ExternalActorParams | undefined {\n const { user } = this.deps.config;\n if (user === \"anonymous\") return undefined;\n return {\n provider_user_id: user.id,\n ...(user.tenant ? { provider_tenant_id: user.tenant } : {}),\n ...(user.name ? { display_name: user.name } : {}),\n };\n }\n\n // ---------------------------------------------------------------- tools\n\n /**\n * Make the agent's custom tools match this request: the custom tools that\n * were not in its launch config are the adapter's, and get replaced by this\n * request's browser tools plus `backendTools`. Profiles are never written.\n */\n private async syncTools(agent: Agent, log: AgentEvent[]): Promise<void> {\n const { api, backendTools } = this.deps;\n const launchId = log.find(\n (e) => e.event_kind === \"agent_input\" && e.input_kind === \"config_change\",\n ) as { agent_config_id?: string } | undefined;\n const currentId = agent.current_config_id;\n if (!currentId) return;\n const current = parseSource(await api.getConfig(currentId));\n const launch =\n launchId?.agent_config_id && launchId.agent_config_id !== currentId\n ? parseSource(await api.getConfig(launchId.agent_config_id))\n : current;\n this.launchCustomTools = new Set(customToolNames(launch));\n // Our writes keep `subagents`: this is the map every subagent was spawned under.\n const subagents =\n (current.subagents as Record<string, { type?: unknown }> | null) ?? {};\n this.selfKeys = new Set(\n Object.keys(subagents).filter((k) => subagents[k]?.type === \"self\"),\n );\n\n // A tool the agent's own definition declares (built in, or custom with its\n // permission, say) is left as the definition has it.\n const declared = new Set(\n Object.keys((launch.tools as Record<string, unknown> | null) ?? {}),\n );\n const wanted: Record<string, unknown> = {};\n for (const t of [...(this.input.tools ?? []), ...backendTools.values()]) {\n if (!declared.has(t.name)) {\n wanted[t.name] = customTool(t.name, t.description, t.parameters);\n }\n }\n\n const tools = { ...((current.tools as Record<string, unknown>) ?? {}) };\n const owned: Record<string, unknown> = {};\n for (const name of customToolNames(current)) {\n if (!this.launchCustomTools.has(name)) {\n owned[name] = tools[name];\n delete tools[name];\n }\n }\n if (canonical(pickToolShape(owned)) === canonical(wanted)) return;\n\n const source = JSON.stringify({\n ...current,\n tools: { ...tools, ...wanted },\n });\n try {\n await api.setConfig(agent.id, source, \"json\", currentId);\n } catch (error) {\n // Omnara rejects an invalid or oversized config; other failures aren't the tools'.\n const status = statusOf(error);\n if (status === 400 || status === 413)\n throw new RunError(\"invalid_tools\", error);\n throw error;\n }\n }\n\n private isBrowserCall(name: string, type: string): boolean {\n return (\n type === \"custom\" &&\n !this.launchCustomTools.has(name) &&\n !this.deps.backendTools.has(name)\n );\n }\n\n private noteToolCalls(event: AgentEvent): void {\n if (event.event_kind !== \"model_output\") return;\n for (const b of event.content_blocks) {\n if (b.type === \"tool_call\")\n this.toolNames.set(b.tool_call_id, { name: b.name, type: b.tool_type });\n }\n }\n\n // ---------------------------------------------------------------- submit\n\n private newWork(log: AgentEvent[]): Work {\n // Omnara's input ids (messages from others the chat holds) and our input keys.\n const known = new Set<string>();\n const keys = new Set<string>();\n const answered = new Set<string>();\n for (const e of log) {\n if (e.event_kind === \"agent_input\") {\n known.add(e.agent_input_id);\n if (e.input_idempotency_key) keys.add(e.input_idempotency_key);\n } else if (e.event_kind === \"tool_result\") {\n answered.add(e.tool_call_id);\n }\n }\n const all = this.input.messages;\n const context = contextBlock(this.input.context);\n return {\n // A message of the user's that the agent doesn't have yet. Omnara\n // takes no empty input: an empty message with no app context is skipped.\n messages: all.filter(\n (m): m is UserMessage =>\n m.role === \"user\" &&\n !known.has(m.id) &&\n !keys.has(inputKey(m.id)) &&\n userBlocks(m, context).blocks.length > 0,\n ),\n // The page answers only its own (browser) tools.\n results: all.filter((m): m is ToolMessage => {\n if (m.role !== \"tool\" || answered.has(m.toolCallId)) return false;\n const call = this.toolNames.get(m.toolCallId);\n return call !== undefined && this.isBrowserCall(call.name, call.type);\n }),\n resume: this.input.resume ?? [],\n };\n }\n\n /** Browser-tool results, then answers, then messages. A 409 means it's already there. */\n private async submit(agentId: string, work: Work): Promise<void> {\n const { api } = this.deps;\n const actor = this.actor();\n\n for (const result of work.results) {\n await this.postResult(\n agentId,\n result.toolCallId,\n result.error ? \"failed\" : \"succeeded\",\n messageText(result.content) || result.error || \"\",\n );\n }\n\n // If answering fails, the check after submitting sees the card still open\n // and ends with it again (CopilotKit hides a card when a run fails).\n const open = work.resume.length\n ? await api.openInteractions(agentId).then(\n (all) => new Map(all.map((i) => [i.id, i])),\n async (error) => {\n await this.report(\"resolve\", error);\n return undefined;\n },\n )\n : undefined;\n if (open) {\n for (const entry of work.resume) {\n const interaction = open.get(entry.interruptId);\n if (!interaction) {\n // Answered or cancelled elsewhere, or not ours: proceed (the snapshot shows what happened).\n await this.report(\n \"unknown_interrupt\",\n new Error(`no open interaction ${entry.interruptId}`),\n );\n continue;\n }\n await accept409(() =>\n api.resolveInteraction(\n interaction.agent_id,\n interaction.id,\n answersFor(interaction, entry),\n actor,\n ),\n ).catch((error) => this.report(\"resolve\", error));\n }\n }\n\n if (!work.messages.length) return;\n // A browser tool call the page never answered blocks the agent for good:\n // cancel that turn (Omnara's own cancel), then deliver the message.\n const answered = new Set(work.results.map((r) => r.toolCallId));\n const abandoned = (await api.readyCustomCalls(agentId)).filter(\n (c) =>\n c.agent_id === agentId &&\n this.isBrowserCall(c.name, c.type) &&\n !answered.has(c.id),\n );\n if (abandoned.length) await api.cancel(agentId, actor);\n\n const context = contextBlock(this.input.context);\n // A 409 means the message is already there, unless the agent was archived.\n const post = (blocks: CreateAgentInputContentBlock[], key: string) =>\n accept409(() =>\n api\n .postInput(agentId, { content_blocks: blocks, actor }, key)\n .catch((error) => {\n if (codeOf(error) === \"state_transition_conflict\") {\n throw new RunError(\"thread_ended\", error);\n }\n throw error;\n }),\n );\n for (const message of work.messages) {\n const key = inputKey(message.id);\n const { blocks, media } = userBlocks(message, context);\n // Over Omnara's limit: the run says so rather than cut or replace it.\n if (contentBytes(blocks) > MAX_CONTENT_BYTES) {\n throw new RunError(\n \"message_too_large\",\n new Error(`message ${message.id} with its context is over 1 MiB`),\n );\n }\n try {\n await post(blocks, key);\n } catch (error) {\n const status = statusOf(error);\n if (\n !media ||\n error instanceof RunError ||\n status === undefined ||\n status < 400 ||\n status >= 500\n )\n throw error;\n // Omnara rejected an attachment: send the message without it.\n await this.report(\"attachment_rejected\", error);\n await post(withoutMedia(blocks), key);\n }\n }\n }\n\n // ---------------------------------------------------------------- follow\n\n private follow(agentId: string, afterSequence: number) {\n let onConnected!: () => void;\n const connected = new Promise<void>((resolve) => (onConnected = resolve));\n const frames = this.deps.api.stream(\n agentId,\n afterSequence,\n this.following.signal,\n onConnected,\n );\n const done = (async () => {\n const timer = setInterval(() => void this.check(), CHECK_INTERVAL_MS);\n try {\n for await (const frame of untilAborted(frames, this.following.signal)) {\n await this.onFrame(frame);\n }\n } finally {\n clearInterval(timer);\n }\n })();\n const timeout = new Promise<never>((_, reject) =>\n setTimeout(\n () => reject(new Error(\"event stream did not connect\")),\n CONNECT_TIMEOUT_MS,\n ).unref?.(),\n );\n return {\n connected: Promise.race([connected, done, timeout]).then(() => undefined),\n done,\n };\n }\n\n private async onFrame(frame: AgentEventStreamFrame): Promise<void> {\n if (\"event_kind\" in frame) return this.onEvent(frame as AgentEvent);\n if (\"model_call_context_id\" in frame && \"event\" in frame)\n return this.onDelta(frame);\n if (\"tool_call_id\" in frame && \"state\" in frame) {\n if (frame.state === \"ready\" || frame.state === \"awaiting_permission\")\n void this.check();\n }\n }\n\n private async onEvent(event: AgentEvent): Promise<void> {\n this.noteToolCalls(event);\n this.noteTurn(event);\n this.lastSequence = Math.max(this.lastSequence, event.sequence);\n if (event.event_kind === \"agent_input\") {\n if (event.input_kind === \"content\") {\n const key = event.input_idempotency_key;\n if (key && this.pendingKeys.delete(key) && this.pendingKeys.size === 0)\n void this.check();\n if (clientIdOf(event) === undefined) await this.emitOtherInput(event);\n } else if (event.input_kind === \"control\") {\n void this.check();\n }\n } else if (event.event_kind === \"model_output\") {\n this.emitModelOutput(event);\n if (this.turnEnded) void this.check();\n } else if (event.event_kind === \"tool_result\") {\n const call = this.toolNames.get(event.tool_call_id);\n // Browser-tool results are the client's own; the producer must not answer them.\n if (!call || !this.isBrowserCall(call.name, call.type)) {\n this.closeOpen();\n this.emit({\n type: EventType.TOOL_CALL_RESULT,\n messageId: event.id,\n toolCallId: event.tool_call_id,\n content: toolResultText(event.content_blocks),\n role: \"tool\",\n });\n }\n }\n }\n\n /** What an event says about the agent's turn: over, failed, cancelled. A message starts a new one. */\n private noteTurn(event: AgentEvent): void {\n this.turnEnded = turnOver(event, this.turnEnded);\n if (event.event_kind === \"agent_input\") {\n if (event.input_kind === \"content\") {\n this.cancelled = false;\n this.modelError = undefined;\n } else if (event.input_kind === \"control\") {\n this.cancelled = true;\n }\n } else if (event.event_kind === \"model_output\") {\n this.modelError =\n event.stop_reason === \"error\"\n ? event.content_blocks\n .map((b) => (b.type === \"error\" ? b.text : \"\"))\n .join(\"\\n\")\n : undefined;\n this.cancelled = false;\n }\n }\n\n /** Finished, or waiting on the user, the page or a host-run tool? Ends the follow when settled. */\n private async check(): Promise<void> {\n if (this.settled || !this.submitted) return;\n if (this.following.signal.aborted) return;\n if (this.checking) {\n // Something happened mid-check: look again once this one is done.\n this.checkAgain = true;\n return;\n }\n this.checking = true;\n const seen = this.lastSequence;\n try {\n const agentId = this.agentId!;\n const waiting = await this.waitingOutcome(agentId);\n if (waiting === null) return; // ran host tools; keep following\n let outcome = waiting;\n if (!outcome && this.pendingKeys.size && this.turnEnded)\n await this.dropCancelledInputs(agentId);\n // Finished only once our messages have started (a queued message runs\n // after whatever is ahead of it) and nothing is still on its way.\n if (\n !outcome &&\n this.pendingKeys.size === 0 &&\n this.turnEnded &&\n !(await this.subagentsBusy(agentId))\n ) {\n outcome = { type: this.cancelled ? \"cancelled\" : \"success\" };\n }\n if (outcome && !this.following.signal.aborted) {\n // An event arrived while checking (a subagent's report, say): what was\n // read may be stale, so look again instead of settling.\n if (this.lastSequence !== seen) {\n this.checkAgain = true;\n return;\n }\n this.settled = outcome;\n this.following.abort();\n }\n } catch (error) {\n await this.report(\"check\", error);\n } finally {\n this.checking = false;\n if (this.checkAgain) {\n this.checkAgain = false;\n void this.check();\n }\n }\n }\n\n /**\n * The outcome for what the agent waits on: an approval or question, or a\n * browser tool. Ready `backendTools` calls are run, a subagent's call to a\n * page tool gets a failed result, and `null` is returned (the agent will\n * continue).\n */\n private async waitingOutcome(\n agentId: string,\n ): Promise<RunFinishedOutcome | undefined | null> {\n const { api, backendTools } = this.deps;\n const interactions = await api.openInteractions(agentId);\n if (interactions.length) {\n return { type: \"interrupt\", interrupts: interactions.map(toInterrupt) };\n }\n const ready = await api.readyCustomCalls(agentId);\n const pageTools = new Set((this.input.tools ?? []).map((t) => t.name));\n const hostCalls: ToolCall[] = [];\n const subagentBrowserCalls: ToolCall[] = [];\n for (const c of ready) {\n if (this.handledCalls.has(c.id)) continue;\n const host = backendTools.has(c.name);\n // `type: self` subagents inherit the page's tools but can't reach the page.\n const page =\n c.agent_id !== agentId &&\n pageTools.has(c.name) &&\n this.isBrowserCall(c.name, c.type);\n // A tool of the same name on a subagent launched from a profile (even\n // this agent's) is that profile's own, left to its worker.\n if (!(host || page) || !(await this.hasOurTools(c.agent_id))) continue;\n (host ? hostCalls : subagentBrowserCalls).push(c);\n }\n if (hostCalls.length || subagentBrowserCalls.length) {\n // Stopped (or the client left) while this looked: nothing starts now.\n if (this.following.signal.aborted) return null;\n await Promise.all([\n ...hostCalls.map((c) => this.runBackendTool(c)),\n ...subagentBrowserCalls.map((c) =>\n this.deliver(c, \"failed\", SUBAGENT_BROWSER_TOOL),\n ),\n ]);\n return null;\n }\n const pending = ready.filter(\n (c) => c.agent_id === agentId && this.isBrowserCall(c.name, c.type),\n );\n if (pending.length)\n return { type: \"success\", pendingToolCallIds: pending.map((c) => c.id) };\n return undefined;\n }\n\n /**\n * Whether an agent has this agent's tools (the page's and `backendTools`):\n * the agent itself, or a subagent spawned under a `type: self` key at every\n * step up to it, each a copy of its parent's config. A subagent launched\n * from a profile, even this agent's, has that profile's tools. False while\n * Omnara can't say; the next check asks again.\n */\n private async hasOurTools(agentId: string): Promise<boolean> {\n const chain: string[] = [];\n let id = agentId;\n let copy: boolean | undefined;\n try {\n while (\n id !== this.agentId &&\n (copy = this.copies.get(id)) === undefined\n ) {\n const subagent = await this.deps.api.getAgent(id);\n chain.push(id);\n const key = subagent.subagent_key;\n if (!key || !this.selfKeys.has(key) || !subagent.parent_agent_id) {\n copy = false;\n break;\n }\n id = subagent.parent_agent_id;\n }\n } catch (error) {\n await this.report(\"get_agent\", error);\n return false;\n }\n copy ??= true;\n for (const c of chain) this.copies.set(c, copy);\n return copy;\n }\n\n /**\n * Whether subagents are still working for this conversation. Omnara stores a\n * subagent's report in the parent's backlog in the same transaction as its\n * final output, then moves it into the log; reading in this order (running\n * subagents, then the backlog, then the log) can't miss a report in transit.\n * A stopped subagent sends no report and is simply not running.\n */\n private async subagentsBusy(agentId: string): Promise<boolean> {\n if (![...this.toolNames.values()].some((t) => t.name === \"spawn_agent\")) {\n return false;\n }\n const { api } = this.deps;\n const children = await api.listChildren(agentId);\n const working = (c: (typeof children)[number]) =>\n c.state !== \"archived\" &&\n (c.activity?.state === \"running\" ||\n c.activity?.state === \"waiting_on_interaction\");\n if (children.some(working)) return true;\n if ((await api.listBacklog(agentId)).length) return true;\n return api.hasEventsAfter(agentId, this.lastSequence);\n }\n\n /** A message of ours that's neither queued nor in the log was cancelled (from Omnara's dashboard, say). */\n private async dropCancelledInputs(agentId: string): Promise<void> {\n const { api } = this.deps;\n // Leaving the queue and entering the log are one step: read the queue first.\n const queued = new Set(\n (await api.listBacklog(agentId)).map((i) => i.input_idempotency_key),\n );\n if (await api.hasEventsAfter(agentId, this.lastSequence)) return;\n for (const key of this.pendingKeys) {\n if (!queued.has(key)) this.pendingKeys.delete(key);\n }\n }\n\n private async runBackendTool(call: ToolCall): Promise<void> {\n this.handledCalls.add(call.id);\n const tool = this.deps.backendTools.get(call.name)!;\n let outcome: \"succeeded\" | \"failed\" = \"succeeded\";\n let text: string;\n try {\n const value = await tool.handler(call.input, { toolCallId: call.id });\n text = typeof value === \"string\" ? value : JSON.stringify(value ?? null);\n } catch (error) {\n // The handler's own message: the host's code, and what the agent needs to recover.\n outcome = \"failed\";\n text = error instanceof Error ? error.message : String(error);\n }\n await this.deliver(call, outcome, text);\n }\n\n /** Post a result for a call this run answers. If Omnara doesn't take it, the run fails. */\n private async deliver(\n call: ToolCall,\n outcome: \"succeeded\" | \"failed\",\n text: string,\n ): Promise<void> {\n this.handledCalls.add(call.id);\n try {\n await this.postResult(call.agent_id, call.id, outcome, text);\n } catch (error) {\n this.failure = error;\n this.following.abort();\n }\n }\n\n /** A tool result over Omnara's size limit goes as a failed result saying so. A 409 means it's already there. */\n private async postResult(\n agentId: string,\n toolCallId: string,\n outcome: \"succeeded\" | \"failed\",\n text: string,\n ): Promise<void> {\n let block = { type: \"text\" as const, text: storable(text) };\n if (contentBytes([block]) > MAX_CONTENT_BYTES) {\n await this.report(\n \"result_too_large\",\n new Error(`result for ${toolCallId} is over 1 MiB`),\n );\n outcome = \"failed\";\n block = { type: \"text\", text: RESULT_TOO_LARGE };\n }\n await accept409(() =>\n this.deps.api.submitResult(agentId, toolCallId, outcome, [block]),\n );\n }\n\n /** Stop: cancel this request's queued messages and the agent's work (once it's known), and end as cancelled. */\n private async endStopped(): Promise<Ending> {\n if (this.agentId) {\n await this.cancelQueuedInputs(this.agentId);\n await this.cancelWork(this.agentId);\n }\n return { outcome: { type: \"cancelled\" } };\n }\n\n /**\n * Omnara's cancel leaves queued inputs waiting, so a message of ours still\n * queued would start after Stop. They go first: one that starts in the\n * meantime is the current turn, which the agent's cancel then stops.\n */\n private async cancelQueuedInputs(agentId: string): Promise<void> {\n if (!this.pendingKeys.size) return;\n const { api } = this.deps;\n const queued = await api.listBacklog(agentId).catch(async (e) => {\n await this.report(\"cancel_input\", e);\n return [];\n });\n for (const input of queued) {\n if (!this.pendingKeys.has(input.input_idempotency_key ?? \"\")) continue;\n await accept409(() => api.cancelQueuedInput(agentId, input.id)).catch(\n (e) => this.report(\"cancel_input\", e),\n );\n }\n }\n\n /** Cancel the agent's running subagents, nested ones first, then the agent (Omnara's default cancel). */\n private async cancelWork(agentId: string): Promise<void> {\n await this.cancelSubagents(agentId);\n await this.deps.api\n .cancel(agentId, this.actor())\n .catch((e) => this.report(\"cancel\", e));\n }\n\n /** Omnara's cancel doesn't reach subagents, and an idle one can have working subagents of its own. */\n private async cancelSubagents(agentId: string): Promise<void> {\n const { api } = this.deps;\n // No `spawn_agent` check (unlike `subagentsBusy`): Stop can land before the log is read.\n const children = await api.listChildren(agentId).catch(async (e) => {\n await this.report(\"cancel_subagent\", e);\n return [];\n });\n for (const child of children) {\n if (child.state === \"archived\") continue;\n await this.cancelSubagents(child.id);\n if (child.activity?.state !== \"idle\") {\n await api\n .cancel(child.id, this.actor())\n .catch((e) => this.report(\"cancel_subagent\", e));\n }\n }\n }\n\n // ---------------------------------------------------------------- emit\n\n private emit(event: AGUIEvent): void {\n if (!this.detached) this.emitEvent(event);\n }\n\n private closeOpen(): void {\n if (this.openText) {\n this.emit({ type: EventType.TEXT_MESSAGE_END, messageId: this.openText });\n this.openText = undefined;\n }\n if (this.openReasoning) {\n this.emit({\n type: EventType.REASONING_MESSAGE_END,\n messageId: this.openReasoning,\n });\n this.emit({\n type: EventType.REASONING_END,\n messageId: this.openReasoning,\n });\n this.openReasoning = undefined;\n }\n }\n\n private openTextMessage(id: string): void {\n if (this.openText === id) return;\n this.closeOpen();\n this.emit({\n type: EventType.TEXT_MESSAGE_START,\n messageId: id,\n role: \"assistant\",\n });\n this.openText = id;\n }\n\n private openReasoningMessage(id: string): void {\n if (this.openReasoning === id) return;\n this.closeOpen();\n this.emit({ type: EventType.REASONING_START, messageId: id });\n this.emit({\n type: EventType.REASONING_MESSAGE_START,\n messageId: id,\n role: \"reasoning\",\n });\n this.openReasoning = id;\n this.shownReasoning ??= id;\n }\n\n /** Live previews. Only a model call seen from its first delta is previewed; a gap stops it. */\n private onDelta(\n frame: Extract<\n AgentEventStreamFrame,\n { model_call_context_id: string; event: unknown }\n >,\n ): void {\n const mcc = frame.model_call_context_id;\n let preview = this.previews.get(mcc);\n if (!preview) {\n preview = {\n text: \"\",\n reasoning: new Set(),\n next: 1,\n broken: frame.seq !== 1,\n };\n this.previews.set(mcc, preview);\n }\n if (preview.broken) return;\n if (frame.seq !== preview.next) {\n preview.broken = true;\n this.closeOpen();\n return;\n }\n preview.next = frame.seq + 1;\n const delta = frame.event;\n switch (delta.kind) {\n case \"block_start\":\n if (delta.block.kind === \"text\") this.openTextMessage(mcc);\n break;\n case \"text_delta\":\n if (this.openText === mcc && delta.delta) {\n preview.text += delta.delta;\n this.emit({\n type: EventType.TEXT_MESSAGE_CONTENT,\n messageId: mcc,\n delta: delta.delta,\n });\n }\n break;\n case \"thinking_delta\": {\n if (!delta.delta) break;\n const id = reasoningId(mcc, delta.block_index);\n // Opened on its first text: OpenAI reasoning streams blocks with none.\n if (!preview.reasoning.has(delta.block_index)) {\n preview.reasoning.add(delta.block_index);\n this.openReasoningMessage(id);\n }\n if (this.openReasoning === id) {\n this.emit({\n type: EventType.REASONING_MESSAGE_CONTENT,\n messageId: id,\n delta: delta.delta,\n });\n }\n break;\n }\n case \"block_stop\":\n if (\n this.openText === mcc ||\n this.openReasoning === reasoningId(mcc, delta.block_index)\n ) {\n this.closeOpen();\n }\n break;\n case \"error\":\n preview.broken = true;\n this.closeOpen();\n break;\n }\n }\n\n /** The recorded output completes what was previewed; tool calls come only from here. */\n private emitModelOutput(\n event: Extract<AgentEvent, { event_kind: \"model_output\" }>,\n ): void {\n const mcc = event.model_call_context_id;\n const preview = this.previews.get(mcc);\n this.closeOpen();\n event.content_blocks.forEach((b, i) => {\n if (b.type !== \"reasoning\" || !b.text || preview?.reasoning.has(i))\n return;\n const id = reasoningId(mcc, i);\n this.openReasoningMessage(id);\n this.emit({\n type: EventType.REASONING_MESSAGE_CONTENT,\n messageId: id,\n delta: b.text,\n });\n this.closeOpen();\n });\n const text = visibleText(event.content_blocks);\n const shown = preview?.text ?? \"\";\n if (text.length > shown.length && text.startsWith(shown)) {\n this.openTextMessage(mcc);\n this.emit({\n type: EventType.TEXT_MESSAGE_CONTENT,\n messageId: mcc,\n delta: text.slice(shown.length),\n });\n this.closeOpen();\n }\n for (const b of event.content_blocks) {\n if (b.type !== \"tool_call\") continue;\n this.emit({\n type: EventType.TOOL_CALL_START,\n toolCallId: b.tool_call_id,\n toolCallName: b.name,\n parentMessageId: mcc,\n });\n this.emit({\n type: EventType.TOOL_CALL_ARGS,\n toolCallId: b.tool_call_id,\n delta: JSON.stringify(b.input ?? {}),\n });\n this.emit({ type: EventType.TOOL_CALL_END, toolCallId: b.tool_call_id });\n }\n }\n\n /** A message from someone else (a subagent report, a dashboard or API user), in place. */\n private async emitOtherInput(\n event: Extract<AgentEvent, { event_kind: \"agent_input\" }>,\n ): Promise<void> {\n const text = inputText(event.content_blocks);\n if (!text) return;\n const author = event.actor_id\n ? await this.author(event.actor_id)\n : { role: \"user\" as const };\n this.closeOpen();\n this.emit({\n type: EventType.TEXT_MESSAGE_START,\n messageId: event.agent_input_id,\n role: author.role,\n ...(author.name ? { name: author.name } : {}),\n });\n this.emit({\n type: EventType.TEXT_MESSAGE_CONTENT,\n messageId: event.agent_input_id,\n delta: text,\n });\n this.emit({\n type: EventType.TEXT_MESSAGE_END,\n messageId: event.agent_input_id,\n });\n }\n\n /**\n * A subagent is an Omnara actor whose user id is an agent id; people in\n * Omnara's dashboard, API keys and schedules are Omnara actors too.\n */\n private author(actorId: string): Promise<Author> {\n let found = this.authors.get(actorId);\n if (!found) {\n found = this.deps.api.getActor(actorId).then(\n (a): Author =>\n a.provider === \"omnara\" && a.provider_user_id.startsWith(\"agt_\")\n ? { role: \"assistant\", name: a.display_name || \"Subagent\" }\n : {\n role: \"user\",\n ...(a.display_name ? { name: a.display_name } : {}),\n },\n async (error) => {\n await this.report(\"actor\", error);\n return { role: \"user\" as const };\n },\n );\n this.authors.set(actorId, found);\n }\n return found;\n }\n\n /** The chat's history from Omnara's log, keeping `clientMessages` (see `snapshotMessages`). */\n private async history(\n events: AgentEvent[],\n clientMessages: Message[],\n ): Promise<Message[]> {\n const authors = new Map<string, Author>();\n for (const e of events) {\n if (\n e.event_kind === \"agent_input\" &&\n e.input_kind === \"content\" &&\n e.actor_id &&\n clientIdOf(e) === undefined\n ) {\n authors.set(e.actor_id, await this.author(e.actor_id));\n }\n }\n return snapshotMessages(events, {\n clientMessages,\n isBrowserCall: (name, type) => this.isBrowserCall(name, type),\n authors,\n });\n }\n\n /**\n * Put what the chat missed while idle (someone else's message, the agent's\n * reply to it) above this request's new messages, where it happened. The\n * client keeps the messages it holds in place and adds new ones at the end,\n * so the history goes out without the new messages, then with them.\n */\n private async restoreOrder(\n log: AgentEvent[],\n fresh: UserMessage[],\n ): Promise<void> {\n const held = new Set(this.input.messages.map((m) => m.id));\n const freshIds = new Set(fresh.map((m) => m.id));\n const history = await this.history(\n log,\n this.input.messages.filter((m) => !freshIds.has(m.id)),\n );\n // Nothing to place it after (a server restart), or nothing missed.\n // Reasoning doesn't count: not every client sends it back.\n if (!history[0] || !held.has(history[0].id)) return;\n if (history.every((m) => m.role === \"reasoning\" || held.has(m.id))) return;\n this.emit({ type: EventType.MESSAGES_SNAPSHOT, messages: history });\n if (fresh.length) {\n this.emit({\n type: EventType.MESSAGES_SNAPSHOT,\n messages: [...history, ...fresh],\n });\n }\n }\n\n private async sendSnapshot(): Promise<void> {\n if (!this.agentId) return;\n try {\n const events = await this.deps.api.listEvents(this.agentId);\n for (const e of events) this.noteToolCalls(e);\n const messages = await this.history(events, this.input.messages);\n // A snapshot without reasoning leaves the client's reasoning in place\n // (AG-UI's rule), so reasoning from an attempt Omnara didn't keep (a\n // failed first try, a canceled call), shown now or held from an earlier\n // request, would stay. Carrying one of those ids, emptied, makes the\n // snapshot the record: the client blanks that one and drops the rest.\n if (!messages.some((m) => m.role === \"reasoning\")) {\n const stale =\n this.input.messages.find((m) => m.role === \"reasoning\")?.id ??\n this.shownReasoning;\n if (stale !== undefined)\n messages.push({ id: stale, role: \"reasoning\", content: \"\" });\n }\n this.emit({ type: EventType.MESSAGES_SNAPSHOT, messages });\n } catch (error) {\n await this.report(\"snapshot\", error);\n }\n }\n\n private report(operation: string, error: unknown): Promise<void> {\n return this.deps.report(error, {\n operation,\n threadId: this.input.threadId,\n agentId: this.agentId,\n });\n }\n}\n\n// ------------------------------------------------------------------ helpers\n\n/**\n * Stop iterating as soon as `signal` aborts. `@omnara/sdk`'s stream can miss\n * an abort after a garbage collection and keep reading until its next\n * heartbeat (up to 10s); this keeps a settled run from waiting on it.\n */\nasync function* untilAborted<T>(\n source: AsyncIterable<T>,\n signal: AbortSignal,\n): AsyncGenerator<T> {\n const iterator = source[Symbol.asyncIterator]();\n const aborted = new Promise<IteratorResult<T>>((resolve) => {\n if (signal.aborted) resolve({ done: true, value: undefined });\n signal.addEventListener(\n \"abort\",\n () => resolve({ done: true, value: undefined }),\n { once: true },\n );\n });\n try {\n for (;;) {\n const next = await Promise.race([iterator.next(), aborted]);\n if (next.done) return;\n yield next.value;\n }\n } finally {\n void iterator.return?.()?.catch(() => undefined);\n }\n}\n\n/**\n * Whether the agent's turn is over after `event`, given whether it was before:\n * a message starts one; a final output or a cancel ends it; a tool result\n * continues it. Anything else (a config change, say) changes nothing.\n */\nfunction turnOver(event: AgentEvent, over: boolean): boolean {\n switch (event.event_kind) {\n case \"agent_input\":\n if (event.input_kind === \"content\") return false;\n return event.input_kind === \"control\" ? true : over;\n case \"model_output\":\n return (\n event.stop_reason !== \"max_tokens\" &&\n !event.content_blocks.some((b) => b.type === \"tool_call\")\n );\n case \"tool_result\":\n return event.outcome === \"canceled\" ? over : false;\n default:\n return over;\n }\n}\n\nasync function accept409(call: () => Promise<unknown>): Promise<void> {\n try {\n await call();\n } catch (error) {\n if (statusOf(error) !== 409) throw error;\n }\n}\n","import { AbstractAgent } from \"@ag-ui/client\";\nimport type { BaseEvent, RunAgentInput } from \"@ag-ui/core\";\nimport { Observable } from \"rxjs\";\nimport { createOmnaraApi, type OmnaraApi } from \"./api\";\nimport { OmnaraRun } from \"./run\";\nimport type {\n BackendTool,\n OmnaraAgentConfig,\n OmnaraErrorContext,\n} from \"./types\";\n\n/**\n * An AG-UI agent backed by an Omnara agent. Each AG-UI thread gets its own\n * Omnara agent (per user), launched from a profile or an inline definition.\n * Omnara's log is the truth; each run restates the chat from it.\n */\nexport class OmnaraAgent extends AbstractAgent {\n private config: OmnaraAgentConfig;\n private api: OmnaraApi;\n private backendTools: Map<string, BackendTool>;\n private currentRun: OmnaraRun | null = null;\n\n /** `api` replaces the Omnara client (tests). */\n constructor(config: OmnaraAgentConfig, api?: OmnaraApi) {\n super(config);\n // Part of each thread's launch key. `AbstractAgent` would otherwise give\n // every instance a random one; CopilotKit sets its registered name.\n this.agentId ??= \"omnara\";\n if (Boolean(config.profile) === Boolean(config.definition)) {\n throw new Error(\n \"OmnaraAgent: give exactly one of `profile` and `definition`\",\n );\n }\n if (!config.user || (config.user !== \"anonymous\" && !config.user.id)) {\n throw new Error(\n 'OmnaraAgent: `user` is required (an `{ id }` from your auth, or \"anonymous\")',\n );\n }\n this.config = config;\n this.backendTools = new Map(\n (config.backendTools ?? []).map((t) => [t.name, t]),\n );\n if (api) {\n this.api = api;\n } else {\n const apiKey = config.apiKey ?? process.env.OMNARA_API_KEY;\n if (!apiKey)\n throw new Error(\"OmnaraAgent: set `apiKey` or OMNARA_API_KEY\");\n this.api = createOmnaraApi({\n apiKey,\n orgId: config.orgId,\n projectId: config.projectId,\n baseUrl: config.baseUrl,\n });\n }\n }\n\n /** `super.clone()` keeps the AbstractAgent state; the Omnara client is shared. */\n public clone(): OmnaraAgent {\n const cloned = super.clone() as OmnaraAgent;\n cloned.config = this.config;\n cloned.api = this.api;\n cloned.backendTools = this.backendTools;\n cloned.currentRun = null;\n return cloned;\n }\n\n /** Stop: cancels the agent's current work and its running subagents, and ends the run as cancelled. */\n public abortRun(): void {\n this.currentRun?.stop();\n }\n\n run(input: RunAgentInput): Observable<BaseEvent> {\n return new Observable<BaseEvent>((subscriber) => {\n const run = new OmnaraRun(\n {\n api: this.api,\n config: this.config,\n aguiAgentId: this.agentId!,\n backendTools: this.backendTools,\n report: (error, context) => this.report(error, context),\n },\n input,\n (event) => subscriber.next(event),\n );\n this.currentRun = run;\n run\n .execute()\n .catch((error) =>\n this.report(error, { operation: \"run\", threadId: input.threadId }),\n )\n .finally(() => {\n if (this.currentRun === run) this.currentRun = null;\n subscriber.complete();\n });\n // Unsubscribing (a closed tab) never cancels the Omnara agent.\n return () => run.detach();\n });\n }\n\n private async report(\n error: unknown,\n context: OmnaraErrorContext,\n ): Promise<void> {\n try {\n if (this.config.onError) await this.config.onError(error, context);\n else console.error(`[@ag-ui/omnara] ${context.operation}`, error);\n } catch {\n // A broken hook must not break the run.\n }\n }\n}\n"],"mappings":"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"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import{AbstractAgent as e}from"@ag-ui/client";import{Observable as t}from"rxjs";import{ApiError as n,bearerToken as r,createOmnaraClient as i,openAgentEventStream as a,sdk as o}from"@omnara/sdk";import{EventType as s,PROTOCOL_VERSION as c}from"@ag-ui/core";import{createHash as l}from"node:crypto";import{parse as u}from"yaml";function d(e){if(e instanceof n)return e.status;let t=e?.status;return typeof t==`number`?t:void 0}function f(e){if(e instanceof n)return e.code;let t=e?.code;return typeof t==`string`?t:void 0}function p(e){let t=i({baseUrl:e.baseUrl,auth:r(e.apiKey),fetch:(e,t)=>{if((e instanceof Request?e.url:String(e)).includes(`/events/stream`))return fetch(e,t);let n=AbortSignal.timeout(3e4),r=t?.signal?AbortSignal.any([t.signal,n]):n;return fetch(e,{...t,signal:r})}}),n={orgID:e.orgId,projectID:e.projectId},s=e=>({...n,agentID:e});return{async createConfig(e,r){let{data:i}=await o.createAgentConfig({client:t,path:n,body:{source:e,source_format:r}});return{id:i.id}},async getConfig(e){let{data:r}=await o.getAgentConfig({client:t,path:{...n,agentConfigID:e}});return r},async getProfile(e){if(e.startsWith(`aprf_`)){let{data:r}=await o.getAgentProfile({client:t,path:{...n,agentProfileID:e}});return r}let{data:r}=await o.listAgentProfiles({client:t,path:n,query:{name:e.replace(/[\\*?]/g,`\\$&`),limit:100}}),i=r.data.find(t=>t.name===e);if(!i)throw Error(`Omnara profile "${e}" not found`);return i},async launch(e,r){let{data:i,response:a}=await o.createAgent({client:t,path:n,body:e,headers:{"Idempotency-Key":r}});return{agent:i.agent,created:a.status===201}},async getAgent(e){let{data:n}=await o.getAgent({client:t,path:s(e)});return n.agent},async listChildren(e){let r=[],i;for(;;){let{data:a}=await o.listAgents({client:t,path:n,query:{parent_agent_id:e,limit:100,cursor:i}});if(r.push(...a.data),!a.next_cursor||a.data.length===0)return r;i=a.next_cursor}},async setConfig(e,n,r,i){await o.updateAgentConfig({client:t,path:s(e),body:{source:n,source_format:r,expected_current_config_id:i}})},async listEvents(e){let n=[],r=0;for(;;){let{data:i}=await o.listEvents({client:t,path:s(e),query:{after_sequence:r,limit:100}});if(n.push(...i.data),!i.has_more||i.data.length===0)return n;r=i.next_after_sequence}},async hasEventsAfter(e,n){let{data:r}=await o.listEvents({client:t,path:s(e),query:{after_sequence:n,limit:1}});return r.data.length>0},async listBacklog(e){let n=[],r;for(;;){let{data:i}=await o.listQueuedBacklogInputs({client:t,path:s(e),query:{limit:100,cursor:r}});if(n.push(...i.data),!i.next_cursor||i.data.length===0)return n;r=i.next_cursor}},async cancelQueuedInput(e,n){await o.cancelQueuedBacklogInput({client:t,path:{...s(e),inputID:n}})},async postInput(e,n,r){await o.createAgentInput({client:t,path:s(e),body:{...n,delivery_mode:`queued`},headers:{"Idempotency-Key":r}})},stream(e,n,r,i){return a({client:t,path:s(e),query:{after_sequence:n,stream_deltas:!0},signal:r,onConnectionStateChange:e=>{e.state===`connected`&&i()}})},async readyCustomCalls(e){let{data:n}=await o.listToolCalls({client:t,path:s(e),query:{state:`ready`,type:`custom`,include_subagents:!0,limit:100}});return n.data},async openInteractions(e){let{data:n}=await o.listAgentInteractions({client:t,path:s(e),query:{state:`open`,include_subagents:!0,limit:100}});return n.data},async submitResult(e,n,r,i){await o.submitToolCallResult({client:t,path:{...s(e),toolCallID:n},body:{outcome:r,content_blocks:i}})},async resolveInteraction(e,n,r,i){await o.resolveAgentInteraction({client:t,path:{...s(e),interactionID:n},body:{answers:r,actor:i}})},async cancel(e,n){await o.cancelAgent({client:t,path:s(e),body:{actor:n}})},async getActor(e){let{data:r}=await o.getActor({client:t,path:{...n,actorID:e}});return r}}}function m(e){let t=e.source?u(e.source):{};return t&&typeof t==`object`?t:{}}function h(e){let t=e.tools??{};return Object.entries(t).filter(([,e])=>e?.type===`custom`).map(([e])=>e)}function g(e,t,n){return{type:`custom`,description:t?.trim()||e,input_schema:n??{type:`object`,properties:{}}}}function _(e){return Object.fromEntries(Object.entries(e).map(([e,t])=>{let n=t;return[e,{type:`custom`,description:n.description,input_schema:n.input_schema}]}))}function v(e){return JSON.stringify(e,(e,t)=>t&&typeof t==`object`&&!Array.isArray(t)?Object.fromEntries(Object.entries(t).sort(([e],[t])=>e.localeCompare(t))):t)}function y(e){return typeof e==`string`?e:e.map(e=>e.type===`text`?e.text??``:``).join(``)}const b=e=>e.replaceAll(`\0`,``);function x(e){if(e?.length)return{type:`text`,text:b(`Context from the app:\n${e.map(e=>`- ${e.description}: ${e.value}`).join(`
|
|
2
|
+
`)}`),metadata:{omnara_hidden:`true`}}}const S=e=>({type:`text`,text:e,metadata:{omnara_hidden:`true`}});function C(e,t){let n=[],r=!1,i=typeof e.content==`string`?[{type:`text`,text:e.content}]:e.content;for(let e of i)if(e.type===`text`){let t=b(e.text);t&&n.push({type:`text`,text:t})}else (e.type===`image`||e.type===`document`)&&e.source.type===`data`?(r=!0,n.push({type:`media`,media_type:e.source.mimeType,data:e.source.value})):n.push(S(`(The user attached a file (${e.type}) that could not be forwarded.)`));return t&&n.push(t),{blocks:n,media:r}}const w=1024*1024;function T(e){return e.reduce((e,t)=>e+(t.type===`media`?0:Buffer.byteLength(JSON.stringify(t).replace(/[<>&\u2028\u2029]/g,`\\u0000`))),0)}function E(e){return e.map(e=>e.type===`media`?S(`(The user attached a file that Omnara could not accept.)`):e)}const D={type:`object`,properties:{approved:{type:`boolean`},reason:{type:`string`}},required:[`approved`]},O={type:`object`,properties:{answers:{type:`array`,description:`One entry per question, in order.`,items:{type:`object`,properties:{optionIndices:{type:`array`,items:{type:`integer`}},text:{type:`string`}},required:[`optionIndices`]}}},required:[`answers`]},k=`The user dismissed this without answering.`;function A(e){let t=e.interaction_kind===`permission`;return{id:e.id,reason:t?`omnara:permission`:`omnara:question`,message:e.request.title,toolCallId:e.tool_call_id,responseSchema:t?D:O,metadata:{omnara:{kind:e.interaction_kind,agentId:e.agent_id,agentName:e.agent_name,toolName:e.tool_name,form:e.request}}}}function j(e,t){let n=t.payload??{};if(e.interaction_kind===`permission`){if(t.status===`resolved`&&n.approved===!0)return[{option_indices:[0]}];let e=t.status===`cancelled`?k:n.reason;return[{option_indices:[1],...e?{text:e}:{}}]}return e.request.questions.map((e,r)=>{if(t.status===`resolved`){let e=n.answers?.[r];return{option_indices:e?.optionIndices??[],...e?.text?{text:e.text}:{}}}let i=e.options.findIndex(e=>e.allows_text);return{option_indices:[i>=0?i:e.options.length-1],text:k}})}const M=`agui:`;function N(e){let t=`${M}${e}`;return t.length<=255&&/^[ -~]*$/.test(e)&&!e.endsWith(` `)?t:`${M}${l(`sha256`).update(e).digest(`hex`)}`}const P=(e,t)=>`${e}:block:${t}`,F=e=>e.metadata?.omnara_hidden===`true`;function I(e){return e.filter(e=>e.type===`text`&&!F(e)).map(e=>e.text??``).join(``)}const L=`[file]`;function R(e){return e.flatMap(e=>e.type===`text`?F(e)?[]:[e.text??``]:e.type===`media_ref`?[L]:[]).join(`
|
|
3
|
+
`)}function z(e){return e.map(e=>e.type===`text`?e.text??``:e.type===`structured_data`?JSON.stringify(e.value):e.type===`media_ref`?L:``).join(`
|
|
4
|
+
`)}function B(e,t){if(e.event_kind!==`agent_input`)return;let n=e.input_idempotency_key;if(n?.startsWith(M))return t?.get(n)??n.slice(5)}function V(e,t){let n=new Map(t.clientMessages.map(e=>[e.id,e])),r=new Map(t.clientMessages.map(e=>[N(e.id),e.id])),i=new Map(t.clientMessages.filter(e=>e.role===`tool`).map(e=>[e.toolCallId,e])),a=new Map,o=new Set;for(let t of e)if(t.event_kind===`model_output`)for(let e of t.content_blocks)e.type===`tool_call`&&a.set(e.tool_call_id,{name:e.name,type:e.tool_type});let s=e=>{let n=a.get(e);return n!==void 0&&t.isBrowserCall(n.name,n.type)};for(let t of e)t.event_kind===`tool_result`&&t.outcome===`canceled`&&s(t.tool_call_id)&&!i.has(t.tool_call_id)&&o.add(t.tool_call_id);let c=[];for(let a of e)if(a.event_kind===`agent_input`){if(a.input_kind!==`content`)continue;let e=B(a,r);if(e!==void 0){c.push(n.get(e)??{id:e,role:`user`,content:R(a.content_blocks)});continue}let i=R(a.content_blocks);if(!i)continue;let o=a.actor_id&&t.authors.get(a.actor_id)||{role:`user`};c.push({id:a.agent_input_id,role:o.role,content:i,...o.name?{name:o.name}:{}})}else if(a.event_kind===`model_output`){a.content_blocks.forEach((e,t)=>{e.type===`reasoning`&&e.text&&c.push({id:P(a.model_call_context_id,t),role:`reasoning`,content:e.text})});let e=I(a.content_blocks),t=a.content_blocks.flatMap(e=>e.type===`tool_call`&&!o.has(e.tool_call_id)?[{id:e.tool_call_id,type:`function`,function:{name:e.name,arguments:JSON.stringify(e.input??{})}}]:[]);if(!e&&t.length===0)continue;c.push({id:a.model_call_context_id,role:`assistant`,...e?{content:e}:{},...t.length?{toolCalls:t}:{}})}else if(a.event_kind===`tool_result`){let e=s(a.tool_call_id)?i.get(a.tool_call_id):void 0;e?c.push(e):o.has(a.tool_call_id)||c.push({id:a.id,role:`tool`,toolCallId:a.tool_call_id,content:z(a.content_blocks)})}let l=c.findIndex(e=>n.has(e.id)),u=l>=0?c.slice(l):n.size?[]:c,d=new Set(u.map(e=>e.id));for(let e of t.clientMessages)d.has(e.id)||(e.role===`user`||e.role===`tool`&&s(e.toolCallId))&&u.push(e);return u}const H={thread_ended:`This chat's Omnara agent was archived. Start a new chat to continue.`,invalid_tools:`Omnara rejected this chat's tools.`,message_too_large:`This message is too large for Omnara. Start a new chat to continue.`,run_failed:`The Omnara agent could not complete this request.`,model_error:`The model failed to respond.`};var U=class extends Error{constructor(e,t){super(H[e]),this.code=e,this.detail=t}},W=class{constructor(e,t,n){this.deps=e,this.input=t,this.emitEvent=n,this.stopped=!1,this.detached=!1,this.following=new AbortController,this.launchCustomTools=new Set,this.toolNames=new Map,this.selfKeys=new Set,this.copies=new Map,this.pendingKeys=new Set,this.submitted=!1,this.turnEnded=!0,this.cancelled=!1,this.lastSequence=0,this.handledCalls=new Set,this.checking=!1,this.checkAgain=!1,this.previews=new Map,this.authors=new Map}stop(){this.stopped=!0,this.following.abort()}detach(){this.detached=!0,this.following.abort()}async execute(){let{threadId:e,runId:t}=this.input;this.emit({type:s.RUN_STARTED,threadId:e,runId:t,protocolVersion:c});let n;try{n=await this.drive()}catch(e){if(this.detached&&!this.stopped){await this.report(`run_after_disconnect`,e);return}let t=e instanceof U?e.code:`run_failed`;await this.report(t,e instanceof U?e.detail:e),n=this.stopped?await this.endStopped():{error:t}}this.detached||(this.closeOpen(),await this.sendSnapshot(),`error`in n?this.emit({type:s.RUN_ERROR,message:H[n.error],code:n.error}):n.outcome.type===`success`&&this.modelError!==void 0?(await this.report(`model_error`,Error(this.modelError)),this.emit({type:s.RUN_ERROR,message:H.model_error,code:`model_error`})):this.emit({type:s.RUN_FINISHED,threadId:e,runId:t,outcome:n.outcome}))}async drive(){let e=await this.findOrCreateAgent();if(this.stopped)return this.endStopped();let t=await this.deps.api.listEvents(e.id);await this.syncTools(e,t);for(let e of t)this.noteToolCalls(e),this.noteTurn(e);let n=this.newWork(t);await this.restoreOrder(t,n.messages);for(let e of n.messages)this.pendingKeys.add(N(e.id));let r=t.at(-1);this.lastSequence=r?.sequence??0;let i=this.follow(e.id,r?.sequence??0);try{if(await i.connected,this.stopped)return this.endStopped();await this.submit(e.id,n),this.submitted=!0,this.check(),await i.done}finally{this.following.abort(),await i.done.catch(()=>void 0)}if(this.stopped)return this.endStopped();if(this.failure)throw this.failure;if(this.detached)return{outcome:{type:`success`}};if(!this.settled)throw Error(`event stream ended before the agent settled`);return{outcome:this.settled}}async findOrCreateAgent(){let{api:e,config:t}=this.deps;if(!this.input.threadId.trim())throw Error(`threadId is required`);let n,r=`AG-UI ${this.input.threadId.replace(/[^\w.:-]/g,``)}`.slice(0,64).trimEnd();if(t.profile){let i=await e.getProfile(t.profile);n={config:i.current_config_id,profile:i.id,name:r}}else{let i=t.definition,a=typeof i.source==`string`,o=a?i.source:JSON.stringify(i.source);n={config:(await e.createConfig(o,i.format??(a?`yaml`:`json`))).id,name:r}}let i=t.user===`anonymous`?{id:`anonymous`}:t.user,a=l(`sha256`).update(JSON.stringify([i.tenant??``,i.id,this.deps.aguiAgentId,this.input.threadId])).digest(`hex`),{agent:o,created:c}=await e.launch(n,`agui-thread:${a}`);if(this.agentId=o.id,o.state===`archived`)throw new U(`thread_ended`,Error(`agent ${o.id} is archived`));return c&&this.emit({type:s.CUSTOM,name:`omnara.agent`,value:{agentId:o.id,threadId:this.input.threadId}}),o}actor(){let{user:e}=this.deps.config;if(e!==`anonymous`)return{provider_user_id:e.id,...e.tenant?{provider_tenant_id:e.tenant}:{},...e.name?{display_name:e.name}:{}}}async syncTools(e,t){let{api:n,backendTools:r}=this.deps,i=t.find(e=>e.event_kind===`agent_input`&&e.input_kind===`config_change`),a=e.current_config_id;if(!a)return;let o=m(await n.getConfig(a)),s=i?.agent_config_id&&i.agent_config_id!==a?m(await n.getConfig(i.agent_config_id)):o;this.launchCustomTools=new Set(h(s));let c=o.subagents??{};this.selfKeys=new Set(Object.keys(c).filter(e=>c[e]?.type===`self`));let l=new Set(Object.keys(s.tools??{})),u={};for(let e of[...this.input.tools??[],...r.values()])l.has(e.name)||(u[e.name]=g(e.name,e.description,e.parameters));let f={...o.tools??{}},p={};for(let e of h(o))this.launchCustomTools.has(e)||(p[e]=f[e],delete f[e]);if(v(_(p))===v(u))return;let y=JSON.stringify({...o,tools:{...f,...u}});try{await n.setConfig(e.id,y,`json`,a)}catch(e){let t=d(e);throw t===400||t===413?new U(`invalid_tools`,e):e}}isBrowserCall(e,t){return t===`custom`&&!this.launchCustomTools.has(e)&&!this.deps.backendTools.has(e)}noteToolCalls(e){if(e.event_kind===`model_output`)for(let t of e.content_blocks)t.type===`tool_call`&&this.toolNames.set(t.tool_call_id,{name:t.name,type:t.tool_type})}newWork(e){let t=new Set,n=new Set,r=new Set;for(let i of e)i.event_kind===`agent_input`?(t.add(i.agent_input_id),i.input_idempotency_key&&n.add(i.input_idempotency_key)):i.event_kind===`tool_result`&&r.add(i.tool_call_id);let i=this.input.messages,a=x(this.input.context);return{messages:i.filter(e=>e.role===`user`&&!t.has(e.id)&&!n.has(N(e.id))&&C(e,a).blocks.length>0),results:i.filter(e=>{if(e.role!==`tool`||r.has(e.toolCallId))return!1;let t=this.toolNames.get(e.toolCallId);return t!==void 0&&this.isBrowserCall(t.name,t.type)}),resume:this.input.resume??[]}}async submit(e,t){let{api:n}=this.deps,r=this.actor();for(let n of t.results)await this.postResult(e,n.toolCallId,n.error?`failed`:`succeeded`,y(n.content)||n.error||``);let i=t.resume.length?await n.openInteractions(e).then(e=>new Map(e.map(e=>[e.id,e])),async e=>{await this.report(`resolve`,e)}):void 0;if(i)for(let e of t.resume){let t=i.get(e.interruptId);if(!t){await this.report(`unknown_interrupt`,Error(`no open interaction ${e.interruptId}`));continue}await q(()=>n.resolveInteraction(t.agent_id,t.id,j(t,e),r)).catch(e=>this.report(`resolve`,e))}if(!t.messages.length)return;let a=new Set(t.results.map(e=>e.toolCallId));(await n.readyCustomCalls(e)).filter(t=>t.agent_id===e&&this.isBrowserCall(t.name,t.type)&&!a.has(t.id)).length&&await n.cancel(e,r);let o=x(this.input.context),s=(t,i)=>q(()=>n.postInput(e,{content_blocks:t,actor:r},i).catch(e=>{throw f(e)===`state_transition_conflict`?new U(`thread_ended`,e):e}));for(let e of t.messages){let t=N(e.id),{blocks:n,media:r}=C(e,o);if(T(n)>w)throw new U(`message_too_large`,Error(`message ${e.id} with its context is over 1 MiB`));try{await s(n,t)}catch(e){let i=d(e);if(!r||e instanceof U||i===void 0||i<400||i>=500)throw e;await this.report(`attachment_rejected`,e),await s(E(n),t)}}}follow(e,t){let n,r=new Promise(e=>n=e),i=this.deps.api.stream(e,t,this.following.signal,n),a=(async()=>{let e=setInterval(()=>void this.check(),5e3);try{for await(let e of G(i,this.following.signal))await this.onFrame(e)}finally{clearInterval(e)}})(),o=new Promise((e,t)=>setTimeout(()=>t(Error(`event stream did not connect`)),3e4).unref?.());return{connected:Promise.race([r,a,o]).then(()=>void 0),done:a}}async onFrame(e){if(`event_kind`in e)return this.onEvent(e);if(`model_call_context_id`in e&&`event`in e)return this.onDelta(e);`tool_call_id`in e&&`state`in e&&(e.state===`ready`||e.state===`awaiting_permission`)&&this.check()}async onEvent(e){if(this.noteToolCalls(e),this.noteTurn(e),this.lastSequence=Math.max(this.lastSequence,e.sequence),e.event_kind===`agent_input`)if(e.input_kind===`content`){let t=e.input_idempotency_key;t&&this.pendingKeys.delete(t)&&this.pendingKeys.size===0&&this.check(),B(e)===void 0&&await this.emitOtherInput(e)}else e.input_kind===`control`&&this.check();else if(e.event_kind===`model_output`)this.emitModelOutput(e),this.turnEnded&&this.check();else if(e.event_kind===`tool_result`){let t=this.toolNames.get(e.tool_call_id);(!t||!this.isBrowserCall(t.name,t.type))&&(this.closeOpen(),this.emit({type:s.TOOL_CALL_RESULT,messageId:e.id,toolCallId:e.tool_call_id,content:z(e.content_blocks),role:`tool`}))}}noteTurn(e){this.turnEnded=K(e,this.turnEnded),e.event_kind===`agent_input`?e.input_kind===`content`?(this.cancelled=!1,this.modelError=void 0):e.input_kind===`control`&&(this.cancelled=!0):e.event_kind===`model_output`&&(this.modelError=e.stop_reason===`error`?e.content_blocks.map(e=>e.type===`error`?e.text:``).join(`
|
|
5
|
+
`):void 0,this.cancelled=!1)}async check(){if(this.settled||!this.submitted||this.following.signal.aborted)return;if(this.checking){this.checkAgain=!0;return}this.checking=!0;let e=this.lastSequence;try{let t=this.agentId,n=await this.waitingOutcome(t);if(n===null)return;let r=n;if(!r&&this.pendingKeys.size&&this.turnEnded&&await this.dropCancelledInputs(t),!r&&this.pendingKeys.size===0&&this.turnEnded&&!await this.subagentsBusy(t)&&(r={type:this.cancelled?`cancelled`:`success`}),r&&!this.following.signal.aborted){if(this.lastSequence!==e){this.checkAgain=!0;return}this.settled=r,this.following.abort()}}catch(e){await this.report(`check`,e)}finally{this.checking=!1,this.checkAgain&&(this.checkAgain=!1,this.check())}}async waitingOutcome(e){let{api:t,backendTools:n}=this.deps,r=await t.openInteractions(e);if(r.length)return{type:`interrupt`,interrupts:r.map(A)};let i=await t.readyCustomCalls(e),a=new Set((this.input.tools??[]).map(e=>e.name)),o=[],s=[];for(let t of i){if(this.handledCalls.has(t.id))continue;let r=n.has(t.name),i=t.agent_id!==e&&a.has(t.name)&&this.isBrowserCall(t.name,t.type);!(r||i)||!await this.hasOurTools(t.agent_id)||(r?o:s).push(t)}if(o.length||s.length)return this.following.signal.aborted||await Promise.all([...o.map(e=>this.runBackendTool(e)),...s.map(e=>this.deliver(e,`failed`,`This tool runs in the user's browser; subagents can't use it.`))]),null;let c=i.filter(t=>t.agent_id===e&&this.isBrowserCall(t.name,t.type));if(c.length)return{type:`success`,pendingToolCallIds:c.map(e=>e.id)}}async hasOurTools(e){let t=[],n=e,r;try{for(;n!==this.agentId&&(r=this.copies.get(n))===void 0;){let e=await this.deps.api.getAgent(n);t.push(n);let i=e.subagent_key;if(!i||!this.selfKeys.has(i)||!e.parent_agent_id){r=!1;break}n=e.parent_agent_id}}catch(e){return await this.report(`get_agent`,e),!1}r??=!0;for(let e of t)this.copies.set(e,r);return r}async subagentsBusy(e){if(![...this.toolNames.values()].some(e=>e.name===`spawn_agent`))return!1;let{api:t}=this.deps;return(await t.listChildren(e)).some(e=>e.state!==`archived`&&(e.activity?.state===`running`||e.activity?.state===`waiting_on_interaction`))||(await t.listBacklog(e)).length?!0:t.hasEventsAfter(e,this.lastSequence)}async dropCancelledInputs(e){let{api:t}=this.deps,n=new Set((await t.listBacklog(e)).map(e=>e.input_idempotency_key));if(!await t.hasEventsAfter(e,this.lastSequence))for(let e of this.pendingKeys)n.has(e)||this.pendingKeys.delete(e)}async runBackendTool(e){this.handledCalls.add(e.id);let t=this.deps.backendTools.get(e.name),n=`succeeded`,r;try{let n=await t.handler(e.input,{toolCallId:e.id});r=typeof n==`string`?n:JSON.stringify(n??null)}catch(e){n=`failed`,r=e instanceof Error?e.message:String(e)}await this.deliver(e,n,r)}async deliver(e,t,n){this.handledCalls.add(e.id);try{await this.postResult(e.agent_id,e.id,t,n)}catch(e){this.failure=e,this.following.abort()}}async postResult(e,t,n,r){let i={type:`text`,text:b(r)};T([i])>w&&(await this.report(`result_too_large`,Error(`result for ${t} is over 1 MiB`)),n=`failed`,i={type:`text`,text:`The result was too large to deliver (over Omnara's 1 MiB limit).`}),await q(()=>this.deps.api.submitResult(e,t,n,[i]))}async endStopped(){return this.agentId&&(await this.cancelQueuedInputs(this.agentId),await this.cancelWork(this.agentId)),{outcome:{type:`cancelled`}}}async cancelQueuedInputs(e){if(!this.pendingKeys.size)return;let{api:t}=this.deps,n=await t.listBacklog(e).catch(async e=>(await this.report(`cancel_input`,e),[]));for(let r of n)this.pendingKeys.has(r.input_idempotency_key??``)&&await q(()=>t.cancelQueuedInput(e,r.id)).catch(e=>this.report(`cancel_input`,e))}async cancelWork(e){await this.cancelSubagents(e),await this.deps.api.cancel(e,this.actor()).catch(e=>this.report(`cancel`,e))}async cancelSubagents(e){let{api:t}=this.deps,n=await t.listChildren(e).catch(async e=>(await this.report(`cancel_subagent`,e),[]));for(let e of n)e.state!==`archived`&&(await this.cancelSubagents(e.id),e.activity?.state!==`idle`&&await t.cancel(e.id,this.actor()).catch(e=>this.report(`cancel_subagent`,e)))}emit(e){this.detached||this.emitEvent(e)}closeOpen(){this.openText&&=(this.emit({type:s.TEXT_MESSAGE_END,messageId:this.openText}),void 0),this.openReasoning&&=(this.emit({type:s.REASONING_MESSAGE_END,messageId:this.openReasoning}),this.emit({type:s.REASONING_END,messageId:this.openReasoning}),void 0)}openTextMessage(e){this.openText!==e&&(this.closeOpen(),this.emit({type:s.TEXT_MESSAGE_START,messageId:e,role:`assistant`}),this.openText=e)}openReasoningMessage(e){this.openReasoning!==e&&(this.closeOpen(),this.emit({type:s.REASONING_START,messageId:e}),this.emit({type:s.REASONING_MESSAGE_START,messageId:e,role:`reasoning`}),this.openReasoning=e,this.shownReasoning??=e)}onDelta(e){let t=e.model_call_context_id,n=this.previews.get(t);if(n||(n={text:``,reasoning:new Set,next:1,broken:e.seq!==1},this.previews.set(t,n)),n.broken)return;if(e.seq!==n.next){n.broken=!0,this.closeOpen();return}n.next=e.seq+1;let r=e.event;switch(r.kind){case`block_start`:r.block.kind===`text`&&this.openTextMessage(t);break;case`text_delta`:this.openText===t&&r.delta&&(n.text+=r.delta,this.emit({type:s.TEXT_MESSAGE_CONTENT,messageId:t,delta:r.delta}));break;case`thinking_delta`:{if(!r.delta)break;let e=P(t,r.block_index);n.reasoning.has(r.block_index)||(n.reasoning.add(r.block_index),this.openReasoningMessage(e)),this.openReasoning===e&&this.emit({type:s.REASONING_MESSAGE_CONTENT,messageId:e,delta:r.delta});break}case`block_stop`:(this.openText===t||this.openReasoning===P(t,r.block_index))&&this.closeOpen();break;case`error`:n.broken=!0,this.closeOpen();break}}emitModelOutput(e){let t=e.model_call_context_id,n=this.previews.get(t);this.closeOpen(),e.content_blocks.forEach((e,r)=>{if(e.type!==`reasoning`||!e.text||n?.reasoning.has(r))return;let i=P(t,r);this.openReasoningMessage(i),this.emit({type:s.REASONING_MESSAGE_CONTENT,messageId:i,delta:e.text}),this.closeOpen()});let r=I(e.content_blocks),i=n?.text??``;r.length>i.length&&r.startsWith(i)&&(this.openTextMessage(t),this.emit({type:s.TEXT_MESSAGE_CONTENT,messageId:t,delta:r.slice(i.length)}),this.closeOpen());for(let n of e.content_blocks)n.type===`tool_call`&&(this.emit({type:s.TOOL_CALL_START,toolCallId:n.tool_call_id,toolCallName:n.name,parentMessageId:t}),this.emit({type:s.TOOL_CALL_ARGS,toolCallId:n.tool_call_id,delta:JSON.stringify(n.input??{})}),this.emit({type:s.TOOL_CALL_END,toolCallId:n.tool_call_id}))}async emitOtherInput(e){let t=R(e.content_blocks);if(!t)return;let n=e.actor_id?await this.author(e.actor_id):{role:`user`};this.closeOpen(),this.emit({type:s.TEXT_MESSAGE_START,messageId:e.agent_input_id,role:n.role,...n.name?{name:n.name}:{}}),this.emit({type:s.TEXT_MESSAGE_CONTENT,messageId:e.agent_input_id,delta:t}),this.emit({type:s.TEXT_MESSAGE_END,messageId:e.agent_input_id})}author(e){let t=this.authors.get(e);return t||(t=this.deps.api.getActor(e).then(e=>e.provider===`omnara`&&e.provider_user_id.startsWith(`agt_`)?{role:`assistant`,name:e.display_name||`Subagent`}:{role:`user`,...e.display_name?{name:e.display_name}:{}},async e=>(await this.report(`actor`,e),{role:`user`})),this.authors.set(e,t)),t}async history(e,t){let n=new Map;for(let t of e)t.event_kind===`agent_input`&&t.input_kind===`content`&&t.actor_id&&B(t)===void 0&&n.set(t.actor_id,await this.author(t.actor_id));return V(e,{clientMessages:t,isBrowserCall:(e,t)=>this.isBrowserCall(e,t),authors:n})}async restoreOrder(e,t){let n=new Set(this.input.messages.map(e=>e.id)),r=new Set(t.map(e=>e.id)),i=await this.history(e,this.input.messages.filter(e=>!r.has(e.id)));!i[0]||!n.has(i[0].id)||i.every(e=>e.role===`reasoning`||n.has(e.id))||(this.emit({type:s.MESSAGES_SNAPSHOT,messages:i}),t.length&&this.emit({type:s.MESSAGES_SNAPSHOT,messages:[...i,...t]}))}async sendSnapshot(){if(this.agentId)try{let e=await this.deps.api.listEvents(this.agentId);for(let t of e)this.noteToolCalls(t);let t=await this.history(e,this.input.messages);if(!t.some(e=>e.role===`reasoning`)){let e=this.input.messages.find(e=>e.role===`reasoning`)?.id??this.shownReasoning;e!==void 0&&t.push({id:e,role:`reasoning`,content:``})}this.emit({type:s.MESSAGES_SNAPSHOT,messages:t})}catch(e){await this.report(`snapshot`,e)}}report(e,t){return this.deps.report(t,{operation:e,threadId:this.input.threadId,agentId:this.agentId})}};async function*G(e,t){let n=e[Symbol.asyncIterator](),r=new Promise(e=>{t.aborted&&e({done:!0,value:void 0}),t.addEventListener(`abort`,()=>e({done:!0,value:void 0}),{once:!0})});try{for(;;){let e=await Promise.race([n.next(),r]);if(e.done)return;yield e.value}}finally{n.return?.()?.catch(()=>void 0)}}function K(e,t){switch(e.event_kind){case`agent_input`:return e.input_kind===`content`?!1:e.input_kind===`control`?!0:t;case`model_output`:return e.stop_reason!==`max_tokens`&&!e.content_blocks.some(e=>e.type===`tool_call`);case`tool_result`:return e.outcome===`canceled`?t:!1;default:return t}}async function q(e){try{await e()}catch(e){if(d(e)!==409)throw e}}var J=class extends e{constructor(e,t){if(super(e),this.currentRun=null,this.agentId??=`omnara`,!!e.profile==!!e.definition)throw Error("OmnaraAgent: give exactly one of `profile` and `definition`");if(!e.user||e.user!==`anonymous`&&!e.user.id)throw Error('OmnaraAgent: `user` is required (an `{ id }` from your auth, or "anonymous")');if(this.config=e,this.backendTools=new Map((e.backendTools??[]).map(e=>[e.name,e])),t)this.api=t;else{let t=e.apiKey??process.env.OMNARA_API_KEY;if(!t)throw Error("OmnaraAgent: set `apiKey` or OMNARA_API_KEY");this.api=p({apiKey:t,orgId:e.orgId,projectId:e.projectId,baseUrl:e.baseUrl})}}clone(){let e=super.clone();return e.config=this.config,e.api=this.api,e.backendTools=this.backendTools,e.currentRun=null,e}abortRun(){this.currentRun?.stop()}run(e){return new t(t=>{let n=new W({api:this.api,config:this.config,aguiAgentId:this.agentId,backendTools:this.backendTools,report:(e,t)=>this.report(e,t)},e,e=>t.next(e));return this.currentRun=n,n.execute().catch(t=>this.report(t,{operation:`run`,threadId:e.threadId})).finally(()=>{this.currentRun===n&&(this.currentRun=null),t.complete()}),()=>n.detach()})}async report(e,t){try{this.config.onError?await this.config.onError(e,t):console.error(`[@ag-ui/omnara] ${t.operation}`,e)}catch{}}};export{H as ERROR_MESSAGES,J as OmnaraAgent};
|
|
6
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["parseYaml"],"sources":["../src/api.ts","../src/inputs.ts","../src/interrupts.ts","../src/messages.ts","../src/run.ts","../src/agent.ts"],"sourcesContent":["import {\n ApiError,\n bearerToken,\n createOmnaraClient,\n openAgentEventStream,\n sdk,\n type Actor,\n type Agent,\n type AgentConfig,\n type AgentEvent,\n type AgentEventStreamFrame,\n type AgentInput,\n type AgentInteraction,\n type CreateAgentInputContentBlock,\n type ExternalActorParams,\n type InteractionAnswer,\n type SubmitToolResultContentBlock,\n type ToolCall,\n} from \"@omnara/sdk\";\n\nexport type {\n Actor,\n Agent,\n AgentEvent,\n AgentEventStreamFrame,\n AgentInteraction,\n CreateAgentInputContentBlock,\n ExternalActorParams,\n InteractionAnswer,\n SubmitToolResultContentBlock,\n ToolCall,\n};\n\n/**\n * The Omnara calls the adapter makes. A narrow seam over `@omnara/sdk` so the\n * run logic can be tested against a fake.\n */\nexport interface OmnaraApi {\n createConfig(\n source: string,\n format: \"yaml\" | \"json\",\n ): Promise<{ id: string }>;\n getConfig(configId: string): Promise<AgentConfig>;\n getProfile(\n idOrName: string,\n ): Promise<{ id: string; current_config_id: string }>;\n /** `created` is false when the idempotency key replayed an existing agent. */\n launch(\n body: { config: string; profile?: string; name: string },\n idempotencyKey: string,\n ): Promise<{ agent: Agent; created: boolean }>;\n getAgent(agentId: string): Promise<Agent>;\n /** All of the agent's unarchived subagents. */\n listChildren(agentId: string): Promise<Agent[]>;\n setConfig(\n agentId: string,\n source: string,\n format: \"yaml\" | \"json\",\n expectedCurrentConfigId: string,\n ): Promise<void>;\n /** The whole log, oldest first. */\n listEvents(agentId: string): Promise<AgentEvent[]>;\n /** Whether the log has events after `sequence`. */\n hasEventsAfter(agentId: string, sequence: number): Promise<boolean>;\n /** All inputs stored but not yet started (queued messages, undelivered subagent reports). */\n listBacklog(\n agentId: string,\n ): Promise<Array<{ id: string; input_idempotency_key?: string }>>;\n /** Cancel an input still in the backlog (a 409 once it has started). */\n cancelQueuedInput(agentId: string, inputId: string): Promise<void>;\n postInput(\n agentId: string,\n body: {\n content_blocks: CreateAgentInputContentBlock[];\n actor?: ExternalActorParams;\n },\n idempotencyKey: string,\n ): Promise<void>;\n stream(\n agentId: string,\n afterSequence: number,\n signal: AbortSignal,\n onConnected: () => void,\n ): AsyncIterable<AgentEventStreamFrame>;\n /** Ready custom calls on the agent and its subagents. */\n readyCustomCalls(agentId: string): Promise<ToolCall[]>;\n /** Open interactions on the agent and its subagents. */\n openInteractions(agentId: string): Promise<AgentInteraction[]>;\n submitResult(\n agentId: string,\n toolCallId: string,\n outcome: \"succeeded\" | \"failed\",\n content: SubmitToolResultContentBlock[],\n ): Promise<void>;\n resolveInteraction(\n agentId: string,\n interactionId: string,\n answers: InteractionAnswer[],\n actor?: ExternalActorParams,\n ): Promise<void>;\n cancel(agentId: string, actor?: ExternalActorParams): Promise<void>;\n getActor(actorId: string): Promise<Actor>;\n}\n\n/** HTTP status of an Omnara API failure, if it was one. */\nexport function statusOf(error: unknown): number | undefined {\n if (error instanceof ApiError) return error.status;\n const status = (error as { status?: unknown } | null)?.status;\n return typeof status === \"number\" ? status : undefined;\n}\n\n/** Omnara's error code (e.g. `state_transition_conflict`), if it was an API failure. */\nexport function codeOf(error: unknown): string | undefined {\n if (error instanceof ApiError) return error.code;\n const code = (error as { code?: unknown } | null)?.code;\n return typeof code === \"string\" ? code : undefined;\n}\n\nconst CALL_TIMEOUT_MS = 30_000;\nconst PAGE_LIMIT = 100;\n\nexport function createOmnaraApi(options: {\n apiKey: string;\n orgId: string;\n projectId: string;\n baseUrl?: string;\n}): OmnaraApi {\n const client = createOmnaraClient({\n baseUrl: options.baseUrl,\n auth: bearerToken(options.apiKey),\n // Every call is bounded, except the event stream, which is meant to stay open.\n fetch: (input, init) => {\n const url = input instanceof Request ? input.url : String(input);\n if (url.includes(\"/events/stream\")) return fetch(input, init);\n const timeout = AbortSignal.timeout(CALL_TIMEOUT_MS);\n const signal = init?.signal\n ? AbortSignal.any([init.signal, timeout])\n : timeout;\n return fetch(input, { ...init, signal });\n },\n });\n const project = { orgID: options.orgId, projectID: options.projectId };\n const agent = (agentID: string) => ({ ...project, agentID });\n\n return {\n async createConfig(source, format) {\n const { data } = await sdk.createAgentConfig({\n client,\n path: project,\n body: { source, source_format: format },\n });\n return { id: data.id };\n },\n async getConfig(configId) {\n const { data } = await sdk.getAgentConfig({\n client,\n path: { ...project, agentConfigID: configId },\n });\n return data;\n },\n async getProfile(idOrName) {\n if (idOrName.startsWith(\"aprf_\")) {\n const { data } = await sdk.getAgentProfile({\n client,\n path: { ...project, agentProfileID: idOrName },\n });\n return data;\n }\n // The filter is a case-insensitive glob, but names are unique only as\n // written: escape the wildcards and pick the exact name.\n const { data } = await sdk.listAgentProfiles({\n client,\n path: project,\n query: { name: idOrName.replace(/[\\\\*?]/g, \"\\\\$&\"), limit: PAGE_LIMIT },\n });\n const found = data.data.find((p) => p.name === idOrName);\n if (!found) throw new Error(`Omnara profile \"${idOrName}\" not found`);\n return found;\n },\n async launch(body, idempotencyKey) {\n const { data, response } = await sdk.createAgent({\n client,\n path: project,\n body,\n headers: { \"Idempotency-Key\": idempotencyKey },\n });\n return { agent: data.agent, created: response.status === 201 };\n },\n async getAgent(agentId) {\n const { data } = await sdk.getAgent({ client, path: agent(agentId) });\n return data.agent;\n },\n async listChildren(agentId) {\n const children: Agent[] = [];\n let cursor: string | undefined;\n for (;;) {\n const { data } = await sdk.listAgents({\n client,\n path: project,\n query: { parent_agent_id: agentId, limit: PAGE_LIMIT, cursor },\n });\n children.push(...data.data);\n if (!data.next_cursor || data.data.length === 0) return children;\n cursor = data.next_cursor;\n }\n },\n async setConfig(agentId, source, format, expectedCurrentConfigId) {\n await sdk.updateAgentConfig({\n client,\n path: agent(agentId),\n body: {\n source,\n source_format: format,\n expected_current_config_id: expectedCurrentConfigId,\n },\n });\n },\n async listEvents(agentId) {\n const events: AgentEvent[] = [];\n let after = 0;\n for (;;) {\n const { data } = await sdk.listEvents({\n client,\n path: agent(agentId),\n query: { after_sequence: after, limit: PAGE_LIMIT },\n });\n events.push(...data.data);\n if (!data.has_more || data.data.length === 0) return events;\n after = data.next_after_sequence;\n }\n },\n async hasEventsAfter(agentId, sequence) {\n const { data } = await sdk.listEvents({\n client,\n path: agent(agentId),\n query: { after_sequence: sequence, limit: 1 },\n });\n return data.data.length > 0;\n },\n async listBacklog(agentId) {\n const inputs: AgentInput[] = [];\n let cursor: string | undefined;\n for (;;) {\n const { data } = await sdk.listQueuedBacklogInputs({\n client,\n path: agent(agentId),\n query: { limit: PAGE_LIMIT, cursor },\n });\n inputs.push(...data.data);\n if (!data.next_cursor || data.data.length === 0) return inputs;\n cursor = data.next_cursor;\n }\n },\n async cancelQueuedInput(agentId, inputId) {\n await sdk.cancelQueuedBacklogInput({\n client,\n path: { ...agent(agentId), inputID: inputId },\n });\n },\n async postInput(agentId, body, idempotencyKey) {\n await sdk.createAgentInput({\n client,\n path: agent(agentId),\n body: { ...body, delivery_mode: \"queued\" },\n headers: { \"Idempotency-Key\": idempotencyKey },\n });\n },\n stream(agentId, afterSequence, signal, onConnected) {\n return openAgentEventStream({\n client,\n path: agent(agentId),\n query: { after_sequence: afterSequence, stream_deltas: true },\n signal,\n onConnectionStateChange: (state) => {\n if (state.state === \"connected\") onConnected();\n },\n });\n },\n async readyCustomCalls(agentId) {\n const { data } = await sdk.listToolCalls({\n client,\n path: agent(agentId),\n query: {\n state: \"ready\",\n type: \"custom\",\n include_subagents: true,\n limit: PAGE_LIMIT,\n },\n });\n return data.data;\n },\n async openInteractions(agentId) {\n const { data } = await sdk.listAgentInteractions({\n client,\n path: agent(agentId),\n query: { state: \"open\", include_subagents: true, limit: PAGE_LIMIT },\n });\n return data.data;\n },\n async submitResult(agentId, toolCallId, outcome, content) {\n await sdk.submitToolCallResult({\n client,\n path: { ...agent(agentId), toolCallID: toolCallId },\n body: { outcome, content_blocks: content },\n });\n },\n async resolveInteraction(agentId, interactionId, answers, actor) {\n await sdk.resolveAgentInteraction({\n client,\n path: { ...agent(agentId), interactionID: interactionId },\n body: { answers, actor },\n });\n },\n async cancel(agentId, actor) {\n await sdk.cancelAgent({ client, path: agent(agentId), body: { actor } });\n },\n async getActor(actorId) {\n const { data } = await sdk.getActor({\n client,\n path: { ...project, actorID: actorId },\n });\n return data;\n },\n };\n}\n","import type { RunAgentInput, UserMessage } from \"@ag-ui/core\";\nimport { parse as parseYaml } from \"yaml\";\nimport type { CreateAgentInputContentBlock } from \"./api\";\n\n// What the adapter sends to Omnara besides API calls: the tool definitions in a\n// derived agent config, and a user message as Omnara content blocks.\n\nexport function parseSource(config: {\n source?: string;\n}): Record<string, unknown> {\n const parsed = config.source ? parseYaml(config.source) : {};\n return parsed && typeof parsed === \"object\"\n ? (parsed as Record<string, unknown>)\n : {};\n}\n\nexport function customToolNames(definition: Record<string, unknown>): string[] {\n const tools =\n (definition.tools as Record<string, { type?: string } | null>) ?? {};\n return Object.entries(tools)\n .filter(([, t]) => t?.type === \"custom\")\n .map(([name]) => name);\n}\n\nexport function customTool(\n name: string,\n description: string | undefined,\n parameters: unknown,\n) {\n return {\n type: \"custom\",\n // Omnara requires a description; a tool without one is described by its name.\n description: description?.trim() || name,\n input_schema: parameters ?? { type: \"object\", properties: {} },\n };\n}\n\nexport function pickToolShape(\n tools: Record<string, unknown>,\n): Record<string, unknown> {\n return Object.fromEntries(\n Object.entries(tools).map(([name, t]) => {\n const tool = t as { description?: string; input_schema?: unknown };\n return [\n name,\n {\n type: \"custom\",\n description: tool.description,\n input_schema: tool.input_schema,\n },\n ];\n }),\n );\n}\n\n/** JSON with sorted keys, for comparing tool definitions. */\nexport function canonical(value: unknown): string {\n return JSON.stringify(value, (_, v) =>\n v && typeof v === \"object\" && !Array.isArray(v)\n ? Object.fromEntries(\n Object.entries(v).sort(([a], [b]) => a.localeCompare(b)),\n )\n : v,\n );\n}\n\nexport function messageText(\n content: string | ReadonlyArray<{ type: string; text?: string }>,\n): string {\n return typeof content === \"string\"\n ? content\n : content.map((p) => (p.type === \"text\" ? (p.text ?? \"\") : \"\")).join(\"\");\n}\n\n/** Omnara stores no U+0000 in text. */\nexport const storable = (text: string): string => text.replaceAll(\"\\0\", \"\");\n\nexport function contextBlock(\n context: RunAgentInput[\"context\"],\n): CreateAgentInputContentBlock | undefined {\n if (!context?.length) return undefined;\n return {\n type: \"text\",\n text: storable(\n `Context from the app:\\n${context.map((c) => `- ${c.description}: ${c.value}`).join(\"\\n\")}`,\n ),\n metadata: { omnara_hidden: \"true\" },\n };\n}\n\nconst note = (text: string): CreateAgentInputContentBlock => ({\n type: \"text\",\n text,\n metadata: { omnara_hidden: \"true\" },\n});\n\n/** The message as Omnara content blocks; inline images and documents become media. */\nexport function userBlocks(\n message: UserMessage,\n context: CreateAgentInputContentBlock | undefined,\n): { blocks: CreateAgentInputContentBlock[]; media: boolean } {\n const blocks: CreateAgentInputContentBlock[] = [];\n let media = false;\n const parts =\n typeof message.content === \"string\"\n ? [{ type: \"text\" as const, text: message.content }]\n : message.content;\n for (const part of parts) {\n if (part.type === \"text\") {\n const text = storable(part.text);\n if (text) blocks.push({ type: \"text\", text });\n } else if (\n (part.type === \"image\" || part.type === \"document\") &&\n part.source.type === \"data\"\n ) {\n media = true;\n blocks.push({\n type: \"media\",\n media_type: part.source.mimeType as Extract<\n CreateAgentInputContentBlock,\n { type: \"media\" }\n >[\"media_type\"],\n data: part.source.value,\n });\n } else {\n blocks.push(\n note(\n `(The user attached a file (${part.type}) that could not be forwarded.)`,\n ),\n );\n }\n }\n if (context) blocks.push(context);\n return { blocks, media };\n}\n\n/** Omnara's limit on the content of one submission, inline media aside. */\nexport const MAX_CONTENT_BYTES = 1024 * 1024;\n\n/**\n * The size Omnara counts against `MAX_CONTENT_BYTES`: the blocks as Go's JSON\n * encodes them, which escapes `<`, `>`, `&`, U+2028 and U+2029 as `\\uXXXX`.\n */\nexport function contentBytes(blocks: ReadonlyArray<{ type: string }>): number {\n return blocks.reduce(\n (n, b) =>\n n +\n (b.type === \"media\"\n ? 0\n : Buffer.byteLength(\n JSON.stringify(b).replace(/[<>&\\u2028\\u2029]/g, \"\\\\u0000\"),\n )),\n 0,\n );\n}\n\nexport function withoutMedia(\n blocks: CreateAgentInputContentBlock[],\n): CreateAgentInputContentBlock[] {\n return blocks.map((b) =>\n b.type === \"media\"\n ? note(\"(The user attached a file that Omnara could not accept.)\")\n : b,\n );\n}\n","import type { Interrupt, ResumeEntry } from \"@ag-ui/core\";\nimport type { AgentInteraction, InteractionAnswer } from \"./api\";\n\n// Omnara's approvals and questions as AG-UI interrupts, and the resume payload\n// back to Omnara's answers.\n\nconst PERMISSION_SCHEMA = {\n type: \"object\",\n properties: { approved: { type: \"boolean\" }, reason: { type: \"string\" } },\n required: [\"approved\"],\n};\nconst QUESTION_SCHEMA = {\n type: \"object\",\n properties: {\n answers: {\n type: \"array\",\n description: \"One entry per question, in order.\",\n items: {\n type: \"object\",\n properties: {\n optionIndices: { type: \"array\", items: { type: \"integer\" } },\n text: { type: \"string\" },\n },\n required: [\"optionIndices\"],\n },\n },\n },\n required: [\"answers\"],\n};\nconst DISMISSED = \"The user dismissed this without answering.\";\n\nexport function toInterrupt(interaction: AgentInteraction): Interrupt {\n const permission = interaction.interaction_kind === \"permission\";\n return {\n id: interaction.id,\n reason: permission ? \"omnara:permission\" : \"omnara:question\",\n message: interaction.request.title,\n toolCallId: interaction.tool_call_id,\n responseSchema: permission ? PERMISSION_SCHEMA : QUESTION_SCHEMA,\n metadata: {\n omnara: {\n kind: interaction.interaction_kind,\n agentId: interaction.agent_id,\n agentName: interaction.agent_name,\n toolName: interaction.tool_name,\n form: interaction.request,\n },\n },\n };\n}\n\n/**\n * Resume payload to Omnara answers. A dismissed card still lets the agent\n * continue: a permission is denied, a question gets its \"Other\" option.\n */\nexport function answersFor(\n interaction: AgentInteraction,\n entry: ResumeEntry,\n): InteractionAnswer[] {\n const payload = (entry.payload ?? {}) as {\n approved?: boolean;\n reason?: string;\n answers?: Array<{ optionIndices?: number[]; text?: string }>;\n };\n if (interaction.interaction_kind === \"permission\") {\n if (entry.status === \"resolved\" && payload.approved === true)\n return [{ option_indices: [0] }];\n const reason = entry.status === \"cancelled\" ? DISMISSED : payload.reason;\n return [{ option_indices: [1], ...(reason ? { text: reason } : {}) }];\n }\n return interaction.request.questions.map((question, i) => {\n if (entry.status === \"resolved\") {\n const answer = payload.answers?.[i];\n return {\n option_indices: answer?.optionIndices ?? [],\n ...(answer?.text ? { text: answer.text } : {}),\n };\n }\n const other = question.options.findIndex((o) => o.allows_text);\n return {\n option_indices: [other >= 0 ? other : question.options.length - 1],\n text: DISMISSED,\n };\n });\n}\n","import type { Message, ToolMessage } from \"@ag-ui/core\";\nimport { createHash } from \"node:crypto\";\nimport type { AgentEvent } from \"./api\";\n\n/**\n * One mapping from Omnara's log to AG-UI messages, shared by live streaming and\n * the end-of-request snapshot, so the ids always match and the snapshot\n * replaces what was streamed instead of duplicating it.\n *\n * - assistant message: the model call id (`mcc_...`)\n * - reasoning message: `<model call id>:block:<index>`\n * - tool call: Omnara's tool-call id\n * - tool message: the tool result's event id\n * - user message: the client's id (behind its `agui:` input key), or\n * Omnara's input id for messages from anyone else (see `Author`)\n */\n\nexport const INPUT_KEY_PREFIX = \"agui:\";\n\n/**\n * A client message's Omnara idempotency key. An id a header can't carry as is\n * (non-ASCII, a trailing space, too long) is hashed; `clientIdOf` maps it back\n * through the client's messages.\n */\nexport function inputKey(messageId: string): string {\n const key = `${INPUT_KEY_PREFIX}${messageId}`;\n return key.length <= 255 &&\n /^[ -~]*$/.test(messageId) &&\n !messageId.endsWith(\" \")\n ? key\n : `${INPUT_KEY_PREFIX}${createHash(\"sha256\").update(messageId).digest(\"hex\")}`;\n}\n\nexport const reasoningId = (modelCallId: string, index: number) =>\n `${modelCallId}:block:${index}`;\n\ntype Blocks = ReadonlyArray<{\n type: string;\n text?: string;\n metadata?: Record<string, unknown>;\n}>;\n\nconst hidden = (block: { metadata?: Record<string, unknown> }) =>\n block.metadata?.omnara_hidden === \"true\";\n\n/** The visible text of a set of content blocks. */\nexport function visibleText(blocks: Blocks): string {\n return blocks\n .filter((b) => b.type === \"text\" && !hidden(b))\n .map((b) => b.text ?? \"\")\n .join(\"\");\n}\n\n/**\n * Where a file was. Omnara files (artifacts) can only be downloaded with the\n * API key, so the chat can't show them; it gets a marker in their place.\n */\nconst FILE_MARKER = \"[file]\";\n\n/** A message's visible text, with a marker for each attached file. */\nexport function inputText(\n blocks: ReadonlyArray<{\n type: string;\n text?: string;\n metadata?: Record<string, unknown>;\n }>,\n): string {\n return blocks\n .flatMap((b) => {\n if (b.type === \"text\") return hidden(b) ? [] : [b.text ?? \"\"];\n return b.type === \"media_ref\" ? [FILE_MARKER] : [];\n })\n .join(\"\\n\");\n}\n\n/** A tool result as text: text as is, structured data as JSON, a marker for each file. */\nexport function toolResultText(\n blocks: ReadonlyArray<{\n type: string;\n text?: string;\n value?: unknown;\n artifact_id?: string;\n }>,\n): string {\n return blocks\n .map((b) => {\n if (b.type === \"text\") return b.text ?? \"\";\n if (b.type === \"structured_data\") return JSON.stringify(b.value);\n if (b.type === \"media_ref\") return FILE_MARKER;\n return \"\";\n })\n .join(\"\\n\");\n}\n\n/**\n * The client message id behind an input key, if the input came from this\n * adapter. `byKey` maps the keys of the client's messages to their ids.\n */\nexport function clientIdOf(\n event: AgentEvent,\n byKey?: ReadonlyMap<string, string>,\n): string | undefined {\n if (event.event_kind !== \"agent_input\") return undefined;\n const key = event.input_idempotency_key;\n if (!key?.startsWith(INPUT_KEY_PREFIX)) return undefined;\n return byKey?.get(key) ?? key.slice(INPUT_KEY_PREFIX.length);\n}\n\n/**\n * Who wrote an input that did not come from this adapter, in AG-UI's terms: a\n * subagent's report is the agent's side (as LangGraph and ADK show subagent\n * output by default), anyone else is a user. `name` is AG-UI's sender name.\n */\nexport type Author = { role: \"user\" | \"assistant\"; name?: string };\n\ninterface SnapshotContext {\n /** The client's messages to keep (usually what it sent this request). */\n clientMessages: Message[];\n /** Browser-tool calls: their results come only from the client. */\n isBrowserCall: (name: string, type: string) => boolean;\n /** Author of each other-writer input, by actor id. */\n authors: ReadonlyMap<string, Author>;\n}\n\n/**\n * The messages to restate at the end of a request: Omnara's log from the\n * oldest message the chat holds onward. The user's own messages and\n * browser-tool results are the client's copies; the agent's messages come\n * from the log, which drops partial replies left by failed previews.\n */\nexport function snapshotMessages(\n events: AgentEvent[],\n ctx: SnapshotContext,\n): Message[] {\n const held = new Map(ctx.clientMessages.map((m) => [m.id, m]));\n const byKey = new Map(ctx.clientMessages.map((m) => [inputKey(m.id), m.id]));\n const clientResults = new Map(\n ctx.clientMessages\n .filter((m): m is ToolMessage => m.role === \"tool\")\n .map((m) => [m.toolCallId, m]),\n );\n\n const calls = new Map<string, { name: string; type: string }>();\n const cancelledBrowserCalls = new Set<string>();\n for (const e of events) {\n if (e.event_kind === \"model_output\") {\n for (const b of e.content_blocks) {\n if (b.type === \"tool_call\")\n calls.set(b.tool_call_id, { name: b.name, type: b.tool_type });\n }\n }\n }\n const isBrowserCall = (id: string) => {\n const call = calls.get(id);\n return call !== undefined && ctx.isBrowserCall(call.name, call.type);\n };\n for (const e of events) {\n if (\n e.event_kind === \"tool_result\" &&\n e.outcome === \"canceled\" &&\n isBrowserCall(e.tool_call_id) &&\n !clientResults.has(e.tool_call_id)\n ) {\n cancelledBrowserCalls.add(e.tool_call_id);\n }\n }\n\n const out: Message[] = [];\n for (const e of events) {\n if (e.event_kind === \"agent_input\") {\n if (e.input_kind !== \"content\") continue;\n const clientId = clientIdOf(e, byKey);\n if (clientId !== undefined) {\n out.push(\n held.get(clientId) ?? {\n id: clientId,\n role: \"user\",\n content: inputText(e.content_blocks),\n },\n );\n continue;\n }\n const text = inputText(e.content_blocks);\n if (!text) continue;\n const author = (e.actor_id && ctx.authors.get(e.actor_id)) || {\n role: \"user\" as const,\n };\n out.push({\n id: e.agent_input_id,\n role: author.role,\n content: text,\n ...(author.name ? { name: author.name } : {}),\n });\n } else if (e.event_kind === \"model_output\") {\n e.content_blocks.forEach((b, i) => {\n if (b.type === \"reasoning\" && b.text) {\n out.push({\n id: reasoningId(e.model_call_context_id, i),\n role: \"reasoning\",\n content: b.text,\n });\n }\n });\n const text = visibleText(e.content_blocks);\n const toolCalls = e.content_blocks.flatMap((b) =>\n b.type === \"tool_call\" && !cancelledBrowserCalls.has(b.tool_call_id)\n ? [\n {\n id: b.tool_call_id,\n type: \"function\" as const,\n function: {\n name: b.name,\n arguments: JSON.stringify(b.input ?? {}),\n },\n },\n ]\n : [],\n );\n if (!text && toolCalls.length === 0) continue;\n out.push({\n id: e.model_call_context_id,\n role: \"assistant\",\n ...(text ? { content: text } : {}),\n ...(toolCalls.length ? { toolCalls } : {}),\n });\n } else if (e.event_kind === \"tool_result\") {\n // The page's copy of its own (browser) results; the log's for the rest.\n const own = isBrowserCall(e.tool_call_id)\n ? clientResults.get(e.tool_call_id)\n : undefined;\n if (own) out.push(own);\n else if (!cancelledBrowserCalls.has(e.tool_call_id)) {\n out.push({\n id: e.id,\n role: \"tool\",\n toolCallId: e.tool_call_id,\n content: toolResultText(e.content_blocks),\n });\n }\n }\n }\n\n // Start at the oldest message the chat holds: history it lacks (after a\n // server restart, say) would land below the new message, so it stays out.\n // An empty chat gets all of it.\n const anchor = out.findIndex((m) => held.has(m.id));\n const kept = anchor >= 0 ? out.slice(anchor) : held.size ? [] : out;\n\n // The page's own messages the log doesn't have yet stay where they are: a\n // message not delivered yet, a browser tool's result. Anything else the log\n // doesn't have (a preview from a failed model call, say) goes.\n const ids = new Set(kept.map((m) => m.id));\n for (const m of ctx.clientMessages) {\n if (ids.has(m.id)) continue;\n if (m.role === \"user\" || (m.role === \"tool\" && isBrowserCall(m.toolCallId)))\n kept.push(m);\n }\n return kept;\n}\n","import {\n EventType,\n PROTOCOL_VERSION,\n type AGUIEvent,\n type BaseEvent,\n type Message,\n type ResumeEntry,\n type RunAgentInput,\n type RunFinishedOutcome,\n type ToolMessage,\n type UserMessage,\n} from \"@ag-ui/core\";\nimport { createHash } from \"node:crypto\";\nimport {\n codeOf,\n statusOf,\n type Agent,\n type AgentEvent,\n type AgentEventStreamFrame,\n type CreateAgentInputContentBlock,\n type ExternalActorParams,\n type OmnaraApi,\n type ToolCall,\n} from \"./api\";\nimport {\n MAX_CONTENT_BYTES,\n canonical,\n contentBytes,\n contextBlock,\n customTool,\n customToolNames,\n messageText,\n parseSource,\n pickToolShape,\n storable,\n userBlocks,\n withoutMedia,\n} from \"./inputs\";\nimport { answersFor, toInterrupt } from \"./interrupts\";\nimport {\n clientIdOf,\n inputKey,\n inputText,\n reasoningId,\n snapshotMessages,\n toolResultText,\n visibleText,\n type Author,\n} from \"./messages\";\nimport type {\n BackendTool,\n OmnaraAgentConfig,\n OmnaraErrorContext,\n} from \"./types\";\n\n/** Stable `RUN_ERROR` codes. Upstream error text never reaches the client; it goes to `onError`. */\nexport const ERROR_MESSAGES = {\n thread_ended:\n \"This chat's Omnara agent was archived. Start a new chat to continue.\",\n invalid_tools: \"Omnara rejected this chat's tools.\",\n message_too_large:\n \"This message is too large for Omnara. Start a new chat to continue.\",\n run_failed: \"The Omnara agent could not complete this request.\",\n model_error: \"The model failed to respond.\",\n} as const;\nexport type OmnaraErrorCode = keyof typeof ERROR_MESSAGES;\n\nclass RunError extends Error {\n constructor(\n readonly code: OmnaraErrorCode,\n readonly detail: unknown,\n ) {\n super(ERROR_MESSAGES[code]);\n }\n}\n\nconst CONNECT_TIMEOUT_MS = 30_000;\nconst CHECK_INTERVAL_MS = 5_000;\n\nconst SUBAGENT_BROWSER_TOOL =\n \"This tool runs in the user's browser; subagents can't use it.\";\nconst RESULT_TOO_LARGE =\n \"The result was too large to deliver (over Omnara's 1 MiB limit).\";\n\ninterface RunDeps {\n api: OmnaraApi;\n config: OmnaraAgentConfig;\n /** The AG-UI agent's id (CopilotKit's registered name). */\n aguiAgentId: string;\n backendTools: ReadonlyMap<string, BackendTool>;\n report: (error: unknown, context: OmnaraErrorContext) => Promise<void>;\n}\n\ntype Ending = { outcome: RunFinishedOutcome } | { error: OmnaraErrorCode };\ntype Preview = {\n text: string;\n reasoning: Set<number>;\n next: number;\n broken: boolean;\n};\ntype Work = {\n messages: UserMessage[];\n results: ToolMessage[];\n resume: ResumeEntry[];\n};\n\n/** One AG-UI request against one Omnara agent. */\nexport class OmnaraRun {\n private agentId?: string;\n private stopped = false;\n private detached = false;\n private readonly following = new AbortController();\n\n // What the tools look like: which custom tools are the page's (browser) tools.\n private launchCustomTools = new Set<string>();\n private readonly toolNames = new Map<\n string,\n { name: string; type: string }\n >();\n /** The agent's `type: self` subagent keys; its `self` copies share them. */\n private selfKeys = new Set<string>();\n /** Whether each subagent asked about has the agent's tools. */\n private readonly copies = new Map<string, boolean>();\n\n // Following.\n private readonly pendingKeys = new Set<string>();\n private submitted = false;\n /** A new agent has no turn under way. */\n private turnEnded = true;\n /** The agent's latest turn was cancelled (someone pressed Stop elsewhere). */\n private cancelled = false;\n private lastSequence = 0;\n private modelError?: string;\n private readonly handledCalls = new Set<string>();\n private settled?: RunFinishedOutcome;\n /** A result Omnara didn't accept while following: ends the run with an error. */\n private failure?: unknown;\n private checking = false;\n private checkAgain = false;\n\n // Streaming.\n private openText?: string;\n private openReasoning?: string;\n private readonly previews = new Map<string, Preview>();\n /** The first reasoning message this run showed. */\n private shownReasoning?: string;\n private readonly authors = new Map<string, Promise<Author>>();\n\n constructor(\n private readonly deps: RunDeps,\n private readonly input: RunAgentInput,\n private readonly emitEvent: (event: BaseEvent) => void,\n ) {}\n\n /** Stop button: cancel the agent's current work and its running subagents, then end as cancelled. */\n stop(): void {\n this.stopped = true;\n this.following.abort();\n }\n\n /** The client went away: stop emitting, leave the agent running. */\n detach(): void {\n this.detached = true;\n this.following.abort();\n }\n\n async execute(): Promise<void> {\n const { threadId, runId } = this.input;\n this.emit({\n type: EventType.RUN_STARTED,\n threadId,\n runId,\n protocolVersion: PROTOCOL_VERSION,\n });\n let ending: Ending;\n try {\n ending = await this.drive();\n } catch (error) {\n if (this.detached && !this.stopped) {\n await this.report(\"run_after_disconnect\", error);\n return;\n }\n const code = error instanceof RunError ? error.code : \"run_failed\";\n await this.report(code, error instanceof RunError ? error.detail : error);\n // Stop still cancels what was sent, however the request failed.\n ending = this.stopped ? await this.endStopped() : { error: code };\n }\n if (this.detached) return;\n this.closeOpen();\n await this.sendSnapshot();\n if (\"error\" in ending) {\n this.emit({\n type: EventType.RUN_ERROR,\n message: ERROR_MESSAGES[ending.error],\n code: ending.error,\n });\n } else if (\n ending.outcome.type === \"success\" &&\n this.modelError !== undefined\n ) {\n await this.report(\"model_error\", new Error(this.modelError));\n this.emit({\n type: EventType.RUN_ERROR,\n message: ERROR_MESSAGES.model_error,\n code: \"model_error\",\n });\n } else {\n this.emit({\n type: EventType.RUN_FINISHED,\n threadId,\n runId,\n outcome: ending.outcome,\n });\n }\n }\n\n private async drive(): Promise<Ending> {\n const agent = await this.findOrCreateAgent();\n if (this.stopped) return this.endStopped();\n const log = await this.deps.api.listEvents(agent.id);\n await this.syncTools(agent, log);\n // By the same rules as while following.\n for (const e of log) {\n this.noteToolCalls(e);\n this.noteTurn(e);\n }\n // With nothing new to send (a reconnect), the run still follows the\n // agent's current work to its end.\n const work = this.newWork(log);\n\n await this.restoreOrder(log, work.messages);\n\n // Registered before the stream opens: a message already queued in Omnara\n // can start while earlier answers are submitted.\n for (const m of work.messages) this.pendingKeys.add(inputKey(m.id));\n const last = log.at(-1);\n this.lastSequence = last?.sequence ?? 0;\n const followed = this.follow(agent.id, last?.sequence ?? 0);\n try {\n await followed.connected;\n if (this.stopped) return this.endStopped();\n await this.submit(agent.id, work);\n this.submitted = true;\n void this.check();\n await followed.done;\n } finally {\n // However the run ends, nothing streams after it.\n this.following.abort();\n await followed.done.catch(() => undefined);\n }\n\n if (this.stopped) return this.endStopped();\n if (this.failure) throw this.failure;\n // The client left: nothing more is sent, and the agent carries on in Omnara.\n if (this.detached) return { outcome: { type: \"success\" } };\n if (!this.settled)\n throw new Error(\"event stream ended before the agent settled\");\n return { outcome: this.settled };\n }\n\n // ---------------------------------------------------------------- agent\n\n private async findOrCreateAgent(): Promise<Agent> {\n const { api, config } = this.deps;\n if (!this.input.threadId.trim()) throw new Error(\"threadId is required\");\n let launch: { config: string; profile?: string; name: string };\n // Omnara agent names: at most 64 characters, no edge or invisible spaces.\n const name = `AG-UI ${this.input.threadId.replace(/[^\\w.:-]/g, \"\")}`\n .slice(0, 64)\n .trimEnd();\n if (config.profile) {\n const profile = await api.getProfile(config.profile);\n launch = { config: profile.current_config_id, profile: profile.id, name };\n } else {\n const def = config.definition!;\n const isText = typeof def.source === \"string\";\n const source = isText\n ? (def.source as string)\n : JSON.stringify(def.source);\n const created = await api.createConfig(\n source,\n def.format ?? (isText ? \"yaml\" : \"json\"),\n );\n launch = { config: created.id, name };\n }\n // A thread has one Omnara agent per AG-UI agent and user: the launch key\n // replays the agent the thread started with, so a changed profile or\n // definition only reaches new threads.\n const user =\n config.user === \"anonymous\" ? { id: \"anonymous\" } : config.user;\n const key = createHash(\"sha256\")\n .update(\n JSON.stringify([\n user.tenant ?? \"\",\n user.id,\n this.deps.aguiAgentId,\n this.input.threadId,\n ]),\n )\n .digest(\"hex\");\n const { agent, created } = await api.launch(launch, `agui-thread:${key}`);\n this.agentId = agent.id;\n if (agent.state === \"archived\")\n throw new RunError(\n \"thread_ended\",\n new Error(`agent ${agent.id} is archived`),\n );\n if (created) {\n this.emit({\n type: EventType.CUSTOM,\n name: \"omnara.agent\",\n value: { agentId: agent.id, threadId: this.input.threadId },\n });\n }\n return agent;\n }\n\n private actor(): ExternalActorParams | undefined {\n const { user } = this.deps.config;\n if (user === \"anonymous\") return undefined;\n return {\n provider_user_id: user.id,\n ...(user.tenant ? { provider_tenant_id: user.tenant } : {}),\n ...(user.name ? { display_name: user.name } : {}),\n };\n }\n\n // ---------------------------------------------------------------- tools\n\n /**\n * Make the agent's custom tools match this request: the custom tools that\n * were not in its launch config are the adapter's, and get replaced by this\n * request's browser tools plus `backendTools`. Profiles are never written.\n */\n private async syncTools(agent: Agent, log: AgentEvent[]): Promise<void> {\n const { api, backendTools } = this.deps;\n const launchId = log.find(\n (e) => e.event_kind === \"agent_input\" && e.input_kind === \"config_change\",\n ) as { agent_config_id?: string } | undefined;\n const currentId = agent.current_config_id;\n if (!currentId) return;\n const current = parseSource(await api.getConfig(currentId));\n const launch =\n launchId?.agent_config_id && launchId.agent_config_id !== currentId\n ? parseSource(await api.getConfig(launchId.agent_config_id))\n : current;\n this.launchCustomTools = new Set(customToolNames(launch));\n // Our writes keep `subagents`: this is the map every subagent was spawned under.\n const subagents =\n (current.subagents as Record<string, { type?: unknown }> | null) ?? {};\n this.selfKeys = new Set(\n Object.keys(subagents).filter((k) => subagents[k]?.type === \"self\"),\n );\n\n // A tool the agent's own definition declares (built in, or custom with its\n // permission, say) is left as the definition has it.\n const declared = new Set(\n Object.keys((launch.tools as Record<string, unknown> | null) ?? {}),\n );\n const wanted: Record<string, unknown> = {};\n for (const t of [...(this.input.tools ?? []), ...backendTools.values()]) {\n if (!declared.has(t.name)) {\n wanted[t.name] = customTool(t.name, t.description, t.parameters);\n }\n }\n\n const tools = { ...((current.tools as Record<string, unknown>) ?? {}) };\n const owned: Record<string, unknown> = {};\n for (const name of customToolNames(current)) {\n if (!this.launchCustomTools.has(name)) {\n owned[name] = tools[name];\n delete tools[name];\n }\n }\n if (canonical(pickToolShape(owned)) === canonical(wanted)) return;\n\n const source = JSON.stringify({\n ...current,\n tools: { ...tools, ...wanted },\n });\n try {\n await api.setConfig(agent.id, source, \"json\", currentId);\n } catch (error) {\n // Omnara rejects an invalid or oversized config; other failures aren't the tools'.\n const status = statusOf(error);\n if (status === 400 || status === 413)\n throw new RunError(\"invalid_tools\", error);\n throw error;\n }\n }\n\n private isBrowserCall(name: string, type: string): boolean {\n return (\n type === \"custom\" &&\n !this.launchCustomTools.has(name) &&\n !this.deps.backendTools.has(name)\n );\n }\n\n private noteToolCalls(event: AgentEvent): void {\n if (event.event_kind !== \"model_output\") return;\n for (const b of event.content_blocks) {\n if (b.type === \"tool_call\")\n this.toolNames.set(b.tool_call_id, { name: b.name, type: b.tool_type });\n }\n }\n\n // ---------------------------------------------------------------- submit\n\n private newWork(log: AgentEvent[]): Work {\n // Omnara's input ids (messages from others the chat holds) and our input keys.\n const known = new Set<string>();\n const keys = new Set<string>();\n const answered = new Set<string>();\n for (const e of log) {\n if (e.event_kind === \"agent_input\") {\n known.add(e.agent_input_id);\n if (e.input_idempotency_key) keys.add(e.input_idempotency_key);\n } else if (e.event_kind === \"tool_result\") {\n answered.add(e.tool_call_id);\n }\n }\n const all = this.input.messages;\n const context = contextBlock(this.input.context);\n return {\n // A message of the user's that the agent doesn't have yet. Omnara\n // takes no empty input: an empty message with no app context is skipped.\n messages: all.filter(\n (m): m is UserMessage =>\n m.role === \"user\" &&\n !known.has(m.id) &&\n !keys.has(inputKey(m.id)) &&\n userBlocks(m, context).blocks.length > 0,\n ),\n // The page answers only its own (browser) tools.\n results: all.filter((m): m is ToolMessage => {\n if (m.role !== \"tool\" || answered.has(m.toolCallId)) return false;\n const call = this.toolNames.get(m.toolCallId);\n return call !== undefined && this.isBrowserCall(call.name, call.type);\n }),\n resume: this.input.resume ?? [],\n };\n }\n\n /** Browser-tool results, then answers, then messages. A 409 means it's already there. */\n private async submit(agentId: string, work: Work): Promise<void> {\n const { api } = this.deps;\n const actor = this.actor();\n\n for (const result of work.results) {\n await this.postResult(\n agentId,\n result.toolCallId,\n result.error ? \"failed\" : \"succeeded\",\n messageText(result.content) || result.error || \"\",\n );\n }\n\n // If answering fails, the check after submitting sees the card still open\n // and ends with it again (CopilotKit hides a card when a run fails).\n const open = work.resume.length\n ? await api.openInteractions(agentId).then(\n (all) => new Map(all.map((i) => [i.id, i])),\n async (error) => {\n await this.report(\"resolve\", error);\n return undefined;\n },\n )\n : undefined;\n if (open) {\n for (const entry of work.resume) {\n const interaction = open.get(entry.interruptId);\n if (!interaction) {\n // Answered or cancelled elsewhere, or not ours: proceed (the snapshot shows what happened).\n await this.report(\n \"unknown_interrupt\",\n new Error(`no open interaction ${entry.interruptId}`),\n );\n continue;\n }\n await accept409(() =>\n api.resolveInteraction(\n interaction.agent_id,\n interaction.id,\n answersFor(interaction, entry),\n actor,\n ),\n ).catch((error) => this.report(\"resolve\", error));\n }\n }\n\n if (!work.messages.length) return;\n // A browser tool call the page never answered blocks the agent for good:\n // cancel that turn (Omnara's own cancel), then deliver the message.\n const answered = new Set(work.results.map((r) => r.toolCallId));\n const abandoned = (await api.readyCustomCalls(agentId)).filter(\n (c) =>\n c.agent_id === agentId &&\n this.isBrowserCall(c.name, c.type) &&\n !answered.has(c.id),\n );\n if (abandoned.length) await api.cancel(agentId, actor);\n\n const context = contextBlock(this.input.context);\n // A 409 means the message is already there, unless the agent was archived.\n const post = (blocks: CreateAgentInputContentBlock[], key: string) =>\n accept409(() =>\n api\n .postInput(agentId, { content_blocks: blocks, actor }, key)\n .catch((error) => {\n if (codeOf(error) === \"state_transition_conflict\") {\n throw new RunError(\"thread_ended\", error);\n }\n throw error;\n }),\n );\n for (const message of work.messages) {\n const key = inputKey(message.id);\n const { blocks, media } = userBlocks(message, context);\n // Over Omnara's limit: the run says so rather than cut or replace it.\n if (contentBytes(blocks) > MAX_CONTENT_BYTES) {\n throw new RunError(\n \"message_too_large\",\n new Error(`message ${message.id} with its context is over 1 MiB`),\n );\n }\n try {\n await post(blocks, key);\n } catch (error) {\n const status = statusOf(error);\n if (\n !media ||\n error instanceof RunError ||\n status === undefined ||\n status < 400 ||\n status >= 500\n )\n throw error;\n // Omnara rejected an attachment: send the message without it.\n await this.report(\"attachment_rejected\", error);\n await post(withoutMedia(blocks), key);\n }\n }\n }\n\n // ---------------------------------------------------------------- follow\n\n private follow(agentId: string, afterSequence: number) {\n let onConnected!: () => void;\n const connected = new Promise<void>((resolve) => (onConnected = resolve));\n const frames = this.deps.api.stream(\n agentId,\n afterSequence,\n this.following.signal,\n onConnected,\n );\n const done = (async () => {\n const timer = setInterval(() => void this.check(), CHECK_INTERVAL_MS);\n try {\n for await (const frame of untilAborted(frames, this.following.signal)) {\n await this.onFrame(frame);\n }\n } finally {\n clearInterval(timer);\n }\n })();\n const timeout = new Promise<never>((_, reject) =>\n setTimeout(\n () => reject(new Error(\"event stream did not connect\")),\n CONNECT_TIMEOUT_MS,\n ).unref?.(),\n );\n return {\n connected: Promise.race([connected, done, timeout]).then(() => undefined),\n done,\n };\n }\n\n private async onFrame(frame: AgentEventStreamFrame): Promise<void> {\n if (\"event_kind\" in frame) return this.onEvent(frame as AgentEvent);\n if (\"model_call_context_id\" in frame && \"event\" in frame)\n return this.onDelta(frame);\n if (\"tool_call_id\" in frame && \"state\" in frame) {\n if (frame.state === \"ready\" || frame.state === \"awaiting_permission\")\n void this.check();\n }\n }\n\n private async onEvent(event: AgentEvent): Promise<void> {\n this.noteToolCalls(event);\n this.noteTurn(event);\n this.lastSequence = Math.max(this.lastSequence, event.sequence);\n if (event.event_kind === \"agent_input\") {\n if (event.input_kind === \"content\") {\n const key = event.input_idempotency_key;\n if (key && this.pendingKeys.delete(key) && this.pendingKeys.size === 0)\n void this.check();\n if (clientIdOf(event) === undefined) await this.emitOtherInput(event);\n } else if (event.input_kind === \"control\") {\n void this.check();\n }\n } else if (event.event_kind === \"model_output\") {\n this.emitModelOutput(event);\n if (this.turnEnded) void this.check();\n } else if (event.event_kind === \"tool_result\") {\n const call = this.toolNames.get(event.tool_call_id);\n // Browser-tool results are the client's own; the producer must not answer them.\n if (!call || !this.isBrowserCall(call.name, call.type)) {\n this.closeOpen();\n this.emit({\n type: EventType.TOOL_CALL_RESULT,\n messageId: event.id,\n toolCallId: event.tool_call_id,\n content: toolResultText(event.content_blocks),\n role: \"tool\",\n });\n }\n }\n }\n\n /** What an event says about the agent's turn: over, failed, cancelled. A message starts a new one. */\n private noteTurn(event: AgentEvent): void {\n this.turnEnded = turnOver(event, this.turnEnded);\n if (event.event_kind === \"agent_input\") {\n if (event.input_kind === \"content\") {\n this.cancelled = false;\n this.modelError = undefined;\n } else if (event.input_kind === \"control\") {\n this.cancelled = true;\n }\n } else if (event.event_kind === \"model_output\") {\n this.modelError =\n event.stop_reason === \"error\"\n ? event.content_blocks\n .map((b) => (b.type === \"error\" ? b.text : \"\"))\n .join(\"\\n\")\n : undefined;\n this.cancelled = false;\n }\n }\n\n /** Finished, or waiting on the user, the page or a host-run tool? Ends the follow when settled. */\n private async check(): Promise<void> {\n if (this.settled || !this.submitted) return;\n if (this.following.signal.aborted) return;\n if (this.checking) {\n // Something happened mid-check: look again once this one is done.\n this.checkAgain = true;\n return;\n }\n this.checking = true;\n const seen = this.lastSequence;\n try {\n const agentId = this.agentId!;\n const waiting = await this.waitingOutcome(agentId);\n if (waiting === null) return; // ran host tools; keep following\n let outcome = waiting;\n if (!outcome && this.pendingKeys.size && this.turnEnded)\n await this.dropCancelledInputs(agentId);\n // Finished only once our messages have started (a queued message runs\n // after whatever is ahead of it) and nothing is still on its way.\n if (\n !outcome &&\n this.pendingKeys.size === 0 &&\n this.turnEnded &&\n !(await this.subagentsBusy(agentId))\n ) {\n outcome = { type: this.cancelled ? \"cancelled\" : \"success\" };\n }\n if (outcome && !this.following.signal.aborted) {\n // An event arrived while checking (a subagent's report, say): what was\n // read may be stale, so look again instead of settling.\n if (this.lastSequence !== seen) {\n this.checkAgain = true;\n return;\n }\n this.settled = outcome;\n this.following.abort();\n }\n } catch (error) {\n await this.report(\"check\", error);\n } finally {\n this.checking = false;\n if (this.checkAgain) {\n this.checkAgain = false;\n void this.check();\n }\n }\n }\n\n /**\n * The outcome for what the agent waits on: an approval or question, or a\n * browser tool. Ready `backendTools` calls are run, a subagent's call to a\n * page tool gets a failed result, and `null` is returned (the agent will\n * continue).\n */\n private async waitingOutcome(\n agentId: string,\n ): Promise<RunFinishedOutcome | undefined | null> {\n const { api, backendTools } = this.deps;\n const interactions = await api.openInteractions(agentId);\n if (interactions.length) {\n return { type: \"interrupt\", interrupts: interactions.map(toInterrupt) };\n }\n const ready = await api.readyCustomCalls(agentId);\n const pageTools = new Set((this.input.tools ?? []).map((t) => t.name));\n const hostCalls: ToolCall[] = [];\n const subagentBrowserCalls: ToolCall[] = [];\n for (const c of ready) {\n if (this.handledCalls.has(c.id)) continue;\n const host = backendTools.has(c.name);\n // `type: self` subagents inherit the page's tools but can't reach the page.\n const page =\n c.agent_id !== agentId &&\n pageTools.has(c.name) &&\n this.isBrowserCall(c.name, c.type);\n // A tool of the same name on a subagent launched from a profile (even\n // this agent's) is that profile's own, left to its worker.\n if (!(host || page) || !(await this.hasOurTools(c.agent_id))) continue;\n (host ? hostCalls : subagentBrowserCalls).push(c);\n }\n if (hostCalls.length || subagentBrowserCalls.length) {\n // Stopped (or the client left) while this looked: nothing starts now.\n if (this.following.signal.aborted) return null;\n await Promise.all([\n ...hostCalls.map((c) => this.runBackendTool(c)),\n ...subagentBrowserCalls.map((c) =>\n this.deliver(c, \"failed\", SUBAGENT_BROWSER_TOOL),\n ),\n ]);\n return null;\n }\n const pending = ready.filter(\n (c) => c.agent_id === agentId && this.isBrowserCall(c.name, c.type),\n );\n if (pending.length)\n return { type: \"success\", pendingToolCallIds: pending.map((c) => c.id) };\n return undefined;\n }\n\n /**\n * Whether an agent has this agent's tools (the page's and `backendTools`):\n * the agent itself, or a subagent spawned under a `type: self` key at every\n * step up to it, each a copy of its parent's config. A subagent launched\n * from a profile, even this agent's, has that profile's tools. False while\n * Omnara can't say; the next check asks again.\n */\n private async hasOurTools(agentId: string): Promise<boolean> {\n const chain: string[] = [];\n let id = agentId;\n let copy: boolean | undefined;\n try {\n while (\n id !== this.agentId &&\n (copy = this.copies.get(id)) === undefined\n ) {\n const subagent = await this.deps.api.getAgent(id);\n chain.push(id);\n const key = subagent.subagent_key;\n if (!key || !this.selfKeys.has(key) || !subagent.parent_agent_id) {\n copy = false;\n break;\n }\n id = subagent.parent_agent_id;\n }\n } catch (error) {\n await this.report(\"get_agent\", error);\n return false;\n }\n copy ??= true;\n for (const c of chain) this.copies.set(c, copy);\n return copy;\n }\n\n /**\n * Whether subagents are still working for this conversation. Omnara stores a\n * subagent's report in the parent's backlog in the same transaction as its\n * final output, then moves it into the log; reading in this order (running\n * subagents, then the backlog, then the log) can't miss a report in transit.\n * A stopped subagent sends no report and is simply not running.\n */\n private async subagentsBusy(agentId: string): Promise<boolean> {\n if (![...this.toolNames.values()].some((t) => t.name === \"spawn_agent\")) {\n return false;\n }\n const { api } = this.deps;\n const children = await api.listChildren(agentId);\n const working = (c: (typeof children)[number]) =>\n c.state !== \"archived\" &&\n (c.activity?.state === \"running\" ||\n c.activity?.state === \"waiting_on_interaction\");\n if (children.some(working)) return true;\n if ((await api.listBacklog(agentId)).length) return true;\n return api.hasEventsAfter(agentId, this.lastSequence);\n }\n\n /** A message of ours that's neither queued nor in the log was cancelled (from Omnara's dashboard, say). */\n private async dropCancelledInputs(agentId: string): Promise<void> {\n const { api } = this.deps;\n // Leaving the queue and entering the log are one step: read the queue first.\n const queued = new Set(\n (await api.listBacklog(agentId)).map((i) => i.input_idempotency_key),\n );\n if (await api.hasEventsAfter(agentId, this.lastSequence)) return;\n for (const key of this.pendingKeys) {\n if (!queued.has(key)) this.pendingKeys.delete(key);\n }\n }\n\n private async runBackendTool(call: ToolCall): Promise<void> {\n this.handledCalls.add(call.id);\n const tool = this.deps.backendTools.get(call.name)!;\n let outcome: \"succeeded\" | \"failed\" = \"succeeded\";\n let text: string;\n try {\n const value = await tool.handler(call.input, { toolCallId: call.id });\n text = typeof value === \"string\" ? value : JSON.stringify(value ?? null);\n } catch (error) {\n // The handler's own message: the host's code, and what the agent needs to recover.\n outcome = \"failed\";\n text = error instanceof Error ? error.message : String(error);\n }\n await this.deliver(call, outcome, text);\n }\n\n /** Post a result for a call this run answers. If Omnara doesn't take it, the run fails. */\n private async deliver(\n call: ToolCall,\n outcome: \"succeeded\" | \"failed\",\n text: string,\n ): Promise<void> {\n this.handledCalls.add(call.id);\n try {\n await this.postResult(call.agent_id, call.id, outcome, text);\n } catch (error) {\n this.failure = error;\n this.following.abort();\n }\n }\n\n /** A tool result over Omnara's size limit goes as a failed result saying so. A 409 means it's already there. */\n private async postResult(\n agentId: string,\n toolCallId: string,\n outcome: \"succeeded\" | \"failed\",\n text: string,\n ): Promise<void> {\n let block = { type: \"text\" as const, text: storable(text) };\n if (contentBytes([block]) > MAX_CONTENT_BYTES) {\n await this.report(\n \"result_too_large\",\n new Error(`result for ${toolCallId} is over 1 MiB`),\n );\n outcome = \"failed\";\n block = { type: \"text\", text: RESULT_TOO_LARGE };\n }\n await accept409(() =>\n this.deps.api.submitResult(agentId, toolCallId, outcome, [block]),\n );\n }\n\n /** Stop: cancel this request's queued messages and the agent's work (once it's known), and end as cancelled. */\n private async endStopped(): Promise<Ending> {\n if (this.agentId) {\n await this.cancelQueuedInputs(this.agentId);\n await this.cancelWork(this.agentId);\n }\n return { outcome: { type: \"cancelled\" } };\n }\n\n /**\n * Omnara's cancel leaves queued inputs waiting, so a message of ours still\n * queued would start after Stop. They go first: one that starts in the\n * meantime is the current turn, which the agent's cancel then stops.\n */\n private async cancelQueuedInputs(agentId: string): Promise<void> {\n if (!this.pendingKeys.size) return;\n const { api } = this.deps;\n const queued = await api.listBacklog(agentId).catch(async (e) => {\n await this.report(\"cancel_input\", e);\n return [];\n });\n for (const input of queued) {\n if (!this.pendingKeys.has(input.input_idempotency_key ?? \"\")) continue;\n await accept409(() => api.cancelQueuedInput(agentId, input.id)).catch(\n (e) => this.report(\"cancel_input\", e),\n );\n }\n }\n\n /** Cancel the agent's running subagents, nested ones first, then the agent (Omnara's default cancel). */\n private async cancelWork(agentId: string): Promise<void> {\n await this.cancelSubagents(agentId);\n await this.deps.api\n .cancel(agentId, this.actor())\n .catch((e) => this.report(\"cancel\", e));\n }\n\n /** Omnara's cancel doesn't reach subagents, and an idle one can have working subagents of its own. */\n private async cancelSubagents(agentId: string): Promise<void> {\n const { api } = this.deps;\n // No `spawn_agent` check (unlike `subagentsBusy`): Stop can land before the log is read.\n const children = await api.listChildren(agentId).catch(async (e) => {\n await this.report(\"cancel_subagent\", e);\n return [];\n });\n for (const child of children) {\n if (child.state === \"archived\") continue;\n await this.cancelSubagents(child.id);\n if (child.activity?.state !== \"idle\") {\n await api\n .cancel(child.id, this.actor())\n .catch((e) => this.report(\"cancel_subagent\", e));\n }\n }\n }\n\n // ---------------------------------------------------------------- emit\n\n private emit(event: AGUIEvent): void {\n if (!this.detached) this.emitEvent(event);\n }\n\n private closeOpen(): void {\n if (this.openText) {\n this.emit({ type: EventType.TEXT_MESSAGE_END, messageId: this.openText });\n this.openText = undefined;\n }\n if (this.openReasoning) {\n this.emit({\n type: EventType.REASONING_MESSAGE_END,\n messageId: this.openReasoning,\n });\n this.emit({\n type: EventType.REASONING_END,\n messageId: this.openReasoning,\n });\n this.openReasoning = undefined;\n }\n }\n\n private openTextMessage(id: string): void {\n if (this.openText === id) return;\n this.closeOpen();\n this.emit({\n type: EventType.TEXT_MESSAGE_START,\n messageId: id,\n role: \"assistant\",\n });\n this.openText = id;\n }\n\n private openReasoningMessage(id: string): void {\n if (this.openReasoning === id) return;\n this.closeOpen();\n this.emit({ type: EventType.REASONING_START, messageId: id });\n this.emit({\n type: EventType.REASONING_MESSAGE_START,\n messageId: id,\n role: \"reasoning\",\n });\n this.openReasoning = id;\n this.shownReasoning ??= id;\n }\n\n /** Live previews. Only a model call seen from its first delta is previewed; a gap stops it. */\n private onDelta(\n frame: Extract<\n AgentEventStreamFrame,\n { model_call_context_id: string; event: unknown }\n >,\n ): void {\n const mcc = frame.model_call_context_id;\n let preview = this.previews.get(mcc);\n if (!preview) {\n preview = {\n text: \"\",\n reasoning: new Set(),\n next: 1,\n broken: frame.seq !== 1,\n };\n this.previews.set(mcc, preview);\n }\n if (preview.broken) return;\n if (frame.seq !== preview.next) {\n preview.broken = true;\n this.closeOpen();\n return;\n }\n preview.next = frame.seq + 1;\n const delta = frame.event;\n switch (delta.kind) {\n case \"block_start\":\n if (delta.block.kind === \"text\") this.openTextMessage(mcc);\n break;\n case \"text_delta\":\n if (this.openText === mcc && delta.delta) {\n preview.text += delta.delta;\n this.emit({\n type: EventType.TEXT_MESSAGE_CONTENT,\n messageId: mcc,\n delta: delta.delta,\n });\n }\n break;\n case \"thinking_delta\": {\n if (!delta.delta) break;\n const id = reasoningId(mcc, delta.block_index);\n // Opened on its first text: OpenAI reasoning streams blocks with none.\n if (!preview.reasoning.has(delta.block_index)) {\n preview.reasoning.add(delta.block_index);\n this.openReasoningMessage(id);\n }\n if (this.openReasoning === id) {\n this.emit({\n type: EventType.REASONING_MESSAGE_CONTENT,\n messageId: id,\n delta: delta.delta,\n });\n }\n break;\n }\n case \"block_stop\":\n if (\n this.openText === mcc ||\n this.openReasoning === reasoningId(mcc, delta.block_index)\n ) {\n this.closeOpen();\n }\n break;\n case \"error\":\n preview.broken = true;\n this.closeOpen();\n break;\n }\n }\n\n /** The recorded output completes what was previewed; tool calls come only from here. */\n private emitModelOutput(\n event: Extract<AgentEvent, { event_kind: \"model_output\" }>,\n ): void {\n const mcc = event.model_call_context_id;\n const preview = this.previews.get(mcc);\n this.closeOpen();\n event.content_blocks.forEach((b, i) => {\n if (b.type !== \"reasoning\" || !b.text || preview?.reasoning.has(i))\n return;\n const id = reasoningId(mcc, i);\n this.openReasoningMessage(id);\n this.emit({\n type: EventType.REASONING_MESSAGE_CONTENT,\n messageId: id,\n delta: b.text,\n });\n this.closeOpen();\n });\n const text = visibleText(event.content_blocks);\n const shown = preview?.text ?? \"\";\n if (text.length > shown.length && text.startsWith(shown)) {\n this.openTextMessage(mcc);\n this.emit({\n type: EventType.TEXT_MESSAGE_CONTENT,\n messageId: mcc,\n delta: text.slice(shown.length),\n });\n this.closeOpen();\n }\n for (const b of event.content_blocks) {\n if (b.type !== \"tool_call\") continue;\n this.emit({\n type: EventType.TOOL_CALL_START,\n toolCallId: b.tool_call_id,\n toolCallName: b.name,\n parentMessageId: mcc,\n });\n this.emit({\n type: EventType.TOOL_CALL_ARGS,\n toolCallId: b.tool_call_id,\n delta: JSON.stringify(b.input ?? {}),\n });\n this.emit({ type: EventType.TOOL_CALL_END, toolCallId: b.tool_call_id });\n }\n }\n\n /** A message from someone else (a subagent report, a dashboard or API user), in place. */\n private async emitOtherInput(\n event: Extract<AgentEvent, { event_kind: \"agent_input\" }>,\n ): Promise<void> {\n const text = inputText(event.content_blocks);\n if (!text) return;\n const author = event.actor_id\n ? await this.author(event.actor_id)\n : { role: \"user\" as const };\n this.closeOpen();\n this.emit({\n type: EventType.TEXT_MESSAGE_START,\n messageId: event.agent_input_id,\n role: author.role,\n ...(author.name ? { name: author.name } : {}),\n });\n this.emit({\n type: EventType.TEXT_MESSAGE_CONTENT,\n messageId: event.agent_input_id,\n delta: text,\n });\n this.emit({\n type: EventType.TEXT_MESSAGE_END,\n messageId: event.agent_input_id,\n });\n }\n\n /**\n * A subagent is an Omnara actor whose user id is an agent id; people in\n * Omnara's dashboard, API keys and schedules are Omnara actors too.\n */\n private author(actorId: string): Promise<Author> {\n let found = this.authors.get(actorId);\n if (!found) {\n found = this.deps.api.getActor(actorId).then(\n (a): Author =>\n a.provider === \"omnara\" && a.provider_user_id.startsWith(\"agt_\")\n ? { role: \"assistant\", name: a.display_name || \"Subagent\" }\n : {\n role: \"user\",\n ...(a.display_name ? { name: a.display_name } : {}),\n },\n async (error) => {\n await this.report(\"actor\", error);\n return { role: \"user\" as const };\n },\n );\n this.authors.set(actorId, found);\n }\n return found;\n }\n\n /** The chat's history from Omnara's log, keeping `clientMessages` (see `snapshotMessages`). */\n private async history(\n events: AgentEvent[],\n clientMessages: Message[],\n ): Promise<Message[]> {\n const authors = new Map<string, Author>();\n for (const e of events) {\n if (\n e.event_kind === \"agent_input\" &&\n e.input_kind === \"content\" &&\n e.actor_id &&\n clientIdOf(e) === undefined\n ) {\n authors.set(e.actor_id, await this.author(e.actor_id));\n }\n }\n return snapshotMessages(events, {\n clientMessages,\n isBrowserCall: (name, type) => this.isBrowserCall(name, type),\n authors,\n });\n }\n\n /**\n * Put what the chat missed while idle (someone else's message, the agent's\n * reply to it) above this request's new messages, where it happened. The\n * client keeps the messages it holds in place and adds new ones at the end,\n * so the history goes out without the new messages, then with them.\n */\n private async restoreOrder(\n log: AgentEvent[],\n fresh: UserMessage[],\n ): Promise<void> {\n const held = new Set(this.input.messages.map((m) => m.id));\n const freshIds = new Set(fresh.map((m) => m.id));\n const history = await this.history(\n log,\n this.input.messages.filter((m) => !freshIds.has(m.id)),\n );\n // Nothing to place it after (a server restart), or nothing missed.\n // Reasoning doesn't count: not every client sends it back.\n if (!history[0] || !held.has(history[0].id)) return;\n if (history.every((m) => m.role === \"reasoning\" || held.has(m.id))) return;\n this.emit({ type: EventType.MESSAGES_SNAPSHOT, messages: history });\n if (fresh.length) {\n this.emit({\n type: EventType.MESSAGES_SNAPSHOT,\n messages: [...history, ...fresh],\n });\n }\n }\n\n private async sendSnapshot(): Promise<void> {\n if (!this.agentId) return;\n try {\n const events = await this.deps.api.listEvents(this.agentId);\n for (const e of events) this.noteToolCalls(e);\n const messages = await this.history(events, this.input.messages);\n // A snapshot without reasoning leaves the client's reasoning in place\n // (AG-UI's rule), so reasoning from an attempt Omnara didn't keep (a\n // failed first try, a canceled call), shown now or held from an earlier\n // request, would stay. Carrying one of those ids, emptied, makes the\n // snapshot the record: the client blanks that one and drops the rest.\n if (!messages.some((m) => m.role === \"reasoning\")) {\n const stale =\n this.input.messages.find((m) => m.role === \"reasoning\")?.id ??\n this.shownReasoning;\n if (stale !== undefined)\n messages.push({ id: stale, role: \"reasoning\", content: \"\" });\n }\n this.emit({ type: EventType.MESSAGES_SNAPSHOT, messages });\n } catch (error) {\n await this.report(\"snapshot\", error);\n }\n }\n\n private report(operation: string, error: unknown): Promise<void> {\n return this.deps.report(error, {\n operation,\n threadId: this.input.threadId,\n agentId: this.agentId,\n });\n }\n}\n\n// ------------------------------------------------------------------ helpers\n\n/**\n * Stop iterating as soon as `signal` aborts. `@omnara/sdk`'s stream can miss\n * an abort after a garbage collection and keep reading until its next\n * heartbeat (up to 10s); this keeps a settled run from waiting on it.\n */\nasync function* untilAborted<T>(\n source: AsyncIterable<T>,\n signal: AbortSignal,\n): AsyncGenerator<T> {\n const iterator = source[Symbol.asyncIterator]();\n const aborted = new Promise<IteratorResult<T>>((resolve) => {\n if (signal.aborted) resolve({ done: true, value: undefined });\n signal.addEventListener(\n \"abort\",\n () => resolve({ done: true, value: undefined }),\n { once: true },\n );\n });\n try {\n for (;;) {\n const next = await Promise.race([iterator.next(), aborted]);\n if (next.done) return;\n yield next.value;\n }\n } finally {\n void iterator.return?.()?.catch(() => undefined);\n }\n}\n\n/**\n * Whether the agent's turn is over after `event`, given whether it was before:\n * a message starts one; a final output or a cancel ends it; a tool result\n * continues it. Anything else (a config change, say) changes nothing.\n */\nfunction turnOver(event: AgentEvent, over: boolean): boolean {\n switch (event.event_kind) {\n case \"agent_input\":\n if (event.input_kind === \"content\") return false;\n return event.input_kind === \"control\" ? true : over;\n case \"model_output\":\n return (\n event.stop_reason !== \"max_tokens\" &&\n !event.content_blocks.some((b) => b.type === \"tool_call\")\n );\n case \"tool_result\":\n return event.outcome === \"canceled\" ? over : false;\n default:\n return over;\n }\n}\n\nasync function accept409(call: () => Promise<unknown>): Promise<void> {\n try {\n await call();\n } catch (error) {\n if (statusOf(error) !== 409) throw error;\n }\n}\n","import { AbstractAgent } from \"@ag-ui/client\";\nimport type { BaseEvent, RunAgentInput } from \"@ag-ui/core\";\nimport { Observable } from \"rxjs\";\nimport { createOmnaraApi, type OmnaraApi } from \"./api\";\nimport { OmnaraRun } from \"./run\";\nimport type {\n BackendTool,\n OmnaraAgentConfig,\n OmnaraErrorContext,\n} from \"./types\";\n\n/**\n * An AG-UI agent backed by an Omnara agent. Each AG-UI thread gets its own\n * Omnara agent (per user), launched from a profile or an inline definition.\n * Omnara's log is the truth; each run restates the chat from it.\n */\nexport class OmnaraAgent extends AbstractAgent {\n private config: OmnaraAgentConfig;\n private api: OmnaraApi;\n private backendTools: Map<string, BackendTool>;\n private currentRun: OmnaraRun | null = null;\n\n /** `api` replaces the Omnara client (tests). */\n constructor(config: OmnaraAgentConfig, api?: OmnaraApi) {\n super(config);\n // Part of each thread's launch key. `AbstractAgent` would otherwise give\n // every instance a random one; CopilotKit sets its registered name.\n this.agentId ??= \"omnara\";\n if (Boolean(config.profile) === Boolean(config.definition)) {\n throw new Error(\n \"OmnaraAgent: give exactly one of `profile` and `definition`\",\n );\n }\n if (!config.user || (config.user !== \"anonymous\" && !config.user.id)) {\n throw new Error(\n 'OmnaraAgent: `user` is required (an `{ id }` from your auth, or \"anonymous\")',\n );\n }\n this.config = config;\n this.backendTools = new Map(\n (config.backendTools ?? []).map((t) => [t.name, t]),\n );\n if (api) {\n this.api = api;\n } else {\n const apiKey = config.apiKey ?? process.env.OMNARA_API_KEY;\n if (!apiKey)\n throw new Error(\"OmnaraAgent: set `apiKey` or OMNARA_API_KEY\");\n this.api = createOmnaraApi({\n apiKey,\n orgId: config.orgId,\n projectId: config.projectId,\n baseUrl: config.baseUrl,\n });\n }\n }\n\n /** `super.clone()` keeps the AbstractAgent state; the Omnara client is shared. */\n public clone(): OmnaraAgent {\n const cloned = super.clone() as OmnaraAgent;\n cloned.config = this.config;\n cloned.api = this.api;\n cloned.backendTools = this.backendTools;\n cloned.currentRun = null;\n return cloned;\n }\n\n /** Stop: cancels the agent's current work and its running subagents, and ends the run as cancelled. */\n public abortRun(): void {\n this.currentRun?.stop();\n }\n\n run(input: RunAgentInput): Observable<BaseEvent> {\n return new Observable<BaseEvent>((subscriber) => {\n const run = new OmnaraRun(\n {\n api: this.api,\n config: this.config,\n aguiAgentId: this.agentId!,\n backendTools: this.backendTools,\n report: (error, context) => this.report(error, context),\n },\n input,\n (event) => subscriber.next(event),\n );\n this.currentRun = run;\n run\n .execute()\n .catch((error) =>\n this.report(error, { operation: \"run\", threadId: input.threadId }),\n )\n .finally(() => {\n if (this.currentRun === run) this.currentRun = null;\n subscriber.complete();\n });\n // Unsubscribing (a closed tab) never cancels the Omnara agent.\n return () => run.detach();\n });\n }\n\n private async report(\n error: unknown,\n context: OmnaraErrorContext,\n ): Promise<void> {\n try {\n if (this.config.onError) await this.config.onError(error, context);\n else console.error(`[@ag-ui/omnara] ${context.operation}`, error);\n } catch {\n // A broken hook must not break the run.\n }\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,70 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ag-ui/omnara",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "AG-UI integration for Omnara (hosted, durable agents)",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/ag-ui-protocol/ag-ui.git",
|
|
9
|
+
"directory": "integrations/community/omnara/typescript"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [
|
|
12
|
+
"ag-ui",
|
|
13
|
+
"omnara",
|
|
14
|
+
"copilotkit",
|
|
15
|
+
"agents",
|
|
16
|
+
"ai"
|
|
17
|
+
],
|
|
18
|
+
"main": "./dist/index.js",
|
|
19
|
+
"module": "./dist/index.mjs",
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"sideEffects": false,
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=22.12"
|
|
24
|
+
},
|
|
25
|
+
"private": false,
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public"
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"dist/**",
|
|
31
|
+
"README.md"
|
|
32
|
+
],
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@omnara/sdk": "^0.1.26",
|
|
35
|
+
"rxjs": "7.8.1",
|
|
36
|
+
"yaml": "^2.8.4"
|
|
37
|
+
},
|
|
38
|
+
"peerDependencies": {
|
|
39
|
+
"@ag-ui/core": ">=1.0.0",
|
|
40
|
+
"@ag-ui/client": ">=1.0.0"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@types/node": "^20.11.19",
|
|
44
|
+
"publint": "^0.3.12",
|
|
45
|
+
"@arethetypeswrong/cli": "^0.17.4",
|
|
46
|
+
"vitest": "^4.0.18",
|
|
47
|
+
"tsdown": "^0.20.1",
|
|
48
|
+
"typescript": "^5.3.3",
|
|
49
|
+
"@ag-ui/core": "1.0.3",
|
|
50
|
+
"@ag-ui/client": "1.0.3"
|
|
51
|
+
},
|
|
52
|
+
"exports": {
|
|
53
|
+
".": {
|
|
54
|
+
"require": "./dist/index.js",
|
|
55
|
+
"import": "./dist/index.mjs"
|
|
56
|
+
},
|
|
57
|
+
"./package.json": "./package.json"
|
|
58
|
+
},
|
|
59
|
+
"scripts": {
|
|
60
|
+
"build": "tsdown",
|
|
61
|
+
"dev": "tsdown --watch",
|
|
62
|
+
"clean": "git clean -fdX --exclude=\"!.env\"",
|
|
63
|
+
"typecheck": "tsc --noEmit",
|
|
64
|
+
"test": "vitest run",
|
|
65
|
+
"test:watch": "vitest",
|
|
66
|
+
"test:exports": "publint --strict && attw --pack",
|
|
67
|
+
"link:global": "pnpm link --global",
|
|
68
|
+
"unlink:global": "pnpm unlink --global"
|
|
69
|
+
}
|
|
6
70
|
}
|