@bibobonking/opensol 3.1.4 → 3.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -12
- package/desktop/src-tauri/icons/128x128.png +0 -0
- package/desktop/src-tauri/icons/128x128@2x.png +0 -0
- package/desktop/src-tauri/icons/32x32.png +0 -0
- package/desktop/src-tauri/icons/64x64.png +0 -0
- package/desktop/src-tauri/icons/Square107x107Logo.png +0 -0
- package/desktop/src-tauri/icons/Square142x142Logo.png +0 -0
- package/desktop/src-tauri/icons/Square150x150Logo.png +0 -0
- package/desktop/src-tauri/icons/Square284x284Logo.png +0 -0
- package/desktop/src-tauri/icons/Square30x30Logo.png +0 -0
- package/desktop/src-tauri/icons/Square310x310Logo.png +0 -0
- package/desktop/src-tauri/icons/Square44x44Logo.png +0 -0
- package/desktop/src-tauri/icons/Square71x71Logo.png +0 -0
- package/desktop/src-tauri/icons/Square89x89Logo.png +0 -0
- package/desktop/src-tauri/icons/StoreLogo.png +0 -0
- package/desktop/src-tauri/icons/icon.icns +0 -0
- package/desktop/src-tauri/icons/icon.ico +0 -0
- package/desktop/src-tauri/icons/icon.png +0 -0
- package/dist/assets/index-C0yvs6Vl.js +281 -0
- package/dist/assets/index-CxNPLBg7.css +1 -0
- package/dist/favicon.svg +18 -15
- package/dist/index.html +2 -2
- package/package.json +1 -1
- package/public/favicon.svg +18 -15
- package/server/daemon.mjs +66 -49
- package/server/lib/deploy.mjs +222 -121
- package/server/lib/providers.mjs +23 -1
- package/server/lib/skills.mjs +385 -100
- package/server/lib/tools.mjs +0 -40
- package/src/agent/adapters/openai-responses.ts +1 -5
- package/src/agent/adapters/openai.ts +4 -11
- package/src/agent/prompt.ts +7 -14
- package/src/agent/subagent.ts +3 -14
- package/src/agent/tools.ts +2 -0
- package/src/components/ChatView.tsx +2 -1
- package/src/components/Composer.tsx +2 -1
- package/src/components/ContextBar.tsx +10 -0
- package/src/components/DeployModal.tsx +266 -252
- package/src/components/FileIcon.tsx +391 -99
- package/src/components/HomeDashboard.tsx +5 -10
- package/src/components/Logo.tsx +9 -11
- package/src/components/ModelDeck.tsx +8 -11
- package/src/components/SettingsModal.tsx +160 -122
- package/src/components/Sidebar.tsx +4 -3
- package/src/components/SystemPromptButton.tsx +198 -0
- package/src/components/ToolCallCard.tsx +2 -0
- package/src/components/TopBar.tsx +2 -19
- package/src/components/WorkspacePanel.tsx +76 -93
- package/src/core/plugins/tools/skill.ts +19 -76
- package/src/core/services/agent-loop.ts +16 -31
- package/src/core/services/subagents.ts +2 -2
- package/src/core/services/system-prompt.ts +16 -23
- package/src/core/services/tools.ts +0 -1
- package/src/lib/boot.ts +2 -0
- package/src/lib/credits.ts +33 -0
- package/src/lib/daemon.ts +40 -19
- package/src/lib/permissions.ts +1 -1
- package/src/lib/retry.test.mjs +40 -12
- package/src/lib/retry.ts +41 -8
- package/src/lib/system-prompt.ts +23 -0
- package/src/lib/usage.ts +8 -13
- package/src/store/chats.ts +0 -1
- package/src/store/settings.ts +12 -44
- package/src/store/skills.ts +79 -0
- package/src/store/ui.ts +3 -1
- package/src/types.ts +30 -15
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/assets/index-B1pQC9Fe.js +0 -288
- package/dist/assets/index-qLr4aZVC.css +0 -1
- package/src/components/SystemPromptModal.tsx +0 -168
- package/src/lib/skills.test.mjs +0 -22
- package/src/lib/skills.ts +0 -93
package/src/agent/prompt.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { AgentMode, AppSettings } from '../types'
|
|
|
2
2
|
import { activeModelId } from '../store/settings'
|
|
3
3
|
import { useWorkspace } from '../store/workspace'
|
|
4
4
|
import { kernel } from '../core/kernel'
|
|
5
|
+
import { skillCatalogPrompt } from '../store/skills'
|
|
5
6
|
|
|
6
7
|
function workspaceContext(): string {
|
|
7
8
|
const state = useWorkspace.getState()
|
|
@@ -26,22 +27,14 @@ function workspaceContext(): string {
|
|
|
26
27
|
.join('\n')
|
|
27
28
|
}
|
|
28
29
|
|
|
29
|
-
export function buildSystemPrompt(settings: AppSettings, mode: AgentMode = settings.mode): string {
|
|
30
|
+
export function buildSystemPrompt(settings: AppSettings, mode: AgentMode = settings.mode, sessionId?: string): string {
|
|
30
31
|
if (kernel.systemPrompt) {
|
|
31
|
-
return kernel.systemPrompt.assemble(settings, mode)
|
|
32
|
+
return kernel.systemPrompt.assemble(settings, mode, sessionId)
|
|
32
33
|
}
|
|
33
34
|
const chunks: string[] = [settings.systemPrompt.trim()]
|
|
34
35
|
|
|
35
|
-
const
|
|
36
|
-
if (
|
|
37
|
-
chunks.push(
|
|
38
|
-
[
|
|
39
|
-
'## Available skills',
|
|
40
|
-
'Call the `skill` tool to load the full instructions (and run scripts from the skill folder) when a task matches one of these. Do not guess a skill’s contents.',
|
|
41
|
-
...skills.map((skill) => `- ${skill.name} (${skill.id}): ${skill.description}`),
|
|
42
|
-
].join('\n'),
|
|
43
|
-
)
|
|
44
|
-
}
|
|
36
|
+
const catalog = skillCatalogPrompt()
|
|
37
|
+
if (catalog && settings.tools.skill?.enabled !== false) chunks.push(catalog)
|
|
45
38
|
|
|
46
39
|
chunks.push(
|
|
47
40
|
[
|
|
@@ -89,9 +82,9 @@ export function buildSystemPrompt(settings: AppSettings, mode: AgentMode = setti
|
|
|
89
82
|
return chunks.filter(Boolean).join('\n\n')
|
|
90
83
|
}
|
|
91
84
|
|
|
92
|
-
export function buildSubagentPrompt(settings: AppSettings): string {
|
|
85
|
+
export function buildSubagentPrompt(settings: AppSettings, sessionId?: string): string {
|
|
93
86
|
return [
|
|
94
|
-
buildSystemPrompt(settings, 'plan'),
|
|
87
|
+
buildSystemPrompt(settings, 'plan', sessionId),
|
|
95
88
|
[
|
|
96
89
|
'## Subagent',
|
|
97
90
|
'You are a focused read-only investigator. Work only on the assigned task.',
|
package/src/agent/subagent.ts
CHANGED
|
@@ -11,8 +11,6 @@ import { streamModel } from './model'
|
|
|
11
11
|
import { buildSubagentPrompt } from './prompt'
|
|
12
12
|
import { executeTool } from './tools'
|
|
13
13
|
|
|
14
|
-
const MAX_SUBAGENT_ROUNDS = 6
|
|
15
|
-
|
|
16
14
|
function id(prefix: string) {
|
|
17
15
|
const raw =
|
|
18
16
|
typeof crypto !== 'undefined' && 'randomUUID' in crypto
|
|
@@ -33,6 +31,7 @@ export async function runSubagent(
|
|
|
33
31
|
task: string,
|
|
34
32
|
context: string,
|
|
35
33
|
signal: AbortSignal,
|
|
34
|
+
sessionId?: string,
|
|
36
35
|
): Promise<string> {
|
|
37
36
|
const cleanTask = task.trim()
|
|
38
37
|
if (!cleanTask) return 'The subagent was not given a task.'
|
|
@@ -40,7 +39,7 @@ export async function runSubagent(
|
|
|
40
39
|
|
|
41
40
|
const settings = useSettings.getState()
|
|
42
41
|
const model = findModel(settings.provider, settings.model)
|
|
43
|
-
const system = buildSubagentPrompt(settings)
|
|
42
|
+
const system = buildSubagentPrompt(settings, sessionId)
|
|
44
43
|
const now = Date.now()
|
|
45
44
|
const first: UserMessage = {
|
|
46
45
|
id: id('sub'),
|
|
@@ -55,9 +54,8 @@ export async function runSubagent(
|
|
|
55
54
|
createdAt: now,
|
|
56
55
|
}
|
|
57
56
|
const history: Message[] = [first]
|
|
58
|
-
let lastContent = ''
|
|
59
57
|
|
|
60
|
-
for (let round = 0;
|
|
58
|
+
for (let round = 0; ; round += 1) {
|
|
61
59
|
if (signal.aborted) throw abortError()
|
|
62
60
|
const result = await streamModel({
|
|
63
61
|
settings,
|
|
@@ -68,8 +66,6 @@ export async function runSubagent(
|
|
|
68
66
|
signal,
|
|
69
67
|
handlers: EMPTY_HANDLERS,
|
|
70
68
|
})
|
|
71
|
-
if (result.content.trim()) lastContent = result.content.trim()
|
|
72
|
-
|
|
73
69
|
const assistant: AssistantMessage = {
|
|
74
70
|
id: id('submsg'),
|
|
75
71
|
role: 'assistant',
|
|
@@ -99,11 +95,4 @@ export async function runSubagent(
|
|
|
99
95
|
history.push(toolMessage)
|
|
100
96
|
}
|
|
101
97
|
}
|
|
102
|
-
|
|
103
|
-
return [
|
|
104
|
-
lastContent,
|
|
105
|
-
`The subagent stopped after ${MAX_SUBAGENT_ROUNDS} investigation rounds. Continue with the evidence above or ask a narrower question.`,
|
|
106
|
-
]
|
|
107
|
-
.filter(Boolean)
|
|
108
|
-
.join('\n\n')
|
|
109
98
|
}
|
package/src/agent/tools.ts
CHANGED
|
@@ -538,6 +538,8 @@ export function toolSummary(name: ToolName, args: Record<string, unknown>): stri
|
|
|
538
538
|
? args.action
|
|
539
539
|
: name === 'subagent'
|
|
540
540
|
? args.task
|
|
541
|
+
: name === 'skill'
|
|
542
|
+
? [args.name, args.file].filter(Boolean).join(' / ')
|
|
541
543
|
: (args.path ?? '')
|
|
542
544
|
return typeof value === 'string' ? value : ''
|
|
543
545
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useSkills } from '../store/skills'
|
|
1
2
|
import { useEffect, useRef, useState } from 'react'
|
|
2
3
|
import { ArrowUp, Bug, FlaskConical, FolderSearch, Gamepad2, Globe2, KeyRound, LayoutTemplate, ListChecks, Sparkles } from 'lucide-react'
|
|
3
4
|
import type { Attachment } from '../types'
|
|
@@ -86,7 +87,7 @@ export function ChatView() {
|
|
|
86
87
|
const lastAssistantId = [...messages].reverse().find((message) => message.role === 'assistant')?.id
|
|
87
88
|
const connected = hasCredentials(settings)
|
|
88
89
|
const selectedModel = activeModelId(settings)
|
|
89
|
-
const activeSkills =
|
|
90
|
+
const activeSkills = useSkills((state) => state.skills.filter((skill) => skill.enabled).length)
|
|
90
91
|
const turns = groupConversationTurns(messages)
|
|
91
92
|
const context = getContextUsage(messages, activeModel)
|
|
92
93
|
const mood = pixleMood(messages, streaming)
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
X,
|
|
25
25
|
} from 'lucide-react'
|
|
26
26
|
import type { Attachment } from '../types'
|
|
27
|
+
import { useSkills } from '../store/skills'
|
|
27
28
|
import { activeModelId, hasCredentials, useSettings } from '../store/settings'
|
|
28
29
|
import { useActiveModel, useProviderModels } from '../store/models'
|
|
29
30
|
import { useUi } from '../store/ui'
|
|
@@ -124,7 +125,7 @@ export function Composer({
|
|
|
124
125
|
const activeModel = useActiveModel()
|
|
125
126
|
const connected = hasCredentials(settings)
|
|
126
127
|
const efforts = effortOptions(activeModel)
|
|
127
|
-
const activeSkills =
|
|
128
|
+
const activeSkills = useSkills((state) => state.skills.filter((skill) => skill.enabled).length)
|
|
128
129
|
const permission = permissionMode(settings.tools)
|
|
129
130
|
const modelLabel = !connected
|
|
130
131
|
? 'No provider'
|
|
@@ -10,6 +10,7 @@ import { useMemo } from 'react'
|
|
|
10
10
|
import type { ModelInfo, Message } from '../types'
|
|
11
11
|
import { getContextUsage, AUTO_COMPACT_THRESHOLD } from '../lib/context'
|
|
12
12
|
import { isCompacting } from '../agent/compact'
|
|
13
|
+
import { formatCredits, sumCost } from '../lib/credits'
|
|
13
14
|
import { cn } from '../lib/utils'
|
|
14
15
|
|
|
15
16
|
interface ContextBarProps {
|
|
@@ -26,6 +27,7 @@ function formatTokens(n: number): string {
|
|
|
26
27
|
|
|
27
28
|
export function ContextBar({ messages, model, sessionId }: ContextBarProps) {
|
|
28
29
|
const usage = useMemo(() => getContextUsage(messages, model), [messages, model])
|
|
30
|
+
const spent = useMemo(() => sumCost(messages), [messages])
|
|
29
31
|
const compacting = sessionId ? isCompacting(sessionId) : false
|
|
30
32
|
|
|
31
33
|
if (messages.length === 0) return null
|
|
@@ -51,6 +53,14 @@ export function ContextBar({ messages, model, sessionId }: ContextBarProps) {
|
|
|
51
53
|
<span className="text-faint">/ {formatTokens(limit)} tokens</span>
|
|
52
54
|
<span className="text-faint">·</span>
|
|
53
55
|
<span>{pct}%</span>
|
|
56
|
+
{spent > 0 && (
|
|
57
|
+
<>
|
|
58
|
+
<span className="text-faint">·</span>
|
|
59
|
+
<span className="text-ink/80" title="Credits spent in this session (provider-reported, or tokens × model price)">
|
|
60
|
+
{formatCredits(spent)}
|
|
61
|
+
</span>
|
|
62
|
+
</>
|
|
63
|
+
)}
|
|
54
64
|
</>
|
|
55
65
|
)}
|
|
56
66
|
</div>
|