نسخهٔ وب مستقل — پلتفرم نیروی کار هوش مصنوعی

مخزن اختصاصی برنامهٔ وب؛ محتوای پوشهٔ web در ریشهٔ مخزن قرار گرفت.
تاریخچهٔ پروژهٔ ربات (agy-bot) در این مخزن وجود ندارد و هیچ وابستگی runtime به آن نیست.
This commit is contained in:
mjalmoudy94
2026-10-13 00:39:28 +03:30
commit 717e53a7ce
185 changed files with 39910 additions and 0 deletions
+19
View File
@@ -0,0 +1,19 @@
{
"name": "@agy/contracts",
"version": "0.1.0",
"private": true,
"description": "Shared API contracts and types between @agy/web and the FastAPI backend.",
"type": "module",
"main": "./src/index.ts",
"types": "./src/index.ts",
"exports": {
".": "./src/index.ts"
},
"scripts": {
"typecheck": "tsc --noEmit",
"lint": "eslint src"
},
"devDependencies": {
"typescript": "^5.7.3"
}
}
+617
View File
@@ -0,0 +1,617 @@
/**
* Shared API contracts.
*
* These types mirror the FastAPI response schemas. They are intentionally
* hand-written and small: the backend is the source of truth, and a drift here
* surfaces immediately as a TypeScript error at the call site.
*/
export type Role = "owner" | "admin" | "manager" | "member" | "viewer";
export type MembershipStatus = "active" | "invited" | "suspended";
/** Provider kinds the AI Control Plane can talk to. */
export type ProviderType =
| "mock"
| "openai_compatible"
| "anthropic"
| "gemini"
| "openrouter";
/** What a model can do. Routing picks models by required capability. */
export type Capability = "text" | "vision" | "tools" | "reasoning" | "long_context" | "code";
/** Routing intents. Customers never see these names — only the platform owner does. */
export type RoutingMode = "fast" | "cheap" | "balanced" | "reasoning" | "vision" | "coding";
export type TaskStatus =
| "new"
| "triaged"
| "waiting_approval"
| "running"
| "done"
| "failed"
| "cancelled";
export type RunStatus =
| "queued"
| "planning"
| "waiting_approval"
| "running"
| "tool_calling"
| "sandbox_running"
| "completed"
| "failed"
| "cancelled"
| "timed_out";
export type RoleKey =
| "manager"
| "planner"
| "developer"
| "reviewer"
| "tester"
| "researcher"
| "content_creator"
| "support";
export type EmployeeStatus = "active" | "paused" | "archived";
export type PreviewDomainStatus = "active" | "disabled" | "failed";
export type RateUnit =
| "model_input_tokens"
| "model_output_tokens"
| "sandbox_cpu_second"
| "sandbox_memory_gb_second"
| "storage_gb_day"
| "tool_call"
| "premium_employee_run";
export interface ApiErrorBody {
error: {
code: string;
message: string;
details?: unknown;
/**
* Correlates this response with the row the API wrote to its error console
* (and with the `X-Request-ID` response header). Surfacing it lets a user
* quote one string that points at exactly one server-side record.
*/
request_id?: string;
};
}
export interface User {
id: string;
email: string;
name: string;
avatar_url?: string | null;
is_platform_owner: boolean;
}
export interface Organization {
id: string;
name: string;
slug: string;
owner_user_id: string;
}
export interface OrganizationWithRole extends Organization {
role: Role;
}
export interface Member {
id: string;
user_id: string;
email: string;
name: string;
role: Role;
status: MembershipStatus;
created_at: string;
}
export interface Invite {
id: string;
email: string;
role: Role;
expires_at: string;
invite_token: string;
invite_url: string;
}
export interface TokenResponse {
access_token: string;
token_type: string;
user: User;
}
export interface MeResponse {
user: User;
organizations: OrganizationWithRole[];
}
export interface Project {
id: string;
organization_id: string;
name: string;
slug: string;
description: string;
default_branch: string;
created_at: string;
}
export interface RepoStatus {
exists: boolean;
private: boolean;
default_branch: string;
branches: string[];
open_pull_requests: number;
}
export interface Repository {
id: string;
provider: string;
owner: string;
repo_name: string;
clone_url: string;
web_url: string;
default_branch: string;
private: boolean;
}
export interface AdminProvider {
id: string;
name: string;
type: string;
base_url: string;
is_active: boolean;
created_at: string;
}
export interface AdminModel {
id: string;
provider_id: string;
internal_name: string;
display_name_for_admin: string;
capabilities: string[];
input_price_per_1m: number;
output_price_per_1m: number;
is_active: boolean;
}
export interface AdminRoutingPolicy {
id: string;
name: string;
description: string;
mode: string;
is_default: boolean;
is_active: boolean;
}
export interface AdminRateCard {
id: string;
name: string;
unit: RateUnit;
customer_price: number;
internal_cost_estimate: number;
is_active: boolean;
}
export interface AdminOrganization {
id: string;
name: string;
slug: string;
member_count: number;
created_at: string;
}
/**
* A stored provider credential.
*
* There is no field here that can carry a plaintext key — the API only ever
* returns a masked form, and on list it returns a fixed mask because the
* plaintext is unrecoverable by design.
*/
export interface AdminCredential {
id: string;
provider_id: string;
name: string;
masked_key: string;
is_active: boolean;
}
/** Result of a routing dry-run: which model a mode would pick, and why. */
export interface ModelChoice {
mode: string;
model_id: string;
internal_name: string;
capabilities: string[];
estimated_input_price_per_1m: number;
estimated_output_price_per_1m: number;
}
export interface AdminUsageRow {
organization_id: string;
quantity: number;
total_price: number;
}
export interface PreviewDomain {
id: string;
host: string;
port: number;
status: PreviewDomainStatus;
protected: boolean;
url: string;
}
export interface Employee {
id: string;
organization_id: string;
project_id?: string | null;
template_id?: string | null;
name: string;
role_key: RoleKey;
status: EmployeeStatus;
routing_policy_id?: string | null;
created_at: string;
}
export interface Task {
id: string;
organization_id: string;
project_id?: string | null;
thread_id?: string | null;
title: string;
description: string;
status: TaskStatus;
assigned_employee_id?: string | null;
created_at: string;
updated_at: string;
}
export interface Run {
id: string;
task_id: string;
employee_id?: string | null;
status: RunStatus;
error?: string | null;
started_at?: string | null;
finished_at?: string | null;
created_at: string;
}
export interface Thread {
id: string;
organization_id: string;
project_id?: string | null;
title: string;
created_at: string;
}
export interface Message {
id: string;
thread_id: string;
role: "user" | "assistant" | "system";
content: string;
employee_id?: string | null;
created_at: string;
}
export interface ThreadDetail extends Thread {
messages: Message[];
}
export interface RunStep {
id: string;
index: number;
kind: string;
title: string;
payload_json: Record<string, unknown>;
created_at: string;
}
export interface ToolCall {
id: string;
tool_key: string;
status: string;
requires_approval: boolean;
arguments_json: Record<string, unknown>;
result_json: Record<string, unknown>;
created_at: string;
}
export interface ArtifactDetail extends Artifact {
content_ref: string;
run_id?: string | null;
}
export interface RunDetail extends Run {
steps: RunStep[];
tool_calls: ToolCall[];
artifacts: ArtifactDetail[];
}
export interface TaskDetail extends Task {
runs: Run[];
}
export interface AgentTemplate {
id: string;
name: string;
role_key: RoleKey;
description: string;
default_tools_json: string[];
}
/** A routing policy as a customer may see it — no mode, no model hints. */
export interface RoutingChoice {
id: string;
name: string;
description: string;
}
export interface PromptVersion {
id: string;
version: number;
content: string;
created_at: string;
}
export interface ToolPermission {
tool_key: string;
allowed: boolean;
}
/** One entry in the tool catalog an employee can be granted. */
export interface ToolSpec {
key: string;
label: string;
description: string;
requires_approval: boolean;
destructive: boolean;
category: string;
}
export interface EmployeeDetail extends Employee {
prompt_versions: PromptVersion[];
tool_permissions: ToolPermission[];
open_task_count: number;
}
export interface PostMessageResponse {
user_message: Message;
assistant_message: Message;
}
export interface Artifact {
id: string;
name: string;
kind: string;
size_bytes: number;
created_at: string;
}
export interface BillingSummary {
balance: number;
currency: string;
low_balance: boolean;
low_balance_threshold: number;
total_spend: number;
by_unit: { unit: RateUnit; quantity: number; total_price: number }[];
by_employee: Record<string, number>;
by_project: Record<string, number>;
}
export interface UsageEvent {
id: string;
unit: RateUnit;
quantity: number;
unit_price: number;
total_price: number;
project_id?: string | null;
employee_id?: string | null;
run_id?: string | null;
created_at: string;
}
export interface Invoice {
id: string;
amount: number;
currency: string;
status: string;
period_start?: string | null;
period_end?: string | null;
created_at: string;
}
export interface Payment {
id: string;
amount: number;
currency: string;
status: string;
provider: string;
created_at: string;
}
export interface Wallet {
balance: number;
currency: string;
low_balance: boolean;
}
export interface AuditEvent {
id: string;
action: string;
actor_user_id?: string | null;
target_type: string;
target_id: string;
created_at: string;
}
// --- sandbox ----------------------------------------------------------------
export type NetworkPolicy = "deny_all" | "allowlist" | "open";
export interface SandboxTemplate {
id: string;
name: string;
provider: string;
image: string;
description: string;
default_cpu: number;
default_memory_mb: number;
default_disk_mb: number;
}
export interface SandboxWorkspace {
id: string;
project_id: string;
template_id: string;
provider: string;
status: string;
created_at: string;
}
export interface SandboxSession {
id: string;
workspace_id: string;
status: string;
started_at: string;
last_active_at: string;
}
export interface SandboxCommandRun {
id: string;
command: string;
exit_code: number | null;
stdout: string;
stderr: string;
duration_ms: number;
truncated: boolean;
created_at: string;
}
export interface SandboxFileRead {
path: string;
content: string;
}
export interface SandboxSnapshot {
id: string;
name: string;
created_at: string;
}
export interface SandboxPreviewUrl {
port: number;
url: string;
}
/**
* Effective limits are resolved server-side (project -> organization ->
* platform) and clamped. The UI only ever displays them.
*/
export interface SandboxResourceLimit {
cpu: number;
memory_mb: number;
disk_mb: number;
timeout_seconds: number;
max_output_bytes: number;
network_policy: NetworkPolicy;
}
export interface HealthResponse {
status: string;
app: string;
env: string;
}
export interface ReadinessResponse {
status: string;
checks: {
database: string;
model_provider: string;
adapters: Record<string, string>;
};
}
/* -------------------------------------------------------------------------- */
/* Error console (platform owner) */
/* -------------------------------------------------------------------------- */
export type ErrorSeverity = "warning" | "error" | "critical";
export type ErrorSource = "http" | "worker" | "startup";
export type ErrorStatusFilter = "open" | "resolved";
/**
* One persisted failure. Deliberately wide: a record that lacks the request
* path or the exception class forces whoever is debugging to reproduce the bug
* just to learn what it was.
*/
export interface ErrorEvent {
id: string;
kind: string;
message: string;
stack: string;
severity: ErrorSeverity;
source: ErrorSource;
error_type: string;
fingerprint: string;
status_code: number | null;
method: string;
path: string;
organization_id: string | null;
user_id: string | null;
run_id: string | null;
request_id: string;
ip: string;
user_agent: string;
metadata_json: Record<string, unknown>;
resolved_at: string | null;
resolved_note: string;
created_at: string;
}
/** Every occurrence of one distinct bug, collapsed into a single row. */
export interface ErrorGroup {
fingerprint: string;
occurrences: number;
open_count: number;
first_seen: string;
last_seen: string;
kind: string;
error_type: string;
severity: ErrorSeverity;
source: ErrorSource;
path: string;
sample_message: string;
}
export interface ErrorSummary {
open_by_severity: Record<string, number>;
total_open: number;
}
export interface ErrorListResponse {
items: ErrorEvent[];
total: number;
limit: number;
offset: number;
}
export interface ResolveErrorResponse {
fingerprint: string;
resolved: number;
}
export interface ErrorQuery {
status?: ErrorStatusFilter;
severity?: ErrorSeverity;
source?: ErrorSource;
organization_id?: string;
search?: string;
limit?: number;
offset?: number;
}
+14
View File
@@ -0,0 +1,14 @@
{
"compilerOptions": {
"target": "ES2022",
"lib": ["esnext"],
"module": "esnext",
"moduleResolution": "bundler",
"strict": true,
"noEmit": true,
"skipLibCheck": true,
"isolatedModules": true,
"declaration": true
},
"include": ["src/**/*.ts"]
}