marona
v2.0.0
Published
Universal Model Gateway and MCP/Skill SDK with mandatory project-scoped Marona authentication.
Readme
Marona TypeScript SDK
Run Agents through one managed API, with structured output, local tools, Hub capabilities, streaming, realtime and A2A collaboration.
Install
Version 2.0.0. Package registry.
Node.js 20+; run this server example with tsx.
npm install [email protected]
npm install --save-dev typescript tsx @types/nodeSet MARONA_API_KEY in your backend environment. Never commit it, log it,
or embed a developer key in browser or mobile code. Use an exact accessible
marona/* model alias from Marona Platform.
Agent quickstart
Save as examples/agent_example.mts. Run without arguments for text, or with a real
PNG/JPEG path for document extraction. Use stable application user IDs and a
distinct session ID for each conversation.
import { readFile } from "node:fs/promises";
import { extname } from "node:path";
import { Agent, Marona, Runner } from "marona";
new Marona({
apiKey: process.env.MARONA_API_KEY,
baseUrl: process.env.MARONA_RUNTIME_URL ?? "https://edge.marona.ai",
});
const agent = new Agent({
name: "Document Assistant",
model: process.env.MARONA_MODEL ?? "marona/qwen-qwen3.8-max-0902",
instructions: "Answer clearly and concisely.",
toolChoice: "none",
});
const path = process.argv[2];
const mimeTypes: Record<string, string> = {
".png": "image/png", ".jpg": "image/jpeg", ".jpeg": "image/jpeg",
};
const mime = path ? mimeTypes[extname(path).toLowerCase()] : undefined;
if (path && !mime) throw new Error("Use a PNG or JPEG image.");
const input = path ? [{
role: "user",
content: [
{ type: "input_text", text: "Describe this image and transcribe any visible text." },
{ type: "input_image", image_url: `data:${mime};base64,${(await readFile(path)).toString("base64")}` },
],
}] : "Reply with exactly OK.";
const result = await Runner.run(agent, input, {
userId: "example-user", sessionId: "example-session",
});
console.log(result.output);npx tsx examples/agent_example.mts
npx tsx examples/agent_example.mts image.pngEncode actual file bytes with standard Base64. Image and file blocks accept
raw Base64 in image_data / file_data, or complete matching data URLs.
Do not encode a path, encode twice, or send placeholder data. Remote URLs must
be reachable by the runtime. PDF, audio and realtime support depend on the
selected model; render PDF pages to images when native PDF is unavailable.
Structured output through Agent
The following fragment uses the authenticated client from the quickstart.
documentInput is your text or document message input.
import { Agent, Runner } from "marona";
const agent = new Agent({
name: "Document Reader",
model: "marona/qwen-qwen3.8-max-0902",
instructions: "Extract the document text.",
outputSchemaStrict: true,
outputSchema: {
type: "object",
properties: { text: { type: "string" } },
required: ["text"],
additionalProperties: false,
},
});
const result = await Runner.run(agent, documentInput, { userId: "user-123" });
console.log(result.output);The explicit strict option asks the provider to enforce the supplied schema; the SDK also validates the final result before returning it. Strict mode requires a compatible model and schema. Declare every object property as required, use nullable values for optional fields, and set additionalProperties to false. Unsupported model capabilities or invalid output produce errors; they do not silently fall back to unstructured text. Input schemas, function tool schemas, guardrails, dynamic instructions and lifecycle hooks are also supported.
Apps and user connections
const page = await marona.apps.list({ userId: "user-123", limit: 20 });
const action = await marona.apps.connect("calendar", { userId: "user-123" });
// Complete any returned authorization_url before calling protected tools.
await marona.apps.disconnect("calendar");Listing an App does not authorize its protected operations. Follow the returned
connection action for the end user. Use hub.connect to expose a scoped set of
App or Skill capabilities to an Agent; Apps authorization and Hub tool discovery
are separate operations.
A2A collaboration and serving
import { A2APeer, A2AServer, A2ATaskStore, Agent } from "marona";
const peer = new A2APeer({ name: "reviewer", url: "https://reviewer.example.com" });
const agent = new Agent({ name: "Coordinator", peers: [peer] });
const server = new A2AServer({
agent,
url: "https://coordinator.example.com",
skills: [{ id: "review", name: "Review", description: "Review a document" }],
apiKey: process.env.A2A_SERVER_KEY,
taskStore: new A2ATaskStore("./data/a2a-tasks"),
});
await server.listen({ host: "127.0.0.1", port: 8100 });
// Call await server.close() during graceful shutdown.Peers support Agent Card discovery, REST/JSON-RPC messages, task retrieval, cancellation, continuation and streamed task events. Servers persist task state. Use explicit credentials, restricted skills, HTTPS, and an appropriate durable task directory for production. Local JSON stores are for a single service instance; multi-instance deployments require coordinated task storage.
The listener and durable file store require Node. Fetch handlers can use an injected platform task store. Push notifications are not implemented.
Execution and errors
Use Runner.stream for streamed Agent events and
RealtimeRunner for a live session. Delegation and handoffs use explicit Agent
graphs. Set execution limits and validate permissions before tools with side
effects; cancellation cannot roll back an operation that has already executed.
Inspect the canonical error code, HTTP status, request ID and retry metadata. Correct invalid input and authorization errors before retrying. Use bounded retries for transient failures. Never include credentials or document content in error reports.
See Platform documentation for language
specific examples and migration guidance. These files are generated from
docs/client-sdk-guides.json; verify them with
python scripts/sync_client_sdk_docs.py --check.
