forked from BasedHardware/omi
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathChatProvider+Skills.swift
More file actions
75 lines (65 loc) · 2.94 KB
/
Copy pathChatProvider+Skills.swift
File metadata and controls
75 lines (65 loc) · 2.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
import Foundation
extension ChatProvider {
func skillContextProjection() -> [String: Any] {
ChatSkillCatalog.contextProjection(
globalSkills: discoveredSkills,
projectSkills: projectDiscoveredSkills,
disabledSkills: getDisabledSkillNames()
)
}
/// Get the set of enabled skill names (all skills minus explicitly disabled ones).
func getEnabledSkillNames() -> Set<String> {
Set(
ChatSkillCatalog.enabledSkills(
globalSkills: discoveredSkills,
projectSkills: projectDiscoveredSkills,
disabledSkills: getDisabledSkillNames()
).map(\.name)
)
}
// MARK: - Lane gating
/// Whether the ACP lane's user-skills plugin is active. The runtime itself
/// gates the plugin on `.claude-plugin/plugin.json` (user-extensions.ts), so
/// the desktop asks the exact same question.
nonisolated static func acpSkillsPluginActive() -> Bool {
FileManager.default.fileExists(atPath: LocalSkillsStore.pluginManifestURL.path)
}
/// The skill catalog has one source of truth per lane. On the pi-mono lane it
/// is the compact catalog plus the load_skill/search_skills tools. On the ACP
/// lane the user-skills plugin already ships the skills natively, so the
/// compact catalog would hand the model the same index twice.
nonisolated static func shouldInjectSkillCatalog(adapterId: String) -> Bool {
adapterId != AgentAdapterId.acp.rawValue || !acpSkillsPluginActive()
}
// MARK: - Disabled skills
/// Explicitly disabled skill names straight from UserDefaults, for callers
/// without a provider instance (task chat, runtime spawn env). The parse —
/// and the set's rename/delete upkeep — live on `LocalSkillsStore`, which
/// owns the slug identity.
nonisolated static func disabledSkillNamesFromDefaults() -> Set<String> {
LocalSkillsStore.disabledSkillNames()
}
/// Canonical JSON array exported to the runtime as `OMI_DISABLED_SKILLS`, so
/// load_skill/search_skills enforce the toggle the same way this catalog
/// does. Nil when nothing is disabled, keeping the env unset.
nonisolated static func disabledSkillsRuntimeEnvValue() -> String? {
let names = disabledSkillNamesFromDefaults().sorted()
guard !names.isEmpty,
let data = try? JSONEncoder().encode(names),
let json = String(data: data, encoding: .utf8)
else { return nil }
return json
}
// MARK: - Disk-backed projection
/// The compact skill catalog built straight from disk, for runtimes that have
/// no ChatProvider instance (task-chat workstreams). Same builder, same
/// disabled filtering as the per-turn injection.
nonisolated static func skillCatalogProjectionFromDisk(workspace: String) -> [String: Any] {
let config = loadClaudeConfigFromDisk(workspace: workspace)
return ChatSkillCatalog.contextProjection(
globalSkills: config.skills,
projectSkills: config.projectSkills,
disabledSkills: disabledSkillNamesFromDefaults()
)
}
}