Skip to content

Commit dc2a320

Browse files
authored
Merge pull request #330 from OpenAgentPlatform/skills
support skills and more slash commands
2 parents cb4b633 + f5e0cf7 commit dc2a320

35 files changed

Lines changed: 759 additions & 83 deletions

electron/main/constant.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export const scriptsDir = path.join(appDir, "scripts")
3535
export const configDir = app.isPackaged ? path.join(appDir, "config") : path.join(process.cwd(), ".config")
3636
export const hostCacheDir = path.join(appDir, "host_cache")
3737
export const logDir = path.join(appDir, "log")
38+
export const skillsDir = path.join(appDir, "skills")
3839

3940
export const binDirList = [
4041
path.join(process.resourcesPath, "node"),

electron/main/service.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import {
1717
DEF_MCP_SERVER_NAME,
1818
getDefMcpBinPath,
1919
binDir,
20+
appDir,
21+
skillsDir,
2022
} from "./constant.js"
2123
import spawn from "cross-spawn"
2224
import { ChildProcess, SpawnOptions, StdioOptions } from "node:child_process"
@@ -185,6 +187,7 @@ async function startHostService() {
185187
...process.env,
186188
DIVE_CONFIG_DIR: baseConfigDir,
187189
RESOURCE_DIR: hostCacheDir,
190+
DIVE_SKILL_DIR: skillsDir,
188191
DIVE_USER_AGENT: `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Dive/${packageJson.version} (+https://github.com/OpenAgentPlatform/Dive)`,
189192
}
190193

src-tauri/src/host.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use tokio::{
1111
io::{AsyncBufReadExt, AsyncWriteExt, BufReader, BufWriter},
1212
};
1313

14-
use crate::{dependency::{NODEJS_BIN_DIR, UV_BIN_DIR}, process::command::Command, shared::{DEF_MCP_BIN_NAME, VERSION}};
14+
use crate::{dependency::NODEJS_BIN_DIR, process::command::Command, shared::{DEF_MCP_BIN_NAME, VERSION}};
1515

1616
pub const COMMAND_ALIAS_FILE: &str = "command_alias.json";
1717
pub const CUSTOM_RULES_FILE: &str = "customrules";
@@ -134,6 +134,7 @@ impl HostProcess {
134134
.env("PATH", crate::util::get_system_path().await)
135135
.env("DIVE_CONFIG_DIR", dirs.config)
136136
.env("RESOURCE_DIR", dirs.cache)
137+
.env("DIVE_SKILL_DIR", dirs.skills)
137138
.env("DIVE_USER_AGENT", format!("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Dive/{} (+https://github.com/OpenAgentPlatform/Dive)", VERSION))
138139
.current_dir(dunce::simplified(cwd))
139140
.stderr(Stdio::piped())
@@ -142,6 +143,7 @@ impl HostProcess {
142143
// set bin path for builtin tools
143144
#[cfg(not(debug_assertions))]
144145
{
146+
use crate::dependency::UV_BIN_DIR;
145147
let uvx_path = if cfg!(windows) {
146148
UV_BIN_DIR.join("uvx.exe")
147149
} else {

src-tauri/src/shared.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ pub static PROJECT_DIRS: LazyLock<Dirs> = LazyLock::new(|| {
3838
bus: home.join(".dive/host_cache/bus"),
3939
log: home.join(".dive/log"),
4040
bin: home.join(".dive/bin"),
41+
skills: home.join(".dive/skills"),
4142

4243
#[cfg(debug_assertions)]
4344
config: std::env::current_dir().unwrap().join("../.config"),
@@ -54,4 +55,5 @@ pub struct Dirs {
5455
pub bus: PathBuf,
5556
pub log: PathBuf,
5657
pub bin: PathBuf,
58+
pub skills: PathBuf,
5759
}

src/atoms/configState.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { isLoggedInOAPAtom, OAPLevelAtom } from "./oapState"
55
import { OAP_PROXY_URL } from "../../shared/oap"
66
import { ModelGroupSetting, ModelProvider, ModelVerifyStatus } from "../../types/model"
77
import { modelSettingsAtom } from "./modelState"
8-
import { defaultBaseModel, defaultModelGroup, intoRawModelConfig, intoRawModelConfigWithQuery, reverseQueryGroup } from "../helper/model"
8+
import { defaultBaseModel, defaultModelGroup, GroupTerm, intoRawModelConfig, intoRawModelConfigWithQuery, ModelTerm, queryGroup, queryModel, reverseQueryGroup } from "../helper/model"
99
import { getVerifyKeyFromModelConfig } from "../helper/verify"
1010
import { oapGetToken } from "../ipc"
1111
import { fetchModels } from "../ipc/llm"
@@ -385,6 +385,26 @@ export const writeOapConfigAtom = atom(
385385
}
386386
)
387387

388+
export const selectModelAtom = atom(
389+
null,
390+
async (get, set, value: { group: GroupTerm, model: ModelTerm }) => {
391+
const settings = get(modelSettingsAtom)
392+
const group = queryGroup(value.group, settings.groups)
393+
if (group.length === 0) {
394+
throw new Error("Group not found")
395+
}
396+
397+
const model = queryModel(value.model, group[0])
398+
if (model.length === 0) {
399+
throw new Error("Model not found")
400+
}
401+
402+
const data = await set(writeRawConfigAtom, intoRawModelConfig(settings, group[0], model[0])!)
403+
localStorage.setItem("selectedModel", JSON.stringify(value))
404+
return data
405+
}
406+
)
407+
388408
export const reloadOapConfigAtom = atom(
389409
null,
390410
async (get, set) => {

src/atoms/modelState.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { atom } from "jotai"
2-
import { LLMGroup, ModelGroupSetting } from "../../types/model"
3-
import { defaultModelGroupSetting, getGroupTerm, removeGroup, updateGroup } from "../helper/model"
2+
import { LLMGroup, ModelGroupSetting, ModelProvider } from "../../types/model"
3+
import { defaultModelGroupSetting, getGroupTerm, getModelNamePrefix, getModelTerm, GroupTerm, ModelTerm, removeGroup, updateGroup } from "../helper/model"
44

55
export const modelSettingsAtom = atom<ModelGroupSetting>(defaultModelGroupSetting())
66

@@ -24,6 +24,27 @@ export const disableModelGroupAtom = atom(
2424
}
2525
)
2626

27+
export interface ModelOption {
28+
provider: ModelProvider
29+
name: string
30+
value: { group: GroupTerm, model: ModelTerm }
31+
}
32+
33+
export const modelListAtom = atom<ModelOption[]>((get) => {
34+
const settings = get(modelSettingsAtom)
35+
return settings.groups
36+
.filter(group => group.active)
37+
.flatMap(group =>
38+
group.models
39+
.filter(m => m.active && m.verifyStatus !== "unSupportModel")
40+
.map(m => ({
41+
provider: group.modelProvider,
42+
name: `${getModelNamePrefix(group) ?? ""}/${m.model}`,
43+
value: { group: getGroupTerm(group), model: getModelTerm(m) }
44+
}))
45+
)
46+
})
47+
2748
export const removeModelGroupAtom = atom(
2849
null,
2950
(get, set, group: LLMGroup) => {

src/atoms/skillState.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { atom } from "jotai"
2+
import { fetchSkills, type Skill } from "../ipc/skills"
3+
4+
export type { Skill } from "../ipc/skills"
5+
6+
export const skillsAtom = atom<Skill[]>([])
7+
8+
export const loadSkillsAtom = atom(null, async (_get, set) => {
9+
try {
10+
const skills = await fetchSkills()
11+
set(skillsAtom, skills)
12+
} catch (error) {
13+
console.error("Failed to load skills:", error)
14+
set(skillsAtom, [])
15+
}
16+
})

0 commit comments

Comments
 (0)