mirror of
https://github.com/zed-industries/zed.git
synced 2026-06-01 03:14:56 +07:00
Merge branch 'main' of https://github.com/zed-industries/zed into martin/ai-233-fix-issue-with-rendering-file-paths
This commit is contained in:
commit
534506f94c
33 changed files with 1453 additions and 830 deletions
1
.github/workflows/after_release.yml
vendored
1
.github/workflows/after_release.yml
vendored
|
|
@ -44,6 +44,7 @@ jobs:
|
|||
uses: zed-industries/zed/.github/workflows/deploy_docs.yml@main
|
||||
secrets:
|
||||
DOCS_AMPLITUDE_API_KEY: ${{ secrets.DOCS_AMPLITUDE_API_KEY }}
|
||||
DOCS_CONSENT_IO_INSTANCE: ${{ secrets.DOCS_CONSENT_IO_INSTANCE }}
|
||||
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||
with:
|
||||
|
|
|
|||
4
.github/workflows/deploy_docs.yml
vendored
4
.github/workflows/deploy_docs.yml
vendored
|
|
@ -16,6 +16,9 @@ on:
|
|||
DOCS_AMPLITUDE_API_KEY:
|
||||
description: DOCS_AMPLITUDE_API_KEY
|
||||
required: true
|
||||
DOCS_CONSENT_IO_INSTANCE:
|
||||
description: DOCS_CONSENT_IO_INSTANCE
|
||||
required: true
|
||||
CLOUDFLARE_API_TOKEN:
|
||||
description: CLOUDFLARE_API_TOKEN
|
||||
required: true
|
||||
|
|
@ -39,6 +42,7 @@ jobs:
|
|||
runs-on: namespace-profile-16x32-ubuntu-2204
|
||||
env:
|
||||
DOCS_AMPLITUDE_API_KEY: ${{ secrets.DOCS_AMPLITUDE_API_KEY }}
|
||||
DOCS_CONSENT_IO_INSTANCE: ${{ secrets.DOCS_CONSENT_IO_INSTANCE }}
|
||||
CC: clang
|
||||
CXX: clang++
|
||||
steps:
|
||||
|
|
|
|||
1
.github/workflows/deploy_nightly_docs.yml
vendored
1
.github/workflows/deploy_nightly_docs.yml
vendored
|
|
@ -13,6 +13,7 @@ jobs:
|
|||
uses: zed-industries/zed/.github/workflows/deploy_docs.yml@main
|
||||
secrets:
|
||||
DOCS_AMPLITUDE_API_KEY: ${{ secrets.DOCS_AMPLITUDE_API_KEY }}
|
||||
DOCS_CONSENT_IO_INSTANCE: ${{ secrets.DOCS_CONSENT_IO_INSTANCE }}
|
||||
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||
with:
|
||||
|
|
|
|||
1
.github/workflows/run_tests.yml
vendored
1
.github/workflows/run_tests.yml
vendored
|
|
@ -668,6 +668,7 @@ jobs:
|
|||
runs-on: namespace-profile-16x32-ubuntu-2204
|
||||
env:
|
||||
DOCS_AMPLITUDE_API_KEY: ${{ secrets.DOCS_AMPLITUDE_API_KEY }}
|
||||
DOCS_CONSENT_IO_INSTANCE: ${{ secrets.DOCS_CONSENT_IO_INSTANCE }}
|
||||
CC: clang
|
||||
CXX: clang++
|
||||
steps:
|
||||
|
|
|
|||
3
Cargo.lock
generated
3
Cargo.lock
generated
|
|
@ -81,6 +81,7 @@ dependencies = [
|
|||
"futures 0.3.32",
|
||||
"git",
|
||||
"gpui",
|
||||
"indoc",
|
||||
"language",
|
||||
"log",
|
||||
"pretty_assertions",
|
||||
|
|
@ -7930,6 +7931,7 @@ dependencies = [
|
|||
"bytemuck",
|
||||
"collections",
|
||||
"cosmic-text",
|
||||
"criterion",
|
||||
"etagere",
|
||||
"gpui",
|
||||
"gpui_util",
|
||||
|
|
@ -7942,6 +7944,7 @@ dependencies = [
|
|||
"raw-window-handle",
|
||||
"smallvec",
|
||||
"swash",
|
||||
"unicode-segmentation",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
|
|
|
|||
|
|
@ -33,12 +33,12 @@ watch.workspace = true
|
|||
|
||||
[dev-dependencies]
|
||||
buffer_diff = { workspace = true, features = ["test-support"] }
|
||||
git.workspace = true
|
||||
collections = { workspace = true, features = ["test-support"] }
|
||||
clock = { workspace = true, features = ["test-support"] }
|
||||
collections = { workspace = true, features = ["test-support"] }
|
||||
ctor.workspace = true
|
||||
git.workspace = true
|
||||
gpui = { workspace = true, features = ["test-support"] }
|
||||
|
||||
indoc.workspace = true
|
||||
language = { workspace = true, features = ["test-support"] }
|
||||
log.workspace = true
|
||||
pretty_assertions.workspace = true
|
||||
|
|
|
|||
|
|
@ -387,6 +387,11 @@ impl ActionLog {
|
|||
let git_diff_base = git_diff.read(cx).base_text(cx).as_rope().clone();
|
||||
let buffer_text = tracked_buffer.snapshot.as_rope().clone();
|
||||
anyhow::Ok(cx.background_spawn(async move {
|
||||
if buffer_text.len() == git_diff_base.len()
|
||||
&& buffer_text.chars_at(0).eq(git_diff_base.chars_at(0))
|
||||
{
|
||||
return (Arc::<str>::from(git_diff_base.to_string()), git_diff_base);
|
||||
}
|
||||
let mut old_unreviewed_edits = old_unreviewed_edits.into_iter().peekable();
|
||||
let committed_edits = language::line_diff(
|
||||
&agent_diff_base.to_string(),
|
||||
|
|
@ -1320,6 +1325,7 @@ mod tests {
|
|||
use super::*;
|
||||
use buffer_diff::DiffHunkStatusKind;
|
||||
use gpui::TestAppContext;
|
||||
use indoc::indoc;
|
||||
use language::Point;
|
||||
use project::{FakeFs, Fs, Project, RemoveOptions};
|
||||
use rand::prelude::*;
|
||||
|
|
@ -2703,6 +2709,86 @@ mod tests {
|
|||
assert_eq!(unreviewed_hunks(&action_log, cx), vec![]);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_keep_edits_on_commit_with_shifted_diff_boundaries(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
let initial_text = indoc! {"
|
||||
use crate::{Alpha, Beta};
|
||||
|
||||
fn keep() {
|
||||
work();
|
||||
}
|
||||
|
||||
fn remove() {
|
||||
work();
|
||||
}
|
||||
|
||||
fn after() {
|
||||
work();
|
||||
}
|
||||
"};
|
||||
let fs = FakeFs::new(cx.executor());
|
||||
fs.insert_tree(
|
||||
path!("/project"),
|
||||
json!({
|
||||
".git": {},
|
||||
"file.rs": initial_text,
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
fs.set_head_for_repo(
|
||||
path!("/project/.git").as_ref(),
|
||||
&[("file.rs", initial_text.into())],
|
||||
"0000000",
|
||||
);
|
||||
cx.run_until_parked();
|
||||
|
||||
let project = Project::test(fs.clone(), [path!("/project").as_ref()], cx).await;
|
||||
let action_log = cx.new(|_| ActionLog::new(project.clone()));
|
||||
|
||||
let file_path = project
|
||||
.read_with(cx, |project, cx| {
|
||||
project.find_project_path(path!("/project/file.rs"), cx)
|
||||
})
|
||||
.unwrap();
|
||||
let buffer = project
|
||||
.update(cx, |project, cx| project.open_buffer(file_path, cx))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let final_text = indoc! {"
|
||||
use crate::{Alpha};
|
||||
|
||||
fn keep() {
|
||||
work();
|
||||
}
|
||||
|
||||
fn after() {
|
||||
work();
|
||||
}
|
||||
"};
|
||||
|
||||
cx.update(|cx| {
|
||||
action_log.update(cx, |log, cx| log.buffer_read(buffer.clone(), cx));
|
||||
buffer.update(cx, |buffer, cx| {
|
||||
buffer.set_text(final_text, cx);
|
||||
});
|
||||
action_log.update(cx, |log, cx| log.buffer_edited(buffer.clone(), cx));
|
||||
});
|
||||
cx.run_until_parked();
|
||||
assert!(!unreviewed_hunks(&action_log, cx).is_empty());
|
||||
|
||||
fs.set_head_for_repo(
|
||||
path!("/project/.git").as_ref(),
|
||||
&[("file.rs", final_text.into())],
|
||||
"0000001",
|
||||
);
|
||||
cx.run_until_parked();
|
||||
|
||||
assert_eq!(unreviewed_hunks(&action_log, cx), vec![]);
|
||||
}
|
||||
|
||||
/// Regression test: when head_commit updates before the BufferDiff's base
|
||||
/// text does, an intermediate DiffChanged (e.g. from a buffer-edit diff
|
||||
/// recalculation) must NOT consume the commit signal. The subscription
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ use collections::HashMap;
|
|||
use editor::{Editor, MultiBuffer};
|
||||
use extension::ExtensionEvents;
|
||||
use extension_host::ExtensionStore;
|
||||
use feature_flags::{FeatureFlagAppExt as _, SkillsFeatureFlag};
|
||||
use fs::Fs;
|
||||
use gpui::{
|
||||
Action, Anchor, Animation, AnimationExt, AnyElement, App, AsyncWindowContext, ClipboardItem,
|
||||
|
|
@ -2094,7 +2095,15 @@ impl AgentPanel {
|
|||
let draft = self.ensure_draft(source, window, cx);
|
||||
if let BaseView::AgentThread { conversation_view } = &self.base_view {
|
||||
if conversation_view.entity_id() == draft.entity_id() {
|
||||
if focus {
|
||||
// If we're already viewing the draft as the base view but an
|
||||
// overlay (e.g. Settings) is covering it, clear the overlay
|
||||
// so the user actually sees the draft they asked for.
|
||||
// Otherwise pressing "New Thread" from the Settings panel is
|
||||
// a silent no-op because the early return below would leave
|
||||
// the overlay on top of the draft.
|
||||
if self.overlay_view.is_some() {
|
||||
self.clear_overlay(focus, window, cx);
|
||||
} else if focus {
|
||||
self.focus_handle(cx).focus(window, cx);
|
||||
}
|
||||
return;
|
||||
|
|
@ -4170,6 +4179,12 @@ impl AgentPanel {
|
|||
.with_handle(self.agent_panel_menu_handle.clone())
|
||||
.menu({
|
||||
move |window, cx| {
|
||||
// When the Skills feature flag is on, hide the legacy Rules menu entry.
|
||||
// The flag is read from a global store populated asynchronously, and
|
||||
// this menu builder runs on every open, so the latest resolved value is
|
||||
// reflected when the user clicks the ellipsis.
|
||||
let skills_enabled = cx.has_flag::<SkillsFeatureFlag>();
|
||||
|
||||
Some(ContextMenu::build(window, cx, |mut menu, _window, _| {
|
||||
menu = menu.context(focus_handle.clone());
|
||||
|
||||
|
|
@ -4204,9 +4219,13 @@ impl AgentPanel {
|
|||
}),
|
||||
)
|
||||
.action("Add Custom Server…", Box::new(AddContextServer))
|
||||
.separator()
|
||||
.action("Rules", Box::new(OpenRulesLibrary::default()))
|
||||
.action("Profiles", Box::new(ManageProfiles::default()));
|
||||
.separator();
|
||||
|
||||
if !skills_enabled {
|
||||
menu = menu.action("Rules", Box::new(OpenRulesLibrary::default()));
|
||||
}
|
||||
|
||||
menu = menu.action("Profiles", Box::new(ManageProfiles::default()));
|
||||
}
|
||||
|
||||
menu = menu
|
||||
|
|
@ -6683,6 +6702,63 @@ mod tests {
|
|||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_new_thread_dismisses_settings_overlay(cx: &mut TestAppContext) {
|
||||
let (panel, mut cx) = setup_panel(cx).await;
|
||||
|
||||
// Put the panel on its ephemeral new-draft view so the base view
|
||||
// already contains the draft that `NewThread` would activate.
|
||||
panel.update_in(&mut cx, |panel, window, cx| {
|
||||
panel.activate_new_thread(true, AgentThreadSource::AgentPanel, window, cx);
|
||||
});
|
||||
cx.run_until_parked();
|
||||
|
||||
panel.read_with(&cx, |panel, cx| {
|
||||
assert!(
|
||||
panel.active_view_is_new_draft(cx),
|
||||
"precondition: base view should be the ephemeral draft"
|
||||
);
|
||||
assert!(!panel.is_overlay_open());
|
||||
});
|
||||
|
||||
// Simulate the Settings overlay being open on top of the draft.
|
||||
// We don't go through `open_configuration` here because it would
|
||||
// build provider configuration views, which call into
|
||||
// `LanguageModelProvider::configuration_view` — unimplemented for
|
||||
// the fake provider used in tests. The bug being exercised lives
|
||||
// entirely in the overlay/base-view bookkeeping, so toggling the
|
||||
// overlay flag directly is sufficient.
|
||||
panel.update_in(&mut cx, |panel, window, cx| {
|
||||
panel.set_overlay(OverlayView::Configuration, true, window, cx);
|
||||
});
|
||||
cx.run_until_parked();
|
||||
|
||||
panel.read_with(&cx, |panel, _cx| {
|
||||
assert!(
|
||||
panel.is_overlay_open(),
|
||||
"precondition: Settings overlay should be open"
|
||||
);
|
||||
});
|
||||
|
||||
// Dispatching `NewThread` while Settings is open must dismiss the
|
||||
// overlay so the user actually sees the new thread. Previously
|
||||
// this was a silent no-op: `activate_draft` early-returned without
|
||||
// clearing the overlay because the base view already held the
|
||||
// draft.
|
||||
panel.update_in(&mut cx, |panel, window, cx| {
|
||||
panel.new_thread(&NewThread, window, cx);
|
||||
});
|
||||
cx.run_until_parked();
|
||||
|
||||
panel.read_with(&cx, |panel, cx| {
|
||||
assert!(
|
||||
!panel.is_overlay_open(),
|
||||
"Settings overlay should be dismissed when invoking NewThread"
|
||||
);
|
||||
assert!(panel.active_view_is_new_draft(cx));
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_terminal_title_omits_placeholder_title(cx: &mut TestAppContext) {
|
||||
let (panel, mut cx) = setup_panel(cx).await;
|
||||
|
|
|
|||
|
|
@ -651,6 +651,12 @@ fn update_command_palette_filter(cx: &mut App) {
|
|||
.edit_predictions
|
||||
.provider;
|
||||
|
||||
// The Skills feature flag is loaded asynchronously, so this value may
|
||||
// be `false` before flags resolve. `update_command_palette_filter`
|
||||
// gets re-run from `cx.on_flags_ready` (see `init`), which means the
|
||||
// filter is reapplied with the correct value once flags arrive.
|
||||
let skills_enabled = cx.has_flag::<SkillsFeatureFlag>();
|
||||
|
||||
CommandPaletteFilter::update_global(cx, |filter, _| {
|
||||
use editor::actions::{
|
||||
AcceptEditPrediction, AcceptNextLineEditPrediction, AcceptNextWordEditPrediction,
|
||||
|
|
@ -667,6 +673,8 @@ fn update_command_palette_filter(cx: &mut App) {
|
|||
TypeId::of::<ToggleEditPrediction>(),
|
||||
];
|
||||
|
||||
let open_rules_library_action = [TypeId::of::<zed_actions::assistant::OpenRulesLibrary>()];
|
||||
|
||||
if disable_ai {
|
||||
filter.hide_namespace("agent");
|
||||
filter.hide_namespace("agents");
|
||||
|
|
@ -715,6 +723,17 @@ fn update_command_palette_filter(cx: &mut App) {
|
|||
|
||||
filter.show_namespace("multi_workspace");
|
||||
}
|
||||
|
||||
// Hide `assistant: open rules library` when Skills are enabled —
|
||||
// Rules are surfaced through the Skills UI in that case. Applied
|
||||
// after the disable-ai / agent-enabled branches so it overrides
|
||||
// the `show_namespace("assistant")` call above without affecting
|
||||
// the rest of that namespace's actions.
|
||||
if !disable_ai && skills_enabled {
|
||||
filter.hide_action_types(&open_rules_library_action);
|
||||
} else {
|
||||
filter.show_action_types(open_rules_library_action.iter());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -540,30 +540,6 @@ impl Model {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn cache_configuration(&self) -> Option<BedrockModelCacheConfiguration> {
|
||||
match self {
|
||||
Self::ClaudeSonnet4
|
||||
| Self::ClaudeSonnet4_5
|
||||
| Self::ClaudeOpus4_1
|
||||
| Self::ClaudeOpus4_5
|
||||
| Self::ClaudeOpus4_6
|
||||
| Self::ClaudeOpus4_7
|
||||
| Self::ClaudeSonnet4_6 => Some(BedrockModelCacheConfiguration {
|
||||
max_cache_anchors: 4,
|
||||
min_total_token: 1024,
|
||||
}),
|
||||
Self::ClaudeHaiku4_5 => Some(BedrockModelCacheConfiguration {
|
||||
max_cache_anchors: 4,
|
||||
min_total_token: 2048,
|
||||
}),
|
||||
Self::Custom {
|
||||
cache_configuration,
|
||||
..
|
||||
} => cache_configuration.clone(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn supports_thinking(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
|
|
|
|||
|
|
@ -3,18 +3,10 @@ use super::*;
|
|||
impl Database {
|
||||
/// Creates a new user.
|
||||
#[cfg(feature = "test-support")]
|
||||
pub async fn create_user(
|
||||
&self,
|
||||
email_address: &str,
|
||||
name: Option<&str>,
|
||||
admin: bool,
|
||||
params: NewUserParams,
|
||||
) -> Result<NewUserResult> {
|
||||
pub async fn create_user(&self, admin: bool, params: NewUserParams) -> Result<NewUserResult> {
|
||||
self.transaction(|tx| async {
|
||||
let tx = tx;
|
||||
let user = user::Entity::insert(user::ActiveModel {
|
||||
email_address: ActiveValue::set(Some(email_address.into())),
|
||||
name: ActiveValue::set(name.map(|s| s.into())),
|
||||
github_login: ActiveValue::set(params.github_login.clone()),
|
||||
github_user_id: ActiveValue::set(params.github_user_id),
|
||||
admin: ActiveValue::set(admin),
|
||||
|
|
@ -22,11 +14,7 @@ impl Database {
|
|||
})
|
||||
.on_conflict(
|
||||
OnConflict::column(user::Column::GithubUserId)
|
||||
.update_columns([
|
||||
user::Column::Admin,
|
||||
user::Column::EmailAddress,
|
||||
user::Column::GithubLogin,
|
||||
])
|
||||
.update_columns([user::Column::Admin, user::Column::GithubLogin])
|
||||
.to_owned(),
|
||||
)
|
||||
.exec_with_returning(&*tx)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
use crate::db::UserId;
|
||||
use chrono::NaiveDateTime;
|
||||
use sea_orm::entity::prelude::*;
|
||||
use serde::Serialize;
|
||||
|
||||
|
|
@ -11,12 +10,8 @@ pub struct Model {
|
|||
pub id: UserId,
|
||||
pub github_login: String,
|
||||
pub github_user_id: i32,
|
||||
pub github_user_created_at: Option<NaiveDateTime>,
|
||||
pub email_address: Option<String>,
|
||||
pub name: Option<String>,
|
||||
pub admin: bool,
|
||||
pub connected_once: bool,
|
||||
pub created_at: NaiveDateTime,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
|
|
|
|||
|
|
@ -209,8 +209,6 @@ static GITHUB_USER_ID: AtomicI32 = AtomicI32::new(5);
|
|||
|
||||
async fn new_test_user(db: &Arc<Database>, email: &str) -> UserId {
|
||||
db.create_user(
|
||||
email,
|
||||
None,
|
||||
false,
|
||||
NewUserParams {
|
||||
github_login: email[0..email.find('@').unwrap()].to_string(),
|
||||
|
|
|
|||
|
|
@ -13,8 +13,6 @@ test_both_dbs!(
|
|||
async fn test_channel_buffers(db: &Arc<Database>) {
|
||||
let a_id = db
|
||||
.create_user(
|
||||
"user_a@example.com",
|
||||
None,
|
||||
false,
|
||||
NewUserParams {
|
||||
github_login: "user_a".into(),
|
||||
|
|
@ -26,8 +24,6 @@ async fn test_channel_buffers(db: &Arc<Database>) {
|
|||
.user_id;
|
||||
let b_id = db
|
||||
.create_user(
|
||||
"user_b@example.com",
|
||||
None,
|
||||
false,
|
||||
NewUserParams {
|
||||
github_login: "user_b".into(),
|
||||
|
|
@ -41,8 +37,6 @@ async fn test_channel_buffers(db: &Arc<Database>) {
|
|||
// This user will not be a part of the channel
|
||||
let c_id = db
|
||||
.create_user(
|
||||
"user_c@example.com",
|
||||
None,
|
||||
false,
|
||||
NewUserParams {
|
||||
github_login: "user_c".into(),
|
||||
|
|
@ -188,8 +182,6 @@ test_both_dbs!(
|
|||
async fn test_channel_buffers_last_operations(db: &Database) {
|
||||
let user_id = db
|
||||
.create_user(
|
||||
"user_a@example.com",
|
||||
None,
|
||||
false,
|
||||
NewUserParams {
|
||||
github_login: "user_a".into(),
|
||||
|
|
@ -201,8 +193,6 @@ async fn test_channel_buffers_last_operations(db: &Database) {
|
|||
.user_id;
|
||||
let observer_id = db
|
||||
.create_user(
|
||||
"user_b@example.com",
|
||||
None,
|
||||
false,
|
||||
NewUserParams {
|
||||
github_login: "user_b".into(),
|
||||
|
|
|
|||
|
|
@ -263,8 +263,6 @@ async fn test_channel_renames(db: &Arc<Database>) {
|
|||
|
||||
let user_1 = db
|
||||
.create_user(
|
||||
"user1@example.com",
|
||||
None,
|
||||
false,
|
||||
NewUserParams {
|
||||
github_login: "user1".into(),
|
||||
|
|
@ -277,8 +275,6 @@ async fn test_channel_renames(db: &Arc<Database>) {
|
|||
|
||||
let user_2 = db
|
||||
.create_user(
|
||||
"user2@example.com",
|
||||
None,
|
||||
false,
|
||||
NewUserParams {
|
||||
github_login: "user2".into(),
|
||||
|
|
@ -314,8 +310,6 @@ test_both_dbs!(
|
|||
async fn test_db_channel_moving(db: &Arc<Database>) {
|
||||
let a_id = db
|
||||
.create_user(
|
||||
"user1@example.com",
|
||||
None,
|
||||
false,
|
||||
NewUserParams {
|
||||
github_login: "user1".into(),
|
||||
|
|
@ -404,8 +398,6 @@ test_both_dbs!(
|
|||
async fn test_channel_reordering(db: &Arc<Database>) {
|
||||
let admin_id = db
|
||||
.create_user(
|
||||
"admin@example.com",
|
||||
None,
|
||||
false,
|
||||
NewUserParams {
|
||||
github_login: "admin".into(),
|
||||
|
|
@ -418,8 +410,6 @@ async fn test_channel_reordering(db: &Arc<Database>) {
|
|||
|
||||
let user_id = db
|
||||
.create_user(
|
||||
"user@example.com",
|
||||
None,
|
||||
false,
|
||||
NewUserParams {
|
||||
github_login: "user".into(),
|
||||
|
|
@ -599,8 +589,6 @@ test_both_dbs!(
|
|||
async fn test_db_channel_moving_bugs(db: &Arc<Database>) {
|
||||
let user_id = db
|
||||
.create_user(
|
||||
"user1@example.com",
|
||||
None,
|
||||
false,
|
||||
NewUserParams {
|
||||
github_login: "user1".into(),
|
||||
|
|
|
|||
|
|
@ -18,8 +18,6 @@ async fn test_add_contacts(db: &Arc<Database>) {
|
|||
for i in 0..3 {
|
||||
user_ids.push(
|
||||
db.create_user(
|
||||
&format!("user{i}@example.com"),
|
||||
None,
|
||||
false,
|
||||
NewUserParams {
|
||||
github_login: format!("user{i}"),
|
||||
|
|
@ -178,8 +176,6 @@ async fn test_project_count(db: &Arc<Database>) {
|
|||
|
||||
let user1 = db
|
||||
.create_user(
|
||||
"admin@example.com",
|
||||
None,
|
||||
true,
|
||||
NewUserParams {
|
||||
github_login: "admin".into(),
|
||||
|
|
@ -190,8 +186,6 @@ async fn test_project_count(db: &Arc<Database>) {
|
|||
.unwrap();
|
||||
let user2 = db
|
||||
.create_user(
|
||||
"user@example.com",
|
||||
None,
|
||||
false,
|
||||
NewUserParams {
|
||||
github_login: "user".into(),
|
||||
|
|
|
|||
|
|
@ -225,8 +225,6 @@ impl<T: RandomizedTest> TestPlan<T> {
|
|||
.app_state
|
||||
.db
|
||||
.create_user(
|
||||
&format!("{username}@example.com"),
|
||||
None,
|
||||
false,
|
||||
NewUserParams {
|
||||
github_login: username.clone(),
|
||||
|
|
|
|||
|
|
@ -535,23 +535,12 @@ impl ConfigurationView {
|
|||
label: impl Into<SharedString>,
|
||||
edit_prediction: bool,
|
||||
) -> impl IntoElement {
|
||||
ButtonLike::new("loading_button")
|
||||
Button::new("loading_button", label)
|
||||
.full_width()
|
||||
.disabled(true)
|
||||
.loading(true)
|
||||
.style(ButtonStyle::Outlined)
|
||||
.when(edit_prediction, |this| this.size(ButtonSize::Medium))
|
||||
.child(
|
||||
h_flex()
|
||||
.w_full()
|
||||
.gap_1()
|
||||
.justify_center()
|
||||
.child(
|
||||
Icon::new(IconName::ArrowCircle)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted)
|
||||
.with_rotate_animation(4),
|
||||
)
|
||||
.child(Label::new(label)),
|
||||
)
|
||||
}
|
||||
|
||||
fn render_sign_in_button(&self, edit_prediction: bool) -> impl IntoElement {
|
||||
|
|
|
|||
|
|
@ -1698,16 +1698,6 @@ impl EditPredictionStore {
|
|||
..
|
||||
} = pending_prediction;
|
||||
let settled_editable_region_for_metrics = settled_editable_region.clone();
|
||||
let kept_rate_result = cx
|
||||
.background_spawn(async move {
|
||||
compute_kept_rate(
|
||||
&editable_region_before_prediction,
|
||||
&predicted_editable_region,
|
||||
&settled_editable_region_for_metrics,
|
||||
)
|
||||
})
|
||||
.await;
|
||||
|
||||
#[cfg(test)]
|
||||
{
|
||||
let request_id = request_id.clone();
|
||||
|
|
@ -1718,12 +1708,17 @@ impl EditPredictionStore {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
cx.background_spawn({
|
||||
let client = client.clone();
|
||||
let llm_token = llm_token.clone();
|
||||
let app_version = app_version.clone();
|
||||
async move {
|
||||
let kept_rate_result = compute_kept_rate(
|
||||
&editable_region_before_prediction,
|
||||
&predicted_editable_region,
|
||||
&settled_editable_region_for_metrics,
|
||||
);
|
||||
|
||||
let result: anyhow::Result<()> = async {
|
||||
let settled_editable_region =
|
||||
can_collect_data.then_some(settled_editable_region);
|
||||
|
|
@ -1756,6 +1751,10 @@ impl EditPredictionStore {
|
|||
model_version,
|
||||
e2e_latency_ms: e2e_latency.as_millis(),
|
||||
};
|
||||
|
||||
let json_bytes = serde_json::to_vec(&body)?;
|
||||
let compressed = zstd::encode_all(&json_bytes[..], 3)?;
|
||||
|
||||
let url = client
|
||||
.http_client()
|
||||
.build_zed_llm_url("/predict_edits/settled", &[])?;
|
||||
|
|
@ -1763,7 +1762,8 @@ impl EditPredictionStore {
|
|||
|builder| {
|
||||
Ok(builder
|
||||
.uri(url.as_ref())
|
||||
.body(serde_json::to_string(&body)?.into())?)
|
||||
.header("Content-Encoding", "zstd")
|
||||
.body(compressed.clone().into())?)
|
||||
},
|
||||
client,
|
||||
llm_token,
|
||||
|
|
|
|||
|
|
@ -2541,6 +2541,11 @@ fn init_test_with_fake_client_and_legacy_data_collection(
|
|||
let http_client = FakeHttpClient::create({
|
||||
move |req| {
|
||||
let uri = req.uri().path().to_string();
|
||||
let content_encoding = req
|
||||
.headers()
|
||||
.get("Content-Encoding")
|
||||
.and_then(|value| value.to_str().ok())
|
||||
.map(str::to_owned);
|
||||
let mut body = req.into_body();
|
||||
let predict_req_tx = predict_req_tx.clone();
|
||||
let reject_req_tx = reject_req_tx.clone();
|
||||
|
|
@ -2573,7 +2578,12 @@ fn init_test_with_fake_client_and_legacy_data_collection(
|
|||
"/predict_edits/settled" => {
|
||||
let mut buf = Vec::new();
|
||||
body.read_to_end(&mut buf).await.ok();
|
||||
let req = serde_json::from_slice(&buf).unwrap();
|
||||
let body = if content_encoding.as_deref() == Some("zstd") {
|
||||
zstd::decode_all(&buf[..]).unwrap()
|
||||
} else {
|
||||
buf
|
||||
};
|
||||
let req = serde_json::from_slice(&body).unwrap();
|
||||
settled_req_tx.unbounded_send(req).unwrap();
|
||||
serde_json::to_string(&SubmitEditPredictionSettledResponse {}).unwrap()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ async fn run_git_blame(
|
|||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.kill_on_drop(true)
|
||||
.spawn()
|
||||
.context("starting git blame process")?
|
||||
};
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ profiling.workspace = true
|
|||
raw-window-handle = "0.6"
|
||||
smallvec.workspace = true
|
||||
swash = "0.2.6"
|
||||
unicode-segmentation.workspace = true
|
||||
gpui_util.workspace = true
|
||||
wgpu.workspace = true
|
||||
|
||||
|
|
@ -43,4 +44,11 @@ pollster.workspace = true
|
|||
wasm-bindgen.workspace = true
|
||||
wasm-bindgen-futures = "0.4"
|
||||
web-sys = { version = "0.3", features = ["HtmlCanvasElement"] }
|
||||
js-sys = "0.3"
|
||||
js-sys = "0.3"
|
||||
|
||||
[dev-dependencies]
|
||||
criterion.workspace = true
|
||||
|
||||
[[bench]]
|
||||
name = "layout_line"
|
||||
harness = false
|
||||
82
crates/gpui_wgpu/benches/layout_line.rs
Normal file
82
crates/gpui_wgpu/benches/layout_line.rs
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
use criterion::{Criterion, criterion_group, criterion_main};
|
||||
use gpui::{FontFallbacks, FontRun, PlatformTextSystem, font, px};
|
||||
use gpui_wgpu::CosmicTextSystem;
|
||||
use std::borrow::Cow;
|
||||
|
||||
const LILEX: &[u8] = include_bytes!("../../../assets/fonts/lilex/Lilex-Regular.ttf");
|
||||
const IBM_PLEX: &[u8] =
|
||||
include_bytes!("../../../assets/fonts/ibm-plex-sans/IBMPlexSans-Regular.ttf");
|
||||
|
||||
// ~4 000 chars of typical ASCII code text.
|
||||
fn code_text() -> String {
|
||||
concat!(
|
||||
" fn compute_run_spans(\n",
|
||||
" text: &str,\n",
|
||||
" run_offset: usize,\n",
|
||||
" run_len: usize,\n",
|
||||
" primary: FontId,\n",
|
||||
" fallback_chain: &[(FontId, SharedString)],\n",
|
||||
" covers: &impl Fn(FontId, char) -> bool,\n",
|
||||
" ) -> SmallVec<[RunSpan; 4]> {\n",
|
||||
" let mut spans = SmallVec::new();\n",
|
||||
" let run_end = run_offset + run_len;\n",
|
||||
" if run_end <= run_offset { return spans; }\n",
|
||||
" let run_text = &text[run_offset..run_end];\n",
|
||||
" let mut span_start = run_offset;\n",
|
||||
" let mut span_slot: Option<usize> = None;\n",
|
||||
" for (ch_idx, ch) in run_text.char_indices() {\n",
|
||||
" let abs = run_offset + ch_idx;\n",
|
||||
" let next = pick_covering_slot(ch, span_slot, primary, fallback_chain, covers);\n",
|
||||
" if next == span_slot { continue; }\n",
|
||||
" if abs > span_start {\n",
|
||||
" spans.push(RunSpan { start: span_start, end: abs, slot: span_slot });\n",
|
||||
" }\n",
|
||||
" span_start = abs;\n",
|
||||
" span_slot = next;\n",
|
||||
" }\n",
|
||||
" spans\n",
|
||||
" }\n",
|
||||
)
|
||||
.repeat(8) // ~3 800 chars
|
||||
}
|
||||
|
||||
fn bench_layout_line(c: &mut Criterion) {
|
||||
let system = CosmicTextSystem::new_without_system_fonts("Lilex");
|
||||
system
|
||||
.add_fonts(vec![Cow::Borrowed(LILEX), Cow::Borrowed(IBM_PLEX)])
|
||||
.unwrap();
|
||||
|
||||
let font_id_no_fallback = system.font_id(&font("Lilex")).unwrap();
|
||||
|
||||
let font_id_with_fallback = {
|
||||
let mut f = font("Lilex");
|
||||
f.fallbacks = Some(FontFallbacks::from_fonts(vec!["IBM Plex Sans".to_string()]));
|
||||
system.font_id(&f).unwrap()
|
||||
};
|
||||
|
||||
let text = code_text();
|
||||
|
||||
let runs_no_fallback = vec![FontRun {
|
||||
len: text.len(),
|
||||
font_id: font_id_no_fallback,
|
||||
}];
|
||||
let runs_with_fallback = vec![FontRun {
|
||||
len: text.len(),
|
||||
font_id: font_id_with_fallback,
|
||||
}];
|
||||
|
||||
let mut group = c.benchmark_group("layout_line");
|
||||
|
||||
group.bench_function("no_fallback", |b| {
|
||||
b.iter(|| system.layout_line(&text, px(14.0), &runs_no_fallback))
|
||||
});
|
||||
|
||||
group.bench_function("with_fallback_ascii", |b| {
|
||||
b.iter(|| system.layout_line(&text, px(14.0), &runs_with_fallback))
|
||||
});
|
||||
|
||||
group.finish();
|
||||
}
|
||||
|
||||
criterion_group!(benches, bench_layout_line);
|
||||
criterion_main!(benches);
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -232,10 +232,6 @@ pub trait LanguageModel: Send + Sync {
|
|||
.boxed()
|
||||
}
|
||||
|
||||
fn cache_configuration(&self) -> Option<LanguageModelCacheConfiguration> {
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
fn as_fake(&self) -> &fake_provider::FakeLanguageModel {
|
||||
unimplemented!()
|
||||
|
|
|
|||
|
|
@ -28,13 +28,6 @@ pub use crate::tool_schema::LanguageModelToolSchemaFormat;
|
|||
pub use crate::util::{fix_streamed_json, parse_prompt_too_long, parse_tool_arguments};
|
||||
pub use gpui_shared_string::SharedString;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct LanguageModelCacheConfiguration {
|
||||
pub max_cache_anchors: usize,
|
||||
pub should_speculate: bool,
|
||||
pub min_total_token: u64,
|
||||
}
|
||||
|
||||
/// A completion event from a language model.
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
||||
pub enum LanguageModelCompletionEvent {
|
||||
|
|
|
|||
|
|
@ -9,11 +9,10 @@ use gpui::{AnyView, App, AsyncApp, Context, Entity, Task, TaskExt};
|
|||
use http_client::HttpClient;
|
||||
use language_model::{
|
||||
ANTHROPIC_PROVIDER_ID, ANTHROPIC_PROVIDER_NAME, ApiKeyState, AuthenticateError,
|
||||
ConfigurationViewTargetAgent, EnvVar, IconOrSvg, LanguageModel,
|
||||
LanguageModelCacheConfiguration, LanguageModelCompletionError, LanguageModelCompletionEvent,
|
||||
LanguageModelId, LanguageModelName, LanguageModelProvider, LanguageModelProviderId,
|
||||
LanguageModelProviderName, LanguageModelProviderState, LanguageModelRequest,
|
||||
LanguageModelToolChoice, RateLimiter, env_var,
|
||||
ConfigurationViewTargetAgent, EnvVar, IconOrSvg, LanguageModel, LanguageModelCompletionError,
|
||||
LanguageModelCompletionEvent, LanguageModelId, LanguageModelName, LanguageModelProvider,
|
||||
LanguageModelProviderId, LanguageModelProviderName, LanguageModelProviderState,
|
||||
LanguageModelRequest, LanguageModelToolChoice, RateLimiter, env_var,
|
||||
};
|
||||
use settings::{Settings, SettingsStore};
|
||||
use std::sync::{Arc, LazyLock};
|
||||
|
|
@ -507,10 +506,6 @@ impl LanguageModel for AnthropicModel {
|
|||
});
|
||||
async move { Ok(future.await?.boxed()) }.boxed()
|
||||
}
|
||||
|
||||
fn cache_configuration(&self) -> Option<LanguageModelCacheConfiguration> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
struct ConfigurationView {
|
||||
|
|
|
|||
|
|
@ -32,12 +32,11 @@ use gpui::{
|
|||
use gpui_tokio::Tokio;
|
||||
use http_client::HttpClient;
|
||||
use language_model::{
|
||||
AuthenticateError, EnvVar, IconOrSvg, LanguageModel, LanguageModelCacheConfiguration,
|
||||
LanguageModelCompletionError, LanguageModelCompletionEvent, LanguageModelId, LanguageModelName,
|
||||
LanguageModelProvider, LanguageModelProviderId, LanguageModelProviderName,
|
||||
LanguageModelProviderState, LanguageModelRequest, LanguageModelToolChoice,
|
||||
LanguageModelToolResultContent, LanguageModelToolUse, MessageContent, RateLimiter, Role,
|
||||
TokenUsage, env_var,
|
||||
AuthenticateError, EnvVar, IconOrSvg, LanguageModel, LanguageModelCompletionError,
|
||||
LanguageModelCompletionEvent, LanguageModelId, LanguageModelName, LanguageModelProvider,
|
||||
LanguageModelProviderId, LanguageModelProviderName, LanguageModelProviderState,
|
||||
LanguageModelRequest, LanguageModelToolChoice, LanguageModelToolResultContent,
|
||||
LanguageModelToolUse, MessageContent, RateLimiter, Role, TokenUsage, env_var,
|
||||
};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
|
@ -799,16 +798,6 @@ impl LanguageModel for BedrockModel {
|
|||
|
||||
async move { Ok(future.await?.boxed()) }.boxed()
|
||||
}
|
||||
|
||||
fn cache_configuration(&self) -> Option<LanguageModelCacheConfiguration> {
|
||||
self.model
|
||||
.cache_configuration()
|
||||
.map(|config| LanguageModelCacheConfiguration {
|
||||
max_cache_anchors: config.max_cache_anchors,
|
||||
should_speculate: false,
|
||||
min_total_token: config.min_total_token,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn deny_tool_use_events(
|
||||
|
|
|
|||
|
|
@ -1015,6 +1015,7 @@ impl Render for ConfigurationView {
|
|||
.unwrap_or_else(|| "Signed in".to_string());
|
||||
|
||||
let weak_state = self.state.downgrade();
|
||||
|
||||
return v_flex()
|
||||
.child(
|
||||
ConfiguredApiCard::new(SharedString::from(label))
|
||||
|
|
@ -1026,30 +1027,52 @@ impl Render for ConfigurationView {
|
|||
.into_any_element();
|
||||
}
|
||||
|
||||
if state.is_signing_in() {
|
||||
return v_flex()
|
||||
.child(Label::new("Signing in…").color(Color::Muted))
|
||||
.into_any_element();
|
||||
}
|
||||
|
||||
let last_auth_error = state.last_auth_error.clone();
|
||||
let provider_state = self.state.clone();
|
||||
let http_client = self.http_client.clone();
|
||||
|
||||
let is_signing_in = state.is_signing_in();
|
||||
let button_label = if is_signing_in {
|
||||
"Signing in…"
|
||||
} else {
|
||||
"Sign in to use ChatGPT Subscription"
|
||||
};
|
||||
|
||||
v_flex()
|
||||
.gap_2()
|
||||
.when_some(last_auth_error, |this, error| {
|
||||
this.child(Label::new(error).color(Color::Error))
|
||||
})
|
||||
.child(Label::new(
|
||||
"Sign in with your ChatGPT Plus or Pro subscription to use OpenAI models in Zed's agent.",
|
||||
))
|
||||
.child(
|
||||
Button::new("sign-in", "Sign in with ChatGPT")
|
||||
Button::new("sign-in", button_label)
|
||||
.full_width()
|
||||
.style(ButtonStyle::Outlined)
|
||||
.loading(is_signing_in)
|
||||
.disabled(is_signing_in)
|
||||
.when(!is_signing_in, |this| {
|
||||
this.start_icon(
|
||||
Icon::new(IconName::AiOpenAi)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
})
|
||||
.on_click(move |_, _window, cx| {
|
||||
do_sign_in(&provider_state, &http_client, cx);
|
||||
}),
|
||||
)
|
||||
.when_some(last_auth_error, |this, error| {
|
||||
this.child(
|
||||
h_flex()
|
||||
.gap_1()
|
||||
.justify_center()
|
||||
.child(
|
||||
Icon::new(IconName::XCircle)
|
||||
.color(Color::Error)
|
||||
.size(IconSize::Small),
|
||||
)
|
||||
.child(Label::new(error).color(Color::Muted)),
|
||||
)
|
||||
})
|
||||
.into_any_element()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,12 +20,12 @@ use http_client::{
|
|||
};
|
||||
use language_model::{
|
||||
ANTHROPIC_PROVIDER_ID, ANTHROPIC_PROVIDER_NAME, GOOGLE_PROVIDER_ID, GOOGLE_PROVIDER_NAME,
|
||||
LanguageModel, LanguageModelCacheConfiguration, LanguageModelCompletionError,
|
||||
LanguageModelCompletionEvent, LanguageModelEffortLevel, LanguageModelId, LanguageModelName,
|
||||
LanguageModelProviderId, LanguageModelProviderName, LanguageModelRequest,
|
||||
LanguageModelToolChoice, LanguageModelToolSchemaFormat, OPEN_AI_PROVIDER_ID,
|
||||
OPEN_AI_PROVIDER_NAME, PaymentRequiredError, RateLimiter, X_AI_PROVIDER_ID, X_AI_PROVIDER_NAME,
|
||||
ZED_CLOUD_PROVIDER_ID, ZED_CLOUD_PROVIDER_NAME,
|
||||
LanguageModel, LanguageModelCompletionError, LanguageModelCompletionEvent,
|
||||
LanguageModelEffortLevel, LanguageModelId, LanguageModelName, LanguageModelProviderId,
|
||||
LanguageModelProviderName, LanguageModelRequest, LanguageModelToolChoice,
|
||||
LanguageModelToolSchemaFormat, OPEN_AI_PROVIDER_ID, OPEN_AI_PROVIDER_NAME,
|
||||
PaymentRequiredError, RateLimiter, X_AI_PROVIDER_ID, X_AI_PROVIDER_NAME, ZED_CLOUD_PROVIDER_ID,
|
||||
ZED_CLOUD_PROVIDER_NAME,
|
||||
};
|
||||
|
||||
use schemars::JsonSchema;
|
||||
|
|
@ -368,21 +368,6 @@ impl<TP: CloudLlmTokenProvider + 'static> LanguageModel for CloudLanguageModel<T
|
|||
Some(self.model.max_output_tokens as u64)
|
||||
}
|
||||
|
||||
fn cache_configuration(&self) -> Option<LanguageModelCacheConfiguration> {
|
||||
match &self.model.provider {
|
||||
cloud_llm_client::LanguageModelProvider::Anthropic => {
|
||||
Some(LanguageModelCacheConfiguration {
|
||||
min_total_token: 2_048,
|
||||
should_speculate: true,
|
||||
max_cache_anchors: 4,
|
||||
})
|
||||
}
|
||||
cloud_llm_client::LanguageModelProvider::OpenAi
|
||||
| cloud_llm_client::LanguageModelProvider::XAi
|
||||
| cloud_llm_client::LanguageModelProvider::Google => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn stream_completion(
|
||||
&self,
|
||||
request: LanguageModelRequest,
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ Zed supports these providers with your own API keys:
|
|||
|
||||
- [Amazon Bedrock](#amazon-bedrock)
|
||||
- [Anthropic](#anthropic)
|
||||
- [ChatGPT Subscription](#chatgpt-subscription)
|
||||
- [DeepSeek](#deepseek)
|
||||
- [GitHub Copilot Chat](#github-copilot-chat)
|
||||
- [Google AI](#google-ai)
|
||||
|
|
@ -225,6 +226,18 @@ You can configure a model to use [extended thinking](https://docs.anthropic.com/
|
|||
}
|
||||
```
|
||||
|
||||
### ChatGPT Subscription {#chatgpt-subscription}
|
||||
|
||||
Use your existing ChatGPT Plus or Pro subscription to access OpenAI models directly in Zed — no separate API key required.
|
||||
|
||||
1. Open the settings view ({#action agent::OpenSettings}) and go to the ChatGPT Subscription section
|
||||
2. Click **Sign in** and complete the OpenAI authentication in your browser
|
||||
3. Once signed in, models appear in the model dropdown, including GPT-5.5 and GPT-5.3 Codex
|
||||
|
||||
To sign out, click **Sign Out** in the ChatGPT Subscription settings.
|
||||
|
||||
> **Note:** Model availability depends on your ChatGPT subscription tier. Some models may require ChatGPT Pro.
|
||||
|
||||
### DeepSeek {#deepseek}
|
||||
|
||||
1. Visit the DeepSeek platform and [create an API key](https://platform.deepseek.com/api_keys)
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@ fn docs_build_steps(
|
|||
|
||||
steps::use_clang(
|
||||
job.add_env(("DOCS_AMPLITUDE_API_KEY", vars::DOCS_AMPLITUDE_API_KEY))
|
||||
.add_env(("DOCS_CONSENT_IO_INSTANCE", vars::DOCS_CONSENT_IO_INSTANCE))
|
||||
.add_step(
|
||||
steps::checkout_repo().when_some(checkout_ref, |step, checkout_ref| {
|
||||
step.with_ref(checkout_ref)
|
||||
|
|
@ -269,6 +270,10 @@ pub(crate) fn deploy_docs_workflow_call(
|
|||
"DOCS_AMPLITUDE_API_KEY".to_owned(),
|
||||
vars::DOCS_AMPLITUDE_API_KEY.to_owned(),
|
||||
),
|
||||
(
|
||||
"DOCS_CONSENT_IO_INSTANCE".to_owned(),
|
||||
vars::DOCS_CONSENT_IO_INSTANCE.to_owned(),
|
||||
),
|
||||
(
|
||||
"CLOUDFLARE_API_TOKEN".to_owned(),
|
||||
vars::CLOUDFLARE_API_TOKEN.to_owned(),
|
||||
|
|
@ -327,6 +332,13 @@ pub(crate) fn deploy_docs() -> Workflow {
|
|||
required: true,
|
||||
},
|
||||
),
|
||||
(
|
||||
"DOCS_CONSENT_IO_INSTANCE".to_owned(),
|
||||
WorkflowCallSecret {
|
||||
description: "DOCS_CONSENT_IO_INSTANCE".to_owned(),
|
||||
required: true,
|
||||
},
|
||||
),
|
||||
(
|
||||
"CLOUDFLARE_API_TOKEN".to_owned(),
|
||||
WorkflowCallSecret {
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ secret!(R2_SECRET_ACCESS_KEY);
|
|||
secret!(CLOUDFLARE_API_TOKEN);
|
||||
secret!(CLOUDFLARE_ACCOUNT_ID);
|
||||
secret!(DOCS_AMPLITUDE_API_KEY);
|
||||
secret!(DOCS_CONSENT_IO_INSTANCE);
|
||||
|
||||
// todo(ci) make these secrets too...
|
||||
var!(AZURE_SIGNING_ACCOUNT_NAME);
|
||||
|
|
|
|||
Loading…
Reference in a new issue