marona 2.0.0
marona: ^2.0.0 copied to clipboard
Universal Model Gateway and MCP/Skill SDK with mandatory project-scoped Marona authentication.
Marona Dart 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.
Dart 3.10+. This is a server or command line example, not a Flutter Web example.
dart pub add 'marona:^2.0.0'
Set 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 example/agent_example.dart. 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 'dart:convert';
import 'dart:io';
import 'package:marona/marona.dart';
Future<void> main(List<String> args) async {
final marona = Marona(
apiKey: Platform.environment['MARONA_API_KEY'],
baseUrl:
Platform.environment['MARONA_RUNTIME_URL'] ?? 'https://edge.marona.ai',
);
try {
final agent = Agent(
name: 'Document Assistant',
model:
Platform.environment['MARONA_MODEL'] ??
'marona/qwen-qwen3.8-max-0902',
instructions: 'Answer clearly and concisely.',
toolChoice: 'none',
);
Object input = 'Reply with exactly OK.';
if (args.isNotEmpty) {
final file = File(args.first);
final extension = file.path.split('.').last.toLowerCase();
final mime = {
'png': 'image/png',
'jpg': 'image/jpeg',
'jpeg': 'image/jpeg',
}[extension];
if (mime == null) throw ArgumentError('Use a PNG or JPEG image.');
final dataUrl =
'data:$mime;base64,${base64Encode(await file.readAsBytes())}';
input = [
{
'role': 'user',
'content': [
{
'type': 'input_text',
'text': 'Describe this image and transcribe any visible text.',
},
{'type': 'input_image', 'image_url': dataUrl},
],
},
];
}
final result = await Runner.run(
agent,
input,
userId: 'example-user',
sessionId: 'example-session',
);
print(result.output);
} finally {
marona.close();
}
}
dart run example/agent_example.dart
dart run example/agent_example.dart image.png
Encode 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.
final agent = 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,
},
);
final result = await Runner.run(agent, documentInput, userId: 'user-123');
print(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 #
final page = await marona.apps.list(userId: 'user-123', limit: 20);
final 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 'dart:io';
import 'package:marona/marona.dart';
final peer = A2APeer(name: 'reviewer', url: 'https://reviewer.example.com');
final agent = Agent(name: 'Coordinator', peers: [peer]);
final server = A2AServer(
agent: agent,
url: 'https://coordinator.example.com',
skills: [{'id': 'review', 'name': 'Review', 'description': 'Review a document'}],
apiKey: Platform.environment['A2A_SERVER_KEY'],
taskStore: A2ATaskStore(directory: './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.
Server hosting requires Dart IO. 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.