Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion forge-app/src/bin/generate_forge_types.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::{env, fs, path::Path};

use anyhow::{Context, Result, bail};
use forge_config::{ForgeProjectSettings, ProjectConfig};
use forge_config::{BetaFeature, FeatureMaturity, ForgeProjectSettings, ProjectConfig};
use forge_omni::{OmniConfig, OmniInstance, RecipientType, SendTextRequest, SendTextResponse};
use ts_rs::TS;

Expand All @@ -18,6 +18,9 @@ fn main() -> Result<()> {
OmniInstance::decl(),
SendTextRequest::decl(),
SendTextResponse::decl(),
// Beta features types
BetaFeature::decl(),
FeatureMaturity::decl(),
];

let body = declarations
Expand Down
48 changes: 46 additions & 2 deletions forge-app/src/router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ use db::models::{
};
use deployment::Deployment;
use executors::profile::ExecutorProfileId;
use forge_config::ForgeProjectSettings;
use forge_config::{BetaFeature, ForgeProjectSettings};
use server::routes::{
self as upstream, approvals, auth, config as upstream_config, containers, drafts, events,
execution_processes, filesystem, images, projects, tags, task_attempts, tasks,
Expand Down Expand Up @@ -158,7 +158,12 @@ fn forge_api_routes() -> Router<ForgeAppState> {
"/api/forge/agents",
get(get_forge_agents).post(create_forge_agent),
)
// Branch-templates extension removed - using simple forge/ prefix
// Beta features API
.route("/api/forge/beta-features", get(list_beta_features))
.route(
"/api/forge/beta-features/{feature_id}/toggle",
post(toggle_beta_feature),
)
}

/// Forge-specific CreateTask that includes is_agent field
Expand Down Expand Up @@ -1758,6 +1763,45 @@ async fn update_project_settings(
Ok(Json(ApiResponse::success(settings)))
}

// ============================================================================
// Beta Features API
// ============================================================================

/// List all beta features with their enabled states
async fn list_beta_features(
State(services): State<ForgeServices>,
) -> Result<Json<ApiResponse<Vec<BetaFeature>>>, StatusCode> {
services
.beta_features
.list()
.await
.map(|features| Json(ApiResponse::success(features)))
.map_err(|e| {
tracing::error!("Failed to list beta features: {}", e);
StatusCode::INTERNAL_SERVER_ERROR
})
}

/// Toggle a beta feature's enabled state
async fn toggle_beta_feature(
Path(feature_id): Path<String>,
State(services): State<ForgeServices>,
) -> Result<Json<ApiResponse<BetaFeature>>, StatusCode> {
services
.beta_features
.toggle(&feature_id)
.await
.map(|feature| Json(ApiResponse::success(feature)))
.map_err(|e| {
tracing::error!("Failed to toggle beta feature '{}': {}", feature_id, e);
if e.to_string().contains("not found") {
StatusCode::NOT_FOUND
} else {
StatusCode::INTERNAL_SERVER_ERROR
}
})
}

/// Get executor profiles for a specific project
async fn get_project_profiles(
Path(project_id): Path<Uuid>,
Expand Down
12 changes: 11 additions & 1 deletion forge-app/src/services/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use tokio::time::{Duration, sleep};
use uuid::Uuid;

// Import forge extension services
use forge_config::ForgeConfigService;
use forge_config::{BetaFeaturesService, ForgeConfigService};
use forge_omni::{OmniConfig, OmniService};

/// Main forge services container
Expand All @@ -31,6 +31,7 @@ pub struct ForgeServices {
pub deployment: Arc<DeploymentImpl>,
pub omni: Arc<RwLock<OmniService>>,
pub config: Arc<ForgeConfigService>,
pub beta_features: Arc<BetaFeaturesService>,
pub pool: SqlitePool,
pub profile_cache: Arc<profile_cache::ProfileCacheManager>,
}
Expand Down Expand Up @@ -73,6 +74,14 @@ impl ForgeServices {
let omni_config = config.effective_omni_config(None).await?;
let omni = Arc::new(RwLock::new(OmniService::new(omni_config)));

// Initialize beta features service
// Look for beta-features.toml in forge-main directory (relative to cwd)
let beta_features_path = std::env::current_dir()?
.join("forge-main")
.join("beta-features.toml");
let beta_features = Arc::new(BetaFeaturesService::new(pool.clone(), beta_features_path)?);
beta_features.ensure_table().await?;

tracing::info!(
forge_omni_enabled = global_settings.omni_enabled,
"Loaded forge extension settings from auxiliary schema"
Expand All @@ -91,6 +100,7 @@ impl ForgeServices {
deployment,
omni,
config,
beta_features,
pool,
profile_cache,
})
Expand Down
2 changes: 2 additions & 0 deletions forge-extensions/config/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ serde_json = { workspace = true }
anyhow = { workspace = true }
tracing = { workspace = true }
ts-rs = { workspace = true }
toml = "0.8"
sqlx = { version = "0.8.6", features = ["runtime-tokio-rustls", "sqlite", "uuid", "chrono"] }
uuid = { version = "1.0", features = ["v4", "serde"] }
chrono = { version = "0.4", features = ["serde"] }
Expand All @@ -17,3 +18,4 @@ services = { git = "https://github.com/namastexlabs/forge-core.git", tag = "v0.8

[dev-dependencies]
tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }
tempfile = "3.10"
7 changes: 7 additions & 0 deletions forge-extensions/config/bindings/BetaFeature.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { FeatureMaturity } from "./FeatureMaturity";

/**
* A beta feature with merged config + state
*/
export type BetaFeature = { id: string, name: string, description: string, maturity: FeatureMaturity, enabled: boolean, };
6 changes: 6 additions & 0 deletions forge-extensions/config/bindings/FeatureMaturity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.

/**
* Feature maturity level
*/
export type FeatureMaturity = "experimental" | "beta" | "stable";
Loading
Loading