287 lines
6.6 KiB
Dart
287 lines
6.6 KiB
Dart
|
|
/// Codex sandbox mode for controlling file system access.
|
|
enum CodexSandboxMode {
|
|
readOnly('read-only'),
|
|
workspaceWrite('workspace-write'),
|
|
dangerFullAccess('danger-full-access');
|
|
|
|
final String value;
|
|
const CodexSandboxMode(this.value);
|
|
}
|
|
|
|
/// Codex approval policy for controlling automatic execution.
|
|
enum CodexApprovalPolicy {
|
|
suggest('suggest'),
|
|
autoEdit('auto-edit'),
|
|
fullAuto('full-auto');
|
|
|
|
final String value;
|
|
const CodexApprovalPolicy(this.value);
|
|
}
|
|
|
|
/// Codex authentication mode.
|
|
enum CodexAuthMode {
|
|
apiKey('api-key'),
|
|
chatgpt('chatgpt'),
|
|
chatgptAuthTokens('chatgptAuthTokens');
|
|
|
|
final String value;
|
|
const CodexAuthMode(this.value);
|
|
}
|
|
|
|
/// Codex thread information.
|
|
class CodexThread {
|
|
final String id;
|
|
final String? path;
|
|
final bool ephemeral;
|
|
final DateTime? createdAt;
|
|
|
|
const CodexThread({
|
|
required this.id,
|
|
this.path,
|
|
this.ephemeral = false,
|
|
this.createdAt,
|
|
});
|
|
|
|
factory CodexThread.fromJson(Map<String, dynamic> json) {
|
|
return CodexThread(
|
|
id: json['id'] as String,
|
|
path: json['path'] as String?,
|
|
ephemeral: json['ephemeral'] as bool? ?? false,
|
|
createdAt: json['createdAt'] != null
|
|
? DateTime.tryParse(json['createdAt'] as String)
|
|
: null,
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'id': id,
|
|
if (path != null) 'path': path,
|
|
'ephemeral': ephemeral,
|
|
if (createdAt != null) 'createdAt': createdAt!.toIso8601String(),
|
|
};
|
|
}
|
|
|
|
/// Codex turn information.
|
|
class CodexTurn {
|
|
final String id;
|
|
final String threadId;
|
|
final String status;
|
|
final DateTime? startedAt;
|
|
final DateTime? completedAt;
|
|
|
|
const CodexTurn({
|
|
required this.id,
|
|
required this.threadId,
|
|
required this.status,
|
|
this.startedAt,
|
|
this.completedAt,
|
|
});
|
|
|
|
factory CodexTurn.fromJson(Map<String, dynamic> json) {
|
|
return CodexTurn(
|
|
id: json['id'] as String,
|
|
threadId: json['threadId'] as String,
|
|
status: json['status'] as String,
|
|
startedAt: json['startedAt'] != null
|
|
? DateTime.tryParse(json['startedAt'] as String)
|
|
: null,
|
|
completedAt: json['completedAt'] != null
|
|
? DateTime.tryParse(json['completedAt'] as String)
|
|
: null,
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Codex account information.
|
|
class CodexAccount {
|
|
final String? email;
|
|
final String? plan;
|
|
final bool hasCredits;
|
|
final double? creditsBalance;
|
|
final List<CodexRateLimit> rateLimits;
|
|
|
|
const CodexAccount({
|
|
this.email,
|
|
this.plan,
|
|
this.hasCredits = false,
|
|
this.creditsBalance,
|
|
this.rateLimits = const [],
|
|
});
|
|
|
|
factory CodexAccount.fromJson(Map<String, dynamic> json) {
|
|
return CodexAccount(
|
|
email: json['email'] as String?,
|
|
plan: json['plan'] as String?,
|
|
hasCredits: json['hasCredits'] as bool? ?? false,
|
|
creditsBalance: (json['creditsBalance'] as num?)?.toDouble(),
|
|
rateLimits:
|
|
(json['rateLimits'] as List?)
|
|
?.map((e) => CodexRateLimit.fromJson(e as Map<String, dynamic>))
|
|
.toList() ??
|
|
[],
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Codex rate limit information.
|
|
class CodexRateLimit {
|
|
final String type;
|
|
final int percentRemaining;
|
|
final DateTime? resetsAt;
|
|
|
|
const CodexRateLimit({
|
|
required this.type,
|
|
required this.percentRemaining,
|
|
this.resetsAt,
|
|
});
|
|
|
|
factory CodexRateLimit.fromJson(Map<String, dynamic> json) {
|
|
return CodexRateLimit(
|
|
type: json['type'] as String,
|
|
percentRemaining: json['percentRemaining'] as int? ?? 0,
|
|
resetsAt: json['resetsAt'] != null
|
|
? DateTime.tryParse(json['resetsAt'] as String)
|
|
: null,
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Codex user input for turn/start.
|
|
class CodexUserInput {
|
|
final String type;
|
|
final String content;
|
|
final List<CodexAttachment>? attachments;
|
|
|
|
const CodexUserInput({
|
|
this.type = 'message',
|
|
required this.content,
|
|
this.attachments,
|
|
});
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'type': type,
|
|
'content': content,
|
|
if (attachments != null && attachments!.isNotEmpty)
|
|
'attachments': attachments!.map((a) => a.toJson()).toList(),
|
|
};
|
|
}
|
|
|
|
/// Codex file attachment.
|
|
class CodexAttachment {
|
|
final String path;
|
|
final String? name;
|
|
|
|
const CodexAttachment({required this.path, this.name});
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'path': path,
|
|
if (name != null) 'name': name,
|
|
};
|
|
}
|
|
|
|
/// Base class for Codex events.
|
|
sealed class CodexEvent {
|
|
const CodexEvent();
|
|
}
|
|
|
|
/// Log event from Codex.
|
|
class CodexLogEvent extends CodexEvent {
|
|
final String level;
|
|
final String message;
|
|
final DateTime timestamp;
|
|
|
|
const CodexLogEvent({
|
|
required this.level,
|
|
required this.message,
|
|
required this.timestamp,
|
|
});
|
|
}
|
|
|
|
/// Notification event from Codex App Server.
|
|
class CodexNotificationEvent extends CodexEvent {
|
|
final String method;
|
|
final Map<String, dynamic> params;
|
|
|
|
const CodexNotificationEvent({required this.method, required this.params});
|
|
}
|
|
|
|
/// Turn event (item/started, item/completed, etc.).
|
|
class CodexTurnEvent extends CodexEvent {
|
|
final String type;
|
|
final String? threadId;
|
|
final String? turnId;
|
|
final String? itemId;
|
|
final Map<String, dynamic> data;
|
|
|
|
const CodexTurnEvent({
|
|
required this.type,
|
|
this.threadId,
|
|
this.turnId,
|
|
this.itemId,
|
|
required this.data,
|
|
});
|
|
|
|
factory CodexTurnEvent.fromNotification(CodexNotificationEvent notification) {
|
|
final params = notification.params;
|
|
return CodexTurnEvent(
|
|
type: notification.method,
|
|
threadId: params['threadId'] as String?,
|
|
turnId: params['turnId'] as String?,
|
|
itemId: params['itemId'] as String?,
|
|
data: params,
|
|
);
|
|
}
|
|
|
|
/// Check if this is a text delta event.
|
|
bool get isTextDelta => type == 'item/agentMessage/delta';
|
|
|
|
/// Get text delta content.
|
|
String? get textDelta => data['delta'] as String?;
|
|
}
|
|
|
|
/// Error from Codex RPC.
|
|
class CodexRpcError implements Exception {
|
|
final int code;
|
|
final String message;
|
|
final dynamic data;
|
|
|
|
const CodexRpcError({required this.code, required this.message, this.data});
|
|
|
|
factory CodexRpcError.fromJson(Map<String, dynamic> json) {
|
|
return CodexRpcError(
|
|
code: json['code'] as int? ?? -1,
|
|
message: json['message'] as String? ?? 'Unknown error',
|
|
data: json['data'],
|
|
);
|
|
}
|
|
|
|
@override
|
|
String toString() => 'CodexRpcError($code): $message';
|
|
}
|
|
|
|
/// Connection state for CodexRuntime.
|
|
enum CodexConnectionState {
|
|
disconnected,
|
|
connecting,
|
|
connected,
|
|
initializing,
|
|
ready,
|
|
error,
|
|
}
|
|
|
|
/// Codex App Server RPC client.
|
|
class CodexRuntime {}
|
|
|
|
class CodexLaunchConfiguration {
|
|
const CodexLaunchConfiguration({
|
|
required this.executable,
|
|
required this.arguments,
|
|
this.runInShell = false,
|
|
});
|
|
|
|
final String executable;
|
|
final List<String> arguments;
|
|
final bool runInShell;
|
|
}
|