SDK Reference Guide
This comprehensive guide covers the Maitento .NET SDK, providing everything you need to programmatically interact with the Maitento platform. The SDK offers an async-first API for managing AI agents, applications, interactions, capsules, virtual file systems, and real-time notifications.
Table of Contents
- SDK Overview
- Getting Started
- Services Summary
- Real-Time Notifications
- Virtual File System Operations
- File and Partition Operations
- Complete Code Examples
- Error Handling
1. SDK Overview
Architecture
The Maitento SDK is built around a central client class (MaitentoClient) that provides access to all platform services through dedicated service interfaces. Each service handles a specific domain of functionality.
IMaitentoClient
|
+-- IAiModelService (AI models)
+-- IAgentService (AI agents)
+-- IAppService (Applications)
+-- IInteractionService (Multi-agent workflows)
+-- IInteractionProcessService (Interaction execution)
+-- ICapsuleService (Container definitions)
+-- ICapsuleProcessService (Container instances)
+-- IVirtualFileSystemService (VFS operations)
+-- IFileService (File management)
+-- IPartitionService (Storage partitions)
+-- INotificationClient (Real-time WebSocket)
+-- ISecretService (Secret management)
+-- IConnectorService (External API connectors)
+-- IAutomatedActionService (Scheduled automation)
+-- ... (additional services)
Key Features
- Async-First API: All operations are asynchronous with proper cancellation token support
- Multiple Authentication Methods: API key, JWT credentials, or pre-existing tokens
- Real-Time Notifications: WebSocket-based notifications with automatic reconnection
- Comprehensive VFS Operations: 60+ methods for file system manipulation
- Semantic Search: Built-in embeddings generation and similarity search
- Dependency Injection Support: Seamless ASP.NET Core integration
- Automatic Token Refresh: JWT tokens are refreshed automatically before expiration
- Configurable Retry Policies: Built-in retry logic for transient failures
Requirements
- .NET 8.0 or later
- NuGet Package:
Maitento.Sdk
2. Getting Started
Installation
Install the SDK via NuGet:
dotnet add package Maitento.Sdk
Authentication Methods
The SDK supports three authentication methods:
API Key Authentication (Recommended for Server-to-Server)
var client = MaitentoClient.CreateWithApiKey(
"your-client-id",
"your-client-secret"
);
Username/Password Authentication
var client = MaitentoClient.CreateWithCredentials(
"user@example.com",
"your-password"
);
Pre-Existing JWT Token
var client = MaitentoClient.CreateWithJwtToken(
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
);
Client Initialization
Using Factory Methods (Simple)
using Maitento.Sdk;
// API key authentication
await using var client = MaitentoClient.CreateWithApiKey(
"your-client-id",
"your-client-secret"
);
// Make API calls
var namespaces = await client.Namespaces.GetAllAsync();
Using Constructor (Advanced)
using Maitento.Sdk;
var options = new MaitentoClientOptions
{
BaseUrl = "https://api.maitento.com",
ApiKeyClientId = "your-client-id",
ApiKeyClientSecret = "your-client-secret",
Timeout = TimeSpan.FromMinutes(2),
RetryPolicyMaxAttempts = 3,
RetryPolicyDelay = TimeSpan.FromSeconds(2)
};
using var httpClient = new HttpClient();
using var loggerFactory = LoggerFactory.Create(builder =>
{
builder.AddConsole().SetMinimumLevel(LogLevel.Debug);
});
await using var client = new MaitentoClient(options, httpClient, loggerFactory);
Dependency Injection
For ASP.NET Core applications, use the built-in DI extension:
using Maitento.Sdk.Extensions;
public void ConfigureServices(IServiceCollection services)
{
services.AddMaitentoClient(options =>
{
options.BaseUrl = "https://api.maitento.com";
options.ApiKeyClientId = Configuration["Maitento:ClientId"];
options.ApiKeyClientSecret = Configuration["Maitento:ClientSecret"];
options.Timeout = TimeSpan.FromMinutes(2);
options.RetryPolicyMaxAttempts = 3;
});
}
// Inject into your services
public class MyService
{
private readonly IMaitentoClient _client;
public MyService(IMaitentoClient maitentoClient)
{
_client = maitentoClient;
}
public async Task DoWorkAsync()
{
var namespaces = await _client.Namespaces.GetAllAsync();
// ...
}
}
Configuration Options
The MaitentoClientOptions class provides comprehensive configuration:
| Property | Type | Default | Description |
|---|---|---|---|
BaseUrl | string | https://api.maitento.com | API endpoint URL |
ApiKeyClientId | string? | null | API key client identifier |
ApiKeyClientSecret | string? | null | API key client secret |
Username | string? | null | Email for JWT auth |
Password | string? | null | Password for JWT auth |
JwtToken | string? | null | Pre-existing JWT token |
Timeout | TimeSpan | 5 minutes | HTTP request timeout |
RetryPolicyMaxAttempts | int | 1 | Maximum retry attempts |
RetryPolicyDelay | TimeSpan | 1 second | Delay between retries |
NotificationReconnectTimeout | TimeSpan | 30 seconds | WebSocket reconnect timeout |
NotificationErrorReconnectTimeout | TimeSpan | 2 seconds | Reconnect timeout after error |
NotificationServerPingTimeout | TimeSpan | 30 seconds | Server ping timeout |
3. Services Summary
Core Services
INamespaceService
Organize resources into logical namespaces.
Task<Namespace[]> GetAllAsync(CancellationToken cancellationToken = default);
Task<Namespace?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default);
Task<Namespace?> GetByNameAsync(string name, CancellationToken cancellationToken = default);
Task<Namespace> CreateAsync(string name, CancellationToken cancellationToken = default);
Task<Namespace> UpdateAsync(Guid id, string name, CancellationToken cancellationToken = default);
IAiModelService
Access available AI models.
Task<AiModel[]> GetAllAsync(CancellationToken cancellationToken = default);
IApiKeyService
Manage API keys for authentication.
Task<UserApiKey[]> GetAllAsync(CancellationToken cancellationToken = default);
Task<UserApiCreateResponse> CreateAsync(string name, DateTime? dateExpires = null, CancellationToken cancellationToken = default);
Task DisableAsync(Guid id, CancellationToken cancellationToken = default);
ISecretService
Secure secret storage.
Task<Secret[]> GetAllAsync(CancellationToken cancellationToken = default);
Task<Secret?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default);
Task<Secret?> GetByNameAsync(string name, CancellationToken cancellationToken = default);
Task<string> GetValueByNameAsync(string name, CancellationToken cancellationToken = default);
Task<Secret> CreateAsync(string name, string value, CancellationToken cancellationToken = default);
Task<Secret> UpdateAsync(Guid id, string name, string? value = null, CancellationToken cancellationToken = default);
Task DeleteAsync(Guid id, CancellationToken cancellationToken = default);
Agent and Interaction Services
IAgentService
Create and manage AI agents.
Task<Agent[]> GetAllAsync(CancellationToken cancellationToken = default);
Task<Agent[]> GetAllInNamespaceAsync(string namespaceName, CancellationToken cancellationToken = default);
Task<Agent?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default);
Task<Agent?> GetByNameAsync(string namespaceName, string name, CancellationToken cancellationToken = default);
Task<Agent> CreateAsync(string namespaceName, string name, Guid aiModelId, string systemPrompt, string summaryForOtherAgents, CancellationToken cancellationToken = default);
Task<Agent> UpdateAsync(Guid id, string name, Guid aiModelId, string systemPrompt, string summaryForOtherAgents, CancellationToken cancellationToken = default);
IInteractionService
Create multi-agent interaction workflows. Supports four types:
- RoundRobin: Agents take turns in a round-robin fashion
- OneShot: Single agent responds to a query
- Managed: Orchestrated by a manager agent
- Routed: Messages routed to specific agents
// Retrieval
Task<Interaction[]> GetAllAsync(CancellationToken cancellationToken = default);
Task<Interaction[]> GetAllInNamespaceAsync(string namespaceName, CancellationToken cancellationToken = default);
Task<Interaction?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default);
Task<Interaction?> GetByNameAsync(string namespaceName, string name, CancellationToken cancellationToken = default);
// Round Robin
Task<Interaction> CreateRoundRobinAsync(...);
Task<Interaction> UpdateRoundRobinAsync(...);
// One Shot
Task<Interaction> CreateOneShotAsync(...);
Task<Interaction> UpdateOneShotAsync(...);
// Managed
Task<Interaction> CreateManagedAsync(...);
Task<Interaction> UpdateManagedAsync(...);
// Routed
Task<Interaction> CreateRoutedAsync(...);
Task<Interaction> UpdateRoutedAsync(...);
IInteractionProcessService
Execute and participate in interactions.
Task<InteractionProcess[]> GetAllAsync(CancellationToken cancellationToken = default);
Task<InteractionProcess?> GetInstanceAsync(Guid id, CancellationToken cancellationToken = default);
Task<InteractionProcess> StartAsync(string namespaceName, string name, NameValuePair[] inputs, CancellationToken cancellationToken = default);
Task<InteractionProcess[]> GetAliveInNamespaceAsync(string namespaceName, CancellationToken cancellationToken = default);
Task AddMessageAsync(Guid id, string authorName, Guid authorId, string message, CancellationToken cancellationToken = default);
Task VoteYesAsync(Guid id, string authorName, Guid authorId, CancellationToken cancellationToken = default);
Task VoteNoAsync(Guid id, string authorName, Guid authorId, string reason, CancellationToken cancellationToken = default);
Process Services
IAppService
Manage applications and execution.
Task<App[]> GetAllAsync(CancellationToken cancellationToken = default);
Task<App[]> GetAllInNamespaceAsync(string namespaceName, CancellationToken cancellationToken = default);
Task<App?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default);
Task<App?> GetByNameAsync(string namespaceName, string name, CancellationToken cancellationToken = default);
Task<App> CreateAsync(string namespaceName, string name, CancellationToken cancellationToken = default);
Task<AppProcess?> GetProcessAsync(Guid processId, CancellationToken cancellationToken = default);
Task<AppProcess> StartAsync(Guid appId, string version, NameValuePair[] inputs, CancellationToken cancellationToken = default);
Task ProcessPatchInputs(Guid id, NameValuePair[] inputs, CancellationToken cancellationToken = default);
Task<AppProcess[]> GetAliveInNamespaceAsync(string namespaceName, CancellationToken cancellationToken = default);
ICapsuleProcessService
Manage containerized environment instances.
Task<CapsuleProcess[]> GetAllAsync(CancellationToken cancellationToken = default);
Task<CapsuleProcess[]> GetAliveInNamespaceAsync(string namespaceName, CancellationToken cancellationToken = default);
Task<CapsuleProcess?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default);
Task<CapsuleProcess> StartAsync(...);
Task TerminateAsync(Guid id, CancellationToken cancellationToken = default);
Task<RunCommandResponse> RunCommandAsync(Guid processId, RunCommandRequest request, CancellationToken cancellationToken = default);
// VFS mounting
Task MountVfsAsync(Guid processId, Guid vfsId, string path, CancellationToken cancellationToken = default);
Task UnmountVfsAsync(Guid processId, Guid vfsId, CancellationToken cancellationToken = default);
// Secret mounting
Task MountSecretAsync(Guid processId, Guid secretId, string path, CancellationToken cancellationToken = default);
Task UnmountSecretAsync(Guid processId, Guid secretId, CancellationToken cancellationToken = default);
// User and package management
Task AddUserAsync(Guid processId, string username, CancellationToken cancellationToken = default);
Task RemoveUserAsync(Guid processId, string username, CancellationToken cancellationToken = default);
Task InstallPackageAsync(Guid processId, string packageName, CancellationToken cancellationToken = default);
Task RemovePackageAsync(Guid processId, string packageName, CancellationToken cancellationToken = default);
ICodeGenerationProcessService
AI-powered code generation.
Task<CodeGenerationProcess> StartAsync(...);
Task<CodeGenerationProcess[]> GetAllAsync(CancellationToken cancellationToken = default);
Task<CodeGenerationProcess[]> GetAlive(CancellationToken cancellationToken = default);
Task<CodeGenerationProcess?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default);
Task UpdateCredentialsAsync(Guid id, string username, string password, CancellationToken cancellationToken = default);
Task UpdateClaudeAuthentication(Guid id, string apiKey, CancellationToken cancellationToken = default);
IProcessService
Generic process management.
Task KillAsync(Guid processId, ProcessType processType, CancellationToken cancellationToken = default);
Infrastructure Services
IAutomatedActionService
Configure scheduled tasks and message-triggered automations.
// CRUD
Task<AutomatedAction[]> GetAllAsync(CancellationToken cancellationToken = default);
Task<AutomatedAction[]> GetAllInNamespaceAsync(string namespaceName, CancellationToken cancellationToken = default);
Task<AutomatedAction?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default);
Task<AutomatedAction?> GetByNameAsync(string namespaceName, string name, CancellationToken cancellationToken = default);
Task<AutomatedAction> CreateAsync(string namespaceName, string name, string? description, AutomatedActionItem[] actions, CancellationToken cancellationToken = default);
Task<AutomatedAction> UpdateAsync(Guid id, string name, string? description, AutomatedActionItem[] actions, CancellationToken cancellationToken = default);
Task DeleteAsync(Guid id, CancellationToken cancellationToken = default);
// Schedule management
Task<AutomatedAction> AddScheduleAsync(Guid id, CronSchedule schedule, CancellationToken cancellationToken = default);
Task<AutomatedAction> UpdateScheduleAsync(Guid id, Guid scheduleId, CronSchedule schedule, CancellationToken cancellationToken = default);
Task<AutomatedAction> RemoveScheduleAsync(Guid id, Guid scheduleId, CancellationToken cancellationToken = default);
Task<AutomatedAction> EnableScheduleAsync(Guid id, Guid scheduleId, CancellationToken cancellationToken = default);
Task<AutomatedAction> DisableScheduleAsync(Guid id, Guid scheduleId, CancellationToken cancellationToken = default);
// Message trigger management
Task<AutomatedAction> AddMessageTriggerAsync(Guid id, MessageTrigger trigger, CancellationToken cancellationToken = default);
Task<AutomatedAction> UpdateMessageTriggerAsync(Guid id, Guid triggerId, MessageTrigger trigger, CancellationToken cancellationToken = default);
Task<AutomatedAction> RemoveMessageTriggerAsync(Guid id, Guid triggerId, CancellationToken cancellationToken = default);
Task<AutomatedAction> EnableMessageTriggerAsync(Guid id, Guid triggerId, CancellationToken cancellationToken = default);
Task<AutomatedAction> DisableMessageTriggerAsync(Guid id, Guid triggerId, CancellationToken cancellationToken = default);
// Execution
Task<Guid> TriggerAsync(Guid id, CancellationToken cancellationToken = default);
Task<ExecutionHistoryEntry[]> GetHistoryAsync(Guid id, int limit = 50, CancellationToken cancellationToken = default);
IConnectorService
Manage external API integrations.
Task<Connector[]> GetAllAsync(CancellationToken cancellationToken = default);
Task<Connector[]> GetAllInNamespaceAsync(string namespaceName, CancellationToken cancellationToken = default);
Task<Connector?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default);
Task<Connector?> GetByNameAsync(string namespaceName, string name, CancellationToken cancellationToken = default);
Task<McpConnector> CreateMcpAsync(string namespaceName, bool? destructiveHint, bool? idempotentHint, bool? openWorldHint, bool? readOnlyHint, string name, string url, string description, string? requestSchemaJson, string? responseSchemaJson, ConnectorAuthenticationType authenticationType, bool postProcessResponseUnicodeCharacters, CancellationToken cancellationToken = default);
Task<OpenApiConnector> CreateOpenApiAsync(string namespaceName, HttpMethod httpMethod, OpenApiParameter[] pathParameters, OpenApiParameter[] queryParameters, string name, string url, string description, string? requestSchemaJson, string? responseSchemaJson, ConnectorAuthenticationType authenticationType, bool postProcessResponseUnicodeCharacters, CancellationToken cancellationToken = default);
Task DeleteByIdAsync(Guid id, CancellationToken cancellationToken = default);
IWebHookService
Configure webhook notifications.
Task<WebHookRegistration[]> GetAllAsync(CancellationToken cancellationToken = default);
Task<WebHookRegistration?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default);
Task<WebHookRegistration> CreateAsync(WebHookType type, string url, string secret, Dictionary<string, string> headers, CancellationToken cancellationToken = default);
Task<WebHookRegistration> UpdateAsync(Guid id, string url, string? secret, Dictionary<string, string> headers, CancellationToken cancellationToken = default);
Task DeleteAsync(Guid id, CancellationToken cancellationToken = default);
4. Real-Time Notifications
The SDK provides a WebSocket-based notification system for receiving real-time updates from the platform.
WebSocket Connection
Starting the Connection
// Start the notification client
await client.Notifications.StartAsync();
// Check connection status
if (client.Notifications.IsConnected)
{
Console.WriteLine("Connected to notifications");
}
Stopping the Connection
await client.Notifications.StopAsync();
Subscribing to Events
// Subscribe to all app process updates
var subscription = client.Notifications.Subscribe(myHandler);
// Subscribe to a specific process only
var filteredSubscription = client.Notifications.Subscribe(
myHandler,
filterId: specificProcessId
);
// Unsubscribe when done
client.Notifications.Unsubscribe(subscription);
Handler Interfaces
Implement these interfaces to receive specific notification types:
INotificationClientHandlerAppProcessUpdated
public class AppProcessHandler : INotificationClientHandlerAppProcessUpdated
{
public Task OnAppProcessUpdated(AppProcess process)
{
Console.WriteLine($"App process {process.Id}: {process.Status}");
return Task.CompletedTask;
}
}
INotificationClientHandlerCodeGenerationProcessUpdated
public class CodeGenHandler : INotificationClientHandlerCodeGenerationProcessUpdated
{
public Task OnCodeGenerationProcessUpdated(CodeGenerationProcess process)
{
Console.WriteLine($"Code generation {process.Id}: {process.Status}");
return Task.CompletedTask;
}
}
INotificationClientHandlerInteractionProcessUpdated
public class InteractionHandler : INotificationClientHandlerInteractionProcessUpdated
{
public Task OnInteractionProcessUpdated(InteractionProcess process)
{
Console.WriteLine($"Interaction {process.Id}: {process.Status}");
return Task.CompletedTask;
}
}
INotificationClientHandlerCapsuleProcessUpdated
public class CapsuleHandler : INotificationClientHandlerCapsuleProcessUpdated
{
public Task OnCapsuleProcessUpdated(CapsuleProcess process)
{
Console.WriteLine($"Capsule process {process.Id}: {process.Status}");
return Task.CompletedTask;
}
}
INotificationClientHandlerIngestedFileUpdated
public class FileHandler : INotificationClientHandlerIngestedFileUpdated
{
public Task OnIngestedFileUpdated(IngestedFile file)
{
Console.WriteLine($"File {file.Name}: {file.Status}");
return Task.CompletedTask;
}
}
INotificationClientHandlerInteractionStream
public class StreamHandler : INotificationClientHandlerInteractionStream
{
private readonly StringBuilder _buffer = new();
public Task OnInteractionStream(InteractionStreamUserNotification notification)
{
_buffer.Append(notification.Stream);
Console.Write(notification.Stream); // Real-time output
return Task.CompletedTask;
}
}
Connection Management
Connection Events
client.Notifications.Connected += (sender, args) =>
{
Console.WriteLine("Connected to notification server");
};
client.Notifications.Disconnected += (sender, args) =>
{
Console.WriteLine($"Disconnected: {args.DisconnectionType}");
if (args.Exception != null)
{
Console.WriteLine($"Error: {args.Exception.Message}");
}
Console.WriteLine("Automatic reconnection will be attempted...");
};
Reconnection Behavior
The notification client includes automatic reconnection logic:
- When disconnection occurs, the
Disconnectedevent fires - Automatic reconnection attempts begin using configured timeouts
- On success, the
Connectedevent fires - All subscriptions remain active (handlers are preserved)
5. Virtual File System Operations
The VFS service provides comprehensive file system operations for virtual file systems that are isolated and namespace-scoped.
VFS Management
Creating and Retrieving VFS
// Get all VFS
VirtualFileSystem[] allVfs = await client.VirtualFileSystems.GetAllAsync();
// Get VFS in a namespace
VirtualFileSystem[] namespaceVfs = await client.VirtualFileSystems
.GetAllInNamespaceAsync("production");
// Get by ID or name
VirtualFileSystem? vfs = await client.VirtualFileSystems.GetByIdAsync(vfsId);
VirtualFileSystem? vfs = await client.VirtualFileSystems
.GetByNameAsync("production", "app-storage");
// Create a new VFS
VirtualFileSystem newVfs = await client.VirtualFileSystems
.CreateAsync("development", "test-storage");
Destroying VFS
// By ID (irreversible)
await client.VirtualFileSystems.DestroyByIdAsync(vfsId);
// By name (irreversible)
await client.VirtualFileSystems.DestroyByNameAsync("development", "test-storage");
File Operations
All file operations have both ById and ByName variants.
Writing Files
// Write text
FileSystemFile file = await client.VirtualFileSystems
.WriteTextById(vfsId, "/config/settings.json", jsonContent);
// Write lines
string[] lines = new[] { "line1", "line2", "line3" };
FileSystemFile file = await client.VirtualFileSystems
.WriteLinesById(vfsId, "/logs/app.log", lines);
// Write binary
byte[] imageData = await File.ReadAllBytesAsync("logo.png");
FileSystemFile file = await client.VirtualFileSystems
.WriteBytesById(vfsId, "/assets/logo.png", imageData);
Reading Files
// Read text
string content = await client.VirtualFileSystems
.ReadTextById(vfsId, "/config/settings.json");
// Read lines
string[] lines = await client.VirtualFileSystems
.ReadLinesById(vfsId, "/logs/app.log");
// Read binary
FileContent imageContent = await client.VirtualFileSystems
.ReadBytesById(vfsId, "/assets/logo.png");
await File.WriteAllBytesAsync("downloaded.png", imageContent.Content);
Appending to Files
// Append text
await client.VirtualFileSystems
.AppendTextById(vfsId, "/logs/app.log", "\nNew log entry");
// Append lines
string[] newLines = new[] { "entry1", "entry2" };
await client.VirtualFileSystems
.AppendLinesById(vfsId, "/logs/app.log", newLines);
File Management
// Check if file exists
bool exists = await client.VirtualFileSystems
.ExistsFileById(vfsId, "/config/settings.json");
// Delete file
await client.VirtualFileSystems
.DeleteFileById(vfsId, "/temp/cache.dat");
// Copy file
FileSystemEntry copied = await client.VirtualFileSystems
.CopyById(vfsId, "/config/settings.json", "/config/settings.backup.json");
// Move/rename file
FileSystemEntry moved = await client.VirtualFileSystems
.MoveById(vfsId, "/docs/draft.md", "/docs/final.md");
Directory Operations
// Create directory
FileSystemDirectory dir = await client.VirtualFileSystems
.CreateDirectoryById(vfsId, "/data/exports/2024");
// Check if directory exists
bool exists = await client.VirtualFileSystems
.ExistsDirectoryById(vfsId, "/config");
// List directory contents
FileSystemEntry[] entries = await client.VirtualFileSystems
.ListById(vfsId, "/");
foreach (var entry in entries)
{
if (entry is FileSystemFile file)
Console.WriteLine($"File: {file.Name} ({file.Size} bytes)");
else if (entry is FileSystemDirectory dir)
Console.WriteLine($"Directory: {dir.Name}/");
}
// Delete directory
await client.VirtualFileSystems
.DeleteDirectoryById(vfsId, "/temp", recursive: true);
Advanced Operations
Find (Search with Glob and Grep)
// Find all C# files
var findRequest = new FindRequest
{
Path = "/src",
Pattern = "**/*.cs",
MaxResults = 50
};
FindResponse results = await client.VirtualFileSystems.FindById(vfsId, findRequest);
// Find files containing "TODO"
var grepRequest = new FindRequest
{
Path = "/src",
Pattern = "**/*.cs",
Grep = "TODO",
IgnoreCase = true,
ContextLines = 2,
MaxResults = 100
};
FindResponse todos = await client.VirtualFileSystems.FindById(vfsId, grepRequest);
foreach (var result in todos.Results)
{
Console.WriteLine($"\n{result.Path}:");
foreach (var match in result.GrepMatches ?? Array.Empty<GrepMatch>())
{
Console.WriteLine($" Line {match.Line}: {match.Content}");
}
}
Edit (Programmatic File Modifications)
// Find and replace
var editRequest = new EditRequest
{
Path = "/config/settings.json",
Operations = new[]
{
new EditOperation
{
Type = "replace",
Find = "\"debug\": true",
Replace = "\"debug\": false"
}
}
};
EditResponse result = await client.VirtualFileSystems.EditById(vfsId, editRequest);
// Replace all occurrences
var replaceAllRequest = new EditRequest
{
Path = "/src/module.cs",
Operations = new[]
{
new EditOperation
{
Type = "replace",
Find = "OldClassName",
Replace = "NewClassName",
ReplaceAll = true
}
}
};
await client.VirtualFileSystems.EditById(vfsId, replaceAllRequest);
// Insert after line
var insertRequest = new EditRequest
{
Path = "/src/file.cs",
Operations = new[]
{
new EditOperation
{
Type = "insertAfter",
InsertAfterLine = 10,
Content = " // New code inserted\n DoSomething();"
}
}
};
await client.VirtualFileSystems.EditById(vfsId, insertRequest);
Batch Operations
// Batch read multiple files
var batchReadRequest = new BatchReadRequest
{
Paths = new[] { "/config/settings.json", "/config/database.yaml", "/.env" },
MaxLinesPerFile = 500
};
BatchReadResponse readResult = await client.VirtualFileSystems.BatchReadById(vfsId, batchReadRequest);
// Atomic batch edit across multiple files
var batchEditRequest = new BatchEditRequest
{
Atomic = true, // All-or-nothing
Edits = new[]
{
new BatchEditFileRequest
{
Path = "/src/UserService.cs",
Operations = new[]
{
new EditOperation { Type = "replace", Find = "IUserRepository", Replace = "IUserDataStore", ReplaceAll = true }
}
},
new BatchEditFileRequest
{
Path = "/src/IUserRepository.cs",
Operations = new[]
{
new EditOperation { Type = "replace", Find = "interface IUserRepository", Replace = "interface IUserDataStore" }
}
}
}
};
BatchEditResponse editResult = await client.VirtualFileSystems.BatchEditById(vfsId, batchEditRequest);
Tree (Directory Structure)
var treeRequest = new TreeRequest
{
Path = "/",
MaxDepth = -1, // Unlimited
IncludeFiles = true,
IncludeHidden = false
};
TreeResponse tree = await client.VirtualFileSystems.TreeById(vfsId, treeRequest);
Console.WriteLine($"Total files: {tree.FileCount}");
Console.WriteLine($"Total directories: {tree.DirectoryCount}");
// Print tree structure
void PrintNode(TreeNode node, int indent = 0)
{
string prefix = new string(' ', indent * 2);
string icon = node.Type == "directory" ? "[D]" : "[F]";
Console.WriteLine($"{prefix}{icon} {node.Name}");
foreach (var child in node.Children)
PrintNode(child, indent + 1);
}
if (tree.Root != null)
PrintNode(tree.Root);
6. File and Partition Operations
Partition Management
Partitions are storage containers for organizing files and enabling scoped semantic search.
// Get all partitions
Partition[] partitions = await client.Partitions.GetAllAsync();
// Get by ID
Partition? partition = await client.Partitions.GetByIdAsync(partitionId);
// Create partition
Partition newPartition = await client.Partitions.CreateAsync("documents");
// Delete partition
await client.Partitions.DeleteAsync(partitionId);
File Ingestion
// Read file from disk
byte[] fileBytes = await File.ReadAllBytesAsync("document.pdf");
// Check for duplicates using checksum
string checksum = ComputeSha256(fileBytes);
IngestedFileSummary? existing = await client.Files.GetByChecksumAsync(checksum);
if (existing == null)
{
// Ingest the file
IngestedFile file = await client.Files.IngestFileAsync(
partitionId,
fileBytes,
"document.pdf",
"application/pdf"
);
Console.WriteLine($"Ingested: {file.Id}");
Console.WriteLine($"Vectors Ready: {file.IsVectorGenerated}");
}
File Operations
// Get file details
IngestedFile? details = await client.Files.GetDetailsAsync(fileId);
// Get extracted text
string? text = await client.Files.GetTextAsync(fileId);
// Download raw content
FileContent? content = await client.Files.GetRawContentAsync(fileId);
if (content != null)
{
await File.WriteAllBytesAsync(content.FileName, content.Content);
}
// Delete file
await client.Files.DeleteAsync(fileId);
Embeddings and Semantic Search
// Generate embeddings for text
string text = "This is a sample document about machine learning.";
float[] embedding = await client.Files.GenerateEmbeddingsAsync(text);
Console.WriteLine($"Generated {embedding.Length} dimensions");
// Split text into chunks (for large documents)
string longDocument = await File.ReadAllTextAsync("long-document.txt");
string[] chunks = await client.Files.GenerateChunksAsync(longDocument);
Console.WriteLine($"Split into {chunks.Length} chunks");
// Semantic search
string query = "What are the quarterly sales figures?";
EmbeddingsSearchResult[] results = await client.Files.SearchEmbeddingsAsync(partitionId, query);
foreach (var result in results)
{
Console.WriteLine($"Score: {result.Score:F4} - {result.Name}");
Console.WriteLine($" Matched: {result.Text.Substring(0, Math.Min(200, result.Text.Length))}...");
}
7. Complete Code Examples
Basic Client Usage
using Maitento.Sdk;
public async Task BasicUsageExample()
{
// Create client
await using var client = MaitentoClient.CreateWithApiKey(
"your-client-id",
"your-client-secret"
);
// List namespaces
var namespaces = await client.Namespaces.GetAllAsync();
foreach (var ns in namespaces)
{
Console.WriteLine($"Namespace: {ns.Name} (ID: {ns.Id})");
}
// Get available AI models
var models = await client.AiModels.GetAllAsync();
foreach (var model in models)
{
Console.WriteLine($"Model: {model.Name}");
}
}
Agent and Interaction Workflow
using Maitento.Sdk;
using Maitento.Entities;
public async Task CreateAgentAndInteraction()
{
await using var client = MaitentoClient.CreateWithApiKey("client-id", "client-secret");
// Get an AI model
var models = await client.AiModels.GetAllAsync();
var claudeModel = models.First(m => m.Name.Contains("claude"));
// Create an agent
var agent = await client.Agents.CreateAsync(
namespaceName: "my-namespace",
name: "research-assistant",
aiModelId: claudeModel.Id,
systemPrompt: "You are a helpful research assistant specializing in technical topics.",
summaryForOtherAgents: "Research assistant for technical queries"
);
Console.WriteLine($"Created agent: {agent.Id}");
// Create a one-shot interaction
var interaction = await client.Interactions.CreateOneShotAsync(
namespaceName: "my-namespace",
name: "quick-query",
agentId: agent.Id,
// ... other parameters
);
// Start an interaction process
var process = await client.InteractionProcesses.StartAsync(
namespaceName: "my-namespace",
name: "quick-query",
inputs: new[]
{
new NameValuePair { Name = "topic", Value = "Machine Learning" }
}
);
Console.WriteLine($"Started process: {process.Id}");
}
Real-Time Process Monitoring
using Maitento.Sdk;
using Maitento.Sdk.Notifications;
using Maitento.Entities.Apps;
public class ProcessMonitor :
INotificationClientHandlerAppProcessUpdated,
INotificationClientHandlerCodeGenerationProcessUpdated
{
private readonly List<NotificationSubscription> _subscriptions = new();
private readonly TaskCompletionSource<bool> _completion = new();
public async Task MonitorProcessesAsync(IMaitentoClient client, Guid processToWatch)
{
// Set up event handlers
client.Notifications.Connected += (s, e) =>
Console.WriteLine("Connected to notifications");
client.Notifications.Disconnected += (s, e) =>
Console.WriteLine($"Disconnected: {e.DisconnectionType}");
// Start notifications
await client.Notifications.StartAsync();
// Subscribe with filter for specific process
_subscriptions.Add(client.Notifications.Subscribe(
(INotificationClientHandlerAppProcessUpdated)this,
filterId: processToWatch));
// Wait for completion
await _completion.Task;
// Cleanup
foreach (var sub in _subscriptions)
client.Notifications.Unsubscribe(sub);
await client.Notifications.StopAsync();
}
public Task OnAppProcessUpdated(AppProcess process)
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] Process {process.Id}: {process.Status}");
if (process.Status == ProcessStatus.Completed || process.Status == ProcessStatus.Failed)
{
_completion.TrySetResult(process.Status == ProcessStatus.Completed);
}
return Task.CompletedTask;
}
public Task OnCodeGenerationProcessUpdated(CodeGenerationProcess process)
{
Console.WriteLine($"[CODEGEN] {process.Id}: {process.Status}");
return Task.CompletedTask;
}
}
// Usage
var client = MaitentoClient.CreateWithApiKey("id", "secret");
var monitor = new ProcessMonitor();
await monitor.MonitorProcessesAsync(client, processId);
Document Search Application
using Maitento.Sdk;
using Maitento.Entities.IngestedFiles;
public class DocumentSearchService
{
private readonly IMaitentoClient _client;
private readonly Guid _partitionId;
public DocumentSearchService(IMaitentoClient client, Guid partitionId)
{
_client = client;
_partitionId = partitionId;
}
public async Task<IngestedFile> UploadDocumentAsync(string filePath)
{
byte[] content = await File.ReadAllBytesAsync(filePath);
string fileName = Path.GetFileName(filePath);
string contentType = GetContentType(fileName);
// Check for duplicates
string checksum = ComputeChecksum(content);
var existing = await _client.Files.GetByChecksumAsync(checksum);
if (existing != null)
{
throw new InvalidOperationException($"File already exists: {existing.Name}");
}
// Ingest
return await _client.Files.IngestFileAsync(_partitionId, content, fileName, contentType);
}
public async Task<IEnumerable<SearchResult>> SearchAsync(string query)
{
var results = await _client.Files.SearchEmbeddingsAsync(_partitionId, query);
return results.Select(r => new SearchResult
{
FileId = r.Id,
FileName = r.Name,
Score = r.Score,
MatchedText = r.Text
});
}
public async Task<byte[]?> DownloadAsync(Guid fileId)
{
var content = await _client.Files.GetRawContentAsync(fileId);
return content?.Content;
}
private static string GetContentType(string fileName)
{
var ext = Path.GetExtension(fileName).ToLowerInvariant();
return ext switch
{
".pdf" => "application/pdf",
".docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
".txt" => "text/plain",
".md" => "text/markdown",
".json" => "application/json",
_ => "application/octet-stream"
};
}
private static string ComputeChecksum(byte[] content)
{
using var sha256 = System.Security.Cryptography.SHA256.Create();
return Convert.ToBase64String(sha256.ComputeHash(content));
}
}
public class SearchResult
{
public Guid FileId { get; set; }
public string FileName { get; set; } = "";
public double Score { get; set; }
public string MatchedText { get; set; } = "";
}
Virtual File System Management
using Maitento.Sdk;
public class VfsManager
{
private readonly IMaitentoClient _client;
public VfsManager(IMaitentoClient client)
{
_client = client;
}
public async Task<Guid> CreateProjectStructureAsync(string namespaceName, string vfsName)
{
// Create VFS
var vfs = await _client.VirtualFileSystems.CreateAsync(namespaceName, vfsName);
// Create directory structure
await _client.VirtualFileSystems.CreateDirectoryById(vfs.Id, "/src");
await _client.VirtualFileSystems.CreateDirectoryById(vfs.Id, "/src/services");
await _client.VirtualFileSystems.CreateDirectoryById(vfs.Id, "/src/models");
await _client.VirtualFileSystems.CreateDirectoryById(vfs.Id, "/tests");
await _client.VirtualFileSystems.CreateDirectoryById(vfs.Id, "/docs");
await _client.VirtualFileSystems.CreateDirectoryById(vfs.Id, "/config");
// Create initial files
await _client.VirtualFileSystems.WriteTextById(vfs.Id, "/README.md", "# Project\n\nProject documentation.");
await _client.VirtualFileSystems.WriteTextById(vfs.Id, "/config/settings.json", "{\n \"debug\": true\n}");
return vfs.Id;
}
public async Task<string> GetProjectTreeAsync(Guid vfsId)
{
var tree = await _client.VirtualFileSystems.TreeById(vfsId, new TreeRequest
{
Path = "/",
MaxDepth = -1,
IncludeFiles = true
});
var sb = new StringBuilder();
sb.AppendLine($"Files: {tree.FileCount}, Directories: {tree.DirectoryCount}");
foreach (var entry in tree.Entries)
{
var indent = new string(' ', entry.Depth * 2);
var icon = entry.Type == "directory" ? "[D]" : "[F]";
sb.AppendLine($"{indent}{icon} {entry.Path}");
}
return sb.ToString();
}
public async Task<FindResponse> SearchCodeAsync(Guid vfsId, string pattern)
{
return await _client.VirtualFileSystems.FindById(vfsId, new FindRequest
{
Path = "/src",
Pattern = "**/*.cs",
Grep = pattern,
IgnoreCase = true,
ContextLines = 2,
MaxResults = 100
});
}
public async Task RefactorAsync(Guid vfsId, string oldName, string newName)
{
// Find all files containing the old name
var findResult = await _client.VirtualFileSystems.FindById(vfsId, new FindRequest
{
Path = "/src",
Pattern = "**/*.cs",
Grep = oldName
});
// Build batch edit request
var edits = findResult.Results.Select(r => new BatchEditFileRequest
{
Path = r.Path,
Operations = new[]
{
new EditOperation
{
Type = "replace",
Find = oldName,
Replace = newName,
ReplaceAll = true
}
}
}).ToArray();
// Execute atomic refactoring
var result = await _client.VirtualFileSystems.BatchEditById(vfsId, new BatchEditRequest
{
Atomic = true,
Edits = edits
});
if (!result.Success)
{
var failures = result.FileResults.Where(f => !f.Success);
throw new Exception($"Refactoring failed: {string.Join(", ", failures.Select(f => f.Error))}");
}
}
}
8. Error Handling
Exception Hierarchy
The SDK uses a structured exception hierarchy:
MaitentoSdkException (base)
|
+-- MaitentoApiException
| +-- StatusCode: HttpStatusCode
| +-- ResponseBody: string
|
+-- MaitentoApiAuthenticationException
| (401/403 responses)
|
+-- MaitentoValidationException
| +-- ValidationErrors: Dictionary<string, string[]>
|
+-- MaitentoDeserializationException
| +-- TypeName: string
| +-- RawContent: string
|
+-- MaitentoUnexpectedNullResponseException
|
+-- MaitentoNotificationAuthenticationException
|
+-- MaitentoNotificationUnsupportedAuthenticationException
Error Handling Patterns
Basic Error Handling
try
{
var agent = await client.Agents.GetByIdAsync(agentId);
}
catch (MaitentoApiAuthenticationException ex)
{
// Authentication failed (401/403)
Console.WriteLine($"Auth error: {ex.StatusCode} - {ex.ResponseBody}");
}
catch (MaitentoValidationException ex)
{
// Validation errors (400 with details)
foreach (var (field, errors) in ex.ValidationErrors)
{
Console.WriteLine($"Field '{field}': {string.Join(", ", errors)}");
}
}
catch (MaitentoApiException ex)
{
// Other API errors
Console.WriteLine($"API error: {ex.StatusCode} - {ex.ResponseBody}");
}
catch (MaitentoDeserializationException ex)
{
// Response parsing failed
Console.WriteLine($"Failed to parse {ex.TypeName}: {ex.RawContent}");
}
catch (MaitentoSdkException ex)
{
// Base exception for all SDK errors
Console.WriteLine($"SDK error: {ex.Message}");
}
Handling Specific HTTP Status Codes
try
{
await client.Files.DeleteAsync(fileId);
}
catch (MaitentoApiException ex) when (ex.StatusCode == HttpStatusCode.NotFound)
{
Console.WriteLine("File not found or already deleted");
}
catch (MaitentoApiException ex) when (ex.StatusCode == HttpStatusCode.Forbidden)
{
Console.WriteLine("Insufficient permissions to delete this file");
}
Using Cancellation Tokens
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));
try
{
var result = await client.Namespaces.GetAllAsync(cts.Token);
}
catch (TaskCanceledException)
{
Console.WriteLine("Operation timed out after 30 seconds");
}
Retry Pattern
The SDK has built-in retry support, but you can also implement custom retry logic:
public async Task<T> ExecuteWithRetryAsync<T>(
Func<Task<T>> operation,
int maxAttempts = 3,
TimeSpan? delay = null)
{
delay ??= TimeSpan.FromSeconds(1);
for (int attempt = 1; attempt <= maxAttempts; attempt++)
{
try
{
return await operation();
}
catch (MaitentoApiException ex) when (
attempt < maxAttempts &&
(ex.StatusCode == HttpStatusCode.ServiceUnavailable ||
ex.StatusCode == HttpStatusCode.GatewayTimeout))
{
Console.WriteLine($"Attempt {attempt} failed, retrying in {delay}...");
await Task.Delay(delay.Value);
delay = TimeSpan.FromMilliseconds(delay.Value.TotalMilliseconds * 2); // Exponential backoff
}
}
throw new Exception("All retry attempts failed");
}
// Usage
var namespaces = await ExecuteWithRetryAsync(() => client.Namespaces.GetAllAsync());
Summary
The Maitento .NET SDK provides a comprehensive, type-safe interface for interacting with the Maitento platform. Key takeaways:
- Use factory methods for simple client creation, or the constructor for advanced scenarios
- Leverage dependency injection in ASP.NET Core applications
- Handle exceptions appropriately using the structured exception hierarchy
- Use real-time notifications for responsive applications
- Organize files in partitions for scoped semantic search
- Use VFS operations for isolated file management
- Always dispose the client to clean up resources properly
For additional details on specific services, refer to the source code documentation and API reference.